UNPKG

@credo-ts/core

Version:

<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1

1 lines • 25.1 kB
{"version":3,"file":"X509Certificate.mjs","names":[],"sources":["../../../src/modules/x509/X509Certificate.ts"],"sourcesContent":["import { AsnParser } from '@peculiar/asn1-schema'\nimport { SubjectPublicKeyInfo } 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 X509ExtensionIdentifier,\n x509SignatureAlgorithmToJwa,\n} from './utils'\nimport type { X509CrlDistributionPoint, X509RevocationReason } from './X509CrlDistributionPoint'\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>(X509ExtensionIdentifier.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>(X509ExtensionIdentifier.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>(\n X509ExtensionIdentifier.AuthorityKeyIdentifier\n )?.map((e) => e.keyId)\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>(\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 // biome-ignore lint/suspicious/useGetterReturn: no explanation\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) {\n return (\n Object.values(X509KeyUsage)\n .filter((key): key is number => typeof key === 'number')\n // KeyUsage is stored as bit value\n .filter((flagValue) => (keyUsages[0] & flagValue) === flagValue)\n .map((flagValue) => flagValue as X509KeyUsage)\n )\n }\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 Key Usages are not allowed')\n }\n\n return (extendedKeyUsages?.[0] as Array<X509ExtendedKeyUsage> | undefined) ?? []\n }\n\n /**\n * Whether this certificate is a certificate authority (the Basic Constraints `cA` flag is set).\n * Returns `false` when the Basic Constraints extension is absent (e.g. an end-entity certificate).\n */\n public get isCertificateAuthority(): boolean {\n const basicConstraints = this.getMatchingExtensions<x509.BasicConstraintsExtension>(\n X509ExtensionIdentifier.BasicConstraints\n )\n\n if (basicConstraints && basicConstraints.length > 1) {\n throw new X509Error('Multiple Basic Constraints extensions are not allowed')\n }\n\n return basicConstraints?.[0]?.ca ?? false\n }\n\n /**\n * Get CRL Distribution Points with full structure including URLs, reasons, and CRL issuer.\n * Based on RFC 5280 Section 4.2.1.13\n *\n * NOTE: only the URI form is surfaced for both the distribution point name (fullName) and the\n * cRLIssuer; nameRelativeToCRLIssuer and non-URI general names are ignored. Indirect CRLs\n * (those with a cRLIssuer) are surfaced here but are not verified during revocation checking.\n */\n public get crlDistributionPoints(): X509CrlDistributionPoint[] {\n const crlDistributionPointsExt = this.getMatchingExtensions<x509.CRLDistributionPointsExtension>(\n X509ExtensionIdentifier.CrlDistributionPoints\n )\n\n if (crlDistributionPointsExt && crlDistributionPointsExt.length > 1) {\n throw new X509Error('Multiple CRL Distribution Points extensions are not allowed')\n }\n\n const ext = crlDistributionPointsExt?.[0]\n if (!ext) {\n return []\n }\n\n const distributionPoints = ext.distributionPoints\n if (!distributionPoints || distributionPoints.length === 0) {\n return []\n }\n\n const result: X509CrlDistributionPoint[] = []\n\n for (const dp of distributionPoints) {\n // Extract URLs - @peculiar library stores these as uniformResourceIdentifier in fullName\n const urls: string[] = []\n\n // fullName is an array of GeneralName objects\n if (dp.distributionPoint?.fullName) {\n for (const generalName of dp.distributionPoint.fullName) {\n // GeneralName has uniformResourceIdentifier property for URLs\n if (generalName.uniformResourceIdentifier) {\n urls.push(generalName.uniformResourceIdentifier)\n }\n }\n }\n\n // Skip distribution points with no URLs\n if (urls.length === 0) {\n continue\n }\n\n // Extract reasons if present\n // If reasons is undefined/null, this is a \"full\" distribution point covering all reasons\n let reasons: X509RevocationReason[] | undefined\n if (dp.reasons !== undefined && dp.reasons !== null) {\n // The reasons field is an ASN.1 BIT STRING. `toNumber()` returns a bitmask where\n // bit `i` corresponds to revocation reason code `i` (e.g. keyCompromise = bit 1).\n const reasonBits = dp.reasons.toNumber()\n reasons = []\n for (let i = 0; i <= 8; i++) {\n // Check if bit i is set (reasons 0-8)\n if ((reasonBits & (1 << i)) !== 0) {\n reasons.push(i)\n }\n }\n }\n\n // Extract the cRLIssuer URI (indirect CRL), if present. Only the URI (uniformResourceIdentifier)\n // form is surfaced. Indirect CRLs are not verified during revocation checking, but exposing the\n // field lets the revocation service recognise and skip such distribution points.\n let crlIssuer: string | undefined\n if (dp.cRLIssuer) {\n for (const generalName of dp.cRLIssuer) {\n if (generalName.uniformResourceIdentifier) {\n crlIssuer = generalName.uniformResourceIdentifier\n break\n }\n }\n }\n\n result.push({\n urls,\n reasons,\n crlIssuer,\n })\n }\n\n return result\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: 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 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 public get subject() {\n return this.x509Certificate.subject\n }\n\n /**\n * The DER-encoded subject distinguished name. Use this for exact, encoding-stable name comparison\n * (e.g. binding a CRL to its issuer) rather than the string form returned by {@link subject}.\n */\n public get subjectNameBytes(): Uint8Array {\n return new Uint8Array(this.x509Certificate.subjectName.toArrayBuffer())\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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"}