code wiki / (root) / nx_cap_keygen.nx

nx_cap_keygen.nx source

↩ module page · 76 lines · 4564 B

1// nx_cap_keygen.nx -- provision the capability-token SIGNING SECRET on the machine that will verify it (the NAS). 2// GAP 2 of the MCP grant: nx_tools_api prefers a real keyfile (TA_CAP_KEYFILE = tools_cap_secret.key, CWD-relative) 3// but FALLS BACK to a forgeable baked placeholder when it is absent -- so until a real key is provisioned, any 4// token is forgeable by anyone who can read the source/binary. This organ draws 32 bytes from the kernel CSPRNG, 5// hex-encodes them (64 ASCII chars, NO trailing newline / NO NUL -- so the file bytes are EXACTLY the secret 6// nx_tools_api reads raw and nx_cap_mint signs with), and writes them 0600. 7// 8// SINGLE RESPONSIBILITY (rule 9): this only PROVISIONS the secret; nx_cap_mint ISSUES tokens from it; nx_tools_api 9// VERIFIES them. Kept a STANDALONE organ (not a supervisor sub) so it is gate-provable off-LAN and deployable via 10// the /api chain. FAIL-SAFE: refuses to overwrite an existing keyfile unless argv[2]=="--force" (a silent rotate 11// would invalidate every outstanding capability). The secret is generated WHERE it is used and NEVER transits a 12// network, and is NEVER printed. license_tier: ORIGINAL expect_exit: 0 13import "nx_csprng.nx" // nx_csprng_fill (getrandom(2) -> /dev/urandom fallback) (+ transitive nx_syscalls, nx_random) 14 15const CK_DEFAULT: *u8 = "tools_cap_secret.key" as *u8 // must match nx_tools_api TA_CAP_KEYFILE 16const CK_BYTES: i64 = 32 // 256-bit secret 17 18// return codes 19const CK_OK: i64 = 1 20const CK_EXISTS: i64 = 0 - 2 // keyfile present + non-empty, force not given -> refused (fail-safe) 21const CK_RNG: i64 = 0 - 3 // CSPRNG draw failed 22const CK_WRITE: i64 = 0 - 4 // open/write of the keyfile failed 23 24func ck_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 25func ck_streq(a: *u8, b: *u8) -> i64 { var i: i64 = 0; while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } if b[i] != (0 as u8) { return 0 } return 1 } 26func ck_hexd(v: i64) -> i64 { if v < 10 { return 48 + v } return 87 + v } // 0-9 then a-f 27 28// ck_provision: PURE core. Provision the keyfile at `path` (0600) with 32 fresh CSPRNG bytes, hex-encoded, unless 29// it already exists and force==0. Also copies the hex secret (NUL-terminated) into out_key and sets out_klen[0]=64 30// so a gate can drive mint/verify against the REAL generated key in-process (no disk read-back needed). Returns CK_*. 31func ck_provision(path: *u8, force: i64, out_key: *u8, out_klen: *i64) -> i64 { 32 if force == 0 { 33 let szp: *i64 = sys_mmap(16) as *i64 34 let ex: *u8 = sys_read_file(path, szp) 35 if (ex as i64) != 0 { if szp[0] > 0 { return CK_EXISTS } } 36 } 37 let raw: *u8 = sys_mmap(64) 38 if nx_csprng_fill(raw, CK_BYTES) < 0 { return CK_RNG } 39 var i: i64 = 0 40 while i < CK_BYTES { 41 let b: i64 = raw[i] as i64 42 let hi: i64 = ck_hexd((b >> 4) & 15) // hoist the call OUT of the array store (nx_cc: call-in-array-store -> SEGV) 43 let lo: i64 = ck_hexd(b & 15) 44 out_key[i * 2] = hi as u8 45 out_key[i * 2 + 1] = lo as u8 46 i = i + 1 47 } 48 out_key[CK_BYTES * 2] = 0 as u8 49 out_klen[0] = CK_BYTES * 2 50 // O_WRONLY|O_CREAT|O_TRUNC (0x241), mode 0600 (0x180). Raw hex, NO trailing newline (byte-exact secret). 51 let fd: i64 = __syscall(257, 0 - 100, path, 0x241, 0x180, 0, 0) 52 if fd < 0 { return CK_WRITE } 53 sys_write(fd, out_key, CK_BYTES * 2) 54 sys_close(fd) 55 return CK_OK 56} 57 58// CLI: nx_cap_keygen [keyfile] [--force] (default keyfile = tools_cap_secret.key in CWD) 59func main(argc: i64, argv: *i64) -> i64 { 60 var path: *u8 = CK_DEFAULT 61 if argc >= 2 { path = argv[1] as *u8 } 62 var force: i64 = 0 63 if argc >= 3 { if ck_streq(argv[2] as *u8, "--force" as *u8) == 1 { force = 1 } } 64 65 let kb: *u8 = sys_mmap(128) 66 let klp: *i64 = sys_mmap(16) as *i64 67 let rc: i64 = ck_provision(path, force, kb, klp) 68 69 if rc == CK_EXISTS { ck_puts("REFUSED: keyfile already present. Pass --force to ROTATE (this invalidates every outstanding capability).\n" as *u8); sys_exit(3); return 3 } 70 if rc == CK_RNG { ck_puts("FAILED: CSPRNG draw failed -- no keyfile written.\n" as *u8); sys_exit(4); return 4 } 71 if rc == CK_WRITE { ck_puts("FAILED: could not open/write the keyfile.\n" as *u8); sys_exit(5); return 5 } 72 73 ck_puts("PROVISIONED capability signing keyfile (256-bit, 0600). Secret NOT printed. Restart nx_tools_api to load it, then nx_cap_mint can issue tokens.\n" as *u8) 74 sys_exit(0) 75 return 0 76}