code wiki / (root) / nx_mtls_issue.nx

nx_mtls_issue.nx source

↩ module page · 105 lines · 6618 B

1// nx_mtls_issue.nx -- R7 ISSUANCE: one call the login daemon makes to hand a browser its identity .p12. 2// 3// The enforcement side has its one-call drop-in (nx_hgw_mtls_resolve_handle). This is the issuance twin: after 4// OPAQUE login succeeds, the daemon holds the 32-byte export_key (RFC 9807) + the user_id_hash; this composes 5// R5 (derive the deterministic Ed25519 identity keypair + mint the bound cert, Subject CN = hex(user_id_hash)) 6// and R5b (package key+cert into a password-protected PKCS#12) into the single browser-importable .p12. The 7// private key is NEVER stored server-side -- it is re-derived from export_key on each login, so re-issuing is 8// idempotent (same login -> byte-identical .p12 in dev). The daemon streams the result to the browser ONCE for 9// a one-time cert import; thereafter the cert rides every connection at the TLS layer (the no-cookie carrier). 10// 11// LIVE NOTE: nx_modern_auth_login / olg_login currently DISCARD export_key (R5 header); surfacing it as an 12// additive out-param is the issuance-side daemon edit. Composes nx_mtls_identity (R5) + nx_mtls_pkcs12 (R5b). 13// license_tier: ORIGINAL expect_exit: 0 14import "nx_syscalls.nx" 15import "nx_mtls_identity.nx" // nx_mtls_mint_identity_cert + NX_MID_OK + nx_mid_hex + mid_find 16import "nx_mtls_pkcs12.nx" // nx_mtls_emit_pkcs12 17const NX_MAGIC_4096: i64 = 4096 18const NX_MAGIC_8192: i64 = 8192 19 20const NX_ISSUE_OK: i64 = 0 21const NX_ISSUE_ERR: i64 = 1 22 23// OPAQUE export_key + uid_hash -> the browser-importable .p12 (identity cert + key, password-protected). 24// On OK: out_p12[0..out_n] is the PFX, out_pub_32 the identity pubkey (the stable handle R6 authorizes on). 25func nx_mtls_issue_identity_p12( 26 export_key_32: *u8, uid_hash_32: *u8, 27 pw: *u8, pw_n: i64, 28 out_p12: *u8, cap: i64, out_n: *i64, 29 out_pub_32: *u8 30) -> i64 { 31 let seed: *u8 = sys_mmap(32) 32 let cert: *u8 = sys_mmap(NX_MAGIC_4096); let clen: *i64 = sys_mmap(8) as *i64 33 if nx_mtls_mint_identity_cert(export_key_32, uid_hash_32, cert, NX_MAGIC_4096, clen, seed, out_pub_32) != NX_MID_OK { return NX_ISSUE_ERR } 34 if nx_mtls_emit_pkcs12(seed, out_pub_32, cert, clen[0], pw, pw_n, out_p12, cap, out_n) != 0 { return NX_ISSUE_ERR } 35 return NX_ISSUE_OK 36} 37 38// ===== in-process gate: export_key -> a valid, identity-bound, idempotent .p12 ===== 39func iss_w(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 40func iss_row(name: *u8, ok: i64) -> i64 { if ok == 1 { iss_w(" PASS " as *u8) } else { iss_w(" FAIL " as *u8) } iss_w(name); iss_w("\n" as *u8); return ok } 41func iss_eq(a: *u8, an: i64, b: *u8, bn: i64) -> i64 { if an != bn { return 0 } var i: i64 = 0; while i < an { if a[i] != b[i] { return 0 } i = i + 1 } return 1 } 42 43func main() -> i64 { 44 iss_w("nx_mtls issuance gate (OPAQUE export_key -> browser-importable identity .p12; R7 issuance, idempotent)\n" as *u8) 45 46 let ek: *u8 = sys_mmap(32); let uid: *u8 = sys_mmap(32) 47 var i: i64 = 0 48 while i < 32 { ek[i] = (0x5a + i) as u8; uid[i] = (0xC3 ^ i) as u8; i = i + 1 } 49 50 let p12a: *u8 = sys_mmap(NX_MAGIC_8192); let na: *i64 = sys_mmap(8) as *i64; let pubA: *u8 = sys_mmap(32) 51 let rc: i64 = nx_mtls_issue_identity_p12(ek, uid, "nishi" as *u8, 5, p12a, NX_MAGIC_8192, na, pubA) 52 var pass: i64 = 0 53 54 // T1: issuance succeeds + emits a well-formed PFX (DER SEQUENCE) of substantial size (key+cert+mac) 55 var t1: i64 = 0 56 if rc == NX_ISSUE_OK { if na[0] > 256 { if (p12a[0] & 0xff) == 0x30 { t1 = 1 } } } 57 pass = pass + iss_row("T1 export_key -> a well-formed PFX .p12 emitted (DER SEQUENCE, key+cert+MAC)" as *u8, t1) 58 59 // T2: idempotent -- the SAME login (export_key+uid+pw) re-issues a BYTE-IDENTICAL .p12 (re-derivable, not stored) 60 let p12b: *u8 = sys_mmap(NX_MAGIC_8192); let nb: *i64 = sys_mmap(8) as *i64; let pubB: *u8 = sys_mmap(32) 61 nx_mtls_issue_identity_p12(ek, uid, "nishi" as *u8, 5, p12b, NX_MAGIC_8192, nb, pubB) 62 var t2: i64 = 0 63 if iss_eq(p12a, na[0], p12b, nb[0]) == 1 { t2 = 1 } 64 pass = pass + iss_row("T2 idempotent: same login re-issues a byte-identical .p12 (no server-stored key)" as *u8, t2) 65 66 // T3: the .p12 carries the RIGHT identity (out_pub == the R5-derived identity pubkey) 67 let seedchk: *u8 = sys_mmap(32); let pubchk: *u8 = sys_mmap(32) 68 nx_mtls_derive_identity_keypair(ek, seedchk, pubchk) 69 var t3: i64 = 0 70 var j: i64 = 0; var ok3: i64 = 1 71 while j < 32 { if pubA[j] != pubchk[j] { ok3 = 0; j = 32 } else { j = j + 1 } } 72 if ok3 == 1 { t3 = 1 } 73 pass = pass + iss_row("T3 the .p12 carries the OPAQUE-bound identity pubkey (out_pub == derived)" as *u8, t3) 74 75 // T4: the .p12 EMBEDS the bound cert (mint the reference cert + find its DER inside the PFX CertBag, plaintext) 76 let refcert: *u8 = sys_mmap(NX_MAGIC_4096); let rcl: *i64 = sys_mmap(8) as *i64 77 let rseed: *u8 = sys_mmap(32); let rpub: *u8 = sys_mmap(32) 78 nx_mtls_mint_identity_cert(ek, uid, refcert, NX_MAGIC_4096, rcl, rseed, rpub) 79 var t4: i64 = 0 80 if mid_find(p12a, na[0], refcert, rcl[0]) >= 0 { t4 = 1 } 81 pass = pass + iss_row("T4 the .p12 embeds the bound identity cert (CN = hex(user_id_hash))" as *u8, t4) 82 83 // T5: independence -- a different export_key yields a DIFFERENT .p12 (distinct identity, not constant output) 84 let ek2: *u8 = sys_mmap(32); var a: i64 = 0; while a < 32 { ek2[a] = ek[a]; a = a + 1 } ek2[0] = (ek2[0] ^ 1) as u8 85 let p12c: *u8 = sys_mmap(NX_MAGIC_8192); let nc: *i64 = sys_mmap(8) as *i64; let pubC: *u8 = sys_mmap(32) 86 nx_mtls_issue_identity_p12(ek2, uid, "nishi" as *u8, 5, p12c, NX_MAGIC_8192, nc, pubC) 87 var t5: i64 = 0 88 if iss_eq(p12a, na[0], p12c, nc[0]) == 0 { t5 = 1 } 89 pass = pass + iss_row("T5 independence: a different export_key -> a different .p12 (distinct identity)" as *u8, t5) 90 91 // T6: the password protects the key -- a different password yields a different .p12 (PBES2 over the key) 92 let p12d: *u8 = sys_mmap(NX_MAGIC_8192); let nd: *i64 = sys_mmap(8) as *i64; let pubD: *u8 = sys_mmap(32) 93 nx_mtls_issue_identity_p12(ek, uid, "other" as *u8, 5, p12d, NX_MAGIC_8192, nd, pubD) 94 var t6: i64 = 0 95 if iss_eq(p12a, na[0], p12d, nd[0]) == 0 { t6 = 1 } 96 pass = pass + iss_row("T6 the password protects the key (different pw -> different .p12; PBES2 binding)" as *u8, t6) 97 98 if pass == 6 { 99 iss_w("NX-MTLS-ISSUE GATE GREEN 6/6 (one call: export_key -> identity-bound, idempotent, password-protected .p12; drops into the login daemon)\n" as *u8) 100 sys_exit(0) 101 } 102 iss_w("NX-MTLS-ISSUE GATE RED\n" as *u8) 103 sys_exit(1) 104 return 1 105}