code wiki / _hdl_build / nx_doc_serve_gate.nx

nx_doc_serve_gate.nx source

↩ module page · 145 lines · 7075 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" 24import "nx_gate_verdict.nx" 25 26const DS_LOG: *u8 = "knowledge/status/doc_serve.log" 27 28func 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 } 29func ewn(fd: i64, v: i64) -> i64 { 30 let bb: *u8 = sys_mmap(28); var m: i64 = v 31 if m < 0 { m = 0 - m; sys_write(fd, "-" as *u8, 1) } 32 let t: *u8 = sys_mmap(28); var k: i64 = 0 33 if m == 0 { t[0] = 48; k = 1 } 34 while m > 0 { t[k] = (48 + (m % 10)) as u8; m = m / 10; k = k + 1 } 35 var i: i64 = 0; while i < k { bb[i] = t[k - 1 - i]; i = i + 1 } 36 sys_write(fd, bb, k); return 0 37} 38func streq(a: *u8, b: *u8) -> i64 { 39 var i: i64 = 0 40 while a[i] != (0 as u8) { 41 if a[i] != b[i] { return 0 } 42 i = i + 1 43 } 44 if b[i] != (0 as u8) { return 0 } 45 return 1 46} 47 48func main() -> i64 { 49 var ok: i64 = 1 50 51 // ---- T1: content-type mapping ---- 52 var t1: i64 = 1 53 if streq(nx_doc_content_type(DF_PDF), "application/pdf" as *u8) != 1 { t1 = 0 } 54 if streq(nx_doc_content_type(DF_HTML), "text/html; charset=utf-8" as *u8) != 1 { t1 = 0 } 55 if streq(nx_doc_content_type(DF_TXT), "text/plain; charset=utf-8" as *u8) != 1 { t1 = 0 } 56 if streq(nx_doc_content_type(DF_NXDOC), "application/x-nishi-doc" as *u8) != 1 { t1 = 0 } 57 if streq(nx_doc_content_type(DF_DOCX), "application/vnd.openxmlformats-officedocument.wordprocessingml.document" as *u8) != 1 { t1 = 0 } 58 if streq(nx_doc_content_type(DF_OCTET), "application/octet-stream" as *u8) != 1 { t1 = 0 } 59 if t1 != 1 { ok = 0 } 60 61 // ---- a document body with adversarial bytes (CRLFCRLF + NUL inside) ---- 62 let body: *u8 = sys_mmap(64) 63 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 64 let blen: i64 = 10 65 66 // ---- T2: byte-exact round-trip + corruption detection ---- 67 var t2: i64 = 1 68 let resp: *u8 = sys_mmap(4096) 69 let n2: i64 = nx_doc_serve_response(resp, body, blen, DF_PDF, DISP_INLINE, "x" as *u8) 70 if nx_doc_serve_roundtrip_ok(resp, n2, body, blen) != 1 { t2 = 0 } 71 resp[n2 - 1] = (resp[n2 - 1] ^ 0x20) as u8 72 if nx_doc_serve_roundtrip_ok(resp, n2, body, blen) != 0 { t2 = 0 } 73 resp[n2 - 1] = (resp[n2 - 1] ^ 0x20) as u8 74 if nx_doc_serve_roundtrip_ok(resp, n2, body, blen) != 1 { t2 = 0 } 75 if t2 != 1 { ok = 0 } 76 77 // ---- T3: disposition (open-in-app vs download) ---- 78 var t3: i64 = 1 79 if nx_doc_default_disposition(DF_DOCX) != DISP_ATTACHMENT { t3 = 0 } 80 if nx_doc_default_disposition(DF_PDF) != DISP_INLINE { t3 = 0 } 81 let r3: *u8 = sys_mmap(4096) 82 let n3: i64 = nx_doc_serve_response(r3, body, blen, DF_DOCX, DISP_ATTACHMENT, "estate_plan.docx" as *u8) 83 if nx_doc_serve_contains(r3, n3, "attachment; filename=" as *u8) != 1 { t3 = 0 } 84 if nx_doc_serve_contains(r3, n3, "estate_plan.docx" as *u8) != 1 { t3 = 0 } 85 let r3b: *u8 = sys_mmap(4096) 86 let n3b: i64 = nx_doc_serve_response(r3b, body, blen, DF_PDF, DISP_INLINE, "x" as *u8) 87 if nx_doc_serve_contains(r3b, n3b, "Content-Disposition: inline" as *u8) != 1 { t3 = 0 } 88 if t3 != 1 { ok = 0 } 89 90 // ---- T4: exact Content-Length + nosniff hardening ---- 91 var t4: i64 = 1 92 if nx_doc_serve_contains(r3b, n3b, "Content-Length: 10" as *u8) != 1 { t4 = 0 } 93 if nx_doc_serve_contains(r3b, n3b, "X-Content-Type-Options: nosniff" as *u8) != 1 { t4 = 0 } 94 if t4 != 1 { ok = 0 } 95 96 // ---- T5: a malicious filename cannot inject a header ---- 97 var t5: i64 = 1 98 let r5: *u8 = sys_mmap(4096) 99 let n5: i64 = nx_doc_serve_response(r5, body, blen, DF_DOCX, DISP_ATTACHMENT, "deed\r\nSet-Cookie: evil.docx" as *u8) 100 if nx_doc_serve_roundtrip_ok(r5, n5, body, blen) != 1 { t5 = 0 } 101 if nx_doc_serve_contains(r5, n5, "\r\nSet-Cookie" as *u8) != 0 { t5 = 0 } 102 if t5 != 1 { ok = 0 } 103 104 // ---- T6: unknown format is octet-stream + attachment (never inlined) ---- 105 var t6: i64 = 1 106 if streq(nx_doc_content_type(DF_OCTET), "application/octet-stream" as *u8) != 1 { t6 = 0 } 107 if nx_doc_default_disposition(DF_OCTET) != DISP_ATTACHMENT { t6 = 0 } 108 if t6 != 1 { ok = 0 } 109 110 // ---- T7: per-tenant prefix discipline ---- 111 var t7: i64 = 1 112 if nx_vault_valid_tid("client_andelinwest" as *u8) != 1 { t7 = 0 } 113 if nx_vault_valid_tid("../secret" as *u8) != 0 { t7 = 0 } 114 if nx_vault_valid_tid("a/b" as *u8) != 0 { t7 = 0 } 115 if t7 != 1 { ok = 0 } 116 117 // ---- evidence ---- 118 var fd: i64 = 1 119 while fd >= 1 { 120 ew(fd, "DOCSERVEGATE authored=organ composes=D1 content_type=" as *u8); ewn(fd, t1) 121 ew(fd, " byte_exact_roundtrip=" as *u8); ewn(fd, t2) 122 ew(fd, " disposition_open_in_app=" as *u8); ewn(fd, t3) 123 ew(fd, " length_exact_nosniff=" as *u8); ewn(fd, t4) 124 ew(fd, " filename_injection_safe=" as *u8); ewn(fd, t5) 125 ew(fd, " unknown_safe_default=" as *u8); ewn(fd, t6) 126 ew(fd, " tenant_isolation=" as *u8); ewn(fd, t7) 127 if ok == 1 { ew(fd, " verdict=GREEN\n" as *u8) } else { ew(fd, " verdict=RED\n" as *u8) } 128 if fd == 1 { 129 let lf: i64 = sys_openat_append(DS_LOG, 420) 130 if lf >= 1 { fd = lf } else { fd = 0 } 131 } else { 132 sys_close(fd); fd = 0 133 } 134 } 135 136 // MIGRATED onto nx_gate_verdict by nx_gate_dry_apply (D001, minimal form): every check 137 // row above is untouched, so the PASS/FAIL vector cannot change; only the hand-rolled 138 // verdict emission is replaced by the ONE shared base class. Proven by nx_gate_migrate verify. 139 let ctr__dry: *i64 = gv_ctr() 140 ctr__dry[0] = ok 141 ctr__dry[1] = 1 142 let rc__dry: i64 = gv_verdict("DOC-SERVE-GATE" as *u8, ctr__dry, "teeth unchanged; verdict emission migrated onto the shared base class" as *u8) 143 sys_exit(rc__dry) 144 return rc__dry 145}