{"version":3,"file":"X509Service.mjs","names":[],"sources":["../../../src/modules/x509/X509Service.ts"],"sourcesContent":["import * as x509 from '@peculiar/x509'\nimport { AgentContext } from '../../agent'\nimport { CredoWebCrypto } from '../../crypto/webcrypto'\nimport { injectable } from '../../plugins'\nimport { CertificateSigningRequest } from './CertificateSigningRequest'\nimport { X509ExtensionIdentifier } from './utils'\nimport { validateCriticalExtensionsForChain } from './utils/criticalExtensions'\nimport { X509Certificate, X509KeyUsage } from './X509Certificate'\nimport { X509CertificateRevocationList } from './X509CertificateRevocationList'\nimport { X509Error, X509ValidationError } from './X509Error'\nimport { X509ModuleConfig } from './X509ModuleConfig'\nimport { X509RevocationService } from './X509RevocationService'\nimport type {\n  X509CreateCertificateOptions,\n  X509CreateCertificateRevocationListOptions,\n  X509CreateCertificateSigningRequestOptions,\n  X509GetLeafCertificateOptions,\n  X509ParseCertificateOptions,\n  X509ParseCertificateSigningRequestOptions,\n  X509ValidateCertificateChainOptions,\n} from './X509ServiceOptions'\nimport { X509RevocationCheckMode } from './X509ValidationOptions'\nimport type { X509CertificateSingleValidationResult, X509ValidationResult } from './X509ValidationResult'\n\n@injectable()\n// biome-ignore lint/complexity/noStaticOnlyClass: no explanation\nexport class X509Service {\n  /**\n   *\n   * Validate a chain of X.509 certificates according to RFC 5280\n   *\n   * This function requires a list of base64 encoded certificates and, optionally, a certificate that should be found in the chain.\n   * If no certificate is provided, it will just assume the leaf certificate\n   *\n   * The leaf certificate should be the 0th index and the root the last\n   *\n   * The Issuer of the certificate is found with the following algorithm:\n   * - Check if there is an AuthorityKeyIdentifierExtension\n   * - Go through all the other certificates and see if the SubjectKeyIdentifier is equal to the AuthorityKeyIdentifier\n   * - If they are equal, the certificate signature is verified and returned as the issuer\n   *\n   * Validation checks performed:\n   *   - Chain validation (structure, signatures, validity, trust anchor)\n   *   - Basic constraints are valid for CA certificates\n   *   - Key usage of issuing CA certificates includes `keyCertSign` (when the extension is present)\n   *   - Path length constraints are satisfied\n   *   - All critical extensions are understood and valid\n   *   - Certificates have not been revoked (CRL) - if enabled\n   *\n   * Limitations (RFC 5280 features not enforced here):\n   *   - Revocation is checked via CRL only; OCSP is not supported.\n   *   - Name Constraints (§4.2.1.10), Policy Constraints (§4.2.1.11), and Certificate Policies\n   *     (§4.2.1.4) are not enforced. A certificate carrying one of these as a *critical* extension is\n   *     rejected (unrecognized critical extension); a non-critical occurrence is ignored.\n   *   - Extended Key Usage is parsed but not enforced.\n   *   - Key Usage is only enforced when the extension is present (it is optional; absent means\n   *     unrestricted).\n   *   - Subject/Issuer Alternative Names only surface the URI and DNS GeneralName forms.\n   */\n  public static async validateCertificateChain(\n    agentContext: AgentContext,\n    {\n      certificateChain,\n      certificate = certificateChain[0],\n      verificationDate = new Date(),\n      trustedCertificates,\n      allowNonRootTrustedCertificate = true,\n    }: X509ValidateCertificateChainOptions\n  ) {\n    const validations: X509ValidationResult['validations'] = {}\n    const config = agentContext.dependencyManager.resolve(X509ModuleConfig)\n\n    let parsedChain: X509Certificate[]\n\n    // Phase 1: Chain validation (structure + signatures + validity + trust)\n    try {\n      if (certificateChain.length === 0) {\n        throw new X509Error('Certificate chain is empty')\n      }\n      const webCrypto = new CredoWebCrypto(agentContext)\n\n      let parsedLeafCertificate: x509.X509Certificate\n      let certificatesToBuildChain: x509.X509Certificate[]\n      try {\n        parsedLeafCertificate = new x509.X509Certificate(certificate)\n        certificatesToBuildChain = [...certificateChain, ...(trustedCertificates ?? [])].map(\n          (c) => new x509.X509Certificate(c)\n        )\n      } catch (error) {\n        throw new X509Error('Error during parsing of x509 certificate', { cause: error })\n      }\n\n      const certificateChainBuilder = new x509.X509ChainBuilder({\n        certificates: certificatesToBuildChain,\n      })\n\n      const chain = await certificateChainBuilder.build(parsedLeafCertificate, webCrypto)\n\n      // The chain is reversed here as the `x5c` header (the expected input),\n      // has the leaf certificate as the first entry, while the `x509` library expects this as the last\n      parsedChain = chain.map((c) => X509Certificate.fromRawCertificate(new Uint8Array(c.rawData))).reverse()\n\n      // We allow longer parsed chain, in case the root cert was not part of the chain, but in the\n      // list of trusted certificates\n      if (parsedChain.length < certificateChain.length) {\n        throw new X509Error('Could not parse the full chain. Likely due to incorrect ordering')\n      }\n\n      let previousCertificate: X509Certificate | undefined\n\n      if (trustedCertificates) {\n        const parsedTrustedCertificates = trustedCertificates.map((trustedCertificate) =>\n          X509Certificate.fromEncodedCertificate(trustedCertificate)\n        )\n\n        const trustedCertificateIndex = parsedChain.findIndex((cert) =>\n          parsedTrustedCertificates.some((tCert) => cert.equal(tCert))\n        )\n\n        if (trustedCertificateIndex === -1) {\n          throw new X509Error('No trusted certificate was found while validating the X.509 chain')\n        }\n\n        if (trustedCertificateIndex > 0) {\n          // When we trust a certificate other than the first certificate in the provided chain we keep a reference to the\n          // previous certificate as we need the key of this certificate to verify the first certificate in the chain as\n          // it's not self-signed.\n          previousCertificate = parsedChain[trustedCertificateIndex - 1]\n\n          // Pop everything off before the index of the trusted certificate (those are more root) as it is not relevant for validation\n          parsedChain = parsedChain.slice(trustedCertificateIndex)\n        }\n      }\n\n      // Verify signatures and validity for all certificates in the chain\n      for (let i = 0; i < parsedChain.length; i++) {\n        const cert = parsedChain[i]\n        const publicJwk = previousCertificate ? previousCertificate.publicJwk : undefined\n\n        // When a trusted certificate is the first in the chain and we don't have its parent certificate's public key,\n        // we may need to skip signature verification based on configuration.\n        //\n        // Scenario: For ISO 18013-5 mDL, the root cert MUST NOT be in the chain. If the intermediate/signer\n        // certificate is directly trusted, we can't verify its signature without the root certificate.\n        // See also https://github.com/openid/OpenID4VCI/issues/62\n        //\n        // If allowNonRootTrustedCertificate is false, we require the signature to be verifiable.\n        const skipSignatureVerification = i === 0 && trustedCertificates && !publicJwk && allowNonRootTrustedCertificate\n\n        // If we don't allow non-root trusted certificates and can't verify the signature, throw an error\n        if (i === 0 && trustedCertificates && !publicJwk && !allowNonRootTrustedCertificate) {\n          throw new X509Error(\n            'Unable to verify the certificate chain. A trusted non-self-signed certificate is the first certificate in the chain, ' +\n              'but no parent certificate was found to verify its signature. Either provide the parent certificate in trustedCertificates, ' +\n              'or set allowNonRootTrustedCertificate to true to allow trusting intermediate certificates without signature verification.'\n          )\n        }\n\n        await cert.verify(\n          {\n            publicJwk,\n            verificationDate,\n            skipSignatureVerification,\n          },\n          webCrypto\n        )\n        previousCertificate = cert\n      }\n\n      validations.chain = { isValid: true }\n    } catch (error) {\n      const x509Error = error instanceof X509Error ? error : new X509Error('Chain validation failed', { cause: error })\n      validations.chain = { isValid: false, error: x509Error }\n      throw new X509ValidationError(x509Error.message, { isValid: false, validations, error: x509Error })\n    }\n\n    // Phase 2: Basic constraints validation for CA certificates\n    validations.basicConstraints = X509Service.validateBasicConstraintsForChain(parsedChain)\n    if (!validations.basicConstraints.isValid) {\n      throw new X509ValidationError(\n        validations.basicConstraints.error?.message ?? 'Basic constraints validation failed',\n        { isValid: false, validations, error: validations.basicConstraints.error }\n      )\n    }\n\n    // Phase 2.5: Key usage validation for issuing CA certificates\n    validations.keyUsage = X509Service.validateKeyUsageForChain(parsedChain)\n    if (!validations.keyUsage.isValid) {\n      throw new X509ValidationError(validations.keyUsage.error?.message ?? 'Key usage validation failed', {\n        isValid: false,\n        validations,\n        error: validations.keyUsage.error,\n      })\n    }\n\n    // Phase 3: Path length constraint validation\n    validations.pathLength = X509Service.validatePathLengthConstraints(parsedChain)\n    if (!validations.pathLength.isValid) {\n      throw new X509ValidationError(\n        validations.pathLength.error?.message ?? 'Path length constraint validation failed',\n        { isValid: false, validations, error: validations.pathLength.error }\n      )\n    }\n\n    // Phase 4: Critical extension validation\n    const peculiarChain = parsedChain.map((cert) => new x509.X509Certificate(cert.rawCertificate))\n    validations.criticalExtensions = validateCriticalExtensionsForChain(peculiarChain)\n    if (!validations.criticalExtensions.isValid) {\n      throw new X509ValidationError(\n        validations.criticalExtensions.error?.message ?? 'Critical extension validation failed',\n        { isValid: false, validations, error: validations.criticalExtensions.error }\n      )\n    }\n\n    // Phase 5: Revocation checking (if enabled)\n    if (config.revocationCheck && config.revocationCheck.mode !== X509RevocationCheckMode.Disabled) {\n      validations.revocationStatus = await X509RevocationService.checkCertificateChainRevocation(\n        agentContext,\n        parsedChain,\n        config,\n        verificationDate\n      )\n      if (!validations.revocationStatus.isValid) {\n        throw new X509ValidationError(validations.revocationStatus.error?.message ?? 'Revocation check failed', {\n          isValid: false,\n          validations,\n          error: validations.revocationStatus.error,\n        })\n      }\n    } else {\n      validations.revocationStatus = { isValid: true, details: 'Revocation checking disabled' }\n    }\n\n    return parsedChain\n  }\n\n  /**\n   *\n   * Parses a base64-encoded X.509 certificate into a {@link X509Certificate}\n   *\n   */\n  public static parseCertificate(\n    _agentContext: AgentContext,\n    { encodedCertificate }: X509ParseCertificateOptions\n  ): X509Certificate {\n    const certificate = X509Certificate.fromEncodedCertificate(encodedCertificate)\n\n    return certificate\n  }\n\n  public static getLeafCertificate(\n    _agentContext: AgentContext,\n    { certificateChain }: X509GetLeafCertificateOptions\n  ): X509Certificate {\n    if (certificateChain.length === 0) throw new X509Error('Certificate chain is empty')\n\n    const certificate = X509Certificate.fromEncodedCertificate(certificateChain[0])\n\n    return certificate\n  }\n\n  public static async createCertificate(agentContext: AgentContext, options: X509CreateCertificateOptions) {\n    const webCrypto = new CredoWebCrypto(agentContext)\n\n    const certificate = await X509Certificate.create(options, webCrypto)\n\n    return certificate\n  }\n\n  public static async createCertificateSigningRequest(\n    agentContext: AgentContext,\n    options: X509CreateCertificateSigningRequestOptions\n  ) {\n    const webCrypto = new CredoWebCrypto(agentContext)\n\n    const csr = await CertificateSigningRequest.create(options, webCrypto)\n\n    return csr\n  }\n\n  /**\n   * Creates and signs a X.509 Certificate Revocation List (CRL).\n   *\n   * Supported CRL extensions: CRL Number (§5.2.3), Delta CRL Indicator (§5.2.4), Authority Key\n   * Identifier (§5.2.1) and Issuing Distribution Point (§5.2.5), plus the per-entry\n   * `certificateIssuer` extension (§5.3.3) for indirect CRLs. Other CRL extensions are not produced.\n   *\n   * Note: issuer/subject names built from a structured object only support the `CN`, `C`, `OU` and\n   * `ST` distinguished-name attributes; pass a raw DN string to use any other attribute.\n   */\n  public static async createCertificateRevocationList(\n    agentContext: AgentContext,\n    options: X509CreateCertificateRevocationListOptions\n  ) {\n    const webCrypto = new CredoWebCrypto(agentContext)\n\n    const crl = await X509CertificateRevocationList.create(options, webCrypto)\n\n    return crl\n  }\n\n  public static parseCertificateSigningRequest({\n    encodedCertificateSigningRequest,\n  }: X509ParseCertificateSigningRequestOptions) {\n    const csr = CertificateSigningRequest.fromEncodedCertificateRequest(encodedCertificateSigningRequest)\n\n    return csr\n  }\n\n  /**\n   * Validates path length constraints for a certificate chain\n   * Per RFC 5280 Section 4.2.1.9\n   */\n  private static validatePathLengthConstraints(\n    certificateChain: X509Certificate[]\n  ): X509CertificateSingleValidationResult {\n    let currentPathLength = 0\n\n    // The chain is ordered root-first (index 0) to leaf (last index). Iterate from the leaf upward,\n    // counting the intermediate CAs encountered so each CA's pathLenConstraint can be checked against\n    // the number of CAs that follow it toward the leaf.\n    for (let i = certificateChain.length - 1; i >= 0; i--) {\n      const cert = certificateChain[i]\n      const peculiarCert = new x509.X509Certificate(cert.rawCertificate)\n      const basicConstraintsExt = peculiarCert.getExtension(X509ExtensionIdentifier.BasicConstraints)\n\n      if (!basicConstraintsExt) {\n        // Leaf certificates don't need basicConstraints\n        if (i === 0) continue\n        // But CA certificates should have it\n        continue\n      }\n\n      const basicConstraints = new x509.BasicConstraintsExtension(basicConstraintsExt.rawData)\n\n      // Skip leaf certificates (not CA)\n      if (!basicConstraints.ca) {\n        continue\n      }\n\n      // Check if pathLength constraint is violated\n      if (basicConstraints.pathLength !== undefined) {\n        const remainingCAsInChain = currentPathLength\n        if (remainingCAsInChain > basicConstraints.pathLength) {\n          return {\n            isValid: false,\n            error: new X509Error(\n              `Path length constraint violated. Certificate '${cert.subject}' has pathLength=${basicConstraints.pathLength} ` +\n                `but ${remainingCAsInChain} intermediate CA(s) follow it in the chain.`\n            ),\n            details: `pathLength=${basicConstraints.pathLength}, actual=${remainingCAsInChain}`,\n          }\n        }\n      }\n\n      currentPathLength++\n    }\n\n    return { isValid: true }\n  }\n\n  /**\n   * Validates basic constraints for CA certificates in the chain\n   * Per RFC 5280 Section 4.2.1.9\n   */\n  private static validateBasicConstraintsForChain(\n    certificateChain: X509Certificate[]\n  ): X509CertificateSingleValidationResult {\n    // Check all certificates except the last one (which is typically the end-entity/leaf)\n    // In a properly ordered chain, CA certificates will be before the leaf\n    for (let i = 0; i < certificateChain.length - 1; i++) {\n      const cert = certificateChain[i]\n      const peculiarCert = new x509.X509Certificate(cert.rawCertificate)\n      const basicConstraintsExt = peculiarCert.getExtension(X509ExtensionIdentifier.BasicConstraints)\n\n      if (!basicConstraintsExt) {\n        return {\n          isValid: false,\n          error: new X509Error(\n            `Certificate '${cert.subject}' is used as a CA but does not have a basicConstraints extension`\n          ),\n        }\n      }\n\n      const basicConstraints = new x509.BasicConstraintsExtension(basicConstraintsExt.rawData)\n\n      // Intermediate and root CAs MUST have ca=true\n      if (!basicConstraints.ca) {\n        return {\n          isValid: false,\n          error: new X509Error(\n            `Certificate '${cert.subject}' is used as a CA but does not have basicConstraints with ca=true`\n          ),\n        }\n      }\n    }\n\n    return { isValid: true }\n  }\n\n  /**\n   * Validates the Key Usage extension of the issuing CA certificates in the chain.\n   * Per RFC 5280 §4.2.1.3 / §6.1.4(n): a certificate used to sign other certificates MUST, when it\n   * asserts a Key Usage extension, include the `keyCertSign` bit.\n   *\n   * Key Usage is optional in a certificate; when the extension is absent, all usages are permitted\n   * and no constraint is enforced. Only the issuing certificates (every certificate except the leaf)\n   * are checked.\n   */\n  private static validateKeyUsageForChain(certificateChain: X509Certificate[]): X509CertificateSingleValidationResult {\n    // Every certificate except the last one (the leaf/end-entity) issues the next certificate in the\n    // chain, mirroring the set checked by validateBasicConstraintsForChain.\n    for (let i = 0; i < certificateChain.length - 1; i++) {\n      const cert = certificateChain[i]\n      const keyUsage = cert.keyUsage\n\n      // An empty result means no Key Usage extension is present, so the key is unrestricted and there\n      // is nothing to enforce (a well-formed Key Usage extension always asserts at least one bit).\n      if (keyUsage && keyUsage.length > 0 && !keyUsage.includes(X509KeyUsage.KeyCertSign)) {\n        return {\n          isValid: false,\n          error: new X509Error(\n            `Certificate '${cert.subject}' is used as a CA but its key usage does not include keyCertSign`\n          ),\n          details: 'Missing keyCertSign key usage',\n        }\n      }\n    }\n\n    return { isValid: true }\n  }\n}\n"],"mappings":"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"}