code wiki / _hdl_build / nx_docportal_authz_route_gate.nx
nx_docportal_authz_route_gate.nx source
↩ module page · 155 lines · 9050 B
1// nx_docportal_authz_route_gate.nx -- MEASURED end-to-end proof that the P2 wiring fired at the REAL da_handle
2// routes: it drives the pure router with per-session DaCtx (carrying the subject the daemon sets from
3// nx_sa_validate_handle) and inspects the sovereign store + the route responses. Fresh nonce domain per run.
4// T1 session A POST /admin/upload visibility=private -> 200 UPLOADED, and own:<cid> == A (ownership recorded).
5// T2 session A GET /admin/doc?cid= -> 200 + the DECRYPTED plaintext (owner reads through authz + at-rest decrypt).
6// T3 session B GET /admin/doc?cid= (same doc) -> 403 Forbidden (non-owner eyes-only DENY).
7// T4 session A POST /admin/upload visibility=public -> 200 UPLOADED + stored PLAINTEXT (public path unchanged).
8// Print pass=4 + GREEN/RED, append knowledge/status/dp_authz_route_gate.log. STANDALONE -- no socket/daemon/deploy.
9// (nx_chacha20_poly1305_decrypt prints one 'A' to STDERR on first decrypt -- shipped-AEAD marker; harmless.)
10// license_tier: ORIGINAL
11import "nx_docportal_admin_lib.nx" // da_handle + DaCtx (the wired routes)
12import "nx_doc_authz.nx" // authz_get_owner (verify recorded ownership)
13import "nx_doc_at_rest.nx" // at_is_magic (verify public stays plaintext)
14import "nx_docportal_lib.nx" // dp_cid / dp_prefix / dp_key / DP_VIS_* + ss_open/ss_hget
15
16func g_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
17func g_num(v: i64) -> i64 {
18 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m; sys_write(1, "-" as *u8, 1) }
19 let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
20 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
21 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(1, bb, k); return 0
22}
23func g_w(fd: i64, s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(fd, s, n); return 0 }
24func g_wn(fd: i64, v: i64) -> i64 {
25 let bb: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }
26 let t: *u8 = sys_mmap(28); var k: i64 = 0; if m == 0 { t[0] = 48 as u8; k = 1 }
27 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
28 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } sys_write(fd, bb, k); return 0
29}
30func g_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
31func g_cat(out: *u8, o: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { out[o] = s[i]; o = o + 1; i = i + 1 } return o }
32func g_catnum(out: *u8, o: i64, v: i64) -> i64 {
33 if v == 0 { out[o] = 48 as u8; return o + 1 }
34 var m: i64 = v; let t: *u8 = sys_mmap(28); var k: i64 = 0
35 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
36 var i: i64 = 0; while i < k { out[o] = t[k - 1 - i]; o = o + 1; i = i + 1 } return o
37}
38func g_eqbytes(a: *u8, b: *u8, n: i64) -> i64 { var i: i64 = 0; while i < n { if a[i] != b[i] { return 0 } i = i + 1 } return 1 }
39func g_starts(buf: *u8, n: i64, s: *u8) -> i64 { let sn: i64 = g_slen(s); if n < sn { return 0 } var i: i64 = 0; while i < sn { if buf[i] != s[i] { return 0 } i = i + 1 } return 1 }
40func g_contains(hay: *u8, hn: i64, ndl: *u8) -> i64 {
41 let nl: i64 = g_slen(ndl); if nl == 0 { return 0 }
42 if hn < nl { return 0 }
43 var i: i64 = 0
44 while i + nl <= hn {
45 var j: i64 = 0; var hit: i64 = 1
46 while j < nl { if hay[i + j] != ndl[j] { hit = 0; j = nl } else { j = j + 1 } }
47 if hit == 1 { return 1 }
48 i = i + 1
49 }
50 return 0
51}
52
53func main() -> i64 {
54 g_puts("=== DOCPORTAL AUTHZ ROUTE GATE (wired da_handle: private upload->owner->read; other session->403) ===\n" as *u8)
55 let nonce: i64 = sys_now_realtime_sec()
56 let dom: *u8 = sys_mmap(64)
57 var dn: i64 = g_cat(dom, 0, "dpwireauthz" as *u8); dn = g_catnum(dom, dn, nonce); dom[dn] = 0 as u8
58
59 let subjA: *u8 = "SESSIONA-uid-aaaa" as *u8
60 let subjB: *u8 = "SESSIONB-uid-bbbb" as *u8
61 let dctxA: *DaCtx = sys_mmap(16) as *DaCtx
62 dctxA.user_level = 2
63 dctxA.subject = subjA
64 let dctxB: *DaCtx = sys_mmap(16) as *DaCtx
65 dctxB.user_level = 2
66 dctxB.subject = subjB
67
68 let req: *u8 = sys_mmap(8192)
69 let out: *u8 = sys_mmap(524288)
70 let pq: *i64 = sys_mmap(16) as *i64
71 let lq: *i64 = sys_mmap(16) as *i64
72
73 let ptConf: *u8 = "WIRE-AUTHZ-CANARY eyes-only client vault document via the live route." as *u8
74 let ptConfLen: i64 = g_slen(ptConf)
75 let cidConf: i64 = dp_cid(ptConf, ptConfLen)
76
77 var pass: i64 = 0
78
79 // T1: session A private upload -> 200 UPLOADED + ownership recorded == A
80 var r: i64 = g_cat(req, 0, "POST /admin/upload?domain=" as *u8)
81 r = g_cat(req, r, dom)
82 r = g_cat(req, r, "&visibility=private HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
83 r = g_cat(req, r, ptConf)
84 let resp1: i64 = da_handle(dctxA, req, r, out)
85 let ownbuf: *u8 = sys_mmap(256)
86 let ownlen: i64 = authz_get_owner(dom, DP_VIS_PRIVATE, cidConf, ownbuf, 255)
87 var t1: i64 = 0
88 if g_starts(out, resp1, "HTTP/1.1 200" as *u8) == 1 { if g_contains(out, resp1, "UPLOADED" as *u8) == 1 {
89 if ownlen == g_slen(subjA) { if g_eqbytes(ownbuf, subjA, ownlen) == 1 { t1 = 1 } }
90 } }
91 pass = pass + t1
92 g_puts(" T1 A private upload -> 200 + own:<cid>==A (ownlen=" as *u8); g_num(ownlen); g_puts("): " as *u8)
93 if t1 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
94
95 // T2: session A GET /admin/doc?cid= -> 200 + decrypted plaintext
96 var r2: i64 = g_cat(req, 0, "GET /admin/doc?domain=" as *u8)
97 r2 = g_cat(req, r2, dom)
98 r2 = g_cat(req, r2, "&cid=" as *u8)
99 r2 = g_catnum(req, r2, cidConf)
100 r2 = g_cat(req, r2, " HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
101 let resp2: i64 = da_handle(dctxA, req, r2, out)
102 var t2: i64 = 0
103 if g_starts(out, resp2, "HTTP/1.1 200" as *u8) == 1 { if g_contains(out, resp2, "WIRE-AUTHZ-CANARY" as *u8) == 1 { t2 = 1 } }
104 pass = pass + t2
105 g_puts(" T2 A reads own doc -> 200 + decrypted plaintext: " as *u8)
106 if t2 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
107
108 // T3: session B GET the SAME doc -> 403 (non-owner denied). Reuse the identical request bytes, dctxB.
109 var r3: i64 = g_cat(req, 0, "GET /admin/doc?domain=" as *u8)
110 r3 = g_cat(req, r3, dom)
111 r3 = g_cat(req, r3, "&cid=" as *u8)
112 r3 = g_catnum(req, r3, cidConf)
113 r3 = g_cat(req, r3, " HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
114 let resp3: i64 = da_handle(dctxB, req, r3, out)
115 var t3: i64 = 0
116 if g_starts(out, resp3, "HTTP/1.1 403" as *u8) == 1 { t3 = 1 }
117 pass = pass + t3
118 g_puts(" T3 B reads A's doc -> 403 Forbidden (eyes-only deny): " as *u8)
119 if t3 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
120
121 // T4: public path unchanged -- A public upload -> 200 UPLOADED + stored PLAINTEXT (no NXENC1 magic)
122 let ptPub: *u8 = "WIRE-AUTHZ-PUBLIC corpus article, no restriction." as *u8
123 let ptPubLen: i64 = g_slen(ptPub)
124 let cidPub: i64 = dp_cid(ptPub, ptPubLen)
125 var r4: i64 = g_cat(req, 0, "POST /admin/upload?domain=" as *u8)
126 r4 = g_cat(req, r4, dom)
127 r4 = g_cat(req, r4, "&visibility=public&pub_search=1 HTTP/1.1\r\nHost: x\r\n\r\n" as *u8)
128 r4 = g_cat(req, r4, ptPub)
129 let resp4: i64 = da_handle(dctxA, req, r4, out)
130 let prefixPub: *u8 = sys_mmap(512); dp_prefix(dom, DP_VIS_PUBLIC, prefixPub)
131 let dkeyPub: *u8 = sys_mmap(64); dp_key(cidPub, dkeyPub)
132 var pubPlain: i64 = 0
133 let hPub: *i64 = ss_open(prefixPub)
134 if (hPub as i64) != 0 { if ss_hget(hPub, dkeyPub, pq, lq) == 1 {
135 let pvp: *u8 = pq[0] as *u8; let pvl: i64 = lq[0]
136 if at_is_magic(pvp, pvl) == 0 { if pvl == ptPubLen { if g_eqbytes(pvp, ptPub, ptPubLen) == 1 { pubPlain = 1 } } }
137 } }
138 var t4: i64 = 0
139 if g_starts(out, resp4, "HTTP/1.1 200" as *u8) == 1 { if g_contains(out, resp4, "UPLOADED" as *u8) == 1 { if pubPlain == 1 { t4 = 1 } } }
140 pass = pass + t4
141 g_puts(" T4 A public upload -> 200 + stored PLAINTEXT (public unchanged, plain=" as *u8); g_num(pubPlain); g_puts("): " as *u8)
142 if t4 == 1 { g_puts("PASS\n" as *u8) } else { g_puts("FAIL\n" as *u8) }
143
144 g_puts("----\nDP-AUTHZ-ROUTE rows=4 pass=" as *u8); g_num(pass); g_puts("\n" as *u8)
145 let lg: i64 = sys_openat_append("knowledge/status/dp_authz_route_gate.log" as *u8, 0x1a4)
146 if lg >= 0 {
147 g_w(lg, "DP-AUTHZ-ROUTE own_recorded=" as *u8); g_wn(lg, t1); g_w(lg, " owner_read=" as *u8); g_wn(lg, t2)
148 g_w(lg, " other_403=" as *u8); g_wn(lg, t3); g_w(lg, " public_plaintext=" as *u8); g_wn(lg, t4)
149 g_w(lg, " rows=4 pass=" as *u8); g_wn(lg, pass)
150 if pass == 4 { g_w(lg, " verdict=GREEN\n" as *u8) } else { g_w(lg, " verdict=RED\n" as *u8) }
151 sys_close(lg)
152 }
153 if pass == 4 { g_puts("DP-AUTHZ-ROUTE GREEN (wired route: owner records + reads decrypted, non-owner 403, public plaintext -- measured)\n" as *u8); sys_exit(0); return 0 }
154 g_puts("DP-AUTHZ-ROUTE RED\n" as *u8); sys_exit(1); return 1
155}