code wiki / _hdl_build / nx_modauth_arm_vault.nx

nx_modauth_arm_vault.nx source

↩ module page · 111 lines · 5826 B

1// nx_modauth_arm_vault.nx -- PRODUCTION arming: provision an admin with the passphrase sourced from the 2// SEALED VAULT (the documented machine-key vault, the same one nx_aw_push uses for the NAS password), NOT a 3// plaintext file. Flow (mirrors nx_aw_push): run nx_machine_key (writes the machine-derived unseal key to 4// /tmp/nxpass) -> nx_vault open <pw-vault.nv> (decrypts -> /tmp/nxsecret.out, 0600, AES-128-GCM authenticated) 5// -> read the passphrase -> register -> SHRED /tmp/nxsecret.out immediately. The passphrase never persists as 6// plaintext; at rest it lives only inside the AES-GCM-sealed .nv. Idempotent (re-run supersedes). 7// 8// Operator seals their passphrase once (out-of-band): stage it to /tmp/nxsecret.in -> nx_machine_key -> 9// nx_vault seal <pw-vault.nv>. The keys-bundle + store live in the documented secrets dir (~/.nishi/secrets/). 10// MUST run with CWD = the nxc2 repo root (the _offc/ helper paths are relative, like nx_aw_push). 11// argv: [1]=pw-vault.nv [2]=auth-keysfile [3]=auth-storefile [4]=realm [5]=handle [6]=mnemonic-outfile 12// Sovereign: nx_modern_auth_flow + nx_machine_key.elf + nx_vault.elf + nx_syscalls. license_tier: ORIGINAL 13import "hub/nx_modern_auth_flow.nx" 14import "nx_syscalls.nx" 15const AV_MAGIC_8192: i64 = 8192 16 17const AV_NXPASS: *u8 = "/tmp/nxpass" 18const AV_SECRET_OUT: *u8 = "/tmp/nxsecret.out" 19 20func av_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 21func av_w(s: *u8) -> i64 { sys_write(1, s, av_len(s)); return 0 } 22func av_unlink(path: *u8) -> i64 { __syscall(263, AT_FDCWD, path, 0, 0, 0, 0) return 0 } 23 24// fork+exec a Nishi .elf with up to 2 args; returns exit code (mirrors nx_aw_push p_run). 25func av_run(path: *u8, a1: *u8, a2: *u8) -> i64 { 26 let pid: i64 = sys_fork() 27 if pid == 0 { 28 let argv: *i64 = sys_mmap(64) as *i64 29 argv[0] = path as i64 30 var ai: i64 = 1 31 if (a1 as i64) != 0 { argv[ai] = a1 as i64; ai = ai + 1 } 32 if (a2 as i64) != 0 { argv[ai] = a2 as i64; ai = ai + 1 } 33 argv[ai] = 0 34 let envp: *i64 = sys_mmap(16) as *i64 35 envp[0] = "PATH=/usr/bin:/bin" as *u8 as i64 36 envp[1] = 0 37 sys_execve(path, argv, envp) 38 sys_exit(127) 39 } 40 let st: *i64 = sys_mmap(16) as *i64 41 sys_wait4(pid, st, 0) 42 return (st[0] >> 8) & 0xff 43} 44 45func main(argc: i64, argv: *i64) -> i64 { 46 if argc < 7 { 47 sys_write(2, "usage: nx_modauth_arm_vault <pw-vault.nv> <keysfile> <storefile> <realm> <handle> <mnemonic-out>\n" as *u8, 96) 48 return 1 49 } 50 let pwvault: *u8 = argv[1] as *u8 51 let keysfile: *u8 = argv[2] as *u8 52 let storefile: *u8 = argv[3] as *u8 53 let realm: *u8 = argv[4] as *u8 54 let handle: *u8 = argv[5] as *u8 55 let mnout: *u8 = argv[6] as *u8 56 let realm_n: i64 = av_len(realm) 57 let handle_n: i64 = av_len(handle) 58 59 // ---- source the passphrase from the sealed vault (machine-key unseal -> /tmp/nxsecret.out) ---- 60 if av_run("_offc/nx_machine_key.elf" as *u8, 0 as *u8, 0 as *u8) != 0 { av_w("ARM FAIL: machine-key (run from nxc2 root)\n" as *u8); av_unlink(AV_NXPASS); return 2 } 61 if av_run("_offc/nx_vault.elf" as *u8, "open" as *u8, pwvault) != 0 { av_w("ARM FAIL: vault open (bad vault / wrong machine)\n" as *u8); av_unlink(AV_NXPASS); return 3 } 62 av_unlink(AV_NXPASS) 63 let pwbox: *i64 = sys_mmap(16) as *i64 64 pwbox[0] = 0 65 let pwbuf: *u8 = sys_read_file(AV_SECRET_OUT, pwbox) 66 if (pwbuf as i64) == 0 { av_w("ARM FAIL: read unsealed secret\n" as *u8); return 4 } 67 var pw_start: i64 = 0 68 if pwbox[0] >= 3 { if (pwbuf[0] as i64) == 239 { if (pwbuf[1] as i64) == 187 { if (pwbuf[2] as i64) == 191 { pw_start = 3 } } } } 69 var pw_n: i64 = pwbox[0] 70 var trimming: i64 = 1 71 while trimming == 1 { 72 trimming = 0 73 if pw_n > pw_start { 74 let c: i64 = pwbuf[pw_n - 1] as i64 75 if c == 10 { pw_n = pw_n - 1; trimming = 1 } 76 if c == 13 { pw_n = pw_n - 1; trimming = 1 } 77 } 78 } 79 let pw_ptr: *u8 = ((pwbuf as i64) + pw_start) as *u8 80 let pw_eff: i64 = pw_n - pw_start 81 if pw_eff < 1 { av_unlink(AV_SECRET_OUT); av_w("ARM FAIL: empty passphrase from vault\n" as *u8); return 4 } 82 83 // ---- arm the server-key bundle + realm context, then register ---- 84 let oprf_seed: *u8 = sys_mmap(32) 85 let akp: *u8 = sys_mmap(32) 86 let akb: *u8 = sys_mmap(33) 87 let edp: *u8 = sys_mmap(32) 88 let edb: *u8 = sys_mmap(32) 89 if nx_uas_server_keys_load_or_init(keysfile, oprf_seed, akp, akb, edp, edb) != NX_UAS_OK { av_unlink(AV_SECRET_OUT); av_w("ARM FAIL: server-key bundle\n" as *u8); return 5 } 90 let ctx: *NxAuthContext = sys_mmap(256) as *NxAuthContext 91 if nx_auth_context_init(ctx, realm, realm_n, realm, realm_n, storefile as i64, oprf_seed, edp, edb, 900, AV_MAGIC_8192, 1, 1, 5, 1) != NX_MAUTH_OK { av_unlink(AV_SECRET_OUT); av_w("ARM FAIL: context init\n" as *u8); return 6 } 92 let mn: *u8 = sys_mmap(512) 93 let mn_n: *i64 = sys_mmap(16) as *i64 94 mn_n[0] = 0 95 let rc: i64 = nx_modern_auth_register(ctx, handle, handle_n, pw_ptr, pw_eff, mn, 512, mn_n) 96 av_unlink(AV_SECRET_OUT) 97 if rc != NX_MAUTH_OK { av_w("ARM FAIL: register\n" as *u8); return 7 } 98 if mn_n[0] < 1 { av_w("ARM FAIL: empty mnemonic\n" as *u8); return 8 } 99 100 let fd: i64 = sys_openat_wr(mnout, 0x180) 101 if fd < 0 { av_w("ARM FAIL: mnemonic out-file\n" as *u8); return 9 } 102 sys_write(fd, mn, mn_n[0]) 103 sys_write(fd, "\n" as *u8, 1) 104 sys_close(fd) 105 106 av_w("ARM OK (vault-sourced): admin provisioned for realm '" as *u8) 107 sys_write(1, realm, realm_n) 108 av_w("' -- passphrase read from the AES-GCM-sealed vault, never a plaintext file.\n" as *u8) 109 av_w(" 24-word BIP39 recovery mnemonic written to the out-file (0600) -- SAVE it, then DELETE the out-file.\n" as *u8) 110 return 0 111}