diff options
-rw-r--r-- | packages/server/src/assertion/verifyAssertionResponse.test.ts | 119 |
1 files changed, 103 insertions, 16 deletions
diff --git a/packages/server/src/assertion/verifyAssertionResponse.test.ts b/packages/server/src/assertion/verifyAssertionResponse.test.ts index 04adc5c..ffd05f5 100644 --- a/packages/server/src/assertion/verifyAssertionResponse.test.ts +++ b/packages/server/src/assertion/verifyAssertionResponse.test.ts @@ -1,24 +1,111 @@ import verifyAssertionResponse from './verifyAssertionResponse'; -test('', () => { +import * as decodeClientDataJSON from '../helpers/decodeClientDataJSON'; +import * as parseAssertionAuthData from './parseAssertionAuthData'; + +let mockDecodeClientData: jest.SpyInstance; +let mockParseAuthData: jest.SpyInstance; + +beforeEach(() => { + mockDecodeClientData = jest.spyOn(decodeClientDataJSON, 'default'); + mockParseAuthData = jest.spyOn(parseAssertionAuthData, 'default'); +}); + +afterEach(() => { + mockDecodeClientData.mockRestore(); + mockParseAuthData.mockRestore(); +}); + +test('should verify an assertion response', () => { const verification = verifyAssertionResponse( - { - base64AuthenticatorData: 'PdxHEOnAiLIp26idVjIguzn3Ipr_RlsKZWsa-5qK-KABAAAAhw', - base64ClientDataJSON: 'eyJjaGFsbGVuZ2UiOiJXRzVRU21RM1oyOTROR2gyTVROUk56WnViVmhMTlZZMWMwOHRP' + - 'V3BLVG5JIiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoi' + - 'aHR0cHM6Ly9kZXYuZG9udG5lZWRhLnB3IiwidHlwZSI6IndlYmF1dGhuLmdldCJ9', - base64Signature: 'MEQCIHZYFY3LsKzI0T9XRwEACl7YsYZysZ2HUw3q9f7tlq3wAiBNbyBbQMNM56P6Z00tBEZ6v' + - 'II4f9Al-p4pZw7OBpSaog', - }, + assertionResponse, 'https://dev.dontneeda.pw', - { - base64PublicKey: 'BBMQEnZRfg4ASys9kfGUj99Xlsa028wqYJZw8xuGahPQJWN3K9D9DajLxzKlY7uf_ulA5D6gh' + - 'UJ9hrouDX84S_I', - base64CredentialID: 'wJZRtQbYjKlpiRnzet7yyVizdsj_oUhi11kFbKyO0hc5gIg-4xeaTC9YC9y9sfow6gO3jE' + - 'MoONBKNX4SmSclmQ', - counter: 134, - }, + authenticator, ); expect(verification.verified).toEqual(true); }); + +test('should throw when response origin is not expected value', () => { + expect(() => { + verifyAssertionResponse( + assertionResponse, + 'https://different.address', + authenticator, + ); + }).toThrow('Assertion origin was an unexpected value'); +}); + +test('should throw when assertion type is not webauthn.create', () => { + // @ts-ignore 2345 + mockDecodeClientData.mockReturnValue({ + origin: assertionOrigin, + type: 'webauthn.badtype', + }); + + expect(() => { + verifyAssertionResponse( + assertionResponse, + assertionOrigin, + authenticator, + ); + }).toThrow('Assertion type was an unexpected value'); +}); + +test('should throw error if user was not present', () => { + mockParseAuthData.mockReturnValue({ + flags: 0, + }); + + expect(() => { + verifyAssertionResponse( + assertionResponse, + assertionOrigin, + authenticator, + ); + }).toThrow('User was NOT present during assertion!'); +}); + +test('should throw error if previous counter value is not less than in response', () => { + // This'll match the `counter` value in `assertionResponse`, simulating a potential replay attack + const badCounter = 135; + const badDevice = { + ...authenticator, + counter: badCounter, + }; + + expect(() => { + verifyAssertionResponse( + assertionResponse, + assertionOrigin, + badDevice, + ); + }).toThrow(`Counter in response did not increment from ${badCounter}`); +}); + +/** + * parsed authData: { + * rpIdHash: <Buffer>, + * flagsBuf: <Buffer>, + * flags: 1, + * counter: 135, + * counterBuf: <Buffer> + * } + */ +const assertionResponse = { + base64AuthenticatorData: 'PdxHEOnAiLIp26idVjIguzn3Ipr_RlsKZWsa-5qK-KABAAAAhw', + base64ClientDataJSON: 'eyJjaGFsbGVuZ2UiOiJXRzVRU21RM1oyOTROR2gyTVROUk56WnViVmhMTlZZMWMwOHRP' + + 'V3BLVG5JIiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoi' + + 'aHR0cHM6Ly9kZXYuZG9udG5lZWRhLnB3IiwidHlwZSI6IndlYmF1dGhuLmdldCJ9', + base64Signature: 'MEQCIHZYFY3LsKzI0T9XRwEACl7YsYZysZ2HUw3q9f7tlq3wAiBNbyBbQMNM56P6Z00tBEZ6v' + + 'II4f9Al-p4pZw7OBpSaog', +}; +const assertionOrigin = 'https://dev.dontneeda.pw'; + +const authenticator = { + base64PublicKey: 'BBMQEnZRfg4ASys9kfGUj99Xlsa028wqYJZw8xuGahPQJWN3K9D9DajLxzKlY7uf_ulA5D6gh' + + 'UJ9hrouDX84S_I', + base64CredentialID: 'wJZRtQbYjKlpiRnzet7yyVizdsj_oUhi11kFbKyO0hc5gIg-4xeaTC9YC9y9sfow6gO3jE' + + 'MoONBKNX4SmSclmQ', + counter: 134, +}; |