mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-31 22:51:28 +01:00
[EC-598] feat: fully working credential creation
This commit is contained in:
parent
e4bbb173b4
commit
91daba5991
@ -1,5 +1,8 @@
|
|||||||
import { Fido2Utils } from "@bitwarden/common/abstractions/fido2/fido2-utils";
|
import { Fido2Utils } from "@bitwarden/common/abstractions/fido2/fido2-utils";
|
||||||
import { CredentialRegistrationParams } from "@bitwarden/common/abstractions/fido2/fido2.service.abstraction";
|
import {
|
||||||
|
CredentialRegistrationParams,
|
||||||
|
CredentialRegistrationResult,
|
||||||
|
} from "@bitwarden/common/abstractions/fido2/fido2.service.abstraction";
|
||||||
|
|
||||||
export class WebauthnUtils {
|
export class WebauthnUtils {
|
||||||
static mapCredentialCreationOptions(
|
static mapCredentialCreationOptions(
|
||||||
@ -44,4 +47,19 @@ export class WebauthnUtils {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mapCredentialRegistrationResult(
|
||||||
|
result: CredentialRegistrationResult
|
||||||
|
): PublicKeyCredential {
|
||||||
|
return {
|
||||||
|
id: result.credentialId,
|
||||||
|
rawId: Fido2Utils.stringToBuffer(result.credentialId),
|
||||||
|
type: "public-key",
|
||||||
|
response: {
|
||||||
|
clientDataJSON: Fido2Utils.stringToBuffer(result.clientDataJSON),
|
||||||
|
attestationObject: Fido2Utils.stringToBuffer(result.attestationObject),
|
||||||
|
} as AuthenticatorAttestationResponse,
|
||||||
|
getClientExtensionResults: () => ({}),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ messenger.addHandler(async (message) => {
|
|||||||
resolve({
|
resolve({
|
||||||
type: MessageType.CredentialCreationResponse,
|
type: MessageType.CredentialCreationResponse,
|
||||||
approved: true,
|
approved: true,
|
||||||
|
result: response,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
import { CredentialRegistrationParams } from "@bitwarden/common/abstractions/fido2/fido2.service.abstraction";
|
import {
|
||||||
|
CredentialRegistrationParams,
|
||||||
|
CredentialRegistrationResult,
|
||||||
|
} from "@bitwarden/common/abstractions/fido2/fido2.service.abstraction";
|
||||||
|
|
||||||
export enum MessageType {
|
export enum MessageType {
|
||||||
CredentialCreationRequest,
|
CredentialCreationRequest,
|
||||||
@ -17,6 +20,7 @@ export type CredentialCreationRequest = {
|
|||||||
export type CredentialCreationResponse = {
|
export type CredentialCreationResponse = {
|
||||||
type: MessageType.CredentialCreationResponse;
|
type: MessageType.CredentialCreationResponse;
|
||||||
approved: boolean;
|
approved: boolean;
|
||||||
|
result?: CredentialRegistrationResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type CredentialGetRequest = {
|
export type CredentialGetRequest = {
|
||||||
|
@ -14,12 +14,16 @@ const browserCredentials = {
|
|||||||
const messenger = Messenger.forDOMCommunication(window);
|
const messenger = Messenger.forDOMCommunication(window);
|
||||||
|
|
||||||
navigator.credentials.create = async (options?: CredentialCreationOptions): Promise<Credential> => {
|
navigator.credentials.create = async (options?: CredentialCreationOptions): Promise<Credential> => {
|
||||||
await messenger.request({
|
const response = await messenger.request({
|
||||||
type: MessageType.CredentialCreationRequest,
|
type: MessageType.CredentialCreationRequest,
|
||||||
data: WebauthnUtils.mapCredentialCreationOptions(options, window.location.origin),
|
data: WebauthnUtils.mapCredentialCreationOptions(options, window.location.origin),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (response.type !== MessageType.CredentialCreationResponse || !response.approved) {
|
||||||
return await browserCredentials.create(options);
|
return await browserCredentials.create(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebauthnUtils.mapCredentialRegistrationResult(response.result);
|
||||||
};
|
};
|
||||||
|
|
||||||
navigator.credentials.get = async (options?: CredentialRequestOptions): Promise<Credential> => {
|
navigator.credentials.get = async (options?: CredentialRequestOptions): Promise<Credential> => {
|
||||||
|
@ -33,7 +33,13 @@ export interface CredentialRegistrationParams {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface CredentialRegistrationResult {
|
||||||
|
credentialId: string;
|
||||||
|
clientDataJSON: string;
|
||||||
|
attestationObject: string;
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class Fido2Service {
|
export abstract class Fido2Service {
|
||||||
createCredential: (params: CredentialRegistrationParams) => Promise<unknown>;
|
createCredential: (params: CredentialRegistrationParams) => Promise<CredentialRegistrationResult>;
|
||||||
assertCredential: () => unknown;
|
assertCredential: () => unknown;
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { Fido2UserInterfaceService } from "../../abstractions/fido2/fido2-user-i
|
|||||||
import { Fido2Utils } from "../../abstractions/fido2/fido2-utils";
|
import { Fido2Utils } from "../../abstractions/fido2/fido2-utils";
|
||||||
import {
|
import {
|
||||||
CredentialRegistrationParams,
|
CredentialRegistrationParams,
|
||||||
|
CredentialRegistrationResult,
|
||||||
Fido2Service as Fido2ServiceAbstraction,
|
Fido2Service as Fido2ServiceAbstraction,
|
||||||
} from "../../abstractions/fido2/fido2.service.abstraction";
|
} from "../../abstractions/fido2/fido2.service.abstraction";
|
||||||
import { Utils } from "../../misc/utils";
|
import { Utils } from "../../misc/utils";
|
||||||
@ -26,10 +27,12 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
|||||||
|
|
||||||
constructor(private fido2UserInterfaceService: Fido2UserInterfaceService) {}
|
constructor(private fido2UserInterfaceService: Fido2UserInterfaceService) {}
|
||||||
|
|
||||||
async createCredential(params: CredentialRegistrationParams): Promise<unknown> {
|
async createCredential(
|
||||||
|
params: CredentialRegistrationParams
|
||||||
|
): Promise<CredentialRegistrationResult> {
|
||||||
await this.fido2UserInterfaceService.confirmNewCredential();
|
await this.fido2UserInterfaceService.confirmNewCredential();
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log("Fido2Service.registerCredential", params);
|
console.log("Fido2Service.createCredential", params);
|
||||||
|
|
||||||
const attestationFormat = STANDARD_ATTESTATION_FORMAT;
|
const attestationFormat = STANDARD_ATTESTATION_FORMAT;
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
@ -39,7 +42,7 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
|||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
type: "webauthn.create",
|
type: "webauthn.create",
|
||||||
challenge: params.challenge,
|
challenge: params.challenge,
|
||||||
origin,
|
origin: params.origin,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const keyPair = await crypto.subtle.generateKey(
|
const keyPair = await crypto.subtle.generateKey(
|
||||||
@ -80,20 +83,22 @@ export class Fido2Service implements Fido2ServiceAbstraction {
|
|||||||
this.credentials.set(credentialId.encoded, {
|
this.credentials.set(credentialId.encoded, {
|
||||||
credentialId,
|
credentialId,
|
||||||
keyPair,
|
keyPair,
|
||||||
origin,
|
origin: params.origin,
|
||||||
rpId: params.rp.id,
|
rpId: params.rp.id,
|
||||||
userHandle: Fido2Utils.stringToBuffer(params.user.id),
|
userHandle: Fido2Utils.stringToBuffer(params.user.id),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log("Fido2Service.createCredential => result", {
|
||||||
|
credentialId: Fido2Utils.bufferToString(credentialId.raw),
|
||||||
|
clientDataJSON: Fido2Utils.bufferToString(clientData),
|
||||||
|
attestationObject: Fido2Utils.bufferToString(attestationObject),
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: credentialId.encoded,
|
credentialId: Fido2Utils.bufferToString(credentialId.raw),
|
||||||
rawId: credentialId.raw,
|
clientDataJSON: Fido2Utils.bufferToString(clientData),
|
||||||
type: "public-key",
|
attestationObject: Fido2Utils.bufferToString(attestationObject),
|
||||||
response: {
|
|
||||||
clientDataJSON: clientData,
|
|
||||||
attestationObject: attestationObject,
|
|
||||||
} as AuthenticatorAttestationResponse,
|
|
||||||
getClientExtensionResults: () => ({}),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,8 +179,7 @@ async function generateAuthData(params: AuthDataParams) {
|
|||||||
coseBytes.set(keyY, 10 + 32 + 3);
|
coseBytes.set(keyY, 10 + 32 + 3);
|
||||||
|
|
||||||
// credential public key - convert to array from CBOR encoded COSE key
|
// credential public key - convert to array from CBOR encoded COSE key
|
||||||
const credPublicKeyBytes = coseBytes.subarray(0, -1);
|
attestedCredentialData.push(...coseBytes);
|
||||||
attestedCredentialData.push(...credPublicKeyBytes);
|
|
||||||
|
|
||||||
authData.push(...attestedCredentialData);
|
authData.push(...attestedCredentialData);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user