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}