Skip to content

Commit

Permalink
Support multiple expected RP IDs
Browse files Browse the repository at this point in the history
  • Loading branch information
MasterKale committed Jan 21, 2021
1 parent 8d6e42d commit b54687e
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 8 deletions.
24 changes: 24 additions & 0 deletions packages/server/src/assertion/verifyAssertionResponse.test.ts
Expand Up @@ -231,6 +231,30 @@ test('should throw an error if origin not in list of expected origins', async ()
}).toThrow(/unexpected assertion origin/i);
});

test('should support multiple possible RP IDs', async () => {
const verification = verifyAssertionResponse({
credential: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: ['dev.dontneeda.pw', 'simplewebauthn.dev'],
authenticator: authenticator,
});

expect(verification.verified).toEqual(true);
});

test('should throw an error if RP ID not in list of possible RP IDs', async () => {
expect(() => {
verifyAssertionResponse({
credential: assertionResponse,
expectedChallenge: assertionChallenge,
expectedOrigin: assertionOrigin,
expectedRPID: ['simplewebauthn.dev'],
authenticator: authenticator,
});
}).toThrow(/unexpected rp id/i);
});

/**
* Assertion examples below
*/
Expand Down
20 changes: 16 additions & 4 deletions packages/server/src/assertion/verifyAssertionResponse.ts
Expand Up @@ -16,7 +16,7 @@ type Options = {
credential: AssertionCredentialJSON;
expectedChallenge: string;
expectedOrigin: string | string[];
expectedRPID: string;
expectedRPID: string | string[];
authenticator: AuthenticatorDevice;
fidoUserVerification?: UserVerificationRequirement;
};
Expand Down Expand Up @@ -126,9 +126,21 @@ export default function verifyAssertionResponse(options: Options): VerifiedAsser
const { rpIdHash, flags, counter } = parsedAuthData;

// Make sure the response's RP ID is ours
const expectedRPIDHash = toHash(Buffer.from(expectedRPID, 'ascii'));
if (!rpIdHash.equals(expectedRPIDHash)) {
throw new Error(`Unexpected RP ID hash`);
if (typeof expectedRPID === 'string') {
const expectedRPIDHash = toHash(Buffer.from(expectedRPID, 'ascii'));
if (!rpIdHash.equals(expectedRPIDHash)) {
throw new Error(`Unexpected RP ID hash`);
}
} else {
// Go through each expected RP ID and try to find one that matches
const foundMatch = expectedRPID.some(expected => {
const expectedIDHash = toHash(Buffer.from(expected, 'ascii'));
return rpIdHash.equals(expectedIDHash);
});

if (!foundMatch) {
throw new Error(`Unexpected RP ID hash`);
}
}

// Enforce user verification if required
Expand Down
22 changes: 22 additions & 0 deletions packages/server/src/attestation/verifyAttestationResponse.test.ts
Expand Up @@ -460,6 +460,28 @@ test('should throw an error if origin not in list of expected origins', async ()
).rejects.toThrow(/unexpected attestation origin/i);
});

test('should support multiple possible RP IDs', async () => {
const verification = await verifyAttestationResponse({
credential: attestationNone,
expectedChallenge: attestationNoneChallenge,
expectedOrigin: 'https://dev.dontneeda.pw',
expectedRPID: ['dev.dontneeda.pw', 'simplewebauthn.dev'],
});

expect(verification.verified).toBe(true);
});

test('should throw an error if RP ID not in list of possible RP IDs', async () => {
await expect(
verifyAttestationResponse({
credential: attestationNone,
expectedChallenge: attestationNoneChallenge,
expectedOrigin: 'https://dev.dontneeda.pw',
expectedRPID: ['simplewebauthn.dev'],
}),
).rejects.toThrow(/unexpected rp id/i);
});

/**
* Various Attestations Below
*/
Expand Down
21 changes: 17 additions & 4 deletions packages/server/src/attestation/verifyAttestationResponse.ts
Expand Up @@ -18,12 +18,13 @@ import verifyAndroidSafetynet from './verifications/verifyAndroidSafetyNet';
import verifyTPM from './verifications/tpm/verifyTPM';
import verifyAndroidKey from './verifications/verifyAndroidKey';
import verifyApple from './verifications/verifyApple';
import e from 'express';

type Options = {
credential: AttestationCredentialJSON;
expectedChallenge: string;
expectedOrigin: string | string[];
expectedRPID?: string;
expectedRPID?: string | string[];
requireUserVerification?: boolean;
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[];
};
Expand Down Expand Up @@ -118,9 +119,21 @@ export default async function verifyAttestationResponse(

// Make sure the response's RP ID is ours
if (expectedRPID) {
const expectedRPIDHash = toHash(Buffer.from(expectedRPID, 'ascii'));
if (!rpIdHash.equals(expectedRPIDHash)) {
throw new Error(`Unexpected RP ID hash`);
if (typeof expectedRPID === 'string') {
const expectedRPIDHash = toHash(Buffer.from(expectedRPID, 'ascii'));
if (!rpIdHash.equals(expectedRPIDHash)) {
throw new Error(`Unexpected RP ID hash`);
}
} else {
// Go through each expected RP ID and try to find one that matches
const foundMatch = expectedRPID.some(expected => {
const expectedIDHash = toHash(Buffer.from(expected, 'ascii'));
return rpIdHash.equals(expectedIDHash);
});

if (!foundMatch) {
throw new Error(`Unexpected RP ID hash`);
}
}
}

Expand Down

0 comments on commit b54687e

Please sign in to comment.