nx_mtls_pkcs12.nx source
↩ module page · 230 lines · 16869 B
1// nx_mtls_pkcs12.nx -- sovereign PKCS#12 (.p12 / PFX) emitter for one-time browser/OS import (RFC 7292).
2//
3// mTLS rung R5b: package the OPAQUE-bound client identity (Ed25519 key + leaf cert) into a .p12 the user
4// imports ONCE into their browser/OS cert store, after which the browser presents it at the TLS layer on
5// every connection -- the no-cookie carrier. Structure (modern, widely-importable: OpenSSL 3 + Windows 11):
6// PFX = SEQ { version 3,
7// authSafe ContentInfo{data, OCTET STRING( AuthenticatedSafe )},
8// macData SEQ{ DigestInfo{sha256, MAC}, macSalt, iter } }
9// AuthenticatedSafe = SEQ OF ContentInfo{data, OCTET STRING( SafeContents )}
10// SafeContents = SEQ OF { ShroudedKeyBag(PBES2: PBKDF2-HMAC-SHA256 + AES-128-CBC over PKCS#8), CertBag }
11// MAC key = PKCS12-KDF(BMPString(pw), macSalt, iter, id=3, 32); MAC = HMAC-SHA256 over the AuthenticatedSafe DER.
12//
13// Composes ONLY sovereign, KAT'd primitives: nx_asn1_emit · nx_pbkdf2 · nx_aes_cbc_enc (AES-CBC, NIST F.2.1)
14// · nx_pkcs12_kdf (RFC 7292 B.2) · nx_hmac · sha256 · nx_x509_leaf_emit. The emitted .p12 is validated
15// end-to-end by `openssl pkcs12` (dev-time oracle only; never shipped). license_tier: ORIGINAL expect_exit: 0
16import "nx_syscalls.nx"
17import "nx_asn1_emit.nx"
18import "sha256.nx"
19import "nx_hmac.nx"
20import "nx_pbkdf2.nx"
21import "nx_pkcs12_kdf.nx"
22import "nx_aes.nx"
23import "nx_aes_cbc_enc.nx"
24import "nx_ed25519_signature.nx"
25import "nx_x509_leaf_emit.nx"
26const K_MAGIC_2048: i64 = 2048
27const K_MAGIC_4096: i64 = 4096
28const K_MAGIC_8192: i64 = 8192
29
30// ---- OID DER value bytes (the content after tag 0x06 + length; nxae_put_oid adds those) ----
31func p12oid_ed25519(o: *u8) -> i64 { o[0]=0x2b as u8;o[1]=0x65 as u8;o[2]=0x70 as u8; return 3 }
32func p12oid_pbes2(o: *u8) -> i64 { o[0]=0x2a as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x86 as u8;o[4]=0xf7 as u8;o[5]=0x0d as u8;o[6]=0x01 as u8;o[7]=0x05 as u8;o[8]=0x0d as u8; return 9 }
33func p12oid_pbkdf2(o: *u8) -> i64 { o[0]=0x2a as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x86 as u8;o[4]=0xf7 as u8;o[5]=0x0d as u8;o[6]=0x01 as u8;o[7]=0x05 as u8;o[8]=0x0c as u8; return 9 }
34func p12oid_hmacsha256(o: *u8) -> i64 { o[0]=0x2a as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x86 as u8;o[4]=0xf7 as u8;o[5]=0x0d as u8;o[6]=0x02 as u8;o[7]=0x09 as u8; return 8 }
35func p12oid_aes128cbc(o: *u8) -> i64 { o[0]=0x60 as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x01 as u8;o[4]=0x65 as u8;o[5]=0x03 as u8;o[6]=0x04 as u8;o[7]=0x01 as u8;o[8]=0x02 as u8; return 9 }
36func p12oid_sha256(o: *u8) -> i64 { o[0]=0x60 as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x01 as u8;o[4]=0x65 as u8;o[5]=0x03 as u8;o[6]=0x04 as u8;o[7]=0x02 as u8;o[8]=0x01 as u8; return 9 }
37func p12oid_data(o: *u8) -> i64 { o[0]=0x2a as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x86 as u8;o[4]=0xf7 as u8;o[5]=0x0d as u8;o[6]=0x01 as u8;o[7]=0x07 as u8;o[8]=0x01 as u8; return 9 }
38func p12oid_shroudedkeybag(o: *u8) -> i64 { o[0]=0x2a as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x86 as u8;o[4]=0xf7 as u8;o[5]=0x0d as u8;o[6]=0x01 as u8;o[7]=0x0c as u8;o[8]=0x0a as u8;o[9]=0x01 as u8;o[10]=0x02 as u8; return 11 }
39func p12oid_certbag(o: *u8) -> i64 { o[0]=0x2a as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x86 as u8;o[4]=0xf7 as u8;o[5]=0x0d as u8;o[6]=0x01 as u8;o[7]=0x0c as u8;o[8]=0x0a as u8;o[9]=0x01 as u8;o[10]=0x03 as u8; return 11 }
40func p12oid_x509cert(o: *u8) -> i64 { o[0]=0x2a as u8;o[1]=0x86 as u8;o[2]=0x48 as u8;o[3]=0x86 as u8;o[4]=0xf7 as u8;o[5]=0x0d as u8;o[6]=0x01 as u8;o[7]=0x09 as u8;o[8]=0x16 as u8;o[9]=0x01 as u8; return 10 }
41
42// DER INTEGER for a small positive value (1..65535), minimal encoding + 0x00 sign-prefix if MSB set.
43func p12_put_uint(out: *u8, off: *i64, cap: i64, v: i64) -> i64 {
44 if v < 256 {
45 nxae_put(out, off, cap, 0x02)
46 if v >= 128 { nxae_put(out, off, cap, 2); nxae_put(out, off, cap, 0); return nxae_put(out, off, cap, v) }
47 nxae_put(out, off, cap, 1); return nxae_put(out, off, cap, v)
48 }
49 let hi: i64 = (v >> 8) & 0xff; let lo: i64 = v & 0xff
50 nxae_put(out, off, cap, 0x02)
51 if hi >= 128 { nxae_put(out, off, cap, 3); nxae_put(out, off, cap, 0); nxae_put(out, off, cap, hi); return nxae_put(out, off, cap, lo) }
52 nxae_put(out, off, cap, 2); nxae_put(out, off, cap, hi); return nxae_put(out, off, cap, lo)
53}
54
55// Emit a complete PFX (.p12) for (seed32, pub32, cert_der) protected by ASCII password pw. out_n = length.
56func nx_mtls_emit_pkcs12(
57 seed32: *u8, pub32: *u8, cert_der: *u8, cert_len: i64,
58 pw_ascii: *u8, pw_n: i64, out: *u8, cap: i64, out_n: *i64
59) -> i64 {
60 // ===== 1. PKCS#8 PrivateKeyInfo (Ed25519) =====
61 let cpk: *u8 = sys_mmap(48); let cpk_o: *i64 = sys_mmap(8) as *i64; cpk_o[0] = 0
62 nxae_put_octet_string(cpk, cpk_o, 48, seed32, 32) // CurvePrivateKey = 04 20 <seed>
63 let edoid: *u8 = sys_mmap(8); let edn: i64 = p12oid_ed25519(edoid)
64 let alg: *u8 = sys_mmap(16); let alg_o: *i64 = sys_mmap(8) as *i64; alg_o[0] = 0
65 nxae_put_oid(alg, alg_o, 16, edoid, edn)
66 let pk8: *u8 = sys_mmap(96); let pk8_o: *i64 = sys_mmap(8) as *i64; pk8_o[0] = 0
67 nxae_put_int_u8(pk8, pk8_o, 96, 0) // version 0
68 nxae_put_tlv(pk8, pk8_o, 96, 0x30, alg, alg_o[0]) // privateKeyAlgorithm
69 nxae_put_octet_string(pk8, pk8_o, 96, cpk, cpk_o[0]) // privateKey OCTET STRING(CurvePrivateKey)
70 let pk8w: *u8 = sys_mmap(112); let pk8w_o: *i64 = sys_mmap(8) as *i64; pk8w_o[0] = 0
71 nxae_put_tlv(pk8w, pk8w_o, 112, 0x30, pk8, pk8_o[0])
72 return nx_mtls_emit_pkcs12_from(pk8w, pk8w_o[0], cert_der, cert_len, pw_ascii, pw_n, out, cap, out_n)
73}
74
75// Generic PFX emitter (key-type AGNOSTIC): takes a wrapped PKCS#8 (pk8w) + cert DER. Used by the Ed25519
76// path above and by the ECDSA driver (nx_mtls_pkcs12_ecdsa). out_n = PFX length.
77func nx_mtls_emit_pkcs12_from(
78 pk8w: *u8, pk8w_len: i64, cert_der: *u8, cert_len: i64,
79 pw_ascii: *u8, pw_n: i64, out: *u8, cap: i64, out_n: *i64
80) -> i64 {
81 let iter: i64 = K_MAGIC_2048
82 // fixed salts/IV (deterministic for dev; production passes random via nx_csprng_fill)
83 let kdf_salt: *u8 = sys_mmap(16); var t: i64 = 0; while t < 16 { kdf_salt[t] = (0x11 + t) as u8; t = t + 1 }
84 let iv: *u8 = sys_mmap(16); t = 0; while t < 16 { iv[t] = (0x22 + t) as u8; t = t + 1 }
85 let mac_salt: *u8 = sys_mmap(8); t = 0; while t < 8 { mac_salt[t] = (0x33 + t) as u8; t = t + 1 }
86 let big: i64 = cert_len + K_MAGIC_2048
87
88 // ===== 2. PBES2-encrypt the PKCS#8 =====
89 let aeskey: *u8 = sys_mmap(16)
90 pbkdf2_sha256(pw_ascii, pw_n, kdf_salt, 16, iter, 16, aeskey)
91 let sched: *u8 = sys_mmap(176); aes128_expand_key(aeskey, sched)
92 let padded: *u8 = sys_mmap(pk8w_len + 16); let pad_n: i64 = aes128_pkcs7_pad(pk8w, pk8w_len, padded)
93 let enc: *u8 = sys_mmap(pad_n); aes128_cbc_encrypt(padded, pad_n, sched, iv, enc)
94 // PBKDF2 AlgId
95 let prfoid: *u8 = sys_mmap(8); let prfn: i64 = p12oid_hmacsha256(prfoid)
96 let prf: *u8 = sys_mmap(16); let prf_o: *i64 = sys_mmap(8) as *i64; prf_o[0] = 0
97 nxae_put_oid(prf, prf_o, 16, prfoid, prfn); nxae_put_null(prf, prf_o, 16)
98 let kp: *u8 = sys_mmap(64); let kp_o: *i64 = sys_mmap(8) as *i64; kp_o[0] = 0
99 nxae_put_octet_string(kp, kp_o, 64, kdf_salt, 16)
100 p12_put_uint(kp, kp_o, 64, iter)
101 nxae_put_tlv(kp, kp_o, 64, 0x30, prf, prf_o[0])
102 let pboid: *u8 = sys_mmap(12); let pbn: i64 = p12oid_pbkdf2(pboid)
103 let kdfalg: *u8 = sys_mmap(96); let kdfalg_o: *i64 = sys_mmap(8) as *i64; kdfalg_o[0] = 0
104 nxae_put_oid(kdfalg, kdfalg_o, 96, pboid, pbn)
105 nxae_put_tlv(kdfalg, kdfalg_o, 96, 0x30, kp, kp_o[0])
106 // AES-128-CBC AlgId
107 let aesoid: *u8 = sys_mmap(12); let aesn: i64 = p12oid_aes128cbc(aesoid)
108 let encalg: *u8 = sys_mmap(48); let encalg_o: *i64 = sys_mmap(8) as *i64; encalg_o[0] = 0
109 nxae_put_oid(encalg, encalg_o, 48, aesoid, aesn)
110 nxae_put_octet_string(encalg, encalg_o, 48, iv, 16)
111 // PBES2-params SEQ { PBKDF2 AlgId, AES-CBC AlgId }
112 let pbes2p: *u8 = sys_mmap(256); let pbes2p_o: *i64 = sys_mmap(8) as *i64; pbes2p_o[0] = 0
113 nxae_put_tlv(pbes2p, pbes2p_o, 256, 0x30, kdfalg, kdfalg_o[0])
114 nxae_put_tlv(pbes2p, pbes2p_o, 256, 0x30, encalg, encalg_o[0])
115 // PBES2 AlgId SEQ { OID pbes2, params }
116 let pbes2oid: *u8 = sys_mmap(12); let pbes2n: i64 = p12oid_pbes2(pbes2oid)
117 let encinfo: *u8 = sys_mmap(320); let encinfo_o: *i64 = sys_mmap(8) as *i64; encinfo_o[0] = 0
118 nxae_put_oid(encinfo, encinfo_o, 320, pbes2oid, pbes2n)
119 nxae_put_tlv(encinfo, encinfo_o, 320, 0x30, pbes2p, pbes2p_o[0])
120 // EncryptedPrivateKeyInfo SEQ { encinfo, OCTET STRING(enc) }
121 let epki_in: *u8 = sys_mmap(320 + pad_n); let epki_in_o: *i64 = sys_mmap(8) as *i64; epki_in_o[0] = 0
122 nxae_put_tlv(epki_in, epki_in_o, 320 + pad_n, 0x30, encinfo, encinfo_o[0])
123 nxae_put_octet_string(epki_in, epki_in_o, 320 + pad_n, enc, pad_n)
124 let epki: *u8 = sys_mmap(360 + pad_n); let epki_o: *i64 = sys_mmap(8) as *i64; epki_o[0] = 0
125 nxae_put_tlv(epki, epki_o, 360 + pad_n, 0x30, epki_in, epki_in_o[0])
126
127 // ===== 3. ShroudedKeyBag = SEQ { OID pkcs8ShroudedKeyBag, [0]{ epki } } =====
128 let skboid: *u8 = sys_mmap(12); let skbn: i64 = p12oid_shroudedkeybag(skboid)
129 let keybag_in: *u8 = sys_mmap(400 + pad_n); let keybag_in_o: *i64 = sys_mmap(8) as *i64; keybag_in_o[0] = 0
130 nxae_put_oid(keybag_in, keybag_in_o, 400 + pad_n, skboid, skbn)
131 nxae_put_context_explicit(keybag_in, keybag_in_o, 400 + pad_n, 0, epki, epki_o[0])
132 let keybag: *u8 = sys_mmap(420 + pad_n); let keybag_o: *i64 = sys_mmap(8) as *i64; keybag_o[0] = 0
133 nxae_put_tlv(keybag, keybag_o, 420 + pad_n, 0x30, keybag_in, keybag_in_o[0])
134
135 // ===== 4. CertBag = SEQ { OID certBag, [0]{ SEQ { OID x509Certificate, [0]{ OCTET STRING(cert) } } } } =====
136 let x509oid: *u8 = sys_mmap(12); let x509n: i64 = p12oid_x509cert(x509oid)
137 let certoctet: *u8 = sys_mmap(cert_len + 8); let certoctet_o: *i64 = sys_mmap(8) as *i64; certoctet_o[0] = 0
138 nxae_put_octet_string(certoctet, certoctet_o, cert_len + 8, cert_der, cert_len)
139 let cbval_in: *u8 = sys_mmap(cert_len + 32); let cbval_in_o: *i64 = sys_mmap(8) as *i64; cbval_in_o[0] = 0
140 nxae_put_oid(cbval_in, cbval_in_o, cert_len + 32, x509oid, x509n)
141 nxae_put_context_explicit(cbval_in, cbval_in_o, cert_len + 32, 0, certoctet, certoctet_o[0])
142 let cbval: *u8 = sys_mmap(cert_len + 48); let cbval_o: *i64 = sys_mmap(8) as *i64; cbval_o[0] = 0
143 nxae_put_tlv(cbval, cbval_o, cert_len + 48, 0x30, cbval_in, cbval_in_o[0])
144 let cboid: *u8 = sys_mmap(12); let cbn: i64 = p12oid_certbag(cboid)
145 let certbag_in: *u8 = sys_mmap(cert_len + 64); let certbag_in_o: *i64 = sys_mmap(8) as *i64; certbag_in_o[0] = 0
146 nxae_put_oid(certbag_in, certbag_in_o, cert_len + 64, cboid, cbn)
147 nxae_put_context_explicit(certbag_in, certbag_in_o, cert_len + 64, 0, cbval, cbval_o[0])
148 let certbag: *u8 = sys_mmap(cert_len + 80); let certbag_o: *i64 = sys_mmap(8) as *i64; certbag_o[0] = 0
149 nxae_put_tlv(certbag, certbag_o, cert_len + 80, 0x30, certbag_in, certbag_in_o[0])
150
151 // ===== 5. SafeContents = SEQ OF { keybag, certbag } =====
152 let sc_in: *u8 = sys_mmap(big); let sc_in_o: *i64 = sys_mmap(8) as *i64; sc_in_o[0] = 0
153 nxae_put_bytes(sc_in, sc_in_o, big, keybag, keybag_o[0])
154 nxae_put_bytes(sc_in, sc_in_o, big, certbag, certbag_o[0])
155 let safec: *u8 = sys_mmap(big); let safec_o: *i64 = sys_mmap(8) as *i64; safec_o[0] = 0
156 nxae_put_tlv(safec, safec_o, big, 0x30, sc_in, sc_in_o[0])
157
158 // ===== 6. AuthenticatedSafe = SEQ OF ContentInfo{ data, [0]{ OCTET STRING(SafeContents) } } =====
159 let dataoid: *u8 = sys_mmap(12); let datan: i64 = p12oid_data(dataoid)
160 let scoctet: *u8 = sys_mmap(big); let scoctet_o: *i64 = sys_mmap(8) as *i64; scoctet_o[0] = 0
161 nxae_put_octet_string(scoctet, scoctet_o, big, safec, safec_o[0])
162 let ci_in: *u8 = sys_mmap(big); let ci_in_o: *i64 = sys_mmap(8) as *i64; ci_in_o[0] = 0
163 nxae_put_oid(ci_in, ci_in_o, big, dataoid, datan)
164 nxae_put_context_explicit(ci_in, ci_in_o, big, 0, scoctet, scoctet_o[0])
165 let ci: *u8 = sys_mmap(big); let ci_o: *i64 = sys_mmap(8) as *i64; ci_o[0] = 0
166 nxae_put_tlv(ci, ci_o, big, 0x30, ci_in, ci_in_o[0])
167 let authsafe: *u8 = sys_mmap(big); let authsafe_o: *i64 = sys_mmap(8) as *i64; authsafe_o[0] = 0
168 nxae_put_tlv(authsafe, authsafe_o, big, 0x30, ci, ci_o[0])
169
170 // ===== 7. MacData over the AuthenticatedSafe DER =====
171 let bmp: *u8 = sys_mmap(pw_n*2 + 4); let bmp_n: i64 = nx_pkcs12_bmp_password(pw_ascii, pw_n, bmp)
172 let mackey: *u8 = sys_mmap(32); nx_pkcs12_kdf(bmp, bmp_n, mac_salt, 8, iter, 3, 32, mackey)
173 let mac: *u8 = sys_mmap(32); hmac_sha256(mackey, 32, authsafe, authsafe_o[0], mac)
174 let shaoid: *u8 = sys_mmap(12); let shan: i64 = p12oid_sha256(shaoid)
175 let digalg: *u8 = sys_mmap(24); let digalg_o: *i64 = sys_mmap(8) as *i64; digalg_o[0] = 0
176 nxae_put_oid(digalg, digalg_o, 24, shaoid, shan); nxae_put_null(digalg, digalg_o, 24)
177 let dig_in: *u8 = sys_mmap(80); let dig_in_o: *i64 = sys_mmap(8) as *i64; dig_in_o[0] = 0
178 nxae_put_tlv(dig_in, dig_in_o, 80, 0x30, digalg, digalg_o[0])
179 nxae_put_octet_string(dig_in, dig_in_o, 80, mac, 32)
180 let diginfo: *u8 = sys_mmap(96); let diginfo_o: *i64 = sys_mmap(8) as *i64; diginfo_o[0] = 0
181 nxae_put_tlv(diginfo, diginfo_o, 96, 0x30, dig_in, dig_in_o[0])
182 let md_in: *u8 = sys_mmap(128); let md_in_o: *i64 = sys_mmap(8) as *i64; md_in_o[0] = 0
183 nxae_put_bytes(md_in, md_in_o, 128, diginfo, diginfo_o[0])
184 nxae_put_octet_string(md_in, md_in_o, 128, mac_salt, 8)
185 p12_put_uint(md_in, md_in_o, 128, iter)
186 let macdata: *u8 = sys_mmap(144); let macdata_o: *i64 = sys_mmap(8) as *i64; macdata_o[0] = 0
187 nxae_put_tlv(macdata, macdata_o, 144, 0x30, md_in, md_in_o[0])
188
189 // ===== 8. PFX = SEQ { version 3, authSafe ContentInfo, macData } =====
190 let asoctet: *u8 = sys_mmap(big); let asoctet_o: *i64 = sys_mmap(8) as *i64; asoctet_o[0] = 0
191 nxae_put_octet_string(asoctet, asoctet_o, big, authsafe, authsafe_o[0])
192 let asci_in: *u8 = sys_mmap(big); let asci_in_o: *i64 = sys_mmap(8) as *i64; asci_in_o[0] = 0
193 nxae_put_oid(asci_in, asci_in_o, big, dataoid, datan)
194 nxae_put_context_explicit(asci_in, asci_in_o, big, 0, asoctet, asoctet_o[0])
195 let asci: *u8 = sys_mmap(big); let asci_o: *i64 = sys_mmap(8) as *i64; asci_o[0] = 0
196 nxae_put_tlv(asci, asci_o, big, 0x30, asci_in, asci_in_o[0])
197 let pfx_in: *u8 = sys_mmap(big); let pfx_in_o: *i64 = sys_mmap(8) as *i64; pfx_in_o[0] = 0
198 nxae_put_int_u8(pfx_in, pfx_in_o, big, 3)
199 nxae_put_bytes(pfx_in, pfx_in_o, big, asci, asci_o[0])
200 nxae_put_bytes(pfx_in, pfx_in_o, big, macdata, macdata_o[0])
201 var fo: i64 = 0
202 nxae_put_tlv(out, &fo, cap, 0x30, pfx_in, pfx_in_o[0])
203 out_n[0] = fo
204 return 0
205}
206
207// ===================== GATE: emit a real .p12 to /tmp for openssl validation =====================
208func p12_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
209func p12_putn(v: i64) -> i64 { let t: *u8 = sys_mmap(24); var m: i64 = v; var k: i64 = 0; if m==0 { t[0]=48 as u8; k=1 } while m>0 { t[k]=(48+(m%10)) as u8; m=m/10; k=k+1 } let o: *u8 = sys_mmap(24); var i: i64=0; while i<k { o[i]=t[k-1-i]; i=i+1 } sys_write(1,o,k); return 0 }
210
211func main() -> i64 {
212 p12_puts("nx_mtls_pkcs12 gate: emit a real .p12 -> /tmp/nishi_test.p12 (then validate with openssl)\n" as *u8)
213 let seed: *u8 = sys_mmap(32); var i: i64 = 0; while i < 32 { seed[i] = (0x40 + i) as u8; i = i + 1 }
214 let pub: *u8 = sys_mmap(32); ed25519_pub_from_priv(seed, pub)
215 let serial: *u8 = sys_mmap(8)
216 serial[0]=0x4a as u8; serial[1]=0x10 as u8; serial[2]=0x20 as u8; serial[3]=0x30 as u8
217 serial[4]=0x40 as u8; serial[5]=0x50 as u8; serial[6]=0x60 as u8; serial[7]=0x70 as u8
218 let cert: *u8 = sys_mmap(K_MAGIC_4096); let cl: *i64 = sys_mmap(8) as *i64
219 if nx_x509_leaf_emit_ed25519(seed, pub, "nishi-uid-test0001" as *u8, 18, serial, 8, "260101000000Z" as *u8, "360101000000Z" as *u8, cert, K_MAGIC_4096, cl) != 0 { p12_puts("CERT FAIL\n" as *u8); sys_exit(1) }
220
221 let p12: *u8 = sys_mmap(K_MAGIC_8192); let pn: *i64 = sys_mmap(8) as *i64
222 if nx_mtls_emit_pkcs12(seed, pub, cert, cl[0], "nishi" as *u8, 5, p12, K_MAGIC_8192, pn) != 0 { p12_puts("EMIT FAIL\n" as *u8); sys_exit(1) }
223
224 let fd: i64 = sys_openat_wr("/tmp/nishi_test.p12" as *u8, 0x1a4)
225 if fd >= 0 { sys_write(fd, p12, pn[0]); sys_close(fd) } else { p12_puts("WRITE FAIL\n" as *u8); sys_exit(1) }
226 p12_puts("wrote /tmp/nishi_test.p12 bytes="); p12_putn(pn[0]); p12_puts(" (password: nishi)\n" as *u8)
227 p12_puts("NX-MTLS-PKCS12 EMITTED -- validate: openssl pkcs12 -in /tmp/nishi_test.p12 -passin pass:nishi -info -noout\n" as *u8)
228 sys_exit(0)
229 return 0
230}