From 8e681056eea3c976c01906e00a84180de96c6e6d Mon Sep 17 00:00:00 2001 From: Antonio Ivanovski Date: Fri, 14 Nov 2025 12:51:20 +0100 Subject: [PATCH 1/2] fix: missing jwk.alg --- src/mdoc/Verifier.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mdoc/Verifier.ts b/src/mdoc/Verifier.ts index 462b39f..d253d91 100644 --- a/src/mdoc/Verifier.ts +++ b/src/mdoc/Verifier.ts @@ -1,8 +1,8 @@ import { compareVersions } from 'compare-versions'; import { X509Certificate } from '@peculiar/x509'; -import { importX509, JWK, KeyLike } from 'jose'; +import { importJWK, importX509, JWK, KeyLike } from 'jose'; import { Buffer } from 'buffer'; -import { COSEKeyToJWK, Sign1, importCOSEKey } from 'cose-kit'; +import { COSEKeyToJWK, Sign1 } from 'cose-kit'; import crypto from 'uncrypto'; import { MDoc } from './model/MDoc'; @@ -147,7 +147,8 @@ export class Verifier { } if (deviceAuth.deviceSignature) { - const deviceKey = await importCOSEKey(deviceKeyCoseKey); + const deviceKeyJwk = COSEKeyToJWK(deviceKeyCoseKey); + const deviceKey = await importJWK(deviceKeyJwk, deviceKeyJwk.alg ?? deviceAuth.deviceSignature.algName); // ECDSA/EdDSA authentication try { From 46e92f88ea49a5df3a9bdeebd47aad3ce75a4c1a Mon Sep 17 00:00:00 2001 From: Antonio Ivanovski Date: Wed, 19 Nov 2025 11:23:48 +0100 Subject: [PATCH 2/2] crv alg mapping --- src/mdoc/Verifier.ts | 22 +++++++++++++++++++++- src/mdoc/utils.ts | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/mdoc/Verifier.ts b/src/mdoc/Verifier.ts index d253d91..8f1e59e 100644 --- a/src/mdoc/Verifier.ts +++ b/src/mdoc/Verifier.ts @@ -9,10 +9,12 @@ import { MDoc } from './model/MDoc'; import { calculateEphemeralMacKey, calculateDeviceAutenticationBytes, + getAlgFromCurve, } from './utils'; import { DiagnosticInformation, + SupportedAlgs, } from './model/types'; import { UserDefinedVerificationCallback, VerificationAssessment, buildCallback, onCatCheck } from './checkCallback'; @@ -29,6 +31,7 @@ const DIGEST_ALGS = { 'SHA-512': 'sha512', } as { [key: string]: string }; + export class Verifier { /** * @@ -148,10 +151,27 @@ export class Verifier { if (deviceAuth.deviceSignature) { const deviceKeyJwk = COSEKeyToJWK(deviceKeyCoseKey); - const deviceKey = await importJWK(deviceKeyJwk, deviceKeyJwk.alg ?? deviceAuth.deviceSignature.algName); + + // Determine algorithm from curve according to ISO/IEC 18013-5 + let alg: SupportedAlgs; + try { + alg = getAlgFromCurve(deviceKeyJwk.crv); + onCheck({ + status: 'PASSED', + check: `Device key curve '${deviceKeyJwk.crv}' is supported`, + }); + } catch (err) { + onCheck({ + status: 'FAILED', + check: 'Device key must use a supported curve', + reason: err.message, + }); + return; + } // ECDSA/EdDSA authentication try { + const deviceKey = await importJWK(deviceKeyJwk, alg); const ds = deviceAuth.deviceSignature; const verificationResult = await new Sign1( diff --git a/src/mdoc/utils.ts b/src/mdoc/utils.ts index cf395f0..6b7c3c8 100644 --- a/src/mdoc/utils.ts +++ b/src/mdoc/utils.ts @@ -10,6 +10,7 @@ import { COSEKeyToJWK } from 'cose-kit'; import { cborEncode, cborDecode } from '../cbor'; import { DataItem } from '../cbor/DataItem'; import COSEKeyToRAW from '../cose/coseKey'; +import { SupportedAlgs } from './model/types'; const { subtle } = webcrypto; @@ -124,3 +125,42 @@ export function fromPEM(pem: string): Uint8Array { const base64 = pem.replace(/-{5}(BEGIN|END) .*-{5}/gm, '').replace(/\s/gm, ''); return Buffer.from(base64, 'base64'); } + +/** + * Maps elliptic curve identifiers to signature algorithms according to ISO/IEC 18013-5. + * + * - ES256 (ECDSA with SHA-256): P-256, brainpoolP256r1 + * - ES384 (ECDSA with SHA-384): P-384, brainpoolP320r1, brainpoolP384r1 + * - ES512 (ECDSA with SHA-512): P-521, brainpoolP512r1 + * - EdDSA: Ed25519, Ed448 + */ +const CURVE_TO_ALG: Record = { + 'P-256': 'ES256', + 'brainpoolP256r1': 'ES256', + 'P-384': 'ES384', + 'brainpoolP320r1': 'ES384', + 'brainpoolP384r1': 'ES384', + 'P-521': 'ES512', + 'brainpoolP512r1': 'ES512', + 'Ed25519': 'EdDSA', + 'Ed448': 'EdDSA', +} as const; + +/** + * Determines the signature algorithm based on the JWK curve parameter. + * + * @param crv - The curve identifier from the JWK + * @returns The corresponding signature algorithm + * @throws Error if the curve is not supported + */ +export function getAlgFromCurve(crv: string | undefined): SupportedAlgs { + if (!crv) { + throw new Error('Missing curve (crv) parameter in device key'); + } + const alg = CURVE_TO_ALG[crv as keyof typeof CURVE_TO_ALG]; + if (!alg) { + throw new Error(`Unsupported curve: ${crv}`); + } + return alg; +} +