code wiki / _hdl_build / nx_login_gate_gate.nx
nx_login_gate_gate.nx source
↩ module page · 112 lines · 6219 B
1// nx_login_gate_gate.nx -- ★NISHI LOGIN Phase-1 keystone: the UNIFIED multi-modal auth gate proven end to end.
2// Mints a REAL scoped ocap cap (capt_issue, HMAC-SHA256 signed) for scope "git", then asserts login_gate_cap
3// authorizes it through ALL THREE wire forms a client can present -- X-Nishi-Cap header, Authorization: Bearer,
4// and git/curl Authorization: Basic <user:cap> -- and correctly DENIES wrong-scope, tampered, expired, and absent
5// credentials, while a "*" wildcard cap authorizes any scope. This is the shared validator behind the edge auth=
6// switch and the git gate. GREEN => one sovereign credential, three presentations, fail-closed. license_tier: ORIGINAL expect_exit: 0
7import "nx_syscalls.nx"
8import "nx_cap_token.nx"
9import "nx_base64.nx"
10import "nx_login_gate.nx"
11
12func hw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
13func pn(v: i64) -> i64 { let b: *u8 = sys_mmap(32) as *u8; var x: i64 = v; var ng: i64 = 0; if x < 0 { ng = 1; x = 0 - x } var i: i64 = 31; if x == 0 { b[i] = 48 as u8; i = i - 1 } while x > 0 { b[i] = (48 + x % 10) as u8; x = x / 10; i = i - 1 } if ng == 1 { b[i] = 45 as u8; i = i - 1 } sys_write(1, (b as i64 + i + 1) as *u8, 31 - i); return 0 }
14
15// copy NUL-terminated literal s into buf at off; return new off
16func apps(buf: *u8, off: i64, s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { buf[off + i] = s[i]; i = i + 1 } return off + i }
17// copy len bytes of tok into buf at off; return new off
18func app(buf: *u8, off: i64, tok: *u8, len: i64) -> i64 { var i: i64 = 0; while i < len { buf[off + i] = tok[i]; i = i + 1 } return off + len }
19
20// assert want==got, tick fails on mismatch
21func expect(name: *u8, got: i64, want: i64, fails: *i64) -> i64 {
22 hw(name); hw(" -> " as *u8); pn(got)
23 if got == want { hw(" OK\n" as *u8); return 0 }
24 hw(" FAIL want " as *u8); pn(want); hw("\n" as *u8)
25 fails[0] = fails[0] + 1
26 return 1
27}
28
29// build "<prefix-literal><tok[..tl]>\r\n\r\n" request into r; return its length
30func mkreq(r: *u8, prefix: *u8, tok: *u8, tl: i64) -> i64 {
31 var o: i64 = 0
32 o = apps(r, o, prefix)
33 o = app(r, o, tok, tl)
34 o = apps(r, o, "\r\n\r\n" as *u8)
35 return o
36}
37
38func main() -> i64 {
39 hw("=== nx_login_gate_gate -- unified multi-modal auth gate (cap in header|bearer|basic) ===\n" as *u8)
40 let fails: *i64 = sys_mmap(16) as *i64
41 fails[0] = 0
42
43 // 32-byte deterministic test key (stands in for tools_cap_secret.key)
44 let key: *u8 = sys_mmap(64)
45 var i: i64 = 0
46 while i < 32 { key[i] = ((0x11 + i) & 0xFF) as u8; i = i + 1 }
47
48 // mint a valid cap for scope "git" (exp far in the future), and evaluate all tests at now=1_000_000_000
49 let cap: *u8 = sys_mmap(1024)
50 let cl: i64 = capt_issue(key, 32, "git" as *u8, 3, 4000000000, 700001, cap, 1024)
51 let now: i64 = 1000000000
52 hw("minted git-cap len=" as *u8); pn(cl); hw("\n" as *u8)
53
54 let r: *u8 = sys_mmap(8192)
55 var rl: i64 = 0
56
57 // T1: X-Nishi-Cap header, scope git -> AUTHORIZED
58 rl = mkreq(r, "GET /info/refs HTTP/1.1\r\nHost: nishifamily.com\r\nX-Nishi-Cap: " as *u8, cap, cl)
59 expect("T1 X-Nishi-Cap (git)" as *u8, login_gate_cap(r, rl, key, 32, "git" as *u8, 3, now), 1, fails)
60
61 // T2: same request, WRONG scope -> DENY
62 expect("T2 wrong-scope (admin)" as *u8, login_gate_cap(r, rl, key, 32, "admin" as *u8, 5, now), 0, fails)
63
64 // T3: Authorization: Bearer <cap>, scope git -> AUTHORIZED
65 rl = mkreq(r, "GET /x HTTP/1.1\r\nHost: h\r\nAuthorization: Bearer " as *u8, cap, cl)
66 expect("T3 Bearer (git)" as *u8, login_gate_cap(r, rl, key, 32, "git" as *u8, 3, now), 1, fails)
67
68 // T4: Authorization: Basic base64("x:<cap>"), scope git -> AUTHORIZED (git's wire form)
69 let up: *u8 = sys_mmap(2048)
70 up[0] = 120 as u8; up[1] = 58 as u8 // "x:"
71 i = 0; while i < cl { up[2 + i] = cap[i]; i = i + 1 }
72 let b64: *u8 = sys_mmap(4096)
73 let bl: i64 = b64_encode(up, 2 + cl, b64)
74 rl = mkreq(r, "GET /x HTTP/1.1\r\nHost: h\r\nAuthorization: Basic " as *u8, b64, bl)
75 expect("T4 Basic x:<cap>(git)" as *u8, login_gate_cap(r, rl, key, 32, "git" as *u8, 3, now), 1, fails)
76
77 // T5: no credential at all -> DENY
78 rl = mkreq(r, "GET /x HTTP/1.1\r\nHost: h\r\nUser-Agent: git/2.4" as *u8, "" as *u8, 0)
79 expect("T5 no-credential" as *u8, login_gate_cap(r, rl, key, 32, "git" as *u8, 3, now), 0, fails)
80
81 // T6: tampered cap (flip last byte of the signature) -> DENY
82 let bad: *u8 = sys_mmap(1024)
83 i = 0; while i < cl { bad[i] = cap[i]; i = i + 1 }
84 bad[cl - 1] = (bad[cl - 1] ^ 0x01) as u8
85 rl = mkreq(r, "GET /x HTTP/1.1\r\nX-Nishi-Cap: " as *u8, bad, cl)
86 expect("T6 tampered-sig" as *u8, login_gate_cap(r, rl, key, 32, "git" as *u8, 3, now), 0, fails)
87
88 // T7: expired cap (exp=500 < now) -> DENY
89 let ecap: *u8 = sys_mmap(1024)
90 let ecl: i64 = capt_issue(key, 32, "git" as *u8, 3, 500, 700002, ecap, 1024)
91 rl = mkreq(r, "GET /x HTTP/1.1\r\nX-Nishi-Cap: " as *u8, ecap, ecl)
92 expect("T7 expired" as *u8, login_gate_cap(r, rl, key, 32, "git" as *u8, 3, now), 0, fails)
93
94 // T8: "*" wildcard cap authorizes scope git -> AUTHORIZED (least-authority still allows explicit-all)
95 let wcap: *u8 = sys_mmap(1024)
96 let wcl: i64 = capt_issue(key, 32, "*" as *u8, 1, 4000000000, 700003, wcap, 1024)
97 rl = mkreq(r, "GET /x HTTP/1.1\r\nX-Nishi-Cap: " as *u8, wcap, wcl)
98 expect("T8 wildcard '*' (git)" as *u8, login_gate_cap(r, rl, key, 32, "git" as *u8, 3, now), 1, fails)
99
100 // T9: cap signed with a DIFFERENT key -> DENY (forgery)
101 let key2: *u8 = sys_mmap(64)
102 i = 0; while i < 32 { key2[i] = ((0x77 + i) & 0xFF) as u8; i = i + 1 }
103 let fcap: *u8 = sys_mmap(1024)
104 let fcl: i64 = capt_issue(key2, 32, "git" as *u8, 3, 4000000000, 700004, fcap, 1024)
105 rl = mkreq(r, "GET /x HTTP/1.1\r\nX-Nishi-Cap: " as *u8, fcap, fcl)
106 expect("T9 foreign-key" as *u8, login_gate_cap(r, rl, key, 32, "git" as *u8, 3, now), 0, fails)
107
108 hw("\n" as *u8)
109 if fails[0] == 0 { hw("ALL GREEN -- unified auth gate fail-closed across 3 wire forms\n" as *u8); return 0 }
110 hw("FAILS=" as *u8); pn(fails[0]); hw("\n" as *u8)
111 return 1
112}