code wiki / (root) / nx_tls13_recv_hs_probe_test.nx

nx_tls13_recv_hs_probe_test.nx source

↩ module page · 272 lines · 13933 B

1// nx_tls13_recv_hs_probe_test.nx -- B1 instrument (pm_plan arc=BROWSER 2// step=B1-RECVHS-EXAMPLE): example.com handshakes to recv_sh GREEN (sh-probe 3// RV=1) but session_run dies SR=-7 (RUN_RECV_HS_FAIL) in the ENCRYPTED 4// handshake -- recv_hs collapses every dispatcher failure to DISPATCH_FAIL, 5// hiding the locus. This probe replicates recv_hs's walk per record with 6// step markers (the KD= cascade pattern that localized the tail-call 7// miscompile), composing the shipped primitives UNCHANGED: 8// 9// RC=/CT=/TL= record number, outer ContentType, total bytes 10// DV=/IC=/PL= record-decrypt verdict, inner ContentType, plaintext len 11// MT=/ML= each handshake message type + body length 12// PV= at WAIT_CERT: the cert pipeline's EXACT verdict 13// (2..12 = msg-bad/parse/validity/SAN/DN/SIG/anchor) 14// CN=/XV=/SA=/SS=/PA= per served cert: index, x509_parse rc, sig-alg id, 15// sig-alg SUPPORTED flag, pubkey-alg id (the P-384/RSA-PSS 16// suspicion becomes a measured fact here) 17// DW=/ST= dispatcher verdict, new session state 18// 19// Exit 0 iff the handshake reaches WAIT_CLIENT_FIN (server Finished 20// verified) -- the bar for landing this module as the B1 gate row. 21// Until the fix, the nonzero exit + markers ARE the Doctor's input. 22// Prereq: /tmp/mozilla_certdata.txt staged (browser gate self-stages it). 23// 24// expect_exit: 0 (once B1 is healed; today it names the defect) 25// license_tier: ORIGINAL 26 27import "nx_syscalls.nx" 28import "nx_https_url_for_fetch.nx" 29import "nx_https_url_connect.nx" 30import "nx_x509_trust_store.nx" 31import "nx_trust_store_load_from_certdata.nx" 32import "nx_https_cert_pipeline.nx" 33import "nx_x509.nx" 34import "nx_x509_sig_alg.nx" 35import "nx_x509_pubkey_alg.nx" 36import "nx_tls13_client_session_recv_sh.nx" 37import "nx_tls13_client_session_recv_hs.nx" 38import "nx_tls13_read_record_from_fd.nx" 39 40func rp_dec(label0: i64, label1: i64, v: i64) -> i64 { 41 let lab: *u8 = sys_mmap(8) 42 lab[0] = label0 as u8; lab[1] = label1 as u8; lab[2] = 0x3D 43 sys_write(1, lab, 3) 44 var av: i64 = v 45 if av < 0 { 46 let neg: *u8 = sys_mmap(8); neg[0] = 0x2D; sys_write(1, neg, 1) 47 av = 0 - av 48 } 49 if av == 0 { 50 let z: *u8 = sys_mmap(8); z[0] = 0x30; sys_write(1, z, 1) 51 } 52 if av > 0 { 53 let buf: *u8 = sys_mmap(32) 54 var pos: i64 = 0 55 var x: i64 = av 56 while x > 0 { buf[pos] = (0x30 + (x % 10)) as u8; x = x / 10; pos = pos + 1 } 57 let out: *u8 = sys_mmap(32) 58 var oi: i64 = 0 59 while oi < pos { out[oi] = buf[pos - 1 - oi]; oi = oi + 1 } 60 sys_write(1, out, pos) 61 } 62 let nl: *u8 = sys_mmap(8); nl[0] = 0x0A; sys_write(1, nl, 1) 63 return 0 64} 65 66// Census of the served Certificate message: per cert print index, 67// parse rc, sig-alg id (+supported), pubkey-alg id. Read-only -- 68// never touches session/transcript state. 69func rp_chain_census(msg: *u8, msg_len: i64) -> i64 { 70 if msg_len < 8 { return 0 - 1 } 71 let ctx_len: i64 = msg[4] & 0xff 72 var p: i64 = 5 + ctx_len 73 if p + 3 > msg_len { return 0 - 2 } 74 let list_len: i64 = ((msg[p] & 0xff) << 16) | ((msg[p + 1] & 0xff) << 8) | (msg[p + 2] & 0xff) 75 p = p + 3 76 var endp: i64 = p + list_len 77 if endp > msg_len { endp = msg_len } 78 var idx: i64 = 0 79 while p + 3 <= endp { 80 let clen: i64 = ((msg[p] & 0xff) << 16) | ((msg[p + 1] & 0xff) << 8) | (msg[p + 2] & 0xff) 81 if p + 3 + clen > endp { return 0 - 3 } 82 let der: *u8 = msg + p + 3 83 rp_dec(0x43, 0x4E, idx) // CN= 84 let cert_raw: *u8 = sys_mmap(512) 85 let cert: *X509Cert = cert_raw as *X509Cert 86 let xv: i64 = x509_parse(der, clen, cert) 87 rp_dec(0x58, 0x56, xv) // XV= 88 if xv == 0 { 89 let sa: i64 = nx_x509_sig_alg_identify(der, cert.sig_alg_off, cert.sig_alg_len) 90 rp_dec(0x53, 0x41, sa) // SA= 91 rp_dec(0x53, 0x53, nx_x509_sig_alg_is_supported(sa)) // SS= 92 let pa: i64 = nx_x509_pubkey_alg_identify(der, cert.pubkey_alg_off, cert.pubkey_alg_len) 93 rp_dec(0x50, 0x41, pa) // PA= 94 } 95 p = p + 3 + clen 96 if p + 2 > endp { return idx + 1 } 97 let ext_len: i64 = ((msg[p] & 0xff) << 8) | (msg[p + 1] & 0xff) 98 p = p + 2 + ext_len 99 idx = idx + 1 100 } 101 return idx 102} 103 104func main(argc: i64, argv: *i64) -> i64 { 105 var url: *u8 = "https://example.com/\x00" 106 if argc >= 2 { url = argv[1] as *u8 } 107 let epoch: i64 = sys_now_realtime_sec() // REAL clock (B1 root cause was a rotted hardcoded epoch) 108 109 // ---- trust store (real Mozilla bundle, gate-staged) ---- 110 let r: i64 = nx_trust_store_load_from_certdata("/tmp/mozilla_certdata.txt\x00" as *u8, 300, 4194304) 111 if r <= 0 { rp_dec(0x4C, 0x4F, r); return 11 } // LO= 112 let store: *TrustStore = r as *TrustStore 113 rp_dec(0x43, 0x41, trust_store_count(store)) // CA= 114 115 // ---- connect ---- 116 let url_p: *NxUrl = nx_url_new() 117 let target_raw: *u8 = sys_mmap(32) 118 let target: *NxHttpsTarget = target_raw as *NxHttpsTarget 119 target.url = url_p 120 target.port = 0 121 if nx_https_url_for_fetch(url, target) != NX_HTTPS_URL_OK { return 12 } 122 let host_len: i64 = target.url.host_len 123 let fd_p: *i64 = sys_mmap(16) as *i64 124 let ucv: i64 = nx_https_url_connect(target, url, 1781100001, fd_p) 125 rp_dec(0x55, 0x43, ucv) // UC= 126 if ucv != NX_HTTPS_CONNECT_OK { return 13 } 127 let fd: i64 = *fd_p 128 sys_set_socket_timeout(fd, 10) 129 let host: *u8 = url + target.url.host_off 130 131 // ---- validation context ---- 132 let val_ctx_raw: *u8 = sys_mmap(64) 133 let val_ctx: *TlsValidationContext = val_ctx_raw as *TlsValidationContext 134 val_ctx.store = store 135 val_ctx.sni_host = host 136 val_ctx.sni_host_len = host_len 137 val_ctx.now_epoch = epoch 138 139 // ---- session + ClientHello ---- 140 let cr: *u8 = sys_mmap(32) 141 let priv: *u8 = sys_mmap(32) 142 var i: i64 = 0 143 while i < 32 { cr[i] = (0xC0 + i) as u8; priv[i] = (0xA0 + i) as u8; i = i + 1 } 144 let s: *Tls13ClientSession = nx_tls13_client_session_new(cr, priv) 145 let ch_buf: *u8 = sys_mmap(1024) 146 let ch_n: i64 = nx_tls13_client_session_emit_ch(s, host, host_len, ch_buf, 1024) 147 rp_dec(0x43, 0x48, ch_n) // CH= 148 if ch_n < 0 { sys_close(fd); return 14 } 149 150 let rec: *u8 = sys_mmap(1024 + NX_TLS13_RECORD_HEADER_LEN) 151 rec[0] = (NX_TLS13_CT_HANDSHAKE & 0xff) as u8 152 rec[1] = 0x03 as u8; rec[2] = 0x01 as u8 153 rec[3] = ((ch_n >> 8) & 0xff) as u8 154 rec[4] = (ch_n & 0xff) as u8 155 var ci: i64 = 0 156 while ci < ch_n { rec[NX_TLS13_RECORD_HEADER_LEN + ci] = ch_buf[ci]; ci = ci + 1 } 157 var sent: i64 = 0 158 let want: i64 = NX_TLS13_RECORD_HEADER_LEN + ch_n 159 while sent < want { 160 let w: i64 = sys_write(fd, rec + sent, want - sent) 161 if w <= 0 { sys_close(fd); rp_dec(0x57, 0x52, w); return 15 } // WR= 162 sent = sent + w 163 } 164 165 // ---- ServerHello ---- 166 let sh_record: *u8 = sys_mmap(16700) 167 let sh_total: i64 = nx_tls13_read_record_from_fd(fd, sh_record, 16700) 168 if sh_total < 0 { sys_close(fd); rp_dec(0x52, 0x44, sh_total); return 16 } // RD= 169 let sh_body: *u8 = sh_record + NX_TLS13_RECORD_HEADER_LEN 170 let sh_body_len: i64 = sh_total - NX_TLS13_RECORD_HEADER_LEN 171 rp_dec(0x43, 0x54, sh_record[0] & 0xff) // CT= outer record ContentType (22=handshake, 21=ALERT) 172 rp_dec(0x42, 0x35, sh_record[5] & 0xff) // B5= first body byte (handshake type 2=SH; or alert level) 173 rp_dec(0x42, 0x36, sh_record[6] & 0xff) // B6= second body byte (SH legacy_version hi; or alert DESCRIPTION) 174 rp_dec(0x54, 0x4c, sh_total) // TL= total record bytes 175 let rv: i64 = nx_tls13_client_session_recv_sh(s, sh_body, sh_body_len) 176 rp_dec(0x52, 0x56, rv) // RV= 177 if rv != NX_TLS13_RECV_SH_OK { sys_close(fd); return 17 } 178 179 // ---- instrumented encrypted-handshake walk (recv_hs mirrored) ---- 180 var recno: i64 = 0 181 var fail: i64 = 0 182 var running: i64 = 1 183 while running == 1 { 184 if s.state == NX_TLS13_CSESSION_STATE_WAIT_CLIENT_FIN { running = 0 } 185 if recno >= 16 { running = 0; if fail == 0 { fail = 90 } } 186 if running == 1 { 187 let hs_record: *u8 = sys_mmap(17000) 188 let hs_total: i64 = nx_tls13_read_record_from_fd(fd, hs_record, 17000) 189 rp_dec(0x52, 0x43, recno) // RC= 190 rp_dec(0x54, 0x4C, hs_total) // TL= 191 if hs_total < 0 { fail = 20; running = 0 } 192 if running == 1 { 193 let oct: i64 = hs_record[0] & 0xff 194 rp_dec(0x43, 0x54, oct) // CT= 195 var skip: i64 = 0 196 if oct == 20 { skip = 1 } 197 if skip == 0 { 198 let header: *u8 = hs_record 199 let ctxt: *u8 = hs_record + NX_TLS13_RECORD_HEADER_LEN 200 let ct_len: i64 = hs_total - NX_TLS13_RECORD_HEADER_LEN - NX_TLS13_RECORD_TAG_LEN 201 let tag: *u8 = hs_record + hs_total - NX_TLS13_RECORD_TAG_LEN 202 let inner: *u8 = sys_mmap(ct_len + 16) 203 let real_ct_p: *i64 = sys_mmap(16) as *i64 204 let real_len_p: *i64 = sys_mmap(16) as *i64 205 let dv: i64 = nx_tls13_record_decrypt_v2( 206 s.cipher_suite, s.server_hs_traffic_key, s.server_hs_iv, 207 s.server_seq, header, ctxt, ct_len, tag, 208 inner, real_ct_p, real_len_p) 209 s.server_seq = s.server_seq + 1 210 rp_dec(0x44, 0x56, dv) // DV= 211 if dv != NX_TLS13_REC_VERDICT_OK { fail = 30; running = 0 } 212 if running == 1 { 213 rp_dec(0x49, 0x43, *real_ct_p) // IC= 214 if *real_ct_p == 21 { 215 if *real_len_p >= 2 { rp_dec(0x41, 0x44, inner[1] & 0xff) } // AD= 216 fail = 31; running = 0 217 } 218 if running == 1 { if *real_ct_p != NX_TLS13_CT_HANDSHAKE { fail = 32; running = 0 } } 219 } 220 if running == 1 { 221 let plen: i64 = *real_len_p 222 rp_dec(0x50, 0x4C, plen) // PL= 223 var off: i64 = 0 224 let new_state_p: *i64 = sys_mmap(16) as *i64 225 while off < plen { 226 if off + 4 > plen { fail = 33; off = plen } 227 if fail == 0 { 228 let mt: i64 = inner[off] & 0xff 229 let body_len: i64 = ((inner[off + 1] & 0xff) << 16) | ((inner[off + 2] & 0xff) << 8) | (inner[off + 3] & 0xff) 230 let msg_len: i64 = 4 + body_len 231 rp_dec(0x4D, 0x54, mt) // MT= 232 rp_dec(0x4D, 0x4C, body_len) // ML= 233 if off + msg_len > plen { fail = 34; off = plen } 234 if fail == 0 { 235 let cstate: i64 = s.state - NX_TLS13_CSESSION_STATE_WAIT_EE + NX_TLS13_CSTATE_WAIT_EE 236 if mt == 11 { 237 let pv: i64 = nx_https_cert_pipeline_verify_with_store( 238 inner + off, msg_len, host, host_len, epoch, store) 239 rp_dec(0x50, 0x56, pv) // PV= 240 rp_chain_census(inner + off, msg_len) 241 } 242 let dw: i64 = tls13_client_dispatch_with_validation( 243 cstate, inner + off, msg_len, 244 s.server_hs_traffic_secret, s.transcript, 245 new_state_p, val_ctx) 246 rp_dec(0x44, 0x57, dw) // DW= 247 if dw != NX_TLS13_DWV_OK { fail = 40 + dw; off = plen } 248 if fail == 0 { 249 if *new_state_p == NX_TLS13_CSTATE_WAIT_EE { s.state = NX_TLS13_CSESSION_STATE_WAIT_EE } 250 if *new_state_p == NX_TLS13_CSTATE_WAIT_CERT { s.state = NX_TLS13_CSESSION_STATE_WAIT_CERT } 251 if *new_state_p == NX_TLS13_CSTATE_WAIT_CV { s.state = NX_TLS13_CSESSION_STATE_WAIT_CV } 252 if *new_state_p == NX_TLS13_CSTATE_WAIT_SF { s.state = NX_TLS13_CSESSION_STATE_WAIT_SF } 253 if *new_state_p == NX_TLS13_CSTATE_CONNECTED { s.state = NX_TLS13_CSESSION_STATE_WAIT_CLIENT_FIN } 254 rp_dec(0x53, 0x54, s.state) // ST= 255 off = off + msg_len 256 } 257 } 258 } 259 } 260 if fail != 0 { running = 0 } 261 } 262 } 263 } 264 recno = recno + 1 265 } 266 } 267 sys_close(fd) 268 rp_dec(0x46, 0x58, fail) // FX= 269 if fail == 0 { if s.state == NX_TLS13_CSESSION_STATE_WAIT_CLIENT_FIN { return 0 } } 270 if fail == 0 { return 91 } 271 return fail 272}