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

97 lines (93 loc) • 4.72 kB
import { injectable } from "../../plugins/index.mjs"; import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.112.0/helpers/decorate.mjs"; import "../../agent/index.mjs"; import { CredoWebCrypto } from "../../crypto/webcrypto/CredoWebCrypto.mjs"; import "../../crypto/webcrypto/index.mjs"; import { X509Error } from "./X509Error.mjs"; import { X509Certificate } from "./X509Certificate.mjs"; import { CertificateSigningRequest } from "./CertificateSigningRequest.mjs"; import * as x509 from "@peculiar/x509"; //#region src/modules/x509/X509Service.ts let X509Service = class X509Service { /** * * Validate a chain of X.509 certificates according to RFC 5280 * * This function requires a list of base64 encoded certificates and, optionally, a certificate that should be found in the chain. * If no certificate is provided, it will just assume the leaf certificate * * The leaf certificate should be the 0th index and the root the last * * The Issuer of the certificate is found with the following algorithm: * - Check if there is an AuthorityKeyIdentifierExtension * - Go through all the other certificates and see if the SubjectKeyIdentifier is equal to the AuthorityKeyIdentifier * - If they are equal, the certificate is verified and returned as the issuer * * Additional validation: * - Make sure at least a single certificate is in the chain * - Check whether a certificate in the chain matches with a trusted certificate */ static async validateCertificateChain(agentContext, { certificateChain, certificate = certificateChain[0], verificationDate = /* @__PURE__ */ new Date(), trustedCertificates }) { if (certificateChain.length === 0) throw new X509Error("Certificate chain is empty"); const webCrypto = new CredoWebCrypto(agentContext); let parsedLeafCertificate; let certificatesToBuildChain; try { parsedLeafCertificate = new x509.X509Certificate(certificate); certificatesToBuildChain = [...certificateChain, ...trustedCertificates ?? []].map((c) => new x509.X509Certificate(c)); } catch (error) { throw new X509Error("Error during parsing of x509 certificate", { cause: error }); } let parsedChain = (await new x509.X509ChainBuilder({ certificates: certificatesToBuildChain }).build(parsedLeafCertificate, webCrypto)).map((c) => X509Certificate.fromRawCertificate(new Uint8Array(c.rawData))).reverse(); if (parsedChain.length < certificateChain.length) throw new X509Error("Could not parse the full chain. Likely due to incorrect ordering"); let previousCertificate; if (trustedCertificates) { const parsedTrustedCertificates = trustedCertificates.map((trustedCertificate) => X509Certificate.fromEncodedCertificate(trustedCertificate)); const trustedCertificateIndex = parsedChain.findIndex((cert) => parsedTrustedCertificates.some((tCert) => cert.equal(tCert))); if (trustedCertificateIndex === -1) throw new X509Error("No trusted certificate was found while validating the X.509 chain"); if (trustedCertificateIndex > 0) { previousCertificate = parsedChain[trustedCertificateIndex - 1]; parsedChain = parsedChain.slice(trustedCertificateIndex); } } for (let i = 0; i < parsedChain.length; i++) { const cert = parsedChain[i]; const publicJwk = previousCertificate ? previousCertificate.publicJwk : void 0; const skipSignatureVerification = i === 0 && trustedCertificates && !publicJwk; await cert.verify({ publicJwk, verificationDate, skipSignatureVerification }, webCrypto); previousCertificate = cert; } return parsedChain; } /** * * Parses a base64-encoded X.509 certificate into a {@link X509Certificate} * */ static parseCertificate(_agentContext, { encodedCertificate }) { return X509Certificate.fromEncodedCertificate(encodedCertificate); } static getLeafCertificate(_agentContext, { certificateChain }) { if (certificateChain.length === 0) throw new X509Error("Certificate chain is empty"); return X509Certificate.fromEncodedCertificate(certificateChain[0]); } static async createCertificate(agentContext, options) { const webCrypto = new CredoWebCrypto(agentContext); return await X509Certificate.create(options, webCrypto); } static async createCertificateSigningRequest(agentContext, options) { const webCrypto = new CredoWebCrypto(agentContext); return await CertificateSigningRequest.create(options, webCrypto); } static parseCertificateSigningRequest({ encodedCertificateSigningRequest }) { return CertificateSigningRequest.fromEncodedCertificateRequest(encodedCertificateSigningRequest); } }; X509Service = __decorate([injectable()], X509Service); //#endregion export { X509Service }; //# sourceMappingURL=X509Service.mjs.map