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}