@sphereon/ssi-sdk-ext.x509-utils
Version:
Sphereon SSI-SDK plugin functions for X.509 Certificate handling.
752 lines (745 loc) • 27 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
}) : x)(function(x) {
if (typeof require !== "undefined") return require.apply(this, arguments);
throw Error('Dynamic require of "' + x + '" is not supported');
});
// src/types/index.ts
var JwkKeyUse = /* @__PURE__ */ (function(JwkKeyUse2) {
JwkKeyUse2["Encryption"] = "enc";
JwkKeyUse2["Signature"] = "sig";
return JwkKeyUse2;
})({});
// src/x509/rsa-key.ts
import * as u8a2 from "uint8arrays";
// src/x509/crypto.ts
var globalCrypto = /* @__PURE__ */ __name((setGlobal, suppliedCrypto) => {
let webcrypto;
if (typeof suppliedCrypto !== "undefined") {
webcrypto = suppliedCrypto;
} else if (typeof crypto !== "undefined") {
webcrypto = crypto;
} else if (typeof global.crypto !== "undefined") {
webcrypto = global.crypto;
} else {
if (typeof global.window?.crypto?.subtle !== "undefined") {
webcrypto = global.window.crypto;
} else {
webcrypto = __require("crypto");
}
}
if (setGlobal) {
global.crypto = webcrypto;
}
return webcrypto;
}, "globalCrypto");
// src/x509/x509-utils.ts
import { Certificate } from "pkijs";
import * as u8a from "uint8arrays";
import keyto from "@trust/keyto";
var { fromString, toString } = u8a;
function pemCertChainTox5c(cert, maxDepth) {
if (!maxDepth) {
maxDepth = 0;
}
const intermediate = cert.replace(/-----[^\n]+\n?/gm, ",").replace(/\n/g, "").replace(/\r/g, "");
let x5c = intermediate.split(",").filter(function(c) {
return c.length > 0;
});
if (maxDepth > 0) {
x5c = x5c.splice(0, maxDepth);
}
return x5c;
}
__name(pemCertChainTox5c, "pemCertChainTox5c");
function x5cToPemCertChain(x5c, maxDepth) {
if (!maxDepth) {
maxDepth = 0;
}
const length = maxDepth === 0 ? x5c.length : Math.min(maxDepth, x5c.length);
let pem = "";
for (let i = 0; i < length; i++) {
pem += derToPEM(x5c[i], "CERTIFICATE");
}
return pem;
}
__name(x5cToPemCertChain, "x5cToPemCertChain");
var pemOrDerToX509Certificate = /* @__PURE__ */ __name((cert) => {
let DER = typeof cert === "string" ? cert : void 0;
if (typeof cert === "object" && !(cert instanceof Uint8Array)) {
return Certificate.fromBER(cert.rawData);
} else if (typeof cert !== "string") {
return Certificate.fromBER(cert);
} else if (cert.includes("CERTIFICATE")) {
DER = PEMToDer(cert);
}
if (!DER) {
throw Error("Invalid cert input value supplied. PEM, DER, Bytes and X509Certificate object are supported");
}
return Certificate.fromBER(fromString(DER, "base64pad"));
}, "pemOrDerToX509Certificate");
var areCertificatesEqual = /* @__PURE__ */ __name((cert1, cert2) => {
return cert1.signatureValue.isEqual(cert2.signatureValue);
}, "areCertificatesEqual");
var toKeyObject = /* @__PURE__ */ __name((PEM, visibility = "public") => {
const jwk = PEMToJwk(PEM, visibility);
const keyVisibility = jwk.d ? "private" : "public";
const keyHex = keyVisibility === "private" ? privateKeyHexFromPEM(PEM) : publicKeyHexFromPEM(PEM);
return {
pem: hexToPEM(keyHex, visibility),
jwk,
keyHex,
keyType: keyVisibility
};
}, "toKeyObject");
var jwkToPEM = /* @__PURE__ */ __name((jwk, visibility = "public") => {
return keyto.from(jwk, "jwk").toString("pem", visibility === "public" ? "public_pkcs8" : "private_pkcs8");
}, "jwkToPEM");
var PEMToJwk = /* @__PURE__ */ __name((pem, visibility = "public") => {
return keyto.from(pem, "pem").toJwk(visibility);
}, "PEMToJwk");
var privateKeyHexFromPEM = /* @__PURE__ */ __name((PEM) => {
return PEMToHex(PEM);
}, "privateKeyHexFromPEM");
var hexKeyFromPEMBasedJwk = /* @__PURE__ */ __name((jwk, visibility = "public") => {
if (visibility === "private") {
return privateKeyHexFromPEM(jwkToPEM(jwk, "private"));
} else {
return publicKeyHexFromPEM(jwkToPEM(jwk, "public"));
}
}, "hexKeyFromPEMBasedJwk");
var publicKeyHexFromPEM = /* @__PURE__ */ __name((PEM) => {
const hex = PEMToHex(PEM);
if (PEM.includes("CERTIFICATE")) {
throw Error("Cannot directly deduce public Key from PEM Certificate yet");
} else if (!PEM.includes("PRIVATE")) {
return hex;
}
const publicJwk = PEMToJwk(PEM, "public");
const publicPEM = jwkToPEM(publicJwk, "public");
return PEMToHex(publicPEM);
}, "publicKeyHexFromPEM");
var PEMToHex = /* @__PURE__ */ __name((PEM, headerKey) => {
if (PEM.indexOf("-----BEGIN ") == -1) {
throw Error(`PEM header not found: ${headerKey}`);
}
let strippedPem;
if (headerKey) {
strippedPem = PEM.replace(new RegExp("^[^]*-----BEGIN " + headerKey + "-----"), "");
strippedPem = strippedPem.replace(new RegExp("-----END " + headerKey + "-----[^]*$"), "");
} else {
strippedPem = PEM.replace(/^[^]*-----BEGIN [^-]+-----/, "");
strippedPem = strippedPem.replace(/-----END [^-]+-----[^]*$/, "");
}
return base64ToHex(strippedPem, "base64pad");
}, "PEMToHex");
function PEMToBinary(pem) {
const pemContents = pem.replace(/^[^]*-----BEGIN [^-]+-----/, "").replace(/-----END [^-]+-----[^]*$/, "").replace(/\s/g, "");
return fromString(pemContents, "base64pad");
}
__name(PEMToBinary, "PEMToBinary");
var base64ToHex = /* @__PURE__ */ __name((input, inputEncoding) => {
const base64NoNewlines = input.replace(/[^0-9A-Za-z_\-~\/+=]*/g, "");
return toString(fromString(base64NoNewlines, inputEncoding ? inputEncoding : "base64pad"), "base16");
}, "base64ToHex");
var hexToBase64 = /* @__PURE__ */ __name((input, targetEncoding) => {
let hex = typeof input === "string" ? input : input.toString(16);
if (hex.length % 2 === 1) {
hex = `0${hex}`;
}
return toString(fromString(hex, "base16"), targetEncoding ? targetEncoding : "base64pad");
}, "hexToBase64");
var hexToPEM = /* @__PURE__ */ __name((hex, type) => {
const base64 = hexToBase64(hex, "base64pad");
const headerKey = type === "private" ? "RSA PRIVATE KEY" : "PUBLIC KEY";
if (type === "private") {
const pem = derToPEM(base64, headerKey);
try {
PEMToJwk(pem);
return pem;
} catch (error) {
return derToPEM(base64, "PRIVATE KEY");
}
}
return derToPEM(base64, headerKey);
}, "hexToPEM");
function PEMToDer(pem) {
return pem.replace(/(-----(BEGIN|END) CERTIFICATE-----|[\n\r])/g, "");
}
__name(PEMToDer, "PEMToDer");
function derToPEM(cert, headerKey) {
const key = headerKey ?? "CERTIFICATE";
if (cert.includes(key)) {
return cert;
}
const matches = cert.match(/.{1,64}/g);
if (!matches) {
throw Error("Invalid cert input value supplied");
}
return `-----BEGIN ${key}-----
${matches.join("\n")}
-----END ${key}-----
`;
}
__name(derToPEM, "derToPEM");
// src/x509/rsa-key.ts
var { toString: toString2 } = u8a2;
var usage = /* @__PURE__ */ __name((jwk) => {
if (jwk.key_ops && jwk.key_ops.length > 0) {
return jwk.key_ops;
}
if (jwk.use) {
const usages = [];
if (jwk.use.includes("sig")) {
usages.push("sign", "verify");
} else if (jwk.use.includes("enc")) {
usages.push("encrypt", "decrypt");
}
if (usages.length > 0) {
return usages;
}
}
if (jwk.kty === "RSA") {
if (jwk.d) {
return jwk.alg?.toUpperCase()?.includes("QAEP") ? [
"encrypt"
] : [
"sign"
];
}
return jwk.alg?.toUpperCase()?.includes("QAEP") ? [
"decrypt"
] : [
"verify"
];
}
return jwk.d && jwk.kty !== "RSA" ? [
"sign",
"decrypt",
"verify",
"encrypt"
] : [
"verify"
];
}, "usage");
var signAlgorithmToSchemeAndHashAlg = /* @__PURE__ */ __name((signingAlg) => {
const alg = signingAlg.toUpperCase();
let scheme;
if (alg.startsWith("RS")) {
scheme = "RSASSA-PKCS1-V1_5";
} else if (alg.startsWith("PS")) {
scheme = "RSA-PSS";
} else {
throw Error(`Invalid signing algorithm supplied ${signingAlg}`);
}
const hashAlgorithm = `SHA-${alg.substring(2)}`;
return {
scheme,
hashAlgorithm
};
}, "signAlgorithmToSchemeAndHashAlg");
var cryptoSubtleImportRSAKey = /* @__PURE__ */ __name(async (jwk, scheme, hashAlgorithm) => {
const hashName = hashAlgorithm ? hashAlgorithm : jwk.alg ? `SHA-${jwk.alg.substring(2)}` : "SHA-256";
const importParams = {
name: scheme,
hash: hashName
};
return await globalCrypto(false).subtle.importKey("jwk", jwk, importParams, false, usage(jwk));
}, "cryptoSubtleImportRSAKey");
var generateRSAKeyAsPEM = /* @__PURE__ */ __name(async (scheme, hashAlgorithm, modulusLength) => {
const hashName = hashAlgorithm ? hashAlgorithm : "SHA-256";
const params = {
name: scheme,
hash: hashName,
modulusLength: modulusLength ? modulusLength : 2048,
publicExponent: new Uint8Array([
1,
0,
1
])
};
const keyUsage = scheme === "RSA-PSS" || scheme === "RSASSA-PKCS1-V1_5" ? [
"sign",
"verify"
] : [
"encrypt",
"decrypt"
];
const keypair = await globalCrypto(false).subtle.generateKey(params, true, keyUsage);
const pkcs8 = await globalCrypto(false).subtle.exportKey("pkcs8", keypair.privateKey);
const uint8Array = new Uint8Array(pkcs8);
return derToPEM(toString2(uint8Array, "base64pad"), "RSA PRIVATE KEY");
}, "generateRSAKeyAsPEM");
// src/x509/rsa-signer.ts
import * as u8a3 from "uint8arrays";
var { fromString: fromString2, toString: toString3 } = u8a3;
var RSASigner = class {
static {
__name(this, "RSASigner");
}
hashAlgorithm;
jwk;
key;
scheme;
/**
*
* @param key Either in PEM or JWK format (no raw hex keys here!)
* @param opts The algorithm and signature/encryption schemes
*/
constructor(key, opts) {
if (typeof key === "string") {
this.jwk = PEMToJwk(key, opts?.visibility);
} else {
this.jwk = key;
}
this.hashAlgorithm = opts?.hashAlgorithm ?? "SHA-256";
this.scheme = opts?.scheme ?? "RSA-PSS";
}
getImportParams() {
if (this.scheme === "RSA-PSS") {
return {
name: this.scheme,
saltLength: 32
};
}
return {
name: this.scheme
/*, hash: this.hashAlgorithm*/
};
}
async getKey() {
if (!this.key) {
this.key = await cryptoSubtleImportRSAKey(this.jwk, this.scheme, this.hashAlgorithm);
}
return this.key;
}
bufferToString(buf) {
const uint8Array = new Uint8Array(buf);
return toString3(uint8Array, "base64url");
}
async sign(data) {
const input = data;
const key = await this.getKey();
const signature = this.bufferToString(await globalCrypto(false).subtle.sign(this.getImportParams(), key, input));
if (!signature) {
throw Error("Could not sign input data");
}
return signature;
}
async verify(data, signature) {
const jws = signature.includes(".") ? signature.split(".")[2] : signature;
const input = typeof data == "string" ? fromString2(data, "utf-8") : data;
let key = await this.getKey();
if (!key.usages.includes("verify")) {
const verifyJwk = {
...this.jwk
};
delete verifyJwk.d;
delete verifyJwk.use;
delete verifyJwk.key_ops;
key = await cryptoSubtleImportRSAKey(verifyJwk, this.scheme, this.hashAlgorithm);
}
const verificationResult = await globalCrypto(false).subtle.verify(this.getImportParams(), key, fromString2(jws, "base64url"), input);
return verificationResult;
}
};
// src/x509/x509-validator.ts
import { AsnParser } from "@peculiar/asn1-schema";
import { SubjectPublicKeyInfo } from "@peculiar/asn1-x509";
import { AlgorithmProvider, X509Certificate } from "@peculiar/x509";
import x509 from "js-x509-utils";
import { CryptoEngine, getCrypto, id_SubjectAltName, setEngine } from "pkijs";
import { container } from "tsyringe";
import * as u8a4 from "uint8arrays";
var { fromString: fromString3, toString: toString4 } = u8a4;
var defaultCryptoEngine = /* @__PURE__ */ __name(() => {
const name = "crypto";
setEngine(name, new CryptoEngine({
name,
crypto: globalCrypto(false)
}));
return getCrypto(true);
}, "defaultCryptoEngine");
var getCertificateInfo = /* @__PURE__ */ __name(async (certificate, opts) => {
let publicKeyJWK;
try {
publicKeyJWK = await getCertificateSubjectPublicKeyJWK(certificate);
} catch (e) {
}
return {
issuer: {
dn: getIssuerDN(certificate)
},
subject: {
dn: getSubjectDN(certificate),
subjectAlternativeNames: getSubjectAlternativeNames(certificate, {
typeFilter: opts?.sanTypeFilter
})
},
publicKeyJWK,
notBefore: certificate.notBefore.value,
notAfter: certificate.notAfter.value
};
}, "getCertificateInfo");
var validateX509CertificateChain = /* @__PURE__ */ __name(async ({ chain: pemOrDerChain, trustAnchors, verificationTime = /* @__PURE__ */ new Date(), opts = {
// If no trust anchor is found, but the chain itself checks out, allow. (defaults to false:)
allowNoTrustAnchorsFound: false,
trustRootWhenNoAnchors: false,
allowSingleNoCAChainElement: true,
blindlyTrustedAnchors: [],
disallowReversedChain: false
} }) => {
return await validateX509CertificateChainImpl({
reversed: false,
chain: [
...pemOrDerChain
].reverse(),
trustAnchors,
verificationTime,
opts
});
}, "validateX509CertificateChain");
var validateX509CertificateChainImpl = /* @__PURE__ */ __name(async ({ reversed, chain: pemOrDerChain, trustAnchors, verificationTime: verifyAt, opts }) => {
const verificationTime = typeof verifyAt === "string" ? new Date(verifyAt) : verifyAt;
const { allowNoTrustAnchorsFound = false, trustRootWhenNoAnchors = false, allowSingleNoCAChainElement = true, blindlyTrustedAnchors = [], disallowReversedChain = false, client } = opts;
const trustedPEMs = trustRootWhenNoAnchors && !trustAnchors ? [
pemOrDerChain[pemOrDerChain.length - 1]
] : trustAnchors;
if (pemOrDerChain.length === 0) {
return {
error: true,
critical: true,
message: "Certificate chain in DER or PEM format must not be empty",
verificationTime
};
}
defaultCryptoEngine();
const chain = await Promise.all(pemOrDerChain.map((raw) => parseCertificate(raw)));
const x5cOrdereredChain = reversed ? [
...chain
] : [
...chain
].reverse();
const trustedCerts = trustedPEMs ? await Promise.all(trustedPEMs.map((raw) => parseCertificate(raw))) : void 0;
const blindlyTrusted = (await Promise.all(blindlyTrustedAnchors.map((raw) => {
try {
return parseCertificate(raw);
} catch (e) {
console.log(`Failed to parse blindly trusted certificate ${raw}. Error: ${e.message}`);
return void 0;
}
}))).filter((cert) => cert !== void 0) ?? [];
const leafCert = x5cOrdereredChain[0];
const chainLength = chain.length;
var foundTrustAnchor = void 0;
for (let i = 0; i < chainLength; i++) {
const currentCert = chain[i];
const previousCert = i > 0 ? chain[i - 1] : void 0;
const blindlyTrustedCert = blindlyTrusted.find((trusted) => areCertificatesEqual(trusted.certificate, currentCert.certificate));
if (blindlyTrustedCert) {
console.log(`Certificate chain validation success as single cert if blindly trusted. WARNING: ONLY USE FOR TESTING PURPOSES.`);
return {
error: false,
critical: false,
message: `Certificate chain validation success as single cert if blindly trusted. WARNING: ONLY USE FOR TESTING PURPOSES.`,
detailMessage: `Blindly trusted certificate ${blindlyTrustedCert.certificateInfo.subject.dn.DN} was found in the chain.`,
trustAnchor: blindlyTrustedCert?.certificateInfo,
verificationTime,
certificateChain: x5cOrdereredChain.map((cert) => cert.certificateInfo),
...client && {
client
}
};
}
if (previousCert) {
if (currentCert.x509Certificate.issuer !== previousCert.x509Certificate.subject) {
if (!reversed && !disallowReversedChain) {
return await validateX509CertificateChainImpl({
reversed: true,
chain: [
...pemOrDerChain
].reverse(),
opts,
verificationTime,
trustAnchors
});
}
return {
error: true,
critical: true,
certificateChain: x5cOrdereredChain.map((cert) => cert.certificateInfo),
message: `Certificate chain validation failed for ${leafCert.certificateInfo.subject.dn.DN}.`,
detailMessage: `The certificate ${currentCert.certificateInfo.subject.dn.DN} with issuer ${currentCert.x509Certificate.issuer}, is not signed by the previous certificate ${previousCert?.certificateInfo.subject.dn.DN} with subject string ${previousCert?.x509Certificate.subject}.`,
verificationTime,
...client && {
client
}
};
}
}
const result = await currentCert.x509Certificate.verify({
date: verificationTime,
publicKey: previousCert?.x509Certificate?.publicKey
}, getCrypto()?.crypto ?? crypto ?? global.crypto);
if (!result) {
if (i == 0 && !reversed && !disallowReversedChain) {
return await validateX509CertificateChainImpl({
reversed: true,
chain: [
...pemOrDerChain
].reverse(),
opts,
verificationTime,
trustAnchors
});
}
return {
error: true,
critical: true,
message: `Certificate chain validation failed for ${leafCert.certificateInfo.subject.dn.DN}.`,
certificateChain: x5cOrdereredChain.map((cert) => cert.certificateInfo),
detailMessage: `Verification of the certificate ${currentCert.certificateInfo.subject.dn.DN} with issuer ${currentCert.x509Certificate.issuer} failed. Public key: ${JSON.stringify(currentCert.certificateInfo.publicKeyJWK)}.`,
verificationTime,
...client && {
client
}
};
}
foundTrustAnchor = foundTrustAnchor ?? trustedCerts?.find((trusted) => isSameCertificate(trusted.x509Certificate, currentCert.x509Certificate));
if (i === 0 && chainLength === 1 && allowSingleNoCAChainElement) {
return {
error: false,
critical: false,
message: `Certificate chain succeeded as allow single cert result is allowed: ${leafCert.certificateInfo.subject.dn.DN}.`,
certificateChain: x5cOrdereredChain.map((cert) => cert.certificateInfo),
trustAnchor: foundTrustAnchor?.certificateInfo,
verificationTime,
...client && {
client
}
};
}
}
if (foundTrustAnchor?.certificateInfo || allowNoTrustAnchorsFound) {
return {
error: false,
critical: false,
message: `Certificate chain was valid`,
certificateChain: x5cOrdereredChain.map((cert) => cert.certificateInfo),
detailMessage: foundTrustAnchor ? `The leaf certificate ${leafCert.certificateInfo.subject.dn.DN} is part of a chain with trust anchor ${foundTrustAnchor?.certificateInfo.subject.dn.DN}.` : `The leaf certificate ${leafCert.certificateInfo.subject.dn.DN} and chain were valid, but no trust anchor has been found. Ignoring as user allowed (allowNoTrustAnchorsFound: ${allowNoTrustAnchorsFound}).)`,
trustAnchor: foundTrustAnchor?.certificateInfo,
verificationTime,
...client && {
client
}
};
}
return {
error: true,
critical: true,
message: `Certificate chain validation failed for ${leafCert.certificateInfo.subject.dn.DN}.`,
certificateChain: x5cOrdereredChain.map((cert) => cert.certificateInfo),
detailMessage: `No trust anchor was found in the chain. between (intermediate) CA ${x5cOrdereredChain[chain.length - 1].certificateInfo.subject.dn.DN} and leaf ${x5cOrdereredChain[0].certificateInfo.subject.dn.DN}.`,
verificationTime,
...client && {
client
}
};
}, "validateX509CertificateChainImpl");
var isSameCertificate = /* @__PURE__ */ __name((cert1, cert2) => {
return cert1.rawData.toString() === cert2.rawData.toString();
}, "isSameCertificate");
var algorithmProvider = container.resolve(AlgorithmProvider);
var getX509AlgorithmProvider = /* @__PURE__ */ __name(() => {
return algorithmProvider;
}, "getX509AlgorithmProvider");
var parseCertificate = /* @__PURE__ */ __name(async (rawCert) => {
const x509Certificate = new X509Certificate(rawCert);
const publicKeyInfo = AsnParser.parse(x509Certificate.publicKey.rawData, SubjectPublicKeyInfo);
const publicKeyRaw = new Uint8Array(publicKeyInfo.subjectPublicKey);
let publicKeyJwk = void 0;
try {
publicKeyJwk = await getCertificateSubjectPublicKeyJWK(new Uint8Array(x509Certificate.rawData));
} catch (e) {
console.error(e.message);
}
const certificate = pemOrDerToX509Certificate(rawCert);
const certificateInfo = await getCertificateInfo(certificate);
const publicKeyAlgorithm = getX509AlgorithmProvider().toWebAlgorithm(publicKeyInfo.algorithm);
return {
publicKeyAlgorithm,
publicKeyInfo,
publicKeyJwk,
publicKeyRaw,
certificateInfo,
certificate,
x509Certificate
};
}, "parseCertificate");
var rdnmap = {
"2.5.4.6": "C",
"2.5.4.10": "O",
"2.5.4.11": "OU",
"2.5.4.3": "CN",
"2.5.4.7": "L",
"2.5.4.8": "ST",
"2.5.4.12": "T",
"2.5.4.42": "GN",
"2.5.4.43": "I",
"2.5.4.4": "SN",
"1.2.840.113549.1.9.1": "E-mail"
};
var getIssuerDN = /* @__PURE__ */ __name((cert) => {
return {
DN: getDNString(cert.issuer.typesAndValues),
attributes: getDNObject(cert.issuer.typesAndValues)
};
}, "getIssuerDN");
var getSubjectDN = /* @__PURE__ */ __name((cert) => {
return {
DN: getDNString(cert.subject.typesAndValues),
attributes: getDNObject(cert.subject.typesAndValues)
};
}, "getSubjectDN");
var getDNObject = /* @__PURE__ */ __name((typesAndValues) => {
const DN = {};
for (const typeAndValue of typesAndValues) {
const type = rdnmap[typeAndValue.type] ?? typeAndValue.type;
DN[type] = typeAndValue.value.getValue();
}
return DN;
}, "getDNObject");
var getDNString = /* @__PURE__ */ __name((typesAndValues) => {
return Object.entries(getDNObject(typesAndValues)).map(([key, value]) => `${key}=${value}`).join(",");
}, "getDNString");
var getCertificateSubjectPublicKeyJWK = /* @__PURE__ */ __name(async (pemOrDerCert) => {
const pemOrDerStr = typeof pemOrDerCert === "string" ? toString4(fromString3(pemOrDerCert, "base64pad"), "base64pad") : pemOrDerCert instanceof Uint8Array ? toString4(pemOrDerCert, "base64pad") : toString4(fromString3(pemOrDerCert.toString("base64"), "base64pad"), "base64pad");
const pem = derToPEM(pemOrDerStr);
const certificate = pemOrDerToX509Certificate(pem);
var jwk;
try {
const subtle = getCrypto(true).subtle;
const pk = await certificate.getPublicKey(void 0, defaultCryptoEngine());
jwk = await subtle.exportKey("jwk", pk);
} catch (error) {
console.log(`Error in primary get JWK from cert:`, error?.message);
}
if (!jwk) {
try {
jwk = await x509.toJwk(pem, "pem");
} catch (error) {
console.log(`Error in secondary get JWK from cert as well:`, error?.message);
}
}
if (!jwk) {
throw Error(`Failed to get JWK from certificate ${pem}`);
}
return jwk;
}, "getCertificateSubjectPublicKeyJWK");
var SubjectAlternativeGeneralName = /* @__PURE__ */ (function(SubjectAlternativeGeneralName2) {
SubjectAlternativeGeneralName2[SubjectAlternativeGeneralName2["rfc822Name"] = 1] = "rfc822Name";
SubjectAlternativeGeneralName2[SubjectAlternativeGeneralName2["dnsName"] = 2] = "dnsName";
SubjectAlternativeGeneralName2[SubjectAlternativeGeneralName2["uniformResourceIdentifier"] = 6] = "uniformResourceIdentifier";
SubjectAlternativeGeneralName2[SubjectAlternativeGeneralName2["ipAddress"] = 7] = "ipAddress";
return SubjectAlternativeGeneralName2;
})({});
var assertCertificateMatchesClientIdScheme = /* @__PURE__ */ __name((certificate, clientId, clientIdScheme) => {
const sans = getSubjectAlternativeNames(certificate, {
clientIdSchemeFilter: clientIdScheme
});
const clientIdMatches = sans.find((san) => san.value === clientId);
if (!clientIdMatches) {
throw Error(`Client id scheme ${clientIdScheme} used had no matching subject alternative names in certificate with DN ${getSubjectDN(certificate).DN}. SANS: ${sans.map((san) => san.value).join(",")}`);
}
}, "assertCertificateMatchesClientIdScheme");
var validateCertificateChainMatchesClientIdScheme = /* @__PURE__ */ __name(async (certificate, clientId, clientIdScheme) => {
const result = {
error: true,
critical: true,
message: `Client Id ${clientId} was not present in certificate using scheme ${clientIdScheme}`,
client: {
clientId,
clientIdScheme
},
certificateChain: [
await getCertificateInfo(certificate)
],
verificationTime: /* @__PURE__ */ new Date()
};
try {
assertCertificateMatchesClientIdScheme(certificate, clientId, clientIdScheme);
} catch (error) {
return result;
}
result.error = false;
result.message = `Client Id ${clientId} was present in certificate using scheme ${clientIdScheme}`;
return result;
}, "validateCertificateChainMatchesClientIdScheme");
var getSubjectAlternativeNames = /* @__PURE__ */ __name((certificate, opts) => {
let typeFilter;
if (opts?.clientIdSchemeFilter) {
typeFilter = opts.clientIdSchemeFilter === "x509_san_dns" ? [
2
] : [
6
];
} else if (opts?.typeFilter) {
typeFilter = Array.isArray(opts.typeFilter) ? opts.typeFilter : [
opts.typeFilter
];
} else {
typeFilter = [
2,
6
];
}
const parsedValue = certificate.extensions?.find((ext) => ext.extnID === id_SubjectAltName)?.parsedValue;
if (!parsedValue) {
return [];
}
const altNames = parsedValue.toJSON().altNames;
return altNames.filter((altName) => typeFilter.includes(altName.type)).map((altName) => {
return {
type: altName.type,
value: altName.value
};
});
}, "getSubjectAlternativeNames");
export {
JwkKeyUse,
PEMToBinary,
PEMToDer,
PEMToHex,
PEMToJwk,
RSASigner,
SubjectAlternativeGeneralName,
areCertificatesEqual,
assertCertificateMatchesClientIdScheme,
base64ToHex,
cryptoSubtleImportRSAKey,
derToPEM,
generateRSAKeyAsPEM,
getCertificateInfo,
getCertificateSubjectPublicKeyJWK,
getIssuerDN,
getSubjectAlternativeNames,
getSubjectDN,
getX509AlgorithmProvider,
hexKeyFromPEMBasedJwk,
hexToBase64,
hexToPEM,
jwkToPEM,
parseCertificate,
pemCertChainTox5c,
pemOrDerToX509Certificate,
privateKeyHexFromPEM,
publicKeyHexFromPEM,
signAlgorithmToSchemeAndHashAlg,
toKeyObject,
validateCertificateChainMatchesClientIdScheme,
validateX509CertificateChain,
x5cToPemCertChain
};
//# sourceMappingURL=index.js.map