code wiki / _hdl_build / nx_tls12_reconnect_stress_gate.nx
nx_tls12_reconnect_stress_gate.nx source
↩ module page · 134 lines · 6642 B
1// nx_tls12_reconnect_stress_gate.nx -- LIVE stress proof for the sovereign
2// TLS 1.3 -> 1.2 reconnect path (rung 1 read-correctness + rung 3 retry).
3//
4// The renewal transport (nx_acme_req) tries TLS 1.3, sees api.porkbun.com
5// refuse it, GRACEFULLY tears down the 1.3 socket, reconnects, and completes
6// over the sovereign TLS 1.2 client -- now wrapped in a BOUNDED reconnect-
7// retry so a transient first-flight failure / garbled ServerHello on the rapid
8// reconnect self-heals instead of failing the renewal.
9//
10// This gate drives that EXACT production path against the READ-ONLY Porkbun
11// ping endpoint N times in rapid succession (the condition under which the
12// intermittent 0xC02B cipher garble / -4 READ_FLIGHT was reported), and
13// asserts EVERY handshake completes and the ping returns HTTP 200 SUCCESS.
14// A garbled/unsupported ServerHello FAILS CLOSED (no session) -> the ping
15// would NOT be 200, so 200-every-time IS the zero-garble end-to-end proof.
16// (The record framer's byte-level immunity to fragmentation is proven
17// deterministically + offline in nx_tls12_frag_read_gate.)
18//
19// READ-ONLY: ping returns your IP; NO DNS record is created or modified, NO
20// Let's Encrypt challenge is triggered. Row 0 is a harmless LE 1.3 GET that
21// proves the 1.3 path is still intact through the same transport.
22//
23// Creds: run ./_offc/nx_secret_cli.elf get porkbun first (writes
24// /tmp/nxsecret.out: line1=apikey, line2=secretapikey; a UTF-8 BOM is stripped).
25//
26// expect_exit: 0
27// license_tier: ORIGINAL
28
29import "nx_syscalls.nx"
30import "nx_x509_trust_store.nx"
31import "nx_trust_store_load_from_certdata.nx"
32import "nx_acme_http.nx"
33import "nx_acme_porkbun.nx"
34import "nx_http_response_parse.nx"
35
36func s_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
37func s_n(v: i64) -> i64 {
38 var m: i64=v
39 if m<0 { s_w("-" as *u8); m=0-m }
40 let t: *u8=sys_mmap(24); var k: i64=0
41 if m==0 { t[0]=48 as u8; k=1 }
42 while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
43 let o: *u8=sys_mmap(24); var i: i64=0
44 while i<k { o[i]=t[k-1-i]; i=i+1 }
45 sys_write(1,o,k); return 0
46}
47func s_read_file(path: *u8, out: *u8, cap: i64) -> i64 {
48 let fd: i64 = sys_openat_rd(path)
49 if fd <= 0 { return 0 - 1 }
50 let n: i64 = sys_read(fd, out, cap)
51 sys_close(fd)
52 return n
53}
54
55func main() -> i64 {
56 let pass: *i64 = sys_mmap(8) as *i64; pass[0]=0
57 var total: i64 = 0
58 s_w("=== NX-TLS12-RECONNECT-STRESS GATE (live 1.3->1.2 fallback x24 to Porkbun ping; zero garbles) ===\n" as *u8)
59
60 let lr: i64 = nx_trust_store_load_from_certdata("data/mozilla_certdata.txt\x00" as *u8, 300, 4194304)
61 if lr <= 0 { s_w(" trust load FAIL rc=" as *u8); s_n(lr); s_w("\nverdict=RED\n" as *u8); sys_exit(1); return 1 }
62 let store: *TrustStore = lr as *TrustStore
63 s_w(" trust store CAs=" as *u8); s_n(trust_store_count(store)); s_w("\n" as *u8)
64 let now: i64 = sys_now_realtime_sec()
65
66 // ---- creds from the sovereign vault (/tmp/nxsecret.out); strip UTF-8 BOM ----
67 let raw: *u8 = sys_mmap(512)
68 let rawn: i64 = s_read_file("/tmp/nxsecret.out\x00" as *u8, raw, 512)
69 if rawn <= 0 { s_w(" VAULT creds read FAILED (run ./_offc/nx_secret_cli.elf get porkbun)\nverdict=RED\n" as *u8); sys_exit(1); return 1 }
70 var base: i64 = 0
71 if rawn >= 3 { if raw[0]==(0xEF as u8) { if raw[1]==(0xBB as u8) { if raw[2]==(0xBF as u8) { base=3 } } } }
72 let creds: *u8 = (raw as i64 + base) as *u8
73 let clen: i64 = rawn - base
74 var nl: i64 = 0
75 while nl < clen { if creds[nl]==0x0a { break }; nl=nl+1 }
76 var ak_end: i64 = nl
77 if ak_end>0 { if creds[ak_end-1]==0x0d { ak_end=ak_end-1 } }
78 let ak: *u8 = creds
79 let akn: i64 = ak_end
80 let s2: i64 = nl + 1
81 var nl2: i64 = s2
82 while nl2 < clen { if creds[nl2]==0x0a { break }; nl2=nl2+1 }
83 var sk_end: i64 = nl2
84 if sk_end>s2 { if creds[sk_end-1]==0x0d { sk_end=sk_end-1 } }
85 let sk: *u8 = (creds as i64 + s2) as *u8
86 let skn: i64 = sk_end - s2
87 if akn<=0 { s_w(" apikey empty\nverdict=RED\n" as *u8); sys_exit(1); return 1 }
88 if skn<=0 { s_w(" secret empty\nverdict=RED\n" as *u8); sys_exit(1); return 1 }
89 s_w(" vault creds loaded (apikey len=" as *u8); s_n(akn); s_w(", secret len=" as *u8); s_n(skn); s_w(")\n" as *u8)
90
91 // ---- Row 0: TLS 1.3 regression (LE directory GET still works) ----
92 let le_url: *u8 = "https://acme-v02.api.letsencrypt.org/directory\x00" as *u8
93 let lebuf: *u8 = sys_mmap(65536)
94 let letot: *i64 = sys_mmap(8) as *i64
95 var le_ok: i64 = 0
96 if nx_acme_req(le_url, 46, 0, 0 as *u8, 0, 0 as *u8, 0, store, now, lebuf, 65536, letot) == NX_ACME_HTTP_OK {
97 let rr: *i64 = nx_http_resp_alloc()
98 if nx_http_response_parse(lebuf, letot[0], rr) == 0 { if rr[1] == 200 { le_ok = 1 } }
99 }
100 total = total + 1
101 s_w(" row REGRESSION: LE directory (TLS 1.3) GET -> 200: " as *u8)
102 if le_ok==1 { s_w("OK\n" as *u8); pass[0]=pass[0]+1 } else { s_w("FAIL\n" as *u8) }
103
104 // ---- Rows 1..N: rapid 1.3->1.2 fallback Porkbun ping; assert 200 each ----
105 let ping_url: *u8 = "https://api.porkbun.com/api/json/v3/ping\x00" as *u8
106 let body: *u8 = sys_mmap(1024)
107 var bo: i64 = pk_creds(body, 0, ak, akn, sk, skn)
108 bo = pk_put(body, bo, "}" as *u8)
109
110 let N: i64 = 24
111 var ok_count: i64 = 0
112 var i: i64 = 0
113 while i < N {
114 let resp: *u8 = sys_mmap(16384)
115 let tot: *i64 = sys_mmap(8) as *i64
116 let rc: i64 = nx_acme_req(ping_url, 40, 1, "application/json" as *u8, 16, body, bo, store, now, resp, 16384, tot)
117 // pk_check asserts HTTP 200 AND JSON "status":"SUCCESS" -- a completed
118 // 0xC02F handshake AND a valid authed round trip. A garbled/failed
119 // handshake (FAIL CLOSED -> no session) cannot reach SUCCESS.
120 var good: i64 = 0
121 if rc == NX_ACME_HTTP_OK { if pk_check(resp, tot[0]) == NX_PORKBUN_OK { good = 1 } }
122 if good == 1 { ok_count = ok_count + 1 }
123 else { s_w(" ping " as *u8); s_n(i); s_w(" NOT SUCCESS: rc=" as *u8); s_n(rc); s_w("\n" as *u8) }
124 i = i + 1
125 }
126 total = total + 1
127 s_w(" row STRESS: " as *u8); s_n(N); s_w(" rapid 1.3->1.2 Porkbun pings -> HTTP 200 each: " as *u8)
128 s_w("(" as *u8); s_n(ok_count); s_w("/" as *u8); s_n(N); s_w(") " as *u8)
129 if ok_count == N { s_w("OK\n" as *u8); pass[0]=pass[0]+1 } else { s_w("FAIL\n" as *u8) }
130
131 s_w("NX-TLS12-RECONNECT-STRESS rows=" as *u8); s_n(total); s_w(" pass=" as *u8); s_n(pass[0])
132 if pass[0]==total { s_w(" verdict=GREEN\n" as *u8); sys_exit(0); return 0 }
133 s_w(" verdict=RED\n" as *u8); sys_exit(1); return 1
134}