{"version":3,"file":"criticalExtensions.mjs","names":[],"sources":["../../../../src/modules/x509/utils/criticalExtensions.ts"],"sourcesContent":["import * as x509 from '@peculiar/x509'\nimport { X509Error } from '../X509Error'\nimport type { X509CertificateSingleValidationResult } from '../X509ValidationResult'\nimport { X509CrlExtensionIdentifier, X509ExtensionIdentifier } from './extensions'\n\n/**\n * Registry of critical extensions that Credo understands and can validate\n * Based on RFC 5280 Section 4.2\n */\nexport const knownCriticalExtensions = [\n  X509ExtensionIdentifier.BasicConstraints,\n  X509ExtensionIdentifier.KeyUsage,\n  X509ExtensionIdentifier.ExtendedKeyUsage, // not always critical\n  X509ExtensionIdentifier.SubjectAltName,\n  X509ExtensionIdentifier.IssuerAltName,\n  X509ExtensionIdentifier.SubjectKeyIdentifier, // typically not critical\n  X509ExtensionIdentifier.AuthorityKeyIdentifier, // typically not critical\n  X509ExtensionIdentifier.CrlDistributionPoints, // typically not critical\n  // Extensions not yet validated by Credo but recognized:\n  // X509ExtensionIdentifier.NameConstraints, // currently not validated\n  // X509ExtensionIdentifier.PolicyConstraints, // currently not validated\n]\n\n/**\n * Registry of critical CRL extensions that Credo understands and can process.\n * Based on RFC 5280 Section 5.2\n */\nexport const knownCriticalCrlExtensions = [\n  X509CrlExtensionIdentifier.IssuingDistributionPoint,\n  X509CrlExtensionIdentifier.DeltaCrlIndicator,\n]\n\nexport interface CriticalExtensionValidationResult {\n  isValid: boolean\n  unknownCriticalExtensions: string[]\n  error?: Error\n}\n\n/**\n * Validates that all critical extensions in a certificate are understood by Credo\n * Per RFC 5280 Section 4.2: \"A certificate-using system MUST reject the certificate if it encounters\n * a critical extension it does not recognize or a critical extension that contains information that it cannot process\"\n */\nexport function validateCriticalExtensions(certificate: x509.X509Certificate): CriticalExtensionValidationResult {\n  const unknownCriticalExtensions: string[] = []\n\n  for (const extension of certificate.extensions) {\n    if (extension.critical && !knownCriticalExtensions.includes(extension.type as X509ExtensionIdentifier)) {\n      unknownCriticalExtensions.push(extension.type)\n    }\n  }\n\n  if (unknownCriticalExtensions.length > 0) {\n    return {\n      isValid: false,\n      unknownCriticalExtensions,\n      error: new X509Error(\n        `Certificate contains unknown critical extensions: ${unknownCriticalExtensions.join(', ')}. ` +\n          `Per RFC 5280, certificates with unrecognized critical extensions MUST be rejected.`\n      ),\n    }\n  }\n\n  return { isValid: true, unknownCriticalExtensions: [] }\n}\n\n/**\n * Validates critical extensions for all certificates in a chain\n */\nexport function validateCriticalExtensionsForChain(\n  certificates: x509.X509Certificate[]\n): X509CertificateSingleValidationResult {\n  for (const cert of certificates) {\n    const result = validateCriticalExtensions(cert)\n    if (!result.isValid) {\n      return {\n        isValid: false,\n        error: result.error,\n        details: `Unknown critical extensions: ${result.unknownCriticalExtensions.join(', ')}`,\n      }\n    }\n  }\n\n  return { isValid: true }\n}\n\n/**\n * Validates that all critical extensions on a CRL are understood by Credo\n * Per RFC 5280 Section 6.3.3: a CRL bearing a critical extension that is not recognized (or that\n * cannot be processed) MUST NOT be used, as it may change the CRL's meaning (e.g. its scope).\n */\nexport function validateCriticalCrlExtensions(crl: x509.X509Crl): CriticalExtensionValidationResult {\n  return validateCriticalCrlExtensionIds(crl.extensions.filter((e) => e.critical).map((e) => e.type))\n}\n\n/**\n * Validates a list of critical CRL extension ids against the extensions Credo understands.\n * See {@link validateCriticalCrlExtensions}.\n */\nexport function validateCriticalCrlExtensionIds(criticalExtensionIds: string[]): CriticalExtensionValidationResult {\n  const unknownCriticalExtensions = criticalExtensionIds.filter(\n    (id) => !knownCriticalCrlExtensions.includes(id as X509CrlExtensionIdentifier)\n  )\n\n  if (unknownCriticalExtensions.length > 0) {\n    return {\n      isValid: false,\n      unknownCriticalExtensions,\n      error: new X509Error(\n        `CRL contains unknown critical extensions: ${unknownCriticalExtensions.join(', ')}. ` +\n          `Per RFC 5280, a CRL with unrecognized critical extensions MUST NOT be used.`\n      ),\n    }\n  }\n\n  return { isValid: true, unknownCriticalExtensions: [] }\n}\n"],"mappings":";;;;;;;;AASA,MAAa,0BAA0B;;;;;;;;;AAYvC;;;;;AAMA,MAAa,6BAA6B,CAAA,aAAA,WAG1C;;;;;;AAaA,SAAgB,2BAA2B,aAAsE;CAC/G,MAAM,4BAAsC,CAAC;CAE7C,KAAK,MAAM,aAAa,YAAY,YAClC,IAAI,UAAU,YAAY,CAAC,wBAAwB,SAAS,UAAU,IAA+B,GACnG,0BAA0B,KAAK,UAAU,IAAI;CAIjD,IAAI,0BAA0B,SAAS,GACrC,OAAO;EACL,SAAS;EACT;EACA,OAAO,IAAI,UACT,qDAAqD,0BAA0B,KAAK,IAAI,EAAE,qFAE5F;CACF;CAGF,OAAO;EAAE,SAAS;EAAM,2BAA2B,CAAC;CAAE;AACxD;;;;AAKA,SAAgB,mCACd,cACuC;CACvC,KAAK,MAAM,QAAQ,cAAc;EAC/B,MAAM,SAAS,2BAA2B,IAAI;EAC9C,IAAI,CAAC,OAAO,SACV,OAAO;GACL,SAAS;GACT,OAAO,OAAO;GACd,SAAS,gCAAgC,OAAO,0BAA0B,KAAK,IAAI;EACrF;CAEJ;CAEA,OAAO,EAAE,SAAS,KAAK;AACzB;;;;;AAeA,SAAgB,gCAAgC,sBAAmE;CACjH,MAAM,4BAA4B,qBAAqB,QACpD,OAAO,CAAC,2BAA2B,SAAS,EAAgC,CAC/E;CAEA,IAAI,0BAA0B,SAAS,GACrC,OAAO;EACL,SAAS;EACT;EACA,OAAO,IAAI,UACT,6CAA6C,0BAA0B,KAAK,IAAI,EAAE,8EAEpF;CACF;CAGF,OAAO;EAAE,SAAS;EAAM,2BAA2B,CAAC;CAAE;AACxD"}