micro509 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +220 -0
  3. package/dist/index.d.ts +21 -0
  4. package/dist/index.js +1 -0
  5. package/dist/internal/asn1/asn1.js +2 -0
  6. package/dist/internal/asn1/asn1.js.map +1 -0
  7. package/dist/internal/asn1/der.js +2 -0
  8. package/dist/internal/asn1/der.js.map +1 -0
  9. package/dist/internal/asn1/oids.js +2 -0
  10. package/dist/internal/asn1/oids.js.map +1 -0
  11. package/dist/internal/crypto/algorithm-names.js +2 -0
  12. package/dist/internal/crypto/algorithm-names.js.map +1 -0
  13. package/dist/internal/crypto/ecdsa.js +2 -0
  14. package/dist/internal/crypto/ecdsa.js.map +1 -0
  15. package/dist/internal/crypto/hash.js +2 -0
  16. package/dist/internal/crypto/hash.js.map +1 -0
  17. package/dist/internal/crypto/pbes2.d.ts +23 -0
  18. package/dist/internal/crypto/pbes2.js +2 -0
  19. package/dist/internal/crypto/pbes2.js.map +1 -0
  20. package/dist/internal/crypto/rsa-pss.js +2 -0
  21. package/dist/internal/crypto/rsa-pss.js.map +1 -0
  22. package/dist/internal/crypto/sig-verify.js +2 -0
  23. package/dist/internal/crypto/sig-verify.js.map +1 -0
  24. package/dist/internal/crypto/signing.d.ts +16 -0
  25. package/dist/internal/crypto/signing.js +2 -0
  26. package/dist/internal/crypto/signing.js.map +1 -0
  27. package/dist/internal/crypto/webcrypto.js +2 -0
  28. package/dist/internal/crypto/webcrypto.js.map +1 -0
  29. package/dist/internal/shared/base64.js +2 -0
  30. package/dist/internal/shared/base64.js.map +1 -0
  31. package/dist/internal/shared/dn.js +2 -0
  32. package/dist/internal/shared/dn.js.map +1 -0
  33. package/dist/internal/shared/ip.js +2 -0
  34. package/dist/internal/shared/ip.js.map +1 -0
  35. package/dist/internal/verify/name-constraints-engine.js +2 -0
  36. package/dist/internal/verify/name-constraints-engine.js.map +1 -0
  37. package/dist/internal/verify/policy-engine.js +2 -0
  38. package/dist/internal/verify/policy-engine.js.map +1 -0
  39. package/dist/internal/verify/verify-path.js +2 -0
  40. package/dist/internal/verify/verify-path.js.map +1 -0
  41. package/dist/internal/x509/extension-bits.d.ts +18 -0
  42. package/dist/internal/x509/extension-bits.js +2 -0
  43. package/dist/internal/x509/extension-bits.js.map +1 -0
  44. package/dist/internal/x509/extension-registry.js +2 -0
  45. package/dist/internal/x509/extension-registry.js.map +1 -0
  46. package/dist/internal/x509/name-fields.js +2 -0
  47. package/dist/internal/x509/name-fields.js.map +1 -0
  48. package/dist/keys/keys.d.ts +431 -0
  49. package/dist/keys/keys.js +5 -0
  50. package/dist/keys/keys.js.map +1 -0
  51. package/dist/keys.d.ts +3 -0
  52. package/dist/keys.js +1 -0
  53. package/dist/pem/pem.d.ts +56 -0
  54. package/dist/pem/pem.js +6 -0
  55. package/dist/pem/pem.js.map +1 -0
  56. package/dist/pem.d.ts +2 -0
  57. package/dist/pem.js +1 -0
  58. package/dist/pkcs/pfx.d.ts +177 -0
  59. package/dist/pkcs/pfx.js +2 -0
  60. package/dist/pkcs/pfx.js.map +1 -0
  61. package/dist/pkcs/pkcs12-mac.d.ts +41 -0
  62. package/dist/pkcs/pkcs12-mac.js +2 -0
  63. package/dist/pkcs/pkcs12-mac.js.map +1 -0
  64. package/dist/pkcs/pkcs7.d.ts +131 -0
  65. package/dist/pkcs/pkcs7.js +2 -0
  66. package/dist/pkcs/pkcs7.js.map +1 -0
  67. package/dist/pkcs.d.ts +5 -0
  68. package/dist/pkcs.js +1 -0
  69. package/dist/result/result.d.ts +68 -0
  70. package/dist/result/result.js +2 -0
  71. package/dist/result/result.js.map +1 -0
  72. package/dist/result.d.ts +2 -0
  73. package/dist/result.js +1 -0
  74. package/dist/revocation/chain.d.ts +180 -0
  75. package/dist/revocation/chain.js +2 -0
  76. package/dist/revocation/chain.js.map +1 -0
  77. package/dist/revocation/crl.d.ts +316 -0
  78. package/dist/revocation/crl.js +2 -0
  79. package/dist/revocation/crl.js.map +1 -0
  80. package/dist/revocation/ocsp.d.ts +332 -0
  81. package/dist/revocation/ocsp.js +2 -0
  82. package/dist/revocation/ocsp.js.map +1 -0
  83. package/dist/revocation/revocation.d.ts +168 -0
  84. package/dist/revocation/revocation.js +2 -0
  85. package/dist/revocation/revocation.js.map +1 -0
  86. package/dist/revocation.d.ts +5 -0
  87. package/dist/revocation.js +1 -0
  88. package/dist/verify/identity.d.ts +129 -0
  89. package/dist/verify/identity.js +2 -0
  90. package/dist/verify/identity.js.map +1 -0
  91. package/dist/verify/name-constraints.d.ts +18 -0
  92. package/dist/verify/policy.d.ts +39 -0
  93. package/dist/verify/verify.d.ts +404 -0
  94. package/dist/verify/verify.js +2 -0
  95. package/dist/verify/verify.js.map +1 -0
  96. package/dist/verify.d.ts +5 -0
  97. package/dist/verify.js +1 -0
  98. package/dist/x509/certificate.d.ts +191 -0
  99. package/dist/x509/certificate.js +2 -0
  100. package/dist/x509/certificate.js.map +1 -0
  101. package/dist/x509/csr.d.ts +55 -0
  102. package/dist/x509/csr.js +2 -0
  103. package/dist/x509/csr.js.map +1 -0
  104. package/dist/x509/extensions.d.ts +550 -0
  105. package/dist/x509/extensions.js +2 -0
  106. package/dist/x509/extensions.js.map +1 -0
  107. package/dist/x509/name.d.ts +140 -0
  108. package/dist/x509/name.js +2 -0
  109. package/dist/x509/name.js.map +1 -0
  110. package/dist/x509/parse.d.ts +377 -0
  111. package/dist/x509/parse.js +2 -0
  112. package/dist/x509/parse.js.map +1 -0
  113. package/dist/x509.d.ts +8 -0
  114. package/dist/x509.js +1 -0
  115. package/package.json +153 -0
