code wiki / _hdl_build / nx_cms_tls_gate.nx

nx_cms_tls_gate.nx source

↩ module page · 464 lines · 22168 B

1// nx_cms_tls_gate.nx -- CMS C8 GATE (re-runnable, evidence-driven): the CMS behind OUR TLS 1.3 2// front, proven with OUR TLS client doing FULL certificate validation. The gate generates a 3// self-signed Ed25519 cert sovereignly (nx_x509_build, the andelinwest daemon's cert shape), makes 4// it the client's ONLY trust anchor, boots the real admin (loopback) behind nx_cms_tls_front (TLS 5// terminator), and walks the admin flow over the encrypted wire: page serve, login (cookie must now 6// carry Secure), editor, edit-publish. NEGATIVE CONTROL: a client with an EMPTY trust store must 7// FAIL the handshake -- proves the validation is real, not pass-through. Appends 8// "CMSGATE row=nx_cms_tls ... verdict=PASS|FAIL". Exit 0 iff all rows pass. license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_connect.nx" // bounded connect: a raw sys_connect hangs ~127s on a black-holed host 11import "nx_csprng.nx" 12import "nx_sha256.nx" 13import "nx_ed25519_signature.nx" 14import "hub/nx_x509_build.nx" 15import "nx_x509.nx" 16import "nx_x509_trust_store.nx" 17import "nx_tls13_client_validate_certificate.nx" 18import "nx_tls13_client_session_run.nx" 19import "nx_tls13_read_record_from_fd.nx" 20import "nx_cms_store.nx" 21import "_hdl_build/nx_kill_portable.nx" 22import "nx_gate_verdict.nx" // D001: inherit the shared verdict contract instead of hand-rolling it 23 24// PORT MOVED 8447 -> 19861 (2026-08-01). ★★8447 IS NOT FREE AND NEVER WAS: it is the LIVE, SUPERVISED 25// nx_translate_daemon (nx_hostctl HC_XLATE, watched by nx_keeper, on the status page, in nx_port_audit). 26// This gate squatted a PRODUCTION service's port from the day it was written, so its front could never 27// bind and every TLS row was red for a reason with nothing to do with TLS. ★A GATE THAT PICKS A PORT BY 28// TASTE INSTEAD OF BY REGISTRY EVENTUALLY PICKS ONE THAT IS ALREADY OWNED -- and then grades the collision 29// as a failure of its subject. 19861 verified unused across a full 21433-file corpus scan. 30const TG_FRONT_PORT: i64 = 19861 31const TG_BACK_PORT: i64 = 8086 32const TG_SITE: *u8 = "/tmp/_cms_tls_site" 33const TG_SNI: *u8 = "cms.gate.local" 34const TG_SNI_N: i64 = 14 35 36func tg_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 tg_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n } 38func tg_cat(dst: *u8, off: i64, s: *u8) -> i64 { 39 var o: i64 = off 40 var k: i64 = 0 41 while s[k] != (0 as u8) { dst[o] = s[k]; o = o + 1; k = k + 1 } 42 return o 43} 44func tg_catn(dst: *u8, off: i64, s: *u8, n: i64) -> i64 { 45 var o: i64 = off 46 var k: i64 = 0 47 while k < n { dst[o] = s[k]; o = o + 1; k = k + 1 } 48 return o 49} 50func tg_index(hay: *u8, n: i64, needle: *u8) -> i64 { 51 let nl: i64 = tg_len(needle) 52 var i: i64 = 0 53 while i + nl <= n { 54 var q: i64 = 0 55 var ok: i64 = 1 56 while q < nl { if (hay[i+q] as i64) != (needle[q] as i64) { ok = 0; q = nl } q = q + 1 } 57 if ok == 1 { return i } 58 i = i + 1 59 } 60 return 0 - 1 61} 62func tg_has(hay: *u8, n: i64, needle: *u8) -> i64 { if tg_index(hay, n, needle) >= 0 { return 1 } return 0 } 63 64func tg_row(id: i64, ok: i64, what: *u8) -> i64 { 65 tg_w("TLSROW " as *u8) 66 let d: *u8 = sys_mmap(8); d[0] = (48 + id/10) as u8; d[1] = (48 + id%10) as u8; d[2] = 32 as u8; d[3] = 0 as u8 67 tg_w(d) 68 if ok == 1 { tg_w("PASS " as *u8) } 69 if ok == 0 { tg_w("FAIL " as *u8) } 70 tg_w(what); tg_w("\n" as *u8) 71 return ok 72} 73 74func tg_mkdir(path: *u8, mode: i64) -> i64 { 75 let nb: *i64 = sys_mmap(8) as *i64 76 nb[0] = 258 77 return __syscall(nb[0], 0 - 100, path, mode, 0, 0, 0) 78} 79 80// build + run a module via the sovereign runner (blocking, output discarded) 81func tg_build(name: *u8) -> i64 { 82 let pid: i64 = sys_fork() 83 if pid == 0 { 84 let dn: i64 = sys_openat_wr("/dev/null" as *u8, 0x1a4) 85 if dn >= 0 { sys_dup3(dn, 1, 0); sys_dup3(dn, 2, 0) } 86 let bargv: *i64 = sys_mmap(32) as *i64 87 bargv[0] = "_offc/nx_sov_build_run.elf" as *u8 as i64 88 bargv[1] = name as i64 89 bargv[2] = 0 90 let benvp: *i64 = sys_mmap(16) as *i64 91 benvp[0] = 0 92 sys_execve("_offc/nx_sov_build_run.elf" as *u8, bargv, benvp); sys_exit(127) 93 } 94 let st: *i64 = sys_mmap(16) as *i64 95 sys_wait4(pid, st, 0) 96 return 0 97} 98 99// one HTTPS request through the front: connect, validated TLS 1.3 handshake, ONE app record out, 100// pump records to close collecting plaintext into resp. Returns resp length, or negative verdict 101// (handshake failure surfaces here -- the negative-control row relies on that). 102func tg_https(store: *TrustStore, req: *u8, rn: i64, resp: *u8, cap: i64) -> i64 { 103 let fd: i64 = sys_socket(2, 1, 0) 104 if fd < 0 { return 0 - 91 } 105 sys_set_socket_timeout(fd, 15) 106 let addr: *u8 = sys_mmap(16) 107 addr[0] = 2 as u8; addr[1] = 0 as u8 108 addr[2] = ((TG_FRONT_PORT >> 8) & 0xff) as u8 109 addr[3] = (TG_FRONT_PORT & 0xff) as u8 110 addr[4] = 127 as u8; addr[5] = 0 as u8; addr[6] = 0 as u8; addr[7] = 1 as u8 111 var zi: i64 = 8 112 while zi < 16 { addr[zi] = 0 as u8; zi = zi + 1 } 113 if nx_connect_bounded(fd, addr, 16, NX_CONN_DEFAULT_MS) < 0 { sys_close(fd); return 0 - 92 } 114 115 let cr: *u8 = sys_mmap(32) 116 let cpriv: *u8 = sys_mmap(32) 117 nx_csprng_fill(cr, 32) 118 nx_csprng_fill(cpriv, 32) 119 let vraw: *u8 = sys_mmap(64) 120 let val_ctx: *TlsValidationContext = vraw as *TlsValidationContext 121 val_ctx.store = store 122 val_ctx.sni_host = TG_SNI 123 val_ctx.sni_host_len = TG_SNI_N 124 val_ctx.now_epoch = sys_now_realtime_sec() 125 let r: i64 = nx_tls13_client_session_run(fd, TG_SNI, TG_SNI_N, cr, cpriv, val_ctx) 126 if r < 0 { sys_close(fd); return r } 127 let s: *Tls13ClientSession = r as *Tls13ClientSession 128 129 // send the request as one application_data record (requests are small) 130 let rec: *u8 = sys_mmap(rn + 64) 131 let v: i64 = nx_tls13_record_encrypt_v2( 132 s.cipher_suite, s.client_app_traffic_key, s.client_app_iv, 133 s.client_app_seq, req, rn, NX_TLS13_CT_APPLICATION_DATA, 0, 134 rec, rec + NX_TLS13_RECORD_HEADER_LEN, rec + NX_TLS13_RECORD_HEADER_LEN + rn + 1) 135 s.client_app_seq = s.client_app_seq + 1 136 if v != NX_TLS13_REC_VERDICT_OK { sys_close(fd); return 0 - 93 } 137 let total: i64 = NX_TLS13_RECORD_HEADER_LEN + rn + 1 + NX_TLS13_RECORD_TAG_LEN 138 var off: i64 = 0 139 while off < total { 140 let w: i64 = sys_write(fd, (rec as i64 + off) as *u8, total - off) 141 if w <= 0 { sys_close(fd); return 0 - 94 } 142 off = off + w 143 } 144 145 // pump response records until close/alert 146 var got: i64 = 0 147 var go: i64 = 1 148 while go == 1 { 149 go = 0 150 let rb: *u8 = sys_mmap(20480) 151 let tn: i64 = nx_tls13_read_record_from_fd(fd, rb, 20480) 152 if tn > 0 { 153 let ct_len: i64 = tn - NX_TLS13_RECORD_HEADER_LEN - NX_TLS13_RECORD_TAG_LEN 154 if ct_len > 0 { 155 let pl: *u8 = sys_mmap(ct_len + 16) 156 let ctp: *i64 = sys_mmap(16) as *i64 157 let lnp: *i64 = sys_mmap(16) as *i64 158 let dv: i64 = nx_tls13_record_decrypt_v2( 159 s.cipher_suite, s.server_app_traffic_key, s.server_app_iv, 160 s.server_app_seq, rb, rb + NX_TLS13_RECORD_HEADER_LEN, ct_len, 161 rb + tn - NX_TLS13_RECORD_TAG_LEN, pl, ctp, lnp) 162 s.server_app_seq = s.server_app_seq + 1 163 if dv == NX_TLS13_REC_VERDICT_OK { 164 if *ctp == NX_TLS13_CT_APPLICATION_DATA { 165 var i: i64 = 0 166 while i < *lnp { if got + i < cap { resp[got + i] = pl[i] } i = i + 1 } 167 got = got + *lnp 168 go = 1 169 } 170 if *ctp != NX_TLS13_CT_APPLICATION_DATA { if *ctp != NX_TLS13_CT_ALERT { go = 1 } } 171 } 172 } 173 } 174 } 175 sys_close(fd) 176 return got 177} 178 179func tg_post(req: *u8, path: *u8, cookie: *u8, body: *u8) -> i64 { 180 var o: i64 = tg_cat(req, 0, "POST " as *u8) 181 o = tg_cat(req, o, path) 182 o = tg_cat(req, o, " HTTP/1.1\r\nHost: cms.gate.local\r\nContent-Type: application/x-www-form-urlencoded\r\n" as *u8) 183 if (cookie[0] as i64) != 0 { 184 o = tg_cat(req, o, "Cookie: nsess=" as *u8) 185 o = tg_catn(req, o, cookie, 32) 186 o = tg_cat(req, o, "\r\n" as *u8) 187 } 188 o = tg_cat(req, o, "Content-Length: " as *u8) 189 let bl: i64 = tg_len(body) 190 let t: *u8 = sys_mmap(24) 191 var m: i64 = bl 192 var k: i64 = 0 193 if m == 0 { t[0] = 48 as u8; k = 1 } 194 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 195 var i: i64 = 0 196 while i < k { req[o] = t[k-1-i]; o = o + 1; i = i + 1 } 197 o = tg_cat(req, o, "\r\n\r\n" as *u8) 198 o = tg_cat(req, o, body) 199 return o 200} 201func tg_get(req: *u8, path: *u8, cookie: *u8) -> i64 { 202 var o: i64 = tg_cat(req, 0, "GET " as *u8) 203 o = tg_cat(req, o, path) 204 o = tg_cat(req, o, " HTTP/1.1\r\nHost: cms.gate.local\r\n" as *u8) 205 if (cookie[0] as i64) != 0 { 206 o = tg_cat(req, o, "Cookie: nsess=" as *u8) 207 o = tg_catn(req, o, cookie, 32) 208 o = tg_cat(req, o, "\r\n" as *u8) 209 } 210 o = tg_cat(req, o, "\r\n" as *u8) 211 return o 212} 213 214func main() -> i64 { 215 // ---- 1. sovereign self-signed Ed25519 cert (the andelinwest daemon's cert shape) ---- 216 let priv: *u8 = sys_mmap(32) 217 let pub: *u8 = sys_mmap(32) 218 nx_csprng_fill(priv, 32) 219 if ed25519_pub_from_priv(priv, pub) != 0 { tg_w("CMSGATE row=nx_cms_tls KEYGEN-FAIL\n" as *u8); sys_exit(1) } 220 let san_ptrs: *i64 = sys_mmap(16) as *i64 221 let san_lens: *i64 = sys_mmap(16) as *i64 222 san_ptrs[0] = TG_SNI as i64 223 san_lens[0] = TG_SNI_N 224 let iraw: *u8 = sys_mmap(256) 225 let inp: *NxX509BuildInputs = iraw as *NxX509BuildInputs 226 let irc: i64 = nx_x509_inputs_init(inp, TG_SNI, TG_SNI_N, san_ptrs, san_lens, 1, 227 priv, pub, "20260101000000Z" as *u8, "20300101000000Z" as *u8, 7) 228 if irc != NX_X509_OK { tg_w("CMSGATE row=nx_cms_tls INPUTS-FAIL\n" as *u8); sys_exit(1) } 229 let cert: *u8 = sys_mmap(4096) 230 let cnb: *i64 = sys_mmap(16) as *i64 231 cnb[0] = 0 232 let brc: i64 = nx_x509_build_self_signed(inp, cert, 4096, cnb) 233 if brc != NX_X509_OK { tg_w("CMSGATE row=nx_cms_tls CERTBUILD-FAIL\n" as *u8); sys_exit(1) } 234 let cert_n: i64 = cnb[0] 235 let cf: i64 = sys_openat_wr("/tmp/_cms_tls_cert.der" as *u8, 0x1a4) 236 sys_write(cf, cert, cert_n) 237 sys_close(cf) 238 let kf: i64 = sys_openat_wr("/tmp/_cms_tls_key.bin" as *u8, 0x180) 239 sys_write(kf, priv, 32) 240 sys_close(kf) 241 242 // ---- 2. trust store: OUR cert is the ONLY anchor ---- 243 let store: *TrustStore = trust_store_alloc(2) 244 let xraw: *u8 = sys_mmap(256) 245 let xc: *X509Cert = xraw as *X509Cert 246 if x509_parse(cert, cert_n, xc) != 0 { tg_w("CMSGATE row=nx_cms_tls SELFPARSE-FAIL\n" as *u8); sys_exit(1) } 247 if trust_store_add(store, cert, xc) != NX_TRUST_STORE_OK { tg_w("CMSGATE row=nx_cms_tls ANCHOR-FAIL\n" as *u8); sys_exit(1) } 248 let empty_store: *TrustStore = trust_store_alloc(1) // the negative control's store 249 250 // ---- 3. site fixture + builds + boots ---- 251 tg_mkdir(TG_SITE, 0x1ed) 252 cst_copy("knowledge/cms/andelinwest/template.html" as *u8, "/tmp/_cms_tls_site/template.html" as *u8) 253 cst_copy("knowledge/cms/andelinwest/content.txt" as *u8, "/tmp/_cms_tls_site/content.txt" as *u8) 254 sys_renameat("/tmp/_cms_tls_site/draft.txt" as *u8, "/tmp/_cms_tls_site/draft.stale" as *u8) 255 let dig: *u8 = sys_mmap(32) 256 sha256_digest("tls-gate-pw-1" as *u8, 13, dig) 257 let hexs: *u8 = sys_mmap(80) 258 let hxc: *u8 = "0123456789abcdef" as *u8 259 var hi: i64 = 0 260 while hi < 32 { 261 hexs[hi*2] = hxc[((dig[hi] as i64) >> 4) & 15] 262 hexs[hi*2+1] = hxc[(dig[hi] as i64) & 15] 263 hi = hi + 1 264 } 265 let pf: i64 = sys_openat_wr("/tmp/_cms_tls_site/admin_pw.sha256" as *u8, 0x1a4) 266 sys_write(pf, hexs, 64) 267 sys_close(pf) 268 tg_build("nx_cms_admin" as *u8) 269 tg_build("nx_cms_tls_front" as *u8) 270 // CALLER-GAP FIX 2026-08-01 (seq1267 class): the runner emits buildroot/_build/<t>.sov.elf under 271 // the no-/tmp doctrine while this probed /tmp. Proven by control: _build copy 208962B, /tmp absent. 272 var bchk: i64 = sys_openat_rd("buildroot/_build/nx_cms_admin.sov.elf" as *u8) 273 var badm: *u8 = "buildroot/_build/nx_cms_admin.sov.elf" as *u8 274 if bchk < 0 { bchk = sys_openat_rd("/tmp/nx_cms_admin.sov.elf" as *u8); badm = "/tmp/nx_cms_admin.sov.elf" as *u8 } 275 if bchk < 0 { tg_w("CMSGATE row=nx_cms_tls ADMIN-BUILD-MISSING (probed buildroot/_build AND /tmp)\n" as *u8); sys_exit(1) } 276 sys_close(bchk) 277 // ★SAME CALLER GAP, SECOND ARTIFACT -- and it only surfaced once the FIRST one was fixed. 278 // This gate builds TWO things (nx_cms_admin and nx_cms_tls_front) and probed /tmp for both; 279 // fixing only the admin probe moved the error from ADMIN-BUILD-MISSING to FRONT-BUILD-MISSING. 280 // ★A DEFECT WITH N INSTANCES IN ONE FILE REVEALS THEM ONE AT A TIME, EACH BEHIND THE LAST -- 281 // so "the fix worked" must mean the gate REACHED ITS SUBJECT, never merely that the message changed. 282 var fchk: i64 = sys_openat_rd("buildroot/_build/nx_cms_tls_front.sov.elf" as *u8) 283 var bfront: *u8 = "buildroot/_build/nx_cms_tls_front.sov.elf" as *u8 284 if fchk < 0 { fchk = sys_openat_rd("/tmp/nx_cms_tls_front.sov.elf" as *u8); bfront = "/tmp/nx_cms_tls_front.sov.elf" as *u8 } 285 if fchk < 0 { tg_w("CMSGATE row=nx_cms_tls FRONT-BUILD-MISSING (probed buildroot/_build AND /tmp)\n" as *u8); sys_exit(1) } 286 sys_close(fchk) 287 288 let pid_admin: i64 = sys_fork() 289 if pid_admin == 0 { 290 let lg: i64 = sys_openat_wr("/tmp/_cms_admin_tls_gate.log" as *u8, 0x1a4) 291 if lg >= 0 { sys_dup3(lg, 1, 0); sys_dup3(lg, 2, 0) } 292 let argvv: *i64 = sys_mmap(8*7) as *i64 293 argvv[0] = badm as i64 294 argvv[1] = "8086" as *u8 as i64 295 argvv[2] = TG_SITE as i64 296 argvv[3] = "99" as *u8 as i64 297 argvv[4] = "tls" as *u8 as i64 298 argvv[5] = 0 299 let envp: *i64 = sys_mmap(16) as *i64 300 envp[0] = 0 301 sys_execve(badm, argvv, envp) 302 sys_exit(127) 303 } 304 let pid_front: i64 = sys_fork() 305 if pid_front == 0 { 306 let lg2: i64 = sys_openat_wr("/tmp/_cms_tls_front_gate.log" as *u8, 0x1a4) 307 if lg2 >= 0 { sys_dup3(lg2, 1, 0); sys_dup3(lg2, 2, 0) } 308 let argvv2: *i64 = sys_mmap(8*8) as *i64 309 argvv2[0] = bfront as i64 310 argvv2[1] = "19861" as *u8 as i64 311 argvv2[2] = "8086" as *u8 as i64 312 argvv2[3] = "/tmp/_cms_tls_cert.der" as *u8 as i64 313 argvv2[4] = "/tmp/_cms_tls_key.bin" as *u8 as i64 314 argvv2[5] = "99" as *u8 as i64 315 argvv2[6] = 0 316 let envp2: *i64 = sys_mmap(16) as *i64 317 envp2[0] = 0 318 sys_execve(bfront, argvv2, envp2) 319 sys_exit(127) 320 } 321 322 let req: *u8 = sys_mmap(65536) 323 let resp: *u8 = sys_mmap(524288) 324 let nocookie: *u8 = sys_mmap(8) 325 nocookie[0] = 0 as u8 326 let sess: *u8 = sys_mmap(64) 327 sess[0] = 0 as u8 328 let csrf: *u8 = sys_mmap(64) 329 csrf[0] = 0 as u8 330 331 // T0: validated HTTPS GET / through the front (boot-poll: handshake fails until both are up) 332 var rn: i64 = 0 - 1 333 var tries: i64 = 0 334 while tries < 60 { 335 let rl0: i64 = tg_get(req, "/" as *u8, nocookie) 336 rn = tg_https(store, req, rl0, resp, 524287) 337 if rn > 0 { tries = 60 } 338 if rn <= 0 { sys_sleep_ms(200); tries = tries + 1 } 339 } 340 // ★★SETUP-FAILED IS NOT A SUBJECT FAILURE -- ADDED 2026-08-01 AFTER THIS GATE LIED BY 4 ROWS. 341 // If the boot-poll never got a single response, the daemons never came up and NOTHING downstream 342 // can be evidence about TLS. Previously the gate ploughed on and reported 1/5: four positive rows 343 // red and the untrusted-anchor row "PASS" -- a NEGATIVE CONTROL THAT PASSES BECAUSE EVERYTHING IS 344 // REFUSED, which cannot tell correct validation from a dead listener. ★A NEG-CONTROL IS ONLY 345 // EVIDENCE WHEN THE POSITIVE PATH WORKS; on a dead subject it is the most dangerous green there is. 346 // MEASURED ROOT CAUSE the first time this fired: both daemon logs said BIND-FAIL -- ports 8086/8447 347 // were still held by ORPHANS from an earlier run that gate_run KILLED ON ITS 12s DEADLINE, so the 348 // gate never reached its own nxk_kill teardown. ★A GATE KILLED BY A DEADLINE SKIPS ITS TEARDOWN AND 349 // ITS ORPHANED DAEMONS POISON EVERY LATER RUN -- run port-binding gates through nx_job_run (uncapped). 350 if rn <= 0 { 351 tg_w("CMSGATE row=nx_cms_tls SETUP-FAILED daemons never served -- NOT a TLS failure. READ THE ERRNO in /tmp/_cms_tls_front_gate.log and /tmp/_cms_admin_tls_gate.log; do NOT assume a cause. 98=EADDRINUSE (something already listens: identify the OWNER before killing anything -- this gate's original port 8447 belonged to the live nx_translate_daemon, and a name-based reaper aimed at it would have killed a supervised production service), 13=EACCES, 99=EADDRNOTAVAIL.\n" as *u8) 352 sys_exit(2) 353 } 354 var pass: i64 = 0 355 var rows: i64 = 0 356 var ok: i64 = 0 357 let ctr: *i64 = gv_ctr() 358 gv_head("nx_cms_tls_gate -- CMS behind a real TLS 1.3 front" as *u8) 359 if rn > 0 { if tg_has(resp, rn, "200 OK" as *u8) == 1 { if tg_has(resp, rn, "Andelin West Law" as *u8) == 1 { ok = 1 } } } 360 rows = rows + 1; pass = pass + tg_row(0, ok, "validated TLS1.3 handshake + proxied GET /" as *u8) 361 gv_check("validated TLS1.3 handshake + proxied GET /" as *u8, ok, ctr) 362 363 // T1: login over TLS -> 303 + Secure cookie 364 var rl: i64 = tg_post(req, "/admin/login" as *u8, nocookie, "pw=tls-gate-pw-1" as *u8) 365 rn = tg_https(store, req, rl, resp, 524287) 366 ok = 0 367 if rn > 0 { if tg_has(resp, rn, "303" as *u8) == 1 { if tg_has(resp, rn, "; Secure" as *u8) == 1 { 368 let sp: i64 = tg_index(resp, rn, "nsess=" as *u8) 369 if sp >= 0 { 370 var m2: i64 = 0 371 while m2 < 32 { sess[m2] = resp[sp+6+m2]; m2 = m2 + 1 } 372 sess[32] = 0 as u8 373 ok = 1 374 } 375 } } } 376 rows = rows + 1; pass = pass + tg_row(1, ok, "login over TLS issues Secure cookie" as *u8) 377 gv_check("login over TLS issues Secure cookie" as *u8, ok, ctr) 378 379 // T2: editor over TLS with the session 380 rl = tg_get(req, "/admin" as *u8, sess) 381 rn = tg_https(store, req, rl, resp, 524287) 382 ok = 0 383 if rn > 0 { if tg_has(resp, rn, "name=\"hero_title\"" as *u8) == 1 { 384 let cp: i64 = tg_index(resp, rn, "name=\"csrf\" value=\"" as *u8) 385 if cp >= 0 { 386 var m3: i64 = 0 387 while m3 < 32 { csrf[m3] = resp[cp+19+m3]; m3 = m3 + 1 } 388 csrf[32] = 0 as u8 389 ok = 1 390 } 391 } } 392 rows = rows + 1; pass = pass + tg_row(2, ok, "editor reached over TLS" as *u8) 393 gv_check("editor reached over TLS" as *u8, ok, ctr) 394 395 // T3: edit-publish over TLS, live page reflects it 396 let body3: *u8 = sys_mmap(4096) 397 var b3: i64 = tg_cat(body3, 0, "csrf=" as *u8) 398 b3 = tg_catn(body3, b3, csrf, 32) 399 b3 = tg_cat(body3, b3, "&hero_title=TLS+Edited+Headline" as *u8) 400 body3[b3] = 0 as u8 401 rl = tg_post(req, "/admin/save" as *u8, sess, body3) 402 rn = tg_https(store, req, rl, resp, 524287) 403 ok = 0 404 if rn > 0 { if tg_has(resp, rn, "303" as *u8) == 1 { 405 let rl3: i64 = tg_get(req, "/" as *u8, nocookie) 406 let rn3: i64 = tg_https(store, req, rl3, resp, 524287) 407 if rn3 > 0 { if tg_has(resp, rn3, "TLS Edited Headline" as *u8) == 1 { ok = 1 } } 408 } } 409 rows = rows + 1; pass = pass + tg_row(3, ok, "edit-publish round trip over TLS" as *u8) 410 gv_check("edit-publish round trip over TLS" as *u8, ok, ctr) 411 412 // T4: NEGATIVE CONTROL -- empty trust store must REFUSE the handshake 413 let rl4: i64 = tg_get(req, "/" as *u8, nocookie) 414 let rn4: i64 = tg_https(empty_store, req, rl4, resp, 524287) 415 ok = 0 416 if rn4 < 0 { ok = 1 } 417 rows = rows + 1; pass = pass + tg_row(4, ok, "untrusted anchor handshake REFUSED (validation real)" as *u8) 418 gv_check("untrusted anchor handshake REFUSED (validation real)" as *u8, ok, ctr) 419 420 // ---- teardown ---- 421 nxk_kill(pid_front, 9) 422 nxk_kill(pid_admin, 9) 423 let stbuf: *i64 = sys_mmap(16) as *i64 424 sys_wait4(pid_front, stbuf, 0) 425 sys_wait4(pid_admin, stbuf, 0) 426 427 var verdict: *u8 = "FAIL" as *u8 428 if pass == rows { verdict = "PASS" as *u8 } 429 let line: *u8 = sys_mmap(512) 430 var lo: i64 = tg_cat(line, 0, "CMSGATE row=nx_cms_tls rows=" as *u8) 431 let t2: *u8 = sys_mmap(24) 432 var mm: i64 = rows 433 var kk: i64 = 0 434 if mm == 0 { t2[0] = 48 as u8; kk = 1 } 435 while mm > 0 { t2[kk] = (48 + (mm % 10)) as u8; mm = mm / 10; kk = kk + 1 } 436 var ii: i64 = 0 437 while ii < kk { line[lo] = t2[kk-1-ii]; lo = lo + 1; ii = ii + 1 } 438 lo = tg_cat(line, lo, " pass=" as *u8) 439 mm = pass; kk = 0 440 if mm == 0 { t2[0] = 48 as u8; kk = 1 } 441 while mm > 0 { t2[kk] = (48 + (mm % 10)) as u8; mm = mm / 10; kk = kk + 1 } 442 ii = 0 443 while ii < kk { line[lo] = t2[kk-1-ii]; lo = lo + 1; ii = ii + 1 } 444 lo = tg_cat(line, lo, " verdict=" as *u8) 445 lo = tg_cat(line, lo, verdict) 446 lo = tg_cat(line, lo, " epoch=" as *u8) 447 mm = sys_now_realtime_sec(); kk = 0 448 if mm == 0 { t2[0] = 48 as u8; kk = 1 } 449 while mm > 0 { t2[kk] = (48 + (mm % 10)) as u8; mm = mm / 10; kk = kk + 1 } 450 ii = 0 451 while ii < kk { line[lo] = t2[kk-1-ii]; lo = lo + 1; ii = ii + 1 } 452 line[lo] = 10 as u8 453 lo = lo + 1 454 sys_write(1, line, lo) 455 let gf: i64 = sys_openat_append("knowledge/status/cms_gate.log" as *u8, 0x1a4) 456 if gf >= 0 { sys_write(gf, line, lo); sys_close(gf) } 457 // D001 MIGRATION 2026-08-01 (hand-migrated: nx_gate_dry_apply SKIPped this gate -- "no verdict=GREEN 458 // tail", the same shape gap that blocked the q4k KAT, so the mechanical remedy could not cover it). 459 // The legacy CMSGATE line above is KEPT because other readers already parse it -- API contract 460 // stability (rule 19): add the new contract first, never break the old one in the same change. 461 let grc: i64 = gv_verdict("cms-tls" as *u8, ctr, "CMS served behind a real validated TLS 1.3 front" as *u8) 462 sys_exit(grc) 463 return grc 464}