Skip to content

Commit

Permalink
Merge 8526e4e into 9d91300
Browse files Browse the repository at this point in the history
  • Loading branch information
microshine committed Apr 4, 2023
2 parents 9d91300 + 8526e4e commit a8c9a40
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 56 deletions.
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@
"url": "https://github.com/PeculiarVentures/node-webcrypto-p11.git"
},
"dependencies": {
"@peculiar/asn1-schema": "^2.3.3",
"@peculiar/asn1-x509": "^2.3.4",
"@peculiar/asn1-schema": "^2.3.6",
"@peculiar/asn1-x509": "^2.3.6",
"@peculiar/json-schema": "^1.1.12",
"@peculiar/x509": "^1.9.3",
"graphene-pk11": "^2.3.2",
"pkcs11js": "^1.3.1",
"pvtsutils": "^1.3.2",
"tslib": "^2.5.0",
"webcrypto-core": "^1.7.6"
"webcrypto-core": "^1.7.7"
},
"keywords": [
"crypto",
Expand All @@ -59,15 +59,15 @@
"devDependencies": {
"@peculiar/webcrypto-test": "^1.0.7",
"@types/mocha": "^10.0.1",
"@types/node": "^18.13.0",
"@types/node": "^18.15.11",
"mocha": "^10.2.0",
"nyc": "^15.1.0",
"rollup": "^3.15.0",
"rollup-plugin-dts": "^5.1.1",
"rollup": "^3.20.2",
"rollup-plugin-dts": "^5.3.0",
"rollup-plugin-typescript2": "^0.34.1",
"ts-node": "^10.9.1",
"tslint": "^6.1.3",
"typescript": "^4.9.5"
"typescript": "^5.0.3"
},
"funding": {
"type": "github",
Expand Down
34 changes: 34 additions & 0 deletions src/certs/cert.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as graphene from "graphene-pk11";
import * as pvtsutils from "pvtsutils";
import * as core from "webcrypto-core";

import { Crypto } from "../crypto";
Expand Down Expand Up @@ -73,4 +74,37 @@ export abstract class CryptoCertificate extends Pkcs11Object implements Pkcs11Cr
public abstract exportKey(): Promise<CryptoKey>;
public abstract exportKey(algorithm: Algorithm, usages: KeyUsage[]): Promise<CryptoKey>;

/**
* Computes and returns the ID of a public key using the WebCrypto API.
* @returnsA Promise that resolves to a Buffer containing the ID of the public key.
*/
protected async computeID(): Promise<Buffer> {
// Retrieve the ID of the public key
let id = this.publicKey.p11Object.id;

// Check if the key exists in the key storage
const indexes = await this.crypto.keyStorage.keys();
if (!indexes.some(o => o.split("-")[2] === id.toString("hex"))) {
// If the key is not found, look for it on the token
const certKeyRaw = await this.crypto.subtle.exportKey("spki", this.publicKey);
for (const index of indexes) {
const [type] = index.split("-");
if (type !== "public") {
continue;
}

// Export the key and compare it to the public key
const key = await this.crypto.keyStorage.getItem(index);
const keyRaw = await this.crypto.subtle.exportKey("spki", key);
if (pvtsutils.BufferSourceConverter.isEqual(keyRaw, certKeyRaw)) {
// found
id = key.p11Object.id;
break;
}
}
}

return id;
}

}
6 changes: 3 additions & 3 deletions src/certs/csr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ export class X509CertificateRequest extends CryptoCertificate implements core.Cr
const { token, label, sensitive, ...keyAlg } = algorithm; // remove custom attrs for key
this.publicKey = await this.getData().publicKey.export(keyAlg, keyUsages, this.crypto as globalThis.Crypto) as CryptoKey;

const hashSPKI = this.publicKey.p11Object.id;
const id = await this.computeID();

const template = this.crypto.templateBuilder.build({
action: "import",
type: "request",
attributes: {
id: hashSPKI,
id,
label: algorithm.label || "X509 Request",
token: !!(algorithm.token),
},
})
});

