{"version":3,"file":"CertificateSigningRequest.mjs","names":[],"sources":["../../../src/modules/x509/CertificateSigningRequest.ts"],"sourcesContent":["import { AsnParser } from '@peculiar/asn1-schema'\nimport {\n  id_ce_extKeyUsage,\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 {\n  CredoWebCrypto,\n  CredoWebCryptoKey,\n  jwaAlgorithmToKeySignParams,\n  publicJwkToCryptoKeyAlgorithm,\n} from '../../crypto/webcrypto'\nimport { spkiToPublicJwk } from '../../crypto/webcrypto/utils'\nimport { PublicJwk } from '../kms'\nimport {\n  convertName,\n  createExtendedKeyUsagesExtension,\n  createKeyUsagesExtension,\n  createSubjectAlternativeNameExtension,\n  createSubjectKeyIdentifierExtension,\n} from './utils'\nimport { X509ExtendedKeyUsage, X509KeyUsage } from './X509Certificate'\nimport { X509Error } from './X509Error'\nimport type { X509CreateCertificateSigningRequestOptions } from './X509ServiceOptions'\n\nexport type CertificateSigningRequestOptions = {\n  publicJwk: PublicJwk\n  certificateRequest: x509.Pkcs10CertificateRequest\n}\n\nexport class CertificateSigningRequest {\n  public publicJwk: PublicJwk\n  private certificateRequest: x509.Pkcs10CertificateRequest\n\n  private constructor(options: CertificateSigningRequestOptions) {\n    this.publicJwk = options.publicJwk\n    this.certificateRequest = options.certificateRequest\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 fromRawCertificateRequest(rawCertificateRequest: Uint8Array): CertificateSigningRequest {\n    const certificateRequest = new x509.Pkcs10CertificateRequest(rawCertificateRequest)\n    return CertificateSigningRequest.parseCertificateRequest(certificateRequest)\n  }\n\n  public static fromEncodedCertificateRequest(encodedCertificateRequest: string): CertificateSigningRequest {\n    const certificateRequest = new x509.Pkcs10CertificateRequest(encodedCertificateRequest)\n    return CertificateSigningRequest.parseCertificateRequest(certificateRequest)\n  }\n\n  private static parseCertificateRequest(certificateRequest: x509.Pkcs10CertificateRequest): CertificateSigningRequest {\n    const spki = AsnParser.parse(certificateRequest.publicKey.rawData, SubjectPublicKeyInfo)\n    const publicJwk = spkiToPublicJwk(spki)\n\n    return new CertificateSigningRequest({\n      publicJwk,\n      certificateRequest,\n    })\n  }\n\n  private getMatchingExtensions<T = { critical: boolean }>(objectIdentifier: string): Array<T> | undefined {\n    const matchingExtensions = this.certificateRequest.extensions.filter((e) => e.type === objectIdentifier)\n    if (matchingExtensions.length === 0) return undefined\n    return matchingExtensions as Array<T>\n  }\n\n  public get rawCertificateRequest() {\n    return new Uint8Array(this.certificateRequest.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 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((san) => san.type === 'url').map((san) => san.value)\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  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 && keyUsages.length > 0) {\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    return []\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 Extended 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: X509CreateCertificateSigningRequestOptions, webCrypto: CredoWebCrypto) {\n    const signingKey = new CredoWebCryptoKey(\n      options.subjectPublicKey,\n      publicJwkToCryptoKeyAlgorithm(options.subjectPublicKey),\n      false,\n      'private',\n      ['sign']\n    )\n    const publicKey = new CredoWebCryptoKey(\n      options.subjectPublicKey,\n      publicJwkToCryptoKeyAlgorithm(options.subjectPublicKey),\n      true,\n      'public',\n      ['verify']\n    )\n\n    const extensions: Array<x509.Extension | undefined> = []\n    extensions.push(\n      createSubjectKeyIdentifierExtension(options.extensions?.subjectKeyIdentifier, {\n        publicJwk: options.subjectPublicKey,\n      })\n    )\n    extensions.push(createKeyUsagesExtension(options.extensions?.keyUsage))\n    extensions.push(createExtendedKeyUsagesExtension(options.extensions?.extendedKeyUsage))\n    extensions.push(createSubjectAlternativeNameExtension(options.extensions?.subjectAlternativeName))\n\n    const subjectName = convertName(options.subject)\n\n    // Get the JWA signature algorithm from the public key and convert to KeySignParams\n    const jwaAlgorithm = options.subjectPublicKey.signatureAlgorithm\n    const signingAlgorithm = jwaAlgorithmToKeySignParams(jwaAlgorithm)\n\n    const csr = await x509.Pkcs10CertificateRequestGenerator.create(\n      {\n        keys: { publicKey, privateKey: signingKey },\n        name: subjectName,\n        signingAlgorithm,\n        extensions: extensions.filter((e) => e !== undefined),\n      },\n      webCrypto\n    )\n\n    const csrInstance = CertificateSigningRequest.parseCertificateRequest(csr)\n    if (options.subjectPublicKey.hasKeyId) csrInstance.publicJwk.keyId = options.subjectPublicKey.keyId\n    return csrInstance\n  }\n\n  public get subject() {\n    return this.certificateRequest.subject\n  }\n\n  public get subjectName() {\n    return this.certificateRequest.subjectName.toString()\n  }\n\n  public async verify(webCrypto: CredoWebCrypto) {\n    const isValid = await this.certificateRequest.verify(webCrypto)\n\n    if (!isValid) {\n      throw new X509Error(\n        `Certificate Signing Request for '${this.certificateRequest.subject}' has an invalid signature`\n      )\n    }\n  }\n\n  /**\n   * Get the data elements of the certificate signing request\n   */\n  public get data() {\n    return {\n      subjectName: this.certificateRequest.subjectName.toString(),\n      subject: this.certificateRequest.subject,\n      pem: this.certificateRequest.toString(),\n    }\n  }\n\n  public getSubjectNameField(field: string) {\n    return this.certificateRequest.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.certificateRequest.toString(format ?? 'pem')\n  }\n\n  public equal(certificateRequest: CertificateSigningRequest) {\n    const parsedOther = new x509.Pkcs10CertificateRequest(certificateRequest.rawCertificateRequest)\n\n    return this.certificateRequest.equal(parsedOther)\n  }\n}\n"],"mappings":"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"}