From 64f60aa870d27557fb075eca4e805c12f6960119 Mon Sep 17 00:00:00 2001 From: Andreas Coroiu Date: Tue, 10 Jan 2023 10:17:46 +0100 Subject: [PATCH] [EC-598] feat: fix google issues Google does not like self-signed packed format. I've removed the attestation statement all-together untill further notice. We're don't really have any statements so --- apps/browser/src/browser/webauthn-utils.ts | 34 ++++++++++++++++--- .../fido2/fido2.service.abstraction.ts | 3 ++ .../src/services/fido2/fido2.service.ts | 21 ++++++++---- 3 files changed, 46 insertions(+), 12 deletions(-) diff --git a/apps/browser/src/browser/webauthn-utils.ts b/apps/browser/src/browser/webauthn-utils.ts index f59816a3a4..c11dfcb5d4 100644 --- a/apps/browser/src/browser/webauthn-utils.ts +++ b/apps/browser/src/browser/webauthn-utils.ts @@ -6,6 +6,32 @@ import { CredentialRegistrationResult, } from "@bitwarden/common/abstractions/fido2/fido2.service.abstraction"; +class BitAuthenticatorAttestationResponse implements AuthenticatorAttestationResponse { + clientDataJSON: ArrayBuffer; + attestationObject: ArrayBuffer; + + constructor(private result: CredentialRegistrationResult) { + this.clientDataJSON = Fido2Utils.stringToBuffer(result.clientDataJSON); + this.attestationObject = Fido2Utils.stringToBuffer(result.attestationObject); + } + + getAuthenticatorData(): ArrayBuffer { + return Fido2Utils.stringToBuffer(this.result.authData); + } + + getPublicKey(): ArrayBuffer { + return null; + } + + getPublicKeyAlgorithm(): number { + return this.result.publicKeyAlgorithm; + } + + getTransports(): string[] { + return this.result.transports; + } +} + export class WebauthnUtils { static mapCredentialCreationOptions( options: CredentialCreationOptions, @@ -57,12 +83,10 @@ export class WebauthnUtils { id: result.credentialId, rawId: Fido2Utils.stringToBuffer(result.credentialId), type: "public-key", - response: { - clientDataJSON: Fido2Utils.stringToBuffer(result.clientDataJSON), - attestationObject: Fido2Utils.stringToBuffer(result.attestationObject), - } as AuthenticatorAttestationResponse, + authenticatorAttachment: "cross-platform", + response: new BitAuthenticatorAttestationResponse(result), getClientExtensionResults: () => ({}), - }; + } as any; } static mapCredentialRequestOptions( diff --git a/libs/common/src/abstractions/fido2/fido2.service.abstraction.ts b/libs/common/src/abstractions/fido2/fido2.service.abstraction.ts index 203a9465cc..6677330d70 100644 --- a/libs/common/src/abstractions/fido2/fido2.service.abstraction.ts +++ b/libs/common/src/abstractions/fido2/fido2.service.abstraction.ts @@ -37,6 +37,9 @@ export interface CredentialRegistrationResult { credentialId: string; clientDataJSON: string; attestationObject: string; + authData: string; + publicKeyAlgorithm: number; + transports: string[]; } export interface CredentialAssertParams { diff --git a/libs/common/src/services/fido2/fido2.service.ts b/libs/common/src/services/fido2/fido2.service.ts index 3ee7a6f10a..6a227460bb 100644 --- a/libs/common/src/services/fido2/fido2.service.ts +++ b/libs/common/src/services/fido2/fido2.service.ts @@ -21,7 +21,9 @@ import { Fido2KeyView } from "../../models/view/fido2-key.view"; import { CredentialId } from "./credential-id"; import { joseToDer } from "./ecdsa-utils"; -const STANDARD_ATTESTATION_FORMAT = "packed"; +// We support self-signing, but Google won't accept it. +// TODO: Look into supporting self-signed packed format. +const STANDARD_ATTESTATION_FORMAT: "none" | "packed" = "none"; interface BitCredential { credentialId: CredentialId; @@ -59,6 +61,7 @@ export class Fido2Service implements Fido2ServiceAbstraction { type: "webauthn.create", challenge: params.challenge, origin: params.origin, + crossOrigin: false, }) ); const keyPair = await crypto.subtle.generateKey( @@ -87,7 +90,6 @@ export class Fido2Service implements Fido2ServiceAbstraction { userPresence: presence, userVerification: true, // TODO: Change to false keyPair, - attestationFormat: STANDARD_ATTESTATION_FORMAT, }); const asn1Der_signature = await generateSignature({ @@ -99,10 +101,13 @@ export class Fido2Service implements Fido2ServiceAbstraction { const attestationObject = new Uint8Array( CBOR.encode({ fmt: attestationFormat, - attStmt: { - alg: -7, - sig: asn1Der_signature, - }, + attStmt: + attestationFormat === "packed" + ? { + alg: -7, + sig: asn1Der_signature, + } + : {}, authData, }) ); @@ -111,6 +116,9 @@ export class Fido2Service implements Fido2ServiceAbstraction { credentialId: Fido2Utils.bufferToString(credentialId.raw), clientDataJSON: Fido2Utils.bufferToString(clientData), attestationObject: Fido2Utils.bufferToString(attestationObject), + authData: Fido2Utils.bufferToString(authData), + publicKeyAlgorithm: -7, + transports: ["nfc", "usb"], }; } @@ -240,7 +248,6 @@ interface AuthDataParams { userPresence: boolean; userVerification: boolean; keyPair?: CryptoKeyPair; - attestationFormat?: "packed" | "fido-u2f"; } async function mapCipherViewToBitCredential(cipherView: CipherView): Promise {