{"version":3,"file":"X509Certificate.mjs","names":[],"sources":["../../../src/modules/x509/X509Certificate.ts"],"sourcesContent":["import { AsnParser } from '@peculiar/asn1-schema'\nimport {\n  id_ce_authorityKeyIdentifier,\n  id_ce_extKeyUsage,\n  id_ce_issuerAltName,\n  id_ce_keyUsage,\n  id_ce_subjectAltName,\n  id_ce_subjectKeyIdentifier,\n  SubjectPublicKeyInfo,\n} from '@peculiar/asn1-x509'\nimport * as x509 from '@peculiar/x509'\nimport type { AgentContext } from '../../agent'\nimport { CredoWebCrypto, CredoWebCryptoKey } from '../../crypto/webcrypto'\nimport { publicJwkToCryptoKeyAlgorithm, spkiToPublicJwk } from '../../crypto/webcrypto/utils'\nimport { TypedArrayEncoder } from '../../utils'\nimport { asymmetricPublicJwkMatches, PublicJwk } from '../kms'\nimport {\n  convertName,\n  createAuthorityKeyIdentifierExtension,\n  createBasicConstraintsExtension,\n  createCrlDistributionPointsExtension,\n  createExtendedKeyUsagesExtension,\n  createIssuerAlternativeNameExtension,\n  createKeyUsagesExtension,\n  createSubjectAlternativeNameExtension,\n  createSubjectKeyIdentifierExtension,\n  x509SignatureAlgorithmToJwa,\n} from './utils'\nimport { X509Error } from './X509Error'\nimport type { X509CreateCertificateOptions } from './X509ServiceOptions'\n\nexport enum X509KeyUsage {\n  DigitalSignature = 1,\n  NonRepudiation = 2,\n  KeyEncipherment = 4,\n  DataEncipherment = 8,\n  KeyAgreement = 16,\n  KeyCertSign = 32,\n  CrlSign = 64,\n  EncipherOnly = 128,\n  DecipherOnly = 256,\n}\n\nexport enum X509ExtendedKeyUsage {\n  ServerAuth = '1.3.6.1.5.5.7.3.1',\n  ClientAuth = '1.3.6.1.5.5.7.3.2',\n  CodeSigning = '1.3.6.1.5.5.7.3.3',\n  EmailProtection = '1.3.6.1.5.5.7.3.4',\n  TimeStamping = '1.3.6.1.5.5.7.3.8',\n  OcspSigning = '1.3.6.1.5.5.7.3.9',\n  MdlDs = '1.0.18013.5.1.2',\n}\n\nexport type X509CertificateOptions = {\n  publicJwk: PublicJwk\n  privateKey?: Uint8Array\n  x509Certificate: x509.X509Certificate\n}\n\nexport class X509Certificate {\n  public publicJwk: PublicJwk\n  public privateKey?: Uint8Array\n  private x509Certificate: x509.X509Certificate\n\n  private constructor(options: X509CertificateOptions) {\n    this.publicJwk = options.publicJwk\n    this.privateKey = options.privateKey\n    this.x509Certificate = options.x509Certificate\n  }\n\n  public set keyId(keyId: string) {\n    this.publicJwk.keyId = keyId\n  }\n\n  public get keyId(): string {\n    return this.publicJwk.keyId\n  }\n\n  public get hasKeyId(): boolean {\n    return this.publicJwk.hasKeyId\n  }\n\n  public static fromRawCertificate(rawCertificate: Uint8Array): X509Certificate {\n    const certificate = new x509.X509Certificate(rawCertificate)\n    return X509Certificate.parseCertificate(certificate)\n  }\n\n  public static fromEncodedCertificate(encodedCertificate: string): X509Certificate {\n    const certificate = new x509.X509Certificate(encodedCertificate)\n    return X509Certificate.parseCertificate(certificate)\n  }\n\n  private static parseCertificate(certificate: x509.X509Certificate): X509Certificate {\n    const spki = AsnParser.parse(certificate.publicKey.rawData, SubjectPublicKeyInfo)\n    const privateKey = certificate.privateKey ? new Uint8Array(certificate.privateKey.rawData) : undefined\n\n    const publicJwk = spkiToPublicJwk(spki)\n\n    return new X509Certificate({\n      publicJwk,\n      privateKey,\n      x509Certificate: certificate,\n    })\n  }\n\n  private getMatchingExtensions<T = { critical: boolean }>(objectIdentifier: string): Array<T> | undefined {\n    return this.x509Certificate.extensions.filter((e) => e.type === objectIdentifier) as Array<T> | undefined\n  }\n\n  public get rawCertificate() {\n    return new Uint8Array(this.x509Certificate.rawData)\n  }\n\n  public get subjectAlternativeNames() {\n    const san = this.getMatchingExtensions<x509.SubjectAlternativeNameExtension>(id_ce_subjectAltName)\n    return san?.flatMap((s) => s.names.items).map((i) => ({ type: i.type, value: i.value })) ?? []\n  }\n\n  public get issuerAlternativeNames() {\n    const ian = this.getMatchingExtensions<x509.IssuerAlternativeNameExtension>(id_ce_issuerAltName)\n    return ian?.flatMap((i) => i.names.items).map((i) => ({ type: i.type, value: i.value })) ?? []\n  }\n\n  public get sanDnsNames() {\n    return this.subjectAlternativeNames.filter((san) => san.type === 'dns').map((san) => san.value)\n  }\n\n  public get sanUriNames() {\n    return this.subjectAlternativeNames.filter((ian) => ian.type === 'url').map((ian) => ian.value)\n  }\n\n  public get ianDnsNames() {\n    return this.issuerAlternativeNames.filter((san) => san.type === 'dns').map((san) => san.value)\n  }\n\n  public get ianUriNames() {\n    return this.issuerAlternativeNames.filter((ian) => ian.type === 'url').map((ian) => ian.value)\n  }\n\n  public get authorityKeyIdentifier() {\n    const keyIds = this.getMatchingExtensions<x509.AuthorityKeyIdentifierExtension>(id_ce_authorityKeyIdentifier)?.map(\n      (e) => e.keyId\n    )\n\n    if (keyIds && keyIds.length > 1) {\n      throw new X509Error('Multiple Authority Key Identifiers are not allowed')\n    }\n\n    return keyIds?.[0]\n  }\n\n  public get subjectKeyIdentifier() {\n    const keyIds = this.getMatchingExtensions<x509.SubjectKeyIdentifierExtension>(id_ce_subjectKeyIdentifier)?.map(\n      (e) => e.keyId\n    )\n\n    if (keyIds && keyIds.length > 1) {\n      throw new X509Error('Multiple Subject Key Identifiers are not allowed')\n    }\n\n    return keyIds?.[0]\n  }\n\n  // biome-ignore lint/suspicious/useGetterReturn: no explanation\n  public get keyUsage() {\n    const keyUsages = this.getMatchingExtensions<x509.KeyUsagesExtension>(id_ce_keyUsage)?.map((e) => e.usages)\n\n    if (keyUsages && keyUsages.length > 1) {\n      throw new X509Error('Multiple Key Usages are not allowed')\n    }\n\n    if (keyUsages) {\n      return Object.values(X509KeyUsage)\n        .filter((key): key is number => typeof key === 'number')\n        .filter((flagValue) => (keyUsages[0] & flagValue) === flagValue)\n        .map((flagValue) => flagValue as X509KeyUsage)\n    }\n  }\n\n  public get extendedKeyUsage() {\n    const extendedKeyUsages = this.getMatchingExtensions<x509.ExtendedKeyUsageExtension>(id_ce_extKeyUsage)?.map(\n      (e) => e.usages\n    )\n\n    if (extendedKeyUsages && extendedKeyUsages.length > 1) {\n      throw new X509Error('Multiple Key Usages are not allowed')\n    }\n\n    return (extendedKeyUsages?.[0] as Array<X509ExtendedKeyUsage> | undefined) ?? []\n  }\n\n  public isExtensionCritical(id: string): boolean {\n    const extension = this.getMatchingExtensions(id)\n    if (!extension) {\n      throw new X509Error(`extension with id '${id}' is not found`)\n    }\n\n    return !!extension[0].critical\n  }\n\n  public static async create(options: X509CreateCertificateOptions, webCrypto: CredoWebCrypto) {\n    const subjectPublicKey = options.subjectPublicKey ?? options.authorityKey\n    const isSelfSignedCertificate = asymmetricPublicJwkMatches(options.authorityKey.toJson(), subjectPublicKey.toJson())\n\n    const signingKey = new CredoWebCryptoKey(\n      options.authorityKey,\n      publicJwkToCryptoKeyAlgorithm(options.authorityKey),\n      false,\n      'private',\n      ['sign']\n    )\n    const publicKey = new CredoWebCryptoKey(\n      subjectPublicKey,\n      publicJwkToCryptoKeyAlgorithm(options.authorityKey),\n      true,\n      'public',\n      ['verify']\n    )\n\n    const issuerName = convertName(options.issuer)\n\n    const extensions: Array<x509.Extension | undefined> = []\n    extensions.push(\n      createSubjectKeyIdentifierExtension(options.extensions?.subjectKeyIdentifier, { publicJwk: subjectPublicKey })\n    )\n    extensions.push(createKeyUsagesExtension(options.extensions?.keyUsage))\n    extensions.push(createExtendedKeyUsagesExtension(options.extensions?.extendedKeyUsage))\n    extensions.push(\n      createAuthorityKeyIdentifierExtension(options.extensions?.authorityKeyIdentifier, {\n        publicJwk: options.authorityKey,\n      })\n    )\n    extensions.push(createIssuerAlternativeNameExtension(options.extensions?.issuerAlternativeName))\n    extensions.push(createSubjectAlternativeNameExtension(options.extensions?.subjectAlternativeName))\n    extensions.push(createBasicConstraintsExtension(options.extensions?.basicConstraints))\n    extensions.push(createCrlDistributionPointsExtension(options.extensions?.crlDistributionPoints))\n\n    if (isSelfSignedCertificate) {\n      if (options.subject) {\n        throw new X509Error('Do not provide a subject name when the certificate is supposed to be self signed')\n      }\n\n      const certificate = await x509.X509CertificateGenerator.createSelfSigned(\n        {\n          keys: { publicKey, privateKey: signingKey },\n          name: issuerName,\n          notBefore: options.validity?.notBefore,\n          notAfter: options.validity?.notAfter,\n          extensions: extensions.filter((e) => e !== undefined),\n          serialNumber: options.serialNumber,\n        },\n        webCrypto\n      )\n\n      const certificateInstance = X509Certificate.parseCertificate(certificate)\n      if (subjectPublicKey.hasKeyId) certificateInstance.publicJwk.keyId = subjectPublicKey.keyId\n      return certificateInstance\n    }\n\n    if (!options.subject) {\n      throw new X509Error('Provide a subject name when the certificate is not supposed to be self signed')\n    }\n\n    const subjectName = convertName(options.subject)\n\n    const certificate = await x509.X509CertificateGenerator.create(\n      {\n        signingKey,\n        publicKey,\n        issuer: issuerName,\n        subject: subjectName,\n        notBefore: options.validity?.notBefore,\n        notAfter: options.validity?.notAfter,\n        extensions: extensions.filter((e) => e !== undefined),\n      },\n      webCrypto\n    )\n\n    const certificateInstance = X509Certificate.parseCertificate(certificate)\n    if (subjectPublicKey.hasKeyId) certificateInstance.publicJwk.keyId = subjectPublicKey.keyId\n    return certificateInstance\n  }\n\n  public get subject() {\n    return this.x509Certificate.subject\n  }\n\n  public get issuer() {\n    return this.x509Certificate.issuer\n  }\n\n  public async verify(\n    {\n      verificationDate = new Date(),\n      publicJwk,\n      skipSignatureVerification = false,\n    }: {\n      verificationDate: Date\n      publicJwk?: PublicJwk\n\n      /**\n       * Whether to skip the verification of the signature and only perform other checks (such\n       * as whether the certificate is not expired).\n       *\n       * This can be useful when an non-self-signed certificate is directly trusted, and it may\n       * not be possible to verify the certificate as the root/intermediate certificate containing\n       * the key of the signer/intermediate is not present.\n       *\n       * @default false\n       */\n      skipSignatureVerification?: boolean\n    },\n    webCrypto: CredoWebCrypto\n  ) {\n    let publicCryptoKey: CredoWebCryptoKey | undefined\n    if (publicJwk) {\n      const cryptoKeyAlgorithm = publicJwkToCryptoKeyAlgorithm(publicJwk, {\n        alg: publicJwk.kty === 'RSA' ? x509SignatureAlgorithmToJwa(this.x509Certificate.signatureAlgorithm) : undefined,\n      })\n\n      publicCryptoKey = new CredoWebCryptoKey(publicJwk, cryptoKeyAlgorithm, true, 'public', ['verify'])\n    }\n\n    // We use the library to validate the signature, but the date is manually verified\n    const isSignatureValid = skipSignatureVerification\n      ? true\n      : await this.x509Certificate.verify({ signatureOnly: true, publicKey: publicCryptoKey }, webCrypto)\n    const time = verificationDate.getTime()\n\n    const isNotBeforeValid = this.x509Certificate.notBefore.getTime() <= time\n    const isNotAfterValid = time <= this.x509Certificate.notAfter.getTime()\n\n    if (!isSignatureValid) {\n      throw new X509Error(`Certificate: '${this.x509Certificate.subject}' has an invalid signature`)\n    }\n\n    if (!isNotBeforeValid) {\n      throw new X509Error(`Certificate: '${this.x509Certificate.subject}' used before it is allowed`)\n    }\n\n    if (!isNotAfterValid) {\n      throw new X509Error(`Certificate: '${this.x509Certificate.subject}' used after it is allowed`)\n    }\n  }\n\n  /**\n   * Get the thumbprint of the X509 certificate in hex format.\n   */\n  public async getThumbprintInHex(agentContext: AgentContext) {\n    const thumbprint = await this.x509Certificate.getThumbprint(new CredoWebCrypto(agentContext))\n    const thumbprintHex = TypedArrayEncoder.toHex(new Uint8Array(thumbprint))\n\n    return thumbprintHex\n  }\n\n  /**\n   * Get the data elements of the x509 certificate\n   */\n  public get data() {\n    return {\n      issuerName: this.x509Certificate.issuerName.toString(),\n      issuer: this.x509Certificate.issuer,\n      subjectName: this.x509Certificate.subjectName.toString(),\n      subject: this.x509Certificate.subject,\n      serialNumber: this.x509Certificate.serialNumber,\n      pem: this.x509Certificate.toString(),\n      notBefore: this.x509Certificate.notBefore,\n      notAfter: this.x509Certificate.notAfter,\n    }\n  }\n\n  public getIssuerNameField(field: string) {\n    return this.x509Certificate.issuerName.getField(field)\n  }\n\n  public getSubjectNameField(field: string) {\n    return this.x509Certificate.subjectName.getField(field)\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.x509Certificate.toString(format ?? 'pem')\n  }\n\n  public equal(certificate: X509Certificate) {\n    const parsedOther = new x509.X509Certificate(certificate.rawCertificate)\n\n    return this.x509Certificate.equal(parsedOther)\n  }\n}\n"],"mappings":"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"}