{"version":3,"file":"X509CertificateRevocationList.mjs","names":["AsnIssuingDistributionPoint"],"sources":["../../../src/modules/x509/X509CertificateRevocationList.ts"],"sourcesContent":["import { AsnParser } from '@peculiar/asn1-schema'\nimport { IssuingDistributionPoint as AsnIssuingDistributionPoint, BaseCRLNumber, CRLNumber } from '@peculiar/asn1-x509'\nimport * as x509 from '@peculiar/x509'\nimport {\n  CredoWebCrypto,\n  CredoWebCryptoKey,\n  jwaAlgorithmToKeySignParams,\n  publicJwkToCryptoKeyAlgorithm,\n} from '../../crypto/webcrypto'\nimport {\n  convertName,\n  createAuthorityKeyIdentifierExtension,\n  createCrlEntryCertificateIssuerExtension,\n  createCrlNumberExtension,\n  createDeltaCrlIndicatorExtension,\n  createIssuingDistributionPointExtension,\n  X509CrlExtensionIdentifier,\n  x509SignatureAlgorithmToJwa,\n} from './utils'\nimport { normalizeSerialNumber } from './utils/serialNumber'\nimport { X509Certificate, X509KeyUsage } from './X509Certificate'\nimport type { X509RevocationReason } from './X509CrlDistributionPoint'\nimport { X509Error } from './X509Error'\nimport type { X509CreateCertificateRevocationListOptions } from './X509ServiceOptions'\n\n/**\n * Reason a certificate was revoked, as carried in a CRL entry's `reasonCode` extension\n * (RFC 5280 §5.3.1 `CRLReason`).\n */\nexport enum X509CertificateRevocationListEntryReason {\n  Unused = 0,\n  KeyCompromise = 1,\n  CACompromise = 2,\n  AffiliationChanged = 3,\n  Superseded = 4,\n  CessationOfOperation = 5,\n  CertificateHold = 6,\n  RemoveFromCrl = 8,\n  PrivilegeWithdrawn = 9,\n  AACompromise = 10,\n}\n\nexport interface X509CertificateRevocationListEntry {\n  serialNumber: string\n  revocationDate: Date\n  reason?: X509CertificateRevocationListEntryReason\n}\n\n/**\n * Parsed Issuing Distribution Point CRL extension (RFC 5280 §5.2.5), describing the scope of a CRL.\n */\nexport interface X509IssuingDistributionPoint {\n  /** Distribution point name as a list of URIs (other GeneralName forms are ignored). */\n  fullName: string[]\n  /** Whether the CRL only covers end-entity certificates. */\n  onlyContainsUserCerts: boolean\n  /** Whether the CRL only covers CA certificates. */\n  onlyContainsCACerts: boolean\n  /** The revocation reasons this CRL is limited to (reasonFlags bits), if scoped. */\n  onlySomeReasons?: X509RevocationReason[]\n  /** Whether this is an indirect CRL (entries may carry a `certificateIssuer`). */\n  indirectCRL: boolean\n  /** Whether the CRL only covers attribute certificates. */\n  onlyContainsAttributeCerts: boolean\n}\n\n/**\n * Byte-for-byte equality of two `Uint8Array`s.\n */\nfunction uint8ArraysEqual(a: Uint8Array, b: Uint8Array): boolean {\n  if (a.length !== b.length) return false\n  for (let i = 0; i < a.length; i++) {\n    if (a[i] !== b[i]) return false\n  }\n  return true\n}\n\n/**\n * Wrapper class for X.509 Certificate Revocation List (CRL)\n * Provides a clean interface over the @peculiar/x509 CRL implementation\n */\nexport class X509CertificateRevocationList {\n  private crl: x509.X509Crl\n\n  private constructor(crl: x509.X509Crl) {\n    this.crl = crl\n  }\n\n  /**\n   * Parse a CRL from raw bytes\n   */\n  public static fromRaw(rawCrl: Uint8Array): X509CertificateRevocationList {\n    try {\n      const crl = new x509.X509Crl(rawCrl)\n      return new X509CertificateRevocationList(crl)\n    } catch (error) {\n      throw new X509Error('Failed to parse CRL', { cause: error instanceof Error ? error : undefined })\n    }\n  }\n\n  /**\n   * Parse a CRL from PEM or base64 encoded string\n   */\n  public static fromEncoded(encodedCrl: string): X509CertificateRevocationList {\n    try {\n      const crl = new x509.X509Crl(encodedCrl)\n      return new X509CertificateRevocationList(crl)\n    } catch (error) {\n      throw new X509Error('Failed to parse encoded CRL', { cause: error instanceof Error ? error : undefined })\n    }\n  }\n\n  /**\n   * Create and sign a new CRL.\n   *\n   * Supports the CRL Number, Authority Key Identifier and Issuing Distribution Point extensions, as\n   * well as indirect CRLs (per-entry `certificateIssuer`). See `options.extensions` / entry options.\n   *\n   * NOTE: indirect CRLs and CRLs whose Issuing Distribution Point scope does not cover the\n   * certificate being checked are rejected during revocation checking (delta CRLs are likewise not\n   * processed), so such CRLs are not treated as authoritative proof that a certificate is unrevoked.\n   */\n  public static async create(\n    options: X509CreateCertificateRevocationListOptions,\n    webCrypto: CredoWebCrypto\n  ): Promise<X509CertificateRevocationList> {\n    const signingKey = new CredoWebCryptoKey(\n      options.authorityKey,\n      publicJwkToCryptoKeyAlgorithm(options.authorityKey),\n      false,\n      'private',\n      ['sign']\n    )\n\n    const entries = options.entries?.map((entry) => {\n      const serialNumber = entry.serialNumber ?? entry.certificate?.data.serialNumber\n      if (!serialNumber) {\n        throw new X509Error('A CRL entry must provide either a serialNumber or a certificate')\n      }\n\n      return {\n        serialNumber,\n        revocationDate: entry.revocationDate,\n        // X509CrlEntryReason mirrors @peculiar/x509's X509CrlReason (RFC 5280 CRLReason) values.\n        reason: entry.reason === undefined ? undefined : (entry.reason as number as x509.X509CrlReason),\n        // For indirect CRLs, the certificateIssuer is carried as a (critical) CRL entry extension.\n        extensions: entry.issuer === undefined ? undefined : [createCrlEntryCertificateIssuerExtension(entry.issuer)],\n      } satisfies x509.X509CrlEntryParams\n    })\n\n    const extensions: Array<x509.Extension | undefined> = [\n      createCrlNumberExtension(options.extensions?.crlNumber),\n      createDeltaCrlIndicatorExtension(options.extensions?.deltaCrlIndicator),\n      createAuthorityKeyIdentifierExtension(options.extensions?.authorityKeyIdentifier, {\n        publicJwk: options.authorityKey,\n      }),\n      createIssuingDistributionPointExtension(options.extensions?.issuingDistributionPoint),\n    ]\n\n    const crl = await x509.X509CrlGenerator.create(\n      {\n        issuer: convertName(options.issuer),\n        thisUpdate: options.validity?.thisUpdate,\n        nextUpdate: options.validity?.nextUpdate,\n        signingKey,\n        signingAlgorithm: jwaAlgorithmToKeySignParams(options.authorityKey.signatureAlgorithm),\n        entries,\n        extensions: extensions.filter((extension): extension is x509.Extension => extension !== undefined),\n      },\n      webCrypto\n    )\n\n    return new X509CertificateRevocationList(crl)\n  }\n\n  /**\n   * Get the raw CRL data\n   */\n  public get rawCertificateRevocationList(): Uint8Array {\n    return new Uint8Array(this.crl.rawData)\n  }\n\n  /**\n   * Get the issuer of the CRL\n   */\n  public get issuer(): string {\n    return this.crl.issuer\n  }\n\n  /**\n   * Get the date this CRL was issued\n   */\n  public get thisUpdate(): Date {\n    return this.crl.thisUpdate\n  }\n\n  /**\n   * Get the date when the next CRL will be published\n   */\n  public get nextUpdate(): Date | undefined {\n    return this.crl.nextUpdate\n  }\n\n  /**\n   * Check if the CRL has expired (past nextUpdate date)\n   */\n  public isExpired(date = new Date()): boolean {\n    return this.nextUpdate ? date > this.nextUpdate : false\n  }\n\n  /**\n   * Check if the CRL is not yet valid (before its thisUpdate date).\n   */\n  public isNotYetValid(date = new Date()): boolean {\n    return date < this.thisUpdate\n  }\n\n  private getMatchingExtensions<T = { critical: boolean }>(objectIdentifier: string): Array<T> {\n    return this.crl.extensions.filter((e) => e.type === objectIdentifier) as Array<T>\n  }\n\n  /**\n   * CRL Number (RFC 5280 §5.2.3): the monotonically increasing sequence number of this CRL.\n   */\n  public get crlNumber(): number | undefined {\n    const extensions = this.getMatchingExtensions<x509.Extension>(X509CrlExtensionIdentifier.CrlNumber)\n\n    if (extensions.length > 1) {\n      throw new X509Error('Multiple CRL Number extensions are not allowed')\n    }\n\n    const extension = extensions[0]\n    if (!extension) return undefined\n\n    return AsnParser.parse(extension.value, CRLNumber).value\n  }\n\n  /**\n   * Delta CRL Indicator (RFC 5280 §5.2.4): when present, this CRL is a delta CRL and the value is\n   * the CRL Number of the base (complete) CRL it is relative to. `undefined` for a complete CRL.\n   */\n  public get deltaCrlIndicator(): number | undefined {\n    const extensions = this.getMatchingExtensions<x509.Extension>(X509CrlExtensionIdentifier.DeltaCrlIndicator)\n\n    if (extensions.length > 1) {\n      throw new X509Error('Multiple Delta CRL Indicator extensions are not allowed')\n    }\n\n    const extension = extensions[0]\n    if (!extension) return undefined\n\n    return AsnParser.parse(extension.value, BaseCRLNumber).value\n  }\n\n  /**\n   * Issuing Distribution Point (RFC 5280 §5.2.5), describing the scope of this CRL.\n   *\n   * NOTE: only the URI form of the distribution point name is surfaced; other GeneralName forms and\n   * `nameRelativeToCRLIssuer` are ignored.\n   */\n  public get issuingDistributionPoint(): X509IssuingDistributionPoint | undefined {\n    const extensions = this.getMatchingExtensions<x509.Extension>(X509CrlExtensionIdentifier.IssuingDistributionPoint)\n\n    if (extensions.length > 1) {\n      throw new X509Error('Multiple Issuing Distribution Point extensions are not allowed')\n    }\n\n    const extension = extensions[0]\n    if (!extension) return undefined\n\n    const idp = AsnParser.parse(extension.value, AsnIssuingDistributionPoint)\n\n    const fullName: string[] = []\n    if (idp.distributionPoint?.fullName) {\n      for (const generalName of idp.distributionPoint.fullName) {\n        if (generalName.uniformResourceIdentifier) {\n          fullName.push(generalName.uniformResourceIdentifier)\n        }\n      }\n    }\n\n    let onlySomeReasons: X509RevocationReason[] | undefined\n    if (idp.onlySomeReasons) {\n      // The ASN.1 BIT STRING uses bit `i` for revocation reason code `i` (e.g. keyCompromise = bit 1).\n      const reasonBits = idp.onlySomeReasons.toNumber()\n      onlySomeReasons = []\n      for (let i = 0; i <= 8; i++) {\n        if ((reasonBits & (1 << i)) !== 0) {\n          onlySomeReasons.push(i)\n        }\n      }\n    }\n\n    return {\n      fullName,\n      onlyContainsUserCerts: idp.onlyContainsUserCerts,\n      onlyContainsCACerts: idp.onlyContainsCACerts,\n      onlySomeReasons,\n      indirectCRL: idp.indirectCRL,\n      onlyContainsAttributeCerts: idp.onlyContainsAttributeCerts,\n    }\n  }\n\n  /**\n   * The object identifiers of all critical extensions on this CRL.\n   */\n  public get criticalExtensionIds(): string[] {\n    return this.crl.extensions.filter((extension) => extension.critical).map((extension) => extension.type)\n  }\n\n  /**\n   * Whether the extension with the given id is marked critical. Throws if the extension is absent.\n   */\n  public isExtensionCritical(id: X509CrlExtensionIdentifier | string): boolean {\n    const extensions = this.getMatchingExtensions(id)\n    if (extensions.length === 0) {\n      throw new X509Error(`extension with id '${id}' is not found`)\n    }\n\n    return !!extensions[0].critical\n  }\n\n  /**\n   * Verify this CRL with the issuer's certificate.\n   *\n   * NOTE: the CRL summary cache fast path in `X509RevocationService` reproduces the\n   * issuer-certificate-dependent checks below (public key, subject name, cRLSign key usage). If a\n   * new check depending on the issuer certificate is added here, update that gate in tandem.\n   */\n  public async verify(\n    {\n      issuerCertificate,\n      verificationDate: now = new Date(),\n    }: {\n      issuerCertificate: X509Certificate\n      verificationDate?: Date\n    },\n    webCrypto: CredoWebCrypto\n  ): Promise<{ isValid: boolean; error?: Error }> {\n    // 1. Verify the CRL signature with the issuer's public key.\n    try {\n      const publicJwk = issuerCertificate.publicJwk\n      const cryptoKeyAlgorithm = publicJwkToCryptoKeyAlgorithm(publicJwk, {\n        alg: publicJwk.kty === 'RSA' ? x509SignatureAlgorithmToJwa(this.crl.signatureAlgorithm) : undefined,\n      })\n      const publicCryptoKey = new CredoWebCryptoKey(publicJwk, cryptoKeyAlgorithm, true, 'public', ['verify'])\n\n      const isValid = await this.crl.verify({ publicKey: publicCryptoKey }, webCrypto)\n\n      if (!isValid) {\n        return { isValid: false, error: new X509Error('CRL signature verification failed') }\n      }\n    } catch (error) {\n      return {\n        isValid: false,\n        error: new X509Error('CRL signature verification failed', {\n          cause: error instanceof Error ? error : undefined,\n        }),\n      }\n    }\n\n    // 2. The signature only proves the key matches; this binds the issuer name too. Compare the\n    // DER-encoded distinguished names (not their string forms) for an exact, encoding-stable match.\n    const crlIssuerNameBytes = new Uint8Array(this.crl.issuerName.toArrayBuffer())\n    if (!uint8ArraysEqual(crlIssuerNameBytes, issuerCertificate.subjectNameBytes)) {\n      return {\n        isValid: false,\n        error: new X509Error(\n          `CRL issuer '${this.issuer}' does not match certificate issuer '${issuerCertificate.subject}'`\n        ),\n      }\n    }\n\n    // 3. RFC 5280 §6.3.3(f): the issuer certificate must be authorized to sign CRLs. Key Usage is\n    // optional; when present, it MUST include the cRLSign bit. An empty result means the extension is\n    // absent, so all usages are permitted (a well-formed Key Usage always asserts at least one bit).\n    const issuerKeyUsage = issuerCertificate.keyUsage\n    if (issuerKeyUsage && issuerKeyUsage.length > 0 && !issuerKeyUsage.includes(X509KeyUsage.CrlSign)) {\n      return {\n        isValid: false,\n        error: new X509Error(\n          `CRL issuer '${issuerCertificate.subject}' is not authorized to sign CRLs (key usage does not include cRLSign)`\n        ),\n      }\n    }\n\n    // 4. Check the CRL validity window.\n    if (this.isNotYetValid(now)) {\n      return {\n        isValid: false,\n        error: new X509Error(`CRL is not yet valid (thisUpdate: ${this.thisUpdate.toISOString()})`),\n      }\n    }\n\n    if (this.isExpired(now)) {\n      return {\n        isValid: false,\n        error: new X509Error(`CRL has expired (nextUpdate: ${this.nextUpdate?.toISOString() ?? 'unknown'})`),\n      }\n    }\n\n    return { isValid: true }\n  }\n\n  /**\n   * Check if a certificate is revoked in this CRL.\n   *\n   * We compare serial numbers ourselves (normalizing case and leading zeros) instead of\n   * delegating to `@peculiar/x509`'s `X509Crl.findRevoked`. The latter eagerly resolves the\n   * global crypto provider (even though it isn't needed for a serial number comparison), which\n   * throws when no provider has been registered globally.\n   */\n  public findRevoked(certificate: X509Certificate): X509CertificateRevocationListEntry | null {\n    const target = normalizeSerialNumber(certificate.data.serialNumber)\n\n    for (const entry of this.crl.entries) {\n      if (normalizeSerialNumber(entry.serialNumber) === target) {\n        return {\n          serialNumber: entry.serialNumber,\n          revocationDate: entry.revocationDate,\n          reason: entry.reason as unknown as X509CertificateRevocationListEntryReason | undefined,\n        }\n      }\n    }\n\n    return null\n  }\n\n  /**\n   * Get all revoked certificates in this CRL\n   */\n  public get revokedCertificates(): X509CertificateRevocationListEntry[] {\n    const revoked: X509CertificateRevocationListEntry[] = []\n\n    for (const entry of this.crl.entries) {\n      revoked.push({\n        serialNumber: entry.serialNumber,\n        revocationDate: entry.revocationDate,\n        reason: entry.reason as unknown as X509CertificateRevocationListEntryReason | undefined,\n      })\n    }\n\n    return revoked\n  }\n\n  /**\n   * Get the number of revoked certificates in this CRL\n   */\n  public get revokedCount(): number {\n    return this.crl.entries.length\n  }\n\n  /**\n   * @param format the format to export to, defaults to `pem`\n   */\n  public toString(format?: 'asn' | 'pem' | 'hex' | 'base64' | 'text' | 'base64url') {\n    return this.crl.toString(format ?? 'pem')\n  }\n\n  public equal(crl: X509CertificateRevocationList) {\n    const parsedOther = new x509.X509Crl(crl.rawCertificateRevocationList)\n\n    return this.crl.equal(parsedOther)\n  }\n}\n"],"mappings":"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"}