summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/server/src')
-rw-r--r--packages/server/src/authentication/generateAuthenticationOptions.test.ts3
-rw-r--r--packages/server/src/authentication/generateAuthenticationOptions.ts10
-rw-r--r--packages/server/src/helpers/convertCertBufferToPEM.ts2
-rw-r--r--packages/server/src/helpers/convertX509PublicKeyToCOSE.ts24
-rw-r--r--packages/server/src/helpers/cose.ts14
-rw-r--r--packages/server/src/helpers/decodeAuthenticatorExtensions.test.ts10
-rw-r--r--packages/server/src/helpers/decodeClientDataJSON.ts2
-rw-r--r--packages/server/src/helpers/matchExpectedRPID.ts29
-rw-r--r--packages/server/src/helpers/parseAuthenticatorData.test.ts9
-rw-r--r--packages/server/src/helpers/toHash.ts5
-rw-r--r--packages/server/src/metadata/mdsTypes.ts2
-rw-r--r--packages/server/src/metadata/parseJWT.ts2
-rw-r--r--packages/server/src/metadata/verifyAttestationWithMetadata.test.ts136
-rw-r--r--packages/server/src/metadata/verifyAttestationWithMetadata.ts25
-rw-r--r--packages/server/src/registration/generateRegistrationOptions.test.ts4
-rw-r--r--packages/server/src/registration/verifyRegistrationResponse.test.ts6
-rw-r--r--packages/server/src/registration/verifyRegistrationResponse.ts2
17 files changed, 159 insertions, 126 deletions
diff --git a/packages/server/src/authentication/generateAuthenticationOptions.test.ts b/packages/server/src/authentication/generateAuthenticationOptions.test.ts
index 65dc66e..9048cf5 100644
--- a/packages/server/src/authentication/generateAuthenticationOptions.test.ts
+++ b/packages/server/src/authentication/generateAuthenticationOptions.test.ts
@@ -5,10 +5,9 @@ import { isoBase64URL } from '../helpers/iso';
import { generateAuthenticationOptions } from './generateAuthenticationOptions';
const challengeString = 'dG90YWxseXJhbmRvbXZhbHVl';
-const challengeBuffer = isoBase64URL.toBuffer(challengeString)
+const challengeBuffer = isoBase64URL.toBuffer(challengeString);
test('should generate credential request options suitable for sending via JSON', () => {
-
const options = generateAuthenticationOptions({
allowCredentials: [
{
diff --git a/packages/server/src/authentication/generateAuthenticationOptions.ts b/packages/server/src/authentication/generateAuthenticationOptions.ts
index 3847b39..bd517e3 100644
--- a/packages/server/src/authentication/generateAuthenticationOptions.ts
+++ b/packages/server/src/authentication/generateAuthenticationOptions.ts
@@ -5,7 +5,7 @@ import type {
UserVerificationRequirement,
} from '@simplewebauthn/typescript-types';
-import { isoBase64URL, isoUint8Array } from '../helpers/iso'
+import { isoBase64URL, isoUint8Array } from '../helpers/iso';
import { generateChallenge } from '../helpers/generateChallenge';
export type GenerateAuthenticationOptionsOpts = {
@@ -45,10 +45,10 @@ export function generateAuthenticationOptions(
/**
* Preserve ability to specify `string` values for challenges
*/
- let _challenge = challenge;
- if (typeof _challenge === 'string') {
- _challenge = isoUint8Array.fromUTF8String(_challenge);
- }
+ let _challenge = challenge;
+ if (typeof _challenge === 'string') {
+ _challenge = isoUint8Array.fromUTF8String(_challenge);
+ }
return {
challenge: isoBase64URL.fromBuffer(_challenge),
diff --git a/packages/server/src/helpers/convertCertBufferToPEM.ts b/packages/server/src/helpers/convertCertBufferToPEM.ts
index 0179eee..adf4201 100644
--- a/packages/server/src/helpers/convertCertBufferToPEM.ts
+++ b/packages/server/src/helpers/convertCertBufferToPEM.ts
@@ -15,7 +15,7 @@ export function convertCertBufferToPEM(certBuffer: Uint8Array | Base64URLString)
if (isoBase64URL.isBase64url(certBuffer)) {
b64cert = isoBase64URL.toBase64(certBuffer);
} else if (isoBase64URL.isBase64(certBuffer)) {
- b64cert = certBuffer
+ b64cert = certBuffer;
} else {
throw new Error('Certificate is not a valid base64 or base64url string');
}
diff --git a/packages/server/src/helpers/convertX509PublicKeyToCOSE.ts b/packages/server/src/helpers/convertX509PublicKeyToCOSE.ts
index de51c7d..cd76146 100644
--- a/packages/server/src/helpers/convertX509PublicKeyToCOSE.ts
+++ b/packages/server/src/helpers/convertX509PublicKeyToCOSE.ts
@@ -3,7 +3,15 @@ import { Certificate } from '@peculiar/asn1-x509';
import { ECParameters, id_ecPublicKey, id_secp256r1 } from '@peculiar/asn1-ecc';
import { RSAPublicKey } from '@peculiar/asn1-rsa';
-import { COSEPublicKey, COSEKTY, COSECRV, COSEKEYS, COSEPublicKeyEC2, COSEPublicKeyRSA, COSEALG } from "./cose";
+import {
+ COSEPublicKey,
+ COSEKTY,
+ COSECRV,
+ COSEKEYS,
+ COSEPublicKeyEC2,
+ COSEPublicKeyRSA,
+ COSEALG,
+} from './cose';
export function convertX509PublicKeyToCOSE(leafCertificate: Uint8Array): COSEPublicKey {
let cosePublicKey: COSEPublicKey = new Map();
@@ -14,10 +22,7 @@ export function convertX509PublicKeyToCOSE(leafCertificate: Uint8Array): COSEPub
const x509 = AsnParser.parse(leafCertificate, Certificate);
const { tbsCertificate } = x509;
- const {
- subjectPublicKeyInfo,
- signature: _tbsSignature,
- } = tbsCertificate;
+ const { subjectPublicKeyInfo, signature: _tbsSignature } = tbsCertificate;
const signatureAlgorithm = _tbsSignature.algorithm;
const publicKeyAlgorithmID = subjectPublicKeyInfo.algorithm.algorithm;
@@ -30,7 +35,10 @@ export function convertX509PublicKeyToCOSE(leafCertificate: Uint8Array): COSEPub
throw new Error('Leaf cert public key missing parameters (EC2)');
}
- const ecParameters = AsnParser.parse(new Uint8Array(subjectPublicKeyInfo.algorithm.parameters), ECParameters);
+ const ecParameters = AsnParser.parse(
+ new Uint8Array(subjectPublicKeyInfo.algorithm.parameters),
+ ECParameters,
+ );
let crv = -999;
if (ecParameters.namedCurve === id_secp256r1) {
@@ -41,7 +49,7 @@ export function convertX509PublicKeyToCOSE(leafCertificate: Uint8Array): COSEPub
);
}
- const subjectPublicKey = new Uint8Array(subjectPublicKeyInfo.subjectPublicKey)
+ const subjectPublicKey = new Uint8Array(subjectPublicKeyInfo.subjectPublicKey);
let x: Uint8Array;
let y: Uint8Array;
@@ -49,7 +57,7 @@ export function convertX509PublicKeyToCOSE(leafCertificate: Uint8Array): COSEPub
// Public key is in "uncompressed form", so we can split the remaining bytes in half
let pointer = 1;
const halfLength = (subjectPublicKey.length - 1) / 2;
- x = subjectPublicKey.slice(pointer, pointer += halfLength);
+ x = subjectPublicKey.slice(pointer, (pointer += halfLength));
y = subjectPublicKey.slice(pointer);
} else {
throw new Error('TODO: Figure out how to handle public keys in "compressed form"');
diff --git a/packages/server/src/helpers/cose.ts b/packages/server/src/helpers/cose.ts
index d4e08f3..2f2e446 100644
--- a/packages/server/src/helpers/cose.ts
+++ b/packages/server/src/helpers/cose.ts
@@ -8,7 +8,7 @@
* These types are an unorthodox way of saying "these Maps should involve these discrete lists of
* keys", but it works.
*/
- export type COSEPublicKey = {
+export type COSEPublicKey = {
// Getters
get(key: COSEKEYS.kty): COSEKTY | undefined;
get(key: COSEKEYS.alg): COSEALG | undefined;
@@ -46,17 +46,23 @@ export type COSEPublicKeyRSA = COSEPublicKey & {
set(key: COSEKEYS.e, value: Uint8Array): void;
};
-export function isCOSEPublicKeyOKP(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyOKP {
+export function isCOSEPublicKeyOKP(
+ cosePublicKey: COSEPublicKey,
+): cosePublicKey is COSEPublicKeyOKP {
const kty = cosePublicKey.get(COSEKEYS.kty);
return isCOSEKty(kty) && kty === COSEKTY.OKP;
}
-export function isCOSEPublicKeyEC2(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyEC2 {
+export function isCOSEPublicKeyEC2(
+ cosePublicKey: COSEPublicKey,
+): cosePublicKey is COSEPublicKeyEC2 {
const kty = cosePublicKey.get(COSEKEYS.kty);
return isCOSEKty(kty) && kty === COSEKTY.EC2;
}
-export function isCOSEPublicKeyRSA(cosePublicKey: COSEPublicKey): cosePublicKey is COSEPublicKeyRSA {
+export function isCOSEPublicKeyRSA(
+ cosePublicKey: COSEPublicKey,
+): cosePublicKey is COSEPublicKeyRSA {
const kty = cosePublicKey.get(COSEKEYS.kty);
return isCOSEKty(kty) && kty === COSEKTY.RSA;
}
diff --git a/packages/server/src/helpers/decodeAuthenticatorExtensions.test.ts b/packages/server/src/helpers/decodeAuthenticatorExtensions.test.ts
index 8afa3d7..6cc5e24 100644
--- a/packages/server/src/helpers/decodeAuthenticatorExtensions.test.ts
+++ b/packages/server/src/helpers/decodeAuthenticatorExtensions.test.ts
@@ -5,11 +5,11 @@ test('should decode authenticator extensions', () => {
const extensions = decodeAuthenticatorExtensions(
isoUint8Array.fromHex(
'A16C6465766963655075624B6579A56364706B584DA5010203262001215820991AABED9D' +
- 'E4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB' +
- '79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA63736967584730450221' +
- '00EFB38074BD15B8C82CF09F87FBC6FB3C7169EA4F1806B7E90937374302345B7A02202B' +
- '7113040731A0E727D338D48542863CE65880AA79E5EA740AC8CCD94347988E656E6F6E63' +
- '65406573636F70654100666161677569645000000000000000000000000000000000',
+ 'E4271A9EDEAD8806F9DC96D6DCCD0C476253A5510489EC8379BE5B225820A0973CFDEDBB' +
+ '79E27FEF4EE7481673FB3312504DDCA5434CFD23431D6AD29EDA63736967584730450221' +
+ '00EFB38074BD15B8C82CF09F87FBC6FB3C7169EA4F1806B7E90937374302345B7A02202B' +
+ '7113040731A0E727D338D48542863CE65880AA79E5EA740AC8CCD94347988E656E6F6E63' +
+ '65406573636F70654100666161677569645000000000000000000000000000000000',
),
);
expect(extensions).toMatchObject({
diff --git a/packages/server/src/helpers/decodeClientDataJSON.ts b/packages/server/src/helpers/decodeClientDataJSON.ts
index 36a949e..e0de0a0 100644
--- a/packages/server/src/helpers/decodeClientDataJSON.ts
+++ b/packages/server/src/helpers/decodeClientDataJSON.ts
@@ -1,4 +1,4 @@
-import { isoBase64URL } from "./iso";
+import { isoBase64URL } from './iso';
/**
* Decode an authenticator's base64url-encoded clientDataJSON to JSON
diff --git a/packages/server/src/helpers/matchExpectedRPID.ts b/packages/server/src/helpers/matchExpectedRPID.ts
index 76991bf..be49fc2 100644
--- a/packages/server/src/helpers/matchExpectedRPID.ts
+++ b/packages/server/src/helpers/matchExpectedRPID.ts
@@ -4,19 +4,24 @@ import { isoUint8Array } from './iso';
/**
* Go through each expected RP ID and try to find one that matches. Raises an Error if no
*/
-export async function matchExpectedRPID(rpIDHash: Uint8Array, expectedRPIDs: string[]): Promise<void> {
+export async function matchExpectedRPID(
+ rpIDHash: Uint8Array,
+ expectedRPIDs: string[],
+): Promise<void> {
try {
- await Promise.any(expectedRPIDs.map((expected) => {
- return new Promise((resolve, reject) => {
- toHash(isoUint8Array.fromASCIIString(expected)).then((expectedRPIDHash) => {
- if (isoUint8Array.areEqual(rpIDHash, expectedRPIDHash)) {
- resolve(true);
- } else {
- reject();
- }
- })
- });
- }));
+ await Promise.any(
+ expectedRPIDs.map(expected => {
+ return new Promise((resolve, reject) => {
+ toHash(isoUint8Array.fromASCIIString(expected)).then(expectedRPIDHash => {
+ if (isoUint8Array.areEqual(rpIDHash, expectedRPIDHash)) {
+ resolve(true);
+ } else {
+ reject();
+ }
+ });
+ });
+ }),
+ );
} catch (err) {
const _err = err as Error;
diff --git a/packages/server/src/helpers/parseAuthenticatorData.test.ts b/packages/server/src/helpers/parseAuthenticatorData.test.ts
index 7885b32..1db4bfe 100644
--- a/packages/server/src/helpers/parseAuthenticatorData.test.ts
+++ b/packages/server/src/helpers/parseAuthenticatorData.test.ts
@@ -2,7 +2,10 @@ import { parseAuthenticatorData } from './parseAuthenticatorData';
import { isoBase64URL } from './iso';
// Grabbed this from a Conformance test, contains attestation data
-const authDataWithAT = isoBase64URL.toBuffer('SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2NBAAAAJch83ZdWwUm4niTLNjZU81AAIHa7Ksm5br3hAh3UjxP9+4rqu8BEsD+7SZ2xWe1/yHv6pAEDAzkBACBZAQDcxA7Ehs9goWB2Hbl6e9v+aUub9rvy2M7Hkvf+iCzMGE63e3sCEW5Ru33KNy4um46s9jalcBHtZgtEnyeRoQvszis+ws5o4Da0vQfuzlpBmjWT1dV6LuP+vs9wrfObW4jlA5bKEIhv63+jAxOtdXGVzo75PxBlqxrmrr5IR9n8Fw7clwRsDkjgRHaNcQVbwq/qdNwU5H3hZKu9szTwBS5NGRq01EaDF2014YSTFjwtAmZ3PU1tcO/QD2U2zg6eB5grfWDeAJtRE8cbndDWc8aLL0aeC37Q36+TVsGe6AhBgHEw6eO3I3NW5r9v/26CqMPBDwmEundeq1iGyKfMloobIUMBAAE=', 'base64');
+const authDataWithAT = isoBase64URL.toBuffer(
+ 'SZYN5YgOjGh0NBcPZHZgW4/krrmihjLHmVzzuoMdl2NBAAAAJch83ZdWwUm4niTLNjZU81AAIHa7Ksm5br3hAh3UjxP9+4rqu8BEsD+7SZ2xWe1/yHv6pAEDAzkBACBZAQDcxA7Ehs9goWB2Hbl6e9v+aUub9rvy2M7Hkvf+iCzMGE63e3sCEW5Ru33KNy4um46s9jalcBHtZgtEnyeRoQvszis+ws5o4Da0vQfuzlpBmjWT1dV6LuP+vs9wrfObW4jlA5bKEIhv63+jAxOtdXGVzo75PxBlqxrmrr5IR9n8Fw7clwRsDkjgRHaNcQVbwq/qdNwU5H3hZKu9szTwBS5NGRq01EaDF2014YSTFjwtAmZ3PU1tcO/QD2U2zg6eB5grfWDeAJtRE8cbndDWc8aLL0aeC37Q36+TVsGe6AhBgHEw6eO3I3NW5r9v/26CqMPBDwmEundeq1iGyKfMloobIUMBAAE=',
+ 'base64',
+);
// Grabbed this from a Conformance test, contains extension data
const authDataWithED = Buffer.from(
@@ -28,7 +31,9 @@ test('should parse attestation data', () => {
const { credentialID, credentialPublicKey, aaguid, counter } = parsed;
- expect(isoBase64URL.fromBuffer(credentialID!)).toEqual('drsqybluveECHdSPE_37iuq7wESwP7tJnbFZ7X_Ie_o');
+ expect(isoBase64URL.fromBuffer(credentialID!)).toEqual(
+ 'drsqybluveECHdSPE_37iuq7wESwP7tJnbFZ7X_Ie_o',
+ );
expect(isoBase64URL.fromBuffer(credentialPublicKey!, 'base64')).toEqual(
'pAEDAzkBACBZAQDcxA7Ehs9goWB2Hbl6e9v+aUub9rvy2M7Hkvf+iCzMGE63e3sCEW5Ru33KNy4um46s9jalcBHtZgtEnyeRoQvszis+ws5o4Da0vQfuzlpBmjWT1dV6LuP+vs9wrfObW4jlA5bKEIhv63+jAxOtdXGVzo75PxBlqxrmrr5IR9n8Fw7clwRsDkjgRHaNcQVbwq/qdNwU5H3hZKu9szTwBS5NGRq01EaDF2014YSTFjwtAmZ3PU1tcO/QD2U2zg6eB5grfWDeAJtRE8cbndDWc8aLL0aeC37Q36+TVsGe6AhBgHEw6eO3I3NW5r9v/26CqMPBDwmEundeq1iGyKfMloobIUMBAAE=',
);
diff --git a/packages/server/src/helpers/toHash.ts b/packages/server/src/helpers/toHash.ts
index 2f8dc30..90edd4e 100644
--- a/packages/server/src/helpers/toHash.ts
+++ b/packages/server/src/helpers/toHash.ts
@@ -5,7 +5,10 @@ import { isoUint8Array, isoCrypto } from './iso';
* Returns hash digest of the given data, using the given algorithm when provided. Defaults to using
* SHA-256.
*/
-export async function toHash(data: Uint8Array | string, algorithm: COSEALG = -7): Promise<Uint8Array> {
+export async function toHash(
+ data: Uint8Array | string,
+ algorithm: COSEALG = -7,
+): Promise<Uint8Array> {
if (typeof data === 'string') {
data = isoUint8Array.fromUTF8String(data);
}
diff --git a/packages/server/src/metadata/mdsTypes.ts b/packages/server/src/metadata/mdsTypes.ts
index 1bf9f80..d86f587 100644
--- a/packages/server/src/metadata/mdsTypes.ts
+++ b/packages/server/src/metadata/mdsTypes.ts
@@ -292,5 +292,5 @@ export type AuthenticatorGetInfo = {
};
maxMsgSize?: number;
pinProtocols?: number[];
- algorithms?: { type: 'public-key', alg: number }[];
+ algorithms?: { type: 'public-key'; alg: number }[];
};
diff --git a/packages/server/src/metadata/parseJWT.ts b/packages/server/src/metadata/parseJWT.ts
index 7b1a291..beb2501 100644
--- a/packages/server/src/metadata/parseJWT.ts
+++ b/packages/server/src/metadata/parseJWT.ts
@@ -1,4 +1,4 @@
-import { isoBase64URL } from "../helpers/iso";
+import { isoBase64URL } from '../helpers/iso';
/**
* Process a JWT into Javascript-friendly data structures
diff --git a/packages/server/src/metadata/verifyAttestationWithMetadata.test.ts b/packages/server/src/metadata/verifyAttestationWithMetadata.test.ts
index 57751b1..c76fb1d 100644
--- a/packages/server/src/metadata/verifyAttestationWithMetadata.test.ts
+++ b/packages/server/src/metadata/verifyAttestationWithMetadata.test.ts
@@ -57,44 +57,45 @@ test('should verify attestation with metadata (android-safetynet)', async () =>
test('should verify attestation with rsa_emsa_pkcs1_sha256_raw authenticator algorithm in metadata', async () => {
const metadataStatement: MetadataStatement = {
- 'legalHeader': 'https://fidoalliance.org/metadata/metadata-statement-legal-header/',
- 'aaguid': '08987058-cadc-4b81-b6e1-30de50dcbe96',
- 'description': 'Windows Hello Hardware Authenticator',
- 'authenticatorVersion': 1,
- 'protocolFamily': 'fido2',
- 'schema': 3,
- 'upv': [{ 'major': 1, 'minor': 0 }],
- 'authenticationAlgorithms': ['rsassa_pkcsv15_sha256_raw'],
- 'publicKeyAlgAndEncodings': ['cose'],
- 'attestationTypes': ['attca'],
- 'userVerificationDetails': [
- [{ 'userVerificationMethod': 'eyeprint_internal' }],
- [{ 'userVerificationMethod': 'passcode_internal' }],
- [{ 'userVerificationMethod': 'fingerprint_internal' }],
- [{ 'userVerificationMethod': 'faceprint_internal' }]
+ legalHeader: 'https://fidoalliance.org/metadata/metadata-statement-legal-header/',
+ aaguid: '08987058-cadc-4b81-b6e1-30de50dcbe96',
+ description: 'Windows Hello Hardware Authenticator',
+ authenticatorVersion: 1,
+ protocolFamily: 'fido2',
+ schema: 3,
+ upv: [{ major: 1, minor: 0 }],
+ authenticationAlgorithms: ['rsassa_pkcsv15_sha256_raw'],
+ publicKeyAlgAndEncodings: ['cose'],
+ attestationTypes: ['attca'],
+ userVerificationDetails: [
+ [{ userVerificationMethod: 'eyeprint_internal' }],
+ [{ userVerificationMethod: 'passcode_internal' }],
+ [{ userVerificationMethod: 'fingerprint_internal' }],
+ [{ userVerificationMethod: 'faceprint_internal' }],
],
- 'keyProtection': ['hardware'],
- 'isKeyRestricted': false,
- 'matcherProtection': ['software'],
- 'attachmentHint': ['internal'],
- 'tcDisplay': [],
- 'attestationRootCertificates': [
- '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'
+ keyProtection: ['hardware'],
+ isKeyRestricted: false,
+ matcherProtection: ['software'],
+ attachmentHint: ['internal'],
+ tcDisplay: [],
+ attestationRootCertificates: [
+ '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',
],
- 'icon': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAACkUlEQVR42uyai3GDMAyGQyegGzACnaCMkBHoBhkhnSAj0A2SDaAT0E6QbEA3cOXW6XEpBtnImMv9utOllxjF/qKHLTdRSm0gdnkAAgACIAACIAACIAACIAgAARAAARAAARAAARBEAFCSJINKkpLuSTtSZbQz76W25zhKkpFWPbtaz6Q75vPuoluuPmqxlZK2yi76s9RznjlpN2K7CrFWaUAHNS0HT0Atw3YpDSjxbdoPuaziG3uk579cvIdeWsbQD7L7NAYoWpKmLy8chueO5reB7KKKrQnQJdDYn9AJZHc5QBT7enINY2hjxrqItsvJWSdxFxKuYlOlWJmE6zPPcsJuN7WFiF7me5DOAws4OyZyG6TOsr/KQziDaJm/mcy2V1V0+T0JeXxqqlrWC9mGGy3O6wwFaI0SdR+EMg9AEAACIAByqViZb+/prgFdN6qb306j3lTWs0BJ76Qjw0ktO+3ad60PQhMrfM9YwqK7lUPe4j+/OR40cDaqJeJ+xo80JsWih1WTBAcb8ysKrb+TfowQKy3v55wbBkk49FJbQusqr4snadL9hEtXC3nO1G1HG6UfxIj5oDnJlHPOVVAerWGmvYQxwc70hiTh7Bidy3/3ZFE6isxf8epNhUCl4n5ftYqWKzMP3IIquaFnquXO0sZ1yn/RWq69SuK6GdPXORfSz4HPnk1bNXO0+UZze5HqKIodNYwnHVVcOUivNcStxj4CGFYhWAWgXgmuF4JzdMhn6wDUm1DpmFyVY7IvQqeTRdod2v2F8lNn/gcpW+rUsOi9mAmFwlSo3Pw9JQ3p+8bhgnAMkPM613BxOBQqc2FEB4SmPQSAAAiAAAiAAAiAAAiAIAAEQAAEQAAEQPco3wIMADOXgFhOTghuAAAAAElFTkSuQmCC',
- 'authenticatorGetInfo': {
- 'versions': ['FIDO_2_0'],
- 'aaguid': '08987058cadc4b81b6e130de50dcbe96',
- 'options': { 'plat': true, 'rk': true, 'up': true },
+ icon: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAYAAABV7bNHAAACkUlEQVR42uyai3GDMAyGQyegGzACnaCMkBHoBhkhnSAj0A2SDaAT0E6QbEA3cOXW6XEpBtnImMv9utOllxjF/qKHLTdRSm0gdnkAAgACIAACIAACIAACIAgAARAAARAAARAAARBEAFCSJINKkpLuSTtSZbQz76W25zhKkpFWPbtaz6Q75vPuoluuPmqxlZK2yi76s9RznjlpN2K7CrFWaUAHNS0HT0Atw3YpDSjxbdoPuaziG3uk579cvIdeWsbQD7L7NAYoWpKmLy8chueO5reB7KKKrQnQJdDYn9AJZHc5QBT7enINY2hjxrqItsvJWSdxFxKuYlOlWJmE6zPPcsJuN7WFiF7me5DOAws4OyZyG6TOsr/KQziDaJm/mcy2V1V0+T0JeXxqqlrWC9mGGy3O6wwFaI0SdR+EMg9AEAACIAByqViZb+/prgFdN6qb306j3lTWs0BJ76Qjw0ktO+3ad60PQhMrfM9YwqK7lUPe4j+/OR40cDaqJeJ+xo80JsWih1WTBAcb8ysKrb+TfowQKy3v55wbBkk49FJbQusqr4snadL9hEtXC3nO1G1HG6UfxIj5oDnJlHPOVVAerWGmvYQxwc70hiTh7Bidy3/3ZFE6isxf8epNhUCl4n5ftYqWKzMP3IIquaFnquXO0sZ1yn/RWq69SuK6GdPXORfSz4HPnk1bNXO0+UZze5HqKIodNYwnHVVcOUivNcStxj4CGFYhWAWgXgmuF4JzdMhn6wDUm1DpmFyVY7IvQqeTRdod2v2F8lNn/gcpW+rUsOi9mAmFwlSo3Pw9JQ3p+8bhgnAMkPM613BxOBQqc2FEB4SmPQSAAAiAAAiAAAiAAAiAIAAEQAAEQAAEQPco3wIMADOXgFhOTghuAAAAAElFTkSuQmCC',
+ authenticatorGetInfo: {
+ versions: ['FIDO_2_0'],
+ aaguid: '08987058cadc4b81b6e130de50dcbe96',
+ options: { plat: true, rk: true, up: true },
},
};
// Extracted from an actual TPM|ECC response
const x5c = [
'MIIFuTCCA6GgAwIBAgIQAM86nt2LQk-si1Q75opOtjANBgkqhkiG9w0BAQsFADBCMUAwPgYDVQQDEzdOQ1UtSU5UQy1LRVlJRC0xN0EwMDU3NUQwNUU1OEUzODgxMjEwQkI5OEIxMDQ1QkI0QzMwNjM5MB4XDTIxMTIwMTA3MTMwOFoXDTI3MDYwMzE3NTExOFowADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN42zmd-TJwY8b8KKakCP_Jmq46s9qIcae5EObWRtWqw-qXBM9fH15vJ3UrE1mHv9mjCsV384_TJP7snP7MHy93jQOZNvR-T8JGNXR1Zhzg1MOjsZlv69w-shGZBF3lWXKKrdyS4q5KP8WbC6A30LVM_Ic0uAxkOeS-z4CdwWC4au2i8TkCTsUSenc98SFEksNOQONdNLA5qQInYCWppdT2lzEi-BbTV2GyropPgL3PCHGKVNt73XWzWZD_e9zuPNrOG9gfhh1hJaQS82TIul59Qp4C6AbIzH5uvhSh3_mhK2YU7Je6-FE_cvFLiTLt4vVimxd5uNGO4Oth_nfUm_sECAwEAAaOCAeswggHnMA4GA1UdDwEB_wQEAwIHgDAMBgNVHRMBAf8EAjAAMG0GA1UdIAEB_wRjMGEwXwYJKwYBBAGCNxUfMFIwUAYIKwYBBQUHAgIwRB5CAFQAQwBQAEEAIAAgAFQAcgB1AHMAdABlAGQAIAAgAFAAbABhAHQAZgBvAHIAbQAgACAASQBkAGUAbgB0AGkAdAB5MBAGA1UdJQQJMAcGBWeBBQgDMFAGA1UdEQEB_wRGMESkQjBAMRYwFAYFZ4EFAgEMC2lkOjQ5NEU1NDQzMQ4wDAYFZ4EFAgIMA0NOTDEWMBQGBWeBBQIDDAtpZDowMDAyMDAwMDAfBgNVHSMEGDAWgBTg0USwFsuPP50VHiH8i_DHd-1qLjAdBgNVHQ4EFgQU99bEZ0-Oi7GG2f-i68p7Xf1-diQwgbMGCCsGAQUFBwEBBIGmMIGjMIGgBggrBgEFBQcwAoaBk2h0dHA6Ly9hemNzcHJvZG5jdWFpa3B1Ymxpc2guYmxvYi5jb3JlLndpbmRvd3MubmV0L25jdS1pbnRjLWtleWlkLTE3YTAwNTc1ZDA1ZTU4ZTM4ODEyMTBiYjk4YjEwNDViYjRjMzA2MzkvYTdjNjk5MjUtZjM4Yi00ZmQwLWExZWMtMmYzMjI1MjA1YmM4LmNlcjANBgkqhkiG9w0BAQsFAAOCAgEAMwXq91wHH27AiR6rrWH3L7xEJ6o-wnoP808WisQcQ5gCUh4o0E3eeICh1IjPpr-n5CCMwU8GSzX5vQGF3VKa8FoEBNrhT4IuD-3qNv939NW1k4VPVQGTwgXy8YHiAlGnLmAIiqmEAgsn9fKLzBDhT448CJWyWzmtA5TflBX_jeL5V94hTvOMDtdtPQOpdGKlpYyArz3_sU8_XyOZad3DAbQbKOiFfzJoyr4CUDjZy1wHcO5ouwW33syPyrQwlqgnS8whBYXPK2M9Y-qT2--VutBAZIWI2wdiqMhY-RTm9OIbURZWmqVZ2DPn7dEGMow9TgdNYHL9m3CYsvRQejWyBffU0l8aLRzt330FqjHIK1x8kvk25V-mF10bTIejS6F516k3iZ2FbH5UeiZVE9ofVgN_lJ8KwyeOUjyG66VuH6dmnRfn4gg_2Uyj9TrDF0dJpoCKTspShuIaPD2-H-pkDQlDkldXo-bHlrGXJJGRBbhutxbBxozRsvkYhgoR4TbSzyDcFzFnDJd1ib_Z9C9q5KwaUiREX0b1rLCd1BZ-JXYGiQTrfnMZDvbHSXuZ-HXhcF9t5TZ8f4xDZX4gfsyj75uGJ34e4ThWxnNvdY7HkhFSXJzmvT6dIlIW1UorbYYm-UtbW4e8GwEVXquG0bpmWIXmL2k9D_WCSkyzkR7tPvw',
- 'MIIG7DCCBNSgAwIBAgITMwAAA-Y6aLPA71ZHOwAAAAAD5jANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE2MDQGA1UEAxMtTWljcm9zb2Z0IFRQTSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDE0MB4XDTIxMDYwMzE3NTExOFoXDTI3MDYwMzE3NTExOFowQjFAMD4GA1UEAxM3TkNVLUlOVEMtS0VZSUQtMTdBMDA1NzVEMDVFNThFMzg4MTIxMEJCOThCMTA0NUJCNEMzMDYzOTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO26HxYkAnL4SBpcIIDBFYw95P18eBVzl0owJPKtEwqtJhRArv6DQMDGKPw9HGy3Vtmh5VvrGgKh6LPyTbqN2xITi-wgPUIv7Mn-WtvzPO70dnhdRvw1vDY8LeulOh2l9zU2o2jII0HzLTl_LJqKmrN3yZpq1NneSQ49l3sbXvsW0eKSj2iCtgvOk2FhY-Os3cyexx6phX5I26BmoP-Y-W5kYqtNw2o8rxol_I0v51PVzNcLBwseGOpHNYtRF0m0QdoudCKZKk0hWzKPA4BE35wSSWGjgUbp91Pjzva33tYmOlk0UOLoIT2rZ2Y5feG3QpBuacD1ImDEUQ01-kJ1S2bATRR3BoaJtRbOCRoz41MS-2XfbXhcnzZxbT5TY7dlbX4oKYZn2Wqw-TYmfBiPYBX-Mo6wObruVOs6Lk04XzznXvx5lLKLNdvDBJxG3dZIzgepo9fLrp7hTiKw0T1EdYn6-MjUO7utoq7RmKA_AzFI1VLTfVJxPn_RahYPJmt8a8F2X7WlYPg5vayPDyWtmXtuuoxoAclNp3ViC9ko5LVr7M78C2RA1T94yk2eAEm_ueCuqn8mrmqQjFo3fMAfvRB2nL66tQhBZwmWyRIjuycRCJRdtSrwjSXRywA_VHLajhVutGzPrizmFcygT3ozL1NB6s5Ill5o4DpQsE9qNIOHAgMBAAGjggGOMIIBijAOBgNVHQ8BAf8EBAMCAoQwGwYDVR0lBBQwEgYJKwYBBAGCNxUkBgVngQUIAzAWBgNVHSAEDzANMAsGCSsGAQQBgjcVHzASBgNVHRMBAf8ECDAGAQH_AgEAMB0GA1UdDgQWBBTg0USwFsuPP50VHiH8i_DHd-1qLjAfBgNVHSMEGDAWgBR6jArOL0hiF-KU0a5VwVLscXSkVjBwBgNVHR8EaTBnMGWgY6Bhhl9odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUUE0lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDE0LmNybDB9BggrBgEFBQcBAQRxMG8wbQYIKwYBBQUHMAKGYWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVFBNJTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAxNC5jcnQwDQYJKoZIhvcNAQELBQADggIBAGW4yKQ4HaO4JdNMVjVO4mCM0lbLMmXQ0YJtyDHCIE6hsywTYv30DeUDm7Nmmhap9nWp26mSihb7qKQuyhdZkfhA10sp4wDbNpcXjQjdEaE2T1rcgKfounCPQRSW1V42DUgX_Bzuh0flbLYGOJIvugR46gBMUuKVQWmMQKyOMwmofFI8xG_z3VaLMcsgQ8Fl0cvJ6XZ2Jly-QRbZ2v44KNItTTuQKYJCL4kx2b50I4CkrRBaq2LAB-npikLN6xxHqsPvulA0t2WRfF9QzzDZhkVVZ5iCP1fAu5dnHvq0ArBlY2W29OIH_zviW2av88wxZ7FSQzIHu6B8GL45s6skvPa7E9lU6hG186LjrJtHJd0Qad3KYzZQyLKT78m1YiZXLFM02vsctM7nXqtndDjbDPVCota3mg8Jgi2s7-Aq59TL9ZBnRMEvJ5m1Rze1ofFwfO21ktBtLB8vXhzkHjtXy5ld0UQXmdbcs32uaqx6Q3_jVzXlXNNjuG6YBW9iBNL2ar3MtFt66LogL1gmOkyrjGK2Cdyzy1lEupr_SKtggthTyubemmf9G6hJtUZuT_gdFxVZm-MOvCtdNsqdi4HaU8VTCPB999upaEc5vv5KeEQ2xQk0wNmffMlGXGHJrQw8WBwCKkm3TW8hjnhZ9e6ePQvdMEzPhefsxjiQirzpf6lB'
+ 'MIIG7DCCBNSgAwIBAgITMwAAA-Y6aLPA71ZHOwAAAAAD5jANBgkqhkiG9w0BAQsFADCBjDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE2MDQGA1UEAxMtTWljcm9zb2Z0IFRQTSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDE0MB4XDTIxMDYwMzE3NTExOFoXDTI3MDYwMzE3NTExOFowQjFAMD4GA1UEAxM3TkNVLUlOVEMtS0VZSUQtMTdBMDA1NzVEMDVFNThFMzg4MTIxMEJCOThCMTA0NUJCNEMzMDYzOTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAO26HxYkAnL4SBpcIIDBFYw95P18eBVzl0owJPKtEwqtJhRArv6DQMDGKPw9HGy3Vtmh5VvrGgKh6LPyTbqN2xITi-wgPUIv7Mn-WtvzPO70dnhdRvw1vDY8LeulOh2l9zU2o2jII0HzLTl_LJqKmrN3yZpq1NneSQ49l3sbXvsW0eKSj2iCtgvOk2FhY-Os3cyexx6phX5I26BmoP-Y-W5kYqtNw2o8rxol_I0v51PVzNcLBwseGOpHNYtRF0m0QdoudCKZKk0hWzKPA4BE35wSSWGjgUbp91Pjzva33tYmOlk0UOLoIT2rZ2Y5feG3QpBuacD1ImDEUQ01-kJ1S2bATRR3BoaJtRbOCRoz41MS-2XfbXhcnzZxbT5TY7dlbX4oKYZn2Wqw-TYmfBiPYBX-Mo6wObruVOs6Lk04XzznXvx5lLKLNdvDBJxG3dZIzgepo9fLrp7hTiKw0T1EdYn6-MjUO7utoq7RmKA_AzFI1VLTfVJxPn_RahYPJmt8a8F2X7WlYPg5vayPDyWtmXtuuoxoAclNp3ViC9ko5LVr7M78C2RA1T94yk2eAEm_ueCuqn8mrmqQjFo3fMAfvRB2nL66tQhBZwmWyRIjuycRCJRdtSrwjSXRywA_VHLajhVutGzPrizmFcygT3ozL1NB6s5Ill5o4DpQsE9qNIOHAgMBAAGjggGOMIIBijAOBgNVHQ8BAf8EBAMCAoQwGwYDVR0lBBQwEgYJKwYBBAGCNxUkBgVngQUIAzAWBgNVHSAEDzANMAsGCSsGAQQBgjcVHzASBgNVHRMBAf8ECDAGAQH_AgEAMB0GA1UdDgQWBBTg0USwFsuPP50VHiH8i_DHd-1qLjAfBgNVHSMEGDAWgBR6jArOL0hiF-KU0a5VwVLscXSkVjBwBgNVHR8EaTBnMGWgY6Bhhl9odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBUUE0lMjBSb290JTIwQ2VydGlmaWNhdGUlMjBBdXRob3JpdHklMjAyMDE0LmNybDB9BggrBgEFBQcBAQRxMG8wbQYIKwYBBQUHMAKGYWh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwVFBNJTIwUm9vdCUyMENlcnRpZmljYXRlJTIwQXV0aG9yaXR5JTIwMjAxNC5jcnQwDQYJKoZIhvcNAQELBQADggIBAGW4yKQ4HaO4JdNMVjVO4mCM0lbLMmXQ0YJtyDHCIE6hsywTYv30DeUDm7Nmmhap9nWp26mSihb7qKQuyhdZkfhA10sp4wDbNpcXjQjdEaE2T1rcgKfounCPQRSW1V42DUgX_Bzuh0flbLYGOJIvugR46gBMUuKVQWmMQKyOMwmofFI8xG_z3VaLMcsgQ8Fl0cvJ6XZ2Jly-QRbZ2v44KNItTTuQKYJCL4kx2b50I4CkrRBaq2LAB-npikLN6xxHqsPvulA0t2WRfF9QzzDZhkVVZ5iCP1fAu5dnHvq0ArBlY2W29OIH_zviW2av88wxZ7FSQzIHu6B8GL45s6skvPa7E9lU6hG186LjrJtHJd0Qad3KYzZQyLKT78m1YiZXLFM02vsctM7nXqtndDjbDPVCota3mg8Jgi2s7-Aq59TL9ZBnRMEvJ5m1Rze1ofFwfO21ktBtLB8vXhzkHjtXy5ld0UQXmdbcs32uaqx6Q3_jVzXlXNNjuG6YBW9iBNL2ar3MtFt66LogL1gmOkyrjGK2Cdyzy1lEupr_SKtggthTyubemmf9G6hJtUZuT_gdFxVZm-MOvCtdNsqdi4HaU8VTCPB999upaEc5vv5KeEQ2xQk0wNmffMlGXGHJrQw8WBwCKkm3TW8hjnhZ9e6ePQvdMEzPhefsxjiQirzpf6lB',
];
- const credentialPublicKey = 'pAEDAzkBACBZAQC3X5SKwYUkxFxxyvCnz_37Z57eSdsgQuiBLDaBOd1R6VEZReAV3nVr_7jiRgmWfu1C-S3Aro65eSG5shcDCgIvY3KdEI8K5ENEPlmucjnFILBAE_MZtPmZlkEDmVCDcVspHX2iKqiVWYV6IFzVX1QUf0SAlWijV9NEfKDbij34ddV0qfG2nEMA0_xVpN2OK2BVXonFg6tS3T00XlFh4MdzIauIHTDT63eAdHlkFrMqU53T5IqDvL3VurBmBjYRJ3VDT9mA2sm7fSrJNXhSVLPst-ZsiOioVKrpzFE9sJmyCQvq2nGZ2RhDo8FfAKiw0kvJRkCSSe1ddxryk9_VSCprIUMBAAE';
+ const credentialPublicKey =
+ 'pAEDAzkBACBZAQC3X5SKwYUkxFxxyvCnz_37Z57eSdsgQuiBLDaBOd1R6VEZReAV3nVr_7jiRgmWfu1C-S3Aro65eSG5shcDCgIvY3KdEI8K5ENEPlmucjnFILBAE_MZtPmZlkEDmVCDcVspHX2iKqiVWYV6IFzVX1QUf0SAlWijV9NEfKDbij34ddV0qfG2nEMA0_xVpN2OK2BVXonFg6tS3T00XlFh4MdzIauIHTDT63eAdHlkFrMqU53T5IqDvL3VurBmBjYRJ3VDT9mA2sm7fSrJNXhSVLPst-ZsiOioVKrpzFE9sJmyCQvq2nGZ2RhDo8FfAKiw0kvJRkCSSe1ddxryk9_VSCprIUMBAAE';
const verified = await verifyAttestationWithMetadata({
statement: metadataStatement,
@@ -107,51 +108,56 @@ test('should verify attestation with rsa_emsa_pkcs1_sha256_raw authenticator alg
test('should not validate certificate path when authenticator is self-referencing its attestation statement certificates', async () => {
const metadataStatement: MetadataStatement = {
- "legalHeader": "https://fidoalliance.org/metadata/metadata-statement-legal-header/",
- "description": "Virtual Secp256R1 FIDO2 Conformance Testing CTAP2 Authenticator with Self Batch Referencing",
- "aaguid": "5b65dac1-7af4-46e6-8a4f-8701fcc4f3b4",
- "alternativeDescriptions": {
- "ru-RU": "Виртуальный Secp256R1 CTAP2 аутентификатор для тестирование серверов на соответсвие спецификации FIDO2 с одинаковыми сертификатами"
+ legalHeader: 'https://fidoalliance.org/metadata/metadata-statement-legal-header/',
+ description:
+ 'Virtual Secp256R1 FIDO2 Conformance Testing CTAP2 Authenticator with Self Batch Referencing',
+ aaguid: '5b65dac1-7af4-46e6-8a4f-8701fcc4f3b4',
+ alternativeDescriptions: {
+ 'ru-RU':
+ 'Виртуальный Secp256R1 CTAP2 аутентификатор для тестирование серверов на соответсвие спецификации FIDO2 с одинаковыми сертификатами',
},
- "protocolFamily": "fido2",
- "authenticatorVersion": 2,
- "upv": [{ "major": 1, "minor": 0 }],
- "authenticationAlgorithms": ["secp256r1_ecdsa_sha256_raw"],
- "publicKeyAlgAndEncodings": ["cose"],
- "attestationTypes": ["basic_full"],
- "schema": 3,
- "userVerificationDetails": [
- [{ "userVerificationMethod": "none" }],
- [{ "userVerificationMethod": "presence_internal" }],
- [{ "userVerificationMethod": "passcode_external", "caDesc": { "base": 10, "minLength": 4 } }],
+ protocolFamily: 'fido2',
+ authenticatorVersion: 2,
+ upv: [{ major: 1, minor: 0 }],
+ authenticationAlgorithms: ['secp256r1_ecdsa_sha256_raw'],
+ publicKeyAlgAndEncodings: ['cose'],
+ attestationTypes: ['basic_full'],
+ schema: 3,
+ userVerificationDetails: [
+ [{ userVerificationMethod: 'none' }],
+ [{ userVerificationMethod: 'presence_internal' }],
+ [{ userVerificationMethod: 'passcode_external', caDesc: { base: 10, minLength: 4 } }],
[
- { "userVerificationMethod": "passcode_external", "caDesc": { "base": 10, "minLength": 4 } },
- { "userVerificationMethod": "presence_internal" }
- ]
+ { userVerificationMethod: 'passcode_external', caDesc: { base: 10, minLength: 4 } },
+ { userVerificationMethod: 'presence_internal' },
+ ],
],
- "keyProtection": ["hardware", "secure_element"],
- "matcherProtection": ["on_chip"],
- "cryptoStrength": 128,
- "attachmentHint": ["external", "wired", "wireless", "nfc"],
- "tcDisplay": [],
- "attestationRootCertificates": [
- "MIIEQTCCAimgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBoTEYMBYGA1UEAwwPRklETzIgVEVTVCBST09UMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMQwwCgYDVQQLDANDV0cxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNWTESMBAGA1UEBwwJV2FrZWZpZWxkMB4XDTE4MDUyMzE0Mzk0M1oXDTI4MDUyMDE0Mzk0M1owgcIxIzAhBgNVBAMMGkZJRE8yIEJBVENIIEtFWSBwcmltZTI1NnYxMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTVkxEjAQBgNVBAcMCVdha2VmaWVsZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE86Xl6rbB+8rpf232RJlnYse+9yAEAqdsbyMPZVbxeqmZtZf8S/UIqvjp7wzQE/Wrm9J5FL8IBDeMvMsRuJtUajLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFZN98D4xlW2oR9sTRnzv0Hi/QF5MA0GCSqGSIb3DQEBCwUAA4ICAQCH3aCf+CCJBdEtQc4JpOnUelwGGw7DxnBMokHHBgrzJxDn9BFcFwxGLxrFV7EfYehQNOD+74OS8fZRgZiNf9EDGAYiHh0+CspfBWd20zCIjlCdDBcyhwq3PLJ65JC/og3CT9AK4kvks4DI+01RYxNv9S8Jx1haO1lgU55hBIr1P/p21ZKnpcCEhPjB/cIFrHJqL5iJGfed+LXni9Suq24OHnp44Mrv4h7OD2elu5yWfdfFb+RGG2TYURFIGYGijsii093w0ZMBOfBS+3Xq/DrHeZbZrrNkY455gJCZ5eV83Nrt9J9/UF0VZHl/hwnSAUC/b3tN/l0ZlC9kPcNzJD04l4ndFBD2KdfQ2HGTX7pybWLZ7yH2BM3ui2OpiacaOzd7OE91rHYB2uZyQ7jdg25yF9M8QI9NHM/itCjdBvAYt4QCT8dX6gmZiIGR2F/YXZAsybtJ16pnUmODVbW80lPbzy+PUQYX79opeD9u6MBorzr9g08Elpb1F3DgSd8VSLlsR2QPllKl4AcJDMIOfZHOQGOzatMV7ipEVRa0L5FnjAWpHHvSNcsjD4Cul562mO3MlI2pCyo+US+nIzG5XZmOeu4Db/Kw/dEPOo2ztHwlU0qKJ7REBsbt63jdQtlwLuiLHwkpiwnrAOZfwbLLu9Yz4tL1eJlQffuwS/Aolsz7HA=="
+ keyProtection: ['hardware', 'secure_element'],
+ matcherProtection: ['on_chip'],
+ cryptoStrength: 128,
+ attachmentHint: ['external', 'wired', 'wireless', 'nfc'],
+ tcDisplay: [],
+ attestationRootCertificates: [
+ 'MIIEQTCCAimgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBoTEYMBYGA1UEAwwPRklETzIgVEVTVCBST09UMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMQwwCgYDVQQLDANDV0cxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNWTESMBAGA1UEBwwJV2FrZWZpZWxkMB4XDTE4MDUyMzE0Mzk0M1oXDTI4MDUyMDE0Mzk0M1owgcIxIzAhBgNVBAMMGkZJRE8yIEJBVENIIEtFWSBwcmltZTI1NnYxMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTVkxEjAQBgNVBAcMCVdha2VmaWVsZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE86Xl6rbB+8rpf232RJlnYse+9yAEAqdsbyMPZVbxeqmZtZf8S/UIqvjp7wzQE/Wrm9J5FL8IBDeMvMsRuJtUajLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFZN98D4xlW2oR9sTRnzv0Hi/QF5MA0GCSqGSIb3DQEBCwUAA4ICAQCH3aCf+CCJBdEtQc4JpOnUelwGGw7DxnBMokHHBgrzJxDn9BFcFwxGLxrFV7EfYehQNOD+74OS8fZRgZiNf9EDGAYiHh0+CspfBWd20zCIjlCdDBcyhwq3PLJ65JC/og3CT9AK4kvks4DI+01RYxNv9S8Jx1haO1lgU55hBIr1P/p21ZKnpcCEhPjB/cIFrHJqL5iJGfed+LXni9Suq24OHnp44Mrv4h7OD2elu5yWfdfFb+RGG2TYURFIGYGijsii093w0ZMBOfBS+3Xq/DrHeZbZrrNkY455gJCZ5eV83Nrt9J9/UF0VZHl/hwnSAUC/b3tN/l0ZlC9kPcNzJD04l4ndFBD2KdfQ2HGTX7pybWLZ7yH2BM3ui2OpiacaOzd7OE91rHYB2uZyQ7jdg25yF9M8QI9NHM/itCjdBvAYt4QCT8dX6gmZiIGR2F/YXZAsybtJ16pnUmODVbW80lPbzy+PUQYX79opeD9u6MBorzr9g08Elpb1F3DgSd8VSLlsR2QPllKl4AcJDMIOfZHOQGOzatMV7ipEVRa0L5FnjAWpHHvSNcsjD4Cul562mO3MlI2pCyo+US+nIzG5XZmOeu4Db/Kw/dEPOo2ztHwlU0qKJ7REBsbt63jdQtlwLuiLHwkpiwnrAOZfwbLLu9Yz4tL1eJlQffuwS/Aolsz7HA==',
],
- "supportedExtensions": [{ "id": "hmac-secret", "fail_if_unknown": false }, { "id": "credProtect", "fail_if_unknown": false }
+ supportedExtensions: [
+ { id: 'hmac-secret', fail_if_unknown: false },
+ { id: 'credProtect', fail_if_unknown: false },
],
- "authenticatorGetInfo": {
- "versions": ["U2F_V2", "FIDO_2_0"],
- "extensions": ["credProtect", "hmac-secret"],
- "aaguid": "5b65dac17af446e68a4f8701fcc4f3b4",
- "options": { "plat": false, "rk": true, "clientPin": true, "up": true, "uv": true },
- "maxMsgSize": 1200,
- }
+ authenticatorGetInfo: {
+ versions: ['U2F_V2', 'FIDO_2_0'],
+ extensions: ['credProtect', 'hmac-secret'],
+ aaguid: '5b65dac17af446e68a4f8701fcc4f3b4',
+ options: { plat: false, rk: true, clientPin: true, up: true, uv: true },
+ maxMsgSize: 1200,
+ },
};
const x5c = [
- 'MIIEQTCCAimgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBoTEYMBYGA1UEAwwPRklETzIgVEVTVCBST09UMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMQwwCgYDVQQLDANDV0cxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNWTESMBAGA1UEBwwJV2FrZWZpZWxkMB4XDTE4MDUyMzE0Mzk0M1oXDTI4MDUyMDE0Mzk0M1owgcIxIzAhBgNVBAMMGkZJRE8yIEJBVENIIEtFWSBwcmltZTI1NnYxMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTVkxEjAQBgNVBAcMCVdha2VmaWVsZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE86Xl6rbB-8rpf232RJlnYse-9yAEAqdsbyMPZVbxeqmZtZf8S_UIqvjp7wzQE_Wrm9J5FL8IBDeMvMsRuJtUajLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFZN98D4xlW2oR9sTRnzv0Hi_QF5MA0GCSqGSIb3DQEBCwUAA4ICAQCH3aCf-CCJBdEtQc4JpOnUelwGGw7DxnBMokHHBgrzJxDn9BFcFwxGLxrFV7EfYehQNOD-74OS8fZRgZiNf9EDGAYiHh0-CspfBWd20zCIjlCdDBcyhwq3PLJ65JC_og3CT9AK4kvks4DI-01RYxNv9S8Jx1haO1lgU55hBIr1P_p21ZKnpcCEhPjB_cIFrHJqL5iJGfed-LXni9Suq24OHnp44Mrv4h7OD2elu5yWfdfFb-RGG2TYURFIGYGijsii093w0ZMBOfBS-3Xq_DrHeZbZrrNkY455gJCZ5eV83Nrt9J9_UF0VZHl_hwnSAUC_b3tN_l0ZlC9kPcNzJD04l4ndFBD2KdfQ2HGTX7pybWLZ7yH2BM3ui2OpiacaOzd7OE91rHYB2uZyQ7jdg25yF9M8QI9NHM_itCjdBvAYt4QCT8dX6gmZiIGR2F_YXZAsybtJ16pnUmODVbW80lPbzy-PUQYX79opeD9u6MBorzr9g08Elpb1F3DgSd8VSLlsR2QPllKl4AcJDMIOfZHOQGOzatMV7ipEVRa0L5FnjAWpHHvSNcsjD4Cul562mO3MlI2pCyo-US-nIzG5XZmOeu4Db_Kw_dEPOo2ztHwlU0qKJ7REBsbt63jdQtlwLuiLHwkpiwnrAOZfwbLLu9Yz4tL1eJlQffuwS_Aolsz7HA'
+ 'MIIEQTCCAimgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBoTEYMBYGA1UEAwwPRklETzIgVEVTVCBST09UMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMQwwCgYDVQQLDANDV0cxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNWTESMBAGA1UEBwwJV2FrZWZpZWxkMB4XDTE4MDUyMzE0Mzk0M1oXDTI4MDUyMDE0Mzk0M1owgcIxIzAhBgNVBAMMGkZJRE8yIEJBVENIIEtFWSBwcmltZTI1NnYxMTEwLwYJKoZIhvcNAQkBFiJjb25mb3JtYW5jZS10b29sc0BmaWRvYWxsaWFuY2Uub3JnMRYwFAYDVQQKDA1GSURPIEFsbGlhbmNlMSIwIAYDVQQLDBlBdXRoZW50aWNhdG9yIEF0dGVzdGF0aW9uMQswCQYDVQQGEwJVUzELMAkGA1UECAwCTVkxEjAQBgNVBAcMCVdha2VmaWVsZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABE86Xl6rbB-8rpf232RJlnYse-9yAEAqdsbyMPZVbxeqmZtZf8S_UIqvjp7wzQE_Wrm9J5FL8IBDeMvMsRuJtUajLDAqMAkGA1UdEwQCMAAwHQYDVR0OBBYEFFZN98D4xlW2oR9sTRnzv0Hi_QF5MA0GCSqGSIb3DQEBCwUAA4ICAQCH3aCf-CCJBdEtQc4JpOnUelwGGw7DxnBMokHHBgrzJxDn9BFcFwxGLxrFV7EfYehQNOD-74OS8fZRgZiNf9EDGAYiHh0-CspfBWd20zCIjlCdDBcyhwq3PLJ65JC_og3CT9AK4kvks4DI-01RYxNv9S8Jx1haO1lgU55hBIr1P_p21ZKnpcCEhPjB_cIFrHJqL5iJGfed-LXni9Suq24OHnp44Mrv4h7OD2elu5yWfdfFb-RGG2TYURFIGYGijsii093w0ZMBOfBS-3Xq_DrHeZbZrrNkY455gJCZ5eV83Nrt9J9_UF0VZHl_hwnSAUC_b3tN_l0ZlC9kPcNzJD04l4ndFBD2KdfQ2HGTX7pybWLZ7yH2BM3ui2OpiacaOzd7OE91rHYB2uZyQ7jdg25yF9M8QI9NHM_itCjdBvAYt4QCT8dX6gmZiIGR2F_YXZAsybtJ16pnUmODVbW80lPbzy-PUQYX79opeD9u6MBorzr9g08Elpb1F3DgSd8VSLlsR2QPllKl4AcJDMIOfZHOQGOzatMV7ipEVRa0L5FnjAWpHHvSNcsjD4Cul562mO3MlI2pCyo-US-nIzG5XZmOeu4Db_Kw_dEPOo2ztHwlU0qKJ7REBsbt63jdQtlwLuiLHwkpiwnrAOZfwbLLu9Yz4tL1eJlQffuwS_Aolsz7HA',
];
- const credentialPublicKey = 'pQECAyYgASFYIBdmUVOxrn-OOtkVwGP_vAspH3VkgzcGXVlu3-acb7EZIlggKgDTs0fr2d51sLR6uL3KP2cqR3iIUkKMCjyMJhYOkf4';
+ const credentialPublicKey =
+ 'pQECAyYgASFYIBdmUVOxrn-OOtkVwGP_vAspH3VkgzcGXVlu3-acb7EZIlggKgDTs0fr2d51sLR6uL3KP2cqR3iIUkKMCjyMJhYOkf4';
const verified = await verifyAttestationWithMetadata({
statement: metadataStatement,
diff --git a/packages/server/src/metadata/verifyAttestationWithMetadata.ts b/packages/server/src/metadata/verifyAttestationWithMetadata.ts
index dea3417..9b4c471 100644
--- a/packages/server/src/metadata/verifyAttestationWithMetadata.ts
+++ b/packages/server/src/metadata/verifyAttestationWithMetadata.ts
@@ -4,7 +4,14 @@ import type { MetadataStatement, AlgSign } from '../metadata/mdsTypes';
import { convertCertBufferToPEM } from '../helpers/convertCertBufferToPEM';
import { validateCertificatePath } from '../helpers/validateCertificatePath';
import { decodeCredentialPublicKey } from '../helpers/decodeCredentialPublicKey';
-import { COSEALG, COSECRV, COSEKEYS, COSEKTY, COSEPublicKeyEC2, isCOSEPublicKeyEC2 } from '../helpers/cose';
+import {
+ COSEALG,
+ COSECRV,
+ COSEKEYS,
+ COSEKTY,
+ COSEPublicKeyEC2,
+ isCOSEPublicKeyEC2,
+} from '../helpers/cose';
/**
* Match properties of the authenticator's attestation statement against expected values as
@@ -21,11 +28,7 @@ export async function verifyAttestationWithMetadata({
x5c: Uint8Array[] | Base64URLString[];
attestationStatementAlg?: number;
}): Promise<boolean> {
- const {
- authenticationAlgorithms,
- authenticatorGetInfo,
- attestationRootCertificates,
- } = statement;
+ const { authenticationAlgorithms, authenticatorGetInfo, attestationRootCertificates } = statement;
// Make sure the alg in the attestation statement matches one of the ones specified in metadata
const keypairCOSEAlgs: Set<COSEInfo> = new Set();
@@ -104,8 +107,9 @@ export async function verifyAttestationWithMetadata({
* ]
* ```
*/
- const debugMDSAlgs = authenticationAlgorithms
- .map((algSign) => `'${algSign}' (COSE info: ${stringifyCOSEInfo(algSignToCOSEInfoMap[algSign])})`);
+ const debugMDSAlgs = authenticationAlgorithms.map(
+ algSign => `'${algSign}' (COSE info: ${stringifyCOSEInfo(algSignToCOSEInfoMap[algSign])})`,
+ );
const strMDSAlgs = JSON.stringify(debugMDSAlgs, null, 2).replace(/"/g, '');
/**
@@ -140,10 +144,7 @@ export async function verifyAttestationWithMetadata({
* certificate chain validation.
*/
let authenticatorIsSelfReferencing = false;
- if (
- authenticatorCerts.length === 1 &&
- statementRootCerts.indexOf(authenticatorCerts[0]) >= 0
- ) {
+ if (authenticatorCerts.length === 1 && statementRootCerts.indexOf(authenticatorCerts[0]) >= 0) {
authenticatorIsSelfReferencing = true;
}
diff --git a/packages/server/src/registration/generateRegistrationOptions.test.ts b/packages/server/src/registration/generateRegistrationOptions.test.ts
index c67a8b2..25f9d30 100644
--- a/packages/server/src/registration/generateRegistrationOptions.test.ts
+++ b/packages/server/src/registration/generateRegistrationOptions.test.ts
@@ -175,7 +175,7 @@ test('should require resident key if residentKey option is absent but requireRes
userName: 'usernameHere',
authenticatorSelection: {
requireResidentKey: true,
- }
+ },
});
expect(options.authenticatorSelection?.requireResidentKey).toEqual(true);
@@ -190,7 +190,7 @@ test('should discourage resident key if residentKey option is absent but require
userName: 'usernameHere',
authenticatorSelection: {
requireResidentKey: false,
- }
+ },
});
expect(options.authenticatorSelection?.requireResidentKey).toEqual(false);
diff --git a/packages/server/src/registration/verifyRegistrationResponse.test.ts b/packages/server/src/registration/verifyRegistrationResponse.test.ts
index 776be4c..09d748b 100644
--- a/packages/server/src/registration/verifyRegistrationResponse.test.ts
+++ b/packages/server/src/registration/verifyRegistrationResponse.test.ts
@@ -237,9 +237,9 @@ test('should throw if an unexpected attestation format is specified', async () =
});
test('should throw error if assertion RP ID is unexpected value', async () => {
- const authData = esmDecodeAttestationObject.decodeAttestationObject(
- isoBase64URL.toBuffer(attestationNone.response.attestationObject),
- ).get('authData');
+ const authData = esmDecodeAttestationObject
+ .decodeAttestationObject(isoBase64URL.toBuffer(attestationNone.response.attestationObject))
+ .get('authData');
const actualAuthData = esmParseAuthenticatorData.parseAuthenticatorData(authData);
mockParseAuthData.mockReturnValue({
diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts
index c937bee..0c1351f 100644
--- a/packages/server/src/registration/verifyRegistrationResponse.ts
+++ b/packages/server/src/registration/verifyRegistrationResponse.ts
@@ -18,7 +18,7 @@ import { COSEKEYS } from '../helpers/cose';
import { convertAAGUIDToString } from '../helpers/convertAAGUIDToString';
import { parseBackupFlags } from '../helpers/parseBackupFlags';
import { matchExpectedRPID } from '../helpers/matchExpectedRPID';
-import { isoBase64URL } from '../helpers/iso';
+import { isoBase64URL } from '../helpers/iso';
import { SettingsService } from '../services/settingsService';
import { supportedCOSEAlgorithmIdentifiers } from './generateRegistrationOptions';