code wiki / (root) / nx_content_put_client_gate.nx

nx_content_put_client_gate.nx source

↩ module page · 210 lines · 10555 B

1// nx_content_put_client_gate.nx -- THE GATE FOR THE SOVEREIGN UPLOAD CLIENT, 2026-09-03. 2// 3// SUBJECT: the BUILT nx_content_put_client elf, forked in `dryrun` mode so the JSON-RPC envelope it 4// would put on the wire becomes a deterministic artifact with no socket involved. 5// 6// WHY dryrun IS THE RIGHT SUBJECT. A malformed envelope is rejected by the SERVER, and the server's 7// refusal names neither the client nor the real fault -- it reports a schema or argument error about a 8// request nobody can see. The first draft of CC_PRE carried a DOUBLED "params" key with a four-brace 9// tail that balanced against itself: syntactically valid JSON of entirely the wrong SHAPE. Nothing in a 10// live run would have named that. T2 exists precisely for it. 11// 12// T3 IS AN EXTERNAL KAT, NOT OUR OWN ARITHMETIC. The fixture is the three bytes "abc", whose SHA-256 is 13// published in FIPS 180-2 as ba7816bf...f20015ad. The client computes the digest it sends with our 14// sha256, and the gate compares against the PUBLISHED constant -- so this tooth cannot pass by our 15// implementation agreeing with itself. If our sha256 were wrong, every upload would carry a digest the 16// server would reject at commit, and this is the cheapest possible place to catch that. 17// 18// T6/T7 ARE THE REFUSAL PAIR. T6 requires a destination carrying a double-quote to be REFUSED rather 19// than escaped -- the client's stated design is refuse-never-escape, because a hand-rolled JSON escaper 20// is wrong in exactly the cases nobody tests. On its own T6 would pass on a client that refused 21// everything, so T7 requires a safe destination to be ACCEPTED. 22// 23// Teeth, in order: 24// T1 the envelope's braces and brackets balance, and it ends with the declared tail. 25// T2 "params" appears EXACTLY ONCE (the doubled-key defect that shipped in the first draft). 26// T3 EXTERNAL KAT: the digest sent for "abc" is the FIPS 180-2 published SHA-256. 27// T4 the destination appears verbatim in the envelope. 28// T5 the capability token appears verbatim (a client that dropped it would 401 for the wrong reason). 29// T6 NEG-CONTROL: a destination containing a quote is REFUSED (exit 4), never escaped. 30// T7 POSITIVE CONTROL: a safe destination is ACCEPTED (exit 0), so T6 cannot pass on a client that 31// refuses everything. 32// T8 the argv array's first element is the verb "begin". 33// MEASURED 8/8 GREEN 2026-09-03: braces 3/3, brackets 1/1, params key exactly once, FIPS vector present, 34// quote-in-destination refused at exit 4 with the safe destination accepted at exit 0. 35// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0 36import "nx_syscalls.nx" 37import "nx_gate_verdict.nx" 38import "nx_tool_run.nx" 39 40const CPG_S_A: *u8 = "buildroot/_build/nx_content_put_client.sov.elf" as *u8 41const CPG_S_B: *u8 = "_build/nx_content_put_client.sov.elf" as *u8 42const CPG_S_C: *u8 = "_offc/nx_content_put_client.elf" as *u8 43const CPG_S_D: *u8 = "nx_content_put_client.elf" as *u8 44const CPG_DIR: *u8 = "/tmp/cpcli" as *u8 45const CPG_FIX: *u8 = "/tmp/cpcli/abc.bin" as *u8 46const CPG_CAPF: *u8 = "/tmp/cpcli/cap.txt" as *u8 47const CPG_CAP: i64 = 65536 48const CPG_MODE: i64 = 420 49// FIPS 180-2 published SHA-256 of the three bytes "abc". An EXTERNAL constant on purpose. 50const CPG_KAT: *u8 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" as *u8 51const CPG_DEST: *u8 = "knowledge/fetched/cpcli_probe.bin" as *u8 52const CPG_CAPTOK: *u8 = "tok~1~abcDEF.ghi-jkl" as *u8 53const CPG_URL: *u8 = "https://example.invalid/api/tools/call" as *u8 54const CPG_LBRACE: i64 = 123 55const CPG_RBRACE: i64 = 125 56const CPG_LBRACK: i64 = 91 57const CPG_RBRACK: i64 = 93 58 59func cpg_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 60 61func cpg_count(buf: *u8, n: i64, needle: *u8) -> i64 { 62 let m: i64 = cpg_slen(needle) 63 if m == 0 { return 0 } 64 var i: i64 = 0 65 var c: i64 = 0 66 while i + m <= n { 67 var j: i64 = 0 68 var same: i64 = 1 69 while j < m { 70 if buf[i + j] != needle[j] { same = 0; j = m } else { j = j + 1 } 71 } 72 if same == 1 { c = c + 1 } 73 i = i + 1 74 } 75 return c 76} 77func cpg_has(buf: *u8, n: i64, needle: *u8) -> i64 { 78 if cpg_count(buf, n, needle) > 0 { return 1 } 79 return 0 80} 81func cpg_byte_count(buf: *u8, n: i64, b: i64) -> i64 { 82 var i: i64 = 0 83 var c: i64 = 0 84 while i < n { if buf[i] == (b as u8) { c = c + 1 } i = i + 1 } 85 return c 86} 87func cpg_write_file(path: *u8, buf: *u8, n: i64) -> i64 { 88 let fd: i64 = sys_openat_wr(path, CPG_MODE) 89 if fd < 0 { return 0 - 1 } 90 var off: i64 = 0 91 var go: i64 = 1 92 while go == 1 { 93 if off >= n { go = 0 } else { 94 let w: i64 = sys_write(fd, (buf as i64 + off) as *u8, n - off) 95 if w <= 0 { go = 0 } else { off = off + w } 96 } 97 } 98 sys_close(fd) 99 return off 100} 101func cpg_exists(p: *u8) -> i64 { 102 let fd: i64 = sys_openat_rd(p) 103 if fd < 0 { return 0 } 104 sys_close(fd) 105 return 1 106} 107func cpg_resolve() -> *u8 { 108 if cpg_exists(CPG_S_A) == 1 { return CPG_S_A } 109 if cpg_exists(CPG_S_B) == 1 { return CPG_S_B } 110 if cpg_exists(CPG_S_C) == 1 { return CPG_S_C } 111 if cpg_exists(CPG_S_D) == 1 { return CPG_S_D } 112 return 0 as *u8 113} 114func cpg_run(subj: *u8, dest: *u8, out: *u8, ol: *i64) -> i64 { 115 let av: *i64 = sys_mmap(64) as *i64 116 av[0] = subj as i64 117 av[1] = "dryrun" as i64 118 av[2] = CPG_FIX as i64 119 av[3] = dest as i64 120 av[4] = CPG_CAPF as i64 121 av[5] = CPG_URL as i64 122 av[6] = 0 123 return tr_run_capture(subj, av, out, CPG_CAP, ol) 124} 125 126func main(argc: i64, argv: *i64) -> i64 { 127 let ctr: *i64 = gv_ctr() 128 gv_head("nx_content_put_client gate -- the JSON-RPC envelope, made inspectable so a wrong SHAPE cannot hide behind a server error" as *u8) 129 130 var subj: *u8 = cpg_resolve() 131 if argc > 1 { subj = argv[1] as *u8 } 132 if subj as i64 == 0 { 133 gv_need("a-built-nx_content_put_client-artifact-on-any-known-path" as *u8, 0, ctr) 134 return gv_verdict("content_put_client" as *u8, ctr, "ABSTAINED: no built subject found, so nothing was measured -- a fork of a missing elf exits 127 and would have convicted a subject that never ran" as *u8) 135 } 136 gv_puts(" subject resolved by stat: " as *u8); gv_puts(subj); gv_puts("\n" as *u8) 137 138 sys_mkdir(CPG_DIR, 0x1ff) 139 let abc: *u8 = sys_mmap(16) 140 abc[0] = 97 as u8 141 abc[1] = 98 as u8 142 abc[2] = 99 as u8 143 cpg_write_file(CPG_FIX, abc, 3) 144 cpg_write_file(CPG_CAPF, CPG_CAPTOK, cpg_slen(CPG_CAPTOK)) 145 146 let out: *u8 = sys_mmap(CPG_CAP + 16) 147 let ol: *i64 = sys_mmap(16) as *i64 148 let rc: i64 = cpg_run(subj, CPG_DEST, out, ol) 149 let n: i64 = *ol 150 151 // ---- T1 balance ---- 152 let lb: i64 = cpg_byte_count(out, n, CPG_LBRACE) 153 let rb: i64 = cpg_byte_count(out, n, CPG_RBRACE) 154 let lk: i64 = cpg_byte_count(out, n, CPG_LBRACK) 155 let rk: i64 = cpg_byte_count(out, n, CPG_RBRACK) 156 gv_puts(" [T1] exit=" as *u8); gv_num(rc); gv_puts(" bytes=" as *u8); gv_num(n) 157 gv_puts(" braces " as *u8); gv_num(lb); gv_puts("/" as *u8); gv_num(rb) 158 gv_puts(" brackets " as *u8); gv_num(lk); gv_puts("/" as *u8); gv_num(rk); gv_puts("\n" as *u8) 159 var t1: i64 = 0 160 if rc == 0 { if lb > 0 { if lb == rb { if lk == rk { if lk > 0 { t1 = 1 } } } } } 161 gv_check("the-envelope-braces-and-brackets-BALANCE" as *u8, t1, ctr) 162 163 // ---- T2 the doubled-key defect ---- 164 let np: i64 = cpg_count(out, n, "\x22params\x22" as *u8) 165 gv_puts(" [T2] occurrences of the params key=" as *u8); gv_num(np); gv_puts(" want=1\n" as *u8) 166 gv_check("the-params-key-appears-EXACTLY-ONCE (the first draft doubled it and the four-brace tail balanced against itself -- valid JSON of the wrong SHAPE)" as *u8, (np == 1) as i64, ctr) 167 168 // ---- T3 EXTERNAL KAT ---- 169 let kat: i64 = cpg_has(out, n, CPG_KAT) 170 gv_puts(" [T3] FIPS 180-2 sha256 of abc present in the envelope=" as *u8); gv_num(kat); gv_puts("\n" as *u8) 171 gv_check("EXTERNAL-KAT-the-digest-sent-for-abc-is-the-FIPS-180-2-published-value (so this cannot pass by our sha256 agreeing with itself)" as *u8, kat, ctr) 172 173 // ---- T4 destination ---- 174 let hd: i64 = cpg_has(out, n, CPG_DEST) 175 gv_puts(" [T4] destination present=" as *u8); gv_num(hd); gv_puts("\n" as *u8) 176 gv_check("the-destination-appears-VERBATIM-in-the-envelope" as *u8, hd, ctr) 177 178 // ---- T5 capability token ---- 179 let hc: i64 = cpg_has(out, n, CPG_CAPTOK) 180 gv_puts(" [T5] cap token present=" as *u8); gv_num(hc); gv_puts("\n" as *u8) 181 gv_check("the-capability-token-appears-VERBATIM (a client that dropped it would 401 for a reason naming the wrong subject)" as *u8, hc, ctr) 182 183 // ---- T8 the verb ---- 184 let hv: i64 = cpg_has(out, n, "[\x22begin\x22" as *u8) 185 gv_puts(" [T8] argv opens with the begin verb=" as *u8); gv_num(hv); gv_puts("\n" as *u8) 186 gv_check("the-argv-array-opens-with-the-begin-verb" as *u8, hv, ctr) 187 188 // ---- T9 the idempotency key rides the envelope (DI4, 2026-09-05) ---- 189 let hi9: i64 = cpg_has(out, n, "\x22_idem\x22:\x22cpc-begin-" as *u8) 190 gv_puts(" [T9] _idem key present with the begin stage prefix=" as *u8); gv_num(hi9); gv_puts("\n" as *u8) 191 gv_check("the-envelope-carries-an-idempotency-key-named-for-the-begin-stage (a retry after an Outcome-Unknown is then a transport REPLAY, never a second begin)" as *u8, hi9, ctr) 192 193 // ---- T6 NEG-CONTROL: refuse-never-escape ---- 194 let bad: *u8 = sys_mmap(128) 195 bad[0] = 107 as u8 196 bad[1] = 34 as u8 197 bad[2] = 120 as u8 198 bad[3] = 0 as u8 199 let out2: *u8 = sys_mmap(CPG_CAP + 16) 200 let ol2: *i64 = sys_mmap(16) as *i64 201 let rc6: i64 = cpg_run(subj, bad, out2, ol2) 202 gv_puts(" [T6] destination containing a quote -> exit=" as *u8); gv_num(rc6); gv_puts(" want=4\n" as *u8) 203 gv_check("neg-control-a-destination-carrying-a-quote-is-REFUSED-not-escaped (a hand-rolled escaper is wrong in exactly the cases nobody tests)" as *u8, (rc6 == 4) as i64, ctr) 204 205 // ---- T7 POSITIVE CONTROL ---- 206 gv_puts(" [T7] safe destination -> exit=" as *u8); gv_num(rc); gv_puts(" want=0\n" as *u8) 207 gv_check("POSITIVE-CONTROL-a-safe-destination-is-ACCEPTED (without this T6 passes on a client that refuses everything)" as *u8, (rc == 0) as i64, ctr) 208 209 return gv_verdict("content_put_client" as *u8, ctr, "the sovereign upload envelope proven inspectable and correctly shaped, with the digest checked against the FIPS 180-2 published vector rather than against our own sha256, and refuse-never-escape carrying a positive control" as *u8) 210}