From 14548bfc932c7c2e12b7b96134ab645fcf66466f Mon Sep 17 00:00:00 2001 From: Berend Sliedrecht <61358536+berendsliedrecht@users.noreply.github.com> Date: Mon, 24 Jun 2024 13:22:15 +0200 Subject: [PATCH] test: x509 chain validation (#4) * tmp Signed-off-by: Berend Sliedrecht * test: more x509 tests for chain validation Signed-off-by: Berend Sliedrecht --------- Signed-off-by: Berend Sliedrecht --- package.json | 2 +- pnpm-lock.yaml | 6 ++-- src/EcdsaProvider.ts | 18 ++++++++--- src/askar.ts | 6 ++-- tests/x509.test.ts | 71 +++++++++++++++++++++++++++++++++++--------- 5 files changed, 79 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index b351478..f9dbe60 100644 --- a/package.json +++ b/package.json @@ -33,12 +33,12 @@ "@peculiar/asn1-ecc": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8", "@peculiar/asn1-x509": "^2.3.8", - "@peculiar/webcrypto": "^1.5.0", "webcrypto-core": "^1.8.0" }, "devDependencies": { "@biomejs/biome": "1.8.1", "@hyperledger/aries-askar-nodejs": "^0.2.1", + "@peculiar/webcrypto": "^1.5.0", "@peculiar/x509": "^1.11.0", "@types/node": "^20.14.2", "release-it": "^17.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a90419a..966ed24 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,9 +26,6 @@ importers: '@peculiar/asn1-x509': specifier: ^2.3.8 version: 2.3.8 - '@peculiar/webcrypto': - specifier: ^1.5.0 - version: 1.5.0 webcrypto-core: specifier: ^1.8.0 version: 1.8.0 @@ -39,6 +36,9 @@ importers: '@hyperledger/aries-askar-nodejs': specifier: ^0.2.1 version: 0.2.1(encoding@0.1.13) + '@peculiar/webcrypto': + specifier: ^1.5.0 + version: 1.5.0 '@peculiar/x509': specifier: ^1.11.0 version: 1.11.0 diff --git a/src/EcdsaProvider.ts b/src/EcdsaProvider.ts index da44a78..2e81ff6 100644 --- a/src/EcdsaProvider.ts +++ b/src/EcdsaProvider.ts @@ -4,13 +4,12 @@ import { ecdsaWithSHA256 } from '@peculiar/asn1-ecc' import * as core from 'webcrypto-core' import { askarExportKeyToJwk, - askarKeyFromSecretBytes, - askarKeyFromPublicBytes, askarKeyGenerate, askarKeyGetPublicBytes, askarKeySign, askarKeyVerify, askarKeyFromJwk, + askarKeyFromPublicBytes, } from './askar' import type { CryptoKeyPair, @@ -81,7 +80,7 @@ export class EcdsaProvider extends core.EcdsaProvider { public async onImportKey( format: KeyFormat, keyData: JsonWebKey | ArrayBuffer, - _algorithm: EcKeyImportParams, + algorithm: EcKeyImportParams, extractable: boolean, keyUsages: KeyUsage[] ): Promise { @@ -96,8 +95,19 @@ export class EcdsaProvider extends core.EcdsaProvider { keyUsages, keyData: keyData as JsonWebKey, }) + case 'spki': { + const keyInfo = AsnParser.parse(new Uint8Array(keyData as ArrayBuffer), core.asn1.PublicKeyInfo) + + return askarKeyFromPublicBytes({ + format, + keyData: new Uint8Array(keyInfo.publicKey), + keyUsages, + extractable, + algorithm, + }) + } default: - throw new core.OperationError("Only format 'jwt' is supported for importing keys") + throw new core.OperationError(`Only format 'jwt' is supported for importing keys. Received: ${format}`) } } } diff --git a/src/askar.ts b/src/askar.ts index 0b60a89..232a6f6 100644 --- a/src/askar.ts +++ b/src/askar.ts @@ -1,6 +1,6 @@ +import { CryptoBox, Jwk, Key, KeyAlgs } from '@hyperledger/aries-askar-shared' import type * as core from 'webcrypto-core' import { getCryptoKey, setCryptoKey } from './storage' -import { Key, type KeyAlgs, CryptoBox, Jwk } from '@hyperledger/aries-askar-shared' import type { EcKeyGenParams, EcKeyImportParams, JsonWebKey, KeyFormat, KeyUsage } from './types' const CBOX_NONCE_LENGTH = 24 @@ -176,4 +176,6 @@ export const askarKeyFromJwk = ({ // TODO: this needs a proper conversion const cryptoAlgorithmToAskarAlgorithm = (algorithm: EcKeyGenParams) => - (algorithm.namedCurve ? algorithm.namedCurve : algorithm.name) as KeyAlgs + algorithm.name === 'ECDSA' + ? KeyAlgs.EcSecp256r1 + : ((algorithm.namedCurve ? algorithm.namedCurve : algorithm.name) as KeyAlgs) diff --git a/tests/x509.test.ts b/tests/x509.test.ts index fff44ce..46e01b7 100644 --- a/tests/x509.test.ts +++ b/tests/x509.test.ts @@ -36,6 +36,8 @@ describe('x509', async () => { { type: 'dns', value: 'paradym.id' }, { type: 'dns', value: 'wallet.paradym.id' }, ]), + new x509.SubjectAlternativeNameExtension([{ type: 'dns', value: 'animo.id' }]), + new x509.SubjectAlternativeNameExtension([{ type: 'url', value: 'animo.id' }]), ], }) @@ -66,21 +68,9 @@ describe('x509', async () => { const jwkPublic = await crypto.subtle.exportKey('jwk', askarKeys.publicKey) - const nodejsPrivateKey = await webCrypto.subtle.importKey( - 'jwk', - jwkPrivate, - { name: 'ECDSA', namedCurve: 'P-256', hash: { name: 'SHA-256' } }, - true, - ['sign'] - ) + const nodejsPrivateKey = await webCrypto.subtle.importKey('jwk', jwkPrivate, alg, true, ['sign']) - const nodejsPublicKey = await webCrypto.subtle.importKey( - 'jwk', - jwkPublic, - { name: 'ECDSA', namedCurve: 'P-256', hash: { name: 'SHA-256' } }, - true, - ['verify'] - ) + const nodejsPublicKey = await webCrypto.subtle.importKey('jwk', jwkPublic, alg, true, ['verify']) const now = new Date() @@ -135,4 +125,57 @@ describe('x509', async () => { assert(isValidNodejsCertificate) assert(isValidAskarCertificate) }) + + it('Validate a certificate chain', async () => { + const crypto = new Crypto() + x509.cryptoProvider.set(crypto) + + const alg = { + name: 'ECDSA', + namedCurve: 'p-256', + hash: 'SHA-256', + } + + const rootKeys = await crypto.subtle.generateKey(alg, true, ['sign', 'verify']) + const rootCert = await x509.X509CertificateGenerator.createSelfSigned({ + serialNumber: '01', + name: 'CN=Root', + notBefore: new Date(), + notAfter: new Date(), + keys: rootKeys, + signingAlgorithm: alg, + }) + + const intermediateKeys = await crypto.subtle.generateKey(alg, 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: alg, + }) + + const leafKeys = await crypto.subtle.generateKey(alg, 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: alg, + }) + + const chain = new x509.X509ChainBuilder({ + certificates: [rootCert, intermediateCert], + }) + + const items = await chain.build(leafCert) + + assert.strictEqual(items.length, 3) + }) })