From 7624baf42bab433558ca60d1ed57d5b403ffa0c1 Mon Sep 17 00:00:00 2001 From: microshine Date: Mon, 11 Jan 2021 13:02:21 +0300 Subject: [PATCH] feat: Validate named curve paramters on importing --- src/mechs/ec/crypto.ts | 22 +++++++++++++++++++++- test/crypto.ts | 19 +++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/mechs/ec/crypto.ts b/src/mechs/ec/crypto.ts index 421978c..9ec09f4 100644 --- a/src/mechs/ec/crypto.ts +++ b/src/mechs/ec/crypto.ts @@ -140,11 +140,13 @@ export class EcCrypto { case "spki": { const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo); const asnKey = new core.asn1.EcPublicKey(keyInfo.publicKey); + this.assertKeyParameters(keyInfo.publicKeyAlgorithm.parameters, algorithm.namedCurve); return this.importPublicKey(asnKey, algorithm, extractable, keyUsages); } case "pkcs8": { const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PrivateKeyInfo); const asnKey = AsnParser.parse(keyInfo.privateKey, core.asn1.EcPrivateKey); + this.assertKeyParameters(keyInfo.privateKeyAlgorithm.parameters, algorithm.namedCurve); return this.importPrivateKey(asnKey, algorithm, extractable, keyUsages); } default: @@ -152,6 +154,23 @@ export class EcCrypto { } } + protected static assertKeyParameters(parameters: ArrayBuffer | null | undefined, namedCurve: string) { + if (!parameters) { + throw new core.CryptoError("Key info doesn't have required parameters"); + } + + let namedCurveIdentifier = ""; + try { + namedCurveIdentifier = AsnParser.parse(parameters, core.asn1.ObjectIdentifier).value; + } catch (e) { + throw new core.CryptoError("Cannot read key info parameters"); + } + + if (getOidByNamedCurve(namedCurve) !== namedCurveIdentifier) { + throw new core.CryptoError("Key info parameter doesn't match to named curve"); + } + } + protected static async importPrivateKey(asnKey: core.asn1.EcPrivateKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) { const keyInfo = new core.asn1.PrivateKeyInfo(); keyInfo.privateKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; @@ -171,7 +190,8 @@ export class EcCrypto { protected static async importPublicKey(asnKey: core.asn1.EcPublicKey, algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[]) { const keyInfo = new core.asn1.PublicKeyInfo(); keyInfo.publicKeyAlgorithm.algorithm = "1.2.840.10045.2.1"; - keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(getOidByNamedCurve(algorithm.namedCurve))); + const namedCurve = getOidByNamedCurve(algorithm.namedCurve); + keyInfo.publicKeyAlgorithm.parameters = AsnSerializer.serialize(new core.asn1.ObjectIdentifier(namedCurve)); keyInfo.publicKey = asnKey.value; const key = new EcPublicKey(); diff --git a/test/crypto.ts b/test/crypto.ts index bea7444..e5d51b0 100644 --- a/test/crypto.ts +++ b/test/crypto.ts @@ -1,5 +1,6 @@ import assert from "assert"; import { WebcryptoTest } from "@peculiar/webcrypto-test"; +import * as core from "webcrypto-core"; import { Crypto } from "../src"; const crypto = new Crypto(); @@ -14,18 +15,28 @@ context("Crypto", () => { const array = new Uint8Array(5); const array2 = crypto.getRandomValues(array); - assert.notEqual(Buffer.from(array).toString("hex"), "0000000000"); - assert.equal(Buffer.from(array2).equals(array), true); + assert.notStrictEqual(Buffer.from(array).toString("hex"), "0000000000"); + assert.strictEqual(Buffer.from(array2).equals(array), true); }); it("Uint16Array", () => { const array = new Uint16Array(5); const array2 = crypto.getRandomValues(array); - assert.notEqual(Buffer.from(array).toString("hex"), "00000000000000000000"); - assert.equal(Buffer.from(array2).equals(Buffer.from(array)), true); + assert.notStrictEqual(Buffer.from(array).toString("hex"), "00000000000000000000"); + assert.strictEqual(Buffer.from(array2).equals(Buffer.from(array)), true); }); }); + it("Import wrong named curve", async () => { + const spki = Buffer.from("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETzlbSDQWz+1nwEHsrT516OAEX5YWzwVYj39BH+Rv5yoP9yLgM5wIXgOls5DoLDJVQ+45XDrD/xjSCcul5NACZw==", "base64"); + await assert.rejects(crypto.subtle.importKey( + "spki", + spki, + { name: "ECDSA", namedCurve: "K-256" } as Algorithm, + false, + ["verify"]), core.CryptoError); + }); + });