summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/server/src')
-rw-r--r--packages/server/src/helpers/convertCOSEtoPKCS.ts74
-rw-r--r--packages/server/src/helpers/convertPublicKeyToPEM.ts30
-rw-r--r--packages/server/src/helpers/iso/isoCrypto.ts32
-rw-r--r--packages/server/src/helpers/verifySignature.ts22
-rw-r--r--packages/server/src/metadata/verifyAttestationWithMetadata.ts36
-rw-r--r--packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts24
-rw-r--r--packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts8
-rw-r--r--packages/server/src/registration/verifications/verifyAttestationPacked.ts12
8 files changed, 171 insertions, 67 deletions
diff --git a/packages/server/src/helpers/convertCOSEtoPKCS.ts b/packages/server/src/helpers/convertCOSEtoPKCS.ts
index b9b9d09..d388d98 100644
--- a/packages/server/src/helpers/convertCOSEtoPKCS.ts
+++ b/packages/server/src/helpers/convertCOSEtoPKCS.ts
@@ -1,12 +1,13 @@
-import { COSEAlgorithmIdentifier } from '@simplewebauthn/typescript-types';
-
import { isoCBOR, isoUint8Array } from './iso';
/**
* Takes COSE-encoded public key and converts it to PKCS key
*/
export function convertCOSEtoPKCS(cosePublicKey: Uint8Array): Uint8Array {
- const struct = isoCBOR.decodeFirst<COSEPublicKey>(cosePublicKey);
+ // This is a little sloppy, I'm using COSEPublicKeyEC2 since it could have both x and y, but when
+ // there's no y it means it's probably better typed as COSEPublicKeyOKP. I'll leave this for now
+ // and revisit it later if it ever becomes an actual problem.
+ const struct = isoCBOR.decodeFirst<COSEPublicKeyEC2>(cosePublicKey);
const tag = Uint8Array.from([0x04]);
const x = struct.get(COSEKEYS.x);
@@ -17,13 +18,62 @@ export function convertCOSEtoPKCS(cosePublicKey: Uint8Array): Uint8Array {
}
if (y) {
- return isoUint8Array.concat([tag, x as Uint8Array, y as Uint8Array]);
+ return isoUint8Array.concat([tag, x, y]);
}
- return isoUint8Array.concat([tag, x as Uint8Array]);
+ return isoUint8Array.concat([tag, x]);
}
-export type COSEPublicKey = Map<COSEAlgorithmIdentifier, number | Uint8Array>;
+/**
+ * Fundamental values that are needed to discern the more specific COSE public key types below
+ */
+export type COSEPublicKey = {
+ // Getters
+ get(key: COSEKEYS.kty): COSEKTY | undefined;
+ get(key: COSEKEYS.alg): COSEALG | undefined;
+ // Setters
+ set(key: COSEKEYS.kty, value: COSEKTY): void;
+ set(key: COSEKEYS.alg, value: COSEALG): void;
+};
+
+export type COSEPublicKeyOKP = COSEPublicKey & {
+ // Getters
+ get(key: COSEKEYS.x): Uint8Array | undefined;
+ // Setters
+ set(key: COSEKEYS.x, value: Uint8Array): void;
+};
+
+export type COSEPublicKeyEC2 = COSEPublicKey & {
+ // Getters
+ get(key: COSEKEYS.crv): number | undefined;
+ get(key: COSEKEYS.x): Uint8Array | undefined;
+ get(key: COSEKEYS.y): Uint8Array | undefined;
+ // Setters
+ set(key: COSEKEYS.crv, value: number): void;
+ set(key: COSEKEYS.x, value: Uint8Array): void;
+ set(key: COSEKEYS.y, value: Uint8Array): void;
+};
+
+export type COSEPublicKeyRSA = COSEPublicKey & {
+ // Getters
+ get(key: COSEKEYS.n): Uint8Array | undefined;
+ get(key: COSEKEYS.e): Uint8Array | undefined;
+ // Setters
+ set(key: COSEKEYS.n, value: Uint8Array): void;
+ set(key: COSEKEYS.e, value: Uint8Array): void;
+};
+
+export function isCOSEPublicKeyOKP(publicKey: COSEPublicKey): publicKey is COSEPublicKeyOKP {
+ return publicKey.get(COSEKEYS.kty) === COSEKTY.OKP;
+}
+
+export function isCOSEPublicKeyEC2(publicKey: COSEPublicKey): publicKey is COSEPublicKeyEC2 {
+ return publicKey.get(COSEKEYS.kty) === COSEKTY.EC2;
+}
+
+export function isCOSEPublicKeyRSA(publicKey: COSEPublicKey): publicKey is COSEPublicKeyRSA {
+ return publicKey.get(COSEKEYS.kty) === COSEKTY.RSA;
+}
export enum COSEKEYS {
kty = 1,
@@ -48,7 +98,14 @@ export enum COSECRV {
ED25519 = 6,
}
-export type COSEALG = number;
+export const coseAlgs = [-65535, -259, -258, -257, -47, -39, -38, -37, -36, -35, -8, -7] as const;
+export type COSEALG = typeof coseAlgs[number];
+/**
+ * Ensure that a number is a valid COSE algorithm ID
+ */
+export function isCOSEAlg(alg: number): alg is COSEALG {
+ return coseAlgs.indexOf(alg as COSEALG) >= 0;
+}
export const COSERSASCHEME: { [key: string]: SigningSchemeHash } = {
'-3': 'pss-sha256',
@@ -72,11 +129,12 @@ export const coseCRV: { [key: number]: string } = {
6: 'ed25519',
};
-export const COSEALGHASH: { [key: string]: string } = {
+export const coseAlgSHAHashMap: { [K in COSEALG]: string } = {
'-65535': 'sha1',
'-259': 'sha512',
'-258': 'sha384',
'-257': 'sha256',
+ '-47': 'sha256',
'-39': 'sha512',
'-38': 'sha384',
'-37': 'sha256',
diff --git a/packages/server/src/helpers/convertPublicKeyToPEM.ts b/packages/server/src/helpers/convertPublicKeyToPEM.ts
index 2721e3a..2aa685d 100644
--- a/packages/server/src/helpers/convertPublicKeyToPEM.ts
+++ b/packages/server/src/helpers/convertPublicKeyToPEM.ts
@@ -1,27 +1,27 @@
import jwkToPem from 'jwk-to-pem';
-import { COSEKEYS, COSEKTY, coseCRV, COSEPublicKey } from './convertCOSEtoPKCS';
+import { COSEKEYS, coseCRV, COSEPublicKey, isCOSEPublicKeyEC2, isCOSEPublicKeyRSA } from './convertCOSEtoPKCS';
import { isoBase64URL, isoCBOR } from './iso';
export function convertPublicKeyToPEM(publicKey: Uint8Array): string {
- let struct;
+ let cosePublicKey;
try {
- struct = isoCBOR.decodeFirst<COSEPublicKey>(publicKey);
+ cosePublicKey = isoCBOR.decodeFirst<COSEPublicKey>(publicKey);
} catch (err) {
const _err = err as Error;
throw new Error(`Error decoding public key while converting to PEM: ${_err.message}`);
}
- const kty = struct.get(COSEKEYS.kty);
+ const kty = cosePublicKey.get(COSEKEYS.kty);
if (!kty) {
throw new Error('Public key was missing kty');
}
- if (kty === COSEKTY.EC2) {
- const crv = struct.get(COSEKEYS.crv);
- const x = struct.get(COSEKEYS.x);
- const y = struct.get(COSEKEYS.y);
+ if (isCOSEPublicKeyEC2(cosePublicKey)) {
+ const crv = cosePublicKey.get(COSEKEYS.crv);
+ const x = cosePublicKey.get(COSEKEYS.x);
+ const y = cosePublicKey.get(COSEKEYS.y);
if (!crv) {
throw new Error('Public key was missing crv (EC2)');
@@ -39,14 +39,14 @@ export function convertPublicKeyToPEM(publicKey: Uint8Array): string {
kty: 'EC',
// Specify curve as "P-256" from "p256"
crv: coseCRV[crv as number].replace('p', 'P-'),
- x: isoBase64URL.fromBuffer(x as Uint8Array, 'base64'),
- y: isoBase64URL.fromBuffer(y as Uint8Array, 'base64'),
+ x: isoBase64URL.fromBuffer(x, 'base64'),
+ y: isoBase64URL.fromBuffer(y, 'base64'),
});
return ecPEM;
- } else if (kty === COSEKTY.RSA) {
- const n = struct.get(COSEKEYS.n);
- const e = struct.get(COSEKEYS.e);
+ } else if (isCOSEPublicKeyRSA(cosePublicKey)) {
+ const n = cosePublicKey.get(COSEKEYS.n);
+ const e = cosePublicKey.get(COSEKEYS.e);
if (!n) {
throw new Error('Public key was missing n (RSA)');
@@ -58,8 +58,8 @@ export function convertPublicKeyToPEM(publicKey: Uint8Array): string {
const rsaPEM = jwkToPem({
kty: 'RSA',
- n: isoBase64URL.fromBuffer(n as Uint8Array, 'base64'),
- e: isoBase64URL.fromBuffer(e as Uint8Array, 'base64'),
+ n: isoBase64URL.fromBuffer(n, 'base64'),
+ e: isoBase64URL.fromBuffer(e, 'base64'),
});
return rsaPEM;
diff --git a/packages/server/src/helpers/iso/isoCrypto.ts b/packages/server/src/helpers/iso/isoCrypto.ts
index 42bd0a9..0296149 100644
--- a/packages/server/src/helpers/iso/isoCrypto.ts
+++ b/packages/server/src/helpers/iso/isoCrypto.ts
@@ -3,7 +3,7 @@ import { ECDSASigValue } from "@peculiar/asn1-ecc";
import { AsnParser } from '@peculiar/asn1-schema';
import { isoUint8Array, isoBase64URL } from './index';
-import { COSECRV, COSEKEYS, COSEKTY, COSEALG, COSEPublicKey } from '../convertCOSEtoPKCS';
+import { COSECRV, COSEKEYS, COSEKTY, COSEALG, COSEPublicKeyEC2, COSEPublicKeyRSA, isCOSEAlg, isCOSEPublicKeyEC2, isCOSEPublicKeyRSA } from '../convertCOSEtoPKCS';
/**
* Fill up the provided bytes array with random bytes equal to its length.
@@ -96,18 +96,18 @@ export async function verify({
* @param rsaHashAlgorithm A SHA hashing identifier for use when verifying signatures with the
* returned RSA public key (e.g. `"sha1"`, `"sha256"`, etc...), if applicable
*/
-export async function importKey(publicKey: COSEPublicKey, rsaHashAlgorithm?: string): Promise<CryptoKey> {
+export async function importKey(publicKey: COSEPublicKeyEC2 | COSEPublicKeyRSA, rsaHashAlgorithm?: string): Promise<CryptoKey> {
const kty = publicKey.get(COSEKEYS.kty);
if (!kty) {
throw new Error('Public key was missing kty');
}
- if (kty === COSEKTY.EC2) {
+ if (isCOSEPublicKeyEC2(publicKey)) {
return importECKey(publicKey);
}
- if (kty === COSEKTY.RSA) {
+ if (isCOSEPublicKeyRSA(publicKey)) {
return importRSAKey(publicKey, rsaHashAlgorithm);
}
@@ -117,7 +117,7 @@ export async function importKey(publicKey: COSEPublicKey, rsaHashAlgorithm?: str
/**
* Import an EC2 public key from its COSE representation
*/
-async function importECKey(publicKey: COSEPublicKey): Promise<CryptoKey> {
+async function importECKey(publicKey: COSEPublicKeyEC2): Promise<CryptoKey> {
const crv = publicKey.get(COSEKEYS.crv);
const x = publicKey.get(COSEKEYS.x);
const y = publicKey.get(COSEKEYS.y);
@@ -151,8 +151,8 @@ async function importECKey(publicKey: COSEPublicKey): Promise<CryptoKey> {
const jwk: JsonWebKey = {
kty: "EC",
crv: _crv,
- x: isoBase64URL.fromBuffer(x as Uint8Array),
- y: isoBase64URL.fromBuffer(y as Uint8Array),
+ x: isoBase64URL.fromBuffer(x),
+ y: isoBase64URL.fromBuffer(y),
ext: false,
};
@@ -197,35 +197,39 @@ async function verifyECSignature(
/**
* Import an RSA public key from its COSE representation
*/
-async function importRSAKey(publicKey: COSEPublicKey, hashAlgorithm?: string): Promise<CryptoKey> {
+async function importRSAKey(publicKey: COSEPublicKeyRSA, hashAlgorithm?: string): Promise<CryptoKey> {
const alg = publicKey.get(COSEKEYS.alg);
const n = publicKey.get(COSEKEYS.n);
const e = publicKey.get(COSEKEYS.e);
if (!alg) {
- throw new Error('RSA public key was missing alg');
+ throw new Error('Public key was missing alg (RSA)');
+ }
+
+ if (!isCOSEAlg(alg)) {
+ throw new Error(`Public key had invalid alg ${alg} (RSA)`);
}
if (!n) {
- throw new Error('RSA public key was missing n');
+ throw new Error('Public key was missing n (RSA)');
}
if (!e) {
- throw new Error('RSA public key was missing e');
+ throw new Error('Public key was missing e (RSA)');
}
const jwk: JsonWebKey = {
kty: 'RSA',
alg: '',
- n: isoBase64URL.fromBuffer(n as Uint8Array),
- e: isoBase64URL.fromBuffer(e as Uint8Array),
+ n: isoBase64URL.fromBuffer(n),
+ e: isoBase64URL.fromBuffer(e),
ext: false,
};
const keyAlgorithm = {
name: 'RSASSA-PKCS1-v1_5',
// This is actually the digest hash that'll get used by `.verify()`
- hash: { name: mapCoseAlgToWebCryptoAlg(alg as number) },
+ hash: { name: mapCoseAlgToWebCryptoAlg(alg) },
};
if (hashAlgorithm) {
diff --git a/packages/server/src/helpers/verifySignature.ts b/packages/server/src/helpers/verifySignature.ts
index e7b4b28..4bc38e2 100644
--- a/packages/server/src/helpers/verifySignature.ts
+++ b/packages/server/src/helpers/verifySignature.ts
@@ -5,7 +5,7 @@ import { Certificate } from '@peculiar/asn1-x509';
import { ECParameters, id_ecPublicKey, id_secp256r1 } from '@peculiar/asn1-ecc';
import { RSAPublicKey } from '@peculiar/asn1-rsa';
-import { COSECRV, COSEKEYS, COSEKTY, COSEPublicKey } from './convertCOSEtoPKCS';
+import { COSEALG, COSECRV, COSEKEYS, COSEKTY, COSEPublicKey, COSEPublicKeyEC2, COSEPublicKeyRSA, isCOSEAlg, isCOSEPublicKeyOKP } from './convertCOSEtoPKCS';
import { isoCrypto } from './iso';
import { decodeCredentialPublicKey } from './decodeCredentialPublicKey';
@@ -43,7 +43,7 @@ export async function verifySignature(
let subtlePublicKey: CryptoKey;
let kty: COSEKTY;
- let alg: number;
+ let alg: COSEALG;
if (_isCredPubKeyOpts) {
const { publicKey } = opts;
@@ -61,21 +61,25 @@ export async function verifySignature(
throw new Error('Public key was missing alg');
}
+ if (!isCOSEAlg(_alg)) {
+ throw new Error(`Public key contained invalid alg ${_alg}`);
+ }
+
// Verify Ed25519 slightly differently
- if (_kty === COSEKTY.OKP) {
+ if (isCOSEPublicKeyOKP(cosePublicKey)) {
const x = cosePublicKey.get(COSEKEYS.x);
if (!x) {
throw new Error('Public key was missing x (OKP)');
}
- return ed25519Verify(signature, data, (x as Uint8Array));
+ return ed25519Verify(signature, data, x);
}
// Assume we're handling COSEKTY.EC2 or COSEKTY.RSA key from here on
- subtlePublicKey = await isoCrypto.importKey(cosePublicKey);
+ subtlePublicKey = await isoCrypto.importKey(cosePublicKey as COSEPublicKeyEC2 | COSEPublicKeyRSA);
kty = _kty as COSEKTY;
- alg = _alg as number;
+ alg = _alg;
} else if (_isLeafcertOpts) {
/**
* Time to extract the public key from an X.509 leaf certificate
@@ -130,7 +134,7 @@ export async function verifySignature(
throw new Error('TODO: Figure out how to handle public keys in "compressed form"');
}
- const coseEC2PubKey: COSEPublicKey = new Map();
+ const coseEC2PubKey: COSEPublicKeyEC2 = new Map();
coseEC2PubKey.set(COSEKEYS.kty, COSEKTY.EC2);
coseEC2PubKey.set(COSEKEYS.crv, crv);
coseEC2PubKey.set(COSEKEYS.x, x);
@@ -145,7 +149,7 @@ export async function verifySignature(
kty = COSEKTY.RSA;
const rsaPublicKey = AsnParser.parse(subjectPublicKeyInfo.subjectPublicKey, RSAPublicKey);
- let _alg = -999;
+ let _alg: COSEALG;
if (signatureAlgorithm === '1.2.840.113549.1.1.11') {
_alg = -257; // RS256
} else if (signatureAlgorithm === '1.2.840.113549.1.1.12') {
@@ -158,7 +162,7 @@ export async function verifySignature(
);
}
- const coseRSAPubKey: COSEPublicKey = new Map();
+ const coseRSAPubKey: COSEPublicKeyRSA = new Map();
coseRSAPubKey.set(COSEKEYS.kty, COSEKTY.RSA);
coseRSAPubKey.set(COSEKEYS.alg, _alg);
coseRSAPubKey.set(COSEKEYS.n, new Uint8Array(rsaPublicKey.modulus));
diff --git a/packages/server/src/metadata/verifyAttestationWithMetadata.ts b/packages/server/src/metadata/verifyAttestationWithMetadata.ts
index aa45809..80a0142 100644
--- a/packages/server/src/metadata/verifyAttestationWithMetadata.ts
+++ b/packages/server/src/metadata/verifyAttestationWithMetadata.ts
@@ -4,7 +4,7 @@ import type { MetadataStatement, AlgSign } from '../metadata/mdsTypes';
import { convertCertBufferToPEM } from '../helpers/convertCertBufferToPEM';
import { validateCertificatePath } from '../helpers/validateCertificatePath';
import { decodeCredentialPublicKey } from '../helpers/decodeCredentialPublicKey';
-import { COSEKEYS, COSEKTY } from '../helpers/convertCOSEtoPKCS';
+import { COSEALG, COSECRV, COSEKEYS, COSEKTY, COSEPublicKeyEC2, isCOSEPublicKeyEC2 } from '../helpers/convertCOSEtoPKCS';
/**
* Match properties of the authenticator's attestation statement against expected values as
@@ -41,14 +41,28 @@ export async function verifyAttestationWithMetadata({
// Extract the public key's COSE info for comparison
const decodedPublicKey = decodeCredentialPublicKey(credentialPublicKey);
+
+ const kty = decodedPublicKey.get(COSEKEYS.kty);
+ const alg = decodedPublicKey.get(COSEKEYS.alg);
+
+ if (!kty) {
+ throw new Error('Credential public key was missing kty');
+ }
+
+ if (!alg) {
+ throw new Error('Credential public key was missing alg');
+ }
+
+ if (!kty) {
+ throw new Error('Credential public key was missing kty');
+ }
+
// Assume everything is a number because these values should be
- const publicKeyCOSEInfo: COSEInfo = {
- kty: decodedPublicKey.get(COSEKEYS.kty) as number,
- alg: decodedPublicKey.get(COSEKEYS.alg) as number,
- crv: decodedPublicKey.get(COSEKEYS.crv) as number,
- };
- if (!publicKeyCOSEInfo.crv) {
- delete publicKeyCOSEInfo.crv;
+ const publicKeyCOSEInfo: COSEInfo = { kty, alg };
+
+ if (isCOSEPublicKeyEC2(decodedPublicKey)) {
+ const crv = decodedPublicKey.get(COSEKEYS.crv);
+ publicKeyCOSEInfo.crv = crv;
}
/**
@@ -148,9 +162,9 @@ export async function verifyAttestationWithMetadata({
}
type COSEInfo = {
- kty: number;
- alg: number;
- crv?: number;
+ kty: COSEKTY;
+ alg: COSEALG;
+ crv?: COSECRV;
};
/**
diff --git a/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts b/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts
index 45ccca8..7a147e3 100644
--- a/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts
+++ b/packages/server/src/registration/verifications/tpm/verifyAttestationTPM.ts
@@ -11,7 +11,7 @@ import {
import type { AttestationFormatVerifierOpts } from '../../verifyRegistrationResponse';
import { decodeCredentialPublicKey } from '../../../helpers/decodeCredentialPublicKey';
-import { COSEKEYS, COSEALGHASH } from '../../../helpers/convertCOSEtoPKCS';
+import { COSEKEYS, coseAlgSHAHashMap, isCOSEAlg, isCOSEPublicKeyEC2, isCOSEPublicKeyRSA } from '../../../helpers/convertCOSEtoPKCS';
import { toHash } from '../../../helpers/toHash';
import { convertCertBufferToPEM } from '../../../helpers/convertCertBufferToPEM';
import { validateCertificatePath } from '../../../helpers/validateCertificatePath';
@@ -50,6 +50,10 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt
throw new Error(`Attestation statement did not contain alg (TPM)`);
}
+ if (!isCOSEAlg(alg)) {
+ throw new Error(`Attestation statement contained invalid alg ${alg} (TPM)`);
+ }
+
if (!x5c) {
throw new Error('No attestation certificate provided in attestation statement (TPM)');
}
@@ -70,6 +74,12 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt
const cosePublicKey = decodeCredentialPublicKey(credentialPublicKey);
if (pubType === 'TPM_ALG_RSA') {
+ if (!isCOSEPublicKeyRSA(cosePublicKey)) {
+ throw new Error(
+ `Credential public key with kty ${cosePublicKey.get(COSEKEYS.kty)} did not match ${pubType}`,
+ );
+ }
+
const n = cosePublicKey.get(COSEKEYS.n);
const e = cosePublicKey.get(COSEKEYS.e);
@@ -80,7 +90,7 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt
throw new Error('COSE public key missing e (TPM|RSA)');
}
- if (!isoUint8Array.areEqual(unique, (n as Uint8Array))) {
+ if (!isoUint8Array.areEqual(unique, n)) {
throw new Error('PubArea unique is not same as credentialPublicKey (TPM|RSA)');
}
@@ -99,6 +109,12 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt
throw new Error(`Unexpected public key exp ${eSum}, expected ${pubAreaExponent} (TPM|RSA)`);
}
} else if (pubType === 'TPM_ALG_ECC') {
+ if (!isCOSEPublicKeyEC2(cosePublicKey)) {
+ throw new Error(
+ `Credential public key with kty ${cosePublicKey.get(COSEKEYS.kty)} did not match ${pubType}`,
+ );
+ }
+
const crv = cosePublicKey.get(COSEKEYS.crv);
const x = cosePublicKey.get(COSEKEYS.x);
const y = cosePublicKey.get(COSEKEYS.y);
@@ -113,7 +129,7 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt
throw new Error('COSE public key missing y (TPM|ECC)');
}
- if (!isoUint8Array.areEqual(unique, isoUint8Array.concat([x as Uint8Array, y as Uint8Array]))) {
+ if (!isoUint8Array.areEqual(unique, isoUint8Array.concat([x, y]))) {
throw new Error('PubArea unique is not same as public key x and y (TPM|ECC)');
}
@@ -158,7 +174,7 @@ export async function verifyAttestationTPM(options: AttestationFormatVerifierOpt
const attToBeSigned = isoUint8Array.concat([authData, clientDataHash]);
// Hash attToBeSigned using the algorithm specified in attStmt.alg to create attToBeSignedHash
- const hashAlg: string = COSEALGHASH[alg as number];
+ const hashAlg: string = coseAlgSHAHashMap[alg];
const attToBeSignedHash = await toHash(attToBeSigned, hashAlg);
// Check that certInfo.extraData is equals to attToBeSignedHash.
diff --git a/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts b/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts
index af2daf9..1287ac0 100644
--- a/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts
+++ b/packages/server/src/registration/verifications/verifyAttestationAndroidKey.ts
@@ -7,7 +7,7 @@ import type { AttestationFormatVerifierOpts } from '../verifyRegistrationRespons
import { convertCertBufferToPEM } from '../../helpers/convertCertBufferToPEM';
import { validateCertificatePath } from '../../helpers/validateCertificatePath';
import { verifySignature } from '../../helpers/verifySignature';
-import { COSEALGHASH, convertCOSEtoPKCS } from '../../helpers/convertCOSEtoPKCS';
+import { coseAlgSHAHashMap, convertCOSEtoPKCS, isCOSEAlg } from '../../helpers/convertCOSEtoPKCS';
import { isoUint8Array } from '../../helpers/iso';
import { MetadataService } from '../../services/metadataService';
import { verifyAttestationWithMetadata } from '../../metadata/verifyAttestationWithMetadata';
@@ -36,6 +36,10 @@ export async function verifyAttestationAndroidKey(
throw new Error(`Attestation statement did not contain alg (AndroidKey)`);
}
+ if (!isCOSEAlg(alg)) {
+ throw new Error(`Attestation statement contained invalid alg ${alg} (AndroidKey)`);
+ }
+
// Check that credentialPublicKey matches the public key in the attestation certificate
// Find the public cert in the certificate as PKCS
const parsedCert = AsnParser.parse(x5c[0], Certificate);
@@ -102,7 +106,7 @@ export async function verifyAttestationAndroidKey(
}
const signatureBase = isoUint8Array.concat([authData, clientDataHash]);
- const hashAlg = COSEALGHASH[alg as number];
+ const hashAlg = coseAlgSHAHashMap[alg];
return verifySignature({
signature: sig,
diff --git a/packages/server/src/registration/verifications/verifyAttestationPacked.ts b/packages/server/src/registration/verifications/verifyAttestationPacked.ts
index 5f00847..bf3fbc7 100644
--- a/packages/server/src/registration/verifications/verifyAttestationPacked.ts
+++ b/packages/server/src/registration/verifications/verifyAttestationPacked.ts
@@ -1,6 +1,6 @@
import type { AttestationFormatVerifierOpts } from '../verifyRegistrationResponse';
-import { COSEALGHASH } from '../../helpers/convertCOSEtoPKCS';
+import { coseAlgSHAHashMap, isCOSEAlg } from '../../helpers/convertCOSEtoPKCS';
import { convertCertBufferToPEM } from '../../helpers/convertCertBufferToPEM';
import { validateCertificatePath } from '../../helpers/validateCertificatePath';
import { getCertificateInfo } from '../../helpers/getCertificateInfo';
@@ -26,8 +26,12 @@ export async function verifyAttestationPacked(
throw new Error('No attestation signature provided in attestation statement (Packed)');
}
- if (typeof alg !== 'number') {
- throw new Error(`Attestation Statement alg "${alg}" is not a number (Packed)`);
+ if (!alg) {
+ throw new Error('Attestation statement did not contain alg (Packed)');
+ }
+
+ if (!isCOSEAlg(alg)) {
+ throw new Error(`Attestation statement contained invalid alg ${alg} (Packed)`);
}
const signatureBase = isoUint8Array.concat([authData, clientDataHash]);
@@ -114,7 +118,7 @@ export async function verifyAttestationPacked(
leafCert: x5c[0],
});
} else {
- const hashAlg: string = COSEALGHASH[alg as number];
+ const hashAlg: string = coseAlgSHAHashMap[alg];
verified = await verifySignature({
signature: sig,