@@ -0,0 +1,5 @@
1
+ import{nullValue as e,objectIdentifier as t,octetString as n,readSequenceChildren as r,sequence as i}from"../internal/asn1/der.js";import{decodeObjectIdentifier as a,extractBitStringValue as o,hexToBytes as s,toArrayBuffer as c,toHex as l}from"../internal/asn1/asn1.js";import{OIDS as u}from"../internal/asn1/oids.js";import{md5 as d}from"../internal/crypto/hash.js";import{getCrypto as f}from"../internal/crypto/webcrypto.js";import{decryptPbes2 as p,encryptPbes2 as m}from"../internal/crypto/pbes2.js";import{base64Decode as h,base64Encode as g}from"../internal/shared/base64.js";import{pemDecode as _,pemEncode as v}from"../pem/pem.js";async function y(e={kind:`ecdsa`,curve:`P-256`}){let t=await f().subtle.generateKey(K(e),!0,[`sign`,`verify`]);if(!(`publicKey`in t)||!(`privateKey`in t))throw Error(`Expected an asymmetric key pair`);return b(t.publicKey,t.privateKey)}function b(e,t){return{publicKey:e,privateKey:t,async exportSpkiDer(){return new Uint8Array(await f().subtle.exportKey(`spki`,e))},async exportSpkiPem(){return v(`PUBLIC KEY`,await this.exportSpkiDer())},async exportPkcs8Der(){return new Uint8Array(await f().subtle.exportKey(`pkcs8`,t))},async exportPkcs8Pem(){return v(`PRIVATE KEY`,await this.exportPkcs8Der())},async exportPublicJwk(){return f().subtle.exportKey(`jwk`,e)},async exportPrivateJwk(){return f().subtle.exportKey(`jwk`,t)}}}async function x(e){return new Uint8Array(await f().subtle.exportKey(`spki`,e))}async function S(e){return new Uint8Array(await f().subtle.exportKey(`pkcs8`,e))}async function ee(e){return f().subtle.exportKey(`jwk`,e)}async function C(e){return f().subtle.exportKey(`jwk`,e)}async function w(e){return v(`PRIVATE KEY`,await S(e))}async function T(e,t){let r=await m(await S(e),t);return i([r.algorithmIdentifierDer,n(r.encryptedData)])}async function E(e,t){return v(`ENCRYPTED PRIVATE KEY`,await T(e,t))}async function D(e){let t=J(await S(e));if(t.algorithmOid!==u.rsaEncryption)throw Error(`PKCS#1 export requires an RSA private key`);return t.privateKeyDer}async function O(e){return v(`RSA PRIVATE KEY`,await D(e))}async function te(e,t){return Z(`RSA PRIVATE KEY`,await D(e),t)}async function k(e){let t=J(await S(e));if(t.algorithmOid!==u.ecPublicKey)throw Error(`SEC1 export requires an EC private key`);return t.privateKeyDer}async function ne(e){return v(`EC PRIVATE KEY`,await k(e))}async function re(e,t){return Z(`EC PRIVATE KEY`,await k(e),t)}async function ie(e){return v(`PUBLIC KEY`,await x(e))}async function A(e){if(e.type===`public`)return g(await x(e));if(e.type===`private`)return g(await S(e));throw Error(`Cannot export secret/symmetric CryptoKey`)}async function j(e,t){me(pe(e),t);try{return await f().subtle.importKey(`spki`,new Uint8Array(e),q(t),!0,[`verify`])}catch{throw Error(`Malformed SubjectPublicKeyInfo`)}}async function M(e,t){return j(_(`PUBLIC KEY`,e),t)}async function N(e,t){let n;try{n=h(e)}catch{throw Error(`Invalid base64 SubjectPublicKeyInfo`)}return j(n,t)}async function P(e,t){let n;try{n=J(e)}catch{throw Error(`Malformed PKCS#8 private key`)}he(n,t);try{return await f().subtle.importKey(`pkcs8`,new Uint8Array(e),q(t),!0,[`sign`])}catch{throw Error(`Malformed PKCS#8 private key`)}}async function F(e,t){return P(_(`PRIVATE KEY`,e),t)}async function I(e,t,n){let i;try{i=r(e)}catch{throw Error(`Malformed EncryptedPrivateKeyInfo`)}let a=i[0],o=i[1];if(i.length!==2||a===void 0||o===void 0||o.tag!==4)throw Error(`Malformed EncryptedPrivateKeyInfo`);return P(await p(e.slice(a.start-a.headerLength,a.end),o.value,t),n)}async function L(e,t,n){return I(_(`ENCRYPTED PRIVATE KEY`,e),t,n)}async function R(e,t={kind:`rsa`}){return P(oe(e),t)}async function z(e,t={kind:`rsa`}){return R(_(`RSA PRIVATE KEY`,e),t)}async function B(e,t,n={kind:`rsa`}){return R(await Q(`RSA PRIVATE KEY`,e,t),n)}async function V(e,t){let n;try{n=h(e)}catch{throw Error(`Invalid base64 PKCS#8 private key`)}return P(n,t)}async function H(e,t){return P(se(e,t.curve),t)}async function U(e,t){return H(_(`EC PRIVATE KEY`,e),t)}async function W(e,t,n){return H(await Q(`EC PRIVATE KEY`,e,t),n)}async function ae(e,t){ge(e,t);try{return await f().subtle.importKey(`jwk`,e,q(t),!0,[`verify`])}catch{throw Error(`Malformed public JWK`)}}async function G(e,t){return f().subtle.importKey(`jwk`,e,q(t),!0,[`sign`])}function K(e){switch(e.kind){case`rsa`:return{name:X(e.scheme),modulusLength:e.modulusLength??2048,publicExponent:Uint8Array.of(1,0,1),hash:e.hash??`SHA-256`};case`ecdsa`:return{name:`ECDSA`,namedCurve:e.curve??`P-256`};case`ed25519`:return{name:`Ed25519`}}}function q(e){switch(e.kind){case`rsa`:return{name:X(e.scheme),hash:e.hash??`SHA-256`};case`ecdsa`:return{name:`ECDSA`,namedCurve:e.curve};case`ed25519`:return{name:`Ed25519`}}}function J(e){let t=r(e),n=t[1],i=t[2];if(t.length<3||t.length>4||n===void 0||n.tag!==48||i===void 0||i.tag!==4)throw Error(`Malformed PKCS#8 private key`);let o=r(e.slice(n.start-n.headerLength,n.end)),s=o[0];if(s===void 0||s.tag!==6||o.length<1||o.length>2)throw Error(`Malformed PKCS#8 private key`);let c=o[1];return{algorithmOid:a(s.value),...c===void 0?{}:{parametersTag:c.tag},...c?.tag===6?{parametersOid:a(c.value)}:{},privateKeyDer:i.value}}function oe(r){return i([Uint8Array.of(2,1,0),i([t(u.rsaEncryption),e()]),n(new Uint8Array(r))])}function se(e,r){return i([Uint8Array.of(2,1,0),i([t(u.ecPublicKey),t(Y(r))]),n(new Uint8Array(e))])}function Y(e){switch(e){case`P-256`:return u.prime256v1;case`P-384`:return u.secp384r1;case`P-521`:return u.secp521r1}}function X(e){return e===`pss`?`RSA-PSS`:`RSASSA-PKCS1-v1_5`}async function Z(e,t,n){let r=n.iv??f().getRandomValues(new Uint8Array(16));if(r.length!==16)throw Error(`Traditional PEM encryption requires a 16-byte IV`);let i=n.cipher??`AES-256-CBC`,a=await $(n.password,r.slice(0,8),i,[`encrypt`]),o=g(new Uint8Array(await f().subtle.encrypt({name:`AES-CBC`,iv:c(r)},a,c(t)))).match(/.{1,64}/g)?.join(`
2
+ `)??``;return[`-----BEGIN ${e}-----`,`Proc-Type: 4,ENCRYPTED`,`DEK-Info: ${i},${l(r).toUpperCase()}`,``,o,`-----END ${e}-----`].join(`
3
+ `)}async function Q(e,t,n){let r=fe(t);if(r.label!==e)throw Error(`Expected ${e} PEM block`);let i=r.headers.get(`DEK-Info`);if(r.headers.get(`Proc-Type`)!==`4,ENCRYPTED`||i===void 0)throw Error(`Traditional PEM encryption headers missing`);let[a,o]=i.split(`,`);if(!ce(a)||o===void 0)throw Error(`Only AES-128-CBC, AES-192-CBC, and AES-256-CBC traditional PEM encryption is supported`);if(!le(o))throw Error(`Traditional PEM encryption requires a 16-byte IV encoded as 32 hex characters`);let l=s(o),u=await $(n,l.slice(0,8),a,[`decrypt`]);try{return new Uint8Array(await f().subtle.decrypt({name:`AES-CBC`,iv:c(l)},u,c(h(r.base64Body))))}catch{throw Error(`Invalid password or encrypted PEM content`)}}async function $(e,t,n,r){let i=ue(n),a=de(e,t,i/8);return f().subtle.importKey(`raw`,c(a),{name:`AES-CBC`,length:i},!1,r)}function ce(e){return e===`AES-128-CBC`||e===`AES-192-CBC`||e===`AES-256-CBC`}function le(e){return e.length===32&&/^[0-9A-Fa-f]+$/.test(e)}function ue(e){switch(e){case`AES-128-CBC`:return 128;case`AES-192-CBC`:return 192;case`AES-256-CBC`:return 256}}function de(e,t,n){let r=new TextEncoder().encode(e),i=[],a=new Uint8Array,o=0;for(;o<n;){let e=new Uint8Array(a.length+r.length+t.length);e.set(a,0),e.set(r,a.length),e.set(t,a.length+r.length),a=d(e),i.push(a),o+=a.length}let s=new Uint8Array(n),c=0;for(let e of i){let t=e.slice(0,Math.min(e.length,n-c));if(s.set(t,c),c+=t.length,c>=n)break}return s}function fe(e){let t=e.replace(/\r/g,``).trim().split(`
4
+ `),n=t[0],r=t[t.length-1];if(n===void 0||r===void 0||!n.startsWith(`-----BEGIN `)||!r.startsWith(`-----END `))throw Error(`Invalid PEM block`);let i=n.slice(11,-5);if(r!==`-----END ${i}-----`)throw Error(`PEM boundaries do not match`);let a=new Map,o=1;for(;o<t.length-1;){let e=t[o];if(e===void 0)break;if(e.length===0){o+=1;break}let n=e.indexOf(`: `);if(n===-1)break;let r=e.slice(0,n);if(a.has(r))throw Error(`Duplicate PEM header: ${r}`);a.set(r,e.slice(n+2)),o+=1}return{label:i,headers:a,base64Body:t.slice(o,t.length-1).join(``)}}function pe(e){try{let t=r(e);if(t.length!==2)throw Error(`Malformed SubjectPublicKeyInfo`);let n=t[0],i=t[1];if(n===void 0||n.tag!==48||i===void 0||i.tag!==3)throw Error(`Malformed SubjectPublicKeyInfo`);o(i);let s=r(e.slice(n.start-n.headerLength,n.end)),c=s[0];if(c===void 0||c.tag!==6||s.length<1||s.length>2)throw Error(`Malformed SubjectPublicKeyInfo`);let l=s[1];return{algorithmOid:a(c.value),...l===void 0?{}:{parametersTag:l.tag},...l?.tag===6?{parametersOid:a(l.value)}:{}}}catch{throw Error(`Malformed SubjectPublicKeyInfo`)}}function me(e,t){switch(t.kind){case`rsa`:if(e.algorithmOid!==u.rsaEncryption||e.parametersTag!==void 0&&e.parametersTag!==5)throw Error(`SubjectPublicKeyInfo algorithm does not match requested import algorithm`);return;case`ecdsa`:if(e.algorithmOid!==u.ecPublicKey||e.parametersTag!==6||e.parametersOid!==Y(t.curve))throw Error(`SubjectPublicKeyInfo algorithm does not match requested import algorithm`);return;case`ed25519`:if(e.algorithmOid!==u.ed25519||e.parametersTag!==void 0)throw Error(`SubjectPublicKeyInfo algorithm does not match requested import algorithm`);return}}function he(e,t){switch(t.kind){case`rsa`:if(e.algorithmOid!==u.rsaEncryption||e.parametersTag!==void 0&&e.parametersTag!==5)throw Error(`PKCS#8 private key algorithm does not match requested import algorithm`);return;case`ecdsa`:if(e.algorithmOid!==u.ecPublicKey||e.parametersTag!==6||e.parametersOid!==Y(t.curve))throw Error(`PKCS#8 private key algorithm does not match requested import algorithm`);return;case`ed25519`:if(e.algorithmOid!==u.ed25519||e.parametersTag!==void 0)throw Error(`PKCS#8 private key algorithm does not match requested import algorithm`);return}}function ge(e,t){if(e.k!==void 0||e.d!==void 0||e.p!==void 0||e.q!==void 0||e.dp!==void 0||e.dq!==void 0||e.qi!==void 0||e.oth!==void 0)throw Error(`Public JWK must not contain private key material`);switch(t.kind){case`rsa`:if(e.kty!==`RSA`||typeof e.n!=`string`||typeof e.e!=`string`)throw Error(`Public JWK algorithm does not match requested import algorithm`);return;case`ecdsa`:if(e.kty!==`EC`||e.crv!==t.curve||typeof e.x!=`string`||typeof e.y!=`string`)throw Error(`Public JWK algorithm does not match requested import algorithm`);return;case`ed25519`:if(e.kty!==`OKP`||e.crv!==`Ed25519`||typeof e.x!=`string`)throw Error(`Public JWK algorithm does not match requested import algorithm`);return}}export{A as exportBinaryBase64,te as exportEncryptedPkcs1Pem,T as exportEncryptedPkcs8Der,E as exportEncryptedPkcs8Pem,re as exportEncryptedSec1Pem,D as exportPkcs1Der,O as exportPkcs1Pem,S as exportPkcs8Der,w as exportPkcs8Pem,C as exportPrivateJwk,ee as exportPublicJwk,k as exportSec1Der,ne as exportSec1Pem,x as exportSpkiDer,ie as exportSpkiPem,y as generateKeyPair,B as importEncryptedPkcs1Pem,I as importEncryptedPkcs8Der,L as importEncryptedPkcs8Pem,W as importEncryptedSec1Pem,R as importPkcs1Der,z as importPkcs1Pem,V as importPkcs8Base64,P as importPkcs8Der,F as importPkcs8Pem,G as importPrivateJwk,ae as importPublicJwk,H as importSec1Der,U as importSec1Pem,N as importSpkiBase64,j as importSpkiDer,M as importSpkiPem};
5
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","names":[],"sources":["../../src/keys/keys.ts"],"sourcesContent":["/**\n * WebCrypto key generation plus import/export for PKCS#1, PKCS#8, SEC1, SPKI, and JWK.\n *\n * Supports RSA (PKCS#1v1.5 and PSS), ECDSA (P-256, P-384, P-521), and Ed25519 keys.\n * All functions use the WebCrypto API and return extractable keys.\n *\n * @example\n * ```ts\n * import { generateKeyPair, exportPkcs8Pem, importSpkiPem } from 'micro509/keys';\n *\n * // Generate and export\n * const keys = await generateKeyPair({ kind: 'ecdsa', curve: 'P-256' });\n * const privatePem = await exportPkcs8Pem(keys.privateKey);\n *\n * // Import\n * const publicKey = await importSpkiPem(publicPem, { kind: 'ecdsa', curve: 'P-256' });\n * ```\n *\n * @module\n */\n\nimport {\n\tdecodeObjectIdentifier,\n\textractBitStringValue,\n\thexToBytes,\n\ttoArrayBuffer,\n\ttoHex,\n} from '#micro509/internal/asn1/asn1.ts';\nimport {\n\tnullValue,\n\tobjectIdentifier,\n\toctetString,\n\treadSequenceChildren,\n\tsequence,\n} from '#micro509/internal/asn1/der.ts';\nimport { OIDS } from '#micro509/internal/asn1/oids.ts';\nimport { md5 } from '#micro509/internal/crypto/hash.ts';\nimport {\n\tdecryptPbes2,\n\tencryptPbes2,\n\ttype Pbes2EncryptionOptions,\n} from '#micro509/internal/crypto/pbes2.ts';\nimport { getCrypto } from '#micro509/internal/crypto/webcrypto.ts';\nimport { base64Decode, base64Encode } from '#micro509/internal/shared/base64.ts';\nimport { pemDecode, pemEncode } from '#micro509/pem/pem.ts';\n\nexport type {\n\tPbes2EncryptionOptions,\n\tPbes2EncryptionScheme,\n\tPbes2Prf,\n} from '#micro509/internal/crypto/pbes2.ts';\n\n/** Hash algorithm paired with an RSA key. */\nexport type RsaHash = 'SHA-256' | 'SHA-384' | 'SHA-512';\n\n/** RSA signature padding scheme. */\nexport type RsaScheme = 'pkcs1-v1_5' | 'pss';\n\n/** NIST elliptic curve for ECDSA keys. */\nexport type EcNamedCurve = 'P-256' | 'P-384' | 'P-521';\n\n/** RSA variant of {@linkcode KeyAlgorithmInput}. */\nexport interface RsaKeyAlgorithmInput {\n\t/** Discriminant selecting RSA key generation. */\n\treadonly kind: 'rsa';\n\t/** RSA modulus size in bits. Defaults to `2048`. */\n\treadonly modulusLength?: 2048 | 3072 | 4096;\n\t/** Hash algorithm for the key. Defaults to `'SHA-256'`. */\n\treadonly hash?: RsaHash;\n\t/** Signature padding scheme. Defaults to `'pkcs1-v1_5'`. */\n\treadonly scheme?: RsaScheme;\n}\n\n/** ECDSA variant of {@linkcode KeyAlgorithmInput}. */\nexport interface EcKeyAlgorithmInput {\n\t/** Discriminant selecting ECDSA key generation. */\n\treadonly kind: 'ecdsa';\n\t/** NIST curve. Defaults to `'P-256'`. */\n\treadonly curve?: EcNamedCurve;\n}\n\n/** Ed25519 variant of {@linkcode KeyAlgorithmInput}. */\nexport interface Ed25519KeyAlgorithmInput {\n\t/** Discriminant selecting Ed25519 key generation. */\n\treadonly kind: 'ed25519';\n}\n\n/** Input for {@linkcode generateKeyPair}. Selects algorithm family and parameters. */\nexport type KeyAlgorithmInput =\n\t| RsaKeyAlgorithmInput\n\t| EcKeyAlgorithmInput\n\t| Ed25519KeyAlgorithmInput;\n\n/** Key pair with convenience export helpers. Returned by {@linkcode generateKeyPair}. */\nexport interface KeyPairMaterial {\n\t/** The WebCrypto public key (extractable, `verify` usage). */\n\treadonly publicKey: CryptoKey;\n\t/** The WebCrypto private key (extractable, `sign` usage). */\n\treadonly privateKey: CryptoKey;\n\t/** Export the public key as DER-encoded SubjectPublicKeyInfo. */\n\texportSpkiDer(): Promise<Uint8Array>;\n\t/** Export the public key as PEM-encoded SubjectPublicKeyInfo. */\n\texportSpkiPem(): Promise<string>;\n\t/** Export the private key as DER-encoded PKCS#8 PrivateKeyInfo. */\n\texportPkcs8Der(): Promise<Uint8Array>;\n\t/** Export the private key as PEM-encoded PKCS#8 PrivateKeyInfo. */\n\texportPkcs8Pem(): Promise<string>;\n\t/** Export the public key as a JSON Web Key. */\n\texportPublicJwk(): Promise<JsonWebKey>;\n\t/** Export the private key as a JSON Web Key. */\n\texportPrivateJwk(): Promise<JsonWebKey>;\n}\n\n/** RSA variant of {@linkcode PublicKeyImportInput}. */\nexport interface ImportRsaPublicKeyInput {\n\t/** Discriminant selecting RSA import. */\n\treadonly kind: 'rsa';\n\t/** Hash algorithm. Defaults to `'SHA-256'`. */\n\treadonly hash?: RsaHash;\n\t/** Signature padding scheme. Defaults to `'pkcs1-v1_5'`. */\n\treadonly scheme?: RsaScheme;\n}\n\n/** ECDSA variant of {@linkcode PublicKeyImportInput}. */\nexport interface ImportEcPublicKeyInput {\n\t/** Discriminant selecting ECDSA import. */\n\treadonly kind: 'ecdsa';\n\t/** NIST curve the key belongs to. Required for EC import. */\n\treadonly curve: EcNamedCurve;\n}\n\n/** Ed25519 variant of {@linkcode PublicKeyImportInput}. */\nexport interface ImportEd25519PublicKeyInput {\n\t/** Discriminant selecting Ed25519 import. */\n\treadonly kind: 'ed25519';\n}\n\n/** Algorithm descriptor for public key import functions. */\nexport type PublicKeyImportInput =\n\t| ImportRsaPublicKeyInput\n\t| ImportEcPublicKeyInput\n\t| ImportEd25519PublicKeyInput;\n\n/** Algorithm descriptor for private key import functions. Same shape as {@linkcode PublicKeyImportInput}. */\nexport type PrivateKeyImportInput = PublicKeyImportInput;\n\n/** PBES2 encryption options for {@linkcode exportEncryptedPkcs8Der} and {@linkcode exportEncryptedPkcs8Pem}. */\nexport type EncryptedPkcs8Options = Pbes2EncryptionOptions;\n\n/** Options for OpenSSL-style `Proc-Type: 4,ENCRYPTED` PEM encryption (PKCS#1/SEC1). */\nexport interface LegacyPemEncryptionOptions {\n\t/** Passphrase used to derive the encryption key. */\n\treadonly password: string;\n\t/** 16-byte initialization vector. Random when omitted. */\n\treadonly iv?: Uint8Array;\n\t/** AES-CBC cipher. Defaults to `'AES-256-CBC'`. */\n\treadonly cipher?: 'AES-128-CBC' | 'AES-192-CBC' | 'AES-256-CBC';\n}\n\n/**\n * Generate an asymmetric key pair for signing and verification.\n *\n * @example\n * ```ts\n * const ecKeys = await generateKeyPair({ kind: 'ecdsa', curve: 'P-384' });\n * const rsaKeys = await generateKeyPair({ kind: 'rsa', modulusLength: 4096 });\n * const edKeys = await generateKeyPair({ kind: 'ed25519' });\n *\n * // Default: ECDSA P-256\n * const keys = await generateKeyPair();\n * const pem = await keys.exportPkcs8Pem();\n * ```\n */\nexport async function generateKeyPair(\n\talgorithm: KeyAlgorithmInput = { kind: 'ecdsa', curve: 'P-256' },\n): Promise<KeyPairMaterial> {\n\tconst subtle = getCrypto().subtle;\n\tconst generated = await subtle.generateKey(toGenerateKeyAlgorithm(algorithm), true, [\n\t\t'sign',\n\t\t'verify',\n\t]);\n\n\tif (!('publicKey' in generated) || !('privateKey' in generated)) {\n\t\tthrow new Error('Expected an asymmetric key pair');\n\t}\n\n\treturn wrapKeyPair(generated.publicKey, generated.privateKey);\n}\n\nfunction wrapKeyPair(publicKey: CryptoKey, privateKey: CryptoKey): KeyPairMaterial {\n\treturn {\n\t\tpublicKey,\n\t\tprivateKey,\n\t\tasync exportSpkiDer() {\n\t\t\treturn new Uint8Array(await getCrypto().subtle.exportKey('spki', publicKey));\n\t\t},\n\t\tasync exportSpkiPem() {\n\t\t\treturn pemEncode('PUBLIC KEY', await this.exportSpkiDer());\n\t\t},\n\t\tasync exportPkcs8Der() {\n\t\t\treturn new Uint8Array(await getCrypto().subtle.exportKey('pkcs8', privateKey));\n\t\t},\n\t\tasync exportPkcs8Pem() {\n\t\t\treturn pemEncode('PRIVATE KEY', await this.exportPkcs8Der());\n\t\t},\n\t\tasync exportPublicJwk() {\n\t\t\treturn getCrypto().subtle.exportKey('jwk', publicKey);\n\t\t},\n\t\tasync exportPrivateJwk() {\n\t\t\treturn getCrypto().subtle.exportKey('jwk', privateKey);\n\t\t},\n\t};\n}\n\n/**\n * Export a public key as DER-encoded SubjectPublicKeyInfo.\n *\n * @see {@linkcode importSpkiDer} for the inverse operation\n * @see {@linkcode exportSpkiPem} for PEM output\n */\nexport async function exportSpkiDer(publicKey: CryptoKey): Promise<Uint8Array> {\n\treturn new Uint8Array(await getCrypto().subtle.exportKey('spki', publicKey));\n}\n\n/**\n * Export a private key as DER-encoded PKCS#8 PrivateKeyInfo.\n *\n * @see {@linkcode importPkcs8Der} for the inverse operation\n * @see {@linkcode exportPkcs8Pem} for PEM output\n * @see {@linkcode exportEncryptedPkcs8Der} for password-protected export\n */\nexport async function exportPkcs8Der(privateKey: CryptoKey): Promise<Uint8Array> {\n\treturn new Uint8Array(await getCrypto().subtle.exportKey('pkcs8', privateKey));\n}\n\n/**\n * Export a public key as a JSON Web Key.\n *\n * @example\n * ```ts\n * const keys = await generateKeyPair({ kind: 'ecdsa', curve: 'P-256' });\n * const jwk = await exportPublicJwk(keys.publicKey);\n * ```\n */\nexport async function exportPublicJwk(publicKey: CryptoKey): Promise<JsonWebKey> {\n\treturn getCrypto().subtle.exportKey('jwk', publicKey);\n}\n\n/**\n * Export a private key as a JSON Web Key.\n *\n * @see {@linkcode importPrivateJwk} for the inverse operation\n * @see {@linkcode exportPublicJwk} for public key export\n */\nexport async function exportPrivateJwk(privateKey: CryptoKey): Promise<JsonWebKey> {\n\treturn getCrypto().subtle.exportKey('jwk', privateKey);\n}\n\n/**\n * Export a private key as PEM-encoded PKCS#8 PrivateKeyInfo.\n *\n * @example\n * ```ts\n * const keys = await generateKeyPair();\n * const pem = await exportPkcs8Pem(keys.privateKey);\n * // -----BEGIN PRIVATE KEY-----\n * // MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEH...\n * // -----END PRIVATE KEY-----\n * ```\n *\n * @see {@linkcode importPkcs8Pem} for the inverse operation\n * @see {@linkcode exportEncryptedPkcs8Pem} for password-protected export\n */\nexport async function exportPkcs8Pem(privateKey: CryptoKey): Promise<string> {\n\treturn pemEncode('PRIVATE KEY', await exportPkcs8Der(privateKey));\n}\n\n/**\n * Export a private key as DER-encoded PBES2-encrypted PKCS#8 EncryptedPrivateKeyInfo.\n *\n * Uses PBES2 (PKCS#5 v2.1) with AES-CBC and PBKDF2. Compatible with OpenSSL.\n *\n * @param privateKey - The private key to export\n * @param options - Encryption options including password and optional algorithm settings\n *\n * @see {@linkcode importEncryptedPkcs8Der} for the inverse operation\n * @see {@linkcode exportEncryptedPkcs8Pem} for PEM output\n */\nexport async function exportEncryptedPkcs8Der(\n\tprivateKey: CryptoKey,\n\toptions: EncryptedPkcs8Options,\n): Promise<Uint8Array> {\n\tconst pkcs8 = await exportPkcs8Der(privateKey);\n\tconst encryption = await encryptPbes2(pkcs8, options);\n\treturn sequence([encryption.algorithmIdentifierDer, octetString(encryption.encryptedData)]);\n}\n\n/**\n * Export a private key as PEM-encoded PBES2-encrypted PKCS#8 EncryptedPrivateKeyInfo.\n *\n * @example\n * ```ts\n * const keys = await generateKeyPair();\n * const pem = await exportEncryptedPkcs8Pem(keys.privateKey, { password: 'secret' });\n * // -----BEGIN ENCRYPTED PRIVATE KEY-----\n * // MIHsMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAc...\n * // -----END ENCRYPTED PRIVATE KEY-----\n * ```\n *\n * @see {@linkcode importEncryptedPkcs8Pem} for the inverse operation\n */\nexport async function exportEncryptedPkcs8Pem(\n\tprivateKey: CryptoKey,\n\toptions: EncryptedPkcs8Options,\n): Promise<string> {\n\treturn pemEncode('ENCRYPTED PRIVATE KEY', await exportEncryptedPkcs8Der(privateKey, options));\n}\n\n/**\n * Export an RSA private key as DER-encoded PKCS#1 RSAPrivateKey.\n *\n * PKCS#1 is the legacy RSA-only format. For algorithm-agnostic export, use\n * {@linkcode exportPkcs8Der}.\n *\n * @throws {Error} If the key is not an RSA key\n *\n * @see {@linkcode importPkcs1Der} for the inverse operation\n * @see {@linkcode exportPkcs1Pem} for PEM output\n */\nexport async function exportPkcs1Der(privateKey: CryptoKey): Promise<Uint8Array> {\n\tconst pkcs8 = await exportPkcs8Der(privateKey);\n\tconst parsed = parsePkcs8PrivateKey(pkcs8);\n\tif (parsed.algorithmOid !== OIDS.rsaEncryption) {\n\t\tthrow new Error('PKCS#1 export requires an RSA private key');\n\t}\n\treturn parsed.privateKeyDer;\n}\n\n/**\n * Export an RSA private key as PEM-encoded PKCS#1 RSAPrivateKey.\n *\n * @throws {Error} If the key is not an RSA key\n *\n * @see {@linkcode importPkcs1Pem} for the inverse operation\n * @see {@linkcode exportEncryptedPkcs1Pem} for password-protected export\n */\nexport async function exportPkcs1Pem(privateKey: CryptoKey): Promise<string> {\n\treturn pemEncode('RSA PRIVATE KEY', await exportPkcs1Der(privateKey));\n}\n\n/**\n * Export an RSA private key as legacy `Proc-Type: 4,ENCRYPTED` PEM (PKCS#1).\n *\n * Uses OpenSSL's traditional PEM encryption with MD5-based key derivation.\n * For modern encryption, prefer {@linkcode exportEncryptedPkcs8Pem}.\n *\n * @throws {Error} If the key is not an RSA key\n *\n * @see {@linkcode importEncryptedPkcs1Pem} for the inverse operation\n */\nexport async function exportEncryptedPkcs1Pem(\n\tprivateKey: CryptoKey,\n\toptions: LegacyPemEncryptionOptions,\n): Promise<string> {\n\treturn encryptTraditionalPem('RSA PRIVATE KEY', await exportPkcs1Der(privateKey), options);\n}\n\n/**\n * Export an EC private key as DER-encoded SEC 1 ECPrivateKey.\n *\n * SEC 1 is the legacy EC-only format. For algorithm-agnostic export, use\n * {@linkcode exportPkcs8Der}.\n *\n * @throws {Error} If the key is not an EC key\n *\n * @see {@linkcode importSec1Der} for the inverse operation\n * @see {@linkcode exportSec1Pem} for PEM output\n */\nexport async function exportSec1Der(privateKey: CryptoKey): Promise<Uint8Array> {\n\tconst pkcs8 = await exportPkcs8Der(privateKey);\n\tconst parsed = parsePkcs8PrivateKey(pkcs8);\n\tif (parsed.algorithmOid !== OIDS.ecPublicKey) {\n\t\tthrow new Error('SEC1 export requires an EC private key');\n\t}\n\treturn parsed.privateKeyDer;\n}\n\n/**\n * Export an EC private key as PEM-encoded SEC 1 ECPrivateKey.\n *\n * @throws {Error} If the key is not an EC key\n *\n * @see {@linkcode importSec1Pem} for the inverse operation\n * @see {@linkcode exportEncryptedSec1Pem} for password-protected export\n */\nexport async function exportSec1Pem(privateKey: CryptoKey): Promise<string> {\n\treturn pemEncode('EC PRIVATE KEY', await exportSec1Der(privateKey));\n}\n\n/**\n * Export an EC private key as legacy `Proc-Type: 4,ENCRYPTED` PEM (SEC 1).\n *\n * Uses OpenSSL's traditional PEM encryption with MD5-based key derivation.\n * For modern encryption, prefer {@linkcode exportEncryptedPkcs8Pem}.\n *\n * @throws {Error} If the key is not an EC key\n *\n * @see {@linkcode importEncryptedSec1Pem} for the inverse operation\n */\nexport async function exportEncryptedSec1Pem(\n\tprivateKey: CryptoKey,\n\toptions: LegacyPemEncryptionOptions,\n): Promise<string> {\n\treturn encryptTraditionalPem('EC PRIVATE KEY', await exportSec1Der(privateKey), options);\n}\n\n/**\n * Export a public key as PEM-encoded SubjectPublicKeyInfo.\n *\n * @example\n * ```ts\n * const keys = await generateKeyPair();\n * const pem = await exportSpkiPem(keys.publicKey);\n * ```\n */\nexport async function exportSpkiPem(publicKey: CryptoKey): Promise<string> {\n\treturn pemEncode('PUBLIC KEY', await exportSpkiDer(publicKey));\n}\n\n/**\n * Export a key as raw base64 (no PEM headers).\n *\n * Returns SPKI-encoded base64 for public keys, PKCS#8-encoded base64 for private keys.\n * Useful for compact storage or transmission where PEM overhead is undesirable.\n *\n * @throws {Error} If the key is a symmetric/secret key\n *\n * @see {@linkcode importSpkiBase64} for public key import\n * @see {@linkcode importPkcs8Base64} for private key import\n */\nexport async function exportBinaryBase64(key: CryptoKey): Promise<string> {\n\tif (key.type === 'public') {\n\t\treturn base64Encode(await exportSpkiDer(key));\n\t}\n\tif (key.type === 'private') {\n\t\treturn base64Encode(await exportPkcs8Der(key));\n\t}\n\tthrow new Error('Cannot export secret/symmetric CryptoKey');\n}\n\n/**\n * Import a public key from DER-encoded SubjectPublicKeyInfo.\n *\n * @param der - DER-encoded SubjectPublicKeyInfo bytes\n * @param algorithm - Expected algorithm (must match key contents)\n * @returns Extractable CryptoKey with `verify` usage\n *\n * @throws {Error} If DER is malformed or algorithm doesn't match key\n *\n * @see {@linkcode exportSpkiDer} for the inverse operation\n * @see {@linkcode importSpkiPem} for PEM input\n */\nexport async function importSpkiDer(\n\tder: Uint8Array,\n\talgorithm: PublicKeyImportInput,\n): Promise<CryptoKey> {\n\tconst parsedSpki = parseSpkiDer(der);\n\tassertSpkiMatchesRequestedAlgorithm(parsedSpki, algorithm);\n\ttry {\n\t\treturn await getCrypto().subtle.importKey(\n\t\t\t'spki',\n\t\t\tnew Uint8Array(der),\n\t\t\ttoImportAlgorithm(algorithm),\n\t\t\ttrue,\n\t\t\t['verify'],\n\t\t);\n\t} catch {\n\t\tthrow new Error('Malformed SubjectPublicKeyInfo');\n\t}\n}\n\n/**\n * Import a public key from PEM-encoded SubjectPublicKeyInfo.\n *\n * @example\n * ```ts\n * const pem = `-----BEGIN PUBLIC KEY-----\n * MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...\n * -----END PUBLIC KEY-----`;\n * const key = await importSpkiPem(pem, { kind: 'ecdsa', curve: 'P-256' });\n * ```\n *\n * @see {@linkcode exportSpkiPem} for the inverse operation\n */\nexport async function importSpkiPem(\n\tpem: string,\n\talgorithm: PublicKeyImportInput,\n): Promise<CryptoKey> {\n\treturn importSpkiDer(pemDecode('PUBLIC KEY', pem), algorithm);\n}\n\n/**\n * Import a public key from base64-encoded SubjectPublicKeyInfo (no PEM headers).\n *\n * @see {@linkcode exportBinaryBase64} for the inverse operation\n * @see {@linkcode importSpkiPem} for PEM input with headers\n */\nexport async function importSpkiBase64(\n\tbase64: string,\n\talgorithm: PublicKeyImportInput,\n): Promise<CryptoKey> {\n\tlet decoded: Uint8Array;\n\ttry {\n\t\tdecoded = base64Decode(base64);\n\t} catch {\n\t\tthrow new Error('Invalid base64 SubjectPublicKeyInfo');\n\t}\n\treturn importSpkiDer(decoded, algorithm);\n}\n\n/**\n * Import a private key from DER-encoded PKCS#8 PrivateKeyInfo.\n *\n * @param der - DER-encoded PKCS#8 PrivateKeyInfo bytes\n * @param algorithm - Expected algorithm (must match key contents)\n * @returns Extractable CryptoKey with `sign` usage\n *\n * @throws {Error} If DER is malformed or algorithm doesn't match key\n *\n * @see {@linkcode exportPkcs8Der} for the inverse operation\n * @see {@linkcode importPkcs8Pem} for PEM input\n * @see {@linkcode importEncryptedPkcs8Der} for encrypted PKCS#8\n */\nexport async function importPkcs8Der(\n\tder: Uint8Array,\n\talgorithm: PrivateKeyImportInput,\n): Promise<CryptoKey> {\n\tlet parsedPrivateKey: ReturnType<typeof parsePkcs8PrivateKey>;\n\ttry {\n\t\tparsedPrivateKey = parsePkcs8PrivateKey(der);\n\t} catch {\n\t\tthrow new Error('Malformed PKCS#8 private key');\n\t}\n\tassertPkcs8MatchesRequestedAlgorithm(parsedPrivateKey, algorithm);\n\ttry {\n\t\treturn await getCrypto().subtle.importKey(\n\t\t\t'pkcs8',\n\t\t\tnew Uint8Array(der),\n\t\t\ttoImportAlgorithm(algorithm),\n\t\t\ttrue,\n\t\t\t['sign'],\n\t\t);\n\t} catch {\n\t\tthrow new Error('Malformed PKCS#8 private key');\n\t}\n}\n\n/**\n * Import a private key from PEM-encoded PKCS#8 PrivateKeyInfo.\n *\n * @example\n * ```ts\n * const key = await importPkcs8Pem(pemString, { kind: 'ecdsa', curve: 'P-256' });\n * ```\n */\nexport async function importPkcs8Pem(\n\tpem: string,\n\talgorithm: PrivateKeyImportInput,\n): Promise<CryptoKey> {\n\treturn importPkcs8Der(pemDecode('PRIVATE KEY', pem), algorithm);\n}\n\n/**\n * Import a private key from DER-encoded PBES2-encrypted PKCS#8 EncryptedPrivateKeyInfo.\n *\n * Decrypts the PBES2 envelope using the provided password, then imports the key.\n *\n * @param der - DER-encoded EncryptedPrivateKeyInfo bytes\n * @param password - Decryption password\n * @param algorithm - Expected algorithm (must match decrypted key)\n *\n * @throws {Error} If DER is malformed, password is wrong, or algorithm doesn't match\n *\n * @see {@linkcode exportEncryptedPkcs8Der} for the inverse operation\n */\nexport async function importEncryptedPkcs8Der(\n\tder: Uint8Array,\n\tpassword: string,\n\talgorithm: PrivateKeyImportInput,\n): Promise<CryptoKey> {\n\tlet children: readonly ReturnType<typeof readSequenceChildren>[number][];\n\ttry {\n\t\tchildren = readSequenceChildren(der);\n\t} catch {\n\t\tthrow new Error('Malformed EncryptedPrivateKeyInfo');\n\t}\n\tconst algorithmIdentifier = children[0];\n\tconst encryptedData = children[1];\n\tif (\n\t\tchildren.length !== 2 ||\n\t\talgorithmIdentifier === undefined ||\n\t\tencryptedData === undefined ||\n\t\tencryptedData.tag !== 0x04\n\t) {\n\t\tthrow new Error('Malformed EncryptedPrivateKeyInfo');\n\t}\n\tconst decrypted = await decryptPbes2(\n\t\tder.slice(\n\t\t\talgorithmIdentifier.start - algorithmIdentifier.headerLength,\n\t\t\talgorithmIdentifier.end,\n\t\t),\n\t\tencryptedData.value,\n\t\tpassword,\n\t);\n\treturn importPkcs8Der(decrypted, algorithm);\n}\n\n/**\n * Import a private key from PEM-encoded PBES2-encrypted PKCS#8 EncryptedPrivateKeyInfo.\n *\n * @example\n * ```ts\n * const key = await importEncryptedPkcs8Pem(pem, 'secret', { kind: 'rsa' });\n * ```\n */\nexport async function importEncryptedPkcs8Pem(\n\tpem: string,\n\tpassword: string,\n\talgorithm: PrivateKeyImportInput,\n): Promise<CryptoKey> {\n\treturn importEncryptedPkcs8Der(pemDecode('ENCRYPTED PRIVATE KEY', pem), password, algorithm);\n}\n\n/**\n * Import an RSA private key from DER-encoded PKCS#1 RSAPrivateKey.\n *\n * PKCS#1 is the legacy RSA-only format. Internally converts to PKCS#8 for import.\n *\n * @see {@linkcode exportPkcs1Der} for the inverse operation\n * @see {@linkcode importPkcs1Pem} for PEM input\n */\nexport async function importPkcs1Der(\n\tder: Uint8Array,\n\talgorithm: ImportRsaPublicKeyInput = { kind: 'rsa' },\n): Promise<CryptoKey> {\n\treturn importPkcs8Der(wrapPkcs1InPkcs8(der), algorithm);\n}\n\n/**\n * Import an RSA private key from PEM-encoded PKCS#1 RSAPrivateKey.\n *\n * Expects the `-----BEGIN RSA PRIVATE KEY-----` PEM label.\n *\n * @see {@linkcode exportPkcs1Pem} for the inverse operation\n * @see {@linkcode importEncryptedPkcs1Pem} for encrypted PEM\n */\nexport async function importPkcs1Pem(\n\tpem: string,\n\talgorithm: ImportRsaPublicKeyInput = { kind: 'rsa' },\n): Promise<CryptoKey> {\n\treturn importPkcs1Der(pemDecode('RSA PRIVATE KEY', pem), algorithm);\n}\n\n/**\n * Import an RSA private key from legacy `Proc-Type: 4,ENCRYPTED` PEM (PKCS#1).\n *\n * Decrypts OpenSSL's traditional PEM encryption format.\n *\n * @see {@linkcode exportEncryptedPkcs1Pem} for the inverse operation\n * @see {@linkcode importEncryptedPkcs8Pem} for modern PBES2 encryption\n */\nexport async function importEncryptedPkcs1Pem(\n\tpem: string,\n\tpassword: string,\n\talgorithm: ImportRsaPublicKeyInput = { kind: 'rsa' },\n): Promise<CryptoKey> {\n\tconst decrypted = await decryptTraditionalPem('RSA PRIVATE KEY', pem, password);\n\treturn importPkcs1Der(decrypted, algorithm);\n}\n\n/**\n * Import a private key from base64-encoded PKCS#8 PrivateKeyInfo (no PEM headers).\n *\n * @see {@linkcode exportBinaryBase64} for the inverse operation\n * @see {@linkcode importPkcs8Pem} for PEM input with headers\n */\nexport async function importPkcs8Base64(\n\tbase64: string,\n\talgorithm: PrivateKeyImportInput,\n): Promise<CryptoKey> {\n\tlet decoded: Uint8Array;\n\ttry {\n\t\tdecoded = base64Decode(base64);\n\t} catch {\n\t\tthrow new Error('Invalid base64 PKCS#8 private key');\n\t}\n\treturn importPkcs8Der(decoded, algorithm);\n}\n\n/**\n * Import an EC private key from DER-encoded SEC 1 ECPrivateKey.\n *\n * SEC 1 is the legacy EC-only format. Internally converts to PKCS#8 for import.\n *\n * @see {@linkcode exportSec1Der} for the inverse operation\n * @see {@linkcode importSec1Pem} for PEM input\n */\nexport async function importSec1Der(\n\tder: Uint8Array,\n\talgorithm: ImportEcPublicKeyInput,\n): Promise<CryptoKey> {\n\treturn importPkcs8Der(wrapSec1InPkcs8(der, algorithm.curve), algorithm);\n}\n\n/**\n * Import an EC private key from PEM-encoded SEC 1 ECPrivateKey.\n *\n * Expects the `-----BEGIN EC PRIVATE KEY-----` PEM label.\n *\n * @see {@linkcode exportSec1Pem} for the inverse operation\n * @see {@linkcode importEncryptedSec1Pem} for encrypted PEM\n */\nexport async function importSec1Pem(\n\tpem: string,\n\talgorithm: ImportEcPublicKeyInput,\n): Promise<CryptoKey> {\n\treturn importSec1Der(pemDecode('EC PRIVATE KEY', pem), algorithm);\n}\n\n/**\n * Import an EC private key from legacy `Proc-Type: 4,ENCRYPTED` PEM (SEC 1).\n *\n * Decrypts OpenSSL's traditional PEM encryption format.\n *\n * @see {@linkcode exportEncryptedSec1Pem} for the inverse operation\n * @see {@linkcode importEncryptedPkcs8Pem} for modern PBES2 encryption\n */\nexport async function importEncryptedSec1Pem(\n\tpem: string,\n\tpassword: string,\n\talgorithm: ImportEcPublicKeyInput,\n): Promise<CryptoKey> {\n\tconst decrypted = await decryptTraditionalPem('EC PRIVATE KEY', pem, password);\n\treturn importSec1Der(decrypted, algorithm);\n}\n\n/**\n * Import a public verification key from a JSON Web Key.\n *\n * @param jwk - JSON Web Key object with public key components\n * @param algorithm - Expected algorithm (must match JWK's `kty` and `crv`)\n * @returns Extractable CryptoKey with `verify` usage\n *\n * @throws {Error} If JWK is malformed or algorithm doesn't match\n *\n * @see {@linkcode exportPublicJwk} for the inverse operation\n */\nexport async function importPublicJwk(\n\tjwk: JsonWebKey,\n\talgorithm: PublicKeyImportInput,\n): Promise<CryptoKey> {\n\tassertPublicJwkMatchesRequestedAlgorithm(jwk, algorithm);\n\ttry {\n\t\treturn await getCrypto().subtle.importKey('jwk', jwk, toImportAlgorithm(algorithm), true, [\n\t\t\t'verify',\n\t\t]);\n\t} catch {\n\t\tthrow new Error('Malformed public JWK');\n\t}\n}\n\n/**\n * Import a private signing key from a JSON Web Key.\n *\n * @example\n * ```ts\n * const jwk = { kty: 'EC', crv: 'P-256', x: '...', y: '...', d: '...' };\n * const key = await importPrivateJwk(jwk, { kind: 'ecdsa', curve: 'P-256' });\n * ```\n */\nexport async function importPrivateJwk(\n\tjwk: JsonWebKey,\n\talgorithm: PrivateKeyImportInput,\n): Promise<CryptoKey> {\n\treturn getCrypto().subtle.importKey('jwk', jwk, toImportAlgorithm(algorithm), true, ['sign']);\n}\n\n/** Map a {@linkcode KeyAlgorithmInput} to the WebCrypto `generateKey` algorithm parameter. */\nfunction toGenerateKeyAlgorithm(\n\talgorithm: KeyAlgorithmInput,\n): EcKeyGenParams | RsaHashedKeyGenParams | AlgorithmIdentifier {\n\tswitch (algorithm.kind) {\n\t\tcase 'rsa':\n\t\t\treturn {\n\t\t\t\tname: rsaSchemeToWebCryptoAlgorithmName(algorithm.scheme),\n\t\t\t\tmodulusLength: algorithm.modulusLength ?? 2048,\n\t\t\t\tpublicExponent: Uint8Array.of(0x01, 0x00, 0x01),\n\t\t\t\thash: algorithm.hash ?? 'SHA-256',\n\t\t\t};\n\t\tcase 'ecdsa':\n\t\t\treturn {\n\t\t\t\tname: 'ECDSA',\n\t\t\t\tnamedCurve: algorithm.curve ?? 'P-256',\n\t\t\t};\n\t\tcase 'ed25519':\n\t\t\treturn { name: 'Ed25519' };\n\t}\n}\n\n/** Map a {@linkcode PublicKeyImportInput} to the WebCrypto `importKey` algorithm parameter. */\nfunction toImportAlgorithm(\n\talgorithm: PublicKeyImportInput,\n): EcKeyImportParams | RsaHashedImportParams | AlgorithmIdentifier {\n\tswitch (algorithm.kind) {\n\t\tcase 'rsa':\n\t\t\treturn {\n\t\t\t\tname: rsaSchemeToWebCryptoAlgorithmName(algorithm.scheme),\n\t\t\t\thash: algorithm.hash ?? 'SHA-256',\n\t\t\t};\n\t\tcase 'ecdsa':\n\t\t\treturn {\n\t\t\t\tname: 'ECDSA',\n\t\t\t\tnamedCurve: algorithm.curve,\n\t\t\t};\n\t\tcase 'ed25519':\n\t\t\treturn { name: 'Ed25519' };\n\t}\n}\n\n/** Extract algorithm OID and inner key bytes from a PKCS#8 PrivateKeyInfo envelope. */\nfunction parsePkcs8PrivateKey(der: Uint8Array): {\n\t/** OID identifying the algorithm family (e.g. rsaEncryption, ecPublicKey). */\n\treadonly algorithmOid: string;\n\t/** Optional algorithm parameter OID (e.g. named curve for EC keys). */\n\treadonly parametersOid?: string;\n\t/** Optional algorithm parameter tag. */\n\treadonly parametersTag?: number;\n\t/** Raw DER of the inner private key (PKCS#1 for RSA, SEC 1 for EC). */\n\treadonly privateKeyDer: Uint8Array;\n} {\n\tconst children = readSequenceChildren(der);\n\tconst algorithm = children[1];\n\tconst privateKey = children[2];\n\tif (\n\t\tchildren.length < 3 ||\n\t\tchildren.length > 4 ||\n\t\talgorithm === undefined ||\n\t\talgorithm.tag !== 0x30 ||\n\t\tprivateKey === undefined ||\n\t\tprivateKey.tag !== 0x04\n\t) {\n\t\tthrow new Error('Malformed PKCS#8 private key');\n\t}\n\tconst algorithmChildren = readSequenceChildren(\n\t\tder.slice(algorithm.start - algorithm.headerLength, algorithm.end),\n\t);\n\tconst algorithmOid = algorithmChildren[0];\n\tif (\n\t\talgorithmOid === undefined ||\n\t\talgorithmOid.tag !== 0x06 ||\n\t\talgorithmChildren.length < 1 ||\n\t\talgorithmChildren.length > 2\n\t) {\n\t\tthrow new Error('Malformed PKCS#8 private key');\n\t}\n\tconst parameters = algorithmChildren[1];\n\treturn {\n\t\talgorithmOid: decodeObjectIdentifier(algorithmOid.value),\n\t\t...(parameters === undefined ? {} : { parametersTag: parameters.tag }),\n\t\t...(parameters?.tag === 0x06\n\t\t\t? { parametersOid: decodeObjectIdentifier(parameters.value) }\n\t\t\t: {}),\n\t\tprivateKeyDer: privateKey.value,\n\t};\n}\n\n/** Wrap a PKCS#1 RSAPrivateKey in a PKCS#8 PrivateKeyInfo envelope for WebCrypto import. */\nfunction wrapPkcs1InPkcs8(der: Uint8Array): Uint8Array {\n\treturn sequence([\n\t\tUint8Array.of(0x02, 0x01, 0x00),\n\t\tsequence([objectIdentifier(OIDS.rsaEncryption), nullValue()]),\n\t\toctetString(new Uint8Array(der)),\n\t]);\n}\n\n/** Wrap a SEC 1 ECPrivateKey in a PKCS#8 PrivateKeyInfo envelope for WebCrypto import. */\nfunction wrapSec1InPkcs8(der: Uint8Array, curve: ImportEcPublicKeyInput['curve']): Uint8Array {\n\treturn sequence([\n\t\tUint8Array.of(0x02, 0x01, 0x00),\n\t\tsequence([objectIdentifier(OIDS.ecPublicKey), objectIdentifier(curveToOid(curve))]),\n\t\toctetString(new Uint8Array(der)),\n\t]);\n}\n\n/** Map a curve name to its ASN.1 OID string. */\nfunction curveToOid(curve: ImportEcPublicKeyInput['curve']): string {\n\tswitch (curve) {\n\t\tcase 'P-256':\n\t\t\treturn OIDS.prime256v1;\n\t\tcase 'P-384':\n\t\t\treturn OIDS.secp384r1;\n\t\tcase 'P-521':\n\t\t\treturn OIDS.secp521r1;\n\t}\n}\n\n/** Map an {@linkcode RsaScheme} to the WebCrypto algorithm name string. */\nfunction rsaSchemeToWebCryptoAlgorithmName(\n\tscheme: RsaScheme | undefined,\n): 'RSASSA-PKCS1-v1_5' | 'RSA-PSS' {\n\tif (scheme === 'pss') {\n\t\treturn 'RSA-PSS';\n\t}\n\treturn 'RSASSA-PKCS1-v1_5';\n}\n\n/** Encrypt DER key material as an OpenSSL-style `Proc-Type: 4,ENCRYPTED` PEM block. */\nasync function encryptTraditionalPem(\n\tlabel: 'RSA PRIVATE KEY' | 'EC PRIVATE KEY',\n\tder: Uint8Array,\n\toptions: LegacyPemEncryptionOptions,\n): Promise<string> {\n\tconst iv = options.iv ?? getCrypto().getRandomValues(new Uint8Array(16));\n\tif (iv.length !== 16) {\n\t\tthrow new Error('Traditional PEM encryption requires a 16-byte IV');\n\t}\n\tconst cipher = options.cipher ?? 'AES-256-CBC';\n\tconst key = await importTraditionalPemAesKey(options.password, iv.slice(0, 8), cipher, [\n\t\t'encrypt',\n\t]);\n\tconst encrypted = new Uint8Array(\n\t\tawait getCrypto().subtle.encrypt(\n\t\t\t{ name: 'AES-CBC', iv: toArrayBuffer(iv) },\n\t\t\tkey,\n\t\t\ttoArrayBuffer(der),\n\t\t),\n\t);\n\tconst body =\n\t\tbase64Encode(encrypted)\n\t\t\t.match(/.{1,64}/g)\n\t\t\t?.join('\\n') ?? '';\n\treturn [\n\t\t`-----BEGIN ${label}-----`,\n\t\t'Proc-Type: 4,ENCRYPTED',\n\t\t`DEK-Info: ${cipher},${toHex(iv).toUpperCase()}`,\n\t\t'',\n\t\tbody,\n\t\t`-----END ${label}-----`,\n\t].join('\\n');\n}\n\n/** Decrypt an OpenSSL-style `Proc-Type: 4,ENCRYPTED` PEM block back to plaintext DER. */\nasync function decryptTraditionalPem(\n\texpectedLabel: 'RSA PRIVATE KEY' | 'EC PRIVATE KEY',\n\tpem: string,\n\tpassword: string,\n): Promise<Uint8Array> {\n\tconst parsed = parseTraditionalPem(pem);\n\tif (parsed.label !== expectedLabel) {\n\t\tthrow new Error(`Expected ${expectedLabel} PEM block`);\n\t}\n\tconst dekInfo = parsed.headers.get('DEK-Info');\n\tif (parsed.headers.get('Proc-Type') !== '4,ENCRYPTED' || dekInfo === undefined) {\n\t\tthrow new Error('Traditional PEM encryption headers missing');\n\t}\n\tconst [cipher, ivHex] = dekInfo.split(',');\n\tif (!isTraditionalPemCipher(cipher) || ivHex === undefined) {\n\t\tthrow new Error(\n\t\t\t'Only AES-128-CBC, AES-192-CBC, and AES-256-CBC traditional PEM encryption is supported',\n\t\t);\n\t}\n\tif (!isTraditionalPemIvHex(ivHex)) {\n\t\tthrow new Error(\n\t\t\t'Traditional PEM encryption requires a 16-byte IV encoded as 32 hex characters',\n\t\t);\n\t}\n\tconst iv = hexToBytes(ivHex);\n\tconst key = await importTraditionalPemAesKey(password, iv.slice(0, 8), cipher, ['decrypt']);\n\ttry {\n\t\treturn new Uint8Array(\n\t\t\tawait getCrypto().subtle.decrypt(\n\t\t\t\t{ name: 'AES-CBC', iv: toArrayBuffer(iv) },\n\t\t\t\tkey,\n\t\t\t\ttoArrayBuffer(base64Decode(parsed.base64Body)),\n\t\t\t),\n\t\t);\n\t} catch {\n\t\tthrow new Error('Invalid password or encrypted PEM content');\n\t}\n}\n\n/** Derive and import an AES-CBC key for legacy PEM encryption using OpenSSL `EVP_BytesToKey`. */\nasync function importTraditionalPemAesKey(\n\tpassword: string,\n\tsalt: Uint8Array,\n\tcipher: 'AES-128-CBC' | 'AES-192-CBC' | 'AES-256-CBC',\n\tusages: KeyUsage[],\n): Promise<CryptoKey> {\n\tconst keyLength = traditionalPemCipherKeyLength(cipher);\n\tconst keyBytes = opensslBytesToKey(password, salt, keyLength / 8);\n\treturn getCrypto().subtle.importKey(\n\t\t'raw',\n\t\ttoArrayBuffer(keyBytes),\n\t\t{ name: 'AES-CBC', length: keyLength },\n\t\tfalse,\n\t\tusages,\n\t);\n}\n\n/** Type guard for the three AES-CBC ciphers supported by legacy PEM encryption. */\nfunction isTraditionalPemCipher(\n\tcipher: string | undefined,\n): cipher is 'AES-128-CBC' | 'AES-192-CBC' | 'AES-256-CBC' {\n\treturn cipher === 'AES-128-CBC' || cipher === 'AES-192-CBC' || cipher === 'AES-256-CBC';\n}\n\nfunction isTraditionalPemIvHex(value: string): boolean {\n\treturn value.length === 32 && /^[0-9A-Fa-f]+$/.test(value);\n}\n\n/** Return the AES key size in bits for a given cipher name. */\nfunction traditionalPemCipherKeyLength(\n\tcipher: 'AES-128-CBC' | 'AES-192-CBC' | 'AES-256-CBC',\n): 128 | 192 | 256 {\n\tswitch (cipher) {\n\t\tcase 'AES-128-CBC':\n\t\t\treturn 128;\n\t\tcase 'AES-192-CBC':\n\t\t\treturn 192;\n\t\tcase 'AES-256-CBC':\n\t\t\treturn 256;\n\t}\n}\n\n/** OpenSSL `EVP_BytesToKey` with MD5 — derives a fixed-length key from password + salt. */\nfunction opensslBytesToKey(password: string, salt: Uint8Array, length: number): Uint8Array {\n\tconst passwordBytes = new TextEncoder().encode(password);\n\tconst chunks: Uint8Array[] = [];\n\tlet previous = new Uint8Array();\n\tlet total = 0;\n\twhile (total < length) {\n\t\tconst input = new Uint8Array(previous.length + passwordBytes.length + salt.length);\n\t\tinput.set(previous, 0);\n\t\tinput.set(passwordBytes, previous.length);\n\t\tinput.set(salt, previous.length + passwordBytes.length);\n\t\tprevious = md5(input);\n\t\tchunks.push(previous);\n\t\ttotal += previous.length;\n\t}\n\tconst out = new Uint8Array(length);\n\tlet offset = 0;\n\tfor (const chunk of chunks) {\n\t\tconst slice = chunk.slice(0, Math.min(chunk.length, length - offset));\n\t\tout.set(slice, offset);\n\t\toffset += slice.length;\n\t\tif (offset >= length) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn out;\n}\n\n/** Parse a PEM block into its label, RFC 1421 headers, and base64 body. */\nfunction parseTraditionalPem(pem: string): {\n\t/** PEM type label between `BEGIN` and `END` markers. */\n\treadonly label: string;\n\t/** RFC 1421 encapsulated headers (e.g. `Proc-Type`, `DEK-Info`). */\n\treadonly headers: ReadonlyMap<string, string>;\n\t/** Base64-encoded payload after the headers. */\n\treadonly base64Body: string;\n} {\n\tconst normalized = pem.replace(/\\r/g, '').trim();\n\tconst lines = normalized.split('\\n');\n\tconst begin = lines[0];\n\tconst end = lines[lines.length - 1];\n\tif (\n\t\tbegin === undefined ||\n\t\tend === undefined ||\n\t\t!begin.startsWith('-----BEGIN ') ||\n\t\t!end.startsWith('-----END ')\n\t) {\n\t\tthrow new Error('Invalid PEM block');\n\t}\n\tconst label = begin.slice(11, -5);\n\tif (end !== `-----END ${label}-----`) {\n\t\tthrow new Error('PEM boundaries do not match');\n\t}\n\tconst headers = new Map<string, string>();\n\tlet index = 1;\n\twhile (index < lines.length - 1) {\n\t\tconst line = lines[index];\n\t\tif (line === undefined) {\n\t\t\tbreak;\n\t\t}\n\t\tif (line.length === 0) {\n\t\t\tindex += 1;\n\t\t\tbreak;\n\t\t}\n\t\tconst delimiter = line.indexOf(': ');\n\t\tif (delimiter === -1) {\n\t\t\tbreak;\n\t\t}\n\t\tconst headerName = line.slice(0, delimiter);\n\t\tif (headers.has(headerName)) {\n\t\t\tthrow new Error(`Duplicate PEM header: ${headerName}`);\n\t\t}\n\t\theaders.set(headerName, line.slice(delimiter + 2));\n\t\tindex += 1;\n\t}\n\tconst body = lines.slice(index, lines.length - 1).join('');\n\treturn { label, headers, base64Body: body };\n}\n\nfunction parseSpkiDer(der: Uint8Array): {\n\treadonly algorithmOid: string;\n\treadonly parametersOid?: string;\n\treadonly parametersTag?: number;\n} {\n\ttry {\n\t\tconst children = readSequenceChildren(der);\n\t\tif (children.length !== 2) {\n\t\t\tthrow new Error('Malformed SubjectPublicKeyInfo');\n\t\t}\n\t\tconst algorithm = children[0];\n\t\tconst subjectPublicKey = children[1];\n\t\tif (\n\t\t\talgorithm === undefined ||\n\t\t\talgorithm.tag !== 0x30 ||\n\t\t\tsubjectPublicKey === undefined ||\n\t\t\tsubjectPublicKey.tag !== 0x03\n\t\t) {\n\t\t\tthrow new Error('Malformed SubjectPublicKeyInfo');\n\t\t}\n\t\textractBitStringValue(subjectPublicKey);\n\t\tconst algorithmChildren = readSequenceChildren(\n\t\t\tder.slice(algorithm.start - algorithm.headerLength, algorithm.end),\n\t\t);\n\t\tconst algorithmOid = algorithmChildren[0];\n\t\tif (\n\t\t\talgorithmOid === undefined ||\n\t\t\talgorithmOid.tag !== 0x06 ||\n\t\t\talgorithmChildren.length < 1 ||\n\t\t\talgorithmChildren.length > 2\n\t\t) {\n\t\t\tthrow new Error('Malformed SubjectPublicKeyInfo');\n\t\t}\n\t\tconst parameters = algorithmChildren[1];\n\t\treturn {\n\t\t\talgorithmOid: decodeObjectIdentifier(algorithmOid.value),\n\t\t\t...(parameters === undefined ? {} : { parametersTag: parameters.tag }),\n\t\t\t...(parameters?.tag === 0x06\n\t\t\t\t? { parametersOid: decodeObjectIdentifier(parameters.value) }\n\t\t\t\t: {}),\n\t\t};\n\t} catch {\n\t\tthrow new Error('Malformed SubjectPublicKeyInfo');\n\t}\n}\n\nfunction assertSpkiMatchesRequestedAlgorithm(\n\tparsedSpki: {\n\t\treadonly algorithmOid: string;\n\t\treadonly parametersOid?: string;\n\t\treadonly parametersTag?: number;\n\t},\n\talgorithm: PublicKeyImportInput,\n): void {\n\tswitch (algorithm.kind) {\n\t\tcase 'rsa':\n\t\t\tif (\n\t\t\t\tparsedSpki.algorithmOid !== OIDS.rsaEncryption ||\n\t\t\t\t(parsedSpki.parametersTag !== undefined && parsedSpki.parametersTag !== 0x05)\n\t\t\t) {\n\t\t\t\tthrow new Error('SubjectPublicKeyInfo algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t\tcase 'ecdsa':\n\t\t\tif (\n\t\t\t\tparsedSpki.algorithmOid !== OIDS.ecPublicKey ||\n\t\t\t\tparsedSpki.parametersTag !== 0x06 ||\n\t\t\t\tparsedSpki.parametersOid !== curveToOid(algorithm.curve)\n\t\t\t) {\n\t\t\t\tthrow new Error('SubjectPublicKeyInfo algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t\tcase 'ed25519':\n\t\t\tif (parsedSpki.algorithmOid !== OIDS.ed25519 || parsedSpki.parametersTag !== undefined) {\n\t\t\t\tthrow new Error('SubjectPublicKeyInfo algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t}\n}\n\nfunction assertPkcs8MatchesRequestedAlgorithm(\n\tparsedPrivateKey: {\n\t\treadonly algorithmOid: string;\n\t\treadonly parametersOid?: string;\n\t\treadonly parametersTag?: number;\n\t},\n\talgorithm: PrivateKeyImportInput,\n): void {\n\tswitch (algorithm.kind) {\n\t\tcase 'rsa':\n\t\t\tif (\n\t\t\t\tparsedPrivateKey.algorithmOid !== OIDS.rsaEncryption ||\n\t\t\t\t(parsedPrivateKey.parametersTag !== undefined && parsedPrivateKey.parametersTag !== 0x05)\n\t\t\t) {\n\t\t\t\tthrow new Error('PKCS#8 private key algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t\tcase 'ecdsa':\n\t\t\tif (\n\t\t\t\tparsedPrivateKey.algorithmOid !== OIDS.ecPublicKey ||\n\t\t\t\tparsedPrivateKey.parametersTag !== 0x06 ||\n\t\t\t\tparsedPrivateKey.parametersOid !== curveToOid(algorithm.curve)\n\t\t\t) {\n\t\t\t\tthrow new Error('PKCS#8 private key algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t\tcase 'ed25519':\n\t\t\tif (\n\t\t\t\tparsedPrivateKey.algorithmOid !== OIDS.ed25519 ||\n\t\t\t\tparsedPrivateKey.parametersTag !== undefined\n\t\t\t) {\n\t\t\t\tthrow new Error('PKCS#8 private key algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t}\n}\n\nfunction assertPublicJwkMatchesRequestedAlgorithm(\n\tjwk: JsonWebKey,\n\talgorithm: PublicKeyImportInput,\n): void {\n\tif (\n\t\tjwk.k !== undefined ||\n\t\tjwk.d !== undefined ||\n\t\tjwk.p !== undefined ||\n\t\tjwk.q !== undefined ||\n\t\tjwk.dp !== undefined ||\n\t\tjwk.dq !== undefined ||\n\t\tjwk.qi !== undefined ||\n\t\tjwk.oth !== undefined\n\t) {\n\t\tthrow new Error('Public JWK must not contain private key material');\n\t}\n\tswitch (algorithm.kind) {\n\t\tcase 'rsa':\n\t\t\tif (jwk.kty !== 'RSA' || typeof jwk.n !== 'string' || typeof jwk.e !== 'string') {\n\t\t\t\tthrow new Error('Public JWK algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t\tcase 'ecdsa':\n\t\t\tif (\n\t\t\t\tjwk.kty !== 'EC' ||\n\t\t\t\tjwk.crv !== algorithm.curve ||\n\t\t\t\ttypeof jwk.x !== 'string' ||\n\t\t\t\ttypeof jwk.y !== 'string'\n\t\t\t) {\n\t\t\t\tthrow new Error('Public JWK algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t\tcase 'ed25519':\n\t\t\tif (jwk.kty !== 'OKP' || jwk.crv !== 'Ed25519' || typeof jwk.x !== 'string') {\n\t\t\t\tthrow new Error('Public JWK algorithm does not match requested import algorithm');\n\t\t\t}\n\t\t\treturn;\n\t}\n}\n"],"mappings":"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"}
package/dist/keys.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Pbes2EncryptionOptions, Pbes2EncryptionScheme, Pbes2Prf } from "./internal/crypto/pbes2.js";
2
+ import { EcKeyAlgorithmInput, EcNamedCurve, Ed25519KeyAlgorithmInput, EncryptedPkcs8Options, ImportEcPublicKeyInput, ImportEd25519PublicKeyInput, ImportRsaPublicKeyInput, KeyAlgorithmInput, KeyPairMaterial, LegacyPemEncryptionOptions, PrivateKeyImportInput, PublicKeyImportInput, RsaHash, RsaKeyAlgorithmInput, RsaScheme, exportBinaryBase64, exportEncryptedPkcs1Pem, exportEncryptedPkcs8Der, exportEncryptedPkcs8Pem, exportEncryptedSec1Pem, exportPkcs1Der, exportPkcs1Pem, exportPkcs8Der, exportPkcs8Pem, exportPrivateJwk, exportPublicJwk, exportSec1Der, exportSec1Pem, exportSpkiDer, exportSpkiPem, generateKeyPair, importEncryptedPkcs1Pem, importEncryptedPkcs8Der, importEncryptedPkcs8Pem, importEncryptedSec1Pem, importPkcs1Der, importPkcs1Pem, importPkcs8Base64, importPkcs8Der, importPkcs8Pem, importPrivateJwk, importPublicJwk, importSec1Der, importSec1Pem, importSpkiBase64, importSpkiDer, importSpkiPem } from "./keys/keys.js";
3
+ export { type EcKeyAlgorithmInput, type EcNamedCurve, type Ed25519KeyAlgorithmInput, type EncryptedPkcs8Options, type ImportEcPublicKeyInput, type ImportEd25519PublicKeyInput, type ImportRsaPublicKeyInput, type KeyAlgorithmInput, type KeyPairMaterial, type LegacyPemEncryptionOptions, type Pbes2EncryptionOptions, type Pbes2EncryptionScheme, type Pbes2Prf, type PrivateKeyImportInput, type PublicKeyImportInput, type RsaHash, type RsaKeyAlgorithmInput, type RsaScheme, exportBinaryBase64, exportEncryptedPkcs1Pem, exportEncryptedPkcs8Der, exportEncryptedPkcs8Pem, exportEncryptedSec1Pem, exportPkcs1Der, exportPkcs1Pem, exportPkcs8Der, exportPkcs8Pem, exportPrivateJwk, exportPublicJwk, exportSec1Der, exportSec1Pem, exportSpkiDer, exportSpkiPem, generateKeyPair, importEncryptedPkcs1Pem, importEncryptedPkcs8Der, importEncryptedPkcs8Pem, importEncryptedSec1Pem, importPkcs1Der, importPkcs1Pem, importPkcs8Base64, importPkcs8Der, importPkcs8Pem, importPrivateJwk, importPublicJwk, importSec1Der, importSec1Pem, importSpkiBase64, importSpkiDer, importSpkiPem };
package/dist/keys.js ADDED
@@ -0,0 +1 @@
1
+ import{exportBinaryBase64 as e,exportEncryptedPkcs1Pem as t,exportEncryptedPkcs8Der as n,exportEncryptedPkcs8Pem as r,exportEncryptedSec1Pem as i,exportPkcs1Der as a,exportPkcs1Pem as o,exportPkcs8Der as s,exportPkcs8Pem as c,exportPrivateJwk as l,exportPublicJwk as u,exportSec1Der as d,exportSec1Pem as f,exportSpkiDer as p,exportSpkiPem as m,generateKeyPair as h,importEncryptedPkcs1Pem as g,importEncryptedPkcs8Der as _,importEncryptedPkcs8Pem as v,importEncryptedSec1Pem as y,importPkcs1Der as b,importPkcs1Pem as x,importPkcs8Base64 as S,importPkcs8Der as C,importPkcs8Pem as w,importPrivateJwk as T,importPublicJwk as E,importSec1Der as D,importSec1Pem as O,importSpkiBase64 as k,importSpkiDer as A,importSpkiPem as j}from"./keys/keys.js";export{e as exportBinaryBase64,t as exportEncryptedPkcs1Pem,n as exportEncryptedPkcs8Der,r as exportEncryptedPkcs8Pem,i as exportEncryptedSec1Pem,a as exportPkcs1Der,o as exportPkcs1Pem,s as exportPkcs8Der,c as exportPkcs8Pem,l as exportPrivateJwk,u as exportPublicJwk,d as exportSec1Der,f as exportSec1Pem,p as exportSpkiDer,m as exportSpkiPem,h as generateKeyPair,g as importEncryptedPkcs1Pem,_ as importEncryptedPkcs8Der,v as importEncryptedPkcs8Pem,y as importEncryptedSec1Pem,b as importPkcs1Der,x as importPkcs1Pem,S as importPkcs8Base64,C as importPkcs8Der,w as importPkcs8Pem,T as importPrivateJwk,E as importPublicJwk,D as importSec1Der,O as importSec1Pem,k as importSpkiBase64,A as importSpkiDer,j as importSpkiPem};
@@ -0,0 +1,56 @@
1
+ //#region src/pem/pem.d.ts
2
+ /** A single decoded PEM block with its label, decoded DER bytes, and original PEM text. */
3
+ interface PemBlock {
4
+ /** RFC 7468 label between the `BEGIN` / `END` markers (e.g. `"CERTIFICATE"`). */
5
+ readonly label: string;
6
+ /** Decoded DER content of this block. */
7
+ readonly bytes: Uint8Array;
8
+ /** The original PEM text including `BEGIN`/`END` lines. */
9
+ readonly pem: string;
10
+ }
11
+ /**
12
+ * PEM blocks grouped by their label into well-known PKI categories.
13
+ * Blocks that don't match any known label land in {@linkcode others}.
14
+ */
15
+ interface CategorizedPemBlocks {
16
+ /** Blocks with label `CERTIFICATE`. */
17
+ readonly certificates: readonly PemBlock[];
18
+ /** Blocks with label `CERTIFICATE REQUEST`. */
19
+ readonly certificateRequests: readonly PemBlock[];
20
+ /** Blocks with label `PRIVATE KEY`, `RSA PRIVATE KEY`, or `EC PRIVATE KEY`. */
21
+ readonly privateKeys: readonly PemBlock[];
22
+ /** Blocks with label `PUBLIC KEY`. */
23
+ readonly publicKeys: readonly PemBlock[];
24
+ /** Blocks whose label doesn't match any of the above categories. */
25
+ readonly others: readonly PemBlock[];
26
+ }
27
+ /**
28
+ * Wraps DER bytes in a PEM envelope with 64-character base64 lines.
29
+ *
30
+ * @param label PEM type label (e.g. `"CERTIFICATE"`, `"PRIVATE KEY"`).
31
+ * @param der Raw DER-encoded content.
32
+ */
33
+ declare function pemEncode(label: string, der: Uint8Array): string;
34
+ /**
35
+ * Extracts and base64-decodes the DER content from a PEM string.
36
+ * Throws if the `BEGIN`/`END` markers don't match `label`.
37
+ *
38
+ * @param label Expected PEM type label.
39
+ * @param pem PEM-encoded text (may contain `\r`).
40
+ */
41
+ declare function pemDecode(label: string, pem: string): Uint8Array;
42
+ /**
43
+ * Finds all `BEGIN`/`END`-delimited PEM blocks in a string and returns
44
+ * them as parsed {@linkcode PemBlock} entries. Handles concatenated PEM files
45
+ * and ignores non-PEM text between blocks.
46
+ */
47
+ declare function splitPemBlocks(input: string): readonly PemBlock[];
48
+ /**
49
+ * Groups PEM blocks by label into well-known PKI categories
50
+ * (certificates, CSRs, private keys, public keys, and everything else).
51
+ * Accepts either raw PEM text or pre-split {@linkcode PemBlock} entries.
52
+ */
53
+ declare function categorizePemBlocks(input: string | readonly PemBlock[]): CategorizedPemBlocks;
54
+ //#endregion
55
+ export { CategorizedPemBlocks, PemBlock, categorizePemBlocks, pemDecode, pemEncode, splitPemBlocks };
56
+ //# sourceMappingURL=pem.d.ts.map
@@ -0,0 +1,6 @@
1
+ import{base64Decode as e,base64Encode as t}from"../internal/shared/base64.js";function n(e,n){return`-----BEGIN ${e}-----\n${(t(n).match(/.{1,64}/g)??[]).join(`
2
+ `)}\n-----END ${e}-----`}function r(t,n){let r=n.replace(/\r/g,``).trim(),i=`-----BEGIN ${t}-----`,a=`-----END ${t}-----`,s=r.split(`
3
+ `);if(s[0]!==i||s[s.length-1]!==a||s.length<3)throw Error(`Invalid PEM for ${t}`);let c=o(s.slice(1,-1));if(c===void 0)throw Error(`Invalid PEM for ${t}`);try{return e(c.join(``))}catch{throw Error(`Invalid PEM for ${t}`)}}function i(e){let t=e.replace(/\r/g,``),n=[],i=0,a=0;for(;a<t.length;){let e=t.indexOf(`-----BEGIN `,a);if(e===-1)break;let o=e+11,c=t.indexOf(`-----`,o);if(c===-1)break;let l=t.slice(o,c),u=c+5;if(l.length===0||l.includes(`-`)||l.includes(`
4
+ `)||t[u]!==`
5
+ `){a=o;continue}let d=u+1,f=`\n-----END ${l}-----`,p=t.indexOf(f,d);if(p===-1)break;let m=p+f.length,h=t.slice(e,m);if(s(t.slice(i,e)))throw Error(`Malformed PEM block`);n.push({label:l,bytes:r(l,h),pem:h}),i=m,a=m}if(s(t.slice(i)))throw Error(`Malformed PEM block`);return n}function a(e){let t=typeof e==`string`?i(e):e,n=[],r=[],a=[],o=[],s=[];for(let e of t)switch(e.label){case`CERTIFICATE`:n.push(e);break;case`CERTIFICATE REQUEST`:r.push(e);break;case`PRIVATE KEY`:case`RSA PRIVATE KEY`:case`EC PRIVATE KEY`:a.push(e);break;case`PUBLIC KEY`:o.push(e);break;default:s.push(e)}return{certificates:n,certificateRequests:r,privateKeys:a,publicKeys:o,others:s}}function o(e){let t=e.map(e=>e.replace(/[ \t]/g,``)).filter(e=>e!==``);return t.length===0?[``]:t.every(e=>/^[A-Za-z0-9+/=]+$/.test(e))?t:void 0}function s(e){return e.includes(`-----BEGIN `)||e.includes(`-----END `)}export{a as categorizePemBlocks,r as pemDecode,n as pemEncode,i as splitPemBlocks};
6
+ //# sourceMappingURL=pem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pem.js","names":[],"sources":["../../src/pem/pem.ts"],"sourcesContent":["/**\n * PEM helpers used across the public API.\n *\n * Encodes, decodes, splits, and categorizes PEM blocks as defined by\n * RFC 7468.\n *\n * @module\n */\n\nimport { base64Decode, base64Encode } from '#micro509/internal/shared/base64.ts';\n\n/** A single decoded PEM block with its label, decoded DER bytes, and original PEM text. */\nexport interface PemBlock {\n\t/** RFC 7468 label between the `BEGIN` / `END` markers (e.g. `\"CERTIFICATE\"`). */\n\treadonly label: string;\n\t/** Decoded DER content of this block. */\n\treadonly bytes: Uint8Array;\n\t/** The original PEM text including `BEGIN`/`END` lines. */\n\treadonly pem: string;\n}\n\n/**\n * PEM blocks grouped by their label into well-known PKI categories.\n * Blocks that don't match any known label land in {@linkcode others}.\n */\nexport interface CategorizedPemBlocks {\n\t/** Blocks with label `CERTIFICATE`. */\n\treadonly certificates: readonly PemBlock[];\n\t/** Blocks with label `CERTIFICATE REQUEST`. */\n\treadonly certificateRequests: readonly PemBlock[];\n\t/** Blocks with label `PRIVATE KEY`, `RSA PRIVATE KEY`, or `EC PRIVATE KEY`. */\n\treadonly privateKeys: readonly PemBlock[];\n\t/** Blocks with label `PUBLIC KEY`. */\n\treadonly publicKeys: readonly PemBlock[];\n\t/** Blocks whose label doesn't match any of the above categories. */\n\treadonly others: readonly PemBlock[];\n}\n\n/**\n * Wraps DER bytes in a PEM envelope with 64-character base64 lines.\n *\n * @param label PEM type label (e.g. `\"CERTIFICATE\"`, `\"PRIVATE KEY\"`).\n * @param der Raw DER-encoded content.\n */\nexport function pemEncode(label: string, der: Uint8Array): string {\n\tconst body = base64Encode(der);\n\tconst lines = body.match(/.{1,64}/g) ?? [];\n\treturn `-----BEGIN ${label}-----\\n${lines.join('\\n')}\\n-----END ${label}-----`;\n}\n\n/**\n * Extracts and base64-decodes the DER content from a PEM string.\n * Throws if the `BEGIN`/`END` markers don't match `label`.\n *\n * @param label Expected PEM type label.\n * @param pem PEM-encoded text (may contain `\\r`).\n */\nexport function pemDecode(label: string, pem: string): Uint8Array {\n\tconst normalized = pem.replace(/\\r/g, '').trim();\n\tconst begin = `-----BEGIN ${label}-----`;\n\tconst end = `-----END ${label}-----`;\n\tconst lines = normalized.split('\\n');\n\tif (lines[0] !== begin || lines[lines.length - 1] !== end || lines.length < 3) {\n\t\tthrow new Error(`Invalid PEM for ${label}`);\n\t}\n\tconst bodyLines = normalizePemBodyLines(lines.slice(1, -1));\n\tif (bodyLines === undefined) {\n\t\tthrow new Error(`Invalid PEM for ${label}`);\n\t}\n\ttry {\n\t\treturn base64Decode(bodyLines.join(''));\n\t} catch {\n\t\tthrow new Error(`Invalid PEM for ${label}`);\n\t}\n}\n\n/**\n * Finds all `BEGIN`/`END`-delimited PEM blocks in a string and returns\n * them as parsed {@linkcode PemBlock} entries. Handles concatenated PEM files\n * and ignores non-PEM text between blocks.\n */\nexport function splitPemBlocks(input: string): readonly PemBlock[] {\n\tconst normalized = input.replace(/\\r/g, '');\n\tconst blocks: PemBlock[] = [];\n\tconst beginToken = '-----BEGIN ';\n\t// Linear `indexOf` scan rather than a global regex with a lazy body: a\n\t// backtracking pattern like `([\\s\\S]*?)…\\1` is polynomial on many unclosed\n\t// BEGIN markers (ReDoS). `indexOf` advances monotonically, so this stays O(n)\n\t// while preserving the original block/gap/label semantics.\n\tlet cursor = 0;\n\tlet scan = 0;\n\twhile (scan < normalized.length) {\n\t\tconst beginIdx = normalized.indexOf(beginToken, scan);\n\t\tif (beginIdx === -1) {\n\t\t\tbreak;\n\t\t}\n\t\tconst labelStart = beginIdx + beginToken.length;\n\t\tconst dashIdx = normalized.indexOf('-----', labelStart);\n\t\tif (dashIdx === -1) {\n\t\t\tbreak;\n\t\t}\n\t\tconst label = normalized.slice(labelStart, dashIdx);\n\t\tconst beginLineEnd = dashIdx + 5;\n\t\t// A well-formed begin line is `-----BEGIN <label>-----\\n` with a dash-free,\n\t\t// single-line label (RFC 7468). Anything else is not a block start; skip it\n\t\t// so it surfaces in the stray-marker checks instead of being parsed.\n\t\tif (\n\t\t\tlabel.length === 0 ||\n\t\t\tlabel.includes('-') ||\n\t\t\tlabel.includes('\\n') ||\n\t\t\tnormalized[beginLineEnd] !== '\\n'\n\t\t) {\n\t\t\tscan = labelStart;\n\t\t\tcontinue;\n\t\t}\n\t\tconst bodyStart = beginLineEnd + 1;\n\t\tconst endToken = `\\n-----END ${label}-----`;\n\t\tconst endIdx = normalized.indexOf(endToken, bodyStart);\n\t\tif (endIdx === -1) {\n\t\t\tbreak;\n\t\t}\n\t\tconst blockEnd = endIdx + endToken.length;\n\t\tconst pem = normalized.slice(beginIdx, blockEnd);\n\t\tif (containsPemMarker(normalized.slice(cursor, beginIdx))) {\n\t\t\tthrow new Error('Malformed PEM block');\n\t\t}\n\t\tblocks.push({\n\t\t\tlabel,\n\t\t\tbytes: pemDecode(label, pem),\n\t\t\tpem,\n\t\t});\n\t\tcursor = blockEnd;\n\t\tscan = blockEnd;\n\t}\n\tif (containsPemMarker(normalized.slice(cursor))) {\n\t\tthrow new Error('Malformed PEM block');\n\t}\n\treturn blocks;\n}\n\n/**\n * Groups PEM blocks by label into well-known PKI categories\n * (certificates, CSRs, private keys, public keys, and everything else).\n * Accepts either raw PEM text or pre-split {@linkcode PemBlock} entries.\n */\nexport function categorizePemBlocks(input: string | readonly PemBlock[]): CategorizedPemBlocks {\n\tconst blocks = typeof input === 'string' ? splitPemBlocks(input) : input;\n\tconst certificates: PemBlock[] = [];\n\tconst certificateRequests: PemBlock[] = [];\n\tconst privateKeys: PemBlock[] = [];\n\tconst publicKeys: PemBlock[] = [];\n\tconst others: PemBlock[] = [];\n\n\tfor (const block of blocks) {\n\t\tswitch (block.label) {\n\t\t\tcase 'CERTIFICATE':\n\t\t\t\tcertificates.push(block);\n\t\t\t\tbreak;\n\t\t\tcase 'CERTIFICATE REQUEST':\n\t\t\t\tcertificateRequests.push(block);\n\t\t\t\tbreak;\n\t\t\tcase 'PRIVATE KEY':\n\t\t\tcase 'RSA PRIVATE KEY':\n\t\t\tcase 'EC PRIVATE KEY':\n\t\t\t\tprivateKeys.push(block);\n\t\t\t\tbreak;\n\t\t\tcase 'PUBLIC KEY':\n\t\t\t\tpublicKeys.push(block);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tothers.push(block);\n\t\t}\n\t}\n\n\treturn { certificates, certificateRequests, privateKeys, publicKeys, others };\n}\n\nfunction normalizePemBodyLines(lines: readonly string[]): readonly string[] | undefined {\n\tconst normalizedLines = lines.map((line) => line.replace(/[ \\t]/g, ''));\n\tconst nonEmptyLines = normalizedLines.filter((line) => line !== '');\n\tif (nonEmptyLines.length === 0) {\n\t\treturn [''];\n\t}\n\treturn nonEmptyLines.every((line) => /^[A-Za-z0-9+/=]+$/.test(line)) ? nonEmptyLines : undefined;\n}\n\nfunction containsPemMarker(value: string): boolean {\n\treturn value.includes('-----BEGIN ') || value.includes('-----END ');\n}\n"],"mappings":"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"}
package/dist/pem.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import { CategorizedPemBlocks, PemBlock, categorizePemBlocks, pemDecode, pemEncode, splitPemBlocks } from "./pem/pem.js";
2
+ export { type CategorizedPemBlocks, type PemBlock, categorizePemBlocks, pemDecode, pemEncode, splitPemBlocks };
package/dist/pem.js ADDED
@@ -0,0 +1 @@
1
+ import{categorizePemBlocks as e,pemDecode as t,pemEncode as n,splitPemBlocks as r}from"./pem/pem.js";export{e as categorizePemBlocks,t as pemDecode,n as pemEncode,r as splitPemBlocks};
@@ -0,0 +1,177 @@
1
+ import { Pbes2EncryptionOptions, Pbes2EncryptionScheme, Pbes2Prf } from "../internal/crypto/pbes2.js";
2
+ import { ErrorResult, Micro509Error } from "../result/result.js";
3
+ import { ParsedCertificate } from "../x509/parse.js";
4
+ import { ParsedPkcs12MacData, Pkcs12MacOptions, createPkcs12MacData, parsePkcs12MacData } from "./pkcs12-mac.js";
5
+
6
+ //#region src/pkcs/pfx.d.ts
7
+ /** PEM string or DER bytes for a certificate to include in a PFX bag. */
8
+ type PfxCertificateSource = string | Uint8Array;
9
+ /** A WebCrypto private key or raw PKCS#8 DER bytes for a PFX key bag. */
10
+ type PfxPrivateKeySource = CryptoKey | Uint8Array;
11
+ /** Optional metadata attached to a certificate or key bag inside a PFX. */
12
+ interface PfxBagAttributesInput {
13
+ /** Human-readable label stored as a BMPString attribute. */
14
+ readonly friendlyName?: string;
15
+ /** Opaque identifier linking a certificate bag to its corresponding key bag. */
16
+ readonly localKeyId?: Uint8Array;
17
+ }
18
+ /** A certificate to embed in a PFX container. Input for {@linkcode createPfx}. */
19
+ interface PfxCertificateBagInput {
20
+ /** Certificate as PEM text or DER bytes. */
21
+ readonly certificate: PfxCertificateSource;
22
+ /** Optional bag-level attributes (friendly name, local key ID). */
23
+ readonly attributes?: PfxBagAttributesInput;
24
+ }
25
+ /** A private key to embed in a PFX container. Input for {@linkcode createPfx}. */
26
+ interface PfxPrivateKeyBagInput {
27
+ /** Private key as a WebCrypto `CryptoKey` or raw PKCS#8 DER bytes. */
28
+ readonly privateKey: PfxPrivateKeySource;
29
+ /** Optional bag-level attributes (friendly name, local key ID). */
30
+ readonly attributes?: PfxBagAttributesInput;
31
+ }
32
+ /** Input for {@linkcode createPfx}. */
33
+ interface CreatePfxInput {
34
+ /** Certificates to include as certBag entries. */
35
+ readonly certificates?: readonly PfxCertificateBagInput[];
36
+ /** Private keys to include as keyBag entries. */
37
+ readonly privateKeys?: readonly PfxPrivateKeyBagInput[];
38
+ /** PBES2 encryption settings for the key-bag ContentInfo. Omit for unencrypted. */
39
+ readonly encryption?: PfxEncryptionOptions;
40
+ /** PKCS#12 MAC integrity settings. Omit to skip MAC generation. */
41
+ readonly mac?: Pkcs12MacOptions;
42
+ }
43
+ /** PBES2 encryption settings for PFX key-bag protection. Alias of {@linkcode Pbes2EncryptionOptions}. */
44
+ type PfxEncryptionOptions = Pbes2EncryptionOptions;
45
+ /** Options for {@linkcode parsePfxDer} and {@linkcode parsePfxPem}. */
46
+ interface ParsePfxOptions {
47
+ /** Password used to decrypt PBES2-encrypted ContentInfo entries. Also used for MAC verification when `macPassword` is omitted. */
48
+ readonly password?: string;
49
+ /** Separate password for MAC verification. Falls back to `password` when omitted. */
50
+ readonly macPassword?: string;
51
+ }
52
+ /** DER, PEM, and base64 encodings of a PFX container produced by {@linkcode createPfx}. */
53
+ interface PfxMaterial {
54
+ /** Raw DER-encoded PFX bytes. */
55
+ readonly der: Uint8Array;
56
+ /** PEM-armored PFX (`-----BEGIN PKCS12-----`). */
57
+ readonly pem: string;
58
+ /** Base64-encoded DER (no PEM armor). */
59
+ readonly base64: string;
60
+ }
61
+ /** A single PKCS#12 bag attribute as decoded by {@linkcode parsePfxDer}. */
62
+ interface ParsedPfxAttribute {
63
+ /** Dotted-decimal OID identifying this attribute type. */
64
+ readonly oid: string;
65
+ /** Hex-encoded DER of each attribute value. */
66
+ readonly valuesHex: readonly string[];
67
+ }
68
+ /** Decoded bag attributes for a single SafeBag inside a PFX. */
69
+ interface ParsedPfxBagAttributes {
70
+ /** All raw attributes as OID + hex-encoded values. */
71
+ readonly entries: readonly ParsedPfxAttribute[];
72
+ /** Decoded BMPString friendly-name attribute, if present. */
73
+ readonly friendlyName?: string;
74
+ /** Hex-encoded localKeyId attribute, if present. */
75
+ readonly localKeyId?: string;
76
+ }
77
+ /**
78
+ * Discriminated union of SafeBag types decoded from a PFX container.
79
+ *
80
+ * Use `kind` to narrow: `'certificate'` | `'privateKey'` | `'unknown'`.
81
+ */
82
+ type ParsedPfxBag = {
83
+ /** Bag contains an X.509 certificate. */readonly kind: "certificate"; /** Dotted-decimal OID of the bag type. */
84
+ readonly bagId: string; /** Decoded bag-level attributes. */
85
+ readonly attributes: ParsedPfxBagAttributes; /** Parsed certificate from the certBag. */
86
+ readonly certificate: ParsedCertificate;
87
+ } | {
88
+ /** Bag contains a PKCS#8 private key. */readonly kind: "privateKey"; /** Dotted-decimal OID of the bag type. */
89
+ readonly bagId: string; /** Decoded bag-level attributes. */
90
+ readonly attributes: ParsedPfxBagAttributes; /** Raw DER-encoded PKCS#8 PrivateKeyInfo. */
91
+ readonly pkcs8Der: Uint8Array;
92
+ } | {
93
+ /** Bag type not recognized by this library. */readonly kind: "unknown"; /** Dotted-decimal OID of the bag type. */
94
+ readonly bagId: string; /** Decoded bag-level attributes. */
95
+ readonly attributes: ParsedPfxBagAttributes; /** Raw DER of the unrecognized bag value. */
96
+ readonly valueDer: Uint8Array;
97
+ };
98
+ /** Fully decoded PFX container returned by {@linkcode parsePfxDer} / {@linkcode parsePfxPem}. */
99
+ interface ParsedPfx {
100
+ /** All SafeBags in the PFX, including unknown types. */
101
+ readonly bags: readonly ParsedPfxBag[];
102
+ /** Convenience: only the parsed certificates extracted from certBag entries. */
103
+ readonly certificates: readonly ParsedCertificate[];
104
+ /** Convenience: raw PKCS#8 DER of each private key extracted from keyBag entries. */
105
+ readonly privateKeys: readonly Uint8Array[];
106
+ /** MAC verification metadata, present when the PFX includes a MacData block. */
107
+ readonly macData?: ParsedPkcs12MacData;
108
+ }
109
+ /** Error codes returned by {@linkcode parsePfxDer} and {@linkcode parsePfxPem}. */
110
+ type ParsePfxErrorCode = "malformed" | "invalid_password" | "password_required";
111
+ /** Error payload for a failed PFX parse. */
112
+ interface ParsePfxFailure extends Micro509Error<ParsePfxErrorCode> {
113
+ /** Always `false` for failures. */
114
+ readonly ok: false;
115
+ }
116
+ /** Success-or-failure result from {@linkcode parsePfxDer} / {@linkcode parsePfxPem}. */
117
+ type ParsePfxResult = {
118
+ /** Parse succeeded. */readonly ok: true; /** Decoded PFX container. */
119
+ readonly value: ParsedPfx;
120
+ } | ErrorResult<ParsePfxErrorCode, Record<never, never>, ParsePfxFailure>;
121
+ /**
122
+ * Builds a PKCS#12/PFX archive containing certificates and/or private keys.
123
+ *
124
+ * When `encryption` is provided, the key-bag ContentInfo is PBES2-encrypted.
125
+ * When `mac` is provided, a PKCS#12 MAC integrity block is appended.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * import { createPfx } from 'micro509';
130
+ *
131
+ * const pfx = await createPfx({
132
+ * certificates: [{ certificate: certPem }],
133
+ * privateKeys: [{ privateKey: keyPair.privateKey }],
134
+ * encryption: { password: 's3cret' },
135
+ * mac: { password: 's3cret' },
136
+ * });
137
+ * // pfx.der, pfx.pem, pfx.base64
138
+ * ```
139
+ */
140
+ declare function createPfx(input: CreatePfxInput): Promise<PfxMaterial>;
141
+ /**
142
+ * Decodes a DER-encoded PKCS#12/PFX container into its constituent bags.
143
+ *
144
+ * Returns a result union — check `ok` before accessing `value`.
145
+ * Encrypted containers require `options.password`. MAC verification uses
146
+ * `options.macPassword` (falls back to `options.password`).
147
+ *
148
+ * @example
149
+ * ```ts
150
+ * import { parsePfxDer } from 'micro509';
151
+ *
152
+ * const result = await parsePfxDer(pfxBytes, { password: 's3cret' });
153
+ * if (result.ok) {
154
+ * console.log(result.value.certificates.length);
155
+ * }
156
+ * ```
157
+ */
158
+ declare function parsePfxDer(der: Uint8Array, options?: ParsePfxOptions): Promise<ParsePfxResult>;
159
+ /**
160
+ * Decodes a PEM-armored PKCS#12/PFX container. Expects exactly one `PKCS12` block.
161
+ *
162
+ * Delegates to {@linkcode parsePfxDer} after PEM decoding.
163
+ *
164
+ * @example
165
+ * ```ts
166
+ * import { parsePfxPem } from 'micro509';
167
+ *
168
+ * const result = await parsePfxPem(pfxPemString, { password: 's3cret' });
169
+ * if (result.ok) {
170
+ * console.log(result.value.privateKeys.length);
171
+ * }
172
+ * ```
173
+ */
174
+ declare function parsePfxPem(pem: string, options?: ParsePfxOptions): Promise<ParsePfxResult>;
175
+ //#endregion
176
+ export { CreatePfxInput, ParsePfxErrorCode, ParsePfxFailure, ParsePfxOptions, ParsePfxResult, ParsedPfx, ParsedPfxAttribute, ParsedPfxBag, ParsedPfxBagAttributes, type ParsedPkcs12MacData, type Pbes2EncryptionOptions, type Pbes2EncryptionScheme, type Pbes2Prf, PfxBagAttributesInput, PfxCertificateBagInput, PfxCertificateSource, PfxEncryptionOptions, PfxMaterial, PfxPrivateKeyBagInput, PfxPrivateKeySource, type Pkcs12MacOptions, createPfx, type createPkcs12MacData, parsePfxDer, parsePfxPem, type parsePkcs12MacData };
177
+ //# sourceMappingURL=pfx.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{explicitContext as e,integerFromNumber as t,objectIdentifier as n,octetString as r,readElement as i,readSequenceChildren as a,sequence as o,setOf as s,tlv as c}from"../internal/asn1/der.js";import{childrenOf as l,decodeIntegerNumber as u,decodeObjectIdentifier as d,toHex as f}from"../internal/asn1/asn1.js";import{OIDS as p}from"../internal/asn1/oids.js";import{decryptPbes2 as m,encryptPbes2 as h}from"../internal/crypto/pbes2.js";import{base64Encode as g}from"../internal/shared/base64.js";import{pemEncode as _,splitPemBlocks as v}from"../pem/pem.js";import{exportPkcs8Der as y}from"../keys/keys.js";import{parseCertificateDer as b}from"../x509/parse.js";import{createPkcs12MacData as x,parsePkcs12MacData as S}from"./pkcs12-mac.js";async function C(e){let n=[],r=[];for(let t of e.certificates??[])n.push(k(z(t.certificate),t.attributes));for(let t of e.privateKeys??[])r.push(A(await R(t.privateKey),t.attributes));let i=[];if(n.length>0&&i.push(j(o(n))),r.length>0){let t=o(r);i.push(e.encryption===void 0?j(t):await M(t,e.encryption))}let a=o(i),s=e.mac===void 0?void 0:await x(a,e.mac),c=o([t(3),j(a),...s===void 0?[]:[s.der]]);return{der:c,pem:_(`PKCS12`,c),base64:g(c)}}async function w(e,t){try{let n=a(e,{maxDepth:64});if(n.length<2||n.length>3)return E(`malformed`,`Malformed PFX structure`);let r=n[0],i=n[1];if(r===void 0||i===void 0||r.tag!==2)return E(`malformed`,`Malformed PFX structure`);if(u(r.value)!==3)return E(`malformed`,`Unsupported PFX version`);let o=D(e.slice(i.start-i.headerLength,i.end)),s=n[2],c;if(s!==void 0){try{c=await S(e.slice(s.start-s.headerLength,s.end),o,t?.macPassword??t?.password)}catch{return E(`malformed`,`Malformed PFX MacData`)}if(c?.valid===!1)return E(`invalid_password`,`Invalid PFX MAC password or corrupted content`)}let l=a(o),d=[];for(let e of l){let n=await O(o.slice(e.start-e.headerLength,e.end),t);if(n.error!==void 0)return n.error;let r=n.data;for(let e of a(r)){let t=r.slice(e.start-e.headerLength,e.end);d.push(P(t))}}return{ok:!0,value:{bags:d,certificates:d.flatMap(e=>e.kind===`certificate`?[e.certificate]:[]),privateKeys:d.flatMap(e=>e.kind===`privateKey`?[e.pkcs8Der]:[]),...c===void 0?{}:{macData:c}}}}catch{return E(`malformed`,`Malformed PFX structure`)}}async function T(e,t){try{let n=v(e).filter(e=>e.label===`PKCS12`),r=n[0];return r===void 0||n.length!==1?E(`malformed`,`Expected exactly one PKCS12 PEM block`):w(r.bytes,t)}catch{return E(`malformed`,`Expected exactly one PKCS12 PEM block`)}}function E(e,t){return{ok:!1,error:{ok:!1,code:e,message:t},code:e,message:t}}function D(e){let t=a(e),n=t[0],r=t[1];if(n===void 0||r===void 0||t.length!==2||n.tag!==6)throw Error(`Malformed ContentInfo`);if(d(n.value)!==p.pkcs7Data)throw Error(`Only passwordless data ContentInfo is supported`);return V(e,r)}async function O(e,t){let n=a(e),r=n[0],i=n[1];if(r===void 0||i===void 0||n.length!==2||r.tag!==6)return{error:E(`malformed`,`Malformed ContentInfo`)};let o=d(r.value);if(o===p.pkcs7Data)return{data:V(e,i)};if(o!==p.pkcs7EncryptedData)return{error:E(`malformed`,`Unsupported PFX ContentInfo type`)};if(t?.password===void 0)return{error:E(`password_required`,`Password required for encrypted PFX content`)};let s=H(e,i);try{let n=await B(e.slice(s.start-s.headerLength,s.end),t.password);return a(n),{data:n}}catch(e){return L(e)?{error:E(`malformed`,`Malformed PFX encrypted content`)}:{error:E(`invalid_password`,`Invalid PFX password or encrypted content`)}}}function k(t,i){let a=o([n(p.x509CertificateBagType),e(0,r(t))]);return o([n(p.pkcs12CertBag),e(0,a),...N(i)])}function A(t,r){return o([n(p.pkcs12KeyBag),e(0,t),...N(r)])}function j(t){return o([n(p.pkcs7Data),e(0,r(t))])}async function M(r,i){let a=await h(r,i),s=o([t(0),o([n(p.pkcs7Data),a.algorithmIdentifierDer,c(128,a.encryptedData)])]);return o([n(p.pkcs7EncryptedData),e(0,s)])}function N(e){if(e===void 0)return[];let t=[];return e.friendlyName!==void 0&&t.push(o([n(p.friendlyName),s([U(e.friendlyName)])])),e.localKeyId!==void 0&&t.push(o([n(p.localKeyId),s([r(e.localKeyId)])])),t.length===0?[]:[s(t)]}function P(e){let t=a(e),n=t[0],r=t[1],i=t[2];if(n===void 0||r===void 0||t.length>3)throw Error(`Malformed SafeBag`);let o=d(n.value),s=F(e,i);if(o===p.pkcs12CertBag){let t=H(e,r),n=e.slice(t.start-t.headerLength,t.end),i=a(n),c=i[0],l=i[1];if(c===void 0||l===void 0||i.length!==2||d(c.value)!==p.x509CertificateBagType)throw Error(`Malformed certBag`);return{kind:`certificate`,bagId:o,attributes:s,certificate:b(V(n,l))}}if(o===p.pkcs12KeyBag){let t=H(e,r);return{kind:`privateKey`,bagId:o,attributes:s,pkcs8Der:e.slice(t.start-t.headerLength,t.end)}}let c=H(e,r);return{kind:`unknown`,bagId:o,attributes:s,valueDer:e.slice(c.start-c.headerLength,c.end)}}function F(e,t){if(t===void 0)return{entries:[]};let n=[],r,i;for(let o of l(e,t)){let t=e.slice(o.start-o.headerLength,o.end),s=a(t),c=s[0],u=s[1];if(c===void 0||u===void 0||s.length!==2||u.tag!==49)throw Error(`Malformed PFX bag attribute`);let m=d(c.value),h=l(t,u).map(e=>t.slice(e.start-e.headerLength,e.end));if(n.push({oid:m,valuesHex:h.map(e=>f(e))}),m===p.friendlyName){let e=h[0];if(r!==void 0||h.length!==1||e===void 0)throw Error(`Malformed friendlyName attribute`);r=W(e);continue}if(m===p.localKeyId){let e=h[0];if(i!==void 0||h.length!==1||e===void 0)throw Error(`Malformed localKeyId attribute`);i=I(e)}}return{entries:n,...r===void 0?{}:{friendlyName:r},...i===void 0?{}:{localKeyId:i}}}function I(e){let t=i(e);if(t.tag!==4)throw Error(`localKeyId must use OCTET STRING`);return f(t.value)}function L(e){return e instanceof Error?e.message.startsWith(`Malformed `)||e.message.startsWith(`Unsupported `)||e.message.startsWith(`Invalid PBES2 `)||e.message===`Only passwordless data ContentInfo is supported`:!1}async function R(e){return e instanceof CryptoKey?y(e):new Uint8Array(e)}function z(e){if(typeof e==`string`){let t=v(e).find(e=>e.label===`CERTIFICATE`);if(t===void 0)throw Error(`Certificate PEM required`);return new Uint8Array(t.bytes)}return new Uint8Array(e)}async function B(e,t){let n=a(e),r=n[1];if(n.length!==2||r===void 0)throw Error(`Malformed EncryptedData`);let i=n[0];if(i===void 0||i.tag!==2||u(i.value)!==0)throw Error(`Malformed EncryptedData`);let o=e.slice(r.start-r.headerLength,r.end),s=a(o),c=s[1],l=s[2];if(c===void 0||l===void 0||s.length!==3||s[0]?.tag!==6)throw Error(`Malformed EncryptedContentInfo`);if(l.tag!==128)throw Error(`Malformed encrypted content`);return m(o.slice(c.start-c.headerLength,c.end),l.value,t)}function V(e,t){let n=H(e,t);if(n.tag!==4)throw Error(`Expected OCTET STRING in context value`);return n.value}function H(e,t){if((t.tag&224)!=160)throw Error(`Expected context-specific constructed value`);let n=l(e,t),r=n[0];if(n.length!==1||r===void 0)throw Error(`Expected context-specific wrapper with exactly one value`);return r}function U(e){let t=new Uint8Array(e.length*2);for(let n=0;n<e.length;n+=1){let r=e.charCodeAt(n);t[n*2]=r>>8,t[n*2+1]=r&255}return c(30,t)}function W(e){let t=i(e);if(t.tag!==30)throw Error(`Expected BMPString`);if(t.value.length%2!=0)throw Error(`BMPString must use an even number of bytes`);let n=``;for(let e=0;e<t.value.length;e+=2){let r=t.value[e]??0,i=t.value[e+1]??0;n+=String.fromCharCode(r<<8|i)}return n}export{C as createPfx,w as parsePfxDer,T as parsePfxPem};
2
+ //# sourceMappingURL=pfx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pfx.js","names":[],"sources":["../../src/pkcs/pfx.ts"],"sourcesContent":["/**\n * PKCS#12/PFX container creation and parsing.\n *\n * Builds and decodes PFX archives containing certificate bags, private-key bags,\n * optional PBES2 encryption, and PKCS#12 MAC integrity verification.\n *\n * @module\n */\n\nimport {\n\tchildrenOf,\n\tdecodeIntegerNumber,\n\tdecodeObjectIdentifier,\n\ttoHex,\n} from '#micro509/internal/asn1/asn1.ts';\nimport type { DerElement } from '#micro509/internal/asn1/der.ts';\nimport {\n\tDEFAULT_MAX_DER_DEPTH,\n\texplicitContext,\n\tintegerFromNumber,\n\tobjectIdentifier,\n\toctetString,\n\treadElement,\n\treadSequenceChildren,\n\tsequence,\n\tsetOf,\n\ttlv,\n} from '#micro509/internal/asn1/der.ts';\nimport { OIDS } from '#micro509/internal/asn1/oids.ts';\nimport {\n\tdecryptPbes2,\n\tencryptPbes2,\n\ttype Pbes2EncryptionOptions,\n} from '#micro509/internal/crypto/pbes2.ts';\nimport { base64Encode } from '#micro509/internal/shared/base64.ts';\nimport { exportPkcs8Der } from '#micro509/keys/keys.ts';\nimport { pemEncode, splitPemBlocks } from '#micro509/pem/pem.ts';\nimport type { ErrorResult, Micro509Error } from '#micro509/result/result.ts';\nimport { type ParsedCertificate, parseCertificateDer } from '#micro509/x509/parse.ts';\nimport {\n\tcreatePkcs12MacData,\n\ttype ParsedPkcs12MacData,\n\ttype Pkcs12MacOptions,\n\tparsePkcs12MacData,\n} from './pkcs12-mac.ts';\n\nexport type {\n\tPbes2EncryptionOptions,\n\tPbes2EncryptionScheme,\n\tPbes2Prf,\n} from '#micro509/internal/crypto/pbes2.ts';\nexport type * from './pkcs12-mac.ts';\n\n/** PEM string or DER bytes for a certificate to include in a PFX bag. */\nexport type PfxCertificateSource = string | Uint8Array;\n/** A WebCrypto private key or raw PKCS#8 DER bytes for a PFX key bag. */\nexport type PfxPrivateKeySource = CryptoKey | Uint8Array;\n\n/** Optional metadata attached to a certificate or key bag inside a PFX. */\nexport interface PfxBagAttributesInput {\n\t/** Human-readable label stored as a BMPString attribute. */\n\treadonly friendlyName?: string;\n\t/** Opaque identifier linking a certificate bag to its corresponding key bag. */\n\treadonly localKeyId?: Uint8Array;\n}\n\n/** A certificate to embed in a PFX container. Input for {@linkcode createPfx}. */\nexport interface PfxCertificateBagInput {\n\t/** Certificate as PEM text or DER bytes. */\n\treadonly certificate: PfxCertificateSource;\n\t/** Optional bag-level attributes (friendly name, local key ID). */\n\treadonly attributes?: PfxBagAttributesInput;\n}\n\n/** A private key to embed in a PFX container. Input for {@linkcode createPfx}. */\nexport interface PfxPrivateKeyBagInput {\n\t/** Private key as a WebCrypto `CryptoKey` or raw PKCS#8 DER bytes. */\n\treadonly privateKey: PfxPrivateKeySource;\n\t/** Optional bag-level attributes (friendly name, local key ID). */\n\treadonly attributes?: PfxBagAttributesInput;\n}\n\n/** Input for {@linkcode createPfx}. */\nexport interface CreatePfxInput {\n\t/** Certificates to include as certBag entries. */\n\treadonly certificates?: readonly PfxCertificateBagInput[];\n\t/** Private keys to include as keyBag entries. */\n\treadonly privateKeys?: readonly PfxPrivateKeyBagInput[];\n\t/** PBES2 encryption settings for the key-bag ContentInfo. Omit for unencrypted. */\n\treadonly encryption?: PfxEncryptionOptions;\n\t/** PKCS#12 MAC integrity settings. Omit to skip MAC generation. */\n\treadonly mac?: Pkcs12MacOptions;\n}\n\n/** PBES2 encryption settings for PFX key-bag protection. Alias of {@linkcode Pbes2EncryptionOptions}. */\nexport type PfxEncryptionOptions = Pbes2EncryptionOptions;\n\n/** Options for {@linkcode parsePfxDer} and {@linkcode parsePfxPem}. */\nexport interface ParsePfxOptions {\n\t/** Password used to decrypt PBES2-encrypted ContentInfo entries. Also used for MAC verification when `macPassword` is omitted. */\n\treadonly password?: string;\n\t/** Separate password for MAC verification. Falls back to `password` when omitted. */\n\treadonly macPassword?: string;\n}\n\n/** DER, PEM, and base64 encodings of a PFX container produced by {@linkcode createPfx}. */\nexport interface PfxMaterial {\n\t/** Raw DER-encoded PFX bytes. */\n\treadonly der: Uint8Array;\n\t/** PEM-armored PFX (`-----BEGIN PKCS12-----`). */\n\treadonly pem: string;\n\t/** Base64-encoded DER (no PEM armor). */\n\treadonly base64: string;\n}\n\n/** A single PKCS#12 bag attribute as decoded by {@linkcode parsePfxDer}. */\nexport interface ParsedPfxAttribute {\n\t/** Dotted-decimal OID identifying this attribute type. */\n\treadonly oid: string;\n\t/** Hex-encoded DER of each attribute value. */\n\treadonly valuesHex: readonly string[];\n}\n\n/** Decoded bag attributes for a single SafeBag inside a PFX. */\nexport interface ParsedPfxBagAttributes {\n\t/** All raw attributes as OID + hex-encoded values. */\n\treadonly entries: readonly ParsedPfxAttribute[];\n\t/** Decoded BMPString friendly-name attribute, if present. */\n\treadonly friendlyName?: string;\n\t/** Hex-encoded localKeyId attribute, if present. */\n\treadonly localKeyId?: string;\n}\n\n/**\n * Discriminated union of SafeBag types decoded from a PFX container.\n *\n * Use `kind` to narrow: `'certificate'` | `'privateKey'` | `'unknown'`.\n */\nexport type ParsedPfxBag =\n\t| {\n\t\t\t/** Bag contains an X.509 certificate. */\n\t\t\treadonly kind: 'certificate';\n\t\t\t/** Dotted-decimal OID of the bag type. */\n\t\t\treadonly bagId: string;\n\t\t\t/** Decoded bag-level attributes. */\n\t\t\treadonly attributes: ParsedPfxBagAttributes;\n\t\t\t/** Parsed certificate from the certBag. */\n\t\t\treadonly certificate: ParsedCertificate;\n\t }\n\t| {\n\t\t\t/** Bag contains a PKCS#8 private key. */\n\t\t\treadonly kind: 'privateKey';\n\t\t\t/** Dotted-decimal OID of the bag type. */\n\t\t\treadonly bagId: string;\n\t\t\t/** Decoded bag-level attributes. */\n\t\t\treadonly attributes: ParsedPfxBagAttributes;\n\t\t\t/** Raw DER-encoded PKCS#8 PrivateKeyInfo. */\n\t\t\treadonly pkcs8Der: Uint8Array;\n\t }\n\t| {\n\t\t\t/** Bag type not recognized by this library. */\n\t\t\treadonly kind: 'unknown';\n\t\t\t/** Dotted-decimal OID of the bag type. */\n\t\t\treadonly bagId: string;\n\t\t\t/** Decoded bag-level attributes. */\n\t\t\treadonly attributes: ParsedPfxBagAttributes;\n\t\t\t/** Raw DER of the unrecognized bag value. */\n\t\t\treadonly valueDer: Uint8Array;\n\t };\n\n/** Fully decoded PFX container returned by {@linkcode parsePfxDer} / {@linkcode parsePfxPem}. */\nexport interface ParsedPfx {\n\t/** All SafeBags in the PFX, including unknown types. */\n\treadonly bags: readonly ParsedPfxBag[];\n\t/** Convenience: only the parsed certificates extracted from certBag entries. */\n\treadonly certificates: readonly ParsedCertificate[];\n\t/** Convenience: raw PKCS#8 DER of each private key extracted from keyBag entries. */\n\treadonly privateKeys: readonly Uint8Array[];\n\t/** MAC verification metadata, present when the PFX includes a MacData block. */\n\treadonly macData?: ParsedPkcs12MacData;\n}\n\n// ---------------------------------------------------------------------------\n// Result types for PFX parsing\n// ---------------------------------------------------------------------------\n\n/** Error codes returned by {@linkcode parsePfxDer} and {@linkcode parsePfxPem}. */\nexport type ParsePfxErrorCode = 'malformed' | 'invalid_password' | 'password_required';\n\n/** Error payload for a failed PFX parse. */\nexport interface ParsePfxFailure extends Micro509Error<ParsePfxErrorCode> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n}\n\n/** Success-or-failure result from {@linkcode parsePfxDer} / {@linkcode parsePfxPem}. */\nexport type ParsePfxResult =\n\t| {\n\t\t\t/** Parse succeeded. */\n\t\t\treadonly ok: true;\n\t\t\t/** Decoded PFX container. */\n\t\t\treadonly value: ParsedPfx;\n\t }\n\t| ErrorResult<ParsePfxErrorCode, Record<never, never>, ParsePfxFailure>;\n\n// ---------------------------------------------------------------------------\n// createPfx\n// ---------------------------------------------------------------------------\n\n/**\n * Builds a PKCS#12/PFX archive containing certificates and/or private keys.\n *\n * When `encryption` is provided, the key-bag ContentInfo is PBES2-encrypted.\n * When `mac` is provided, a PKCS#12 MAC integrity block is appended.\n *\n * @example\n * ```ts\n * import { createPfx } from 'micro509';\n *\n * const pfx = await createPfx({\n * certificates: [{ certificate: certPem }],\n * privateKeys: [{ privateKey: keyPair.privateKey }],\n * encryption: { password: 's3cret' },\n * mac: { password: 's3cret' },\n * });\n * // pfx.der, pfx.pem, pfx.base64\n * ```\n */\nexport async function createPfx(input: CreatePfxInput): Promise<PfxMaterial> {\n\tconst certificateBags: Uint8Array[] = [];\n\tconst privateKeyBags: Uint8Array[] = [];\n\tfor (const certificate of input.certificates ?? []) {\n\t\tcertificateBags.push(\n\t\t\tcreateCertificateBag(normalizeCertificate(certificate.certificate), certificate.attributes),\n\t\t);\n\t}\n\tfor (const privateKey of input.privateKeys ?? []) {\n\t\tprivateKeyBags.push(\n\t\t\tcreatePrivateKeyBag(await normalizePrivateKey(privateKey.privateKey), privateKey.attributes),\n\t\t);\n\t}\n\tconst contentInfos: Uint8Array[] = [];\n\tif (certificateBags.length > 0) {\n\t\tcontentInfos.push(createDataContentInfo(sequence(certificateBags)));\n\t}\n\tif (privateKeyBags.length > 0) {\n\t\tconst safeContents = sequence(privateKeyBags);\n\t\tcontentInfos.push(\n\t\t\tinput.encryption === undefined\n\t\t\t\t? createDataContentInfo(safeContents)\n\t\t\t\t: await createEncryptedDataContentInfo(safeContents, input.encryption),\n\t\t);\n\t}\n\tconst authenticatedSafe = sequence(contentInfos);\n\tconst macData =\n\t\tinput.mac === undefined ? undefined : await createPkcs12MacData(authenticatedSafe, input.mac);\n\tconst der = sequence([\n\t\tintegerFromNumber(3),\n\t\tcreateDataContentInfo(authenticatedSafe),\n\t\t...(macData === undefined ? [] : [macData.der]),\n\t]);\n\treturn {\n\t\tder,\n\t\tpem: pemEncode('PKCS12', der),\n\t\tbase64: base64Encode(der),\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// parsePfxDer / parsePfxPem — Result-returning\n// ---------------------------------------------------------------------------\n\n/**\n * Decodes a DER-encoded PKCS#12/PFX container into its constituent bags.\n *\n * Returns a result union — check `ok` before accessing `value`.\n * Encrypted containers require `options.password`. MAC verification uses\n * `options.macPassword` (falls back to `options.password`).\n *\n * @example\n * ```ts\n * import { parsePfxDer } from 'micro509';\n *\n * const result = await parsePfxDer(pfxBytes, { password: 's3cret' });\n * if (result.ok) {\n * console.log(result.value.certificates.length);\n * }\n * ```\n */\nexport async function parsePfxDer(\n\tder: Uint8Array,\n\toptions?: ParsePfxOptions,\n): Promise<ParsePfxResult> {\n\ttry {\n\t\tconst topLevel = readSequenceChildren(der, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\t\tif (topLevel.length < 2 || topLevel.length > 3) {\n\t\t\treturn pfxFailure('malformed', 'Malformed PFX structure');\n\t\t}\n\t\tconst version = topLevel[0];\n\t\tconst authSafe = topLevel[1];\n\t\tif (version === undefined || authSafe === undefined || version.tag !== 0x02) {\n\t\t\treturn pfxFailure('malformed', 'Malformed PFX structure');\n\t\t}\n\t\tif (decodeIntegerNumber(version.value) !== 3) {\n\t\t\treturn pfxFailure('malformed', 'Unsupported PFX version');\n\t\t}\n\t\tconst authSafeDer = der.slice(authSafe.start - authSafe.headerLength, authSafe.end);\n\t\tconst authenticatedSafeOctets = extractContentInfoData(authSafeDer);\n\t\tconst macElement = topLevel[2];\n\t\tlet macData: ParsedPkcs12MacData | undefined;\n\t\tif (macElement !== undefined) {\n\t\t\ttry {\n\t\t\t\tmacData = await parsePkcs12MacData(\n\t\t\t\t\tder.slice(macElement.start - macElement.headerLength, macElement.end),\n\t\t\t\t\tauthenticatedSafeOctets,\n\t\t\t\t\toptions?.macPassword ?? options?.password,\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\treturn pfxFailure('malformed', 'Malformed PFX MacData');\n\t\t\t}\n\t\t\tif (macData?.valid === false) {\n\t\t\t\treturn pfxFailure('invalid_password', 'Invalid PFX MAC password or corrupted content');\n\t\t\t}\n\t\t}\n\t\tconst authenticatedSafe = readSequenceChildren(authenticatedSafeOctets);\n\t\tconst bags: ParsedPfxBag[] = [];\n\t\tfor (const contentInfo of authenticatedSafe) {\n\t\t\tconst contentInfoDer = authenticatedSafeOctets.slice(\n\t\t\t\tcontentInfo.start - contentInfo.headerLength,\n\t\t\t\tcontentInfo.end,\n\t\t\t);\n\t\t\tconst safeContentsResult = await extractSafeContents(contentInfoDer, options);\n\t\t\tif (safeContentsResult.error !== undefined) {\n\t\t\t\treturn safeContentsResult.error;\n\t\t\t}\n\t\t\tconst safeContents = safeContentsResult.data;\n\t\t\tfor (const bag of readSequenceChildren(safeContents)) {\n\t\t\t\tconst bagDer = safeContents.slice(bag.start - bag.headerLength, bag.end);\n\t\t\t\tbags.push(parseSafeBag(bagDer));\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tok: true,\n\t\t\tvalue: {\n\t\t\t\tbags,\n\t\t\t\tcertificates: bags.flatMap((bag) => (bag.kind === 'certificate' ? [bag.certificate] : [])),\n\t\t\t\tprivateKeys: bags.flatMap((bag) => (bag.kind === 'privateKey' ? [bag.pkcs8Der] : [])),\n\t\t\t\t...(macData === undefined ? {} : { macData }),\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn pfxFailure('malformed', 'Malformed PFX structure');\n\t}\n}\n\n/**\n * Decodes a PEM-armored PKCS#12/PFX container. Expects exactly one `PKCS12` block.\n *\n * Delegates to {@linkcode parsePfxDer} after PEM decoding.\n *\n * @example\n * ```ts\n * import { parsePfxPem } from 'micro509';\n *\n * const result = await parsePfxPem(pfxPemString, { password: 's3cret' });\n * if (result.ok) {\n * console.log(result.value.privateKeys.length);\n * }\n * ```\n */\nexport async function parsePfxPem(pem: string, options?: ParsePfxOptions): Promise<ParsePfxResult> {\n\ttry {\n\t\tconst blocks = splitPemBlocks(pem).filter((block) => block.label === 'PKCS12');\n\t\tconst block = blocks[0];\n\t\tif (block === undefined || blocks.length !== 1) {\n\t\t\treturn pfxFailure('malformed', 'Expected exactly one PKCS12 PEM block');\n\t\t}\n\t\treturn parsePfxDer(block.bytes, options);\n\t} catch {\n\t\treturn pfxFailure('malformed', 'Expected exactly one PKCS12 PEM block');\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Private: PFX helpers\n// ---------------------------------------------------------------------------\n\n/** Shorthand for constructing a PFX parse failure result. */\nfunction pfxFailure(\n\tcode: ParsePfxErrorCode,\n\tmessage: string,\n): ErrorResult<ParsePfxErrorCode, Record<never, never>, ParsePfxFailure> {\n\tconst error: ParsePfxFailure = { ok: false, code, message };\n\treturn { ok: false, error, code, message };\n}\n\n/** Unwraps a `data` ContentInfo to its inner OCTET STRING payload. */\nfunction extractContentInfoData(contentInfoDer: Uint8Array): Uint8Array {\n\tconst contentInfoChildren = readSequenceChildren(contentInfoDer);\n\tconst contentType = contentInfoChildren[0];\n\tconst content = contentInfoChildren[1];\n\tif (\n\t\tcontentType === undefined ||\n\t\tcontent === undefined ||\n\t\tcontentInfoChildren.length !== 2 ||\n\t\tcontentType.tag !== 0x06\n\t) {\n\t\tthrow new Error('Malformed ContentInfo');\n\t}\n\tif (decodeObjectIdentifier(contentType.value) !== OIDS.pkcs7Data) {\n\t\tthrow new Error('Only passwordless data ContentInfo is supported');\n\t}\n\treturn extractContextOctetString(contentInfoDer, content);\n}\n\n/** Extracts SafeContents bytes from a ContentInfo, decrypting if EncryptedData. */\nasync function extractSafeContents(\n\tcontentInfoDer: Uint8Array,\n\toptions: ParsePfxOptions | undefined,\n): Promise<\n\t| {\n\t\t\treadonly data: Uint8Array;\n\t\t\treadonly error?: undefined;\n\t }\n\t| {\n\t\t\treadonly data?: undefined;\n\t\t\treadonly error: ErrorResult<ParsePfxErrorCode, Record<never, never>, ParsePfxFailure>;\n\t }\n> {\n\tconst contentInfoChildren = readSequenceChildren(contentInfoDer);\n\tconst contentType = contentInfoChildren[0];\n\tconst content = contentInfoChildren[1];\n\tif (\n\t\tcontentType === undefined ||\n\t\tcontent === undefined ||\n\t\tcontentInfoChildren.length !== 2 ||\n\t\tcontentType.tag !== 0x06\n\t) {\n\t\treturn { error: pfxFailure('malformed', 'Malformed ContentInfo') };\n\t}\n\tconst oid = decodeObjectIdentifier(contentType.value);\n\tif (oid === OIDS.pkcs7Data) {\n\t\treturn { data: extractContextOctetString(contentInfoDer, content) };\n\t}\n\tif (oid !== OIDS.pkcs7EncryptedData) {\n\t\treturn {\n\t\t\terror: pfxFailure('malformed', 'Unsupported PFX ContentInfo type'),\n\t\t};\n\t}\n\tif (options?.password === undefined) {\n\t\treturn {\n\t\t\terror: pfxFailure('password_required', 'Password required for encrypted PFX content'),\n\t\t};\n\t}\n\tconst encryptedData = extractContextChild(contentInfoDer, content);\n\ttry {\n\t\tconst decrypted = await decryptEncryptedData(\n\t\t\tcontentInfoDer.slice(encryptedData.start - encryptedData.headerLength, encryptedData.end),\n\t\t\toptions.password,\n\t\t);\n\t\treadSequenceChildren(decrypted);\n\t\treturn { data: decrypted };\n\t} catch (error) {\n\t\tif (isMalformedPfxEncryptedContentError(error)) {\n\t\t\treturn {\n\t\t\t\terror: pfxFailure('malformed', 'Malformed PFX encrypted content'),\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\terror: pfxFailure('invalid_password', 'Invalid PFX password or encrypted content'),\n\t\t};\n\t}\n}\n\n/** Encodes a certBag SafeBag wrapping a DER certificate with optional attributes. */\nfunction createCertificateBag(\n\tcertificateDer: Uint8Array,\n\tattributes: PfxBagAttributesInput | undefined,\n): Uint8Array {\n\tconst certBag = sequence([\n\t\tobjectIdentifier(OIDS.x509CertificateBagType),\n\t\texplicitContext(0, octetString(certificateDer)),\n\t]);\n\treturn sequence([\n\t\tobjectIdentifier(OIDS.pkcs12CertBag),\n\t\texplicitContext(0, certBag),\n\t\t...encodeBagAttributes(attributes),\n\t]);\n}\n\n/** Encodes a keyBag SafeBag wrapping PKCS#8 DER with optional attributes. */\nfunction createPrivateKeyBag(\n\tpkcs8Der: Uint8Array,\n\tattributes: PfxBagAttributesInput | undefined,\n): Uint8Array {\n\treturn sequence([\n\t\tobjectIdentifier(OIDS.pkcs12KeyBag),\n\t\texplicitContext(0, pkcs8Der),\n\t\t...encodeBagAttributes(attributes),\n\t]);\n}\n\n/** Wraps raw bytes in a `pkcs7-data` ContentInfo SEQUENCE. */\nfunction createDataContentInfo(data: Uint8Array): Uint8Array {\n\treturn sequence([objectIdentifier(OIDS.pkcs7Data), explicitContext(0, octetString(data))]);\n}\n\n/** PBES2-encrypts data and wraps it in a `pkcs7-encryptedData` ContentInfo. */\nasync function createEncryptedDataContentInfo(\n\tdata: Uint8Array,\n\toptions: PfxEncryptionOptions,\n): Promise<Uint8Array> {\n\tconst encryption = await encryptPbes2(data, options);\n\tconst encryptedData = sequence([\n\t\tintegerFromNumber(0),\n\t\tsequence([\n\t\t\tobjectIdentifier(OIDS.pkcs7Data),\n\t\t\tencryption.algorithmIdentifierDer,\n\t\t\ttlv(0x80, encryption.encryptedData),\n\t\t]),\n\t]);\n\treturn sequence([objectIdentifier(OIDS.pkcs7EncryptedData), explicitContext(0, encryptedData)]);\n}\n\n/** DER-encodes optional friendlyName / localKeyId into a SET OF SEQUENCE. */\nfunction encodeBagAttributes(attributes: PfxBagAttributesInput | undefined): readonly Uint8Array[] {\n\tif (attributes === undefined) {\n\t\treturn [];\n\t}\n\tconst out: Uint8Array[] = [];\n\tif (attributes.friendlyName !== undefined) {\n\t\tout.push(\n\t\t\tsequence([objectIdentifier(OIDS.friendlyName), setOf([bmpString(attributes.friendlyName)])]),\n\t\t);\n\t}\n\tif (attributes.localKeyId !== undefined) {\n\t\tout.push(\n\t\t\tsequence([objectIdentifier(OIDS.localKeyId), setOf([octetString(attributes.localKeyId)])]),\n\t\t);\n\t}\n\treturn out.length === 0 ? [] : [setOf(out)];\n}\n\n/** Decodes a single SafeBag from DER into a {@linkcode ParsedPfxBag} discriminated union. */\nfunction parseSafeBag(der: Uint8Array): ParsedPfxBag {\n\tconst children = readSequenceChildren(der);\n\tconst bagId = children[0];\n\tconst bagValue = children[1];\n\tconst attributeSet = children[2];\n\tif (bagId === undefined || bagValue === undefined || children.length > 3) {\n\t\tthrow new Error('Malformed SafeBag');\n\t}\n\tconst bagOid = decodeObjectIdentifier(bagId.value);\n\tconst attributes = parseBagAttributes(der, attributeSet);\n\tif (bagOid === OIDS.pkcs12CertBag) {\n\t\tconst certBag = extractContextChild(der, bagValue);\n\t\tconst certBagDer = der.slice(certBag.start - certBag.headerLength, certBag.end);\n\t\tconst certBagChildren = readSequenceChildren(certBagDer);\n\t\tconst certType = certBagChildren[0];\n\t\tconst certValue = certBagChildren[1];\n\t\tif (\n\t\t\tcertType === undefined ||\n\t\t\tcertValue === undefined ||\n\t\t\tcertBagChildren.length !== 2 ||\n\t\t\tdecodeObjectIdentifier(certType.value) !== OIDS.x509CertificateBagType\n\t\t) {\n\t\t\tthrow new Error('Malformed certBag');\n\t\t}\n\t\tconst certificateDer = extractContextOctetString(certBagDer, certValue);\n\t\treturn {\n\t\t\tkind: 'certificate',\n\t\t\tbagId: bagOid,\n\t\t\tattributes,\n\t\t\tcertificate: parseCertificateDer(certificateDer),\n\t\t};\n\t}\n\tif (bagOid === OIDS.pkcs12KeyBag) {\n\t\tconst pkcs8 = extractContextChild(der, bagValue);\n\t\treturn {\n\t\t\tkind: 'privateKey',\n\t\t\tbagId: bagOid,\n\t\t\tattributes,\n\t\t\tpkcs8Der: der.slice(pkcs8.start - pkcs8.headerLength, pkcs8.end),\n\t\t};\n\t}\n\tconst value = extractContextChild(der, bagValue);\n\treturn {\n\t\tkind: 'unknown',\n\t\tbagId: bagOid,\n\t\tattributes,\n\t\tvalueDer: der.slice(value.start - value.headerLength, value.end),\n\t};\n}\n\n/** Decodes the SET OF attributes attached to a SafeBag. */\nfunction parseBagAttributes(\n\tsource: Uint8Array,\n\tattributeSet: DerElement | undefined,\n): ParsedPfxBagAttributes {\n\tif (attributeSet === undefined) {\n\t\treturn { entries: [] };\n\t}\n\tconst entries: ParsedPfxAttribute[] = [];\n\tlet friendlyName: string | undefined;\n\tlet localKeyId: string | undefined;\n\tfor (const attribute of childrenOf(source, attributeSet)) {\n\t\tconst attributeDer = source.slice(attribute.start - attribute.headerLength, attribute.end);\n\t\tconst parts = readSequenceChildren(attributeDer);\n\t\tconst oid = parts[0];\n\t\tconst values = parts[1];\n\t\tif (oid === undefined || values === undefined || parts.length !== 2 || values.tag !== 0x31) {\n\t\t\tthrow new Error('Malformed PFX bag attribute');\n\t\t}\n\t\tconst attrOid = decodeObjectIdentifier(oid.value);\n\t\tconst rawValues = childrenOf(attributeDer, values).map((value) =>\n\t\t\tattributeDer.slice(value.start - value.headerLength, value.end),\n\t\t);\n\t\tentries.push({\n\t\t\toid: attrOid,\n\t\t\tvaluesHex: rawValues.map((value) => toHex(value)),\n\t\t});\n\t\tif (attrOid === OIDS.friendlyName) {\n\t\t\tconst firstValue = rawValues[0];\n\t\t\tif (friendlyName !== undefined || rawValues.length !== 1 || firstValue === undefined) {\n\t\t\t\tthrow new Error('Malformed friendlyName attribute');\n\t\t\t}\n\t\t\tfriendlyName = decodeBmpString(firstValue);\n\t\t\tcontinue;\n\t\t}\n\t\tif (attrOid === OIDS.localKeyId) {\n\t\t\tconst firstValue = rawValues[0];\n\t\t\tif (localKeyId !== undefined || rawValues.length !== 1 || firstValue === undefined) {\n\t\t\t\tthrow new Error('Malformed localKeyId attribute');\n\t\t\t}\n\t\t\tlocalKeyId = decodeLocalKeyId(firstValue);\n\t\t}\n\t}\n\treturn {\n\t\tentries,\n\t\t...(friendlyName === undefined ? {} : { friendlyName }),\n\t\t...(localKeyId === undefined ? {} : { localKeyId }),\n\t};\n}\n\nfunction decodeLocalKeyId(der: Uint8Array): string {\n\tconst element = readElement(der);\n\tif (element.tag !== 0x04) {\n\t\tthrow new Error('localKeyId must use OCTET STRING');\n\t}\n\treturn toHex(element.value);\n}\n\nfunction isMalformedPfxEncryptedContentError(error: unknown): boolean {\n\tif (!(error instanceof Error)) {\n\t\treturn false;\n\t}\n\treturn (\n\t\terror.message.startsWith('Malformed ') ||\n\t\terror.message.startsWith('Unsupported ') ||\n\t\terror.message.startsWith('Invalid PBES2 ') ||\n\t\terror.message === 'Only passwordless data ContentInfo is supported'\n\t);\n}\n\n/** Exports a `CryptoKey` to PKCS#8 DER, or passes raw bytes through. */\nasync function normalizePrivateKey(source: PfxPrivateKeySource): Promise<Uint8Array> {\n\tif (source instanceof CryptoKey) {\n\t\treturn exportPkcs8Der(source);\n\t}\n\treturn new Uint8Array(source);\n}\n\n/** Extracts DER bytes from a PEM string, or passes raw DER through. */\nfunction normalizeCertificate(source: PfxCertificateSource): Uint8Array {\n\tif (typeof source === 'string') {\n\t\tconst block = splitPemBlocks(source).find((candidate) => candidate.label === 'CERTIFICATE');\n\t\tif (block === undefined) {\n\t\t\tthrow new Error('Certificate PEM required');\n\t\t}\n\t\treturn new Uint8Array(block.bytes);\n\t}\n\treturn new Uint8Array(source);\n}\n\n/** Decrypts a PKCS#7 EncryptedData structure using PBES2 with the given password. */\nasync function decryptEncryptedData(\n\tencryptedDataDer: Uint8Array,\n\tpassword: string,\n): Promise<Uint8Array> {\n\tconst topLevel = readSequenceChildren(encryptedDataDer);\n\tconst encryptedContentInfo = topLevel[1];\n\tif (topLevel.length !== 2 || encryptedContentInfo === undefined) {\n\t\tthrow new Error('Malformed EncryptedData');\n\t}\n\tconst version = topLevel[0];\n\tif (version === undefined || version.tag !== 0x02 || decodeIntegerNumber(version.value) !== 0) {\n\t\tthrow new Error('Malformed EncryptedData');\n\t}\n\tconst contentInfoDer = encryptedDataDer.slice(\n\t\tencryptedContentInfo.start - encryptedContentInfo.headerLength,\n\t\tencryptedContentInfo.end,\n\t);\n\tconst contentInfoChildren = readSequenceChildren(contentInfoDer);\n\tconst algorithm = contentInfoChildren[1];\n\tconst encryptedContent = contentInfoChildren[2];\n\tif (\n\t\talgorithm === undefined ||\n\t\tencryptedContent === undefined ||\n\t\tcontentInfoChildren.length !== 3 ||\n\t\tcontentInfoChildren[0]?.tag !== 0x06\n\t) {\n\t\tthrow new Error('Malformed EncryptedContentInfo');\n\t}\n\tif (encryptedContent.tag !== 0x80) {\n\t\tthrow new Error('Malformed encrypted content');\n\t}\n\treturn decryptPbes2(\n\t\tcontentInfoDer.slice(algorithm.start - algorithm.headerLength, algorithm.end),\n\t\tencryptedContent.value,\n\t\tpassword,\n\t);\n}\n\n/** Reads the first child of a context-tagged element, expecting an OCTET STRING. */\nfunction extractContextOctetString(source: Uint8Array, element: DerElement): Uint8Array {\n\tconst child = extractContextChild(source, element);\n\tif (child.tag !== 0x04) {\n\t\tthrow new Error('Expected OCTET STRING in context value');\n\t}\n\treturn child.value;\n}\n\n/** Reads the first child element inside a context-specific constructed wrapper. */\nfunction extractContextChild(source: Uint8Array, element: DerElement): DerElement {\n\tif ((element.tag & 0xe0) !== 0xa0) {\n\t\tthrow new Error('Expected context-specific constructed value');\n\t}\n\tconst children = childrenOf(source, element);\n\tconst child = children[0];\n\tif (children.length !== 1 || child === undefined) {\n\t\tthrow new Error('Expected context-specific wrapper with exactly one value');\n\t}\n\treturn child;\n}\n\n/** Encodes a JS string as an ASN.1 BMPString (UCS-2 big-endian, tag 0x1e). */\nfunction bmpString(value: string): Uint8Array {\n\tconst bytes = new Uint8Array(value.length * 2);\n\tfor (let index = 0; index < value.length; index += 1) {\n\t\tconst codePoint = value.charCodeAt(index);\n\t\tbytes[index * 2] = codePoint >> 8;\n\t\tbytes[index * 2 + 1] = codePoint & 0xff;\n\t}\n\treturn tlv(0x1e, bytes);\n}\n\n/** Decodes a DER-encoded BMPString (tag 0x1e) back to a JS string. */\nfunction decodeBmpString(der: Uint8Array): string {\n\tconst element = readElement(der);\n\tif (element.tag !== 0x1e) {\n\t\tthrow new Error('Expected BMPString');\n\t}\n\tif (element.value.length % 2 !== 0) {\n\t\tthrow new Error('BMPString must use an even number of bytes');\n\t}\n\tlet value = '';\n\tfor (let index = 0; index < element.value.length; index += 2) {\n\t\tconst left = element.value[index] ?? 0;\n\t\tconst right = element.value[index + 1] ?? 0;\n\t\tvalue += String.fromCharCode((left << 8) | right);\n\t}\n\treturn value;\n}\n"],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ //#region src/pkcs/pkcs12-mac.d.ts
2
+ /** Input for {@linkcode createPkcs12MacData}. */
3
+ interface Pkcs12MacOptions {
4
+ /** Password used to derive the HMAC key via the PKCS#12 KDF. */
5
+ readonly password: string;
6
+ /** PKCS#12 KDF iteration count. Default: `2048`. */
7
+ readonly iterations?: number;
8
+ /** Random salt. Default: 16 cryptographically random bytes. */
9
+ readonly salt?: Uint8Array;
10
+ }
11
+ /** Decoded PKCS#12 MacData block returned by {@linkcode parsePkcs12MacData}. */
12
+ interface ParsedPkcs12MacData {
13
+ /** OID of the digest algorithm (currently always SHA-256). */
14
+ readonly digestAlgorithmOid: string;
15
+ /** Human-readable digest algorithm name (currently `"SHA-256"`). */
16
+ readonly digestAlgorithmName: string;
17
+ /** Hex-encoded MAC digest value. */
18
+ readonly digestHex: string;
19
+ /** Hex-encoded salt bytes used during key derivation. */
20
+ readonly saltHex: string;
21
+ /** Number of PKCS#12 KDF iterations. */
22
+ readonly iterations: number;
23
+ /** MAC verification outcome. Present only when a password was supplied during parsing. */
24
+ readonly valid?: boolean;
25
+ }
26
+ /**
27
+ * Computes a PKCS#12 HMAC-SHA-256 MAC over the AuthenticatedSafe and returns
28
+ * the DER-encoded MacData block alongside its parsed representation.
29
+ */
30
+ declare function createPkcs12MacData(authenticatedSafe: Uint8Array, options: Pkcs12MacOptions): Promise<{
31
+ /** DER-encoded MacData SEQUENCE. */readonly der: Uint8Array; /** Structured representation of the MAC parameters and digest. */
32
+ readonly parsed: ParsedPkcs12MacData;
33
+ }>;
34
+ /**
35
+ * Decodes a DER-encoded MacData block. When `password` is provided, verifies
36
+ * the MAC and sets the `valid` flag on the returned structure.
37
+ */
38
+ declare function parsePkcs12MacData(der: Uint8Array, authenticatedSafe: Uint8Array, password?: string): Promise<ParsedPkcs12MacData>;
39
+ //#endregion
40
+ export { ParsedPkcs12MacData, Pkcs12MacOptions, createPkcs12MacData, parsePkcs12MacData };
41
+ //# sourceMappingURL=pkcs12-mac.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{concatBytes as e,integerFromNumber as t,nullValue as n,objectIdentifier as r,octetString as i,readSequenceChildren as a,sequence as o}from"../internal/asn1/der.js";import{decodeNonNegativeIntegerNumber as s,decodeObjectIdentifier as c,toArrayBuffer as l,toHex as u}from"../internal/asn1/asn1.js";import{OIDS as d}from"../internal/asn1/oids.js";import{getCrypto as f}from"../internal/crypto/webcrypto.js";import{describeHashAlgorithm as p}from"../internal/crypto/algorithm-names.js";async function m(e,a){let s=a.iterations??2048;g(s);let c=a.salt??f().getRandomValues(new Uint8Array(16)),l=await _(e,a.password,c,s);return{der:o([o([o([r(d.sha256),n()]),i(l)]),i(c),t(s)]),parsed:{digestAlgorithmOid:d.sha256,digestAlgorithmName:p(d.sha256),digestHex:u(l),saltHex:u(c),iterations:s}}}async function h(e,t,n){let r=a(e),i=r[0],o=r[1],l=r[2];if(r.length!==3||i===void 0||o===void 0||l===void 0||o.tag!==4)throw Error(`Malformed MacData`);let f=e.slice(i.start-i.headerLength,i.end),m=a(f),h=m[0],v=m[1];if(m.length!==2||h===void 0||v===void 0||v.tag!==4)throw Error(`Malformed DigestInfo`);let y=a(f.slice(h.start-h.headerLength,h.end)),b=y[0];if(b===void 0||y.length!==1&&y.length!==2)throw Error(`MacData algorithm missing`);let x=c(b.value);if(x!==d.sha256)throw Error(`Only SHA-256 PKCS#12 MAC is supported`);let S=s(l.value,`MacData iterations`);g(S);let C={digestAlgorithmOid:x,digestAlgorithmName:p(x),digestHex:u(v.value),saltHex:u(o.value),iterations:S};if(n===void 0)return C;let T=await _(t,n,o.value,C.iterations);return{...C,valid:w(T,v.value)}}function g(e){if(!Number.isSafeInteger(e)||e<=0)throw Error(`MacData iterations must be a positive safe integer`)}async function _(e,t,n,r){let i=await v(t,n,r,3,32),a=await f().subtle.importKey(`raw`,l(i),{name:`HMAC`,hash:`SHA-256`},!1,[`sign`]);return new Uint8Array(await f().subtle.sign(`HMAC`,a,l(e)))}async function v(t,n,r,i,a){let o=new Uint8Array(64).fill(i),s=b(t),c=e([x(n,64),x(s,64)]),l=Math.ceil(a/32),u=new Uint8Array(l*32);for(let t=0;t<l;t+=1){let n=await y(e([o,c]));for(let e=1;e<r;e+=1)n=await y(n);if(u.set(n,t*32),c.length===0)continue;let i=S(n,64),a=new Uint8Array(c.length);for(let e=0;e<c.length/64;e+=1){let t=c.slice(e*64,e*64+64);C(t,i),a.set(t,e*64)}c=a}return u.slice(0,a)}async function y(e){return new Uint8Array(await f().subtle.digest(`SHA-256`,l(e)))}function b(e){let t=new Uint8Array((e.length+1)*2);for(let n=0;n<e.length;n+=1){let r=e.charCodeAt(n);t[n*2]=r>>8,t[n*2+1]=r&255}return t}function x(e,t){return e.length===0?new Uint8Array:S(e,t*Math.ceil(e.length/t))}function S(e,t){let n=new Uint8Array(t);for(let r=0;r<t;r+=1)n[r]=e[r%e.length]??0;return n}function C(e,t){let n=1;for(let r=e.length-1;r>=0;--r){let i=(e[r]??0)+(t[r]??0)+n;e[r]=i&255,n=i>>8}}function w(e,t){if(e.length!==t.length)return!1;let n=0;for(let r=0;r<e.length;r+=1)n|=(e[r]??0)^(t[r]??0);return n===0}export{m as createPkcs12MacData,h as parsePkcs12MacData};
2
+ //# sourceMappingURL=pkcs12-mac.js.map