code wiki / _hdl_build / nx_doc_serve_gate.nx
nx_doc_serve_gate.nx source
↩ module page · 137 lines · 6540 B
1// nx_doc_serve_gate.nx -- GATE for LEGAL D3 (nx_doc_serve).
2//
3// Asserts the open-in-app-of-choice serve invariants, each w/ a negative control:
4// T1 CONTENT-TYPE : every format maps to its exact MIME (browser opens the
5// right app).
6// T2 BYTE-EXACT : a body that itself contains CRLFCRLF + NUL round-trips
7// bit-for-bit (Content-Length framed); flipping one body
8// byte is detected.
9// T3 DISPOSITION : DOCX defaults to download (open in Word), PDF inline;
10// the attachment response carries the filename.
11// T4 LENGTH+HARDENING : Content-Length is exact + X-Content-Type-Options:nosniff
12// present (no MIME-sniff of a legal doc).
13// T5 INJECTION-SAFE : a "name\r\nSet-Cookie: ..." filename cannot inject a
14// header -- framing intact AND the CRLF is stripped.
15// T6 SAFE-BY-DEFAULT : an unknown format is octet-stream + attachment (never
16// inlined).
17// T7 TENANT ISOLATION : the vault prefix discipline rejects '.'/'/' tenant ids.
18//
19// Evidence -> knowledge/status/doc_serve.log
20// license_tier: ORIGINAL
21import "nx_doc_serve.nx"
22import "nx_doc_vault.nx"
23import "nx_syscalls.nx"
24
25const DS_LOG: *u8 = "knowledge/status/doc_serve.log"
26
27func ew(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 }
28func ewn(fd: i64, v: i64) -> i64 {
29 let bb: *u8 = sys_mmap(28); var m: i64 = v
30 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) }
31 let t: *u8 = sys_mmap(28); var k: i64 = 0
32 if m == 0 { t[0] = 48; k = 1 }
33 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 }
34 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 }
35 sys_write(fd, bb, k); return 0
36}
37func streq(a: *u8, b: *u8) -> i64 {
38 var i: i64 = 0
39 while a[i] != (0 as u8) {
40 if a[i] != b[i] { return 0 }
41 i = i + 1
42 }
43 if b[i] != (0 as u8) { return 0 }
44 return 1
45}
46
47func main() -> i64 {
48 var ok: i64 = 1
49
50 // ---- T1: content-type mapping ----
51 var t1: i64 = 1
52 if streq(nx_doc_content_type(DF_PDF), "application/pdf" as *u8) != 1 { t1 = 0 }
53 if streq(nx_doc_content_type(DF_HTML), "text/html; charset=utf-8" as *u8) != 1 { t1 = 0 }
54 if streq(nx_doc_content_type(DF_TXT), "text/plain; charset=utf-8" as *u8) != 1 { t1 = 0 }
55 if streq(nx_doc_content_type(DF_NXDOC), "application/x-nishi-doc" as *u8) != 1 { t1 = 0 }
56 if streq(nx_doc_content_type(DF_DOCX), "application/vnd.openxmlformats-officedocument.wordprocessingml.document" as *u8) != 1 { t1 = 0 }
57 if streq(nx_doc_content_type(DF_OCTET), "application/octet-stream" as *u8) != 1 { t1 = 0 }
58 if t1 != 1 { ok = 0 }
59
60 // ---- a document body with adversarial bytes (CRLFCRLF + NUL inside) ----
61 let body: *u8 = sys_mmap(64)
62 body[0]=72; body[1]=105; body[2]=13; body[3]=10; body[4]=13; body[5]=10; body[6]=0; body[7]=66; body[8]=121; body[9]=101
63 let blen: i64 = 10
64
65 // ---- T2: byte-exact round-trip + corruption detection ----
66 var t2: i64 = 1
67 let resp: *u8 = sys_mmap(4096)
68 let n2: i64 = nx_doc_serve_response(resp, body, blen, DF_PDF, DISP_INLINE, "x" as *u8)
69 if nx_doc_serve_roundtrip_ok(resp, n2, body, blen) != 1 { t2 = 0 }
70 resp[n2 - 1] = (resp[n2 - 1] ^ 0x20) as u8
71 if nx_doc_serve_roundtrip_ok(resp, n2, body, blen) != 0 { t2 = 0 }
72 resp[n2 - 1] = (resp[n2 - 1] ^ 0x20) as u8
73 if nx_doc_serve_roundtrip_ok(resp, n2, body, blen) != 1 { t2 = 0 }
74 if t2 != 1 { ok = 0 }
75
76 // ---- T3: disposition (open-in-app vs download) ----
77 var t3: i64 = 1
78 if nx_doc_default_disposition(DF_DOCX) != DISP_ATTACHMENT { t3 = 0 }
79 if nx_doc_default_disposition(DF_PDF) != DISP_INLINE { t3 = 0 }
80 let r3: *u8 = sys_mmap(4096)
81 let n3: i64 = nx_doc_serve_response(r3, body, blen, DF_DOCX, DISP_ATTACHMENT, "estate_plan.docx" as *u8)
82 if nx_doc_serve_contains(r3, n3, "attachment; filename=" as *u8) != 1 { t3 = 0 }
83 if nx_doc_serve_contains(r3, n3, "estate_plan.docx" as *u8) != 1 { t3 = 0 }
84 let r3b: *u8 = sys_mmap(4096)
85 let n3b: i64 = nx_doc_serve_response(r3b, body, blen, DF_PDF, DISP_INLINE, "x" as *u8)
86 if nx_doc_serve_contains(r3b, n3b, "Content-Disposition: inline" as *u8) != 1 { t3 = 0 }
87 if t3 != 1 { ok = 0 }
88
89 // ---- T4: exact Content-Length + nosniff hardening ----
90 var t4: i64 = 1
91 if nx_doc_serve_contains(r3b, n3b, "Content-Length: 10" as *u8) != 1 { t4 = 0 }
92 if nx_doc_serve_contains(r3b, n3b, "X-Content-Type-Options: nosniff" as *u8) != 1 { t4 = 0 }
93 if t4 != 1 { ok = 0 }
94
95 // ---- T5: a malicious filename cannot inject a header ----
96 var t5: i64 = 1
97 let r5: *u8 = sys_mmap(4096)
98 let n5: i64 = nx_doc_serve_response(r5, body, blen, DF_DOCX, DISP_ATTACHMENT, "deed\r\nSet-Cookie: evil.docx" as *u8)
99 if nx_doc_serve_roundtrip_ok(r5, n5, body, blen) != 1 { t5 = 0 }
100 if nx_doc_serve_contains(r5, n5, "\r\nSet-Cookie" as *u8) != 0 { t5 = 0 }
101 if t5 != 1 { ok = 0 }
102
103 // ---- T6: unknown format is octet-stream + attachment (never inlined) ----
104 var t6: i64 = 1
105 if streq(nx_doc_content_type(DF_OCTET), "application/octet-stream" as *u8) != 1 { t6 = 0 }
106 if nx_doc_default_disposition(DF_OCTET) != DISP_ATTACHMENT { t6 = 0 }
107 if t6 != 1 { ok = 0 }
108
109 // ---- T7: per-tenant prefix discipline ----
110 var t7: i64 = 1
111 if nx_vault_valid_tid("client_andelinwest" as *u8) != 1 { t7 = 0 }
112 if nx_vault_valid_tid("../secret" as *u8) != 0 { t7 = 0 }
113 if nx_vault_valid_tid("a/b" as *u8) != 0 { t7 = 0 }
114 if t7 != 1 { ok = 0 }
115
116 // ---- evidence ----
117 var fd: i64 = 1
118 while fd >= 1 {
119 ew(fd, "DOCSERVEGATE authored=organ composes=D1 content_type=" as *u8); ewn(fd, t1)
120 ew(fd, " byte_exact_roundtrip=" as *u8); ewn(fd, t2)
121 ew(fd, " disposition_open_in_app=" as *u8); ewn(fd, t3)
122 ew(fd, " length_exact_nosniff=" as *u8); ewn(fd, t4)
123 ew(fd, " filename_injection_safe=" as *u8); ewn(fd, t5)
124 ew(fd, " unknown_safe_default=" as *u8); ewn(fd, t6)
125 ew(fd, " tenant_isolation=" as *u8); ewn(fd, t7)
126 if ok == 1 { ew(fd, " verdict=GREEN\n" as *u8) } else { ew(fd, " verdict=RED\n" as *u8) }
127 if fd == 1 {
128 let lf: i64 = sys_openat_append(DS_LOG, 420)
129 if lf >= 1 { fd = lf } else { fd = 0 }
130 } else {
131 sys_close(fd); fd = 0
132 }
133 }
134
135 if ok == 1 { return 0 }
136 return 1
137}