From b61507c192f4a13ef30850885f85630e7734b779 Mon Sep 17 00:00:00 2001 From: microshine Date: Tue, 19 Dec 2023 11:13:21 +0100 Subject: [PATCH] fix: error on chain building #67 --- src/x509_chain_builder.ts | 17 ++++++--- test/issues.ts | 74 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 test/issues.ts diff --git a/src/x509_chain_builder.ts b/src/x509_chain_builder.ts index 44354b5..6139e1a 100644 --- a/src/x509_chain_builder.ts +++ b/src/x509_chain_builder.ts @@ -6,6 +6,10 @@ import { cryptoProvider } from "./provider"; import { X509Certificate } from "./x509_cert"; import { X509Certificates } from "./x509_certs"; +export interface X509ChainBuilderParams { + certificates?: X509Certificate[]; +} + /** * Represents a chain-building engine for X509Certificate certificates * @example @@ -27,7 +31,7 @@ export class X509ChainBuilder { public certificates: X509Certificate[] = []; - public constructor(params: Partial = {}) { + public constructor(params: X509ChainBuilderParams = {}) { if (params.certificates) { this.certificates = params.certificates; } @@ -76,10 +80,13 @@ export class X509ChainBuilder { } } } - if (!await cert.verify({ - publicKey: await item.publicKey.export(cert.signatureAlgorithm, ["verify"], crypto), - signatureOnly: true, - }, crypto)) { + try { + const algorithm = { ...item.publicKey.algorithm, ...cert.signatureAlgorithm }; + const publicKey = await item.publicKey.export(algorithm, ["verify"], crypto); + if (!await cert.verify({ publicKey, signatureOnly: true }, crypto)) { + continue; + } + } catch (e) { continue; } diff --git a/test/issues.ts b/test/issues.ts new file mode 100644 index 0000000..ba3889b --- /dev/null +++ b/test/issues.ts @@ -0,0 +1,74 @@ +import * as assert from "node:assert"; +import { webcrypto } from "node:crypto"; +import * as x509 from "../src"; + +const crypto = webcrypto as globalThis.Crypto; + +context("issues", () => { + it("#67", async () => { + // https://github.com/PeculiarVentures/x509/issues/67 + const rootKeys = await crypto.subtle.generateKey({ + name: "ECDSA", + namedCurve: "P-256", + }, true, ["sign", "verify"]); + const rootCert = await x509.X509CertificateGenerator.createSelfSigned({ + serialNumber: "01", + name: "CN=Root", + notBefore: new Date(), + notAfter: new Date(), + keys: rootKeys, + signingAlgorithm: { + name: "ECDSA", + hash: "SHA-256", + }, + }, crypto); + + const intermediateKeys = await crypto.subtle.generateKey({ + name: "ECDSA", + namedCurve: "P-384", + }, true, ["sign", "verify"]); + const intermediateCert = await x509.X509CertificateGenerator.create({ + serialNumber: "02", + subject: "CN=Intermediate", + issuer: rootCert.subject, + notBefore: new Date(), + notAfter: new Date(), + signingKey: rootKeys.privateKey, + publicKey: intermediateKeys.publicKey, + signingAlgorithm: { + name: "ECDSA", + hash: "SHA-256", + }, + }, crypto); + + const leafKeys = await crypto.subtle.generateKey({ + name: "ECDSA", + namedCurve: "P-384", + }, true, ["sign", "verify"]); + const leafCert = await x509.X509CertificateGenerator.create({ + serialNumber: "03", + subject: "CN=Leaf", + issuer: intermediateCert.subject, + notBefore: new Date(), + notAfter: new Date(), + signingKey: intermediateKeys.privateKey, + publicKey: leafKeys.publicKey, + signingAlgorithm: { + name: "ECDSA", + hash: "SHA-256", + }, + }, crypto); + + // console.log([ + // rootCert.toString("pem"), + // intermediateCert.toString("pem"), + // leafCert.toString("pem"), + // ].join("\n")); + + const chain = new x509.X509ChainBuilder({ + certificates: [rootCert, intermediateCert], + }); + const items = await chain.build(leafCert, crypto); + assert.strictEqual(items.length, 3); + }); +}); \ No newline at end of file