{"version":3,"file":"CertificateSigningRequest.mjs","names":[],"sources":["../../../src/modules/x509/CertificateSigningRequest.ts"],"sourcesContent":["import { AsnParser } from '@peculiar/asn1-schema'\nimport { SubjectPublicKeyInfo } 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  X509ExtensionIdentifier,\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>(X509ExtensionIdentifier.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>(\n      X509ExtensionIdentifier.SubjectKeyIdentifier\n    )?.map((e) => e.keyId)\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>(X509ExtensionIdentifier.KeyUsage)?.map(\n      (e) => e.usages\n    )\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>(\n      X509ExtensionIdentifier.ExtendedKeyUsage\n    )?.map((e) => e.usages)\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: X509ExtensionIdentifier | 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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"}