summaryrefslogtreecommitdiffhomepage
path: root/packages/server/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/server/src')
-rw-r--r--packages/server/src/authentication/verifyAuthenticationResponse.test.ts48
-rw-r--r--packages/server/src/authentication/verifyAuthenticationResponse.ts10
-rw-r--r--packages/server/src/registration/verifyRegistrationResponse.ts3
3 files changed, 57 insertions, 4 deletions
diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
index 212de2c..b78a5c4 100644
--- a/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
+++ b/packages/server/src/authentication/verifyAuthenticationResponse.test.ts
@@ -260,6 +260,54 @@ test('should throw an error if RP ID not in list of possible RP IDs', async () =
}).toThrow(/unexpected rp id/i);
});
+test('should pass verification if custom challenge verifier returns true', () => {
+ const verification = verifyAuthenticationResponse({
+ credential: {
+ 'id': 'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
+ 'rawId': 'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA',
+ 'response': {
+ 'authenticatorData': 'SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MFYftypQ',
+ 'clientDataJSON': 'eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiZXlKaFkzUjFZV3hEYUdGc2JHVnVaMlVpT2lKTE0xRjRUMnB1VmtwTWFVZHNibFpGY0RWMllUVlJTbVZOVmxkT1psODNVRmxuZFhSbllrRjBRVlZCSWl3aVlYSmlhWFJ5WVhKNVJHRjBZU0k2SW5OcFoyNU5aVkJzWldGelpTSjkiLCJvcmlnaW4iOiJodHRwOi8vbG9jYWxob3N0OjgwMDAiLCJjcm9zc09yaWdpbiI6ZmFsc2V9',
+ 'signature': 'MEUCIByFAVGfkoKPEzynp-37BX_HOXSaC6-58-ELjB7BG9opAiEAyD_1mN9YAPrphcwpzK3ym2Xx8EjAapgQ326mKgQ1pW0',
+ 'userHandle': 'internalUserId'
+ },
+ 'type': 'public-key',
+ 'clientExtensionResults': {}
+ },
+ expectedChallenge: (challenge: string) => {
+ const parsedChallenge: { actualChallenge: string; arbitraryData: string; } = JSON.parse(
+ base64url.decode(challenge),
+ );
+ return parsedChallenge.actualChallenge === 'K3QxOjnVJLiGlnVEp5va5QJeMVWNf_7PYgutgbAtAUA';
+ },
+ expectedOrigin: 'http://localhost:8000',
+ expectedRPID: 'localhost',
+ authenticator: {
+ credentialID: base64url.toBuffer(
+ 'AaIBxnYfL2pDWJmIii6CYgHBruhVvFGHheWamphVioG_TnEXxKA9MW4FWnJh21zsbmRpRJso9i2JmAtWOtXfVd4oXTgYVusXwhWWsA'
+ ),
+ credentialPublicKey: base64url.toBuffer(
+ 'pQECAyYgASFYILTrxTUQv3X4DRM6L_pk65FSMebenhCx3RMsTKoBm-AxIlggEf3qk5552QLNSh1T1oQs7_2C2qysDwN4r4fCp52Hsqs'
+ ),
+ counter: 0,
+ },
+ });
+
+ expect(verification.verified).toEqual(true);
+});
+
+test('should fail verification if custom challenge verifier returns false', () => {
+ expect(() => {
+ verifyAuthenticationResponse({
+ credential: assertionResponse,
+ expectedChallenge: (challenge) => challenge === 'willNeverMatch',
+ expectedOrigin: assertionOrigin,
+ expectedRPID: 'dev.dontneeda.pw',
+ authenticator: authenticator,
+ });
+ }).toThrow(/custom challenge verifier returned false/i);
+});
+
/**
* Assertion examples below
*/
diff --git a/packages/server/src/authentication/verifyAuthenticationResponse.ts b/packages/server/src/authentication/verifyAuthenticationResponse.ts
index cd83be3..c1ccc65 100644
--- a/packages/server/src/authentication/verifyAuthenticationResponse.ts
+++ b/packages/server/src/authentication/verifyAuthenticationResponse.ts
@@ -14,7 +14,7 @@ import isBase64URLString from '../helpers/isBase64URLString';
export type VerifyAuthenticationResponseOpts = {
credential: AuthenticationCredentialJSON;
- expectedChallenge: string;
+ expectedChallenge: string | ((challenge: string) => boolean);
expectedOrigin: string | string[];
expectedRPID: string | string[];
authenticator: AuthenticatorDevice;
@@ -82,7 +82,13 @@ export default function verifyAuthenticationResponse(
}
// Ensure the device provided the challenge we gave it
- if (challenge !== expectedChallenge) {
+ if (typeof expectedChallenge === 'function') {
+ if (!expectedChallenge(challenge)) {
+ throw new Error(
+ `Custom challenge verifier returned false for registration response challenge "${challenge}"`,
+ );
+ }
+ } else if (challenge !== expectedChallenge) {
throw new Error(
`Unexpected authentication response challenge "${challenge}", expected "${expectedChallenge}"`,
);
diff --git a/packages/server/src/registration/verifyRegistrationResponse.ts b/packages/server/src/registration/verifyRegistrationResponse.ts
index a2a4cf6..f9c111d 100644
--- a/packages/server/src/registration/verifyRegistrationResponse.ts
+++ b/packages/server/src/registration/verifyRegistrationResponse.ts
@@ -26,13 +26,12 @@ import verifyApple from './verifications/verifyApple';
export type VerifyRegistrationResponseOpts = {
credential: RegistrationCredentialJSON;
- expectedChallenge: string | ChallengeVerifier;
+ expectedChallenge: string | ((challenge: string) => boolean);
expectedOrigin: string | string[];
expectedRPID?: string | string[];
requireUserVerification?: boolean;
supportedAlgorithmIDs?: COSEAlgorithmIdentifier[];
};
-export type ChallengeVerifier = (challenge: string) => boolean;
/**
* Verify that the user has legitimately completed the registration process