From d71d0d9af635ff12d3f832bdf09a8d7c662c6cb9 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Fri, 23 Apr 2021 21:07:15 +0200 Subject: [PATCH] Improve WebAuthn error detection for invalid data (#946) --- src/connectors/common-webauthn.ts | 14 ++++++++++++++ src/connectors/webauthn-fallback.ts | 13 ++----------- src/connectors/webauthn.ts | 13 ++----------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/connectors/common-webauthn.ts b/src/connectors/common-webauthn.ts index b8daf0743d..907357fd53 100644 --- a/src/connectors/common-webauthn.ts +++ b/src/connectors/common-webauthn.ts @@ -27,6 +27,20 @@ export function b64Decode(str: string) { }).join('')); } +export function parseWebauthnJson(jsonString: string) { + const json = JSON.parse(jsonString); + + const challenge = json.challenge.replace(/-/g, '+').replace(/_/g, '/'); + json.challenge = Uint8Array.from(atob(challenge), c => c.charCodeAt(0)); + + json.allowCredentials.forEach((listItem: any) => { + const fixedId = listItem.id.replace(/\_/g, '/').replace(/\-/g, '+'); + listItem.id = Uint8Array.from(atob(fixedId), c => c.charCodeAt(0)); + }); + + return json; +} + // From https://github.com/abergs/fido2-net-lib/blob/b487a1d47373ea18cd752b4988f7262035b7b54e/Demo/wwwroot/js/helpers.js#L34 // License: https://github.com/abergs/fido2-net-lib/blob/master/LICENSE.txt function coerceToBase64Url(thing: any) { diff --git a/src/connectors/webauthn-fallback.ts b/src/connectors/webauthn-fallback.ts index 6be8e2710c..9c3ebbd032 100644 --- a/src/connectors/webauthn-fallback.ts +++ b/src/connectors/webauthn-fallback.ts @@ -1,5 +1,5 @@ import { getQsParam } from './common'; -import { b64Decode, buildDataString } from './common-webauthn'; +import { b64Decode, buildDataString, parseWebauthnJson } from './common-webauthn'; // tslint:disable-next-line require('./webauthn.scss'); @@ -63,7 +63,7 @@ function start() { let json: any; try { const jsonString = b64Decode(data); - json = JSON.parse(jsonString); + json = parseWebauthnJson(jsonString); } catch (e) { error('Cannot parse data.'); @@ -74,15 +74,6 @@ function start() { } async function initWebAuthn(obj: any) { - const challenge = obj.challenge.replace(/-/g, '+').replace(/_/g, '/'); - obj.challenge = Uint8Array.from(atob(challenge), c => c.charCodeAt(0)); - - // fix escaping. Change this to coerce - obj.allowCredentials.forEach((listItem: any) => { - const fixedId = listItem.id.replace(/\_/g, '/').replace(/\-/g, '+'); - listItem.id = Uint8Array.from(atob(fixedId), c => c.charCodeAt(0)); - }); - try { const assertedCredential = await navigator.credentials.get({ publicKey: obj }) as PublicKeyCredential; diff --git a/src/connectors/webauthn.ts b/src/connectors/webauthn.ts index 1d210802ad..c71dd47e09 100644 --- a/src/connectors/webauthn.ts +++ b/src/connectors/webauthn.ts @@ -1,5 +1,5 @@ import { getQsParam } from './common'; -import { b64Decode, buildDataString } from './common-webauthn'; +import { b64Decode, buildDataString, parseWebauthnJson } from './common-webauthn'; // tslint:disable-next-line require('./webauthn.scss'); @@ -50,22 +50,13 @@ function start() { try { const jsonString = b64Decode(data); - obj = JSON.parse(jsonString); + obj = parseWebauthnJson(jsonString); } catch (e) { error('Cannot parse data.'); return; } - const challenge = obj.challenge.replace(/-/g, '+').replace(/_/g, '/'); - obj.challenge = Uint8Array.from(atob(challenge), c => c.charCodeAt(0)); - - // fix escaping. Change this to coerce - obj.allowCredentials.forEach((listItem: any) => { - const fixedId = listItem.id.replace(/\_/g, '/').replace(/\-/g, '+'); - listItem.id = Uint8Array.from(atob(fixedId), c => c.charCodeAt(0)); - }); - stopWebAuthn = false; if (navigator.userAgent.indexOf(' Safari/') !== -1 && navigator.userAgent.indexOf('Chrome') === -1) {