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}