Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/mdoc/Verifier.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
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';

import {
calculateEphemeralMacKey,
calculateDeviceAutenticationBytes,
getAlgFromCurve,
} from './utils';

import {
DiagnosticInformation,
SupportedAlgs,
} from './model/types';
import { UserDefinedVerificationCallback, VerificationAssessment, buildCallback, onCatCheck } from './checkCallback';

Expand All @@ -29,6 +31,7 @@ const DIGEST_ALGS = {
'SHA-512': 'sha512',
} as { [key: string]: string };


export class Verifier {
/**
*
Expand Down Expand Up @@ -147,10 +150,28 @@ export class Verifier {
}

if (deviceAuth.deviceSignature) {
const deviceKey = await importCOSEKey(deviceKeyCoseKey);
const deviceKeyJwk = COSEKeyToJWK(deviceKeyCoseKey);

// 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(
Expand Down
40 changes: 40 additions & 0 deletions src/mdoc/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<string, SupportedAlgs> = {
'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;
}