From a1fb91c8d590b6c15fc8a86fc2b1fa5f0e2ca834 Mon Sep 17 00:00:00 2001 From: AlexanderTar Date: Thu, 11 Jan 2024 18:04:20 +0000 Subject: [PATCH] fix: using specification algorithm for ECDSA signatures (IEEE-P1363 format) --- src/algorithm/index.ts | 21 +++++++++++++++++---- src/types/index.ts | 2 +- test/algorithm/ecdsa-p256-sha256.ts | 19 +++++++++++++------ test/algorithm/ecdsa-p384-sha384.ts | 10 ++++++++-- test/httpbis/httpbis.int.ts | 11 +++++------ 5 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/algorithm/index.ts b/src/algorithm/index.ts index e78ba35..ad08ba2 100644 --- a/src/algorithm/index.ts +++ b/src/algorithm/index.ts @@ -11,6 +11,7 @@ import { VerifyPublicKeyInput, sign, verify, + KeyObject, } from 'crypto'; import { RSA_PKCS1_PADDING, RSA_PKCS1_PSS_PADDING } from 'constants'; import { SigningKey, Algorithm, Verifier } from '../types'; @@ -50,10 +51,16 @@ export function createSigner(key: BinaryLike | KeyLike | SignKeyObjectInput | Si } as SignPrivateKeyInput); break; case 'ecdsa-p256-sha256': - signer.sign = async (data: Buffer) => createSign('sha256').update(data).sign(key as KeyLike); + signer.sign = async (data: Buffer) => createSign('sha256').update(data).sign({ + key: key as KeyObject, + dsaEncoding: 'ieee-p1363', + }); break; case 'ecdsa-p384-sha384': - signer.sign = async (data: Buffer) => createSign('sha384').update(data).sign(key as KeyLike); + signer.sign = async (data: Buffer) => createSign('sha384').update(data).sign({ + key: key as KeyObject, + dsaEncoding: 'ieee-p1363', + }); break; case 'ed25519': signer.sign = async (data: Buffer) => sign(null, data, key as KeyLike); @@ -108,10 +115,16 @@ export function createVerifier(key: BinaryLike | KeyLike | VerifyKeyObjectInput } as VerifyPublicKeyInput, signature); break; case 'ecdsa-p256-sha256': - verifier = async (data: Buffer, signature: Buffer) => createVerify('sha256').update(data).verify(key as KeyLike, signature); + verifier = async (data: Buffer, signature: Buffer) => createVerify('sha256').update(data).verify({ + key: key as KeyObject, + dsaEncoding: 'ieee-p1363', + }, signature); break; case 'ecdsa-p384-sha384': - verifier = async (data: Buffer, signature: Buffer) => createVerify('sha384').update(data).verify(key as KeyLike, signature); + verifier = async (data: Buffer, signature: Buffer) => createVerify('sha384').update(data).verify({ + key: key as KeyObject, + dsaEncoding: 'ieee-p1363', + }, signature); break; case 'ed25519': verifier = async (data: Buffer, signature: Buffer) => verify(null, data, key as KeyLike, signature) as unknown as boolean; diff --git a/src/types/index.ts b/src/types/index.ts index 85a7460..3dc1ffc 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -13,7 +13,7 @@ export type Signer = (data: Buffer) => Promise; export type Verifier = (data: Buffer, signature: Buffer, parameters?: SignatureParameters) => Promise; export type VerifierFinder = (parameters: SignatureParameters) => Promise; -export type Algorithm = 'rsa-v1_5-sha256' | 'ecdsa-p256-sha256' | 'hmac-sha256' | 'rsa-pss-sha512' | string; +export type Algorithm = 'rsa-v1_5-sha256' | 'ecdsa-p256-sha256' | 'ecdsa-p384-sha384' | 'ed25519' | 'hmac-sha256' | 'rsa-pss-sha512' | string; export interface SigningKey { /** diff --git a/test/algorithm/ecdsa-p256-sha256.ts b/test/algorithm/ecdsa-p256-sha256.ts index 4678349..3ed9fcc 100644 --- a/test/algorithm/ecdsa-p256-sha256.ts +++ b/test/algorithm/ecdsa-p256-sha256.ts @@ -27,14 +27,20 @@ describe('ecdsa-p256-sha256', () => { const data = Buffer.from('some random data'); const sig = await signer.sign(data); expect(signer.alg).to.equal('ecdsa-p256-sha256'); - expect(sig).to.satisfy((arg: Buffer) => verify('sha256', data, ecdsaKeyPair.publicKey, arg)); + expect(sig).to.satisfy((arg: Buffer) => verify('sha256', data, { + key: ecdsaKeyPair.publicKey, + dsaEncoding: 'ieee-p1363', + }, arg)); }); }); describe('verifying', () => { it('verifies a signature', async () => { const verifier = createVerifier(ecdsaKeyPair.publicKey, 'ecdsa-p256-sha256'); const data = Buffer.from('some random data'); - const sig = sign('sha256', data, ecdsaKeyPair.privateKey); + const sig = sign('sha256', data, { + key: ecdsaKeyPair.privateKey, + dsaEncoding: 'ieee-p1363', + }); expect(sig).to.satisfy((arg: Buffer) => verifier(data, arg)); }); }); @@ -52,11 +58,12 @@ describe('ecdsa-p256-sha256', () => { '"@signature-params": ("@status" "content-type" "content-digest" "content-length");created=1618884473;keyid="test-key-ecc-p256"'); it('successfully signs a payload', async () => { const sig = await (createSigner(ecKeyPem, 'ecdsa-p256-sha256').sign(data)); - expect(sig).to.satisfy((arg: Buffer) => verify('sha256', data, ecKeyPem, arg)); + expect(sig).to.satisfy((arg: Buffer) => verify('sha256', data, { + key: ecKeyPem, + dsaEncoding: 'ieee-p1363', + }, arg)); }); - // seems to be broken in node - Error: error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long - // could be to do with https://stackoverflow.com/a/39575576 - it.skip('successfully verifies a signature', async () => { + it('successfully verifies a signature', async () => { const sig = Buffer.from('wNmSUAhwb5LxtOtOpNa6W5xj067m5hFrj0XQ4fvpaCLx0NKocgPquLgyahnzDnDAUy5eCdlYUEkLIj+32oiasw==', 'base64'); expect(await (createVerifier(ecKeyPem, 'ecdsa-p256-sha256')(data, sig))).to.equal(true); }); diff --git a/test/algorithm/ecdsa-p384-sha384.ts b/test/algorithm/ecdsa-p384-sha384.ts index 28ecfef..41a1cb8 100644 --- a/test/algorithm/ecdsa-p384-sha384.ts +++ b/test/algorithm/ecdsa-p384-sha384.ts @@ -25,14 +25,20 @@ describe('ecdsa-p384-sha384', () => { const data = Buffer.from('some random data'); const sig = await signer.sign(data); expect(signer.alg).to.equal('ecdsa-p384-sha384'); - expect(sig).to.satisfy((arg: Buffer) => verify('sha384', data, ecdsaKeyPair.publicKey, arg)); + expect(sig).to.satisfy((arg: Buffer) => verify('sha384', data, { + key: ecdsaKeyPair.publicKey, + dsaEncoding: 'ieee-p1363', + }, arg)); }); }); describe('verifying', () => { it('verifies a signature', async () => { const verifier = createVerifier(ecdsaKeyPair.publicKey, 'ecdsa-p384-sha384'); const data = Buffer.from('some random data'); - const sig = sign('sha384', data, ecdsaKeyPair.privateKey); + const sig = sign('sha384', data, { + key: ecdsaKeyPair.privateKey, + dsaEncoding: 'ieee-p1363', + }); expect(sig).to.satisfy((arg: Buffer) => verifier(data, arg)); }); }); diff --git a/test/httpbis/httpbis.int.ts b/test/httpbis/httpbis.int.ts index 3651a4b..b309ad5 100644 --- a/test/httpbis/httpbis.int.ts +++ b/test/httpbis/httpbis.int.ts @@ -185,7 +185,7 @@ describe('httpbis', () => { res.setHeader('Content-Digest', 'sha-512=:mEWXIS7MaLRuGgxOBdODa3xqM1XdEvxoYhvlCFJ41QJgJc4GTsPp29l5oGX69wWdXymyU0rjJuahq4l5aGgfLQ==:'); res.setHeader('Content-Length', '23'); res.setHeader('Signature-Input', 'sig-b24=("@status" "content-type" "content-digest" "content-length");created=1618884473;keyid="test-key-ecc-p256"'); - res.setHeader('Signature', 'sig-b24=:MEYCIQDXrmWrcxKWLQQm0zlwbFr5/KAlB9oHkfMpNRVCuGVHjQIhAKtljVKRuRoWv5dCKuc+GgP3eqLAq+Eg0d3olyR67BYK:'); + res.setHeader('Signature', 'sig-b24=:wNmSUAhwb5LxtOtOpNa6W5xj067m5hFrj0XQ4fvpaCLx0NKocgPquLgyahnzDnDAUy5eCdlYUEkLIj+32oiasw==:'); res.end('{"message": "good dog"}'); }); return server.start(); @@ -335,8 +335,7 @@ describe('httpbis', () => { }); }); describe('ecdsa-p256-sha256', () => { - // There seems to be a problem in node in verifying ecdsa signatures from external sources - it.skip('verifies a response', async () => { + it('verifies a response', async () => { const response = await makeHttpRequest({ method: 'POST', url: 'http://example.com/foo?param=Value&Pet=dog', @@ -455,7 +454,7 @@ describe('httpbis', () => { 'content-digest': 'sha-512=:mEWXIS7MaLRuGgxOBdODa3xqM1XdEvxoYhvlCFJ41QJgJc4GTsPp29l5oGX69wWdXymyU0rjJuahq4l5aGgfLQ==:', 'content-length': '23', 'signature-input': 'sig-b24=("@status" "content-type" "content-digest" "content-length");created=1618884473;keyid="test-key-ecc-p256"', - 'signature': 'sig-b24=:MEYCIQDXrmWrcxKWLQQm0zlwbFr5/KAlB9oHkfMpNRVCuGVHjQIhAKtljVKRuRoWv5dCKuc+GgP3eqLAq+Eg0d3olyR67BYK:', + 'signature': 'sig-b24=:wNmSUAhwb5LxtOtOpNa6W5xj067m5hFrj0XQ4fvpaCLx0NKocgPquLgyahnzDnDAUy5eCdlYUEkLIj+32oiasw==:', }); stream.end('{"message": "good dog"}'); stream.close(); @@ -610,8 +609,7 @@ describe('httpbis', () => { }); }); describe('ecdsa-p256-sha256', () => { - // There seems to be a problem in node in verifying ecdsa signatures from external sources - it.skip('verifies a response', async () => { + it('verifies a response', async () => { const response = await makeHttp2Request({ method: 'POST', url: 'http://example.com/foo?param=Value&Pet=dog', @@ -634,6 +632,7 @@ describe('httpbis', () => { } return null; }); + console.log(response.headers); const valid = await httpbis.verifyMessage({ keyLookup, }, {