code wiki / (root) / nx_tls13_server_session_recv_cf.nx

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}