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":"chain.js","names":[],"sources":["../../src/revocation/chain.ts"],"sourcesContent":["/**\n * Chain-level revocation orchestration.\n *\n * Evaluates CRL and OCSP evidence for an entire validated certificate chain,\n * implementing the revocation checking portion of RFC 5280 §6.3.\n *\n * @see {@link https://datatracker.ietf.org/doc/html/rfc5280#section-6.3 | RFC 5280 §6.3 CRL Validation}\n * @module\n */\n\nimport type { ParsedCertificate } from '#micro509/x509/parse.ts';\nimport { parseCertificateFromSource } from '#micro509/x509/parse.ts';\nimport {\n\tcheckCertificateRevocationAgainstCrl,\n\tparseCertificateRevocationListDer,\n\tparseCertificateRevocationListPem,\n\ttype ParsedCertificateRevocationList,\n\ttype RevocationReason,\n} from './crl.ts';\nimport type { CrlSource } from './crl.ts';\n\nexport type { CrlSource };\n\n// ---------------------------------------------------------------------------\n// Input Types\n// ---------------------------------------------------------------------------\n\n/**\n * Certificate in any supported format.\n *\n * Accepts PEM string, DER bytes, or an already-parsed {@linkcode ParsedCertificate}.\n * Used for {@linkcode CheckChainRevocationInput.extraCertificates}.\n */\nexport type CertificateSource = string | Uint8Array | ParsedCertificate;\n\n/**\n * OCSP response in any supported format.\n *\n * Accepts PEM string or DER bytes. Reserved for future OCSP support in\n * {@linkcode CheckChainRevocationInput.ocspResponses}.\n */\nexport type OcspResponseSource = string | Uint8Array;\n\n/**\n * Revocation checking policy for {@linkcode checkChainRevocation}.\n *\n * Controls how indeterminate results (missing evidence, expired CRLs) affect\n * the final {@linkcode CheckChainRevocationValue.decision | decision}.\n */\nexport interface RevocationPolicy {\n\t/**\n\t * How to handle indeterminate status.\n\t *\n\t * - `'soft-fail'`: indeterminate certificates are allowed (default)\n\t * - `'hard-fail'`: indeterminate certificates cause denial\n\t */\n\treadonly mode?: 'soft-fail' | 'hard-fail';\n\t/**\n\t * Evidence preference when multiple sources are available.\n\t *\n\t * - `'best-available'`: use whichever evidence is freshest (default)\n\t * - `'ocsp'`: prefer OCSP over CRL\n\t * - `'crl'`: prefer CRL over OCSP\n\t */\n\treadonly prefer?: 'ocsp' | 'crl' | 'best-available';\n}\n\n/** Input for {@linkcode checkChainRevocation}. */\nexport interface CheckChainRevocationInput {\n\t/** Validated certificate chain (leaf first, root last). */\n\treadonly chain: readonly ParsedCertificate[];\n\t/** CRLs to evaluate. */\n\treadonly crls?: readonly CrlSource[];\n\t/** OCSP responses to evaluate. */\n\treadonly ocspResponses?: readonly OcspResponseSource[];\n\t/** Extra certs for indirect CRL issuers / delegated OCSP responders. */\n\treadonly extraCertificates?: readonly CertificateSource[];\n\t/** Evaluation time. Defaults to `new Date()`. */\n\treadonly at?: Date;\n\t/** Revocation policy. */\n\treadonly policy?: RevocationPolicy;\n}\n\n// ---------------------------------------------------------------------------\n// Output Types\n// ---------------------------------------------------------------------------\n\n/**\n * Granular reasons why revocation status could not be determined.\n *\n * Returned in {@linkcode CertificateRevocationStatus.indeterminateReasons} when\n * `status` is `'indeterminate'`. Grouped by category:\n *\n * - **Evidence not found**: `no_applicable_crl`, `no_applicable_ocsp`\n * - **Scope mismatch**: `distribution_point_mismatch`, `issuer_name_mismatch`,\n * `reason_scope_mismatch`, `indirect_crl_scope_mismatch`, `reason_coverage_incomplete`\n * - **Signer trust**: `crl_signer_not_found`, `crl_signer_not_authorized`,\n * `crl_signer_revoked`, `crl_signer_indeterminate`, and OCSP equivalents\n * - **Freshness**: `crl_expired`, `ocsp_response_expired`\n */\nexport type RevocationIndeterminateReason =\n\t// Evidence not found\n\t| 'no_applicable_crl'\n\t| 'no_applicable_ocsp'\n\t// Scope issues\n\t| 'distribution_point_mismatch'\n\t| 'issuer_name_mismatch'\n\t| 'reason_scope_mismatch'\n\t| 'indirect_crl_scope_mismatch'\n\t| 'reason_coverage_incomplete'\n\t// Signer trust issues\n\t| 'crl_signer_not_found'\n\t| 'crl_signer_not_authorized'\n\t| 'crl_signer_revoked'\n\t| 'crl_signer_indeterminate'\n\t| 'ocsp_responder_not_found'\n\t| 'ocsp_responder_not_authorized'\n\t| 'ocsp_responder_revoked'\n\t| 'ocsp_responder_indeterminate'\n\t// Freshness\n\t| 'crl_expired'\n\t| 'ocsp_response_expired'\n\t// OCSP specific\n\t| 'ocsp_status_unknown';\n\n/**\n * Identifies the source of revocation evidence.\n *\n * Included in {@linkcode CertificateRevocationStatus.source} when status is\n * `'good'` or `'revoked'` to indicate which CRL or OCSP response provided the answer.\n */\nexport interface RevocationSource {\n\t/** Whether evidence came from a CRL or OCSP response. */\n\treadonly type: 'crl' | 'ocsp';\n\t/** Certificate that signed the evidence (CRL issuer or OCSP responder). */\n\treadonly signerCertificate?: ParsedCertificate;\n\t/** Identifier for debugging (e.g., CRL issuer DN or OCSP responder URL). */\n\treadonly evidenceIdentifier?: string;\n}\n\n/**\n * Revocation evaluation result for a single certificate.\n *\n * One entry per certificate in {@linkcode CheckChainRevocationValue.certificates}.\n * The trust anchor is excluded (never checked for revocation).\n */\nexport interface CertificateRevocationStatus {\n\t/** The certificate that was evaluated. */\n\treadonly certificate: ParsedCertificate;\n\t/**\n\t * Revocation status determination.\n\t *\n\t * - `'good'`: evidence confirms certificate is not revoked\n\t * - `'revoked'`: evidence confirms certificate is revoked\n\t * - `'indeterminate'`: could not determine status (see {@linkcode indeterminateReasons})\n\t */\n\treadonly status: 'good' | 'revoked' | 'indeterminate';\n\t/** Evidence source when status is `'good'` or `'revoked'`. */\n\treadonly source?: RevocationSource;\n\t/** Why status could not be determined. Present when `status` is `'indeterminate'`. */\n\treadonly indeterminateReasons?: readonly RevocationIndeterminateReason[];\n\t/** Revocation details. Present when `status` is `'revoked'`. */\n\treadonly revocationInfo?: {\n\t\t/** When the certificate was revoked. */\n\t\treadonly date: Date;\n\t\t/** RFC 5280 CRLReason code, if provided by the CRL/OCSP response. */\n\t\treadonly reason?: RevocationReason;\n\t};\n}\n\n/**\n * Errors encountered while processing revocation evidence.\n *\n * Distinct from {@linkcode RevocationIndeterminateReason}: execution errors are\n * code failures (malformed CRL, unsupported extension) rather than evaluation\n * outcomes (CRL doesn't cover this certificate).\n *\n * Collected in {@linkcode CheckChainRevocationValue.executionErrors}.\n */\nexport interface RevocationExecutionError {\n\t/** Error category. */\n\treadonly kind: 'parse_error' | 'unsupported_extension' | 'internal_error';\n\t/** Human-readable error description. */\n\treadonly message: string;\n\t/** Which evidence caused the error (e.g., CRL issuer DN). */\n\treadonly evidenceIdentifier?: string;\n}\n\n/**\n * Detailed revocation check results.\n *\n * Returned as {@linkcode CheckChainRevocationResult.value} from\n * {@linkcode checkChainRevocation}. Contains both the policy decision and\n * detailed per-certificate findings for debugging.\n */\nexport interface CheckChainRevocationValue {\n\t/**\n\t * Final policy decision based on {@linkcode RevocationPolicy}.\n\t *\n\t * - `'allow'`: chain passes revocation check\n\t * - `'deny'`: chain fails (revoked certificate or hard-fail on indeterminate)\n\t */\n\treadonly decision: 'allow' | 'deny';\n\t/** Quick-access summary of problematic certificates. */\n\treadonly summary: {\n\t\t/** Certificates confirmed as revoked. */\n\t\treadonly revokedCertificates: readonly ParsedCertificate[];\n\t\t/** Certificates whose status could not be determined. */\n\t\treadonly indeterminateCertificates: readonly ParsedCertificate[];\n\t};\n\t/** Per-certificate evaluation results. See {@linkcode CertificateRevocationStatus}. */\n\treadonly certificates: readonly CertificateRevocationStatus[];\n\t/** Evidence that could not be processed. See {@linkcode RevocationExecutionError}. */\n\treadonly executionErrors?: readonly RevocationExecutionError[];\n}\n\n/** Result type for {@linkcode checkChainRevocation}. */\nexport type CheckChainRevocationResult = {\n\treadonly ok: true;\n\treadonly value: CheckChainRevocationValue;\n};\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Parses a CRL from various source formats.\n */\nfunction parseCrlFromSource(source: CrlSource): ParsedCertificateRevocationList {\n\tif (typeof source === 'object' && 'issuer' in source) {\n\t\treturn source;\n\t}\n\tif (typeof source === 'string') {\n\t\treturn parseCertificateRevocationListPem(source);\n\t}\n\treturn parseCertificateRevocationListDer(source);\n}\n\n/**\n * Parses a certificate from various source formats, returning undefined on failure.\n */\nfunction parseCertificateSafe(source: CertificateSource): ParsedCertificate | undefined {\n\ttry {\n\t\treturn parseCertificateFromSource(source);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Compares two certificates by DER bytes for identity.\n * Reference equality fails when same cert is parsed from different sources.\n */\nfunction sameCertificate(a: ParsedCertificate, b: ParsedCertificate): boolean {\n\tif (a.der.length !== b.der.length) return false;\n\tfor (let i = 0; i < a.der.length; i++) {\n\t\tif (a.der[i] !== b.der[i]) return false;\n\t}\n\treturn true;\n}\n\n/**\n * Searches for a certificate that could have signed the given CRL.\n * Matches by AKI/SKI or issuer/subject DN.\n */\nfunction findIndirectCrlIssuer(\n\tcrl: ParsedCertificateRevocationList,\n\textraCertificates: readonly CertificateSource[],\n\tchain: readonly ParsedCertificate[],\n): ParsedCertificate | undefined {\n\t// Combine extra certs with chain certs for searching\n\t// Chain certs are already parsed; extra certs may need parsing\n\tconst parsedExtras: ParsedCertificate[] = [];\n\tfor (const source of extraCertificates) {\n\t\tconst parsed = parseCertificateSafe(source);\n\t\tif (parsed !== undefined) {\n\t\t\tparsedExtras.push(parsed);\n\t\t}\n\t}\n\n\tconst candidates = [...parsedExtras, ...chain];\n\n\t// First pass: prefer AKI/SKI match (more specific)\n\tif (crl.authorityKeyIdentifier !== undefined) {\n\t\tfor (const candidate of candidates) {\n\t\t\tif (\n\t\t\t\tcandidate.subjectKeyIdentifier !== undefined &&\n\t\t\t\tnormalizeHex(crl.authorityKeyIdentifier) === normalizeHex(candidate.subjectKeyIdentifier)\n\t\t\t) {\n\t\t\t\treturn candidate;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Second pass: fall back to DN match\n\tfor (const candidate of candidates) {\n\t\tif (crl.issuer.derHex === candidate.subject.derHex) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/** Lowercases a hex string for bytewise comparison. */\nfunction normalizeHex(value: string): string {\n\treturn value.toLowerCase();\n}\n\n// ---------------------------------------------------------------------------\n// CRL Signer Validation (RFC 5280 §6.3.3)\n// ---------------------------------------------------------------------------\n\n/**\n * State machine for CRL signer validation with memoization.\n * - `visiting`: Currently being checked (cycle detection)\n * - `resolved-valid`: Signer is not revoked\n * - `resolved-revoked`: Signer is revoked\n * - `resolved-indeterminate`: Can't determine signer status\n */\ntype SignerValidationState =\n\t| 'visiting'\n\t| 'resolved-valid'\n\t| 'resolved-revoked'\n\t| 'resolved-indeterminate';\n\n/** Context for CRL signer validation with memoization cache. */\ninterface SignerValidationContext {\n\treadonly cache: Map<string, SignerValidationState>;\n\treadonly chain: readonly ParsedCertificate[];\n\treadonly crls: readonly CrlSource[];\n\treadonly extraCertificates: readonly CertificateSource[];\n\treadonly at: Date;\n}\n\n/**\n * Builds a unique cache key for a certificate.\n * Uses issuer DN + serial number which uniquely identifies a cert.\n */\nfunction certCacheKey(cert: ParsedCertificate): string {\n\treturn `${cert.issuer.derHex}:${cert.serialNumberHex}`;\n}\n\n/**\n * Validates that a CRL signer certificate is not revoked.\n * Uses memoization to avoid redundant checks and detect cycles.\n */\nasync function validateCrlSigner(\n\tsigner: ParsedCertificate,\n\tctx: SignerValidationContext,\n): Promise<SignerValidationState> {\n\t// Use issuer+serial as cache key (unique per certificate)\n\tconst key = certCacheKey(signer);\n\tconst cached = ctx.cache.get(key);\n\n\t// Cycle detection: if we're already visiting this signer, it's indeterminate\n\tif (cached === 'visiting') {\n\t\treturn 'resolved-indeterminate';\n\t}\n\n\t// Return cached result if already resolved\n\tif (cached !== undefined) {\n\t\treturn cached;\n\t}\n\n\t// Mark as visiting before recursive checks\n\tctx.cache.set(key, 'visiting');\n\n\t// Trust anchor (last in chain) is trusted by definition\n\tconst trustAnchor = ctx.chain[ctx.chain.length - 1];\n\tif (trustAnchor !== undefined && sameCertificate(signer, trustAnchor)) {\n\t\tctx.cache.set(key, 'resolved-valid');\n\t\treturn 'resolved-valid';\n\t}\n\n\t// If signer is in the validated chain, it's trusted\n\t// (Chain was already validated before revocation checking)\n\tconst isInChain = ctx.chain.some((c) => sameCertificate(c, signer));\n\tif (isInChain) {\n\t\tctx.cache.set(key, 'resolved-valid');\n\t\treturn 'resolved-valid';\n\t}\n\n\t// Signer is not in chain — need to check its revocation status\n\t// Find signer's issuer to perform revocation check\n\tconst signerIssuer = findSignerIssuer(signer, ctx);\n\tif (signerIssuer === undefined) {\n\t\tctx.cache.set(key, 'resolved-indeterminate');\n\t\treturn 'resolved-indeterminate';\n\t}\n\n\t// Check signer's revocation status (recursive)\n\tconst signerRevocation = await checkSignerRevocation(signer, signerIssuer, ctx);\n\tctx.cache.set(key, signerRevocation);\n\treturn signerRevocation;\n}\n\n/**\n * Finds the issuer certificate for a CRL signer.\n * Searches the chain and extraCertificates by AKI/SKI or DN matching.\n */\nfunction findSignerIssuer(\n\tsigner: ParsedCertificate,\n\tctx: SignerValidationContext,\n): ParsedCertificate | undefined {\n\t// Parse extra certificates\n\tconst parsedExtras: ParsedCertificate[] = [];\n\tfor (const source of ctx.extraCertificates) {\n\t\tconst parsed = parseCertificateSafe(source);\n\t\tif (parsed !== undefined) {\n\t\t\tparsedExtras.push(parsed);\n\t\t}\n\t}\n\n\tconst candidates = [...ctx.chain, ...parsedExtras];\n\n\tfor (const candidate of candidates) {\n\t\t// Match by AKI → SKI (preferred, more specific)\n\t\tif (\n\t\t\tsigner.authorityKeyIdentifier !== undefined &&\n\t\t\tcandidate.subjectKeyIdentifier !== undefined &&\n\t\t\tnormalizeHex(signer.authorityKeyIdentifier) === normalizeHex(candidate.subjectKeyIdentifier)\n\t\t) {\n\t\t\treturn candidate;\n\t\t}\n\n\t\t// Match by issuer DN → subject DN\n\t\tif (signer.issuer.derHex === candidate.subject.derHex) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\n/**\n * Checks if a CRL signer certificate is revoked by examining available CRLs.\n * Recursively validates the CRL signer of any CRL used to check revocation.\n */\nasync function checkSignerRevocation(\n\tsigner: ParsedCertificate,\n\tissuer: ParsedCertificate,\n\tctx: SignerValidationContext,\n): Promise<SignerValidationState> {\n\t// If the signer's issuer is in the validated chain, the signer is trusted\n\t// by virtue of being issued by a trusted CA. We only need to check if\n\t// it's explicitly revoked, not prove \"good\" status.\n\tconst issuerInChain = ctx.chain.some((c) => sameCertificate(c, issuer));\n\n\t// Try each CRL to check signer's revocation\n\tfor (const crlSource of ctx.crls) {\n\t\tlet crl: ParsedCertificateRevocationList;\n\t\ttry {\n\t\t\tcrl = parseCrlFromSource(crlSource);\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Check if this CRL can provide revocation info for the signer\n\t\tconst result = await checkCertificateRevocationAgainstCrl({\n\t\t\tcertificate: signer,\n\t\t\tissuerCertificate: issuer,\n\t\t\tcrl,\n\t\t\tat: ctx.at,\n\t\t});\n\n\t\tif (result.ok) {\n\t\t\tif (result.value.status === 'revoked') {\n\t\t\t\treturn 'resolved-revoked';\n\t\t\t}\n\t\t\tif (result.value.status === 'good') {\n\t\t\t\t// Before accepting this result, validate the CRL's signer\n\t\t\t\t// The CRL's signer is the issuer we just used\n\t\t\t\tconst crlSignerStatus = await validateCrlSigner(issuer, ctx);\n\t\t\t\tif (crlSignerStatus === 'resolved-valid') {\n\t\t\t\t\treturn 'resolved-valid';\n\t\t\t\t}\n\t\t\t\t// If CRL signer is revoked or indeterminate, can't trust this result\n\t\t\t}\n\t\t}\n\t}\n\n\t// If the signer's issuer is in the chain and we found no revocation,\n\t// trust the signer (issued by trusted CA, no evidence of revocation)\n\tif (issuerInChain) {\n\t\treturn 'resolved-valid';\n\t}\n\n\treturn 'resolved-indeterminate';\n}\n\n/** Builds a CertificateRevocationStatus for a CRL check result. */\nfunction buildCrlStatus(\n\tcert: ParsedCertificate,\n\tsigner: ParsedCertificate,\n\tstatus: 'good' | 'revoked',\n\trevocationDate?: Date,\n\treasonCode?: RevocationReason,\n): CertificateRevocationStatus {\n\tif (status === 'revoked' && revocationDate !== undefined) {\n\t\treturn {\n\t\t\tcertificate: cert,\n\t\t\tstatus: 'revoked',\n\t\t\tsource: { type: 'crl', signerCertificate: signer },\n\t\t\trevocationInfo: {\n\t\t\t\tdate: revocationDate,\n\t\t\t\t...(reasonCode !== undefined ? { reason: reasonCode } : {}),\n\t\t\t},\n\t\t};\n\t}\n\treturn {\n\t\tcertificate: cert,\n\t\tstatus: 'good',\n\t\tsource: { type: 'crl', signerCertificate: signer },\n\t};\n}\n\n/**\n * Evaluates revocation status for a single certificate using available CRLs.\n * Returns both status and any execution errors encountered.\n *\n * Tries the chain issuer first; if that fails, searches extraCertificates\n * and chain for an indirect CRL issuer that matches the CRL's AKI or issuer DN.\n *\n * Also validates that CRL signers are not revoked (RFC 5280 §6.3.3).\n */\n// RFC 5280 ReasonFlags — all possible revocation reasons that CRLs can cover.\nconst ALL_REASON_FLAGS: readonly string[] = [\n\t'keyCompromise',\n\t'cACompromise',\n\t'affiliationChanged',\n\t'superseded',\n\t'cessationOfOperation',\n\t'certificateHold',\n\t'privilegeWithdrawn',\n\t'aACompromise',\n];\n\nasync function evaluateCertificateRevocation(\n\tcert: ParsedCertificate,\n\tissuer: ParsedCertificate,\n\tinput: CheckChainRevocationInput,\n\tsignerCtx: SignerValidationContext,\n): Promise<{\n\tstatus: CertificateRevocationStatus;\n\texecutionErrors: readonly RevocationExecutionError[];\n}> {\n\tconst { crls = [], extraCertificates = [], chain = [], at = new Date() } = input;\n\tconst executionErrors: RevocationExecutionError[] = [];\n\tlet sawCrlSignerRevoked = false;\n\tlet sawCrlSignerIndeterminate = false;\n\tlet sawGood = false;\n\tlet lastGoodSigner: ParsedCertificate | undefined;\n\tconst coveredReasons = new Set<string>();\n\n\t// Parse all CRLs and separate base CRLs from delta CRLs\n\tconst parsedCrls: ParsedCertificateRevocationList[] = [];\n\tfor (const crlSource of crls) {\n\t\ttry {\n\t\t\tparsedCrls.push(parseCrlFromSource(crlSource));\n\t\t} catch (e) {\n\t\t\texecutionErrors.push({\n\t\t\t\tkind: 'parse_error',\n\t\t\t\tmessage: e instanceof Error ? e.message : 'CRL parse failed',\n\t\t\t});\n\t\t}\n\t}\n\n\tconst baseCrls = parsedCrls.filter((crl) => crl.baseCrlNumber === undefined);\n\tconst deltaCrls = parsedCrls.filter((crl) => crl.baseCrlNumber !== undefined);\n\n\t// Helper to check CRL with given issuer and optional delta\n\tconst checkWithIssuer = async (\n\t\tcrl: ParsedCertificateRevocationList,\n\t\tdeltaCrl: ParsedCertificateRevocationList | undefined,\n\t\tcrlIssuer: ParsedCertificate,\n\t) => {\n\t\treturn checkCertificateRevocationAgainstCrl({\n\t\t\tcertificate: cert,\n\t\t\tissuerCertificate: crlIssuer,\n\t\t\tcrl,\n\t\t\t...(deltaCrl !== undefined ? { deltaCrl } : {}),\n\t\t\tat,\n\t\t});\n\t};\n\n\t// Process base CRLs (optionally paired with delta CRLs)\n\tfor (const baseCrl of baseCrls) {\n\t\t// Find applicable delta CRL for this base CRL (if any)\n\t\t// Delta CRL applies if it has the same issuer and crlNumber matches baseCrlNumber\n\t\tconst applicableDelta = deltaCrls.find(\n\t\t\t(d) =>\n\t\t\t\td.issuer.derHex === baseCrl.issuer.derHex &&\n\t\t\t\td.baseCrlNumber !== undefined &&\n\t\t\t\tbaseCrl.crlNumber !== undefined &&\n\t\t\t\tBigInt(d.baseCrlNumber) <= BigInt(baseCrl.crlNumber),\n\t\t);\n\n\t\t// Try chain issuer first\n\t\tlet result = await checkWithIssuer(baseCrl, applicableDelta, issuer);\n\t\tlet effectiveSigner = issuer;\n\n\t\t// Chain issuer failed — try to find indirect CRL issuer\n\t\tif (!result.ok) {\n\t\t\tconst indirectIssuer = findIndirectCrlIssuer(baseCrl, extraCertificates, chain);\n\t\t\tif (indirectIssuer !== undefined && !sameCertificate(indirectIssuer, issuer)) {\n\t\t\t\tresult = await checkWithIssuer(baseCrl, applicableDelta, indirectIssuer);\n\t\t\t\teffectiveSigner = indirectIssuer;\n\t\t\t}\n\t\t}\n\n\t\tif (!result.ok) {\n\t\t\tcontinue; // CRL doesn't apply to this certificate\n\t\t}\n\n\t\t// Validate CRL signer is not revoked before accepting result\n\t\tconst signerStatus = await validateCrlSigner(effectiveSigner, signerCtx);\n\t\tif (signerStatus === 'resolved-revoked') {\n\t\t\tsawCrlSignerRevoked = true;\n\t\t\tcontinue; // CRL signer revoked — can't trust this CRL\n\t\t}\n\t\tif (signerStatus === 'resolved-indeterminate') {\n\t\t\tsawCrlSignerIndeterminate = true;\n\t\t\tcontinue; // CRL signer status unknown — try other CRLs\n\t\t}\n\n\t\t// CRL is valid — check result\n\t\tif (result.value.status === 'revoked') {\n\t\t\t// Immediately return revoked status\n\t\t\treturn {\n\t\t\t\tstatus: buildCrlStatus(\n\t\t\t\t\tcert,\n\t\t\t\t\teffectiveSigner,\n\t\t\t\t\t'revoked',\n\t\t\t\t\tresult.value.revocationDate,\n\t\t\t\t\tresult.value.reasonCode,\n\t\t\t\t),\n\t\t\t\texecutionErrors,\n\t\t\t};\n\t\t}\n\n\t\t// Status is 'good' — track which reasons this CRL covers\n\t\tsawGood = true;\n\t\tlastGoodSigner = effectiveSigner;\n\t\tconst crlReasons = baseCrl.issuingDistributionPoint?.onlySomeReasons?.flags;\n\t\tif (crlReasons === undefined) {\n\t\t\t// CRL covers all reasons\n\t\t\tfor (const reason of ALL_REASON_FLAGS) {\n\t\t\t\tcoveredReasons.add(reason);\n\t\t\t}\n\t\t} else {\n\t\t\t// CRL only covers specific reasons\n\t\t\tfor (const reason of crlReasons) {\n\t\t\t\tcoveredReasons.add(reason);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Return 'good' only if we saw at least one good result AND all reasons are covered\n\tif (sawGood) {\n\t\tconst allReasonsCovered = ALL_REASON_FLAGS.every((r) => coveredReasons.has(r));\n\t\tif (allReasonsCovered) {\n\t\t\treturn {\n\t\t\t\tstatus: {\n\t\t\t\t\tcertificate: cert,\n\t\t\t\t\tstatus: 'good',\n\t\t\t\t\t...(lastGoodSigner !== undefined\n\t\t\t\t\t\t? { source: { type: 'crl', signerCertificate: lastGoodSigner } }\n\t\t\t\t\t\t: {}),\n\t\t\t\t},\n\t\t\t\texecutionErrors,\n\t\t\t};\n\t\t}\n\t\t// Not all reasons covered — indeterminate\n\t\treturn {\n\t\t\tstatus: {\n\t\t\t\tcertificate: cert,\n\t\t\t\tstatus: 'indeterminate',\n\t\t\t\tindeterminateReasons: ['reason_coverage_incomplete'],\n\t\t\t},\n\t\t\texecutionErrors,\n\t\t};\n\t}\n\n\t// No applicable CRL found — determine most appropriate indeterminate reason\n\tconst reasons: RevocationIndeterminateReason[] = [];\n\tif (sawCrlSignerRevoked) {\n\t\treasons.push('crl_signer_revoked');\n\t} else if (sawCrlSignerIndeterminate) {\n\t\treasons.push('crl_signer_indeterminate');\n\t} else if (crls.length === 0) {\n\t\treasons.push('no_applicable_crl', 'no_applicable_ocsp');\n\t} else {\n\t\treasons.push('no_applicable_crl');\n\t}\n\n\treturn {\n\t\tstatus: {\n\t\t\tcertificate: cert,\n\t\t\tstatus: 'indeterminate',\n\t\t\tindeterminateReasons: reasons,\n\t\t},\n\t\texecutionErrors,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Function\n// ---------------------------------------------------------------------------\n\n/**\n * Checks revocation status for all certificates in a validated chain.\n *\n * Evaluates CRL and OCSP evidence against each certificate (except the trust\n * anchor), applies the revocation policy, and returns a unified decision.\n *\n * @example\n * ```ts\n * const result = await checkChainRevocation({\n * chain: validatedChain,\n * crls: [crl1, crl2],\n * policy: { mode: 'hard-fail' },\n * });\n * if (result.value.decision === 'deny') {\n * console.log('Revocation check failed');\n * }\n * ```\n */\nexport async function checkChainRevocation(\n\tinput: CheckChainRevocationInput,\n): Promise<CheckChainRevocationResult> {\n\tconst { chain, policy, crls = [], extraCertificates = [], at = new Date() } = input;\n\tconst mode = policy?.mode ?? 'soft-fail';\n\n\t// Empty chain → allow\n\tif (chain.length === 0) {\n\t\treturn {\n\t\t\tok: true,\n\t\t\tvalue: {\n\t\t\t\tdecision: 'allow',\n\t\t\t\tsummary: { revokedCertificates: [], indeterminateCertificates: [] },\n\t\t\t\tcertificates: [],\n\t\t\t},\n\t\t};\n\t}\n\n\t// Create signer validation context with memoization cache\n\t// This cache is shared across all certificate checks in this chain evaluation\n\tconst signerCtx: SignerValidationContext = {\n\t\tcache: new Map(),\n\t\tchain,\n\t\tcrls,\n\t\textraCertificates,\n\t\tat,\n\t};\n\n\t// Skip trust anchor (last cert) — it's the trust base\n\tconst certsToCheck = chain.slice(0, -1);\n\tconst certificates: CertificateRevocationStatus[] = [];\n\tconst revokedCertificates: ParsedCertificate[] = [];\n\tconst indeterminateCertificates: ParsedCertificate[] = [];\n\tconst allExecutionErrors: RevocationExecutionError[] = [];\n\n\tfor (let i = 0; i < certsToCheck.length; i++) {\n\t\tconst cert = certsToCheck[i];\n\t\tconst issuer = chain[i + 1]; // Next cert in chain is the issuer\n\t\tif (cert === undefined || issuer === undefined) {\n\t\t\tcontinue; // Should never happen given loop bounds\n\t\t}\n\n\t\tconst { status, executionErrors } = await evaluateCertificateRevocation(\n\t\t\tcert,\n\t\t\tissuer,\n\t\t\tinput,\n\t\t\tsignerCtx,\n\t\t);\n\t\tcertificates.push(status);\n\t\tallExecutionErrors.push(...executionErrors);\n\n\t\tif (status.status === 'revoked') {\n\t\t\trevokedCertificates.push(cert);\n\t\t} else if (status.status === 'indeterminate') {\n\t\t\tindeterminateCertificates.push(cert);\n\t\t}\n\t}\n\n\t// Apply policy\n\tconst hasRevoked = revokedCertificates.length > 0;\n\tconst hasIndeterminate = indeterminateCertificates.length > 0;\n\tconst decision: 'allow' | 'deny' = hasRevoked\n\t\t? 'deny'\n\t\t: hasIndeterminate && mode === 'hard-fail'\n\t\t\t? 'deny'\n\t\t\t: 'allow';\n\n\treturn {\n\t\tok: true,\n\t\tvalue: {\n\t\t\tdecision,\n\t\t\tsummary: { revokedCertificates, indeterminateCertificates },\n\t\t\tcertificates,\n\t\t\t...(allExecutionErrors.length > 0 ? { executionErrors: allExecutionErrors } : {}),\n\t\t},\n\t};\n}\n"],"mappings":"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"}
@@ -0,0 +1,316 @@
1
+ import { ErrorResult, Micro509Error } from "../result/result.js";
2
+ import { NameInput } from "../x509/name.js";
3
+ import { DistributionPoint, GeneralName, IssuingDistributionPoint } from "../x509/extensions.js";
4
+ import { ParsedCertificate, ParsedDistributionPoint, ParsedIssuingDistributionPoint, ParsedName } from "../x509/parse.js";
5
+
6
+ //#region src/revocation/crl.d.ts
7
+ /**
8
+ * Single revoked certificate entry for {@linkcode createCertificateRevocationList}.
9
+ */
10
+ interface RevokedCertificateInput {
11
+ /** DER-encoded certificate serial number to revoke. */
12
+ readonly serialNumber: Uint8Array;
13
+ /** When the certificate was revoked. Defaults to `thisUpdate` of the CRL. */
14
+ readonly revocationDate?: Date;
15
+ /** RFC 5280 CRLReason code. Omit for `unspecified`. */
16
+ readonly reasonCode?: RevocationReason;
17
+ /** When the key or certificate became suspect — may predate `revocationDate`. */
18
+ readonly invalidityDate?: Date;
19
+ }
20
+ /**
21
+ * RFC 5280 §5.3.1 CRLReason code values.
22
+ *
23
+ * `removeFromCRL` is used in delta CRLs to un-hold a certificate.
24
+ */
25
+ type RevocationReason = "unspecified" | "keyCompromise" | "cACompromise" | "affiliationChanged" | "superseded" | "cessationOfOperation" | "certificateHold" | "removeFromCRL" | "privilegeWithdrawn" | "aACompromise";
26
+ /**
27
+ * Input for {@linkcode createCertificateRevocationList}.
28
+ */
29
+ interface CreateCertificateRevocationListInput {
30
+ /** Distinguished name of the CRL issuer (typically the signing CA). */
31
+ readonly issuer: NameInput;
32
+ /** Private key used to sign the CRL. Algorithm is inferred from the key. */
33
+ readonly signerPrivateKey: CryptoKey;
34
+ /** Issuer public key — used to embed an Authority Key Identifier extension. */
35
+ readonly issuerPublicKey?: CryptoKey;
36
+ /** Issuance timestamp. Defaults to `new Date()`. */
37
+ readonly thisUpdate?: Date;
38
+ /** Planned next issuance. Omit for an open-ended CRL. */
39
+ readonly nextUpdate?: Date;
40
+ /** Certificates to list as revoked in this CRL. */
41
+ readonly revokedCertificates?: readonly RevokedCertificateInput[];
42
+ /** Monotonically-increasing CRL sequence number (CRLNumber extension). */
43
+ readonly crlNumber?: number;
44
+ /** If set, marks this CRL as a delta CRL referencing the given base CRL number. */
45
+ readonly baseCrlNumber?: number;
46
+ /** Issuing distribution point extension — scopes this CRL to a subset of certificates. */
47
+ readonly issuingDistributionPoint?: IssuingDistributionPoint;
48
+ /** Freshest CRL distribution points — tells relying parties where to find delta CRLs. */
49
+ readonly freshestCrlDistributionPoints?: readonly DistributionPoint[];
50
+ }
51
+ /**
52
+ * Encoded CRL in multiple serialisation formats, returned by {@linkcode createCertificateRevocationList}.
53
+ */
54
+ interface CertificateRevocationListMaterial {
55
+ /** Raw DER bytes of the signed CRL. */
56
+ readonly der: Uint8Array;
57
+ /** PEM-encoded CRL (`-----BEGIN X509 CRL-----`). */
58
+ readonly pem: string;
59
+ /** Base64-encoded DER (no PEM armour). */
60
+ readonly base64: string;
61
+ }
62
+ /**
63
+ * A single revoked-certificate entry decoded from a CRL.
64
+ */
65
+ interface ParsedRevokedCertificate {
66
+ /** Hex-encoded serial number of the revoked certificate. */
67
+ readonly serialNumberHex: string;
68
+ /** When the CA declared this certificate revoked. */
69
+ readonly revocationDate: Date;
70
+ /** RFC 5280 CRLReason, if the entry carries one. */
71
+ readonly reasonCode?: RevocationReason;
72
+ /** When the key or certificate actually became suspect, if present. */
73
+ readonly invalidityDate?: Date;
74
+ /** Indirect-CRL certificate issuer override (RFC 5280 §5.3.3). */
75
+ readonly certificateIssuer?: readonly GeneralName[];
76
+ }
77
+ /**
78
+ * Decoded X.509 CRL, returned by {@linkcode parseCertificateRevocationListDer}
79
+ * and {@linkcode parseCertificateRevocationListPem}.
80
+ */
81
+ interface ParsedCertificateRevocationList {
82
+ /** Original DER bytes when this object came from {@linkcode parseCertificateRevocationListDer} or PEM parsing. */
83
+ readonly der?: Uint8Array;
84
+ /** CRL version (1 = v1, 2 = v2 with extensions). */
85
+ readonly version: number;
86
+ /** DER-encoded TBSCertList — the signed payload for signature verification. */
87
+ readonly tbsCertListDer: Uint8Array;
88
+ /** Raw signature bytes from the CRL outer wrapper. */
89
+ readonly signatureValue: Uint8Array;
90
+ /** CRL issuer distinguished name. */
91
+ readonly issuer: ParsedName;
92
+ /** Start of the CRL validity window. */
93
+ readonly thisUpdate: Date;
94
+ /** End of the CRL validity window. Absent if the CA does not commit to a schedule. */
95
+ readonly nextUpdate?: Date;
96
+ /** OID of the algorithm used to sign this CRL. */
97
+ readonly signatureAlgorithmOid: string;
98
+ /** Human-readable signature algorithm name (e.g. `"ECDSA with SHA-256"`). */
99
+ readonly signatureAlgorithmName: string;
100
+ /** DER-encoded signature algorithm parameters (e.g. DER NULL for RSA PKCS#1 v1.5). */
101
+ readonly signatureAlgorithmParametersDer?: Uint8Array;
102
+ /** OID of the issuer's public key algorithm, when available. */
103
+ readonly issuerPublicKeyAlgorithmOid?: string;
104
+ /** OID of the issuer's public key parameters (e.g. named curve), when available. */
105
+ readonly issuerPublicKeyParametersOid?: string;
106
+ /** Hex-encoded Authority Key Identifier, if the extension is present. */
107
+ readonly authorityKeyIdentifier?: string;
108
+ /** CRLNumber extension value — monotonically increasing sequence number. */
109
+ readonly crlNumber?: number;
110
+ /** Delta CRL indicator — present only on delta CRLs, referencing the base CRL number. */
111
+ readonly baseCrlNumber?: number;
112
+ /** Issuing distribution point extension — scopes this CRL to a certificate subset. */
113
+ readonly issuingDistributionPoint?: ParsedIssuingDistributionPoint;
114
+ /** Freshest CRL extension — points to delta CRL locations. */
115
+ readonly freshestCrlDistributionPoints?: readonly ParsedDistributionPoint[];
116
+ /** All revoked certificate entries (empty array if none). */
117
+ readonly revokedCertificates: readonly ParsedRevokedCertificate[];
118
+ }
119
+ /** PEM string, DER bytes, or already-parsed CRL. */
120
+ type CrlSource = string | Uint8Array | ParsedCertificateRevocationList;
121
+ /** PEM string, DER bytes, or already-parsed certificate. */
122
+ type CrlCertificateSource = string | Uint8Array | ParsedCertificate;
123
+ /** Failure detail when CRL signature verification fails. */
124
+ interface VerifyCertificateRevocationListFailure extends Micro509Error<"signature_invalid"> {
125
+ /** Always `false` for failures. */
126
+ readonly ok: false;
127
+ }
128
+ /**
129
+ * Result of {@linkcode verifyCertificateRevocationList}.
130
+ *
131
+ * On success, `value` is the parsed CRL whose signature has been verified.
132
+ */
133
+ type VerifyCertificateRevocationListResult = {
134
+ readonly ok: true; /** Parsed CRL with a verified signature. */
135
+ readonly value: ParsedCertificateRevocationList;
136
+ } | ErrorResult<"signature_invalid", Record<never, never>, VerifyCertificateRevocationListFailure>;
137
+ /**
138
+ * Input for {@linkcode validateCertificateRevocationList}.
139
+ */
140
+ interface ValidateCertificateRevocationListInput {
141
+ /** The CRL to validate. */
142
+ readonly crl: CrlSource;
143
+ /** Certificate of the CA that should have signed the CRL. */
144
+ readonly issuerCertificate: CrlCertificateSource;
145
+ /** Evaluation time for freshness checks. Defaults to `new Date()`. */
146
+ readonly at?: Date;
147
+ /** Tolerance in milliseconds for clock skew when checking `thisUpdate`/`nextUpdate`. */
148
+ readonly clockSkewMs?: number;
149
+ }
150
+ /**
151
+ * Failure detail for {@linkcode validateCertificateRevocationList}.
152
+ *
153
+ * Possible codes: `signature_invalid`, `issuer_mismatch`, `stale_crl`, `crl_sign_not_permitted`.
154
+ */
155
+ interface ValidateCertificateRevocationListFailure extends Micro509Error<"signature_invalid" | "issuer_mismatch" | "stale_crl" | "crl_sign_not_permitted"> {
156
+ /** Always `false` for failures. */
157
+ readonly ok: false;
158
+ }
159
+ /**
160
+ * Result of {@linkcode validateCertificateRevocationList}.
161
+ *
162
+ * On success, the CRL has passed signature, issuer, key-usage, and freshness checks.
163
+ */
164
+ type ValidateCertificateRevocationListResult = {
165
+ readonly ok: true; /** Validated and parsed CRL. */
166
+ readonly value: ParsedCertificateRevocationList;
167
+ } | ErrorResult<"signature_invalid" | "issuer_mismatch" | "stale_crl" | "crl_sign_not_permitted", Record<never, never>, ValidateCertificateRevocationListFailure>;
168
+ /**
169
+ * Input for {@linkcode checkCertificateRevocationAgainstCrl}.
170
+ */
171
+ interface CheckCertificateRevocationAgainstCrlInput {
172
+ /** Certificate whose revocation status to check. */
173
+ readonly certificate: CrlCertificateSource;
174
+ /** Issuer of `certificate` — also expected signer of the CRL. */
175
+ readonly issuerCertificate: CrlCertificateSource;
176
+ /** Complete (base) CRL to check against. */
177
+ readonly crl: CrlSource;
178
+ /** Optional delta CRL for more recent revocation information. */
179
+ readonly deltaCrl?: CrlSource;
180
+ /** Evaluation time. Defaults to `new Date()`. */
181
+ readonly at?: Date;
182
+ /** Clock-skew tolerance in milliseconds for freshness checks. */
183
+ readonly clockSkewMs?: number;
184
+ }
185
+ /** Error codes that {@linkcode checkCertificateRevocationAgainstCrl} may return. */
186
+ type CheckCertificateRevocationAgainstCrlErrorCode = "signature_invalid" | "issuer_mismatch" | "stale_crl" | "crl_sign_not_permitted" | "non_applicable";
187
+ /** Structured reason why a CRL was deemed non-applicable to a given certificate. */
188
+ type CrlApplicabilityFailureReason = "certificate_scope_mismatch" | "delta_crl_incompatible" | "delta_crl_unsupported" | "distribution_point_mismatch" | "indirect_crl_unsupported" | "issuer_mismatch" | "reasons_mismatch";
189
+ /** Structured details attached to a {@linkcode CheckCertificateRevocationAgainstCrlFailure}. */
190
+ interface CheckCertificateRevocationAgainstCrlFailureDetails {
191
+ /** Why the CRL was non-applicable, when the error code is `non_applicable`. */
192
+ readonly reason?: CrlApplicabilityFailureReason;
193
+ }
194
+ /** Failure detail for {@linkcode checkCertificateRevocationAgainstCrl}. */
195
+ interface CheckCertificateRevocationAgainstCrlFailure extends Micro509Error<CheckCertificateRevocationAgainstCrlErrorCode, CheckCertificateRevocationAgainstCrlFailureDetails> {
196
+ /** Always `false` for failures. */
197
+ readonly ok: false;
198
+ }
199
+ /** Success value when the certificate is not found in the CRL. */
200
+ interface CheckCertificateRevocationAgainstCrlGoodValue {
201
+ /** Certificate is not revoked. */
202
+ readonly status: "good";
203
+ /** The validated CRL that was checked. */
204
+ readonly crl: ParsedCertificateRevocationList;
205
+ }
206
+ /** Success value when the certificate is found as revoked in the CRL. */
207
+ interface CheckCertificateRevocationAgainstCrlRevokedValue {
208
+ /** Certificate is revoked. */
209
+ readonly status: "revoked";
210
+ /** The validated CRL that contained the revocation entry. */
211
+ readonly crl: ParsedCertificateRevocationList;
212
+ /** When the CA declared this certificate revoked. */
213
+ readonly revocationDate: Date;
214
+ /** CRLReason from the entry, if present. */
215
+ readonly reasonCode?: RevocationReason;
216
+ }
217
+ /** Discriminated union of `good` and `revoked` outcomes. */
218
+ type CheckCertificateRevocationAgainstCrlValue = CheckCertificateRevocationAgainstCrlGoodValue | CheckCertificateRevocationAgainstCrlRevokedValue;
219
+ /**
220
+ * Result of {@linkcode checkCertificateRevocationAgainstCrl}.
221
+ *
222
+ * On success `value.status` is `'good'` or `'revoked'`.
223
+ * On failure the CRL could not be validated or was non-applicable.
224
+ */
225
+ type CheckCertificateRevocationAgainstCrlResult = {
226
+ readonly ok: true;
227
+ readonly value: CheckCertificateRevocationAgainstCrlValue;
228
+ } | ErrorResult<CheckCertificateRevocationAgainstCrlErrorCode, CheckCertificateRevocationAgainstCrlFailureDetails, CheckCertificateRevocationAgainstCrlFailure>;
229
+ /**
230
+ * Signs and encodes an X.509 v2 CRL.
231
+ *
232
+ * Embeds Authority Key Identifier, CRLNumber, delta CRL indicator,
233
+ * issuing distribution point, and freshest-CRL extensions as configured.
234
+ *
235
+ * @example
236
+ * ```ts
237
+ * import { createCertificateRevocationList } from 'micro509';
238
+ *
239
+ * const crl = await createCertificateRevocationList({
240
+ * issuer: { commonName: 'Example CA' },
241
+ * signerPrivateKey: caPrivateKey,
242
+ * issuerPublicKey: caPublicKey,
243
+ * thisUpdate: new Date('2025-01-01'),
244
+ * nextUpdate: new Date('2025-02-01'),
245
+ * crlNumber: 42,
246
+ * revokedCertificates: [
247
+ * { serialNumber: revokedSerial, reasonCode: 'keyCompromise' },
248
+ * ],
249
+ * });
250
+ * // crl.pem, crl.der, crl.base64
251
+ * ```
252
+ */
253
+ declare function createCertificateRevocationList(input: CreateCertificateRevocationListInput): Promise<CertificateRevocationListMaterial>;
254
+ /**
255
+ * Decodes a DER-encoded X.509 CRL into a structured {@linkcode ParsedCertificateRevocationList}.
256
+ *
257
+ * Does not verify the signature — call {@linkcode verifyCertificateRevocationList} or
258
+ * {@linkcode validateCertificateRevocationList} for that.
259
+ */
260
+ declare function parseCertificateRevocationListDer(der: Uint8Array): ParsedCertificateRevocationList;
261
+ /**
262
+ * Decodes a PEM-encoded X.509 CRL (`-----BEGIN X509 CRL-----`).
263
+ *
264
+ * @example
265
+ * ```ts
266
+ * import { parseCertificateRevocationListPem } from 'micro509';
267
+ *
268
+ * const crl = parseCertificateRevocationListPem(pemString);
269
+ * console.log(crl.issuer.values.commonName, crl.revokedCertificates.length);
270
+ * ```
271
+ */
272
+ declare function parseCertificateRevocationListPem(pem: string): ParsedCertificateRevocationList;
273
+ /**
274
+ * Verifies the CRL signature against the issuer certificate's public key.
275
+ *
276
+ * Does **not** check issuer name match, key-usage, or freshness — use
277
+ * {@linkcode validateCertificateRevocationList} for full validation.
278
+ */
279
+ declare function verifyCertificateRevocationList(crl: string | Uint8Array, issuerCertificate: string | Uint8Array): Promise<VerifyCertificateRevocationListResult>;
280
+ /**
281
+ * Full CRL validation: issuer name match, authority key identifier match,
282
+ * cRLSign key-usage check, signature verification, and `thisUpdate`/`nextUpdate`
283
+ * freshness check (with optional clock-skew tolerance).
284
+ */
285
+ declare function validateCertificateRevocationList(input: ValidateCertificateRevocationListInput): Promise<ValidateCertificateRevocationListResult>;
286
+ /**
287
+ * End-to-end revocation check: validates the CRL (and optional delta CRL),
288
+ * verifies applicability via distribution-point and scope matching, then
289
+ * resolves the certificate's revocation status.
290
+ *
291
+ * Returns `good` if the serial is absent, `revoked` with date/reason if present,
292
+ * or an error if the CRL cannot be validated or is non-applicable.
293
+ *
294
+ * @example
295
+ * ```ts
296
+ * import { checkCertificateRevocationAgainstCrl } from 'micro509';
297
+ *
298
+ * const result = await checkCertificateRevocationAgainstCrl({
299
+ * certificate: leafPem,
300
+ * issuerCertificate: caPem,
301
+ * crl: crlPem,
302
+ * });
303
+ * if (result.ok && result.value.status === 'revoked') {
304
+ * console.log('revoked on', result.value.revocationDate);
305
+ * }
306
+ * ```
307
+ */
308
+ declare function checkCertificateRevocationAgainstCrl(input: CheckCertificateRevocationAgainstCrlInput): Promise<CheckCertificateRevocationAgainstCrlResult>;
309
+ /**
310
+ * Quick serial-number lookup — returns `true` if the serial appears in the
311
+ * CRL's revoked entries. Does **not** validate the CRL or check applicability.
312
+ */
313
+ declare function isCertificateRevoked(certificateSerialNumber: Uint8Array | string, crl: ParsedCertificateRevocationList): boolean;
314
+ //#endregion
315
+ export { CertificateRevocationListMaterial, CheckCertificateRevocationAgainstCrlErrorCode, CheckCertificateRevocationAgainstCrlFailure, CheckCertificateRevocationAgainstCrlFailureDetails, CheckCertificateRevocationAgainstCrlGoodValue, CheckCertificateRevocationAgainstCrlInput, CheckCertificateRevocationAgainstCrlResult, CheckCertificateRevocationAgainstCrlRevokedValue, CheckCertificateRevocationAgainstCrlValue, CreateCertificateRevocationListInput, CrlApplicabilityFailureReason, CrlCertificateSource, CrlSource, ParsedCertificateRevocationList, ParsedRevokedCertificate, RevocationReason, RevokedCertificateInput, ValidateCertificateRevocationListFailure, ValidateCertificateRevocationListInput, ValidateCertificateRevocationListResult, VerifyCertificateRevocationListFailure, VerifyCertificateRevocationListResult, checkCertificateRevocationAgainstCrl, createCertificateRevocationList, isCertificateRevoked, parseCertificateRevocationListDer, parseCertificateRevocationListPem, validateCertificateRevocationList, verifyCertificateRevocationList };
316
+ //# sourceMappingURL=crl.d.ts.map
@@ -0,0 +1,2 @@
1
+ import{bitString as e,concatBytes as t,explicitContext as n,generalizedTime as r,implicitConstructedContext as i,implicitPrimitiveContext as a,integer as o,integerFromNumber as s,readElement as c,readRootElement as l,readSequenceChildren as u,sequence as d,time as f,tlv as p}from"../internal/asn1/der.js";import{childrenOf as m,decodeBoolean as ee,decodeIntegerNumber as h,decodeObjectIdentifier as g,decodeString as _,extractBitStringValue as v,hexToBytes as y,parseTime as b,requireElement as x,toHex as S}from"../internal/asn1/asn1.js";import{OIDS as C}from"../internal/asn1/oids.js";import{base64Encode as w}from"../internal/shared/base64.js";import{pemDecode as T,pemEncode as E}from"../pem/pem.js";import{exportSpkiDer as D}from"../keys/keys.js";import{describeSignatureAlgorithm as te}from"../internal/crypto/algorithm-names.js";import{decodeIpAddress as ne}from"../internal/shared/ip.js";import{encodeDistributionPointReasonFlagsContent as re,parseDistributionPointReasonFlagsContent as O}from"../internal/x509/extension-bits.js";import{nameFieldKeyFromOid as k}from"../internal/x509/name-fields.js";import{encodeName as ie,encodeRelativeDistinguishedName as ae}from"../x509/name.js";import{buildSubjectKeyIdentifier as oe,encodeCrlDistributionPoints as se,encodeExtension as A,encodeSubjectAltName as ce}from"../x509/extensions.js";import{parseCertificateDer as le,parseCertificateFromSource as j}from"../x509/parse.js";import{verifySignedDataDetailed as ue}from"../internal/crypto/sig-verify.js";import{compareDistinguishedNames as M,compareNameAttributeValue as de}from"../internal/shared/dn.js";import{encodeAlgorithmIdentifier as fe,getSignatureAlgorithm as pe,signBytes as me}from"../internal/crypto/signing.js";const he={unspecified:0,keyCompromise:1,cACompromise:2,affiliationChanged:3,superseded:4,cessationOfOperation:5,certificateHold:6,removeFromCRL:8,privilegeWithdrawn:9,aACompromise:10};async function ge(t){let r=pe(t.signerPrivateKey),i=t.thisUpdate??new Date,a=t.nextUpdate,o=await Me(t.issuerPublicKey,t.crlNumber,t.baseCrlNumber,t.issuingDistributionPoint,t.freshestCrlDistributionPoints),c=t.revokedCertificates??[],l=c.length===0?[]:[d(c.map(e=>Ne(e,i)))],u=d([s(1),fe(r),ie(t.issuer),f(i),...a===void 0?[]:[f(a)],...l,...o.length===0?[]:[n(0,d(o))]]),p=await me(t.signerPrivateKey,r,u),m=d([u,fe(r),e(p)]);return{der:m,pem:E(`X509 CRL`,m),base64:w(m)}}function N(e){let t=u(e,{maxDepth:64});if(t.length!==3)throw Error(`Malformed CRL`);let n=x(t[0],`TBSCertList`),r=x(t[1],`signatureAlgorithm`),i=x(t[2],`signatureValue`),a=tt(e.slice(n.start-n.headerLength,n.end)),o=Xe(e,r);return{der:new Uint8Array(e),version:a.version,tbsCertListDer:e.slice(n.start-n.headerLength,n.end),signatureValue:v(i),issuer:a.issuer,thisUpdate:a.thisUpdate,...a.nextUpdate===void 0?{}:{nextUpdate:a.nextUpdate},signatureAlgorithmOid:o.oid,signatureAlgorithmName:te(o.oid,o.parametersDer),...o.parametersDer===void 0?{}:{signatureAlgorithmParametersDer:o.parametersDer},...a.authorityKeyIdentifier===void 0?{}:{authorityKeyIdentifier:a.authorityKeyIdentifier},...a.crlNumber===void 0?{}:{crlNumber:a.crlNumber},...a.baseCrlNumber===void 0?{}:{baseCrlNumber:a.baseCrlNumber},...a.issuingDistributionPoint===void 0?{}:{issuingDistributionPoint:a.issuingDistributionPoint},...a.freshestCrlDistributionPoints===void 0?{}:{freshestCrlDistributionPoints:a.freshestCrlDistributionPoints},revokedCertificates:a.revokedCertificates}}function P(e){return N(T(`X509 CRL`,e))}async function _e(e,t){let n,r;try{n=typeof e==`string`?P(e):N(new Uint8Array(e)),r=typeof t==`string`?$e(t):Qe(new Uint8Array(t))}catch{return I(`signature_invalid`,`certificate revocation list or issuer certificate input is malformed`)}let i;try{i=await ue(n.signatureAlgorithmOid,n.signatureAlgorithmParametersDer,r.publicKeyAlgorithmOid,r.publicKeyParametersOid,r.subjectPublicKeyInfoDer,n.signatureValue,n.tbsCertListDer)}catch{return I(`signature_invalid`,`certificate revocation list signature verification failed`)}return i.ok?i.valid?{ok:!0,value:n}:I(`signature_invalid`,`certificate revocation list signature does not verify`):i.code===`verification_error`?I(`signature_invalid`,`certificate revocation list signature verification failed`):I(`signature_invalid`,`certificate revocation list signature uses unsupported algorithm parameters`)}async function F(e){let t;try{t=et(e.crl)}catch{return L(`signature_invalid`,`certificate revocation list signed content is malformed`)}let n;try{n=Q(e.issuerCertificate)}catch{return L(`signature_invalid`,`issuer certificate input is malformed`)}if(!M(t.issuer,n.subject))return L(`issuer_mismatch`,`CRL issuer name does not match certificate subject`);if(t.authorityKeyIdentifier!==void 0&&n.subjectKeyIdentifier!==void 0&&t.authorityKeyIdentifier!==n.subjectKeyIdentifier)return L(`issuer_mismatch`,`CRL authority key identifier does not match issuer subject key identifier`);if(n.keyUsage!==void 0&&!n.keyUsage.flags.includes(`cRLSign`))return L(`crl_sign_not_permitted`,`issuer certificate key usage does not permit CRL signing`);let r;try{r=await ue(t.signatureAlgorithmOid,t.signatureAlgorithmParametersDer,n.publicKeyAlgorithmOid,n.publicKeyParametersOid,n.subjectPublicKeyInfoDer,t.signatureValue,t.tbsCertListDer)}catch{return L(`signature_invalid`,`certificate revocation list signature verification failed`)}if(!r.ok)return r.code===`verification_error`?L(`signature_invalid`,`certificate revocation list signature verification failed`):L(`signature_invalid`,`certificate revocation list signature uses unsupported algorithm parameters`);if(!r.valid)return L(`signature_invalid`,`certificate revocation list signature does not verify`);let i=e.at??new Date,a=e.clockSkewMs??0;return t.thisUpdate.getTime()-a>i.getTime()||t.nextUpdate!==void 0&&t.nextUpdate.getTime()+a<i.getTime()?L(`stale_crl`,`CRL is not valid at requested time`):{ok:!0,value:t}}async function ve(e){let t;try{t=Q(e.certificate)}catch{return R(`non_applicable`,`certificate input is malformed`)}let n=await F({crl:e.crl,issuerCertificate:e.issuerCertificate,...e.at===void 0?{}:{at:e.at},...e.clockSkewMs===void 0?{}:{clockSkewMs:e.clockSkewMs}});if(!n.ok)return R(n.code,n.message);let r;if(e.deltaCrl!==void 0){let t=await F({crl:e.deltaCrl,issuerCertificate:e.issuerCertificate,...e.at===void 0?{}:{at:e.at},...e.clockSkewMs===void 0?{}:{clockSkewMs:e.clockSkewMs}});if(!t.ok)return R(t.code,t.message);let i=be(n.value,t.value);if(i!==void 0)return i;r=t.value}let i=V(t,n.value);if(i!==void 0)return i;if(r!==void 0){let e=V(t,r,!0);if(e!==void 0)return e}let a=B(t,n.value);if(!a.ok)return a;let o;if(r!==void 0){let e=B(t,r);if(!e.ok)return e;o=e.entry}return Ce(t,e.at??new Date,n.value,a.entry,o)}function I(e,t){return{ok:!1,error:{ok:!1,code:e,message:t},code:e,message:t}}function L(e,t){return{ok:!1,error:{ok:!1,code:e,message:t},code:e,message:t}}function R(e,t,n){return{ok:!1,error:{ok:!1,code:e,message:t,...n===void 0?{}:{details:n}},code:e,message:t,...n===void 0?{}:{details:n}}}function z(e){return{ok:!0,value:e}}function ye(e,t){let n=typeof e==`string`?Z(e):S(e);return t.revokedCertificates.some(e=>Z(e.serialNumberHex)===n)}function B(e,t){let n=Z(e.serialNumberHex),r,i=!1,a;for(let o of t.revokedCertificates){if(o.certificateIssuer!==void 0&&(r=o.certificateIssuer),Z(o.serialNumberHex)!==n)continue;let s=Se(e,t,r);if(s===`match`){if(a!==void 0)return R(`signature_invalid`,`CRL contains multiple revoked entries for certificate`);a=o;continue}s===`unsupported`&&(i=!0)}return a===void 0?i?H(`indirect_crl_unsupported`,`indirect CRL entry certificateIssuer must include a directoryName`):{ok:!0}:{ok:!0,entry:a}}function V(e,t,n=!1){if(!n&&t.baseCrlNumber!==void 0)return H(`delta_crl_unsupported`,`a delta CRL cannot be used as the primary complete CRL input`);let r=t.issuingDistributionPoint,i=r?.indirectCrl===!0;if(!i&&!M(e.issuer,t.issuer))return H(`issuer_mismatch`,`CRL issuer does not match certificate issuer for direct CRL processing`);if(r?.onlyContainsAttributeCerts===!0)return H(`certificate_scope_mismatch`,`attribute-certificate-only CRLs are not applicable to public-key certificates`);let a=e.basicConstraints?.ca===!0;if(r?.onlyContainsUserCerts===!0&&a)return H(`certificate_scope_mismatch`,`CRL only applies to end-entity certificates`);if(r?.onlyContainsCACerts===!0&&!a)return H(`certificate_scope_mismatch`,`CRL only applies to CA certificates`);let o=e.crlDistributionPoints??[];if(o.length===0)return r?.distributionPoint===void 0?i&&!M(e.issuer,t.issuer)?H(`issuer_mismatch`,`indirect CRLs for alternate certificate issuers require matching CRLIssuer distribution points`):void 0:H(`distribution_point_mismatch`,`certificates without CRL distribution points only accept full-scope CRLs`);let s=!1,c=!1,l=!1,u=!1,d=!1;for(let n of o){if(!i&&n.crlIssuer!==void 0){s=!0;continue}if(i&&(!M(e.issuer,t.issuer)||n.crlIssuer!==void 0)){let e=xe(n.crlIssuer,t);if(e===`unsupported`){u=!0;continue}if(!e){l=!0;continue}}if(!we(n.distributionPoint,r?.distributionPoint,t.issuer)){c=!0;continue}if(!Ae(n.reasons,r?.onlySomeReasons)){d=!0;continue}return}return d?H(`reasons_mismatch`,`certificate distribution point reasons do not overlap the CRL reason scope`):u?H(`indirect_crl_unsupported`,`indirect CRL distribution points must identify the CRL issuer with directoryName`):l?H(`issuer_mismatch`,`certificate distribution points do not authorize this indirect CRL issuer`):c?H(`distribution_point_mismatch`,`certificate distribution points do not match the CRL issuing distribution point`):s?H(`indirect_crl_unsupported`,`certificate distribution points that name alternate CRL issuers are not supported yet`):H(`distribution_point_mismatch`,`certificate distribution points do not match the CRL scope`)}function be(e,t){if(e.baseCrlNumber!==void 0)return H(`delta_crl_incompatible`,`complete CRL input must not itself be a delta CRL`);if(t.baseCrlNumber===void 0)return H(`delta_crl_incompatible`,`delta CRL input must include a delta CRL indicator`);if(!M(e.issuer,t.issuer))return H(`delta_crl_incompatible`,`complete and delta CRLs must share the same issuer`);if(e.authorityKeyIdentifier!==t.authorityKeyIdentifier)return H(`delta_crl_incompatible`,`complete and delta CRLs must share the same authority key identifier`);if(!Ee(e.issuingDistributionPoint,t.issuingDistributionPoint))return H(`delta_crl_incompatible`,`complete and delta CRLs must share the same issuing distribution point scope`);if(e.crlNumber===void 0||t.crlNumber===void 0)return H(`delta_crl_incompatible`,`complete and delta CRLs must both carry CRL numbers for delta processing`);if(e.crlNumber<t.baseCrlNumber)return H(`delta_crl_incompatible`,`delta CRL base number must not exceed the complete CRL number`);if(e.crlNumber>=t.crlNumber)return H(`delta_crl_incompatible`,`delta CRL number must be newer than the complete CRL number`)}function xe(e,t){if(e===void 0)return!1;let n=!1;for(let r of e){if(r.type===`directoryName`){if(X(r.derHex,t.issuer))return!0;continue}n=!0}return n?`unsupported`:!1}function Se(e,t,n){if(n===void 0)return M(e.issuer,t.issuer)?`match`:`mismatch`;let r=!1;for(let t of n){if(t.type===`directoryName`){if(X(t.derHex,e.issuer))return`match`;continue}r=!0}return r?`unsupported`:`mismatch`}function H(e,t){return R(`non_applicable`,t,{reason:e})}function Ce(e,t,n,r,i){if(i!==void 0)if(i.reasonCode===`removeFromCRL`){if(r?.reasonCode===`certificateHold`||e.notAfter.getTime()<t.getTime())return z({status:`good`,crl:n})}else return z({status:`revoked`,crl:n,revocationDate:i.revocationDate,...i.reasonCode===void 0?{}:{reasonCode:i.reasonCode}});return z(r===void 0?{status:`good`,crl:n}:{status:`revoked`,crl:n,revocationDate:r.revocationDate,...r.reasonCode===void 0?{}:{reasonCode:r.reasonCode}})}function we(e,t,n){if(t===void 0)return!0;if(e===void 0)return!1;if(e.fullName!==void 0&&t.fullName!==void 0)return e.fullName.some(e=>t.fullName?.some(t=>W(e,t))===!0);if(e.relativeName!==void 0&&t.fullName!==void 0){let r=U(n,e.relativeName);return t.fullName.some(e=>e.type===`directoryName`&&e.derHex===r)}if(e.relativeName!==void 0&&t.relativeName!==void 0)return G(e.relativeName,t.relativeName);if(e.fullName!==void 0&&t.relativeName!==void 0){let r=U(n,t.relativeName);return e.fullName.some(e=>e.type===`directoryName`&&e.derHex===r)}return!1}function U(e,t){let n=e.rdns.map(e=>y(e.derHex)),r=Te(y(t.derHex));return n.push(r),S(d(n))}function Te(e){return p(49,l(e,{maxDepth:64}).value)}function Ee(e,t){return e===void 0||t===void 0?e===t:De(e.distributionPoint,t.distributionPoint)&&e.onlyContainsUserCerts===!0==(t.onlyContainsUserCerts===!0)&&e.onlyContainsCACerts===!0==(t.onlyContainsCACerts===!0)&&e.indirectCrl===!0==(t.indirectCrl===!0)&&e.onlyContainsAttributeCerts===!0==(t.onlyContainsAttributeCerts===!0)&&ke(e.onlySomeReasons,t.onlySomeReasons)}function De(e,t){return e===void 0||t===void 0?e===t:e.fullName!==void 0||t.fullName!==void 0?e.fullName===void 0||t.fullName===void 0?!1:Oe(e.fullName,t.fullName):e.relativeName===void 0||t.relativeName===void 0?!1:G(e.relativeName,t.relativeName)}function Oe(e,t){if(e.length!==t.length)return!1;let n=Array(t.length).fill(!1);for(let r of e){let e=!1;for(let i=0;i<t.length;i+=1){let a=t[i];if(!(a===void 0||n[i])&&W(r,a)){n[i]=!0,e=!0;break}}if(!e)return!1}return!0}function ke(e,t){return e===void 0||t===void 0?e===t:e.flags.length===t.flags.length?e.flags.every(e=>t.flags.includes(e)):!1}function Ae(e,t){return e===void 0||t===void 0?!0:e.flags.some(e=>t.flags.includes(e))}function W(e,t){if(e.type===`dns`&&t.type===`dns`||e.type===`email`&&t.type===`email`||e.type===`ip`&&t.type===`ip`||e.type===`uri`&&t.type===`uri`)return e.value===t.value;if(e.type===`directoryName`&&t.type===`directoryName`){let n=Y(e.derHex),r=Y(t.derHex);return n===void 0||r===void 0?!1:M(n,r)}return e.type===`unknown`&&t.type===`unknown`?e.tag===t.tag&&je(e.value,t.value):!1}function je(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length;n+=1)if(e[n]!==t[n])return!1;return!0}function G(e,t){if(e.attributes.length!==t.attributes.length)return!1;let n=Array(t.attributes.length).fill(!1);for(let r of e.attributes){let e=!1;for(let i=0;i<t.attributes.length;i+=1){let a=t.attributes[i];if(!(a===void 0||n[i])&&de(r,a)){n[i]=!0,e=!0;break}}if(!e)return!1}return!0}async function Me(e,t,n,r,i){let o=[];if(e!==void 0){let t=await D(e);o.push(A(C.authorityKeyIdentifier,d([a(0,oe(t))])))}return t!==void 0&&o.push(A(C.cRLNumber,s(t))),n!==void 0&&o.push(A(C.deltaCRLIndicator,s(n),!0)),r!==void 0&&o.push(A(C.issuingDistributionPoint,He(r),!0)),i!==void 0&&i.length>0&&o.push(A(C.freshestCRL,se(i))),o}function Ne(e,t){let n=Pe(e);return d([o(e.serialNumber),f(e.revocationDate??t),...n.length===0?[]:[d(n)]])}function Pe(e){let t=[];return e.reasonCode!==void 0&&t.push(A(C.cRLReason,p(10,Uint8Array.of(he[e.reasonCode])))),e.invalidityDate!==void 0&&t.push(A(C.invalidityDate,r(e.invalidityDate))),t}function Fe(e,t){if(e===void 0||t===void 0)return{};let n,r,i,a=new Set;for(let o of m(e,t)){let t=m(e,o);if(t.length<2||t.length>3||t.length===3&&t[1]?.tag!==1)throw Error(`Malformed revoked certificate extension`);let s=g(x(t[0],`revoked certificate extension OID`).value);if(a.has(s))throw Error(`Duplicate revoked certificate extension OID: ${s}`);a.add(s);let u=x(t[t.length-1],`revoked certificate extension value`);if(u.tag!==4)throw Error(`Revoked certificate extension value must use OCTET STRING`);if(s===C.cRLReason&&(n=Ze(c(u.value).value[0])),s===C.invalidityDate&&(r=b(c(u.value))),s===C.certificateIssuer){let e=l(u.value,{maxDepth:64});if(e.tag!==48)throw Error(`certificateIssuer must use SEQUENCE`);i=q(u.value,e)}}return{...n===void 0?{}:{reasonCode:n},...r===void 0?{}:{invalidityDate:r},...i===void 0?{}:{certificateIssuer:i}}}function Ie(e){let t=l(e,{maxDepth:64}),n,r,i,a,o,s;for(let c of m(e,t))if(c.tag===160){if(n!==void 0)throw Error(`IssuingDistributionPoint distributionPoint must not repeat`);let t=K(e,c);t!==void 0&&(n=t)}else if(c.tag===129){if(r!==void 0)throw Error(`IssuingDistributionPoint onlyContainsUserCerts must not repeat`);r=J(c)}else if(c.tag===130){if(i!==void 0)throw Error(`IssuingDistributionPoint onlyContainsCACerts must not repeat`);i=J(c)}else if(c.tag===131){if(a!==void 0)throw Error(`IssuingDistributionPoint onlySomeReasons must not repeat`);a=O(c.value)}else if(c.tag===132){if(o!==void 0)throw Error(`IssuingDistributionPoint indirectCrl must not repeat`);o=J(c)}else if(c.tag===133){if(s!==void 0)throw Error(`IssuingDistributionPoint onlyContainsAttributeCerts must not repeat`);s=J(c)}else throw Error(`Unsupported IssuingDistributionPoint field tag: ${String(c.tag)}`);if([r,i,s].filter(e=>e===!0).length>1)throw Error(`IssuingDistributionPoint scope booleans are mutually exclusive`);return{...n===void 0?{}:{distributionPoint:n},...r===void 0?{}:{onlyContainsUserCerts:r},...i===void 0?{}:{onlyContainsCACerts:i},...a===void 0?{}:{onlySomeReasons:a},...o===void 0?{}:{indirectCrl:o},...s===void 0?{}:{onlyContainsAttributeCerts:s}}}function Le(e){let t=l(e,{maxDepth:64});if(t.tag!==48)throw Error(`DistributionPoints must use SEQUENCE`);let n=m(e,t);if(n.length===0)throw Error(`DistributionPoints must not be empty`);return n.map(t=>Re(e,t))}function K(e,t){let n=m(e,t);if(n.length!==1)throw Error(`distributionPointName must contain exactly one choice`);let r=x(n[0],`distributionPointName`);if(r.tag===160){let t=m(e,r);if(t.length===0)throw Error(`distributionPointName fullName must not be empty`);for(let e of t)if((e.tag&192)!=128)throw Error(`distributionPointName fullName must contain GeneralName entries`);return{fullName:t.map(e=>ze(e))}}if(r.tag===161)return{relativeName:Be(e,r)};throw Error(`Unsupported distributionPointName tag: ${String(r.tag)}`)}function Re(e,t){if(t.tag!==48)throw Error(`DistributionPoint must use SEQUENCE`);let n,r,i;for(let a of m(e,t))if(a.tag===160){if(n!==void 0)throw Error(`DistributionPoint distributionPoint must not repeat`);let t=K(e,a);t!==void 0&&(n=t)}else if(a.tag===129){if(r!==void 0)throw Error(`DistributionPoint reasons must not repeat`);r=O(a.value)}else if(a.tag===162){if(i!==void 0)throw Error(`DistributionPoint crlIssuer must not repeat`);i=q(e,a)}else throw Error(`Unsupported DistributionPoint field tag: ${String(a.tag)}`);if(n===void 0&&i===void 0)throw Error(`DistributionPoint must include distributionPoint or crlIssuer`);return{...n===void 0?{}:{distributionPoint:n},...r===void 0?{}:{reasons:r},...i===void 0?{}:{crlIssuer:i}}}function ze(e){switch(e.tag){case 129:return{type:`email`,value:$.decode(e.value)};case 130:return{type:`dns`,value:$.decode(e.value)};case 134:return{type:`uri`,value:$.decode(e.value)};case 135:return{type:`ip`,value:ne(e.value)};case 164:return{type:`directoryName`,derHex:S(Ge(e))};default:return{type:`unknown`,tag:e.tag,value:new Uint8Array(e.value)}}}function q(e,t){let n=m(e,t);if(n.length===0)throw Error(`GeneralNames must not be empty`);for(let e of n)if((e.tag&192)!=128)throw Error(`GeneralNames must contain GeneralName entries`);return n.map(e=>ze(e))}function Be(e,t){let n=[],r={};for(let i of m(e,t)){let t=m(e,i),a=g(x(t[0],`name OID`).value),o=x(t[1],`name value`),s=k(a),c=Ve(o),l=s===void 0?{oid:a,valueTag:o.tag,value:c}:{oid:a,key:s,valueTag:o.tag,value:c};n.push(l),s!==void 0&&r[s]===void 0&&(r[s]=c)}return{derHex:S(e.slice(t.start-t.headerLength,t.end)),attributes:n,values:r}}function Ve(e){return _(e.tag,e.value)}function J(e){return(e.value[0]??0)!==0}function He(e){if([e.onlyContainsUserCerts===!0,e.onlyContainsCACerts===!0,e.onlyContainsAttributeCerts===!0].filter(Boolean).length>1)throw Error(`IssuingDistributionPoint can assert at most one of user, CA, or attribute cert scope`);let t=[];return e.distributionPoint!==void 0&&t.push(i(0,Ue(e.distributionPoint))),e.onlyContainsUserCerts&&t.push(a(1,Uint8Array.of(255))),e.onlyContainsCACerts&&t.push(a(2,Uint8Array.of(255))),e.onlySomeReasons!==void 0&&e.onlySomeReasons.length>0&&t.push(a(3,re(e.onlySomeReasons))),e.indirectCrl&&t.push(a(4,Uint8Array.of(255))),e.onlyContainsAttributeCerts&&t.push(a(5,Uint8Array.of(255))),d(t)}function Ue(e){if(e===void 0)throw Error(`IssuingDistributionPoint distributionPoint is required`);if(e.fullName!==void 0&&e.relativeName!==void 0)throw Error(`DistributionPointName cannot contain both fullName and relativeName`);if(e.fullName!==void 0){if(e.fullName.length===0)throw Error(`DistributionPointName fullName must not be empty`);return i(0,We(e.fullName))}if(e.relativeName!==void 0){let t=ae(e.relativeName),n=c(t);return i(1,t.slice(n.start,n.end))}throw Error(`DistributionPointName must contain fullName or relativeName`)}function We(e){return t(e.map(e=>ce(e)))}function Ge(e){return e.value.length>0&&e.value[0]===48?new Uint8Array(e.value):p(48,e.value)}function Ke(e,t){let n=S(e.slice(t.start-t.headerLength,t.end)),r=[],i=[],a={};for(let n of m(e,t)){let t=[],o={};for(let r of m(e,n)){let n=m(e,r),s=x(n[0],`issuer attribute OID`),c=x(n[1],`issuer attribute value`),l=g(s.value),u;try{u=_(c.tag,c.value)}catch{u=$.decode(c.value)}let d=k(l),f=d===void 0?{oid:l,valueTag:c.tag,value:u}:{oid:l,key:d,valueTag:c.tag,value:u};t.push(f),i.push(f),d!==void 0&&(o[d]===void 0&&(o[d]=u),a[d]===void 0&&(a[d]=u))}r.push({derHex:S(e.slice(n.start-n.headerLength,n.end)),attributes:t,values:o})}return{derHex:n,rdns:r,attributes:i,values:a}}function Y(e){try{let t=y(e),n=qe(t,l(t,{maxDepth:64}));return n.tag===48?Ke(t,n):void 0}catch{return}}function qe(e,t){if(t.tag!==48)return t;let n=m(e,t),r=n[0];return n.length===1&&r?.tag===48?r:t}function X(e,t){let n=Y(e);return n===void 0?!1:M(n,t)}function Je(e){let t=l(e,{maxDepth:64,allowOpaqueConstructedTags:[161,162]});if(t.tag!==48)throw Error(`authorityKeyIdentifier must use SEQUENCE`);let n,r=!1,i=!1,a=-1;for(let o of m(e,t)){if(o.tag===128){if(n!==void 0)throw Error(`authorityKeyIdentifier keyIdentifier must not repeat`);if(a>=0)throw Error(`authorityKeyIdentifier fields must preserve DER order`);n=S(o.value),a=0;continue}if(o.tag===161){if(r)throw Error(`authorityKeyIdentifier authorityCertIssuer must not repeat`);if(a>=1)throw Error(`authorityKeyIdentifier fields must preserve DER order`);q(e,o),r=!0,a=1;continue}if(o.tag===130){if(i)throw Error(`authorityKeyIdentifier authorityCertSerialNumber must not repeat`);if(a>=2||!r)throw Error(`authorityKeyIdentifier fields must preserve DER order`);Ye(o.value,`authorityKeyIdentifier authorityCertSerialNumber`),i=!0,a=2;continue}throw Error(`Unsupported authorityKeyIdentifier field tag: ${String(o.tag)}`)}return n}function Ye(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`)}function Xe(e,t){let n=m(e,t),r=x(n[0],`algorithm OID`),i=n[1];return i===void 0?{oid:g(r.value)}:{oid:g(r.value),parametersDer:e.slice(i.start-i.headerLength,i.end)}}function Z(e){return e.toLowerCase()}function Ze(e){switch(e){case 0:return`unspecified`;case 1:return`keyCompromise`;case 2:return`cACompromise`;case 3:return`affiliationChanged`;case 4:return`superseded`;case 5:return`cessationOfOperation`;case 6:return`certificateHold`;case 8:return`removeFromCRL`;case 9:return`privilegeWithdrawn`;case 10:return`aACompromise`}}function Qe(e){return j(e)}function $e(e){return j(e)}function et(e){if(typeof e==`string`)return P(e);if(e instanceof Uint8Array)return N(new Uint8Array(e));if(rt(e))return N(new Uint8Array(e.der));throw Error(`certificate revocation list input is malformed`)}function tt(e){let t=m(e,l(e,{maxDepth:64})),n=0,r=1,i=t[n];if(i!==void 0&&i.tag!==2&&i.tag!==48)throw Error(`version must use INTEGER`);if(i?.tag===2){let e=x(t[n],`version`);if(e.tag!==2)throw Error(`version must use INTEGER`);if(r=h(e.value)+1,r!==2)throw Error(`Unsupported CRL version: ${String(r)}`);n+=1}n+=1;let a=x(t[n],`issuer`),o=x(t[n+1],`thisUpdate`),s=n+2,d=t[s],f=d!==void 0&&(d.tag===23||d.tag===24)?b(d):void 0;f!==void 0&&(s+=1);let p=[],_=t[s];_?.tag===48&&(p=m(e,_).map(t=>{let n=e.slice(t.start-t.headerLength,t.end),i=u(n),a=x(i[0],`revoked serialNumber`);if(a.tag!==2)throw Error(`revoked serialNumber must use INTEGER`);let o=i[2];if(o!==void 0&&r!==2)throw Error(`revoked certificate extensions require CRL version 2`);let s=Fe(n,o);return{serialNumberHex:S(a.value),revocationDate:b(x(i[1],`revocationDate`)),...s.reasonCode===void 0?{}:{reasonCode:s.reasonCode},...s.invalidityDate===void 0?{}:{invalidityDate:s.invalidityDate},...s.certificateIssuer===void 0?{}:{certificateIssuer:s.certificateIssuer}}}),s+=1);let v,y,w,T,E,D=t[s];if(D?.tag===160){if(r!==2)throw Error(`CRL extensions require version 2`);let t=new Set,n=x(m(e,D)[0],`crl extensions`);for(let r of m(e,n)){let n=m(e,r);if(n.length<2||n.length>3||n.length===3&&n[1]?.tag!==1)throw Error(`Malformed CRL extension`);let i=g(x(n[0],`extension OID`).value);if(t.has(i))throw Error(`Duplicate CRL extension OID: ${i}`);t.add(i);let a=n.length===3?ee(x(n[1],`extension critical`).value):!1,o=x(n[n.length-1],`extension value`);if(o.tag!==4)throw Error(`CRL extension value must use OCTET STRING`);if(i!==C.authorityKeyIdentifier&&i!==C.cRLNumber&&i!==C.deltaCRLIndicator&&i!==C.issuingDistributionPoint&&i!==C.freshestCRL&&a)throw Error(`Unsupported critical CRL extension OID: ${i}`);i===C.authorityKeyIdentifier&&(v=Je(o.value)),i===C.cRLNumber&&(y=h(c(o.value).value)),i===C.deltaCRLIndicator&&(w=h(c(o.value).value)),i===C.issuingDistributionPoint&&(T=Ie(o.value)),i===C.freshestCRL&&(E=Le(o.value))}}return{version:r,issuer:Ke(e,a),thisUpdate:b(o),...f===void 0?{}:{nextUpdate:f},...v===void 0?{}:{authorityKeyIdentifier:v},...y===void 0?{}:{crlNumber:y},...w===void 0?{}:{baseCrlNumber:w},...T===void 0?{}:{issuingDistributionPoint:T},...E===void 0?{}:{freshestCrlDistributionPoints:E},revokedCertificates:p}}function Q(e){return nt(e)?le(new Uint8Array(e.der)):j(e)}function nt(e){return typeof e!=`string`&&`subjectPublicKeyInfoDer`in e}function rt(e){return`der`in e&&e.der instanceof Uint8Array}const $=new TextDecoder;export{ve as checkCertificateRevocationAgainstCrl,ge as createCertificateRevocationList,ye as isCertificateRevoked,N as parseCertificateRevocationListDer,P as parseCertificateRevocationListPem,F as validateCertificateRevocationList,_e as verifyCertificateRevocationList};
2
+ //# sourceMappingURL=crl.js.map