code wiki / (root) / nx_tls13_sh_probe_test.nx

nx_tls13_sh_probe_test.nx source

↩ module page · 252 lines · 10746 B

1// nx_tls13_sh_probe_test.nx -- ServerHello DIAGNOSTIC PROBE. 2// 3// The browser's arbitrary-host gap (RUN verdict -5 = RECV_SH_FAIL) 4// swallows the INNER recv_sh cause. This probe surfaces it, per 5// host, from a data-driven host table: 6// 7// HOST <name> 8// CT= first record content type (22 handshake / 21 alert) 9// AD= alert description byte (only when CT=21) 10// PV= tls13_server_hello_parse verdict (only when != OK) 11// LV= legacy_version (771 = 0x0303) 12// CS= chosen cipher (4865=AES128GCM 4866=AES256GCM 4867=CHACHA) 13// SV= supported_versions value (772 = 0x0304 TLS1.3; 0 = absent 14// = server negotiated TLS 1.2 path) 15// GR= key_share group (29 x25519 / 23 secp256r1 / -1 absent) 16// HR= 1 if SH.random == the RFC 8446 HelloRetryRequest sentinel 17// RV= inner nx_tls13_client_session_recv_sh verdict (1 = OK) 18// 19// Exit 0 always -- this is a DIAGNOSIS instrument, not a gate; the 20// browser gate consumes its findings. Bounded reads, 5s socket 21// timeout (KNOWN_LESSONS bounded-parsing discipline). 22// 23// expect_exit: 0 24// license_tier: ORIGINAL 25 26import "nx_syscalls.nx" 27import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 28import "nx_dns_resolve_a_record.nx" 29import "nx_https_url_connect.nx" 30import "nx_tls13.nx" 31import "nx_tls13_record.nx" 32import "nx_tls13_hello.nx" 33import "nx_tls13_client_session.nx" 34import "nx_tls13_client_session_recv_sh.nx" 35import "nx_tls13_read_record_from_fd.nx" 36 37// Print 2-char label '=' signed-decimal '\n' to stdout. 38func probe_dec(label0: i64, label1: i64, v: i64) -> i64 { 39 let lab: *u8 = sys_mmap(8) 40 lab[0] = label0 as u8; lab[1] = label1 as u8; lab[2] = 0x3D 41 sys_write(1, lab, 3) 42 var av: i64 = v 43 if av < 0 { 44 let neg: *u8 = sys_mmap(8); neg[0] = 0x2D; sys_write(1, neg, 1) 45 av = 0 - av 46 } 47 if av == 0 { 48 let z: *u8 = sys_mmap(8); z[0] = 0x30; sys_write(1, z, 1) 49 } 50 if av > 0 { 51 let buf: *u8 = sys_mmap(32) 52 var pos: i64 = 0 53 var x: i64 = av 54 while x > 0 { 55 buf[pos] = (0x30 + (x % 10)) as u8 56 x = x / 10 57 pos = pos + 1 58 } 59 let out: *u8 = sys_mmap(32) 60 var oi: i64 = 0 61 while oi < pos { 62 out[oi] = buf[pos - 1 - oi] 63 oi = oi + 1 64 } 65 sys_write(1, out, pos) 66 } 67 let nl: *u8 = sys_mmap(8); nl[0] = 0x0A; sys_write(1, nl, 1) 68 return 0 69} 70 71// RFC 8446 section 4.1.3 HelloRetryRequest sentinel Random. 72func probe_hrr_sentinel(out32: *u8) -> i64 { 73 out32[0]=0xCF as u8; out32[1]=0x21 as u8; out32[2]=0xAD as u8; out32[3]=0x74 as u8 74 out32[4]=0xE5 as u8; out32[5]=0x9A as u8; out32[6]=0x61 as u8; out32[7]=0x11 as u8 75 out32[8]=0xBE as u8; out32[9]=0x1D as u8; out32[10]=0x8C as u8; out32[11]=0x02 as u8 76 out32[12]=0x1E as u8; out32[13]=0x65 as u8; out32[14]=0xB8 as u8; out32[15]=0x91 as u8 77 out32[16]=0xC2 as u8; out32[17]=0xA2 as u8; out32[18]=0x11 as u8; out32[19]=0x16 as u8 78 out32[20]=0x7A as u8; out32[21]=0xBB as u8; out32[22]=0x8C as u8; out32[23]=0x5E as u8 79 out32[24]=0x07 as u8; out32[25]=0x9E as u8; out32[26]=0x09 as u8; out32[27]=0xE2 as u8 80 out32[28]=0xC8 as u8; out32[29]=0xA8 as u8; out32[30]=0x33 as u8; out32[31]=0x9C as u8 81 return 0 82} 83 84// Probe one host: full diagnosis line set. Never aborts the run. 85func probe_host(host: *u8, host_len: i64, seed: i64) -> i64 { 86 let hdr: *u8 = sys_mmap(8) 87 hdr[0] = 0x48; hdr[1] = 0x4F; hdr[2] = 0x53; hdr[3] = 0x54; hdr[4] = 0x20 // "HOST " 88 sys_write(1, hdr, 5) 89 sys_write(1, host, host_len) 90 let nl: *u8 = sys_mmap(8); nl[0] = 0x0A; sys_write(1, nl, 1) 91 92 // ---- DNS ---- 93 let dns: *DnsResolveResult = nx_dns_resolve_default(host, host_len, seed) 94 if dns.verdict != NX_DNS_R_OK { probe_dec(0x44, 0x4E, dns.verdict); return 1 } // DN= 95 if dns.ipv4_packed == 0 { probe_dec(0x44, 0x4E, 0 - 99); return 1 } 96 97 // ---- TCP 443 ---- 98 let fd: i64 = sys_socket(NX_HTTPS_AF_INET, NX_HTTPS_SOCK_STREAM, 0) 99 if fd < 0 { probe_dec(0x54, 0x43, fd); return 1 } // TC= 100 sys_set_socket_timeout(fd, 5) 101 let sa: *u8 = sys_mmap(16) 102 nx_https_build_sockaddr(sa, dns.ipv4_packed, 443) 103 if nx_connect_bounded(fd, sa, 16, NX_CONN_DEFAULT_MS) < 0 { sys_close(fd); probe_dec(0x54, 0x43, 0 - 1); return 1 } 104 105 // ---- Session + ClientHello ---- 106 let cr: *u8 = sys_mmap(32) 107 let pk: *u8 = sys_mmap(32) 108 var i: i64 = 0 109 while i < 32 { 110 cr[i] = (((seed * 31) + (i * 17)) & 0xff) as u8 111 pk[i] = (((seed * 131) + (i * 29) + 7) & 0xff) as u8 112 i = i + 1 113 } 114 let s: *Tls13ClientSession = nx_tls13_client_session_new(cr, pk) 115 let ch_buf: *u8 = sys_mmap(1024) 116 let ch_n: i64 = nx_tls13_client_session_emit_ch(s, host, host_len, ch_buf, 1024) 117 if ch_n < 0 { sys_close(fd); probe_dec(0x43, 0x48, ch_n); return 1 } // CH= 118 119 let rec: *u8 = sys_mmap(1024 + NX_TLS13_RECORD_HEADER_LEN) 120 rec[0] = (NX_TLS13_CT_HANDSHAKE & 0xff) as u8 121 rec[1] = 0x03 as u8; rec[2] = 0x01 as u8 122 rec[3] = ((ch_n >> 8) & 0xff) as u8 123 rec[4] = (ch_n & 0xff) as u8 124 var ci: i64 = 0 125 while ci < ch_n { 126 rec[NX_TLS13_RECORD_HEADER_LEN + ci] = ch_buf[ci] 127 ci = ci + 1 128 } 129 var sent: i64 = 0 130 let want: i64 = NX_TLS13_RECORD_HEADER_LEN + ch_n 131 while sent < want { 132 let w: i64 = sys_write(fd, rec + sent, want - sent) 133 if w <= 0 { sys_close(fd); probe_dec(0x57, 0x52, w); return 1 } // WR= 134 sent = sent + w 135 } 136 137 // ---- First server record ---- 138 let sh_record: *u8 = sys_mmap(16700) 139 let sh_total: i64 = nx_tls13_read_record_from_fd(fd, sh_record, 16700) 140 sys_close(fd) 141 if sh_total < 0 { probe_dec(0x52, 0x44, sh_total); return 1 } // RD= 142 143 let ct: i64 = sh_record[0] & 0xff 144 probe_dec(0x43, 0x54, ct) // CT= 145 let body: *u8 = sh_record + NX_TLS13_RECORD_HEADER_LEN 146 let body_len: i64 = sh_total - NX_TLS13_RECORD_HEADER_LEN 147 if ct == 21 { 148 if body_len >= 2 { probe_dec(0x41, 0x44, body[1] & 0xff) } // AD= 149 return 1 150 } 151 if ct != 22 { return 1 } 152 153 // ---- Parse SH ---- 154 let p_lv: *i64 = sys_mmap(16) as *i64 155 let p_ro: *i64 = sys_mmap(16) as *i64 156 let p_cs: *i64 = sys_mmap(16) as *i64 157 let p_eo: *i64 = sys_mmap(16) as *i64 158 let p_el: *i64 = sys_mmap(16) as *i64 159 let pv: i64 = tls13_server_hello_parse(body, body_len, p_lv, p_ro, p_cs, p_eo, p_el) 160 if pv != NX_TLS13_HELLO_VERDICT_OK { probe_dec(0x50, 0x56, pv); return 1 } // PV= 161 probe_dec(0x4C, 0x56, *p_lv) // LV= 162 probe_dec(0x43, 0x53, *p_cs) // CS= 163 164 // ---- supported_versions (absent => TLS 1.2 negotiation) ---- 165 let p_off: *i64 = sys_mmap(16) as *i64 166 let p_len: *i64 = sys_mmap(16) as *i64 167 var sv: i64 = 0 168 let sv_v: i64 = tls13_ext_find(body + *p_eo, *p_el, EXT_SUPPORTED_VERSIONS, p_off, p_len) 169 if sv_v == NX_TLS13_HELLO_VERDICT_OK { 170 if *p_len >= 2 { 171 let svb: *u8 = body + *p_eo + *p_off 172 sv = ((svb[0] & 0xff) << 8) | (svb[1] & 0xff) 173 } 174 } 175 probe_dec(0x53, 0x56, sv) // SV= 176 177 // ---- key_share group ---- 178 var grp: i64 = 0 - 1 179 let ks_v: i64 = tls13_ext_find(body + *p_eo, *p_el, EXT_KEY_SHARE, p_off, p_len) 180 if ks_v == NX_TLS13_HELLO_VERDICT_OK { 181 if *p_len >= 2 { 182 let ksb: *u8 = body + *p_eo + *p_off 183 grp = ((ksb[0] & 0xff) << 8) | (ksb[1] & 0xff) 184 } 185 } 186 probe_dec(0x47, 0x52, grp) // GR= 187 188 // ---- HRR sentinel ---- 189 let sentinel: *u8 = sys_mmap(32) 190 probe_hrr_sentinel(sentinel) 191 var hrr: i64 = 1 192 var hi: i64 = 0 193 while hi < 32 { 194 if (body[*p_ro + hi] & 0xff) != (sentinel[hi] & 0xff) { hrr = 0 } 195 hi = hi + 1 196 } 197 probe_dec(0x48, 0x52, hrr) // HR= 198 199 // ---- Step-localize the recv_sh cascade (crash diagnosis) ---- 200 // Replicates recv_sh's internals with KD= markers so a fault 201 // names its step instead of dying silently. 202 if grp == 29 { 203 let ksb2: *u8 = body + *p_eo + *p_off 204 let spub: *u8 = sys_mmap(32) 205 var si: i64 = 0 206 while si < 32 { spub[si] = ksb2[4 + si]; si = si + 1 } 207 let shared: *u8 = sys_mmap(32) 208 let xv: i64 = x25519(s.x25519_priv, spub, shared) 209 probe_dec(0x58, 0x56, xv) // XV= 210 let zeros: *u8 = sys_mmap(64) 211 let early: *u8 = sys_mmap(32) 212 tls13_early_secret(zeros, TLS13_HASH_LEN_SHA256, early) 213 probe_dec(0x4B, 0x44, 1) // KD=1 214 let empty_hash: *u8 = sys_mmap(32) 215 sha256_digest(zeros, 0, empty_hash) 216 probe_dec(0x4B, 0x44, 2) 217 let derived_1: *u8 = sys_mmap(32) 218 tls13_derived(early, empty_hash, TLS13_HASH_LEN_SHA256, derived_1) 219 probe_dec(0x4B, 0x44, 3) 220 tls13_handshake_secret(derived_1, TLS13_HASH_LEN_SHA256, shared, 32, s.handshake_secret) 221 probe_dec(0x4B, 0x44, 4) 222 nx_tls13_transcript_update(s.transcript, body, body_len) 223 let h1: *u8 = sys_mmap(32) 224 nx_tls13_transcript_snapshot(s.transcript, h1) 225 probe_dec(0x4B, 0x44, 5) 226 tls13_traffic_secret(s.handshake_secret, NX_TLS13_LABEL_C_HS_TRAFFIC, 227 h1, TLS13_HASH_LEN_SHA256, s.client_hs_traffic_secret) 228 tls13_traffic_secret(s.handshake_secret, NX_TLS13_LABEL_S_HS_TRAFFIC, 229 h1, TLS13_HASH_LEN_SHA256, s.server_hs_traffic_secret) 230 probe_dec(0x4B, 0x44, 6) 231 tls13_traffic_key(s.client_hs_traffic_secret, 16, s.client_hs_traffic_key) 232 tls13_traffic_iv(s.client_hs_traffic_secret, 12, s.client_hs_iv) 233 probe_dec(0x4B, 0x44, 7) 234 } 235 236 // ---- Inner recv_sh verdict ---- 237 let rv: i64 = nx_tls13_client_session_recv_sh(s, body, body_len) 238 probe_dec(0x52, 0x56, rv) // RV= 239 return 0 240} 241 242func main() -> i64 { 243 probe_host("example.com\x00", 11, 1779290001) 244 probe_host("httpbin.org\x00", 11, 1779290002) 245 probe_host("en.wikipedia.org\x00", 16, 1779290003) 246 probe_host("github.com\x00", 10, 1779290004) 247 probe_host("www.google.com\x00", 14, 1779290005) 248 probe_host("nishifamily.com\x00", 15, 1779290006) 249 let done: *u8 = "SH_PROBE_DONE\n\x00" 250 sys_write(1, done, 14) 251 return 0 252}