// set data attributes
template.value = Buffer.from(data);
Expand Down
7 changes: 3 additions & 4 deletions src/certs/x509.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,16 @@ export class X509Certificate extends CryptoCertificate implements core.CryptoX50
this.parse(array.buffer as ArrayBuffer);

const { token, label, sensitive, ...keyAlg } = algorithm; // remove custom attrs for key
this.publicKey = await this.getData().publicKey.export(keyAlg, keyUsages, this.crypto as globalThis.Crypto) as CryptoKey;

const hashSPKI = this.publicKey.p11Object.id;
this.publicKey = await this.getData().publicKey.export(keyAlg, keyUsages, this.crypto) as CryptoKey;

const id = await this.computeID();
const certLabel = this.getName();

const template = this.crypto.templateBuilder.build({
action: "import",
type: "x509",
attributes: {
id: hashSPKI,
id,
label: algorithm.label || certLabel,
token: !!(algorithm.token),
},
Expand Down
123 changes: 116 additions & 7 deletions test/cert_storage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as assert from "assert";
import * as graphene from "graphene-pk11";
import * as x509 from "@peculiar/x509";
import { CryptoCertificateFormat, PemConverter } from "webcrypto-core";
import { Pkcs11RsaHashedKeyAlgorithm, X509Certificate, X509CertificateRequest } from "../src";
Expand All @@ -16,13 +17,8 @@ const X509_REQUEST_PEM = PemConverter.fromBufferSource(X509_REQUEST_RAW, "CERTIF
("Certificate storage", () => {

beforeEach(async () => {
let keys = await crypto.certStorage.keys();
if (keys.length) {
await crypto.certStorage.clear();
}

keys = await crypto.certStorage.keys();
assert.strictEqual(keys.length, 0);
await crypto.certStorage.clear();
await crypto.keyStorage.clear();
});

context("indexOf", () => {
Expand Down Expand Up @@ -244,4 +240,117 @@ const X509_REQUEST_PEM = PemConverter.fromBufferSource(X509_REQUEST_RAW, "CERTIF
assert.strictEqual(keyIndex.split("-")[2], certIndex.split("-")[2]);
});

context("issue #75", () => {

/**
* Generate RSA key pair using graphene
* @returns id of generated key
*/
function generateRsaKeys(): Buffer {
const id = crypto.getRandomValues(Buffer.alloc(10));

crypto.session.generateKeyPair(graphene.KeyGenMechanism.RSA, {
keyType: graphene.KeyType.RSA,
id,
modulusBits: 2048,
publicExponent: Buffer.from([1, 0, 1]),
token: true,
verify: true,
encrypt: true,
wrap: true
}, {
keyType: graphene.KeyType.RSA,
id,
token: true,
sign: true,
decrypt: true,
unwrap: true
});
return id;
}

interface NullableCryptoKeyPair {
privateKey: CryptoKey | null;
publicKey: CryptoKey | null;
}

/**
* Get CryptoKeyPair using node-webcrypto-p11
* @param id id of key pair
* @returns CryptoKeyPair
*/
async function getCryptoKeys(id: Buffer): Promise<NullableCryptoKeyPair> {
let privateKey: CryptoKey | null = null;
let publicKey: CryptoKey | null = null;

const indexes = await crypto.keyStorage.keys();
for (const index of indexes) {
if (index.split("-")[2] === id.toString("hex")) {
const key = await crypto.keyStorage.getItem(index);
if (key.type === "private") {
privateKey = key;
} else if (key.type === "public") {
publicKey = key;
}
}
}

return { privateKey, publicKey };
}

it("import x509 certificate", async () => {
// generate RSA key using graphene
const id = generateRsaKeys();
const keys = await getCryptoKeys(id);

assert.ok(keys.privateKey, "Private key not found");
assert.ok(keys.publicKey, "Public key not found");

const signingAlg = {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
};
const cert = await x509.X509CertificateGenerator.createSelfSigned({
serialNumber: "01",
name: "CN=Test",
notBefore: new Date("2020/01/01"),
notAfter: new Date("2020/01/02"),
signingAlgorithm: signingAlg,
keys: {
privateKey: keys.privateKey,
publicKey: keys.publicKey,
},
}, crypto);

const p11Cert = await crypto.certStorage.importCert("raw", cert.rawData, signingAlg, ["verify"]);
assert.strictEqual(p11Cert.id.split("-")[2], id.toString("hex"));
});

it("import CSR", async () => {
// generate RSA key using graphene
const id = generateRsaKeys();
const keys = await getCryptoKeys(id);

assert.ok(keys.privateKey, "Private key not found");
assert.ok(keys.publicKey, "Public key not found");

const signingAlg = {
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
};
const cert = await x509.Pkcs10CertificateRequestGenerator.create({
name: "CN=Test",
signingAlgorithm: signingAlg,
keys: {
privateKey: keys.privateKey,
publicKey: keys.publicKey,
},
}, crypto);

const p11Cert = await crypto.certStorage.importCert("raw", cert.rawData, signingAlg, ["verify"]);
assert.strictEqual(p11Cert.id.split("-")[2], id.toString("hex"));
});

});
});

70 changes: 35 additions & 35 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,10 @@
asn1js "^3.0.5"
tslib "^2.4.0"

"@peculiar/asn1-schema@^2.1.6", "@peculiar/asn1-schema@^2.3.3":
version "2.3.3"
resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.3.3.tgz#21418e1f3819e0b353ceff0c2dad8ccb61acd777"
integrity sha512-6GptMYDMyWBHTUKndHaDsRZUO/XMSgIns2krxcm2L7SEExRHwawFvSwNBhqNPR9HJwv3MruAiF1bhN0we6j6GQ==
"@peculiar/asn1-schema@^2.3.3", "@peculiar/asn1-schema@^2.3.6":
version "2.3.6"
resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.3.6.tgz#3dd3c2ade7f702a9a94dfb395c192f5fa5d6b922"
integrity sha512-izNRxPoaeJeg/AyH8hER6s+H7p4itk+03QCa4sbxI3lNdseQYCuxzgsuNK8bTXChtLTjpJz6NmXKA73qLa3rCA==
dependencies:
asn1js "^3.0.5"
pvtsutils "^1.3.2"
Expand All @@ -343,12 +343,12 @@
asn1js "^3.0.5"
tslib "^2.4.0"

"@peculiar/asn1-x509@^2.3.4":
version "2.3.4"
resolved "https://registry.yarnpkg.com/@peculiar/asn1-x509/-/asn1-x509-2.3.4.tgz#416bfd9ccdba3c512354d9d43d67969d6084f2fa"
integrity sha512-NhA6U76kiGKTQG2WQyGfRS/piYHt7HxUsGb0IvQaiJheuucKb2CYu0/tOk1dayZcvFf6Pnf9HjFGQ/5ud/ndRQ==
"@peculiar/asn1-x509@^2.3.4", "@peculiar/asn1-x509@^2.3.6":
version "2.3.6"
resolved "https://registry.yarnpkg.com/@peculiar/asn1-x509/-/asn1-x509-2.3.6.tgz#e50154a460cdf43da8a41b23ee807a53e0036af0"
integrity sha512-dRwX31R1lcbIdzbztiMvLNTDoGptxdV7HocNx87LfKU0fEWh7fTWJjx4oV+glETSy6heF/hJHB2J4RGB3vVSYg==
dependencies:
"@peculiar/asn1-schema" "^2.3.3"
"@peculiar/asn1-schema" "^2.3.6"
asn1js "^3.0.5"
ipaddr.js "^2.0.1"
pvtsutils "^1.3.2"
Expand Down Expand Up @@ -419,10 +419,10 @@
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b"
integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==

"@types/node@^18.13.0":
version "18.13.0"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.13.0.tgz#0400d1e6ce87e9d3032c19eb6c58205b0d3f7850"
integrity sha512-gC3TazRzGoOnoKAhUx+Q0t8S9Tzs74z7m0ipwGpSqQrleP14hKxP4/JUeEQcD3W1/aIpnWl8pHowI7WokuZpXg==
"@types/node@^18.15.11":
version "18.15.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f"
integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==

acorn-walk@^8.1.1:
version "8.2.0"
Expand Down Expand Up @@ -1168,10 +1168,10 @@ lru-cache@^6.0.0:
dependencies:
yallist "^4.0.0"

magic-string@^0.27.0:
version "0.27.0"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3"
integrity sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==
magic-string@^0.30.0:
version "0.30.0"
resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.0.tgz#fd58a4748c5c4547338a424e90fa5dd17f4de529"
integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.13"

Expand Down Expand Up @@ -1487,12 +1487,12 @@ rimraf@^3.0.0:
dependencies:
glob "^7.1.3"

rollup-plugin-dts@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/rollup-plugin-dts/-/rollup-plugin-dts-5.1.1.tgz#8cc36ab13135b77ef0cfd6107e4af561c5dffd04"
integrity sha512-zpgo52XmnLg8w4k3MScinFHZK1+ro6r7uVe34fJ0Ee8AM45FvgvTuvfWWaRgIpA4pQ1BHJuu2ospncZhkcJVeA==
rollup-plugin-dts@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/rollup-plugin-dts/-/rollup-plugin-dts-5.3.0.tgz#80a95988002f188e376f6db3b7e2f53679168957"
integrity sha512-8FXp0ZkyZj1iU5klkIJYLjIq/YZSwBoERu33QBDxm/1yw5UU4txrEtcmMkrq+ZiKu3Q4qvPCNqc3ovX6rjqzbQ==
dependencies:
magic-string "^0.27.0"
magic-string "^0.30.0"
optionalDependencies:
"@babel/code-frame" "^7.18.6"

Expand All @@ -1507,10 +1507,10 @@ rollup-plugin-typescript2@^0.34.1:
semver "^7.3.7"
tslib "^2.4.0"

rollup@^3.15.0:
version "3.15.0"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.15.0.tgz#6f4105e8c4b8145229657b74ad660b02fbfacc05"
integrity sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg==
rollup@^3.20.2:
version "3.20.2"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.20.2.tgz#f798c600317f216de2e4ad9f4d9ab30a89b690ff"
integrity sha512-3zwkBQl7Ai7MFYQE0y1MeQ15+9jsi7XxfrqwTb/9EK8D9C9+//EBR4M+CuA1KODRaNbFez/lWxA5vhEGZp4MUg==
optionalDependencies:
fsevents "~2.3.2"

Expand Down Expand Up @@ -1739,10 +1739,10 @@ typedarray-to-buffer@^3.1.5:
dependencies:
is-typedarray "^1.0.0"

typescript@^4.9.5:
version "4.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
typescript@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.3.tgz#fe976f0c826a88d0a382007681cbb2da44afdedf"
integrity sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==

universalify@^2.0.0:
version "2.0.0"
Expand All @@ -1759,12 +1759,12 @@ v8-compile-cache-lib@^3.0.1:
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==

webcrypto-core@^1.7.6:
version "1.7.6"
resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.6.tgz#e32c4a12a13de4251f8f9ef336a6cba7cdec9b55"
integrity sha512-TBPiewB4Buw+HI3EQW+Bexm19/W4cP/qZG/02QJCXN+iN+T5sl074vZ3rJcle/ZtDBQSgjkbsQO/1eFcxnSBUA==
webcrypto-core@^1.7.7:
version "1.7.7"
resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.7.tgz#06f24b3498463e570fed64d7cab149e5437b162c"
integrity sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g==
dependencies:
"@peculiar/asn1-schema" "^2.1.6"
"@peculiar/asn1-schema" "^2.3.6"
"@peculiar/json-schema" "^1.1.12"
asn1js "^3.0.1"
pvtsutils "^1.3.2"
Expand Down

0 comments on commit a8c9a40

Please sign in to comment.