1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-16 08:13:42 +00:00

[EC-598] feat: add check for unsupported algorithms

This commit is contained in:
Andreas Coroiu
2023-03-21 16:59:26 +01:00
parent 078bf9dcb5
commit 696e036ca8
3 changed files with 61 additions and 16 deletions

View File

@@ -2,8 +2,14 @@ export abstract class Fido2AuthenticatorService {
makeCredential: (params: Fido2AuthenticatorMakeCredentialsParams) => void; makeCredential: (params: Fido2AuthenticatorMakeCredentialsParams) => void;
} }
export enum Fido2AlgorithmIdentifier {
ES256 = -7,
RS256 = -257,
}
export enum Fido2AutenticatorErrorCode { export enum Fido2AutenticatorErrorCode {
CTAP2_ERR_CREDENTIAL_EXCLUDED, CTAP2_ERR_CREDENTIAL_EXCLUDED,
CTAP2_ERR_UNSUPPORTED_ALGORITHM,
} }
export class Fido2AutenticatorError extends Error { export class Fido2AutenticatorError extends Error {

View File

@@ -5,6 +5,7 @@ import { mock, MockProxy } from "jest-mock-extended";
import { Utils } from "../../misc/utils"; import { Utils } from "../../misc/utils";
import { CipherService } from "../../vault/abstractions/cipher.service"; import { CipherService } from "../../vault/abstractions/cipher.service";
import { CipherType } from "../../vault/enums/cipher-type"; import { CipherType } from "../../vault/enums/cipher-type";
import { Cipher } from "../../vault/models/domain/cipher";
import { CipherView } from "../../vault/models/view/cipher.view"; import { CipherView } from "../../vault/models/view/cipher.view";
import { import {
Fido2AutenticatorErrorCode, Fido2AutenticatorErrorCode,
@@ -12,7 +13,7 @@ import {
} from "../abstractions/fido2-authenticator.service.abstraction"; } from "../abstractions/fido2-authenticator.service.abstraction";
import { Fido2UserInterfaceService } from "../abstractions/fido2-user-interface.service.abstraction"; import { Fido2UserInterfaceService } from "../abstractions/fido2-user-interface.service.abstraction";
import { Fido2Utils } from "../abstractions/fido2-utils"; import { Fido2Utils } from "../abstractions/fido2-utils";
import { Fido2KeyView } from "../models/view/fido2-key.view"; import { Fido2Key } from "../models/domain/fido2-key";
import { Fido2AuthenticatorService } from "./fido2-authenticator.service"; import { Fido2AuthenticatorService } from "./fido2-authenticator.service";
@@ -31,15 +32,19 @@ describe("FidoAuthenticatorService", () => {
describe("authenticatorMakeCredential", () => { describe("authenticatorMakeCredential", () => {
describe("when vault contains excluded credential", () => { describe("when vault contains excluded credential", () => {
let excludedCipher: CipherView; let excludedCipherView: CipherView;
let params: Fido2AuthenticatorMakeCredentialsParams; let params: Fido2AuthenticatorMakeCredentialsParams;
beforeEach(async () => { beforeEach(async () => {
excludedCipher = createCipherView(); const excludedCipher = createCipher();
excludedCipherView = await excludedCipher.decrypt();
params = await createCredentialParams({ params = await createCredentialParams({
excludeList: [{ id: Fido2Utils.stringToBuffer(excludedCipher.id), type: "public-key" }], excludeList: [{ id: Fido2Utils.stringToBuffer(excludedCipher.id), type: "public-key" }],
}); });
cipherService.getAllDecrypted.mockResolvedValue([excludedCipher]); cipherService.get.mockImplementation(async (id) =>
id === excludedCipher.id ? excludedCipher : undefined
);
cipherService.getAllDecrypted.mockResolvedValue([excludedCipherView]);
}); });
/** Spec: wait for user presence */ /** Spec: wait for user presence */
@@ -62,6 +67,19 @@ describe("FidoAuthenticatorService", () => {
); );
}); });
}); });
// Spec: If the pubKeyCredParams parameter does not contain a valid COSEAlgorithmIdentifier value that is supported by the authenticator, terminate this procedure and return error code
it("should throw error when input does not contain any supported algorithms", async () => {
const params = await createCredentialParams({
pubKeyCredParams: [{ alg: 9001, type: "public-key" }],
});
const result = async () => await authenticator.makeCredential(params);
await expect(result).rejects.toThrowError(
Fido2AutenticatorErrorCode[Fido2AutenticatorErrorCode.CTAP2_ERR_UNSUPPORTED_ALGORITHM]
);
});
}); });
}); });
@@ -82,7 +100,7 @@ async function createCredentialParams(
}, },
pubKeyCredParams: params.pubKeyCredParams ?? [ pubKeyCredParams: params.pubKeyCredParams ?? [
{ {
alg: -1, // ES256 alg: -7, // ES256
type: "public-key", type: "public-key",
}, },
], ],
@@ -106,11 +124,11 @@ async function createCredentialParams(
}; };
} }
function createCipherView(id = Utils.newGuid()): CipherView { function createCipher(id = Utils.newGuid()): Cipher {
const cipher = new CipherView(); const cipher = new Cipher();
cipher.id = id; cipher.id = id;
cipher.type = CipherType.Fido2Key; cipher.type = CipherType.Fido2Key;
cipher.fido2Key = new Fido2KeyView(); cipher.fido2Key = new Fido2Key();
return cipher; return cipher;
} }

View File

@@ -1,5 +1,6 @@
import { CipherService } from "../../vault/services/cipher.service"; import { CipherService } from "../../vault/services/cipher.service";
import { import {
Fido2AlgorithmIdentifier,
Fido2AutenticatorError, Fido2AutenticatorError,
Fido2AutenticatorErrorCode, Fido2AutenticatorErrorCode,
Fido2AuthenticatorMakeCredentialsParams, Fido2AuthenticatorMakeCredentialsParams,
@@ -19,16 +20,36 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
) {} ) {}
async makeCredential(params: Fido2AuthenticatorMakeCredentialsParams): Promise<void> { async makeCredential(params: Fido2AuthenticatorMakeCredentialsParams): Promise<void> {
const userConfirmation = await this.userInterface.confirmDuplicateCredential( const duplicateExists = await this.vaultContainsId(
[Fido2Utils.bufferToString(params.excludeList[0].id)], params.excludeList.map((key) => Fido2Utils.bufferToString(key.id))
{
credentialName: params.rp.name,
userName: params.user.name,
}
); );
if (!userConfirmation) { if (duplicateExists) {
throw new Fido2AutenticatorError(Fido2AutenticatorErrorCode.CTAP2_ERR_CREDENTIAL_EXCLUDED); const userConfirmation = await this.userInterface.confirmDuplicateCredential(
[Fido2Utils.bufferToString(params.excludeList[0].id)],
{
credentialName: params.rp.name,
userName: params.user.name,
}
);
if (!userConfirmation) {
throw new Fido2AutenticatorError(Fido2AutenticatorErrorCode.CTAP2_ERR_CREDENTIAL_EXCLUDED);
}
}
if (params.pubKeyCredParams.every((p) => p.alg !== Fido2AlgorithmIdentifier.ES256)) {
throw new Fido2AutenticatorError(Fido2AutenticatorErrorCode.CTAP2_ERR_UNSUPPORTED_ALGORITHM);
} }
} }
private async vaultContainsId(ids: string[]): Promise<boolean> {
for (const id of ids) {
if ((await this.cipherService.get(id)) != undefined) {
return true;
}
}
return false;
}
} }