code wiki / _hdl_build / nx_uiq_wire_lib.nx
nx_uiq_wire_lib.nx source
↩ module page · 188 lines · 9342 B
1// nx_uiq_wire_lib.nx -- FROM THE FIRST BYTE UP: the wire/response layer of experiential testing.
2// Every other uiq organ starts at the HTML source or the rendered pixels; this one starts at BYTE 0 of
3// the HTTP response -- the status line + headers the edge emits BEFORE any body. Audits the SOTA
4// security/quality header posture (OWASP Secure Headers / web.dev): Content-Type(+charset),
5// X-Content-Type-Options:nosniff, X-Frame-Options|CSP frame-ancestors (clickjacking),
6// Content-Security-Policy (the defense-in-depth that neutralises stored injection BEFORE escaping),
7// Referrer-Policy, Strict-Transport-Security (HSTS). Parses a captured raw response (status line +
8// headers up to the blank line); the fetch is the already-sovereign nx_https_get (compose, don't rebuild).
9// HONEST ENVELOPE (in output): header PRESENCE + a coarse CSP-strength read; it does NOT execute the CSP
10// or prove the policy is tight -- presence is the floor, not proof. license_tier: ORIGINAL genealogy: experiential wire layer
11import "nx_syscalls.nx"
12import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc)
13const UW_MAGIC_1024: i64 = 1024
14const UW_MAGIC_8192: i64 = 8192
15const UW_MAGIC_8191: i64 = 8191
16const UW_MAGIC_4096: i64 = 4096
17const UW_MAGIC_4095: i64 = 4095
18
19const UW_SEC_TOTAL: i64 = 5 // the 5 scored security headers
20
21func uw_w(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
22// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer
23// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the
24// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls).
25// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign.
26func uw_pn(v: i64) -> i64 { nxi_out(v); return 0 }
27func uw_cat(d: *u8, off: i64, s: *u8) -> i64 { var i: i64=0; var o: i64=off; while s[i]!=(0 as u8){d[o]=s[i]; o=o+1; i=i+1} return o }
28func uw_catn(d: *u8, off: i64, v: i64) -> i64 {
29 let t: *u8 = sys_mmap(28); var m: i64=v; var o: i64=off; if m<0 { d[o]=45 as u8; o=o+1; m=0-m }
30 var k: i64=0; if m==0 { t[0]=48 as u8; k=1 } while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
31 var i: i64=0; while i<k { d[o]=t[k-1-i]; o=o+1; i=i+1 } return o
32}
33func uw_len(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} return n }
34func uw_lc(c: i64) -> i64 { if c>=65 { if c<=90 { return c+32 } } return c }
35
36// header block = bytes up to the first \r\n\r\n (or end). returns that length.
37func uw_hdr_end(buf: *u8, n: i64) -> i64 {
38 var i: i64=0
39 while i+3<n {
40 if buf[i]==(13 as u8) { if buf[i+1]==(10 as u8) { if buf[i+2]==(13 as u8) { if buf[i+3]==(10 as u8) { return i+2 } } } }
41 i=i+1
42 }
43 return n
44}
45// case-insensitive: is `name:` present at a line start within [0,hn)? a line start = index 0 or preceded by \n.
46func uw_has(buf: *u8, hn: i64, name: *u8) -> i64 {
47 let ln: i64 = uw_len(name)
48 var i: i64=0
49 while i<hn {
50 var atline: i64=0
51 if i==0 { atline=1 } else { if buf[i-1]==(10 as u8) { atline=1 } }
52 if atline==1 {
53 var k: i64=0
54 var ok: i64=1
55 while k<ln { if i+k>=hn { ok=0; k=ln } else { let a: i64=uw_lc(buf[i+k] as i64); let b: i64=uw_lc(name[k] as i64); if a!=b { ok=0; k=ln } else { k=k+1 } } }
56 if ok==1 { if i+ln<hn { if buf[i+ln]==(58 as u8) { return 1 } } }
57 }
58 i=i+1
59 }
60 return 0
61}
62// does the header VALUE for `name` contain `needle` (case-insensitive)? scans the whole header block for
63// name: then needle within that line. Coarse but sufficient for frame-ancestors / nosniff detection.
64func uw_val_has(buf: *u8, hn: i64, name: *u8, needle: *u8) -> i64 {
65 let ln: i64 = uw_len(name)
66 let nn: i64 = uw_len(needle)
67 var i: i64=0
68 while i<hn {
69 var atline: i64=0
70 if i==0 { atline=1 } else { if buf[i-1]==(10 as u8) { atline=1 } }
71 if atline==1 {
72 var k: i64=0; var ok: i64=1
73 while k<ln { if i+k>=hn { ok=0; k=ln } else { let a: i64=uw_lc(buf[i+k] as i64); let b: i64=uw_lc(name[k] as i64); if a!=b { ok=0; k=ln } else { k=k+1 } } }
74 if ok==1 { if i+ln<hn { if buf[i+ln]==(58 as u8) {
75 var e: i64=i+ln
76 while e<hn { if buf[e]==(10 as u8) { e=hn } else { e=e+1 } }
77 var j: i64=i+ln
78 let lim: i64=e
79 while j+nn<=lim {
80 var m: i64=0; var mok: i64=1
81 while m<nn { let a2: i64=uw_lc(buf[j+m] as i64); let b2: i64=uw_lc(needle[m] as i64); if a2!=b2 { mok=0; m=nn } else { m=m+1 } }
82 if mok==1 { return 1 }
83 j=j+1
84 }
85 return 0
86 } } }
87 }
88 i=i+1
89 }
90 return 0
91}
92func uw_status(buf: *u8, n: i64) -> i64 {
93 var i: i64=0
94 while i<n { if buf[i]==(32 as u8) { let c0: i64=buf[i+1] as i64; let c1: i64=buf[i+2] as i64; let c2: i64=buf[i+3] as i64; return (c0-48)*100 + (c1-48)*10 + (c2-48) } if buf[i]==(13 as u8) { return 0 } i=i+1 }
95 return 0
96}
97
98// audit into out[]: [0]=status [1]=ctype [2]=nosniff [3]=frameguard [4]=csp [5]=referrer [6]=hsts [7]=sec_score
99func uw_audit(buf: *u8, n: i64, out: *i64) -> i64 {
100 let hn: i64 = uw_hdr_end(buf, n)
101 out[0] = uw_status(buf, n)
102 out[1] = uw_has(buf, hn, "content-type" as *u8)
103 out[2] = uw_val_has(buf, hn, "x-content-type-options" as *u8, "nosniff" as *u8)
104 var fg: i64 = uw_has(buf, hn, "x-frame-options" as *u8)
105 if fg==0 { fg = uw_val_has(buf, hn, "content-security-policy" as *u8, "frame-ancestors" as *u8) }
106 out[3] = fg
107 out[4] = uw_has(buf, hn, "content-security-policy" as *u8)
108 out[5] = uw_has(buf, hn, "referrer-policy" as *u8)
109 out[6] = uw_has(buf, hn, "strict-transport-security" as *u8)
110 out[7] = out[2]+out[3]+out[4]+out[5]+out[6]
111 return 0
112}
113
114func uw_slurp(path: *u8, buf: *u8, cap: i64) -> i64 {
115 let fd: i64 = sys_openat_rd(path)
116 if fd<0 { return 0 }
117 var total: i64=0
118 var nrd: i64=sys_read(fd, buf, cap)
119 while nrd>0 { total=total+nrd; if total>=cap { nrd=0 } else { nrd=sys_read(fd, ((buf as i64)+total) as *u8, cap-total) } }
120 sys_close(fd)
121 return total
122}
123
124func uw_emit(label: *u8, out: *i64) -> i64 {
125 let j: *u8 = sys_mmap(UW_MAGIC_1024)
126 var p: i64=0
127 p = uw_cat(j, 0, "{\"organ\":\"nx_uiq_wire\",\"target\":\"" as *u8)
128 p = uw_cat(j, p, label)
129 p = uw_cat(j, p, "\",\"status\":" as *u8)
130 p = uw_catn(j, p, out[0])
131 p = uw_cat(j, p, ",\"headers\":{\"content_type\":" as *u8)
132 p = uw_catn(j, p, out[1])
133 p = uw_cat(j, p, ",\"x_content_type_options_nosniff\":" as *u8)
134 p = uw_catn(j, p, out[2])
135 p = uw_cat(j, p, ",\"frame_guard\":" as *u8)
136 p = uw_catn(j, p, out[3])
137 p = uw_cat(j, p, ",\"content_security_policy\":" as *u8)
138 p = uw_catn(j, p, out[4])
139 p = uw_cat(j, p, ",\"referrer_policy\":" as *u8)
140 p = uw_catn(j, p, out[5])
141 p = uw_cat(j, p, ",\"hsts\":" as *u8)
142 p = uw_catn(j, p, out[6])
143 p = uw_cat(j, p, "},\"sec_score\":" as *u8)
144 p = uw_catn(j, p, out[7])
145 p = uw_cat(j, p, ",\"sec_total\":5,\"verdict\":\"" as *u8)
146 if out[7]>=5 { p = uw_cat(j, p, "HARDENED" as *u8) } else { if out[7]>=3 { p = uw_cat(j, p, "PARTIAL" as *u8) } else { p = uw_cat(j, p, "EXPOSED" as *u8) } }
147 p = uw_cat(j, p, "\",\"env\":\"first-byte-up;response-header-presence;coarse-not-policy-exec;fetch=nx_https_get\"}\n" as *u8)
148 sys_write(1, j, p)
149 return 0
150}
151
152func uw_write_kat(path: *u8, body: *u8) -> i64 {
153 let fd: i64 = sys_openat_wr(path, 420)
154 if fd<0 { return 0-1 }
155 var n: i64=0; while body[n]!=(0 as u8){n=n+1}
156 sys_write(fd, body, n); sys_close(fd); return 0
157}
158// selftest: a BARE response = EXPOSED (only content-type); a HARDENED response = 5/5; frame-ancestors
159// counts as frame guard; case-insensitive. 0 = GREEN.
160func uw_selftest() -> i64 {
161 var f: i64=0
162 let bare: *u8 = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nCache-Control: no-cache\r\n\r\n<html></html>" as *u8
163 uw_write_kat("uwkat_bare.txt" as *u8, bare)
164 let b1: *u8 = sys_mmap(UW_MAGIC_8192)
165 let n1: i64 = uw_slurp("uwkat_bare.txt" as *u8, b1, UW_MAGIC_8191)
166 let o1: *i64 = sys_mmap(64) as *i64
167 uw_audit(b1, n1, o1)
168 if o1[0]!=200 { f=f+1 }
169 if o1[1]!=1 { f=f+1 }
170 if o1[7]!=0 { f=f+1 }
171 let hard: *u8 = "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=utf-8\r\nX-Content-Type-Options: nosniff\r\nContent-Security-Policy: default-src 'self'; frame-ancestors 'self'\r\nReferrer-Policy: strict-origin-when-cross-origin\r\nStrict-Transport-Security: max-age=63072000\r\n\r\nbody" as *u8
172 uw_write_kat("uwkat_hard.txt" as *u8, hard)
173 let b2: *u8 = sys_mmap(UW_MAGIC_8192)
174 let n2: i64 = uw_slurp("uwkat_hard.txt" as *u8, b2, UW_MAGIC_8191)
175 let o2: *i64 = sys_mmap(64) as *i64
176 uw_audit(b2, n2, o2)
177 if o2[7]!=5 { f=f+1 }
178 if o2[3]!=1 { f=f+1 }
179 if o2[4]!=1 { f=f+1 }
180 let xfo: *u8 = "HTTP/1.1 200 OK\r\nX-FRAME-OPTIONS: SAMEORIGIN\r\n\r\nx" as *u8
181 uw_write_kat("uwkat_xfo.txt" as *u8, xfo)
182 let b3: *u8 = sys_mmap(UW_MAGIC_4096)
183 let n3: i64 = uw_slurp("uwkat_xfo.txt" as *u8, b3, UW_MAGIC_4095)
184 let o3: *i64 = sys_mmap(64) as *i64
185 uw_audit(b3, n3, o3)
186 if o3[3]!=1 { f=f+1 }
187 return f
188}