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 @@
1
+ {"version":3,"file":"pkcs12-mac.js","names":[],"sources":["../../src/pkcs/pkcs12-mac.ts"],"sourcesContent":["/**\n * PKCS#12 MAC data creation and verification.\n *\n * Computes and verifies the password-based HMAC-SHA-256 integrity check\n * defined in PKCS#12 (RFC 7292), using the PKCS#12 key-derivation scheme.\n *\n * @module\n */\n\nimport {\n\tdecodeNonNegativeIntegerNumber,\n\tdecodeObjectIdentifier,\n\ttoArrayBuffer,\n\ttoHex,\n} from '#micro509/internal/asn1/asn1.ts';\nimport {\n\tconcatBytes,\n\tintegerFromNumber,\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 { describeHashAlgorithm } from '#micro509/internal/crypto/algorithm-names.ts';\nimport { getCrypto } from '#micro509/internal/crypto/webcrypto.ts';\n\n/** Input for {@linkcode createPkcs12MacData}. */\nexport interface Pkcs12MacOptions {\n\t/** Password used to derive the HMAC key via the PKCS#12 KDF. */\n\treadonly password: string;\n\t/** PKCS#12 KDF iteration count. Default: `2048`. */\n\treadonly iterations?: number;\n\t/** Random salt. Default: 16 cryptographically random bytes. */\n\treadonly salt?: Uint8Array;\n}\n\n/** Decoded PKCS#12 MacData block returned by {@linkcode parsePkcs12MacData}. */\nexport interface ParsedPkcs12MacData {\n\t/** OID of the digest algorithm (currently always SHA-256). */\n\treadonly digestAlgorithmOid: string;\n\t/** Human-readable digest algorithm name (currently `\"SHA-256\"`). */\n\treadonly digestAlgorithmName: string;\n\t/** Hex-encoded MAC digest value. */\n\treadonly digestHex: string;\n\t/** Hex-encoded salt bytes used during key derivation. */\n\treadonly saltHex: string;\n\t/** Number of PKCS#12 KDF iterations. */\n\treadonly iterations: number;\n\t/** MAC verification outcome. Present only when a password was supplied during parsing. */\n\treadonly valid?: boolean;\n}\n\n/**\n * Computes a PKCS#12 HMAC-SHA-256 MAC over the AuthenticatedSafe and returns\n * the DER-encoded MacData block alongside its parsed representation.\n */\nexport async function createPkcs12MacData(\n\tauthenticatedSafe: Uint8Array,\n\toptions: Pkcs12MacOptions,\n): Promise<{\n\t/** DER-encoded MacData SEQUENCE. */\n\treadonly der: Uint8Array;\n\t/** Structured representation of the MAC parameters and digest. */\n\treadonly parsed: ParsedPkcs12MacData;\n}> {\n\tconst iterations = options.iterations ?? 2048;\n\tassertPkcs12MacIterations(iterations);\n\tconst salt = options.salt ?? getCrypto().getRandomValues(new Uint8Array(16));\n\tconst mac = await computePkcs12Mac(authenticatedSafe, options.password, salt, iterations);\n\tconst der = sequence([\n\t\tsequence([sequence([objectIdentifier(OIDS.sha256), nullValue()]), octetString(mac)]),\n\t\toctetString(salt),\n\t\tintegerFromNumber(iterations),\n\t]);\n\treturn {\n\t\tder,\n\t\tparsed: {\n\t\t\tdigestAlgorithmOid: OIDS.sha256,\n\t\t\tdigestAlgorithmName: describeHashAlgorithm(OIDS.sha256),\n\t\t\tdigestHex: toHex(mac),\n\t\t\tsaltHex: toHex(salt),\n\t\t\titerations,\n\t\t},\n\t};\n}\n\n/**\n * Decodes a DER-encoded MacData block. When `password` is provided, verifies\n * the MAC and sets the `valid` flag on the returned structure.\n */\nexport async function parsePkcs12MacData(\n\tder: Uint8Array,\n\tauthenticatedSafe: Uint8Array,\n\tpassword?: string,\n): Promise<ParsedPkcs12MacData> {\n\tconst top = readSequenceChildren(der);\n\tconst digestInfo = top[0];\n\tconst salt = top[1];\n\tconst iterations = top[2];\n\tif (\n\t\ttop.length !== 3 ||\n\t\tdigestInfo === undefined ||\n\t\tsalt === undefined ||\n\t\titerations === undefined ||\n\t\tsalt.tag !== 0x04\n\t) {\n\t\tthrow new Error('Malformed MacData');\n\t}\n\tconst digestInfoDer = der.slice(digestInfo.start - digestInfo.headerLength, digestInfo.end);\n\tconst digestInfoChildren = readSequenceChildren(digestInfoDer);\n\tconst algorithm = digestInfoChildren[0];\n\tconst digest = digestInfoChildren[1];\n\tif (\n\t\tdigestInfoChildren.length !== 2 ||\n\t\talgorithm === undefined ||\n\t\tdigest === undefined ||\n\t\tdigest.tag !== 0x04\n\t) {\n\t\tthrow new Error('Malformed DigestInfo');\n\t}\n\tconst algorithmDer = digestInfoDer.slice(algorithm.start - algorithm.headerLength, algorithm.end);\n\tconst algorithmChildren = readSequenceChildren(algorithmDer);\n\tconst algorithmOid = algorithmChildren[0];\n\tif (\n\t\talgorithmOid === undefined ||\n\t\t(algorithmChildren.length !== 1 && algorithmChildren.length !== 2)\n\t) {\n\t\tthrow new Error('MacData algorithm missing');\n\t}\n\tconst digestAlgorithmOid = decodeObjectIdentifier(algorithmOid.value);\n\tif (digestAlgorithmOid !== OIDS.sha256) {\n\t\tthrow new Error('Only SHA-256 PKCS#12 MAC is supported');\n\t}\n\tconst parsedIterations = decodeNonNegativeIntegerNumber(iterations.value, 'MacData iterations');\n\tassertPkcs12MacIterations(parsedIterations);\n\tconst parsed: ParsedPkcs12MacData = {\n\t\tdigestAlgorithmOid,\n\t\tdigestAlgorithmName: describeHashAlgorithm(digestAlgorithmOid),\n\t\tdigestHex: toHex(digest.value),\n\t\tsaltHex: toHex(salt.value),\n\t\titerations: parsedIterations,\n\t};\n\tif (password === undefined) {\n\t\treturn parsed;\n\t}\n\tconst expected = await computePkcs12Mac(\n\t\tauthenticatedSafe,\n\t\tpassword,\n\t\tsalt.value,\n\t\tparsed.iterations,\n\t);\n\treturn { ...parsed, valid: equalBytes(expected, digest.value) };\n}\n\nfunction assertPkcs12MacIterations(iterations: number): void {\n\tif (!Number.isSafeInteger(iterations) || iterations <= 0) {\n\t\tthrow new Error('MacData iterations must be a positive safe integer');\n\t}\n}\n\n/** Derives an HMAC-SHA-256 key via the PKCS#12 KDF and signs the AuthenticatedSafe. */\nasync function computePkcs12Mac(\n\tauthenticatedSafe: Uint8Array,\n\tpassword: string,\n\tsalt: Uint8Array,\n\titerations: number,\n): Promise<Uint8Array> {\n\tconst keyBytes = await derivePkcs12Key(password, salt, iterations, 3, 32);\n\tconst key = await getCrypto().subtle.importKey(\n\t\t'raw',\n\t\ttoArrayBuffer(keyBytes),\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign'],\n\t);\n\treturn new Uint8Array(\n\t\tawait getCrypto().subtle.sign('HMAC', key, toArrayBuffer(authenticatedSafe)),\n\t);\n}\n\n/** PKCS#12 key derivation (RFC 7292 Appendix B). `id` selects the purpose (3 = MAC key). */\nasync function derivePkcs12Key(\n\tpassword: string,\n\tsalt: Uint8Array,\n\titerations: number,\n\tid: number,\n\tlength: number,\n): Promise<Uint8Array> {\n\tconst u = 32;\n\tconst v = 64;\n\tconst D = new Uint8Array(v).fill(id);\n\tconst passwordBytes = encodePkcs12Password(password);\n\tconst S = repeatToMultiple(salt, v);\n\tconst P = repeatToMultiple(passwordBytes, v);\n\tlet I = concatBytes([S, P]);\n\tconst blocks = Math.ceil(length / u);\n\tconst output = new Uint8Array(blocks * u);\n\tfor (let index = 0; index < blocks; index += 1) {\n\t\tlet A = await digestSha256(concatBytes([D, I]));\n\t\tfor (let round = 1; round < iterations; round += 1) {\n\t\t\tA = await digestSha256(A);\n\t\t}\n\t\toutput.set(A, index * u);\n\t\tif (I.length === 0) {\n\t\t\tcontinue;\n\t\t}\n\t\tconst B = repeatToLength(A, v);\n\t\tconst next = new Uint8Array(I.length);\n\t\tfor (let blockIndex = 0; blockIndex < I.length / v; blockIndex += 1) {\n\t\t\tconst block = I.slice(blockIndex * v, blockIndex * v + v);\n\t\t\taddBlockInPlace(block, B);\n\t\t\tnext.set(block, blockIndex * v);\n\t\t}\n\t\tI = next;\n\t}\n\treturn output.slice(0, length);\n}\n\n/** SHA-256 hash via WebCrypto. */\nasync function digestSha256(bytes: Uint8Array): Promise<Uint8Array> {\n\treturn new Uint8Array(await getCrypto().subtle.digest('SHA-256', toArrayBuffer(bytes)));\n}\n\n/** Encodes a password as a null-terminated UCS-2 big-endian byte array (RFC 7292 B.1). */\nfunction encodePkcs12Password(password: string): Uint8Array {\n\tconst out = new Uint8Array((password.length + 1) * 2);\n\tfor (let index = 0; index < password.length; index += 1) {\n\t\tconst code = password.charCodeAt(index);\n\t\tout[index * 2] = code >> 8;\n\t\tout[index * 2 + 1] = code & 0xff;\n\t}\n\treturn out;\n}\n\n/** Repeats `bytes` to the nearest multiple of `size`. */\nfunction repeatToMultiple(bytes: Uint8Array, size: number): Uint8Array {\n\tif (bytes.length === 0) {\n\t\treturn new Uint8Array();\n\t}\n\treturn repeatToLength(bytes, size * Math.ceil(bytes.length / size));\n}\n\n/** Cyclically repeats `bytes` to fill exactly `length` bytes. */\nfunction repeatToLength(bytes: Uint8Array, length: number): Uint8Array {\n\tconst out = new Uint8Array(length);\n\tfor (let index = 0; index < length; index += 1) {\n\t\tout[index] = bytes[index % bytes.length] ?? 0;\n\t}\n\treturn out;\n}\n\n/** Big-endian add-with-carry of `addend` into `block`, modifying `block` in place. */\nfunction addBlockInPlace(block: Uint8Array, addend: Uint8Array): void {\n\tlet carry = 1;\n\tfor (let index = block.length - 1; index >= 0; index -= 1) {\n\t\tconst sum = (block[index] ?? 0) + (addend[index] ?? 0) + carry;\n\t\tblock[index] = sum & 0xff;\n\t\tcarry = sum >> 8;\n\t}\n}\n\n/** Constant-time byte comparison to avoid timing side-channels in MAC checks. */\nfunction equalBytes(left: Uint8Array, right: Uint8Array): boolean {\n\tif (left.length !== right.length) {\n\t\treturn false;\n\t}\n\tlet result = 0;\n\tfor (let index = 0; index < left.length; index += 1) {\n\t\tresult |= (left[index] ?? 0) ^ (right[index] ?? 0);\n\t}\n\treturn result === 0;\n}\n"],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ import { ErrorResult, Micro509Error } from "../result/result.js";
2
+ import { ParsedCertificate, ParsedName } from "../x509/parse.js";
3
+
4
+ //#region src/pkcs/pkcs7.d.ts
5
+ /** PEM text (may contain multiple CERTIFICATE blocks) or raw DER bytes. */
6
+ type Pkcs7CertificateSource = string | Uint8Array;
7
+ /** DER, PEM, and base64 encodings of a PKCS#7 certificate bag. */
8
+ interface Pkcs7CertBag {
9
+ /** Raw DER-encoded PKCS#7 structure. */
10
+ readonly der: Uint8Array;
11
+ /** PEM-armored PKCS#7 (`-----BEGIN PKCS7-----`). */
12
+ readonly pem: string;
13
+ /** Base64-encoded DER (no PEM armor). */
14
+ readonly base64: string;
15
+ }
16
+ /** A single SignerInfo decoded from a PKCS#7 SignedData structure. */
17
+ interface ParsedPkcs7SignerInfo {
18
+ /** CMS SignerInfo version (typically 1 for issuerAndSerialNumber). */
19
+ readonly version: number;
20
+ /** Parsed issuer distinguished name, if present (issuerAndSerialNumber signer identifier). */
21
+ readonly issuer?: ParsedName;
22
+ /** Hex-encoded serial number used to locate the signer certificate, if present. */
23
+ readonly serialNumberHex?: string;
24
+ /** Hex-encoded SubjectKeyIdentifier used to locate the signer certificate, if present. */
25
+ readonly subjectKeyIdentifier?: string;
26
+ /** OID of the digest algorithm used to hash the content. */
27
+ readonly digestAlgorithmOid: string;
28
+ /** Human-readable digest algorithm name (e.g. `"SHA-256"`). */
29
+ readonly digestAlgorithmName: string;
30
+ /** OID of the algorithm used to produce the signature. */
31
+ readonly signatureAlgorithmOid: string;
32
+ /** Human-readable signature algorithm name. */
33
+ readonly signatureAlgorithmName: string;
34
+ /** Raw DER of the signature AlgorithmIdentifier parameters, if present. */
35
+ readonly signatureAlgorithmParametersDer?: Uint8Array;
36
+ /** Hex-encoded raw signature bytes. */
37
+ readonly signatureHex: string;
38
+ /** Raw signature bytes. */
39
+ readonly signature: Uint8Array;
40
+ /** Whether this SignerInfo includes authenticated (signed) attributes. */
41
+ readonly hasSignedAttrs: boolean;
42
+ /** Raw DER of signedAttrs with original IMPLICIT [0] tag (0xa0). Present only when `hasSignedAttrs` is true. */
43
+ readonly signedAttrsDer?: Uint8Array;
44
+ }
45
+ /** Decoded PKCS#7 SignedData content, including certificates and signer info. */
46
+ interface ParsedPkcs7SignedData {
47
+ /** Original DER bytes when this object came from {@linkcode parsePkcs7SignedDataDer} or PEM parsing. */
48
+ readonly der?: Uint8Array;
49
+ /** Outer ContentInfo type OID (always `pkcs7-signedData`). */
50
+ readonly contentTypeOid: string;
51
+ /** SignedData version number. */
52
+ readonly version: number;
53
+ /** OIDs of digest algorithms declared in `digestAlgorithms`. */
54
+ readonly digestAlgorithmOids: readonly string[];
55
+ /** Human-readable digest algorithm names declared in `digestAlgorithms`. */
56
+ readonly digestAlgorithmNames: readonly string[];
57
+ /** OID of the encapsulated content type (e.g. `pkcs7-data`). */
58
+ readonly encapsulatedContentTypeOid: string;
59
+ /** Raw encapsulated content bytes. Absent in degenerate (certs-only) bags. */
60
+ readonly encapsulatedContent?: Uint8Array;
61
+ /** Certificates included in the SignedData certificate set. */
62
+ readonly certificates: readonly ParsedCertificate[];
63
+ /** Decoded signer info entries. Empty for degenerate cert bags. */
64
+ readonly signerInfos: readonly ParsedPkcs7SignerInfo[];
65
+ }
66
+ /** Error codes for PKCS#7 parse failures. */
67
+ type ParsePkcs7ErrorCode = "malformed" | "not_signed_data";
68
+ /** Error payload for a failed PKCS#7 parse. */
69
+ interface ParsePkcs7Failure extends Micro509Error<ParsePkcs7ErrorCode> {
70
+ /** Always `false` for failures. */
71
+ readonly ok: false;
72
+ }
73
+ /** Success-or-failure result from {@linkcode parsePkcs7SignedDataDer} / {@linkcode parsePkcs7SignedDataPem}. */
74
+ type ParsePkcs7SignedDataResult = {
75
+ /** Parse succeeded. */readonly ok: true; /** Decoded SignedData. */
76
+ readonly value: ParsedPkcs7SignedData;
77
+ } | ErrorResult<ParsePkcs7ErrorCode, Record<never, never>, ParsePkcs7Failure>;
78
+ /** Success-or-failure result from {@linkcode parsePkcs7CertBagDer} / {@linkcode parsePkcs7CertBagPem}. */
79
+ type ParsePkcs7CertBagResult = {
80
+ /** Parse succeeded. */readonly ok: true; /** Parsed certificates from the cert bag. */
81
+ readonly value: readonly ParsedCertificate[];
82
+ } | ErrorResult<ParsePkcs7ErrorCode, Record<never, never>, ParsePkcs7Failure>;
83
+ /** Error payload for a failed {@linkcode verifyPkcs7SignedData} call. */
84
+ interface VerifyPkcs7SignedDataFailure extends Micro509Error<"signer_not_found" | "signature_invalid" | "message_digest_mismatch" | "content_missing" | ParsePkcs7ErrorCode> {
85
+ /** Always `false` for failures. */
86
+ readonly ok: false;
87
+ }
88
+ /** Success-or-failure result from {@linkcode verifyPkcs7SignedData}. */
89
+ type VerifyPkcs7SignedDataResult = {
90
+ /** Verification succeeded. */readonly ok: true; /** The verified SignedData structure. */
91
+ readonly value: ParsedPkcs7SignedData;
92
+ } | ErrorResult<"signer_not_found" | "signature_invalid" | "message_digest_mismatch" | "content_missing" | ParsePkcs7ErrorCode, Record<never, never>, VerifyPkcs7SignedDataFailure>;
93
+ /**
94
+ * Creates a degenerate PKCS#7 SignedData structure containing only certificates (no signers).
95
+ *
96
+ * Returns the raw DER encoding. Use {@linkcode createPkcs7CertBagPem} for PEM + base64.
97
+ */
98
+ declare function createPkcs7CertBagDer(certificates: readonly Pkcs7CertificateSource[]): Uint8Array;
99
+ /**
100
+ * Creates a degenerate PKCS#7 SignedData certificate bag and returns DER, PEM, and base64 forms.
101
+ */
102
+ declare function createPkcs7CertBagPem(certificates: readonly Pkcs7CertificateSource[]): Pkcs7CertBag;
103
+ /** Parses a DER-encoded PKCS#7 cert bag, returning the contained certificates. */
104
+ declare function parsePkcs7CertBagDer(der: Uint8Array): ParsePkcs7CertBagResult;
105
+ /** Parses a PEM-armored PKCS#7 cert bag. Expects exactly one `PKCS7` PEM block. */
106
+ declare function parsePkcs7CertBagPem(pem: string): ParsePkcs7CertBagResult;
107
+ /** Decodes a DER-encoded PKCS#7 ContentInfo expecting `signedData` content type. */
108
+ declare function parsePkcs7SignedDataDer(der: Uint8Array): ParsePkcs7SignedDataResult;
109
+ /** Decodes a PEM-armored PKCS#7 SignedData. Expects exactly one `PKCS7` PEM block. */
110
+ declare function parsePkcs7SignedDataPem(pem: string): ParsePkcs7SignedDataResult;
111
+ /**
112
+ * Verifies all signer signatures in a PKCS#7 SignedData structure.
113
+ *
114
+ * Accepts PEM text, raw DER, or an already-parsed {@linkcode ParsedPkcs7SignedData}.
115
+ * For each signer, locates the matching certificate in the embedded set and
116
+ * verifies the signature (including signed-attribute digest checks per RFC 5652 Section 5.4).
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * import { verifyPkcs7SignedData } from 'micro509';
121
+ *
122
+ * const result = await verifyPkcs7SignedData(pkcs7Pem);
123
+ * if (result.ok) {
124
+ * console.log('all signers verified');
125
+ * }
126
+ * ```
127
+ */
128
+ declare function verifyPkcs7SignedData(input: string | Uint8Array | ParsedPkcs7SignedData): Promise<VerifyPkcs7SignedDataResult>;
129
+ //#endregion
130
+ export { ParsePkcs7CertBagResult, ParsePkcs7ErrorCode, ParsePkcs7Failure, ParsePkcs7SignedDataResult, ParsedPkcs7SignedData, ParsedPkcs7SignerInfo, Pkcs7CertBag, Pkcs7CertificateSource, VerifyPkcs7SignedDataFailure, VerifyPkcs7SignedDataResult, createPkcs7CertBagDer, createPkcs7CertBagPem, parsePkcs7CertBagDer, parsePkcs7CertBagPem, parsePkcs7SignedDataDer, parsePkcs7SignedDataPem, verifyPkcs7SignedData };
131
+ //# sourceMappingURL=pkcs7.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{concatBytes as e,explicitContext as t,integerFromNumber as n,objectIdentifier as r,readElement as i,readRootElement as a,readSequenceChildren as o,sequence as s,setOf as c}from"../internal/asn1/der.js";import{childrenOf as l,decodeIntegerNumber as u,decodeObjectIdentifier as d,decodeString as f,requireElement as p,toArrayBuffer as m,toHex as h}from"../internal/asn1/asn1.js";import{OIDS as g}from"../internal/asn1/oids.js";import{getCrypto as _}from"../internal/crypto/webcrypto.js";import{base64Encode as v}from"../internal/shared/base64.js";import{pemEncode as y,splitPemBlocks as b}from"../pem/pem.js";import{describeHashAlgorithm as x,describeSignatureAlgorithm as S}from"../internal/crypto/algorithm-names.js";import{nameFieldKeyFromOid as C}from"../internal/x509/name-fields.js";import{parseCertificateDer as w}from"../x509/parse.js";import{verifySignedDataDetailed as T}from"../internal/crypto/sig-verify.js";import{compareDistinguishedNames as E}from"../internal/shared/dn.js";function D(i){let a=i.flatMap(I),o=s([n(1),c([]),s([r(g.pkcs7Data)]),t(0,e(a)),c([])]);return s([r(g.pkcs7SignedData),t(0,o)])}function O(e){let t=D(e);return{der:t,pem:y(`PKCS7`,t),base64:v(t)}}function k(e){let t=j(e);return t.ok?{ok:!0,value:t.value.certificates}:t}function A(e){try{let t=b(e).filter(e=>e.label===`PKCS7`);if(t.length!==1)return P(`malformed`,`Expected exactly one PKCS7 PEM block`);let n=t[0];return n===void 0?P(`malformed`,`Missing PKCS7 block`):k(n.bytes)}catch{return P(`malformed`,`Expected exactly one PKCS7 PEM block`)}}function j(e){try{let t=o(e,{maxDepth:64}),n=t[0],r=t[1];if(n===void 0||r===void 0||t.length!==2||n.tag!==6||r.tag!==160||l(e,r).length!==1)return P(`malformed`,`Malformed PKCS#7 content info`);let i=d(n.value);if(i!==g.pkcs7SignedData)return P(`not_signed_data`,`PKCS#7 content is not signedData`);let a=l(e,W(e,r,0,`signedData`)),s=a[0],c=a[1],f=a[2],p=a.slice(3),m=p[p.length-1],h,_;for(let e of p.slice(0,-1)){if(e?.tag===160){if(_!==void 0)return P(`malformed`,`SignedData certificates field must precede CRLs field`);if(h!==void 0)return P(`malformed`,`SignedData certificates field must not repeat`);h=e;continue}if(e?.tag===161){if(_!==void 0)return P(`malformed`,`SignedData CRLs field must not repeat`);_=e;continue}return P(`malformed`,`Malformed SignedData optional field`)}if(s===void 0||c===void 0||f===void 0||m===void 0||m.tag!==49)return P(`malformed`,`Malformed SignedData`);let v=e.slice(f.start-f.headerLength,f.end),y=o(v),b=y[0],S=y[1],C=R(e,c);return b===void 0?P(`malformed`,`Malformed EncapsulatedContentInfo`):{ok:!0,value:{der:new Uint8Array(e),contentTypeOid:i,version:u(s.value),digestAlgorithmOids:C,digestAlgorithmNames:C.map(e=>x(e)),encapsulatedContentTypeOid:d(b.value),...S===void 0?{}:{encapsulatedContent:B(v,S)},certificates:L(e,h),signerInfos:z(e,m)}}}catch{return P(`malformed`,`Malformed PKCS#7 structure`)}}function M(e){try{let t=b(e).filter(e=>e.label===`PKCS7`),n=t[0];return n===void 0||t.length!==1?P(`malformed`,`Expected exactly one PKCS7 PEM block`):j(n.bytes)}catch{return P(`malformed`,`Expected exactly one PKCS7 PEM block`)}}async function N(e){let t;if(typeof e==`string`){let n=M(e);if(!n.ok)return n;t=n.value}else if(e instanceof Uint8Array){let n=j(e);if(!n.ok)return n;t=n.value}else{if(!Q(e))return F(`malformed`,`SignedData parsed input is malformed`);let n=j(new Uint8Array(e.der));if(!n.ok)return n;t=n.value}if(t.encapsulatedContent===void 0)return F(`content_missing`,`SignedData encapsulated content is missing`);for(let e of t.signerInfos){let n=t.certificates.find(t=>X(t,e));if(n===void 0)return F(`signer_not_found`,`Signer certificate not found in SignedData certificates`);if(e.hasSignedAttrs){let r=await Y(e,n,t.encapsulatedContent,t.encapsulatedContentTypeOid);if(!r.ok)return r;continue}let r;try{let i=await T(e.signatureAlgorithmOid,e.signatureAlgorithmParametersDer,n.publicKeyAlgorithmOid,n.publicKeyParametersOid,n.subjectPublicKeyInfoDer,e.signature,t.encapsulatedContent);if(!i.ok)return i.code===`verification_error`?F(`malformed`,`SignedData signature verification failed`):F(`malformed`,`Unsupported signature algorithm in SignedData`);r=i.valid}catch{return F(`malformed`,`Unsupported signature algorithm in SignedData`)}if(!r)return F(`signature_invalid`,`SignedData signature does not verify`)}return{ok:!0,value:t}}function P(e,t){return{ok:!1,error:{ok:!1,code:e,message:t},code:e,message:t}}function F(e,t){return{ok:!1,error:{ok:!1,code:e,message:t},code:e,message:t}}function I(e){return typeof e==`string`?b(e).filter(e=>e.label===`CERTIFICATE`).map(e=>new Uint8Array(e.bytes)):[new Uint8Array(e)]}function L(e,t){if(t===void 0||t.tag!==160)return[];let n=[],r=t.start;for(;r<t.end;){let t=i(e,r);n.push(w(e.slice(r,t.end))),r=t.end}return n}function R(e,t){let n=[];if(t.tag!==49)throw Error(`digestAlgorithms must use SET`);for(let r of l(e,t)){if(r.tag!==48)throw Error(`digestAlgorithm must use AlgorithmIdentifier SEQUENCE`);let t=o(e.slice(r.start-r.headerLength,r.end)),i=t[0];if(i===void 0||t.length<1||t.length>2||i.tag!==6)throw Error(`Malformed digest AlgorithmIdentifier`);n.push(d(i.value))}return n}function z(e,t){let n=[];for(let r of l(e,t)){let t=e.slice(r.start-r.headerLength,r.end),i=o(t),a=i[0],s=i[1],c=i[2],l=3,f=i[l]?.tag===160?i[l]:void 0,m=f!==void 0;m&&(l+=1);let g=i[l],_=i[l+1],v=i[l+2];if(a===void 0||s===void 0||c===void 0||g===void 0||_===void 0||_.tag!==4||i.length>l+3||v!==void 0&&v.tag!==161)throw Error(`Malformed SignerInfo`);let y=d(p(o(t.slice(c.start-c.headerLength,c.end))[0],`digest algorithm OID`).value),b=t.slice(g.start-g.headerLength,g.end),C=o(b),w=d(p(C[0],`signature algorithm OID`).value),T=C[1],E=V(t.slice(s.start-s.headerLength,s.end));n.push({version:u(a.value),...E.issuer===void 0?{}:{issuer:E.issuer},...E.serialNumberHex===void 0?{}:{serialNumberHex:E.serialNumberHex},...E.subjectKeyIdentifier===void 0?{}:{subjectKeyIdentifier:E.subjectKeyIdentifier},digestAlgorithmOid:y,digestAlgorithmName:x(y),signatureAlgorithmOid:w,signatureAlgorithmName:S(w,T===void 0?void 0:new Uint8Array(b.slice(T.start-T.headerLength,T.end))),...T===void 0?{}:{signatureAlgorithmParametersDer:new Uint8Array(b.slice(T.start-T.headerLength,T.end))},signatureHex:h(_.value),signature:new Uint8Array(_.value),hasSignedAttrs:m,...f===void 0?{}:{signedAttrsDer:new Uint8Array(t.slice(f.start-f.headerLength,f.end))}})}return n}function B(e,t){if(t.tag!==160)throw Error(`Unexpected encapsulated content tag`);let n=i(e,t.start);if(n.tag!==4)throw Error(`Expected encapsulated OCTET STRING`);return n.value}function V(e){let t=a(e,{maxDepth:64});if(t.tag===128){if(t.value.length===0)throw Error(`SignerIdentifier subjectKeyIdentifier must not be empty`);return{subjectKeyIdentifier:h(t.value)}}if(t.tag===48){let t=o(e),n=t[0],r=t[1];if(n===void 0||r===void 0||t.length!==2)throw Error(`SignerIdentifier issuerAndSerialNumber is malformed`);if(n.tag!==48)throw Error(`SignerIdentifier issuer must use Name SEQUENCE`);if(r.tag!==2)throw Error(`SignerIdentifier serialNumber must use INTEGER`);return $(r.value,`SignerIdentifier serialNumber`),{issuer:U(e,n),serialNumberHex:h(r.value)}}throw Error(`Unsupported SignerIdentifier tag: ${String(t.tag)}`)}const H=new TextDecoder;function U(e,t){let n=h(e.slice(t.start-t.headerLength,t.end)),r=[],i=[],a={};for(let n of l(e,t)){let t=[],o={};for(let r of l(e,n)){let n=l(e,r),s=p(n[0],`signer issuer attribute OID`),c=p(n[1],`signer issuer attribute value`),u=d(s.value),m;try{m=f(c.tag,c.value)}catch{m=H.decode(c.value)}let h=C(u),g=h===void 0?{oid:u,valueTag:c.tag,value:m}:{oid:u,key:h,valueTag:c.tag,value:m};t.push(g),i.push(g),h!==void 0&&(o[h]===void 0&&(o[h]=m),a[h]===void 0&&(a[h]=m))}r.push({derHex:h(e.slice(n.start-n.headerLength,n.end)),attributes:t,values:o})}return{derHex:n,rdns:r,attributes:i,values:a}}function W(e,t,n,r){let a=t.start,o=0;for(;a<t.end;){let t=i(e,a);if(o===n)return t;a=t.end,o+=1}throw Error(`Missing ${r}`)}function G(e){switch(e){case g.sha256:return`SHA-256`;case g.sha384:return`SHA-384`;case g.sha512:return`SHA-512`;default:throw Error(`Unsupported digest algorithm OID: ${e}`)}}function K(e){let t=i(e),n,r;for(let i of l(e,t)){let t=e.slice(i.start-i.headerLength,i.end),a=o(t),s=a[0],c=a[1];if(s===void 0||c===void 0||a.length!==2||c.tag!==49)throw Error(`Malformed signedAttrs attribute`);let u=d(s.value),f=l(t,c);if(u===g.cmsMessageDigest){if(n!==void 0||f.length!==1)throw Error(`messageDigest attribute must appear exactly once with one value`);let e=f[0];if(e===void 0||e.tag!==4)throw Error(`messageDigest attribute value must use OCTET STRING`);n=e.value;continue}if(u===g.cmsContentType){if(r!==void 0||f.length!==1)throw Error(`contentType attribute must appear exactly once with one value`);let e=f[0];if(e===void 0||e.tag!==6)throw Error(`contentType attribute value must use OBJECT IDENTIFIER`);r=d(e.value)}}if(n===void 0)throw Error(`Missing messageDigest attribute in signedAttrs`);if(r===void 0)throw Error(`Missing contentType attribute in signedAttrs`);return{messageDigest:n,contentTypeOid:r}}function q(e){let t=new Uint8Array(e);return t[0]=49,t}function J(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}async function Y(e,t,n,r){if(e.signedAttrsDer===void 0)return F(`malformed`,`Missing signedAttrs DER`);let i;try{Z(e.signedAttrsDer),i=K(e.signedAttrsDer)}catch{return F(`malformed`,`Malformed signedAttrs in SignedData`)}if(i.contentTypeOid!==r)return F(`malformed`,`SignedData contentType attribute does not match`);let a;try{let t=G(e.digestAlgorithmOid);a=new Uint8Array(await _().subtle.digest(t,m(n)))}catch{return F(`malformed`,`Unsupported digest algorithm in SignedData`)}if(!J(a,i.messageDigest))return F(`message_digest_mismatch`,`Content digest does not match messageDigest attribute`);let o;try{o=q(e.signedAttrsDer)}catch{return F(`malformed`,`Malformed signedAttrs in SignedData`)}let s;try{let n=await T(e.signatureAlgorithmOid,e.signatureAlgorithmParametersDer,t.publicKeyAlgorithmOid,t.publicKeyParametersOid,t.subjectPublicKeyInfoDer,e.signature,o);if(!n.ok)return n.code===`verification_error`?F(`malformed`,`SignedData signature verification failed`):F(`malformed`,`Unsupported signature algorithm in SignedData`);s=n.valid}catch{return F(`malformed`,`Unsupported signature algorithm in SignedData`)}return s?{ok:!0}:F(`signature_invalid`,`SignedData signature over signedAttrs does not verify`)}function X(e,t){return t.issuer!==void 0||t.serialNumberHex!==void 0?t.issuer!==void 0&&t.serialNumberHex!==void 0&&e.serialNumberHex===t.serialNumberHex&&E(e.issuer,t.issuer):t.subjectKeyIdentifier!==void 0&&e.subjectKeyIdentifier===t.subjectKeyIdentifier}function Z(e){if(i(e).tag!==160)throw Error(`signedAttrs must use IMPLICIT [0] tag`)}function Q(e){return`der`in e&&e.der instanceof Uint8Array}function $(e,t){let n=e[0];if(n===void 0)throw Error(`${t} must not be empty`);if(n&128)throw Error(`${t} must be non-negative`);if(e.length>1&&n===0&&!((e[1]??0)&128))throw Error(`${t} must use minimal encoding`)}export{D as createPkcs7CertBagDer,O as createPkcs7CertBagPem,k as parsePkcs7CertBagDer,A as parsePkcs7CertBagPem,j as parsePkcs7SignedDataDer,M as parsePkcs7SignedDataPem,N as verifyPkcs7SignedData};
2
+ //# sourceMappingURL=pkcs7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pkcs7.js","names":[],"sources":["../../src/pkcs/pkcs7.ts"],"sourcesContent":["/**\n * PKCS#7/CMS certificate bags and SignedData.\n *\n * Creates degenerate (signature-less) certificate bags, parses RFC 2315 / RFC 5652\n * SignedData structures, and verifies signer signatures including signed-attribute flows.\n *\n * @module\n */\n\nimport {\n\tchildrenOf,\n\tdecodeIntegerNumber,\n\tdecodeObjectIdentifier,\n\tdecodeString,\n\trequireElement,\n\ttoArrayBuffer,\n\ttoHex,\n} from '#micro509/internal/asn1/asn1.ts';\nimport type { DerElement } from '#micro509/internal/asn1/der.ts';\nimport {\n\tconcatBytes,\n\tDEFAULT_MAX_DER_DEPTH,\n\texplicitContext,\n\tintegerFromNumber,\n\tobjectIdentifier,\n\treadElement,\n\treadRootElement,\n\treadSequenceChildren,\n\tsequence,\n\tsetOf,\n} from '#micro509/internal/asn1/der.ts';\nimport { OIDS } from '#micro509/internal/asn1/oids.ts';\nimport {\n\tdescribeHashAlgorithm,\n\tdescribeSignatureAlgorithm,\n} from '#micro509/internal/crypto/algorithm-names.ts';\nimport { verifySignedDataDetailed } from '#micro509/internal/crypto/sig-verify.ts';\nimport { getCrypto } from '#micro509/internal/crypto/webcrypto.ts';\nimport { base64Encode } from '#micro509/internal/shared/base64.ts';\nimport { compareDistinguishedNames } from '#micro509/internal/shared/dn.ts';\nimport { pemEncode, splitPemBlocks } from '#micro509/pem/pem.ts';\nimport type { ErrorResult, Micro509Error } from '#micro509/result/result.ts';\nimport { type NameFieldKey, nameFieldKeyFromOid } from '#micro509/x509/name.ts';\nimport type {\n\tParsedCertificate,\n\tParsedName,\n\tParsedNameAttribute,\n\tParsedRelativeDistinguishedName,\n} from '#micro509/x509/parse.ts';\nimport { parseCertificateDer } from '#micro509/x509/parse.ts';\n\n/** PEM text (may contain multiple CERTIFICATE blocks) or raw DER bytes. */\nexport type Pkcs7CertificateSource = string | Uint8Array;\n\n/** DER, PEM, and base64 encodings of a PKCS#7 certificate bag. */\nexport interface Pkcs7CertBag {\n\t/** Raw DER-encoded PKCS#7 structure. */\n\treadonly der: Uint8Array;\n\t/** PEM-armored PKCS#7 (`-----BEGIN PKCS7-----`). */\n\treadonly pem: string;\n\t/** Base64-encoded DER (no PEM armor). */\n\treadonly base64: string;\n}\n\n/** A single SignerInfo decoded from a PKCS#7 SignedData structure. */\nexport interface ParsedPkcs7SignerInfo {\n\t/** CMS SignerInfo version (typically 1 for issuerAndSerialNumber). */\n\treadonly version: number;\n\t/** Parsed issuer distinguished name, if present (issuerAndSerialNumber signer identifier). */\n\treadonly issuer?: ParsedName;\n\t/** Hex-encoded serial number used to locate the signer certificate, if present. */\n\treadonly serialNumberHex?: string;\n\t/** Hex-encoded SubjectKeyIdentifier used to locate the signer certificate, if present. */\n\treadonly subjectKeyIdentifier?: string;\n\t/** OID of the digest algorithm used to hash the content. */\n\treadonly digestAlgorithmOid: string;\n\t/** Human-readable digest algorithm name (e.g. `\"SHA-256\"`). */\n\treadonly digestAlgorithmName: string;\n\t/** OID of the algorithm used to produce the signature. */\n\treadonly signatureAlgorithmOid: string;\n\t/** Human-readable signature algorithm name. */\n\treadonly signatureAlgorithmName: string;\n\t/** Raw DER of the signature AlgorithmIdentifier parameters, if present. */\n\treadonly signatureAlgorithmParametersDer?: Uint8Array;\n\t/** Hex-encoded raw signature bytes. */\n\treadonly signatureHex: string;\n\t/** Raw signature bytes. */\n\treadonly signature: Uint8Array;\n\t/** Whether this SignerInfo includes authenticated (signed) attributes. */\n\treadonly hasSignedAttrs: boolean;\n\t/** Raw DER of signedAttrs with original IMPLICIT [0] tag (0xa0). Present only when `hasSignedAttrs` is true. */\n\treadonly signedAttrsDer?: Uint8Array;\n}\n\n/** Decoded PKCS#7 SignedData content, including certificates and signer info. */\nexport interface ParsedPkcs7SignedData {\n\t/** Original DER bytes when this object came from {@linkcode parsePkcs7SignedDataDer} or PEM parsing. */\n\treadonly der?: Uint8Array;\n\t/** Outer ContentInfo type OID (always `pkcs7-signedData`). */\n\treadonly contentTypeOid: string;\n\t/** SignedData version number. */\n\treadonly version: number;\n\t/** OIDs of digest algorithms declared in `digestAlgorithms`. */\n\treadonly digestAlgorithmOids: readonly string[];\n\t/** Human-readable digest algorithm names declared in `digestAlgorithms`. */\n\treadonly digestAlgorithmNames: readonly string[];\n\t/** OID of the encapsulated content type (e.g. `pkcs7-data`). */\n\treadonly encapsulatedContentTypeOid: string;\n\t/** Raw encapsulated content bytes. Absent in degenerate (certs-only) bags. */\n\treadonly encapsulatedContent?: Uint8Array;\n\t/** Certificates included in the SignedData certificate set. */\n\treadonly certificates: readonly ParsedCertificate[];\n\t/** Decoded signer info entries. Empty for degenerate cert bags. */\n\treadonly signerInfos: readonly ParsedPkcs7SignerInfo[];\n}\n\n// ---------------------------------------------------------------------------\n// Result types for PKCS#7 parsing\n// ---------------------------------------------------------------------------\n\n/** Error codes for PKCS#7 parse failures. */\nexport type ParsePkcs7ErrorCode = 'malformed' | 'not_signed_data';\n\n/** Error payload for a failed PKCS#7 parse. */\nexport interface ParsePkcs7Failure extends Micro509Error<ParsePkcs7ErrorCode> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n}\n\n/** Success-or-failure result from {@linkcode parsePkcs7SignedDataDer} / {@linkcode parsePkcs7SignedDataPem}. */\nexport type ParsePkcs7SignedDataResult =\n\t| {\n\t\t\t/** Parse succeeded. */\n\t\t\treadonly ok: true;\n\t\t\t/** Decoded SignedData. */\n\t\t\treadonly value: ParsedPkcs7SignedData;\n\t }\n\t| ErrorResult<ParsePkcs7ErrorCode, Record<never, never>, ParsePkcs7Failure>;\n\n/** Success-or-failure result from {@linkcode parsePkcs7CertBagDer} / {@linkcode parsePkcs7CertBagPem}. */\nexport type ParsePkcs7CertBagResult =\n\t| {\n\t\t\t/** Parse succeeded. */\n\t\t\treadonly ok: true;\n\t\t\t/** Parsed certificates from the cert bag. */\n\t\t\treadonly value: readonly ParsedCertificate[];\n\t }\n\t| ErrorResult<ParsePkcs7ErrorCode, Record<never, never>, ParsePkcs7Failure>;\n\n/** Error payload for a failed {@linkcode verifyPkcs7SignedData} call. */\nexport interface VerifyPkcs7SignedDataFailure\n\textends Micro509Error<\n\t\t| 'signer_not_found'\n\t\t| 'signature_invalid'\n\t\t| 'message_digest_mismatch'\n\t\t| 'content_missing'\n\t\t| ParsePkcs7ErrorCode\n\t> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n}\n\n/** Success-or-failure result from {@linkcode verifyPkcs7SignedData}. */\nexport type VerifyPkcs7SignedDataResult =\n\t| {\n\t\t\t/** Verification succeeded. */\n\t\t\treadonly ok: true;\n\t\t\t/** The verified SignedData structure. */\n\t\t\treadonly value: ParsedPkcs7SignedData;\n\t }\n\t| ErrorResult<\n\t\t\t| 'signer_not_found'\n\t\t\t| 'signature_invalid'\n\t\t\t| 'message_digest_mismatch'\n\t\t\t| 'content_missing'\n\t\t\t| ParsePkcs7ErrorCode,\n\t\t\tRecord<never, never>,\n\t\t\tVerifyPkcs7SignedDataFailure\n\t >;\n\n// ---------------------------------------------------------------------------\n// createPkcs7CertBag\n// ---------------------------------------------------------------------------\n\n/**\n * Creates a degenerate PKCS#7 SignedData structure containing only certificates (no signers).\n *\n * Returns the raw DER encoding. Use {@linkcode createPkcs7CertBagPem} for PEM + base64.\n */\nexport function createPkcs7CertBagDer(certificates: readonly Pkcs7CertificateSource[]): Uint8Array {\n\tconst certificateDers = certificates.flatMap(normalizeCertificateSource);\n\tconst signedData = sequence([\n\t\tintegerFromNumber(1),\n\t\tsetOf([]),\n\t\tsequence([objectIdentifier(OIDS.pkcs7Data)]),\n\t\texplicitContext(0, concatBytes(certificateDers)),\n\t\tsetOf([]),\n\t]);\n\treturn sequence([objectIdentifier(OIDS.pkcs7SignedData), explicitContext(0, signedData)]);\n}\n\n/**\n * Creates a degenerate PKCS#7 SignedData certificate bag and returns DER, PEM, and base64 forms.\n */\nexport function createPkcs7CertBagPem(\n\tcertificates: readonly Pkcs7CertificateSource[],\n): Pkcs7CertBag {\n\tconst der = createPkcs7CertBagDer(certificates);\n\treturn {\n\t\tder,\n\t\tpem: pemEncode('PKCS7', der),\n\t\tbase64: base64Encode(der),\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// parsePkcs7CertBag — Result-returning\n// ---------------------------------------------------------------------------\n\n/** Parses a DER-encoded PKCS#7 cert bag, returning the contained certificates. */\nexport function parsePkcs7CertBagDer(der: Uint8Array): ParsePkcs7CertBagResult {\n\tconst result = parsePkcs7SignedDataDer(der);\n\tif (!result.ok) {\n\t\treturn result;\n\t}\n\treturn { ok: true, value: result.value.certificates };\n}\n\n/** Parses a PEM-armored PKCS#7 cert bag. Expects exactly one `PKCS7` PEM block. */\nexport function parsePkcs7CertBagPem(pem: string): ParsePkcs7CertBagResult {\n\ttry {\n\t\tconst blocks = splitPemBlocks(pem).filter((block) => block.label === 'PKCS7');\n\t\tif (blocks.length !== 1) {\n\t\t\treturn pkcs7Failure('malformed', 'Expected exactly one PKCS7 PEM block');\n\t\t}\n\t\tconst block = blocks[0];\n\t\tif (block === undefined) {\n\t\t\treturn pkcs7Failure('malformed', 'Missing PKCS7 block');\n\t\t}\n\t\treturn parsePkcs7CertBagDer(block.bytes);\n\t} catch {\n\t\treturn pkcs7Failure('malformed', 'Expected exactly one PKCS7 PEM block');\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// parsePkcs7SignedData — Result-returning\n// ---------------------------------------------------------------------------\n\n/** Decodes a DER-encoded PKCS#7 ContentInfo expecting `signedData` content type. */\nexport function parsePkcs7SignedDataDer(der: Uint8Array): ParsePkcs7SignedDataResult {\n\ttry {\n\t\tconst contentInfo = readSequenceChildren(der, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\t\tconst contentType = contentInfo[0];\n\t\tconst content = contentInfo[1];\n\t\tif (\n\t\t\tcontentType === undefined ||\n\t\t\tcontent === undefined ||\n\t\t\tcontentInfo.length !== 2 ||\n\t\t\tcontentType.tag !== 0x06 ||\n\t\t\tcontent.tag !== 0xa0\n\t\t) {\n\t\t\treturn pkcs7Failure('malformed', 'Malformed PKCS#7 content info');\n\t\t}\n\t\tif (childrenOf(der, content).length !== 1) {\n\t\t\treturn pkcs7Failure('malformed', 'Malformed PKCS#7 content info');\n\t\t}\n\t\tconst contentTypeOid = decodeObjectIdentifier(contentType.value);\n\t\tif (contentTypeOid !== OIDS.pkcs7SignedData) {\n\t\t\treturn pkcs7Failure('not_signed_data', 'PKCS#7 content is not signedData');\n\t\t}\n\t\tconst signedData = childAt(der, content, 0, 'signedData');\n\t\tconst signedDataChildren = childrenOf(der, signedData);\n\t\tconst version = signedDataChildren[0];\n\t\tconst digestAlgorithms = signedDataChildren[1];\n\t\tconst encapContentInfo = signedDataChildren[2];\n\t\tconst trailingChildren = signedDataChildren.slice(3);\n\t\tconst signerInfos = trailingChildren[trailingChildren.length - 1];\n\t\tlet certificates: ReturnType<typeof readElement> | undefined;\n\t\tlet crls: ReturnType<typeof readElement> | undefined;\n\t\tfor (const child of trailingChildren.slice(0, -1)) {\n\t\t\tif (child?.tag === 0xa0) {\n\t\t\t\tif (crls !== undefined) {\n\t\t\t\t\treturn pkcs7Failure('malformed', 'SignedData certificates field must precede CRLs field');\n\t\t\t\t}\n\t\t\t\tif (certificates !== undefined) {\n\t\t\t\t\treturn pkcs7Failure('malformed', 'SignedData certificates field must not repeat');\n\t\t\t\t}\n\t\t\t\tcertificates = child;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (child?.tag === 0xa1) {\n\t\t\t\tif (crls !== undefined) {\n\t\t\t\t\treturn pkcs7Failure('malformed', 'SignedData CRLs field must not repeat');\n\t\t\t\t}\n\t\t\t\tcrls = child;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn pkcs7Failure('malformed', 'Malformed SignedData optional field');\n\t\t}\n\t\tif (\n\t\t\tversion === undefined ||\n\t\t\tdigestAlgorithms === undefined ||\n\t\t\tencapContentInfo === undefined ||\n\t\t\tsignerInfos === undefined ||\n\t\t\tsignerInfos.tag !== 0x31\n\t\t) {\n\t\t\treturn pkcs7Failure('malformed', 'Malformed SignedData');\n\t\t}\n\t\tconst encapDer = der.slice(\n\t\t\tencapContentInfo.start - encapContentInfo.headerLength,\n\t\t\tencapContentInfo.end,\n\t\t);\n\t\tconst encapChildren = readSequenceChildren(encapDer);\n\t\tconst encapType = encapChildren[0];\n\t\tconst encapContent = encapChildren[1];\n\t\tconst digestAlgorithmOids = parseDigestAlgorithms(der, digestAlgorithms);\n\t\tif (encapType === undefined) {\n\t\t\treturn pkcs7Failure('malformed', 'Malformed EncapsulatedContentInfo');\n\t\t}\n\t\treturn {\n\t\t\tok: true,\n\t\t\tvalue: {\n\t\t\t\tder: new Uint8Array(der),\n\t\t\t\tcontentTypeOid,\n\t\t\t\tversion: decodeIntegerNumber(version.value),\n\t\t\t\tdigestAlgorithmOids,\n\t\t\t\tdigestAlgorithmNames: digestAlgorithmOids.map((oid) => describeHashAlgorithm(oid)),\n\t\t\t\tencapsulatedContentTypeOid: decodeObjectIdentifier(encapType.value),\n\t\t\t\t...(encapContent === undefined\n\t\t\t\t\t? {}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tencapsulatedContent: extractEncapsulatedContent(encapDer, encapContent),\n\t\t\t\t\t\t}),\n\t\t\t\tcertificates: parseCertificateSet(der, certificates),\n\t\t\t\tsignerInfos: parseSignerInfos(der, signerInfos),\n\t\t\t},\n\t\t};\n\t} catch {\n\t\treturn pkcs7Failure('malformed', 'Malformed PKCS#7 structure');\n\t}\n}\n\n/** Decodes a PEM-armored PKCS#7 SignedData. Expects exactly one `PKCS7` PEM block. */\nexport function parsePkcs7SignedDataPem(pem: string): ParsePkcs7SignedDataResult {\n\ttry {\n\t\tconst blocks = splitPemBlocks(pem).filter((block) => block.label === 'PKCS7');\n\t\tconst block = blocks[0];\n\t\tif (block === undefined || blocks.length !== 1) {\n\t\t\treturn pkcs7Failure('malformed', 'Expected exactly one PKCS7 PEM block');\n\t\t}\n\t\treturn parsePkcs7SignedDataDer(block.bytes);\n\t} catch {\n\t\treturn pkcs7Failure('malformed', 'Expected exactly one PKCS7 PEM block');\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// verifyPkcs7SignedData\n// ---------------------------------------------------------------------------\n\n/**\n * Verifies all signer signatures in a PKCS#7 SignedData structure.\n *\n * Accepts PEM text, raw DER, or an already-parsed {@linkcode ParsedPkcs7SignedData}.\n * For each signer, locates the matching certificate in the embedded set and\n * verifies the signature (including signed-attribute digest checks per RFC 5652 Section 5.4).\n *\n * @example\n * ```ts\n * import { verifyPkcs7SignedData } from 'micro509';\n *\n * const result = await verifyPkcs7SignedData(pkcs7Pem);\n * if (result.ok) {\n * console.log('all signers verified');\n * }\n * ```\n */\nexport async function verifyPkcs7SignedData(\n\tinput: string | Uint8Array | ParsedPkcs7SignedData,\n): Promise<VerifyPkcs7SignedDataResult> {\n\tlet parsed: ParsedPkcs7SignedData;\n\tif (typeof input === 'string') {\n\t\tconst result = parsePkcs7SignedDataPem(input);\n\t\tif (!result.ok) {\n\t\t\treturn result;\n\t\t}\n\t\tparsed = result.value;\n\t} else if (input instanceof Uint8Array) {\n\t\tconst result = parsePkcs7SignedDataDer(input);\n\t\tif (!result.ok) {\n\t\t\treturn result;\n\t\t}\n\t\tparsed = result.value;\n\t} else {\n\t\tif (!hasReparseablePkcs7SignedData(input)) {\n\t\t\treturn verifyPkcs7Failure('malformed', 'SignedData parsed input is malformed');\n\t\t}\n\t\tconst result = parsePkcs7SignedDataDer(new Uint8Array(input.der));\n\t\tif (!result.ok) {\n\t\t\treturn result;\n\t\t}\n\t\tparsed = result.value;\n\t}\n\tif (parsed.encapsulatedContent === undefined) {\n\t\treturn verifyPkcs7Failure('content_missing', 'SignedData encapsulated content is missing');\n\t}\n\tfor (const signerInfo of parsed.signerInfos) {\n\t\tconst signer = parsed.certificates.find((certificate) =>\n\t\t\tsignerIdentifierMatches(certificate, signerInfo),\n\t\t);\n\t\tif (signer === undefined) {\n\t\t\treturn verifyPkcs7Failure(\n\t\t\t\t'signer_not_found',\n\t\t\t\t'Signer certificate not found in SignedData certificates',\n\t\t\t);\n\t\t}\n\t\tif (signerInfo.hasSignedAttrs) {\n\t\t\tconst attrsResult = await verifySignedAttrs(\n\t\t\t\tsignerInfo,\n\t\t\t\tsigner,\n\t\t\t\tparsed.encapsulatedContent,\n\t\t\t\tparsed.encapsulatedContentTypeOid,\n\t\t\t);\n\t\t\tif (!attrsResult.ok) {\n\t\t\t\treturn attrsResult;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tlet verified: boolean;\n\t\ttry {\n\t\t\tconst verificationResult = await verifySignedDataDetailed(\n\t\t\t\tsignerInfo.signatureAlgorithmOid,\n\t\t\t\tsignerInfo.signatureAlgorithmParametersDer,\n\t\t\t\tsigner.publicKeyAlgorithmOid,\n\t\t\t\tsigner.publicKeyParametersOid,\n\t\t\t\tsigner.subjectPublicKeyInfoDer,\n\t\t\t\tsignerInfo.signature,\n\t\t\t\tparsed.encapsulatedContent,\n\t\t\t);\n\t\t\tif (!verificationResult.ok) {\n\t\t\t\tif (verificationResult.code === 'verification_error') {\n\t\t\t\t\treturn verifyPkcs7Failure('malformed', 'SignedData signature verification failed');\n\t\t\t\t}\n\t\t\t\treturn verifyPkcs7Failure('malformed', 'Unsupported signature algorithm in SignedData');\n\t\t\t}\n\t\t\tverified = verificationResult.valid;\n\t\t} catch {\n\t\t\treturn verifyPkcs7Failure('malformed', 'Unsupported signature algorithm in SignedData');\n\t\t}\n\t\tif (!verified) {\n\t\t\treturn verifyPkcs7Failure('signature_invalid', 'SignedData signature does not verify');\n\t\t}\n\t}\n\treturn { ok: true, value: parsed };\n}\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\n/** Shorthand for constructing a PKCS#7 parse failure result. */\nfunction pkcs7Failure(\n\tcode: ParsePkcs7ErrorCode,\n\tmessage: string,\n): ErrorResult<ParsePkcs7ErrorCode, Record<never, never>, ParsePkcs7Failure> {\n\tconst error: ParsePkcs7Failure = { ok: false, code, message };\n\treturn { ok: false, error, code, message };\n}\n\n/** Shorthand for constructing a PKCS#7 verification failure result. */\nfunction verifyPkcs7Failure(\n\tcode:\n\t\t| 'signer_not_found'\n\t\t| 'signature_invalid'\n\t\t| 'message_digest_mismatch'\n\t\t| 'content_missing'\n\t\t| ParsePkcs7ErrorCode,\n\tmessage: string,\n): ErrorResult<\n\t| 'signer_not_found'\n\t| 'signature_invalid'\n\t| 'message_digest_mismatch'\n\t| 'content_missing'\n\t| ParsePkcs7ErrorCode,\n\tRecord<never, never>,\n\tVerifyPkcs7SignedDataFailure\n> {\n\tconst error: VerifyPkcs7SignedDataFailure = { ok: false, code, message };\n\treturn { ok: false, error, code, message };\n}\n\n/** Converts PEM text to an array of DER certificate blobs, or wraps raw DER. */\nfunction normalizeCertificateSource(source: Pkcs7CertificateSource): readonly Uint8Array[] {\n\tif (typeof source === 'string') {\n\t\treturn splitPemBlocks(source)\n\t\t\t.filter((block) => block.label === 'CERTIFICATE')\n\t\t\t.map((block) => new Uint8Array(block.bytes));\n\t}\n\treturn [new Uint8Array(source)];\n}\n\n/** Parses the IMPLICIT [0] certificate set from a SignedData structure. */\nfunction parseCertificateSet(\n\tsource: Uint8Array,\n\tcertificates: ReturnType<typeof readElement> | undefined,\n): readonly ParsedCertificate[] {\n\tif (certificates === undefined || certificates.tag !== 0xa0) {\n\t\treturn [];\n\t}\n\tconst parsed: ParsedCertificate[] = [];\n\tlet offset = certificates.start;\n\twhile (offset < certificates.end) {\n\t\tconst element = readElement(source, offset);\n\t\tparsed.push(parseCertificateDer(source.slice(offset, element.end)));\n\t\toffset = element.end;\n\t}\n\treturn parsed;\n}\n\n/** Extracts the list of digest algorithm OIDs from the digestAlgorithms SET. */\nfunction parseDigestAlgorithms(\n\tsource: Uint8Array,\n\telement: ReturnType<typeof readElement>,\n): readonly string[] {\n\tconst digests: string[] = [];\n\tif (element.tag !== 0x31) {\n\t\tthrow new Error('digestAlgorithms must use SET');\n\t}\n\tfor (const child of childrenOf(source, element)) {\n\t\tif (child.tag !== 0x30) {\n\t\t\tthrow new Error('digestAlgorithm must use AlgorithmIdentifier SEQUENCE');\n\t\t}\n\t\tconst childDer = source.slice(child.start - child.headerLength, child.end);\n\t\tconst parts = readSequenceChildren(childDer);\n\t\tconst oid = parts[0];\n\t\tif (oid === undefined || parts.length < 1 || parts.length > 2 || oid.tag !== 0x06) {\n\t\t\tthrow new Error('Malformed digest AlgorithmIdentifier');\n\t\t}\n\t\tdigests.push(decodeObjectIdentifier(oid.value));\n\t}\n\treturn digests;\n}\n\n/** Decodes the signerInfos SET OF from a SignedData structure. */\nfunction parseSignerInfos(\n\tsource: Uint8Array,\n\telement: ReturnType<typeof readElement>,\n): readonly ParsedPkcs7SignerInfo[] {\n\tconst signers: ParsedPkcs7SignerInfo[] = [];\n\tfor (const signerInfo of childrenOf(source, element)) {\n\t\tconst signerDer = source.slice(signerInfo.start - signerInfo.headerLength, signerInfo.end);\n\t\tconst parts = readSequenceChildren(signerDer);\n\t\tconst version = parts[0];\n\t\tconst sid = parts[1];\n\t\tconst digestAlgorithm = parts[2];\n\t\tlet index = 3;\n\t\tconst signedAttrsElement = parts[index]?.tag === 0xa0 ? parts[index] : undefined;\n\t\tconst hasSignedAttrs = signedAttrsElement !== undefined;\n\t\tif (hasSignedAttrs) {\n\t\t\tindex += 1;\n\t\t}\n\t\tconst signatureAlgorithm = parts[index];\n\t\tconst signature = parts[index + 1];\n\t\tconst unauthenticatedAttributes = parts[index + 2];\n\t\tif (\n\t\t\tversion === undefined ||\n\t\t\tsid === undefined ||\n\t\t\tdigestAlgorithm === undefined ||\n\t\t\tsignatureAlgorithm === undefined ||\n\t\t\tsignature === undefined ||\n\t\t\tsignature.tag !== 0x04 ||\n\t\t\tparts.length > index + 3 ||\n\t\t\t(unauthenticatedAttributes !== undefined && unauthenticatedAttributes.tag !== 0xa1)\n\t\t) {\n\t\t\tthrow new Error('Malformed SignerInfo');\n\t\t}\n\t\tconst digestAlgorithmDer = signerDer.slice(\n\t\t\tdigestAlgorithm.start - digestAlgorithm.headerLength,\n\t\t\tdigestAlgorithm.end,\n\t\t);\n\t\tconst digestAlgorithmOid = decodeObjectIdentifier(\n\t\t\trequireElement(readSequenceChildren(digestAlgorithmDer)[0], 'digest algorithm OID').value,\n\t\t);\n\t\tconst signatureAlgorithmDer = signerDer.slice(\n\t\t\tsignatureAlgorithm.start - signatureAlgorithm.headerLength,\n\t\t\tsignatureAlgorithm.end,\n\t\t);\n\t\tconst signatureAlgorithmChildren = readSequenceChildren(signatureAlgorithmDer);\n\t\tconst signatureAlgorithmOid = decodeObjectIdentifier(\n\t\t\trequireElement(signatureAlgorithmChildren[0], 'signature algorithm OID').value,\n\t\t);\n\t\tconst signatureAlgorithmParams = signatureAlgorithmChildren[1];\n\t\tconst parsedSid = parseSignerIdentifier(signerDer.slice(sid.start - sid.headerLength, sid.end));\n\t\tsigners.push({\n\t\t\tversion: decodeIntegerNumber(version.value),\n\t\t\t...(parsedSid.issuer === undefined ? {} : { issuer: parsedSid.issuer }),\n\t\t\t...(parsedSid.serialNumberHex === undefined\n\t\t\t\t? {}\n\t\t\t\t: { serialNumberHex: parsedSid.serialNumberHex }),\n\t\t\t...(parsedSid.subjectKeyIdentifier === undefined\n\t\t\t\t? {}\n\t\t\t\t: { subjectKeyIdentifier: parsedSid.subjectKeyIdentifier }),\n\t\t\tdigestAlgorithmOid,\n\t\t\tdigestAlgorithmName: describeHashAlgorithm(digestAlgorithmOid),\n\t\t\tsignatureAlgorithmOid,\n\t\t\tsignatureAlgorithmName: describeSignatureAlgorithm(\n\t\t\t\tsignatureAlgorithmOid,\n\t\t\t\tsignatureAlgorithmParams === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: new Uint8Array(\n\t\t\t\t\t\t\tsignatureAlgorithmDer.slice(\n\t\t\t\t\t\t\t\tsignatureAlgorithmParams.start - signatureAlgorithmParams.headerLength,\n\t\t\t\t\t\t\t\tsignatureAlgorithmParams.end,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t),\n\t\t\t...(signatureAlgorithmParams === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tsignatureAlgorithmParametersDer: new Uint8Array(\n\t\t\t\t\t\t\tsignatureAlgorithmDer.slice(\n\t\t\t\t\t\t\t\tsignatureAlgorithmParams.start - signatureAlgorithmParams.headerLength,\n\t\t\t\t\t\t\t\tsignatureAlgorithmParams.end,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t}),\n\t\t\tsignatureHex: toHex(signature.value),\n\t\t\tsignature: new Uint8Array(signature.value),\n\t\t\thasSignedAttrs,\n\t\t\t...(signedAttrsElement === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tsignedAttrsDer: new Uint8Array(\n\t\t\t\t\t\t\tsignerDer.slice(\n\t\t\t\t\t\t\t\tsignedAttrsElement.start - signedAttrsElement.headerLength,\n\t\t\t\t\t\t\t\tsignedAttrsElement.end,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t}),\n\t\t});\n\t}\n\treturn signers;\n}\n\n/** Unwraps the OCTET STRING inside the IMPLICIT [0] encapsulated content. */\nfunction extractEncapsulatedContent(\n\tencapDer: Uint8Array,\n\telement: ReturnType<typeof readElement>,\n): Uint8Array {\n\tif (element.tag !== 0xa0) {\n\t\tthrow new Error('Unexpected encapsulated content tag');\n\t}\n\tconst inner = readElement(encapDer, element.start);\n\tif (inner.tag !== 0x04) {\n\t\tthrow new Error('Expected encapsulated OCTET STRING');\n\t}\n\treturn inner.value;\n}\n\n/** Extracts issuer Name and serial number from an issuerAndSerialNumber SEQUENCE, or subjectKeyIdentifier from [0] IMPLICIT. */\nfunction parseSignerIdentifier(der: Uint8Array): {\n\treadonly issuer?: ParsedName;\n\treadonly serialNumberHex?: string;\n\treadonly subjectKeyIdentifier?: string;\n} {\n\tconst element = readRootElement(der, { maxDepth: DEFAULT_MAX_DER_DEPTH });\n\t// [0] IMPLICIT SubjectKeyIdentifier\n\tif (element.tag === 0x80) {\n\t\tif (element.value.length === 0) {\n\t\t\tthrow new Error('SignerIdentifier subjectKeyIdentifier must not be empty');\n\t\t}\n\t\treturn {\n\t\t\tsubjectKeyIdentifier: toHex(element.value),\n\t\t};\n\t}\n\t// SEQUENCE { issuer Name, serialNumber INTEGER }\n\tif (element.tag === 0x30) {\n\t\tconst top = readSequenceChildren(der);\n\t\tconst issuerElement = top[0];\n\t\tconst serial = top[1];\n\t\tif (issuerElement === undefined || serial === undefined || top.length !== 2) {\n\t\t\tthrow new Error('SignerIdentifier issuerAndSerialNumber is malformed');\n\t\t}\n\t\tif (issuerElement.tag !== 0x30) {\n\t\t\tthrow new Error('SignerIdentifier issuer must use Name SEQUENCE');\n\t\t}\n\t\tif (serial.tag !== 0x02) {\n\t\t\tthrow new Error('SignerIdentifier serialNumber must use INTEGER');\n\t\t}\n\t\tassertImplicitSerialNumberEncoding(serial.value, 'SignerIdentifier serialNumber');\n\t\treturn {\n\t\t\tissuer: parseSignerIssuerName(der, issuerElement),\n\t\t\tserialNumberHex: toHex(serial.value),\n\t\t};\n\t}\n\tthrow new Error(`Unsupported SignerIdentifier tag: ${String(element.tag)}`);\n}\n\nconst textDecoder = new TextDecoder();\n\n/** Parses a Name SEQUENCE element from a PKCS#7 signer identifier into a {@linkcode ParsedName}. */\nfunction parseSignerIssuerName(source: Uint8Array, element: DerElement): ParsedName {\n\tconst derHex = toHex(source.slice(element.start - element.headerLength, element.end));\n\tconst rdns: ParsedRelativeDistinguishedName[] = [];\n\tconst allAttributes: ParsedNameAttribute[] = [];\n\tconst values: Partial<Record<NameFieldKey, string>> = {};\n\tfor (const setElement of childrenOf(source, element)) {\n\t\tconst rdnAttributes: ParsedNameAttribute[] = [];\n\t\tconst rdnValues: Partial<Record<NameFieldKey, string>> = {};\n\t\tfor (const attrSequence of childrenOf(source, setElement)) {\n\t\t\tconst parts = childrenOf(source, attrSequence);\n\t\t\tconst oidElement = requireElement(parts[0], 'signer issuer attribute OID');\n\t\t\tconst valueElement = requireElement(parts[1], 'signer issuer attribute value');\n\t\t\tconst oid = decodeObjectIdentifier(oidElement.value);\n\t\t\tlet fieldValue: string;\n\t\t\ttry {\n\t\t\t\tfieldValue = decodeString(valueElement.tag, valueElement.value);\n\t\t\t} catch {\n\t\t\t\tfieldValue = textDecoder.decode(valueElement.value);\n\t\t\t}\n\t\t\tconst fieldKey = nameFieldKeyFromOid(oid);\n\t\t\tconst attribute: ParsedNameAttribute =\n\t\t\t\tfieldKey !== undefined\n\t\t\t\t\t? { oid, key: fieldKey, valueTag: valueElement.tag, value: fieldValue }\n\t\t\t\t\t: { oid, valueTag: valueElement.tag, value: fieldValue };\n\t\t\trdnAttributes.push(attribute);\n\t\t\tallAttributes.push(attribute);\n\t\t\tif (fieldKey !== undefined) {\n\t\t\t\tif (rdnValues[fieldKey] === undefined) {\n\t\t\t\t\trdnValues[fieldKey] = fieldValue;\n\t\t\t\t}\n\t\t\t\tif (values[fieldKey] === undefined) {\n\t\t\t\t\tvalues[fieldKey] = fieldValue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\trdns.push({\n\t\t\tderHex: toHex(source.slice(setElement.start - setElement.headerLength, setElement.end)),\n\t\t\tattributes: rdnAttributes,\n\t\t\tvalues: rdnValues,\n\t\t});\n\t}\n\treturn { derHex, rdns, attributes: allAttributes, values };\n}\n\n/** Returns the nth child element inside a constructed ASN.1 element, or throws. */\nfunction childAt(source: Uint8Array, parent: DerElement, index: number, label: string): DerElement {\n\tlet offset = parent.start;\n\tlet currentIndex = 0;\n\twhile (offset < parent.end) {\n\t\tconst child = readElement(source, offset);\n\t\tif (currentIndex === index) {\n\t\t\treturn child;\n\t\t}\n\t\toffset = child.end;\n\t\tcurrentIndex += 1;\n\t}\n\tthrow new Error(`Missing ${label}`);\n}\n\n// ---------------------------------------------------------------------------\n// CMS signed attributes verification (RFC 5652 Section 5.4)\n// ---------------------------------------------------------------------------\n\n/** Maps a digest algorithm OID to the WebCrypto hash name. */\nfunction digestAlgorithmHash(digestAlgorithmOid: string): 'SHA-256' | 'SHA-384' | 'SHA-512' {\n\tswitch (digestAlgorithmOid) {\n\t\tcase OIDS.sha256:\n\t\t\treturn 'SHA-256';\n\t\tcase OIDS.sha384:\n\t\t\treturn 'SHA-384';\n\t\tcase OIDS.sha512:\n\t\t\treturn 'SHA-512';\n\t\tdefault:\n\t\t\tthrow new Error(`Unsupported digest algorithm OID: ${digestAlgorithmOid}`);\n\t}\n}\n\n/** Parses required signed attributes and enforces uniqueness + exact-one-value shape. */\nfunction parseSignedAttributeRequirements(signedAttrsDer: Uint8Array): {\n\treadonly messageDigest: Uint8Array;\n\treadonly contentTypeOid: string;\n} {\n\tconst outer = readElement(signedAttrsDer);\n\tlet messageDigest: Uint8Array | undefined;\n\tlet contentTypeOid: string | undefined;\n\tfor (const attr of childrenOf(signedAttrsDer, outer)) {\n\t\tconst attrDer = signedAttrsDer.slice(attr.start - attr.headerLength, attr.end);\n\t\tconst parts = readSequenceChildren(attrDer);\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 signedAttrs attribute');\n\t\t}\n\t\tconst attrOid = decodeObjectIdentifier(oid.value);\n\t\tconst valueElements = childrenOf(attrDer, values);\n\t\tif (attrOid === OIDS.cmsMessageDigest) {\n\t\t\tif (messageDigest !== undefined || valueElements.length !== 1) {\n\t\t\t\tthrow new Error('messageDigest attribute must appear exactly once with one value');\n\t\t\t}\n\t\t\tconst digestElement = valueElements[0];\n\t\t\tif (digestElement === undefined || digestElement.tag !== 0x04) {\n\t\t\t\tthrow new Error('messageDigest attribute value must use OCTET STRING');\n\t\t\t}\n\t\t\tmessageDigest = digestElement.value;\n\t\t\tcontinue;\n\t\t}\n\t\tif (attrOid === OIDS.cmsContentType) {\n\t\t\tif (contentTypeOid !== undefined || valueElements.length !== 1) {\n\t\t\t\tthrow new Error('contentType attribute must appear exactly once with one value');\n\t\t\t}\n\t\t\tconst contentType = valueElements[0];\n\t\t\tif (contentType === undefined || contentType.tag !== 0x06) {\n\t\t\t\tthrow new Error('contentType attribute value must use OBJECT IDENTIFIER');\n\t\t\t}\n\t\t\tcontentTypeOid = decodeObjectIdentifier(contentType.value);\n\t\t}\n\t}\n\tif (messageDigest === undefined) {\n\t\tthrow new Error('Missing messageDigest attribute in signedAttrs');\n\t}\n\tif (contentTypeOid === undefined) {\n\t\tthrow new Error('Missing contentType attribute in signedAttrs');\n\t}\n\treturn { messageDigest, contentTypeOid };\n}\n\n/** Replaces the IMPLICIT [0] tag (0xa0) with SET OF (0x31) per RFC 5652 Section 5.4. */\nfunction retagSignedAttrsAsSet(signedAttrsDer: Uint8Array): Uint8Array {\n\t// Replace IMPLICIT [0] tag (0xa0) with SET OF tag (0x31) per RFC 5652 Section 5.4\n\tconst copy = new Uint8Array(signedAttrsDer);\n\tcopy[0] = 0x31;\n\treturn copy;\n}\n\n/** Constant-time byte comparison to avoid timing side-channels in digest checks. */\nfunction constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean {\n\tif (a.length !== b.length) {\n\t\treturn false;\n\t}\n\tlet diff = 0;\n\tfor (let index = 0; index < a.length; index += 1) {\n\t\tdiff |= (a[index] ?? 0) ^ (b[index] ?? 0);\n\t}\n\treturn diff === 0;\n}\n\n/** Verifies a signed-attributes flow: digest match + signature over re-tagged attrs. */\nasync function verifySignedAttrs(\n\tsignerInfo: ParsedPkcs7SignerInfo,\n\tsigner: ParsedCertificate,\n\tencapsulatedContent: Uint8Array,\n\tencapsulatedContentTypeOid: string,\n): Promise<\n\t| { readonly ok: true }\n\t| ErrorResult<\n\t\t\t| 'signer_not_found'\n\t\t\t| 'signature_invalid'\n\t\t\t| 'message_digest_mismatch'\n\t\t\t| 'content_missing'\n\t\t\t| ParsePkcs7ErrorCode,\n\t\t\tRecord<never, never>,\n\t\t\tVerifyPkcs7SignedDataFailure\n\t >\n> {\n\tif (signerInfo.signedAttrsDer === undefined) {\n\t\treturn verifyPkcs7Failure('malformed', 'Missing signedAttrs DER');\n\t}\n\t// Step 1: Parse required signed attributes from signedAttrs\n\tlet signedAttributes: { readonly messageDigest: Uint8Array; readonly contentTypeOid: string };\n\ttry {\n\t\tassertImplicitSignedAttrsDer(signerInfo.signedAttrsDer);\n\t\tsignedAttributes = parseSignedAttributeRequirements(signerInfo.signedAttrsDer);\n\t} catch {\n\t\treturn verifyPkcs7Failure('malformed', 'Malformed signedAttrs in SignedData');\n\t}\n\tif (signedAttributes.contentTypeOid !== encapsulatedContentTypeOid) {\n\t\treturn verifyPkcs7Failure('malformed', 'SignedData contentType attribute does not match');\n\t}\n\t// Step 2: Compute digest of encapsulated content\n\tlet actualDigest: Uint8Array;\n\ttry {\n\t\tconst hash = digestAlgorithmHash(signerInfo.digestAlgorithmOid);\n\t\tactualDigest = new Uint8Array(\n\t\t\tawait getCrypto().subtle.digest(hash, toArrayBuffer(encapsulatedContent)),\n\t\t);\n\t} catch {\n\t\treturn verifyPkcs7Failure('malformed', 'Unsupported digest algorithm in SignedData');\n\t}\n\t// Step 3: Compare digests (constant-time)\n\tif (!constantTimeEqual(actualDigest, signedAttributes.messageDigest)) {\n\t\treturn verifyPkcs7Failure(\n\t\t\t'message_digest_mismatch',\n\t\t\t'Content digest does not match messageDigest attribute',\n\t\t);\n\t}\n\t// Step 4: Verify signature over re-tagged signedAttrs (0xa0 → 0x31 SET OF)\n\tlet signedData: Uint8Array;\n\ttry {\n\t\tsignedData = retagSignedAttrsAsSet(signerInfo.signedAttrsDer);\n\t} catch {\n\t\treturn verifyPkcs7Failure('malformed', 'Malformed signedAttrs in SignedData');\n\t}\n\tlet verified: boolean;\n\ttry {\n\t\tconst verificationResult = await verifySignedDataDetailed(\n\t\t\tsignerInfo.signatureAlgorithmOid,\n\t\t\tsignerInfo.signatureAlgorithmParametersDer,\n\t\t\tsigner.publicKeyAlgorithmOid,\n\t\t\tsigner.publicKeyParametersOid,\n\t\t\tsigner.subjectPublicKeyInfoDer,\n\t\t\tsignerInfo.signature,\n\t\t\tsignedData,\n\t\t);\n\t\tif (!verificationResult.ok) {\n\t\t\tif (verificationResult.code === 'verification_error') {\n\t\t\t\treturn verifyPkcs7Failure('malformed', 'SignedData signature verification failed');\n\t\t\t}\n\t\t\treturn verifyPkcs7Failure('malformed', 'Unsupported signature algorithm in SignedData');\n\t\t}\n\t\tverified = verificationResult.valid;\n\t} catch {\n\t\treturn verifyPkcs7Failure('malformed', 'Unsupported signature algorithm in SignedData');\n\t}\n\tif (!verified) {\n\t\treturn verifyPkcs7Failure(\n\t\t\t'signature_invalid',\n\t\t\t'SignedData signature over signedAttrs does not verify',\n\t\t);\n\t}\n\treturn { ok: true };\n}\n\nfunction signerIdentifierMatches(\n\tcertificate: ParsedCertificate,\n\tsignerInfo: ParsedPkcs7SignerInfo,\n): boolean {\n\tif (signerInfo.issuer !== undefined || signerInfo.serialNumberHex !== undefined) {\n\t\treturn (\n\t\t\tsignerInfo.issuer !== undefined &&\n\t\t\tsignerInfo.serialNumberHex !== undefined &&\n\t\t\tcertificate.serialNumberHex === signerInfo.serialNumberHex &&\n\t\t\tcompareDistinguishedNames(certificate.issuer, signerInfo.issuer)\n\t\t);\n\t}\n\treturn (\n\t\tsignerInfo.subjectKeyIdentifier !== undefined &&\n\t\tcertificate.subjectKeyIdentifier === signerInfo.subjectKeyIdentifier\n\t);\n}\n\nfunction assertImplicitSignedAttrsDer(signedAttrsDer: Uint8Array): void {\n\tif (readElement(signedAttrsDer).tag !== 0xa0) {\n\t\tthrow new Error('signedAttrs must use IMPLICIT [0] tag');\n\t}\n}\n\nfunction hasReparseablePkcs7SignedData(\n\tvalue: ParsedPkcs7SignedData,\n): value is ParsedPkcs7SignedData & { readonly der: Uint8Array } {\n\treturn 'der' in value && value.der instanceof Uint8Array;\n}\n\nfunction assertImplicitSerialNumberEncoding(bytes: Uint8Array, label: string): void {\n\tconst first = bytes[0];\n\tif (first === undefined) {\n\t\tthrow new Error(`${label} must not be empty`);\n\t}\n\tif ((first & 0x80) !== 0) {\n\t\tthrow new Error(`${label} must be non-negative`);\n\t}\n\tif (bytes.length > 1 && first === 0 && ((bytes[1] ?? 0) & 0x80) === 0) {\n\t\tthrow new Error(`${label} must use minimal encoding`);\n\t}\n}\n"],"mappings":"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"}
package/dist/pkcs.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import { Pbes2EncryptionOptions, Pbes2EncryptionScheme, Pbes2Prf } from "./internal/crypto/pbes2.js";
2
+ import { ParsedPkcs12MacData, Pkcs12MacOptions, createPkcs12MacData, parsePkcs12MacData } from "./pkcs/pkcs12-mac.js";
3
+ import { CreatePfxInput, ParsePfxErrorCode, ParsePfxFailure, ParsePfxOptions, ParsePfxResult, ParsedPfx, ParsedPfxAttribute, ParsedPfxBag, ParsedPfxBagAttributes, PfxBagAttributesInput, PfxCertificateBagInput, PfxCertificateSource, PfxEncryptionOptions, PfxMaterial, PfxPrivateKeyBagInput, PfxPrivateKeySource, createPfx, parsePfxDer, parsePfxPem } from "./pkcs/pfx.js";
4
+ import { ParsePkcs7CertBagResult, ParsePkcs7ErrorCode, ParsePkcs7Failure, ParsePkcs7SignedDataResult, ParsedPkcs7SignedData, ParsedPkcs7SignerInfo, Pkcs7CertBag, Pkcs7CertificateSource, VerifyPkcs7SignedDataFailure, VerifyPkcs7SignedDataResult, createPkcs7CertBagDer, createPkcs7CertBagPem, parsePkcs7CertBagDer, parsePkcs7CertBagPem, parsePkcs7SignedDataDer, parsePkcs7SignedDataPem, verifyPkcs7SignedData } from "./pkcs/pkcs7.js";
5
+ export { type CreatePfxInput, type ParsePfxErrorCode, type ParsePfxFailure, type ParsePfxOptions, type ParsePfxResult, type ParsePkcs7CertBagResult, type ParsePkcs7ErrorCode, type ParsePkcs7Failure, type ParsePkcs7SignedDataResult, type ParsedPfx, type ParsedPfxAttribute, type ParsedPfxBag, type ParsedPfxBagAttributes, type ParsedPkcs12MacData, type ParsedPkcs7SignedData, type ParsedPkcs7SignerInfo, type Pbes2EncryptionOptions, type Pbes2EncryptionScheme, type Pbes2Prf, type PfxBagAttributesInput, type PfxCertificateBagInput, type PfxCertificateSource, type PfxEncryptionOptions, type PfxMaterial, type PfxPrivateKeyBagInput, type PfxPrivateKeySource, type Pkcs12MacOptions, type Pkcs7CertBag, type Pkcs7CertificateSource, type VerifyPkcs7SignedDataFailure, type VerifyPkcs7SignedDataResult, createPfx, createPkcs12MacData, createPkcs7CertBagDer, createPkcs7CertBagPem, parsePfxDer, parsePfxPem, parsePkcs12MacData, parsePkcs7CertBagDer, parsePkcs7CertBagPem, parsePkcs7SignedDataDer, parsePkcs7SignedDataPem, verifyPkcs7SignedData };
package/dist/pkcs.js ADDED
@@ -0,0 +1 @@
1
+ import{createPkcs12MacData as e,parsePkcs12MacData as t}from"./pkcs/pkcs12-mac.js";import{createPfx as n,parsePfxDer as r,parsePfxPem as i}from"./pkcs/pfx.js";import{createPkcs7CertBagDer as a,createPkcs7CertBagPem as o,parsePkcs7CertBagDer as s,parsePkcs7CertBagPem as c,parsePkcs7SignedDataDer as l,parsePkcs7SignedDataPem as u,verifyPkcs7SignedData as d}from"./pkcs/pkcs7.js";export{n as createPfx,e as createPkcs12MacData,a as createPkcs7CertBagDer,o as createPkcs7CertBagPem,r as parsePfxDer,i as parsePfxPem,t as parsePkcs12MacData,s as parsePkcs7CertBagDer,c as parsePkcs7CertBagPem,l as parsePkcs7SignedDataDer,u as parsePkcs7SignedDataPem,d as verifyPkcs7SignedData};
@@ -0,0 +1,68 @@
1
+ //#region src/result/result.d.ts
2
+ /**
3
+ * Internal result helper types and constructors shared by low-level modules.
4
+ *
5
+ * Mirrors the public result model without depending on the public barrel.
6
+ *
7
+ * @module
8
+ */
9
+ /**
10
+ * Discriminated `ok` union: either `{ ok: true; value }` or `{ ok: false; error }`.
11
+ *
12
+ * Every fallible public API in micro509 returns a specialization of this type.
13
+ */
14
+ type Result<TValue, TError> = {
15
+ /** Operation succeeded. */readonly ok: true; /** Successful payload. */
16
+ readonly value: TValue;
17
+ } | {
18
+ /** Operation failed. */readonly ok: false; /** Structured error payload. */
19
+ readonly error: TError;
20
+ };
21
+ /** Failed result with a flattened code/message/details surface for ergonomic matching. */
22
+ interface ErrorResult<TCode extends string, TDetails, TError extends Micro509Error<TCode, TDetails>> {
23
+ /** Always `false` for failures. */
24
+ readonly ok: false;
25
+ /** Structured error payload. */
26
+ readonly error: TError;
27
+ /** Machine-readable failure reason, mirrored from `error.code`. */
28
+ readonly code: TCode;
29
+ /** Human-readable diagnostic, mirrored from `error.message`. */
30
+ readonly message: string;
31
+ /** Optional structured context for the failure. */
32
+ readonly details?: TDetails | undefined;
33
+ }
34
+ /** Like {@link ErrorResult} but also carries an index into the collection that was being processed. */
35
+ interface IndexedErrorResult<TCode extends string, TDetails, TError extends IndexedMicro509Error<TCode, TDetails>> extends ErrorResult<TCode, TDetails, TError> {
36
+ /** Zero-based position of the failing item in the input collection. */
37
+ readonly index?: number | undefined;
38
+ }
39
+ /** Base error shape carried by all failure results in the library. */
40
+ interface Micro509Error<TCode extends string, TDetails = Record<never, never>> {
41
+ /** Machine-readable failure reason (e.g. `'malformed'`, `'expired'`). */
42
+ readonly code: TCode;
43
+ /** Human-readable diagnostic message. */
44
+ readonly message: string;
45
+ /** Optional structured context for the failure. */
46
+ readonly details?: TDetails;
47
+ }
48
+ /** Like {@link Micro509Error} but includes a positional index for collection-processing APIs. */
49
+ interface IndexedMicro509Error<TCode extends string, TDetails = Record<never, never>> extends Micro509Error<TCode, TDetails> {
50
+ /** Zero-based position of the failing item in the input collection. */
51
+ readonly index?: number;
52
+ }
53
+ /** Wraps a value in a success result (`{ ok: true, value }`). */
54
+ declare function successResult<TValue>(value: TValue): {
55
+ readonly ok: true;
56
+ readonly value: TValue;
57
+ };
58
+ /** Constructs a {@link Micro509Error} payload. */
59
+ declare function micro509Error<TCode extends string, TDetails = Record<never, never>>(code: TCode, message: string, details?: TDetails): Micro509Error<TCode, TDetails>;
60
+ /** Constructs an {@link IndexedMicro509Error} payload with an optional collection index. */
61
+ declare function indexedMicro509Error<TCode extends string, TDetails = Record<never, never>>(code: TCode, message: string, index?: number, details?: TDetails): IndexedMicro509Error<TCode, TDetails>;
62
+ /** Wraps a {@link Micro509Error} in a flattened {@link ErrorResult}. */
63
+ declare function errorResult<TCode extends string, TDetails, TError extends Micro509Error<TCode, TDetails>>(error: TError): ErrorResult<TCode, TDetails, TError>;
64
+ /** Wraps an {@link IndexedMicro509Error} in a flattened {@link IndexedErrorResult}. */
65
+ declare function indexedErrorResult<TCode extends string, TDetails, TError extends IndexedMicro509Error<TCode, TDetails>>(error: TError): IndexedErrorResult<TCode, TDetails, TError>;
66
+ //#endregion
67
+ export { ErrorResult, IndexedErrorResult, IndexedMicro509Error, Micro509Error, Result, errorResult, indexedErrorResult, indexedMicro509Error, micro509Error, successResult };
68
+ //# sourceMappingURL=result.d.ts.map
@@ -0,0 +1,2 @@
1
+ function e(e){return{ok:!0,value:e}}function t(e,t,n){return{code:e,message:t,...n===void 0?{}:{details:n}}}function n(e,t,n,r){return{code:e,message:t,...n===void 0?{}:{index:n},...r===void 0?{}:{details:r}}}function r(e){return{ok:!1,error:e,code:e.code,message:e.message,...e.details===void 0?{}:{details:e.details}}}function i(e){return{ok:!1,error:e,code:e.code,message:e.message,...e.details===void 0?{}:{details:e.details},...e.index===void 0?{}:{index:e.index}}}export{r as errorResult,i as indexedErrorResult,n as indexedMicro509Error,t as micro509Error,e as successResult};
2
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result.js","names":[],"sources":["../../src/result/result.ts"],"sourcesContent":["/**\n * Internal result helper types and constructors shared by low-level modules.\n *\n * Mirrors the public result model without depending on the public barrel.\n *\n * @module\n */\n\n/**\n * Discriminated `ok` union: either `{ ok: true; value }` or `{ ok: false; error }`.\n *\n * Every fallible public API in micro509 returns a specialization of this type.\n */\nexport type Result<TValue, TError> =\n\t| {\n\t\t\t/** Operation succeeded. */\n\t\t\treadonly ok: true;\n\t\t\t/** Successful payload. */\n\t\t\treadonly value: TValue;\n\t }\n\t| {\n\t\t\t/** Operation failed. */\n\t\t\treadonly ok: false;\n\t\t\t/** Structured error payload. */\n\t\t\treadonly error: TError;\n\t };\n\n/** Failed result with a flattened code/message/details surface for ergonomic matching. */\nexport interface ErrorResult<\n\tTCode extends string,\n\tTDetails,\n\tTError extends Micro509Error<TCode, TDetails>,\n> {\n\t/** Always `false` for failures. */\n\treadonly ok: false;\n\t/** Structured error payload. */\n\treadonly error: TError;\n\t/** Machine-readable failure reason, mirrored from `error.code`. */\n\treadonly code: TCode;\n\t/** Human-readable diagnostic, mirrored from `error.message`. */\n\treadonly message: string;\n\t/** Optional structured context for the failure. */\n\treadonly details?: TDetails | undefined;\n}\n\n/** Like {@link ErrorResult} but also carries an index into the collection that was being processed. */\nexport interface IndexedErrorResult<\n\tTCode extends string,\n\tTDetails,\n\tTError extends IndexedMicro509Error<TCode, TDetails>,\n> extends ErrorResult<TCode, TDetails, TError> {\n\t/** Zero-based position of the failing item in the input collection. */\n\treadonly index?: number | undefined;\n}\n\n/** Base error shape carried by all failure results in the library. */\nexport interface Micro509Error<TCode extends string, TDetails = Record<never, never>> {\n\t/** Machine-readable failure reason (e.g. `'malformed'`, `'expired'`). */\n\treadonly code: TCode;\n\t/** Human-readable diagnostic message. */\n\treadonly message: string;\n\t/** Optional structured context for the failure. */\n\treadonly details?: TDetails;\n}\n\n/** Like {@link Micro509Error} but includes a positional index for collection-processing APIs. */\nexport interface IndexedMicro509Error<TCode extends string, TDetails = Record<never, never>>\n\textends Micro509Error<TCode, TDetails> {\n\t/** Zero-based position of the failing item in the input collection. */\n\treadonly index?: number;\n}\n\n/** Wraps a value in a success result (`{ ok: true, value }`). */\nexport function successResult<TValue>(value: TValue): {\n\treadonly ok: true;\n\treadonly value: TValue;\n} {\n\treturn { ok: true, value };\n}\n\n/** Constructs a {@link Micro509Error} payload. */\nexport function micro509Error<TCode extends string, TDetails = Record<never, never>>(\n\tcode: TCode,\n\tmessage: string,\n\tdetails?: TDetails,\n): Micro509Error<TCode, TDetails> {\n\treturn {\n\t\tcode,\n\t\tmessage,\n\t\t...(details === undefined ? {} : { details }),\n\t};\n}\n\n/** Constructs an {@link IndexedMicro509Error} payload with an optional collection index. */\nexport function indexedMicro509Error<TCode extends string, TDetails = Record<never, never>>(\n\tcode: TCode,\n\tmessage: string,\n\tindex?: number,\n\tdetails?: TDetails,\n): IndexedMicro509Error<TCode, TDetails> {\n\treturn {\n\t\tcode,\n\t\tmessage,\n\t\t...(index === undefined ? {} : { index }),\n\t\t...(details === undefined ? {} : { details }),\n\t};\n}\n\n/** Wraps a {@link Micro509Error} in a flattened {@link ErrorResult}. */\nexport function errorResult<\n\tTCode extends string,\n\tTDetails,\n\tTError extends Micro509Error<TCode, TDetails>,\n>(error: TError): ErrorResult<TCode, TDetails, TError> {\n\treturn {\n\t\tok: false,\n\t\terror,\n\t\tcode: error.code,\n\t\tmessage: error.message,\n\t\t...(error.details === undefined ? {} : { details: error.details }),\n\t};\n}\n\n/** Wraps an {@link IndexedMicro509Error} in a flattened {@link IndexedErrorResult}. */\nexport function indexedErrorResult<\n\tTCode extends string,\n\tTDetails,\n\tTError extends IndexedMicro509Error<TCode, TDetails>,\n>(error: TError): IndexedErrorResult<TCode, TDetails, TError> {\n\treturn {\n\t\tok: false,\n\t\terror,\n\t\tcode: error.code,\n\t\tmessage: error.message,\n\t\t...(error.details === undefined ? {} : { details: error.details }),\n\t\t...(error.index === undefined ? {} : { index: error.index }),\n\t};\n}\n"],"mappings":"AAyEA,SAAgB,EAAsB,EAGpC,CACD,MAAO,CAAE,GAAI,GAAM,OAAM,CAC1B,CAGA,SAAgB,EACf,EACA,EACA,EACiC,CACjC,MAAO,CACN,OACA,UACA,GAAI,IAAY,IAAA,GAAY,CAAC,EAAI,CAAE,SAAQ,CAC5C,CACD,CAGA,SAAgB,EACf,EACA,EACA,EACA,EACwC,CACxC,MAAO,CACN,OACA,UACA,GAAI,IAAU,IAAA,GAAY,CAAC,EAAI,CAAE,OAAM,EACvC,GAAI,IAAY,IAAA,GAAY,CAAC,EAAI,CAAE,SAAQ,CAC5C,CACD,CAGA,SAAgB,EAId,EAAqD,CACtD,MAAO,CACN,GAAI,GACJ,QACA,KAAM,EAAM,KACZ,QAAS,EAAM,QACf,GAAI,EAAM,UAAY,IAAA,GAAY,CAAC,EAAI,CAAE,QAAS,EAAM,OAAQ,CACjE,CACD,CAGA,SAAgB,EAId,EAA4D,CAC7D,MAAO,CACN,GAAI,GACJ,QACA,KAAM,EAAM,KACZ,QAAS,EAAM,QACf,GAAI,EAAM,UAAY,IAAA,GAAY,CAAC,EAAI,CAAE,QAAS,EAAM,OAAQ,EAChE,GAAI,EAAM,QAAU,IAAA,GAAY,CAAC,EAAI,CAAE,MAAO,EAAM,KAAM,CAC3D,CACD"}
@@ -0,0 +1,2 @@
1
+ import { ErrorResult, IndexedErrorResult, IndexedMicro509Error, Micro509Error, Result, errorResult, indexedErrorResult, indexedMicro509Error, micro509Error, successResult } from "./result/result.js";
2
+ export { type ErrorResult, type IndexedErrorResult, type IndexedMicro509Error, type Micro509Error, type Result, errorResult, indexedErrorResult, indexedMicro509Error, micro509Error, successResult };
package/dist/result.js ADDED
@@ -0,0 +1 @@
1
+ import{errorResult as e,indexedErrorResult as t,indexedMicro509Error as n,micro509Error as r,successResult as i}from"./result/result.js";export{e as errorResult,t as indexedErrorResult,n as indexedMicro509Error,r as micro509Error,i as successResult};
@@ -0,0 +1,180 @@
1
+ import { ParsedCertificate } from "../x509/parse.js";
2
+ import { CrlSource, RevocationReason } from "./crl.js";
3
+
4
+ //#region src/revocation/chain.d.ts
5
+ /**
6
+ * Certificate in any supported format.
7
+ *
8
+ * Accepts PEM string, DER bytes, or an already-parsed {@linkcode ParsedCertificate}.
9
+ * Used for {@linkcode CheckChainRevocationInput.extraCertificates}.
10
+ */
11
+ type CertificateSource = string | Uint8Array | ParsedCertificate;
12
+ /**
13
+ * OCSP response in any supported format.
14
+ *
15
+ * Accepts PEM string or DER bytes. Reserved for future OCSP support in
16
+ * {@linkcode CheckChainRevocationInput.ocspResponses}.
17
+ */
18
+ type OcspResponseSource = string | Uint8Array;
19
+ /**
20
+ * Revocation checking policy for {@linkcode checkChainRevocation}.
21
+ *
22
+ * Controls how indeterminate results (missing evidence, expired CRLs) affect
23
+ * the final {@linkcode CheckChainRevocationValue.decision | decision}.
24
+ */
25
+ interface RevocationPolicy {
26
+ /**
27
+ * How to handle indeterminate status.
28
+ *
29
+ * - `'soft-fail'`: indeterminate certificates are allowed (default)
30
+ * - `'hard-fail'`: indeterminate certificates cause denial
31
+ */
32
+ readonly mode?: "soft-fail" | "hard-fail";
33
+ /**
34
+ * Evidence preference when multiple sources are available.
35
+ *
36
+ * - `'best-available'`: use whichever evidence is freshest (default)
37
+ * - `'ocsp'`: prefer OCSP over CRL
38
+ * - `'crl'`: prefer CRL over OCSP
39
+ */
40
+ readonly prefer?: "ocsp" | "crl" | "best-available";
41
+ }
42
+ /** Input for {@linkcode checkChainRevocation}. */
43
+ interface CheckChainRevocationInput {
44
+ /** Validated certificate chain (leaf first, root last). */
45
+ readonly chain: readonly ParsedCertificate[];
46
+ /** CRLs to evaluate. */
47
+ readonly crls?: readonly CrlSource[];
48
+ /** OCSP responses to evaluate. */
49
+ readonly ocspResponses?: readonly OcspResponseSource[];
50
+ /** Extra certs for indirect CRL issuers / delegated OCSP responders. */
51
+ readonly extraCertificates?: readonly CertificateSource[];
52
+ /** Evaluation time. Defaults to `new Date()`. */
53
+ readonly at?: Date;
54
+ /** Revocation policy. */
55
+ readonly policy?: RevocationPolicy;
56
+ }
57
+ /**
58
+ * Granular reasons why revocation status could not be determined.
59
+ *
60
+ * Returned in {@linkcode CertificateRevocationStatus.indeterminateReasons} when
61
+ * `status` is `'indeterminate'`. Grouped by category:
62
+ *
63
+ * - **Evidence not found**: `no_applicable_crl`, `no_applicable_ocsp`
64
+ * - **Scope mismatch**: `distribution_point_mismatch`, `issuer_name_mismatch`,
65
+ * `reason_scope_mismatch`, `indirect_crl_scope_mismatch`, `reason_coverage_incomplete`
66
+ * - **Signer trust**: `crl_signer_not_found`, `crl_signer_not_authorized`,
67
+ * `crl_signer_revoked`, `crl_signer_indeterminate`, and OCSP equivalents
68
+ * - **Freshness**: `crl_expired`, `ocsp_response_expired`
69
+ */
70
+ type RevocationIndeterminateReason = "no_applicable_crl" | "no_applicable_ocsp" | "distribution_point_mismatch" | "issuer_name_mismatch" | "reason_scope_mismatch" | "indirect_crl_scope_mismatch" | "reason_coverage_incomplete" | "crl_signer_not_found" | "crl_signer_not_authorized" | "crl_signer_revoked" | "crl_signer_indeterminate" | "ocsp_responder_not_found" | "ocsp_responder_not_authorized" | "ocsp_responder_revoked" | "ocsp_responder_indeterminate" | "crl_expired" | "ocsp_response_expired" | "ocsp_status_unknown";
71
+ /**
72
+ * Identifies the source of revocation evidence.
73
+ *
74
+ * Included in {@linkcode CertificateRevocationStatus.source} when status is
75
+ * `'good'` or `'revoked'` to indicate which CRL or OCSP response provided the answer.
76
+ */
77
+ interface RevocationSource {
78
+ /** Whether evidence came from a CRL or OCSP response. */
79
+ readonly type: "crl" | "ocsp";
80
+ /** Certificate that signed the evidence (CRL issuer or OCSP responder). */
81
+ readonly signerCertificate?: ParsedCertificate;
82
+ /** Identifier for debugging (e.g., CRL issuer DN or OCSP responder URL). */
83
+ readonly evidenceIdentifier?: string;
84
+ }
85
+ /**
86
+ * Revocation evaluation result for a single certificate.
87
+ *
88
+ * One entry per certificate in {@linkcode CheckChainRevocationValue.certificates}.
89
+ * The trust anchor is excluded (never checked for revocation).
90
+ */
91
+ interface CertificateRevocationStatus {
92
+ /** The certificate that was evaluated. */
93
+ readonly certificate: ParsedCertificate;
94
+ /**
95
+ * Revocation status determination.
96
+ *
97
+ * - `'good'`: evidence confirms certificate is not revoked
98
+ * - `'revoked'`: evidence confirms certificate is revoked
99
+ * - `'indeterminate'`: could not determine status (see {@linkcode indeterminateReasons})
100
+ */
101
+ readonly status: "good" | "revoked" | "indeterminate";
102
+ /** Evidence source when status is `'good'` or `'revoked'`. */
103
+ readonly source?: RevocationSource;
104
+ /** Why status could not be determined. Present when `status` is `'indeterminate'`. */
105
+ readonly indeterminateReasons?: readonly RevocationIndeterminateReason[];
106
+ /** Revocation details. Present when `status` is `'revoked'`. */
107
+ readonly revocationInfo?: {
108
+ /** When the certificate was revoked. */readonly date: Date; /** RFC 5280 CRLReason code, if provided by the CRL/OCSP response. */
109
+ readonly reason?: RevocationReason;
110
+ };
111
+ }
112
+ /**
113
+ * Errors encountered while processing revocation evidence.
114
+ *
115
+ * Distinct from {@linkcode RevocationIndeterminateReason}: execution errors are
116
+ * code failures (malformed CRL, unsupported extension) rather than evaluation
117
+ * outcomes (CRL doesn't cover this certificate).
118
+ *
119
+ * Collected in {@linkcode CheckChainRevocationValue.executionErrors}.
120
+ */
121
+ interface RevocationExecutionError {
122
+ /** Error category. */
123
+ readonly kind: "parse_error" | "unsupported_extension" | "internal_error";
124
+ /** Human-readable error description. */
125
+ readonly message: string;
126
+ /** Which evidence caused the error (e.g., CRL issuer DN). */
127
+ readonly evidenceIdentifier?: string;
128
+ }
129
+ /**
130
+ * Detailed revocation check results.
131
+ *
132
+ * Returned as {@linkcode CheckChainRevocationResult.value} from
133
+ * {@linkcode checkChainRevocation}. Contains both the policy decision and
134
+ * detailed per-certificate findings for debugging.
135
+ */
136
+ interface CheckChainRevocationValue {
137
+ /**
138
+ * Final policy decision based on {@linkcode RevocationPolicy}.
139
+ *
140
+ * - `'allow'`: chain passes revocation check
141
+ * - `'deny'`: chain fails (revoked certificate or hard-fail on indeterminate)
142
+ */
143
+ readonly decision: "allow" | "deny";
144
+ /** Quick-access summary of problematic certificates. */
145
+ readonly summary: {
146
+ /** Certificates confirmed as revoked. */readonly revokedCertificates: readonly ParsedCertificate[]; /** Certificates whose status could not be determined. */
147
+ readonly indeterminateCertificates: readonly ParsedCertificate[];
148
+ };
149
+ /** Per-certificate evaluation results. See {@linkcode CertificateRevocationStatus}. */
150
+ readonly certificates: readonly CertificateRevocationStatus[];
151
+ /** Evidence that could not be processed. See {@linkcode RevocationExecutionError}. */
152
+ readonly executionErrors?: readonly RevocationExecutionError[];
153
+ }
154
+ /** Result type for {@linkcode checkChainRevocation}. */
155
+ type CheckChainRevocationResult = {
156
+ readonly ok: true;
157
+ readonly value: CheckChainRevocationValue;
158
+ };
159
+ /**
160
+ * Checks revocation status for all certificates in a validated chain.
161
+ *
162
+ * Evaluates CRL and OCSP evidence against each certificate (except the trust
163
+ * anchor), applies the revocation policy, and returns a unified decision.
164
+ *
165
+ * @example
166
+ * ```ts
167
+ * const result = await checkChainRevocation({
168
+ * chain: validatedChain,
169
+ * crls: [crl1, crl2],
170
+ * policy: { mode: 'hard-fail' },
171
+ * });
172
+ * if (result.value.decision === 'deny') {
173
+ * console.log('Revocation check failed');
174
+ * }
175
+ * ```
176
+ */
177
+ declare function checkChainRevocation(input: CheckChainRevocationInput): Promise<CheckChainRevocationResult>;
178
+ //#endregion
179
+ export { CertificateRevocationStatus, CertificateSource, CheckChainRevocationInput, CheckChainRevocationResult, CheckChainRevocationValue, type CrlSource, OcspResponseSource, RevocationExecutionError, RevocationIndeterminateReason, RevocationPolicy, RevocationSource, checkChainRevocation };
180
+ //# sourceMappingURL=chain.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{parseCertificateFromSource as e}from"../x509/parse.js";import{checkCertificateRevocationAgainstCrl as t,parseCertificateRevocationListDer as n,parseCertificateRevocationListPem as r}from"./crl.js";function i(e){return typeof e==`object`&&`issuer`in e?e:typeof e==`string`?r(e):n(e)}function a(t){try{return e(t)}catch{return}}function o(e,t){if(e.der.length!==t.der.length)return!1;for(let n=0;n<e.der.length;n++)if(e.der[n]!==t.der[n])return!1;return!0}function s(e,t,n){let r=[];for(let e of t){let t=a(e);t!==void 0&&r.push(t)}let i=[...r,...n];if(e.authorityKeyIdentifier!==void 0){for(let t of i)if(t.subjectKeyIdentifier!==void 0&&c(e.authorityKeyIdentifier)===c(t.subjectKeyIdentifier))return t}for(let t of i)if(e.issuer.derHex===t.subject.derHex)return t}function c(e){return e.toLowerCase()}function l(e){return`${e.issuer.derHex}:${e.serialNumberHex}`}async function u(e,t){let n=l(e),r=t.cache.get(n);if(r===`visiting`)return`resolved-indeterminate`;if(r!==void 0)return r;t.cache.set(n,`visiting`);let i=t.chain[t.chain.length-1];if(i!==void 0&&o(e,i)||t.chain.some(t=>o(t,e)))return t.cache.set(n,`resolved-valid`),`resolved-valid`;let a=d(e,t);if(a===void 0)return t.cache.set(n,`resolved-indeterminate`),`resolved-indeterminate`;let s=await f(e,a,t);return t.cache.set(n,s),s}function d(e,t){let n=[];for(let e of t.extraCertificates){let t=a(e);t!==void 0&&n.push(t)}let r=[...t.chain,...n];for(let t of r)if(e.authorityKeyIdentifier!==void 0&&t.subjectKeyIdentifier!==void 0&&c(e.authorityKeyIdentifier)===c(t.subjectKeyIdentifier)||e.issuer.derHex===t.subject.derHex)return t}async function f(e,n,r){let a=r.chain.some(e=>o(e,n));for(let a of r.crls){let o;try{o=i(a)}catch{continue}let s=await t({certificate:e,issuerCertificate:n,crl:o,at:r.at});if(s.ok){if(s.value.status===`revoked`)return`resolved-revoked`;if(s.value.status===`good`&&await u(n,r)===`resolved-valid`)return`resolved-valid`}}return a?`resolved-valid`:`resolved-indeterminate`}function p(e,t,n,r,i){return n===`revoked`&&r!==void 0?{certificate:e,status:`revoked`,source:{type:`crl`,signerCertificate:t},revocationInfo:{date:r,...i===void 0?{}:{reason:i}}}:{certificate:e,status:`good`,source:{type:`crl`,signerCertificate:t}}}const m=[`keyCompromise`,`cACompromise`,`affiliationChanged`,`superseded`,`cessationOfOperation`,`certificateHold`,`privilegeWithdrawn`,`aACompromise`];async function h(e,n,r,a){let{crls:c=[],extraCertificates:l=[],chain:d=[],at:f=new Date}=r,h=[],g=!1,_=!1,v=!1,y,b=new Set,x=[];for(let e of c)try{x.push(i(e))}catch(e){h.push({kind:`parse_error`,message:e instanceof Error?e.message:`CRL parse failed`})}let S=x.filter(e=>e.baseCrlNumber===void 0),C=x.filter(e=>e.baseCrlNumber!==void 0),w=async(n,r,i)=>t({certificate:e,issuerCertificate:i,crl:n,...r===void 0?{}:{deltaCrl:r},at:f});for(let t of S){let r=C.find(e=>e.issuer.derHex===t.issuer.derHex&&e.baseCrlNumber!==void 0&&t.crlNumber!==void 0&&BigInt(e.baseCrlNumber)<=BigInt(t.crlNumber)),i=await w(t,r,n),c=n;if(!i.ok){let e=s(t,l,d);e!==void 0&&!o(e,n)&&(i=await w(t,r,e),c=e)}if(!i.ok)continue;let f=await u(c,a);if(f===`resolved-revoked`){g=!0;continue}if(f===`resolved-indeterminate`){_=!0;continue}if(i.value.status===`revoked`)return{status:p(e,c,`revoked`,i.value.revocationDate,i.value.reasonCode),executionErrors:h};v=!0,y=c;let x=t.issuingDistributionPoint?.onlySomeReasons?.flags;if(x===void 0)for(let e of m)b.add(e);else for(let e of x)b.add(e)}if(v)return m.every(e=>b.has(e))?{status:{certificate:e,status:`good`,...y===void 0?{}:{source:{type:`crl`,signerCertificate:y}}},executionErrors:h}:{status:{certificate:e,status:`indeterminate`,indeterminateReasons:[`reason_coverage_incomplete`]},executionErrors:h};let T=[];return g?T.push(`crl_signer_revoked`):_?T.push(`crl_signer_indeterminate`):c.length===0?T.push(`no_applicable_crl`,`no_applicable_ocsp`):T.push(`no_applicable_crl`),{status:{certificate:e,status:`indeterminate`,indeterminateReasons:T},executionErrors:h}}async function g(e){let{chain:t,policy:n,crls:r=[],extraCertificates:i=[],at:a=new Date}=e,o=n?.mode??`soft-fail`;if(t.length===0)return{ok:!0,value:{decision:`allow`,summary:{revokedCertificates:[],indeterminateCertificates:[]},certificates:[]}};let s={cache:new Map,chain:t,crls:r,extraCertificates:i,at:a},c=t.slice(0,-1),l=[],u=[],d=[],f=[];for(let n=0;n<c.length;n++){let r=c[n],i=t[n+1];if(r===void 0||i===void 0)continue;let{status:a,executionErrors:o}=await h(r,i,e,s);l.push(a),f.push(...o),a.status===`revoked`?u.push(r):a.status===`indeterminate`&&d.push(r)}let p=u.length>0,m=d.length>0;return{ok:!0,value:{decision:p||m&&o===`hard-fail`?`deny`:`allow`,summary:{revokedCertificates:u,indeterminateCertificates:d},certificates:l,...f.length>0?{executionErrors:f}:{}}}}export{g as checkChainRevocation};
2
+ //# sourceMappingURL=chain.js.map