code wiki / _hdl_build / nx_aw_sni_router_gate.nx
nx_aw_sni_router_gate.nx source
↩ module page · 92 lines · 5387 B
1import "nx_gate_base.nx"
2// nx_aw_sni_router_gate.nx -- SOVEREIGN offline KAT for the SNI router's routing brain (nx_sni_route). Builds
3// real TLS ClientHellos carrying a known SNI, asserts sni_extract returns that host and sni_backend picks the
4// right port, plus negative controls (non-handshake record, truncation mid-name) that MUST yield 0 (no
5// over-read of untrusted bytes). No network -- pure logic, so it gates the risky parse before it ever faces :443.
6// license_tier: ORIGINAL
7import "nx_syscalls.nx"
8import "nx_sni_route.nx"
9
10func grow(name: *u8, ok: i64) -> i64 { if ok==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8) } gw(name); gw("
11" as *u8); return ok }
12func 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 }
13func g_puti(v: i64) -> i64 {
14 let t: *u8 = sys_mmap(24); var m: i64=v; var k: i64=0
15 if m==0 { t[0]=48 as u8; k=1 } else { while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } }
16 let o: *u8 = sys_mmap(24); var i: i64=0; while i<k { o[i]=t[k-1-i]; i=i+1 } sys_write(1,o,k); return 0
17}
18
19// build a TLS ClientHello carrying SNI=host[0..hlen) into buf; return total byte length
20func mk_ch(buf: *u8, host: *u8, hlen: i64) -> i64 {
21 buf[0]=22 as u8; buf[1]=3 as u8; buf[2]=1 as u8 // record: handshake, TLS1.0 framing
22 buf[5]=1 as u8 // ClientHello
23 buf[9]=3 as u8; buf[10]=3 as u8 // client_version TLS1.2
24 var i: i64=0; while i<32 { buf[11+i]=170 as u8; i=i+1 } // random
25 buf[43]=0 as u8 // session_id_len = 0
26 var q: i64 = 44
27 buf[q]=0 as u8; buf[q+1]=2 as u8; buf[q+2]=19 as u8; buf[q+3]=1 as u8; q=q+4 // cipher_suites: 0x1301
28 buf[q]=1 as u8; buf[q+1]=0 as u8; q=q+2 // compression: 1 method (null)
29 let entrylen: i64 = 3 + hlen // entry_type(1)+name_len(2)+name
30 let listlen: i64 = entrylen
31 let extdata: i64 = 2 + listlen // list_len(2)+list
32 let exttot: i64 = 4 + extdata // ext_type(2)+ext_len(2)+data
33 buf[q]=((exttot>>8)&0xff) as u8; buf[q+1]=(exttot&0xff) as u8; q=q+2 // extensions_len
34 buf[q]=0 as u8; buf[q+1]=0 as u8 // ext type 0x0000 = server_name
35 buf[q+2]=((extdata>>8)&0xff) as u8; buf[q+3]=(extdata&0xff) as u8; q=q+4
36 buf[q]=((listlen>>8)&0xff) as u8; buf[q+1]=(listlen&0xff) as u8; q=q+2
37 buf[q]=0 as u8; q=q+1 // entry type 0 = host_name
38 buf[q]=((hlen>>8)&0xff) as u8; buf[q+1]=(hlen&0xff) as u8; q=q+2
39 var k: i64=0; while k<hlen { buf[q+k]=host[k]; k=k+1 } q=q+hlen
40 let reclen: i64 = q - 5
41 buf[3]=((reclen>>8)&0xff) as u8; buf[4]=(reclen&0xff) as u8
42 let hslen: i64 = q - 9
43 buf[6]=((hslen>>16)&0xff) as u8; buf[7]=((hslen>>8)&0xff) as u8; buf[8]=(hslen&0xff) as u8
44 return q
45}
46
47func streq(a: *u8, an: i64, b: *u8, bn: i64) -> i64 {
48 if an != bn { return 0 }
49 var i: i64=0; while i<an { if a[i]!=b[i] { return 0 } i=i+1 }
50 return 1
51}
52
53// returns 1 on FAIL, 0 on PASS
54func check(host: *u8, expect_port: i64) -> i64 {
55 let buf: *u8 = sys_mmap(1024)
56 let hl: i64 = g_slen(host)
57 let n: i64 = mk_ch(buf, host, hl)
58 let out: *u8 = sys_mmap(256)
59 let el: i64 = sni_extract(buf, n, out, 255)
60 let bp: i64 = sni_backend(out, el)
61 g_puts(" "); sys_write(1, host, hl); g_puts(" -> extracted='")
62 if el>0 { sys_write(1, out, el) }
63 g_puts("' backend="); g_puti(bp); g_puts(" expect="); g_puti(expect_port)
64 if streq(out, el, host, hl) == 1 { if bp == expect_port { g_puts(" OK\n"); return 0 } }
65 g_puts(" FAIL\n"); return 1
66}
67
68func main() -> i64 {
69 var fail: i64 = 0
70 g_puts("== SNI ROUTE KAT ==\n")
71 fail = fail + check("nishifamily.com" as *u8, NX_BK_NISHI)
72 fail = fail + check("www.nishifamily.com" as *u8, NX_BK_NGINX) // exact-apex law: LE cert has no www SAN
73 fail = fail + check("andelinwest.com" as *u8, NX_BK_NISHI) // valid both-SAN cert + static site + /search
74 fail = fail + check("www.andelinwest.com" as *u8, NX_BK_NGINX)
75 fail = fail + check("example.com" as *u8, NX_BK_NGINX) // default: every other vhost stays on nginx
76
77 g_puts("== negative controls ==\n")
78 // NEG1: non-handshake record (b[0]=23 application_data) -> no SNI
79 let nb: *u8 = sys_mmap(64); let nn: i64 = mk_ch(nb, "nishifamily.com" as *u8, 15); nb[0]=23 as u8
80 let o1: *u8 = sys_mmap(64); let e1: i64 = sni_extract(nb, nn, o1, 63)
81 g_puts(" non-handshake -> el="); g_puti(e1); if e1==0 { g_puts(" OK\n") } else { g_puts(" FAIL\n"); fail=fail+1 }
82 // NEG2: truncate 5 bytes into the name -> bounds guard must reject (el=0), no over-read
83 let tb: *u8 = sys_mmap(1024); let tn: i64 = mk_ch(tb, "nishifamily.com" as *u8, 15)
84 let o2: *u8 = sys_mmap(64); let e2: i64 = sni_extract(tb, tn - 5, o2, 63)
85 g_puts(" truncated-name -> el="); g_puti(e2); if e2==0 { g_puts(" OK\n") } else { g_puts(" FAIL\n"); fail=fail+1 }
86 // NEG3: empty buffer
87 let zb: *u8 = sys_mmap(8); let e3: i64 = sni_extract(zb, 0, o2, 63)
88 g_puts(" empty -> el="); g_puti(e3); if e3==0 { g_puts(" OK\n") } else { g_puts(" FAIL\n"); fail=fail+1 }
89
90 if fail == 0 { g_puts("SNI-ROUTE-GATE GREEN\n") } else { g_puts("SNI-ROUTE-GATE RED fails="); g_puti(fail); g_puts("\n") }
91 return fail
92}