code wiki / (root) / nx_stun_gate.nx

nx_stun_gate.nx source

↩ module page · 122 lines · 6206 B

1// nx_stun_gate.nx -- KAT the sovereign STUN codec BYTE-EXACT against the IETF's own RFC 5769 test vectors. 2// If GREEN, our NishiLang STUN implementation interoperates with the real protocol from the first byte up: 3// T1 CRC-32 check value: crc32("123456789") == 0xCBF43926 (proves our CRC-32 vs the standard check) 4// T2 XOR-MAPPED-ADDRESS DECODE of the RFC 5769 2.2 sample response -> IPv4 192.0.2.1 : 32853 5// T3 XOR-MAPPED-ADDRESS ENCODE of 192.0.2.1:32853 -> the exact 8 attribute bytes in the sample 6// T4 FINGERPRINT: CRC-32(first 72 bytes) XOR 0x5354554E == the sample's 0xB5BE215B 7// T5 MESSAGE-INTEGRITY: HMAC-SHA1(password, first 48 bytes w/ len field 0x0034) == the sample's 20 bytes 8// T6 header build+parse round-trip for a Binding Request 9// license_tier: ORIGINAL expect_exit: 0 10import "nx_syscalls.nx" 11import "nx_stun.nx" 12 13func gw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 } 14func gn(v: i64) -> i64 { 15 let b: *u8=sys_mmap(28); var m: i64=v; if m<0 {sys_write(1,"-" as *u8,1); m=0-m} 16 let t: *u8=sys_mmap(28); 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} 17 var i: i64=0; while i<k {b[i]=t[k-1-i];i=i+1} sys_write(1,b,k); return 0 18} 19func gx(v: i64) -> i64 { 20 gw("0x" as *u8); let d: *u8="0123456789abcdef" as *u8; let b: *u8=sys_mmap(16); var i: i64=7 21 while i>=0 { b[7-i]=d[(v>>(i*4))&0xf]; i=i-1 } sys_write(1,b,8); return 0 22} 23func gck(pass: i64, name: *u8, fails: *i64) -> i64 { 24 if pass==1 { gw(" PASS " as *u8) } else { gw(" FAIL " as *u8); fails[0]=fails[0]+1 } 25 gw(name); gw("\n" as *u8); return 0 26} 27func hxv(c: i64) -> i64 { 28 if c>=48 { if c<=57 { return c-48 } } 29 if c>=97 { if c<=102 { return c-87 } } 30 if c>=65 { if c<=70 { return c-55 } } 31 return 0 32} 33func hexdec(hex: *u8, nbytes: i64, out: *u8) -> i64 { 34 var i: i64=0 35 while i<nbytes { out[i]=((hxv(hex[i*2] as i64)<<4) | hxv(hex[i*2+1] as i64)) as u8; i=i+1 } 36 return 0 37} 38func beq(a: *u8, b: *u8, n: i64) -> i64 { var i: i64=0; while i<n { if a[i]!=b[i] { return 0 } i=i+1 } return 1 } 39 40func main() -> i64 { 41 let fails: *i64 = sys_mmap(16) as *i64 42 fails[0]=0 43 gw("=== nx_stun_gate -- sovereign STUN codec vs RFC 5769 test vectors ===\n" as *u8) 44 45 // ---- the RFC 5769 2.2 "Sample IPv4 Response" -- 80 bytes, verbatim from RFC 5769 (fetched authoritative) ---- 46 let msg: *u8 = sys_mmap(128) 47 hexdec("0101003c2112a442b7e7a701bc34d686fa87dfae8022000b7465737420766563746f7220002000080001a147e112a643000800142b91f599fd9e90c38c7489f92af9ba53f06be7d780280004c07d4c96" as *u8, 80, msg) 48 49 // sanity: it parses as a Binding Response with the right magic + length 50 var t0: i64 = 1 51 if st_type(msg)!=STUN_BINDING_RESPONSE { t0=0 } 52 if st_magic(msg)!=STUN_MAGIC { t0=0 } 53 if st_len(msg)!=0x3c { t0=0 } 54 gck(t0, "T0 header parse: Binding Response, magic 0x2112A442, length 0x3C" as *u8, fails) 55 56 // ---- T1: CRC-32 check value ---- 57 var t1: i64 = 1 58 let cv: i64 = nx_crc32("123456789" as *u8, 9) 59 if cv != 0xCBF43926 { t1=0 } 60 gw(" [measure] crc32(\"123456789\")=" as *u8); gx(cv); gw(" (RFC-standard check 0xCBF43926)\n" as *u8) 61 gck(t1, "T1 CRC-32 check value == 0xCBF43926" as *u8, fails) 62 63 // ---- T2: XOR-MAPPED-ADDRESS DECODE (attribute value at bytes 40..48) ---- 64 let xma: *u8 = (msg as i64 + 40) as *u8 65 var t2: i64 = 1 66 if st_xma_family(xma)!=1 { t2=0 } // IPv4 67 let port: i64 = st_xma_port(xma) 68 let addr: i64 = st_xma_addr(xma) 69 if port != 32853 { t2=0 } 70 if addr != 0xC0000201 { t2=0 } // 192.0.2.1 71 gw(" [measure] mapped = " as *u8); gn((addr>>24)&0xff); gw("." as *u8); gn((addr>>16)&0xff); gw("." as *u8); gn((addr>>8)&0xff); gw("." as *u8); gn(addr&0xff); gw(":" as *u8); gn(port); gw("\n" as *u8) 72 gck(t2, "T2 XOR-MAPPED-ADDRESS decode -> 192.0.2.1:32853" as *u8, fails) 73 74 // ---- T3: XOR-MAPPED-ADDRESS ENCODE round-trips to the exact sample bytes ---- 75 var t3: i64 = 1 76 let enc: *u8 = sys_mmap(16) 77 st_xma_encode(enc, 32853, 0xC0000201) 78 if beq(enc, xma, 8)==0 { t3=0 } 79 gck(t3, "T3 XOR-MAPPED-ADDRESS encode(192.0.2.1:32853) == the sample's 8 bytes" as *u8, fails) 80 81 // ---- T4: FINGERPRINT over the first 72 bytes == sample's value (bytes 76..80) ---- 82 var t4: i64 = 1 83 let fp: i64 = st_fingerprint(msg, 72) 84 let fp_exp: i64 = st_get32(msg, 76) 85 if fp != fp_exp { t4=0 } 86 if fp != 0xC07D4C96 { t4=0 } 87 gw(" [measure] fingerprint=" as *u8); gx(fp); gw(" (RFC 0xC07D4C96)\n" as *u8) 88 gck(t4, "T4 FINGERPRINT CRC-32 XOR 0x5354554E == 0xC07D4C96" as *u8, fails) 89 90 // ---- T5: MESSAGE-INTEGRITY == sample's 20 bytes (bytes 52..72). HMAC-SHA1 over bytes 0..48 with the 91 // header length field temporarily set to 0x0034 (length up to and including MESSAGE-INTEGRITY). ---- 92 var t5: i64 = 1 93 let mibuf: *u8 = sys_mmap(64) 94 var c: i64 = 0 95 while c<48 { mibuf[c]=msg[c]; c=c+1 } 96 st_put16(mibuf, 2, 0x34) // adjust length per RFC 5389 15.4 97 let mi: *u8 = sys_mmap(24) 98 st_message_integrity("VOkJxbRl1RmTxUk/WvJxBt" as *u8, 22, mibuf, 48, mi) 99 let mi_exp: *u8 = (msg as i64 + 52) as *u8 100 if beq(mi, mi_exp, 20)==0 { t5=0 } 101 gck(t5, "T5 MESSAGE-INTEGRITY HMAC-SHA1(password) == the sample's 20-byte tag" as *u8, fails) 102 103 // ---- T6: header build + parse round-trip for a Binding Request ---- 104 var t6: i64 = 1 105 let txid: *u8 = sys_mmap(16) 106 var ti: i64=0 107 while ti<12 { txid[ti]=(0xa0+ti) as u8; ti=ti+1 } 108 let req: *u8 = sys_mmap(32) 109 st_write_header(req, STUN_BINDING_REQUEST, 0, txid) 110 if st_type(req)!=STUN_BINDING_REQUEST { t6=0 } 111 if st_magic(req)!=STUN_MAGIC { t6=0 } 112 if st_len(req)!=0 { t6=0 } 113 var tq: i64=0 114 while tq<12 { if req[8+tq]!=txid[tq] { t6=0 } tq=tq+1 } 115 gck(t6, "T6 header build+parse round-trip (Binding Request, txid preserved)" as *u8, fails) 116 117 gw(" fails=" as *u8); gn(fails[0]); gw("\n" as *u8) 118 if fails[0]==0 { gw("VERDICT: verdict=GREEN (sovereign NishiLang STUN interoperates byte-exact with RFC 5769)\n" as *u8); sys_exit(0) } 119 gw("VERDICT: verdict=RED\n" as *u8) 120 sys_exit(1) 121 return 1 122}