Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true,
"deno.path": "/opt/homebrew/bin/deno",
"deno.path": "/Users/matt/.dvm/bin/deno",
"deno.enable": true,
"deno.config": "./deno.json",
"deno.disablePaths": [
Expand Down
31 changes: 22 additions & 9 deletions packages/server/src/metadata/verifyAttestationWithMetadata.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { assertEquals } from '@std/assert';
import { assertEquals, assertRejects } from '@std/assert';
import { FakeTime } from '@std/testing/time';

import { verifyAttestationWithMetadata } from './verifyAttestationWithMetadata.ts';
import type { MetadataStatement } from '../metadata/mdsTypes.ts';
import { isoBase64URL } from '../helpers/iso/index.ts';

Deno.test('should verify attestation with metadata (android-safetynet)', async () => {
Deno.test('should not verify attestation with revoked certificate in metadata (android-safetynet)', async () => {
// Faking time to something that'll satisfy all of these ranges:
// {
// notBefore: 2022-01-25T10:00:34.000Z,
Expand Down Expand Up @@ -69,13 +69,16 @@ Deno.test('should verify attestation with metadata (android-safetynet)', async (
const credentialPublicKey =
'pQECAyYgASFYIAKH2NrGZT-lUEA3tbBXR9owjW_7OnA1UqoL1UuKY_VCIlggpjeOH0xyBCpGDya55JLXXKrzyOieQN3dvG1pV-Qs-Gs';

const verified = await verifyAttestationWithMetadata({
statement: metadataStatementJSONSafetyNet,
credentialPublicKey: isoBase64URL.toBuffer(credentialPublicKey),
x5c,
});

assertEquals(verified, true);
await assertRejects(
() =>
verifyAttestationWithMetadata({
statement: metadataStatementJSONSafetyNet,
credentialPublicKey: isoBase64URL.toBuffer(credentialPublicKey),
x5c,
}),
Error,
'revoked certificate',
);

fakedNow.restore();
});
Expand Down Expand Up @@ -201,6 +204,16 @@ Deno.test('should not validate certificate path when authenticator is self-refer
});

Deno.test('should verify idmelon attestation with updated root certificate', async () => {
// Faking time to something that'll satisfy all of these ranges:
// {
// notBefore: 2018-12-22T17:43:28.000Z,
// notAfter: 2068-12-09T17:43:28.000Z
// }
// {
// notBefore: 2022-12-14T18:41:09.000Z,
// notAfter: 2072-12-01T18:41:09.000Z
// }
// const mockDate = new FakeTime(new Date('2025-01-30T23:59:59.000Z'));
/**
* See https://github.com/MasterKale/SimpleWebAuthn/issues/302 for more context, basically
* IDmelon's root cert in FIDO MDS was missing an extension. I worked with IDmelon to generate a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import { FakeTime } from '@std/testing/time';
import { verifyRegistrationResponse } from '../../verifyRegistrationResponse.ts';

Deno.test('should verify TPM response', async () => {
// Faking time to something that'll satisfy all of these ranges:
// {
// notBefore: 2018-02-01T00:00:00.000Z,
// notAfter: 2025-01-31T23:59:59.000Z
// }
const mockDate = new FakeTime(new Date('2025-01-30T23:59:59.000Z'));

const verification = await verifyRegistrationResponse({
response: {
id: 'SErwRhxIzjPowcnM3e-D-u89EQXLUe1NYewpshd7Mc0',
Expand All @@ -25,9 +32,18 @@ Deno.test('should verify TPM response', async () => {
});

assertEquals(verification.verified, true);

mockDate.restore();
});

Deno.test('should verify SHA1 TPM response', async () => {
// Faking time to something that'll satisfy all of these ranges:
// {
// notBefore: 2018-02-01T00:00:00.000Z,
// notAfter: 2025-01-31T23:59:59.000Z
// }
const mockDate = new FakeTime(new Date('2025-01-30T23:59:59.000Z'));

/**
* Generated on real hardware on 03/03/2020
*
Expand Down Expand Up @@ -55,9 +71,18 @@ Deno.test('should verify SHA1 TPM response', async () => {
});

assertEquals(verification.verified, true);

mockDate.restore();
});

Deno.test('should verify SHA256 TPM response', async () => {
// Faking time to something that'll satisfy all of these ranges:
// {
// notBefore: 2018-02-01T00:00:00.000Z,
// notAfter: 2025-01-31T23:59:59.000Z
// }
const mockDate = new FakeTime(new Date('2025-01-30T23:59:59.000Z'));

/**
* Generated on real hardware on 03/03/2020
*
Expand Down Expand Up @@ -85,9 +110,17 @@ Deno.test('should verify SHA256 TPM response', async () => {
});

assertEquals(verification.verified, true);

mockDate.restore();
});

Deno.test('should verify TPM response with spec-compliant tcgAtTpm SAN structure', async () => {
// Faking time to something that'll satisfy all of these ranges:
// {
// notBefore: 2020-08-27T15:12:30.000Z,
// notAfter: 2025-03-21T20:29:15.000Z
// }
const mockDate = new FakeTime(new Date('2025-03-20T00:00:42.000Z'));
/**
* Name [
* RelativeDistinguishedName [
Expand Down Expand Up @@ -121,6 +154,8 @@ Deno.test('should verify TPM response with spec-compliant tcgAtTpm SAN structure
});

assertEquals(verification.verified, true);

mockDate.restore();
});

Deno.test('should verify TPM response with non-spec-compliant tcgAtTpm SAN structure', async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ Deno.test('should throw error when timestamp is not within one minute of now', a
);
});

Deno.test('should validate response with cert path completed with GlobalSign R1 root cert', async () => {
Deno.test('should reject when a revoked certificate is found', async () => {
const {
aaguid,
attStmt,
Expand Down Expand Up @@ -151,19 +151,22 @@ Deno.test('should validate response with cert path completed with GlobalSign R1
// }
const mockDate = new FakeTime(new Date('2021-10-15T00:00:42.000Z'));

const verified = await verifyAttestationAndroidSafetyNet({
attStmt,
authData,
clientDataHash,
verifyTimestampMS: false,
aaguid,
rootCertificates,
credentialID,
credentialPublicKey,
rpIdHash,
});

assert(verified);
await assertRejects(
() =>
verifyAttestationAndroidSafetyNet({
attStmt,
authData,
clientDataHash,
verifyTimestampMS: false,
aaguid,
rootCertificates,
credentialID,
credentialPublicKey,
rpIdHash,
}),
Error,
'revoked certificate',
);

mockDate.restore();
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { assert, assertEquals, assertFalse, assertObjectMatch, assertRejects } from '@std/assert';
import { returnsNext, stub } from '@std/testing/mock';
import { FakeTime } from '@std/testing/time';

import { verifyRegistrationResponse } from './verifyRegistrationResponse.ts';
import type { RegistrationResponseJSON } from '../types/index.ts';
Expand Down Expand Up @@ -608,6 +609,13 @@ Deno.test(
);

Deno.test('should validate TPM RSA response (SHA256)', async () => {
// Faking time to something that'll satisfy all of these ranges:
// {
// notBefore: 2018-02-01T00:00:00.000Z,
// notAfter: 2025-01-31T23:59:59.000Z
// }
const mockDate = new FakeTime(new Date('2025-01-30T23:59:59.000Z'));

const expectedChallenge = '3a07cf85-e7b6-447f-8270-b25433f6018e';
const verification = await verifyRegistrationResponse({
response: {
Expand Down Expand Up @@ -647,9 +655,18 @@ Deno.test('should validate TPM RSA response (SHA256)', async () => {
'https://dev.dontneeda.pw',
);
assertEquals(verification.registrationInfo?.rpID, 'dev.dontneeda.pw');

mockDate.restore();
});

Deno.test('should validate TPM RSA response (SHA1)', async () => {
// Faking time to something that'll satisfy all of these ranges:
// {
// notBefore: 2018-02-01T00:00:00.000Z,
// notAfter: 2025-01-31T23:59:59.000Z
// }
const mockDate = new FakeTime(new Date('2025-01-30T23:59:59.000Z'));

const expectedChallenge = 'f4e8d87b-d363-47cc-ab4d-1a84647bf245';
const verification = await verifyRegistrationResponse({
response: {
Expand Down Expand Up @@ -689,6 +706,8 @@ Deno.test('should validate TPM RSA response (SHA1)', async () => {
'https://dev.dontneeda.pw',
);
assertEquals(verification.registrationInfo?.rpID, 'dev.dontneeda.pw');

mockDate.restore();
});

Deno.test('should validate Android-Key response', async () => {
Expand Down