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:
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,6 +20,11 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async makeCredential(params: Fido2AuthenticatorMakeCredentialsParams): Promise<void> {
|
async makeCredential(params: Fido2AuthenticatorMakeCredentialsParams): Promise<void> {
|
||||||
|
const duplicateExists = await this.vaultContainsId(
|
||||||
|
params.excludeList.map((key) => Fido2Utils.bufferToString(key.id))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (duplicateExists) {
|
||||||
const userConfirmation = await this.userInterface.confirmDuplicateCredential(
|
const userConfirmation = await this.userInterface.confirmDuplicateCredential(
|
||||||
[Fido2Utils.bufferToString(params.excludeList[0].id)],
|
[Fido2Utils.bufferToString(params.excludeList[0].id)],
|
||||||
{
|
{
|
||||||
@@ -31,4 +37,19 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
|
|||||||
throw new Fido2AutenticatorError(Fido2AutenticatorErrorCode.CTAP2_ERR_CREDENTIAL_EXCLUDED);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user