code wiki / _hdl_build / nx_cap_provision.nx

nx_cap_provision.nx source

↩ module page · 55 lines · 2747 B

1// nx_cap_provision.nx -- FAIL-CLOSED capability-secret provisioning check (closes audit risk #1: 2// the tools-api's baked placeholder HMAC secret is forgeable by anyone reading the binary). A cap- 3// signing secret MUST come from the sovereign vault keyfile, NEVER the compiled placeholder. This 4// PURE check lets the tools-api serve organ FAIL-FAST at startup (CLAUDE.md #20): if the key is 5// absent / too short / still the placeholder -> refuse to bind rather than verify caps against a 6// constant. ADDITIVE + zero-collision (new organ, no edit to the contended nx_tools_api gate suite). 7// The serve-startup wiring + provisioning the real 0600 keyfile on the NAS = operator-coordinated last mile. 8// license_tier: ORIGINAL 9import "nx_syscalls.nx" 10 11// minimum acceptable key length in bytes (a 1-byte keyfile must NOT count as provisioned). 12const CAP_MINKEY: i64 = 16 13// the exact baked placeholder from nx_tools_api.nx L17 -- a keyfile containing THIS is unprovisioned. 14const CAP_PLACEHOLDER: *u8 = "nishi-tools-cap-hmac-secret-v1-REPLACE-FROM-VAULT" as *u8 15 16func cp_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 17 18// does the first n bytes of buf exactly equal the nul-terminated pat (same length AND bytes)? 19func cp_eq_bytes(buf: *u8, n: i64, pat: *u8) -> i64 { 20 let pl: i64 = cp_slen(pat) 21 if n != pl { return 0 } 22 var i: i64 = 0 23 while i < n { if buf[i] != pat[i] { return 0 } i = i + 1 } 24 return 1 25} 26 27// THE fail-closed verdict: 1 = a real vault key is present (bind allowed); 0 = FAIL CLOSED (refuse). 28// keyfile absent -> 0 ; shorter than minkey -> 0 ; byte-identical to the placeholder -> 0 ; else 1. 29func cap_provisioned(keyfile: *u8, minkey: i64) -> i64 { 30 let szp: *i64 = sys_mmap(16) as *i64 31 let buf: *u8 = sys_read_file(keyfile, szp) 32 if (buf as i64) == 0 { return 0 } 33 let n: i64 = szp[0] 34 if n < minkey { return 0 } 35 if cp_eq_bytes(buf, n, CAP_PLACEHOLDER) == 1 { return 0 } 36 return 1 37} 38 39// convenience: the production default (the real keyfile path + CAP_MINKEY). 40func cap_provisioned_default() -> i64 { 41 return cap_provisioned("tools_cap_secret.key" as *u8, CAP_MINKEY) 42} 43 44func cp_p(s: *u8) -> i64 { let n: i64 = cp_slen(s); sys_write(1, s, n); return 0 } 45 46func main(argc: i64, argv: *i64) -> i64 { 47 var keyfile: *u8 = "tools_cap_secret.key" 48 if argc >= 2 { keyfile = argv[1] as *u8 } 49 let v: i64 = cap_provisioned(keyfile, CAP_MINKEY) 50 cp_p("CAP-PROVISION keyfile=" as *u8); cp_p(keyfile) 51 if v == 1 { cp_p(" provisioned=YES (real vault key -> serve may bind)\n" as *u8) } 52 else { cp_p(" provisioned=NO (absent/short/placeholder -> FAIL-CLOSED: serve must refuse to bind)\n" as *u8) } 53 sys_exit(1 - v) 54 return 1 - v 55}