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}