

import { __decorate } from "../../_virtual/_@oxc-project_runtime@0.94.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 { injectable } from "tsyringe";
import * as x509 from "@peculiar/x509";

//#region src/modules/x509/X509Service.ts
let X509Service = class X509Service$1 {
	/**
	*
	* 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 thje AuthorityKeyIdentifier
	* - If they are equal, the certificate is verified and returned as the issuer
	*
	* Additional validation:
	*   - Make sure atleast 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);
	}
};
X509Service = __decorate([injectable()], X509Service);

//#endregion
export { X509Service };
//# sourceMappingURL=X509Service.mjs.map