nx_tls13_server_session_recv_cf.nx source
↩ module page · 223 lines · 9225 B
1// nx_tls13_server_session_recv_cf.nx -- 8th (final) TLS server stone.
2//
3// Receives the client Finished record (AEAD-encrypted under
4// client_hs_traffic_key + iv), verifies the HMAC against the
5// server's transcript-snapshot, then derives application traffic
6// keys per RFC 8446 §7.1. Closes the loopback-class TLS 1.3
7// server handshake arc.
8//
9// Steps:
10// 1. Parse record header (must be type=0x17 app_data)
11// 2. AEAD decrypt with c_hs_traffic_key + iv + client_seq
12// 3. Inner type must be CT_HANDSHAKE; payload must be HT_FINISHED
13// 4. Recompute expected verify_data = HMAC(finished_key_c, transcript)
14// 5. Constant-time compare against received verify_data
15// 6. On match: derive master_secret + app traffic secrets + keys
16// 7. State -> CONNECTED
17//
18// Precondition: state == SF_SENT (server has emitted its Finished)
19// Postcondition on success: state == CONNECTED
20//
21// license_tier: ORIGINAL
22
23import "nx_syscalls.nx"
24import "nx_hmac.nx"
25import "nx_tls13.nx"
26import "nx_tls13_kdf.nx"
27import "nx_tls13_record.nx"
28import "nx_tls13_transcript.nx"
29import "nx_hkdf.nx"
30import "nx_tls13_server_session.nx"
31
32const NX_TLS13_CF_VERIFY_LEN: i64 = 32
33const NX_TLS13_CF_REC_HEADER: i64 = 5
34const NX_TLS13_CF_REC_TAG: i64 = 16
35
36// Constant-time 32-byte compare. Returns 1 if equal, 0 if not.
37func cf_ct_eq_32(a: *u8, b: *u8) -> i64 {
38 var diff: i64 = 0
39 var i: i64 = 0
40 while i < 32 {
41 let ai: i64 = a[i] as i64
42 let bi: i64 = b[i] as i64
43 diff = diff | (ai ^ bi)
44 i = i + 1
45 }
46 if diff == 0 { return 1 }
47 return 0
48}
49
50func nx_tls13_server_session_recv_cf(
51 session: *Tls13ServerSession,
52 record: *u8, record_len: i64
53) -> i64 {
54 if (session as i64) == 0 { return NX_TLS13_SSESSION_BAD_STATE }
55 if (record as i64) == 0 { return NX_TLS13_SSESSION_BAD_STATE }
56 if session.state != NX_TLS13_SSTATE_SF_SENT {
57 return NX_TLS13_SSESSION_BAD_STATE
58 }
59 if (session.client_hs_traffic_key as i64) == 0 {
60 return NX_TLS13_SSESSION_INTERNAL
61 }
62 if (session.client_hs_traffic_secret as i64) == 0 {
63 return NX_TLS13_SSESSION_INTERNAL
64 }
65
66 // Record layout: 5 header + ct + 16 tag. Minimum total = 5 + 36 + 1 + 16 = 58.
67 let min_rec: i64 = NX_TLS13_CF_REC_HEADER + 36 + 1 + NX_TLS13_CF_REC_TAG
68 if record_len < min_rec { return NX_TLS13_SSESSION_PROTOCOL_ERR }
69
70 let header: *u8 = record
71 if header[0] != 0x17 { return NX_TLS13_SSESSION_PROTOCOL_ERR } // not app_data
72
73 let body_len: i64 = ((header[3] as i64) << 8) | (header[4] as i64)
74 if NX_TLS13_CF_REC_HEADER + body_len > record_len {
75 return NX_TLS13_SSESSION_PROTOCOL_ERR
76 }
77
78 let ct_len: i64 = body_len - NX_TLS13_CF_REC_TAG
79 if ct_len < 1 { return NX_TLS13_SSESSION_PROTOCOL_ERR }
80 let ct: *u8 = (((record as i64) + NX_TLS13_CF_REC_HEADER)) as *u8
81 let tag: *u8 = (((record as i64) + NX_TLS13_CF_REC_HEADER + ct_len)) as *u8
82
83 let pt_buf: *u8 = sys_mmap(ct_len + 16)
84 let real_ct_box: *i64 = sys_mmap(8) as *i64
85 let real_len_box: *i64 = sys_mmap(8) as *i64
86
87 let rv: i64 = nx_tls13_record_decrypt_v2(
88 session.cipher_suite,
89 session.client_hs_traffic_key,
90 session.client_hs_iv,
91 session.client_seq,
92 header, ct, ct_len, tag,
93 pt_buf, real_ct_box, real_len_box)
94 if rv != NX_TLS13_REC_VERDICT_OK {
95 return NX_TLS13_SSESSION_PROTOCOL_ERR
96 }
97 if *real_ct_box != CT_HANDSHAKE {
98 return NX_TLS13_SSESSION_PROTOCOL_ERR
99 }
100 let pt_len: i64 = *real_len_box
101 if pt_len < 36 { return NX_TLS13_SSESSION_PROTOCOL_ERR }
102 if pt_buf[0] != (HT_FINISHED & 0xff) as u8 {
103 return NX_TLS13_SSESSION_PROTOCOL_ERR
104 }
105 let stated_len: i64 = ((pt_buf[1] as i64) << 16) | ((pt_buf[2] as i64) << 8) | (pt_buf[3] as i64)
106 if stated_len != NX_TLS13_CF_VERIFY_LEN {
107 return NX_TLS13_SSESSION_PROTOCOL_ERR
108 }
109
110 // Compute expected verify_data:
111 // finished_key_c = HKDF-Expand-Label(c_hs_traffic_secret,
112 // "finished", "", 32)
113 // th = transcript snapshot at this point (includes
114 // server's Finished -- updated when emit_sf ran)
115 // expected = HMAC-SHA256(finished_key_c, th)
116 let finished_label: *u8 = "finished"
117 let empty: *u8 = sys_mmap(1)
118 let finished_key_c: *u8 = sys_mmap(NX_TLS13_CF_VERIFY_LEN)
119 let r1: i64 = tls13_hkdf_expand_label(
120 session.client_hs_traffic_secret,
121 finished_label, 8,
122 empty, 0,
123 NX_TLS13_CF_VERIFY_LEN, finished_key_c)
124 if r1 != NX_TLS13_KDF_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
125
126 let th: *u8 = sys_mmap(NX_TLS13_CF_VERIFY_LEN)
127 let r2: i64 = nx_tls13_transcript_snapshot(session.transcript, th)
128 if r2 != NX_TLS13_TX_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
129
130 let expected: *u8 = sys_mmap(NX_TLS13_CF_VERIFY_LEN)
131 hmac_sha256(finished_key_c, NX_TLS13_CF_VERIFY_LEN,
132 th, NX_TLS13_CF_VERIFY_LEN, expected)
133
134 let received: *u8 = (((pt_buf as i64) + 4)) as *u8
135 if cf_ct_eq_32(received, expected) != 1 {
136 return NX_TLS13_SSESSION_PROTOCOL_ERR
137 }
138
139 // ----- HMAC verified. Derive application traffic keys per
140 // RFC 8446 §7.1. -----
141 //
142 // 1. empty_derived = Derive-Secret(handshake_secret, "derived", "")
143 // (with hash("") canonical SHA-256)
144 let empty_hash: *u8 = sys_mmap(32)
145 empty_hash[0] = 0xe3 as u8; empty_hash[1] = 0xb0 as u8
146 empty_hash[2] = 0xc4 as u8; empty_hash[3] = 0x42 as u8
147 empty_hash[4] = 0x98 as u8; empty_hash[5] = 0xfc as u8
148 empty_hash[6] = 0x1c as u8; empty_hash[7] = 0x14 as u8
149 empty_hash[8] = 0x9a as u8; empty_hash[9] = 0xfb as u8
150 empty_hash[10] = 0xf4 as u8; empty_hash[11] = 0xc8 as u8
151 empty_hash[12] = 0x99 as u8; empty_hash[13] = 0x6f as u8
152 empty_hash[14] = 0xb9 as u8; empty_hash[15] = 0x24 as u8
153 empty_hash[16] = 0x27 as u8; empty_hash[17] = 0xae as u8
154 empty_hash[18] = 0x41 as u8; empty_hash[19] = 0xe4 as u8
155 empty_hash[20] = 0x64 as u8; empty_hash[21] = 0x9b as u8
156 empty_hash[22] = 0x93 as u8; empty_hash[23] = 0x4c as u8
157 empty_hash[24] = 0xa4 as u8; empty_hash[25] = 0x95 as u8
158 empty_hash[26] = 0x99 as u8; empty_hash[27] = 0x1b as u8
159 empty_hash[28] = 0x78 as u8; empty_hash[29] = 0x52 as u8
160 empty_hash[30] = 0xb8 as u8; empty_hash[31] = 0x55 as u8
161
162 let derived_label: *u8 = "derived"
163 let empty_derived: *u8 = sys_mmap(32)
164 let r3: i64 = tls13_hkdf_expand_label(
165 session.handshake_secret,
166 derived_label, 7,
167 empty_hash, 32,
168 32, empty_derived)
169 if r3 != NX_TLS13_KDF_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
170
171 // 2. master_secret = HKDF-Extract(salt=empty_derived, IKM=zero32)
172 let zero_ikm: *u8 = sys_mmap(32)
173 let master_secret: *u8 = sys_mmap(32)
174 let r4: i64 = hkdf_extract(empty_derived, 32, zero_ikm, 32, master_secret)
175 if r4 != 0 { return NX_TLS13_SSESSION_INTERNAL }
176 session.master_secret = master_secret
177
178 // 3. c_app_traffic = Derive-Secret(master, "c ap traffic", th_for_app)
179 // Per RFC, th_for_app = transcript through ServerFinished.
180 // Our `th` from above is exactly that (we snapshotted after
181 // emit_sf updated transcript).
182 let cap_label: *u8 = "c ap traffic"
183 let cap_secret: *u8 = sys_mmap(32)
184 let r5: i64 = tls13_derive_secret(master_secret, cap_label, 12, th, 32, cap_secret)
185 if r5 != NX_TLS13_KDF_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
186 session.client_app_traffic_secret = cap_secret
187
188 let sap_label: *u8 = "s ap traffic"
189 let sap_secret: *u8 = sys_mmap(32)
190 let r6: i64 = tls13_derive_secret(master_secret, sap_label, 12, th, 32, sap_secret)
191 if r6 != NX_TLS13_KDF_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
192 session.server_app_traffic_secret = sap_secret
193
194 // 4. App keys + IVs (key length per negotiated cipher; IV always 12).
195 let key_lbl: *u8 = "key"
196 let iv_lbl: *u8 = "iv"
197 let akl: i64 = nx_tls13_aead_key_len(session.cipher_suite)
198
199 let cap_key: *u8 = sys_mmap(akl)
200 let r7: i64 = tls13_hkdf_expand_label(cap_secret, key_lbl, 3, empty, 0, akl, cap_key)
201 if r7 != NX_TLS13_KDF_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
202 session.client_app_traffic_key = cap_key
203
204 let cap_iv: *u8 = sys_mmap(12)
205 let r8: i64 = tls13_hkdf_expand_label(cap_secret, iv_lbl, 2, empty, 0, 12, cap_iv)
206 if r8 != NX_TLS13_KDF_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
207 session.client_app_iv = cap_iv
208
209 let sap_key: *u8 = sys_mmap(akl)
210 let r9: i64 = tls13_hkdf_expand_label(sap_secret, key_lbl, 3, empty, 0, akl, sap_key)
211 if r9 != NX_TLS13_KDF_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
212 session.server_app_traffic_key = sap_key
213
214 let sap_iv: *u8 = sys_mmap(12)
215 let r10: i64 = tls13_hkdf_expand_label(sap_secret, iv_lbl, 2, empty, 0, 12, sap_iv)
216 if r10 != NX_TLS13_KDF_VERDICT_OK { return NX_TLS13_SSESSION_INTERNAL }
217 session.server_app_iv = sap_iv
218
219 // 5. Advance state + sequence numbers
220 session.client_seq = session.client_seq + 1
221 session.state = NX_TLS13_SSTATE_CONNECTED
222 return NX_TLS13_SSESSION_OK
223}