1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-17 16:53:34 +00:00

[PM-1859] Refactor to credentialId (#6034)

* PM-1859 Refactor to credentialId

* PM-1859 Minor changes

* PM-1859 Fix credentialId initialization logic

* PM-1859 Added missing logic

* PM-1859 Fixed logic to use credentialID instead of cipher.id

* [PM-1859] fix: missing renames

---------

Co-authored-by: Andreas Coroiu <andreas.coroiu@gmail.com>
This commit is contained in:
Carlos Gonçalves
2023-09-07 15:20:56 +01:00
committed by GitHub
parent 7e00e02f95
commit f35b25649a
11 changed files with 66 additions and 72 deletions

View File

@@ -6,7 +6,7 @@ import { Fido2Key as Fido2KeyDomain } from "./../../vault/models/domain/fido2-ke
export class Fido2KeyExport { export class Fido2KeyExport {
static template(): Fido2KeyExport { static template(): Fido2KeyExport {
const req = new Fido2KeyExport(); const req = new Fido2KeyExport();
req.nonDiscoverableId = "keyId"; req.credentialId = "keyId";
req.keyType = "keyType"; req.keyType = "keyType";
req.keyAlgorithm = "keyAlgorithm"; req.keyAlgorithm = "keyAlgorithm";
req.keyCurve = "keyCurve"; req.keyCurve = "keyCurve";
@@ -20,7 +20,7 @@ export class Fido2KeyExport {
} }
static toView(req: Fido2KeyExport, view = new Fido2KeyView()) { static toView(req: Fido2KeyExport, view = new Fido2KeyView()) {
view.nonDiscoverableId = req.nonDiscoverableId; view.credentialId = req.credentialId;
view.keyType = req.keyType as "public-key"; view.keyType = req.keyType as "public-key";
view.keyAlgorithm = req.keyAlgorithm as "ECDSA"; view.keyAlgorithm = req.keyAlgorithm as "ECDSA";
view.keyCurve = req.keyCurve as "P-256"; view.keyCurve = req.keyCurve as "P-256";
@@ -34,8 +34,7 @@ export class Fido2KeyExport {
} }
static toDomain(req: Fido2KeyExport, domain = new Fido2KeyDomain()) { static toDomain(req: Fido2KeyExport, domain = new Fido2KeyDomain()) {
domain.nonDiscoverableId = domain.credentialId = req.credentialId != null ? new EncString(req.credentialId) : null;
req.nonDiscoverableId != null ? new EncString(req.nonDiscoverableId) : null;
domain.keyType = req.keyType != null ? new EncString(req.keyType) : null; domain.keyType = req.keyType != null ? new EncString(req.keyType) : null;
domain.keyAlgorithm = req.keyAlgorithm != null ? new EncString(req.keyAlgorithm) : null; domain.keyAlgorithm = req.keyAlgorithm != null ? new EncString(req.keyAlgorithm) : null;
domain.keyCurve = req.keyCurve != null ? new EncString(req.keyCurve) : null; domain.keyCurve = req.keyCurve != null ? new EncString(req.keyCurve) : null;
@@ -49,7 +48,7 @@ export class Fido2KeyExport {
return domain; return domain;
} }
nonDiscoverableId: string; credentialId: string;
keyType: string; keyType: string;
keyAlgorithm: string; keyAlgorithm: string;
keyCurve: string; keyCurve: string;
@@ -66,7 +65,7 @@ export class Fido2KeyExport {
} }
if (o instanceof Fido2KeyView) { if (o instanceof Fido2KeyView) {
this.nonDiscoverableId = o.nonDiscoverableId; this.credentialId = o.credentialId;
this.keyType = o.keyType; this.keyType = o.keyType;
this.keyAlgorithm = o.keyAlgorithm; this.keyAlgorithm = o.keyAlgorithm;
this.keyCurve = o.keyCurve; this.keyCurve = o.keyCurve;
@@ -77,7 +76,7 @@ export class Fido2KeyExport {
this.rpName = o.rpName; this.rpName = o.rpName;
this.userDisplayName = o.userDisplayName; this.userDisplayName = o.userDisplayName;
} else { } else {
this.nonDiscoverableId = o.nonDiscoverableId?.encryptedString; this.credentialId = o.credentialId?.encryptedString;
this.keyType = o.keyType?.encryptedString; this.keyType = o.keyType?.encryptedString;
this.keyAlgorithm = o.keyAlgorithm?.encryptedString; this.keyAlgorithm = o.keyAlgorithm?.encryptedString;
this.keyCurve = o.keyCurve?.encryptedString; this.keyCurve = o.keyCurve?.encryptedString;

View File

@@ -1,7 +1,7 @@
import { BaseResponse } from "../../models/response/base.response"; import { BaseResponse } from "../../models/response/base.response";
export class Fido2KeyApi extends BaseResponse { export class Fido2KeyApi extends BaseResponse {
nonDiscoverableId: string; credentialId: string;
keyType: "public-key"; keyType: "public-key";
keyAlgorithm: "ECDSA"; keyAlgorithm: "ECDSA";
keyCurve: "P-256"; keyCurve: "P-256";
@@ -18,7 +18,7 @@ export class Fido2KeyApi extends BaseResponse {
return; return;
} }
this.nonDiscoverableId = this.getResponseProperty("NonDiscoverableId"); this.credentialId = this.getResponseProperty("CredentialId");
this.keyType = this.getResponseProperty("KeyType"); this.keyType = this.getResponseProperty("KeyType");
this.keyAlgorithm = this.getResponseProperty("KeyAlgorithm"); this.keyAlgorithm = this.getResponseProperty("KeyAlgorithm");
this.keyCurve = this.getResponseProperty("KeyCurve"); this.keyCurve = this.getResponseProperty("KeyCurve");

View File

@@ -1,7 +1,7 @@
import { Fido2KeyApi } from "../../api/fido2-key.api"; import { Fido2KeyApi } from "../../api/fido2-key.api";
export class Fido2KeyData { export class Fido2KeyData {
nonDiscoverableId: string; credentialId: string;
keyType: "public-key"; keyType: "public-key";
keyAlgorithm: "ECDSA"; keyAlgorithm: "ECDSA";
keyCurve: "P-256"; keyCurve: "P-256";
@@ -17,7 +17,7 @@ export class Fido2KeyData {
return; return;
} }
this.nonDiscoverableId = data.nonDiscoverableId; this.credentialId = data.credentialId;
this.keyType = data.keyType; this.keyType = data.keyType;
this.keyAlgorithm = data.keyAlgorithm; this.keyAlgorithm = data.keyAlgorithm;
this.keyCurve = data.keyCurve; this.keyCurve = data.keyCurve;

View File

@@ -12,7 +12,7 @@ describe("Fido2Key", () => {
const fido2Key = new Fido2Key(data); const fido2Key = new Fido2Key(data);
expect(fido2Key).toEqual({ expect(fido2Key).toEqual({
nonDiscoverableId: null, credentialId: null,
keyType: null, keyType: null,
keyAlgorithm: null, keyAlgorithm: null,
keyCurve: null, keyCurve: null,
@@ -27,7 +27,7 @@ describe("Fido2Key", () => {
it("returns all fields as EncStrings when given full Fido2KeyData", () => { it("returns all fields as EncStrings when given full Fido2KeyData", () => {
const data: Fido2KeyData = { const data: Fido2KeyData = {
nonDiscoverableId: "nonDiscoverableId", credentialId: "credentialId",
keyType: "public-key", keyType: "public-key",
keyAlgorithm: "ECDSA", keyAlgorithm: "ECDSA",
keyCurve: "P-256", keyCurve: "P-256",
@@ -41,7 +41,7 @@ describe("Fido2Key", () => {
const fido2Key = new Fido2Key(data); const fido2Key = new Fido2Key(data);
expect(fido2Key).toEqual({ expect(fido2Key).toEqual({
nonDiscoverableId: { encryptedString: "nonDiscoverableId", encryptionType: 0 }, credentialId: { encryptedString: "credentialId", encryptionType: 0 },
keyType: { encryptedString: "public-key", encryptionType: 0 }, keyType: { encryptedString: "public-key", encryptionType: 0 },
keyAlgorithm: { encryptedString: "ECDSA", encryptionType: 0 }, keyAlgorithm: { encryptedString: "ECDSA", encryptionType: 0 },
keyCurve: { encryptedString: "P-256", encryptionType: 0 }, keyCurve: { encryptedString: "P-256", encryptionType: 0 },
@@ -58,7 +58,7 @@ describe("Fido2Key", () => {
const fido2Key = new Fido2Key(); const fido2Key = new Fido2Key();
expect(fido2Key).toEqual({ expect(fido2Key).toEqual({
nonDiscoverableId: null, credentialId: null,
}); });
}); });
}); });
@@ -66,7 +66,7 @@ describe("Fido2Key", () => {
describe("decrypt", () => { describe("decrypt", () => {
it("decrypts and populates all fields when populated with EncStrings", async () => { it("decrypts and populates all fields when populated with EncStrings", async () => {
const fido2Key = new Fido2Key(); const fido2Key = new Fido2Key();
fido2Key.nonDiscoverableId = mockEnc("nonDiscoverableId"); fido2Key.credentialId = mockEnc("credentialId");
fido2Key.keyType = mockEnc("keyType"); fido2Key.keyType = mockEnc("keyType");
fido2Key.keyAlgorithm = mockEnc("keyAlgorithm"); fido2Key.keyAlgorithm = mockEnc("keyAlgorithm");
fido2Key.keyCurve = mockEnc("keyCurve"); fido2Key.keyCurve = mockEnc("keyCurve");
@@ -80,7 +80,7 @@ describe("Fido2Key", () => {
const fido2KeyView = await fido2Key.decrypt(null); const fido2KeyView = await fido2Key.decrypt(null);
expect(fido2KeyView).toEqual({ expect(fido2KeyView).toEqual({
nonDiscoverableId: "nonDiscoverableId", credentialId: "credentialId",
keyType: "keyType", keyType: "keyType",
keyAlgorithm: "keyAlgorithm", keyAlgorithm: "keyAlgorithm",
keyCurve: "keyCurve", keyCurve: "keyCurve",
@@ -97,7 +97,7 @@ describe("Fido2Key", () => {
describe("toFido2KeyData", () => { describe("toFido2KeyData", () => {
it("encodes to data object when converted from Fido2KeyData and back", () => { it("encodes to data object when converted from Fido2KeyData and back", () => {
const data: Fido2KeyData = { const data: Fido2KeyData = {
nonDiscoverableId: "nonDiscoverableId", credentialId: "credentialId",
keyType: "public-key", keyType: "public-key",
keyAlgorithm: "ECDSA", keyAlgorithm: "ECDSA",
keyCurve: "P-256", keyCurve: "P-256",
@@ -119,7 +119,7 @@ describe("Fido2Key", () => {
describe("fromJSON", () => { describe("fromJSON", () => {
it("recreates equivalent object when converted to JSON and back", () => { it("recreates equivalent object when converted to JSON and back", () => {
const fido2Key = new Fido2Key(); const fido2Key = new Fido2Key();
fido2Key.nonDiscoverableId = createEncryptedEncString("nonDiscoverableId"); fido2Key.credentialId = createEncryptedEncString("credentialId");
fido2Key.keyType = createEncryptedEncString("keyType"); fido2Key.keyType = createEncryptedEncString("keyType");
fido2Key.keyAlgorithm = createEncryptedEncString("keyAlgorithm"); fido2Key.keyAlgorithm = createEncryptedEncString("keyAlgorithm");
fido2Key.keyCurve = createEncryptedEncString("keyCurve"); fido2Key.keyCurve = createEncryptedEncString("keyCurve");

View File

@@ -7,7 +7,7 @@ import { Fido2KeyData } from "../data/fido2-key.data";
import { Fido2KeyView } from "../view/fido2-key.view"; import { Fido2KeyView } from "../view/fido2-key.view";
export class Fido2Key extends Domain { export class Fido2Key extends Domain {
nonDiscoverableId: EncString | null = null; credentialId: EncString | null = null;
keyType: EncString; keyType: EncString;
keyAlgorithm: EncString; keyAlgorithm: EncString;
keyCurve: EncString; keyCurve: EncString;
@@ -28,7 +28,7 @@ export class Fido2Key extends Domain {
this, this,
obj, obj,
{ {
nonDiscoverableId: null, credentialId: null,
keyType: null, keyType: null,
keyAlgorithm: null, keyAlgorithm: null,
keyCurve: null, keyCurve: null,
@@ -47,7 +47,7 @@ export class Fido2Key extends Domain {
const view = await this.decryptObj( const view = await this.decryptObj(
new Fido2KeyView(), new Fido2KeyView(),
{ {
nonDiscoverableId: null, credentialId: null,
keyType: null, keyType: null,
keyAlgorithm: null, keyAlgorithm: null,
keyCurve: null, keyCurve: null,
@@ -78,7 +78,7 @@ export class Fido2Key extends Domain {
toFido2KeyData(): Fido2KeyData { toFido2KeyData(): Fido2KeyData {
const i = new Fido2KeyData(); const i = new Fido2KeyData();
this.buildDataModel(this, i, { this.buildDataModel(this, i, {
nonDiscoverableId: null, credentialId: null,
keyType: null, keyType: null,
keyAlgorithm: null, keyAlgorithm: null,
keyCurve: null, keyCurve: null,
@@ -97,7 +97,7 @@ export class Fido2Key extends Domain {
return null; return null;
} }
const nonDiscoverableId = EncString.fromJSON(obj.nonDiscoverableId); const credentialId = EncString.fromJSON(obj.credentialId);
const keyType = EncString.fromJSON(obj.keyType); const keyType = EncString.fromJSON(obj.keyType);
const keyAlgorithm = EncString.fromJSON(obj.keyAlgorithm); const keyAlgorithm = EncString.fromJSON(obj.keyAlgorithm);
const keyCurve = EncString.fromJSON(obj.keyCurve); const keyCurve = EncString.fromJSON(obj.keyCurve);
@@ -109,7 +109,7 @@ export class Fido2Key extends Domain {
const userDisplayName = EncString.fromJSON(obj.userDisplayName); const userDisplayName = EncString.fromJSON(obj.userDisplayName);
return Object.assign(new Fido2Key(), obj, { return Object.assign(new Fido2Key(), obj, {
nonDiscoverableId, credentialId,
keyType, keyType,
keyAlgorithm, keyAlgorithm,
keyCurve, keyCurve,

View File

@@ -113,7 +113,7 @@ describe("Login DTO", () => {
passwordRevisionDate: passwordRevisionDate.toISOString(), passwordRevisionDate: passwordRevisionDate.toISOString(),
totp: "myTotp" as EncryptedString, totp: "myTotp" as EncryptedString,
fido2Key: { fido2Key: {
nonDiscoverableId: "keyId" as EncryptedString, credentialId: "keyId" as EncryptedString,
keyType: "keyType" as EncryptedString, keyType: "keyType" as EncryptedString,
keyAlgorithm: "keyAlgorithm" as EncryptedString, keyAlgorithm: "keyAlgorithm" as EncryptedString,
keyCurve: "keyCurve" as EncryptedString, keyCurve: "keyCurve" as EncryptedString,
@@ -133,7 +133,7 @@ describe("Login DTO", () => {
passwordRevisionDate: passwordRevisionDate, passwordRevisionDate: passwordRevisionDate,
totp: "myTotp_fromJSON", totp: "myTotp_fromJSON",
fido2Key: { fido2Key: {
nonDiscoverableId: "keyId_fromJSON", credentialId: "keyId_fromJSON",
keyType: "keyType_fromJSON", keyType: "keyType_fromJSON",
keyAlgorithm: "keyAlgorithm_fromJSON", keyAlgorithm: "keyAlgorithm_fromJSON",
keyCurve: "keyCurve_fromJSON", keyCurve: "keyCurve_fromJSON",

View File

@@ -66,9 +66,9 @@ export class CipherRequest {
if (cipher.login.fido2Key != null) { if (cipher.login.fido2Key != null) {
this.login.fido2Key = new Fido2KeyApi(); this.login.fido2Key = new Fido2KeyApi();
this.login.fido2Key.nonDiscoverableId = this.login.fido2Key.credentialId =
cipher.login.fido2Key.nonDiscoverableId != null cipher.login.fido2Key.credentialId != null
? cipher.login.fido2Key.nonDiscoverableId.encryptedString ? cipher.login.fido2Key.credentialId.encryptedString
: null; : null;
this.login.fido2Key.keyType = this.login.fido2Key.keyType =
cipher.login.fido2Key.keyType != null cipher.login.fido2Key.keyType != null
@@ -167,9 +167,9 @@ export class CipherRequest {
break; break;
case CipherType.Fido2Key: case CipherType.Fido2Key:
this.fido2Key = new Fido2KeyApi(); this.fido2Key = new Fido2KeyApi();
this.fido2Key.nonDiscoverableId = this.fido2Key.credentialId =
cipher.fido2Key.nonDiscoverableId != null cipher.fido2Key.credentialId != null
? cipher.fido2Key.nonDiscoverableId.encryptedString ? cipher.fido2Key.credentialId.encryptedString
: null; : null;
this.fido2Key.keyType = this.fido2Key.keyType =
cipher.fido2Key.keyType != null cipher.fido2Key.keyType != null

View File

@@ -3,7 +3,7 @@ import { Jsonify } from "type-fest";
import { ItemView } from "./item.view"; import { ItemView } from "./item.view";
export class Fido2KeyView extends ItemView { export class Fido2KeyView extends ItemView {
nonDiscoverableId: string; credentialId: string;
keyType: "public-key"; keyType: "public-key";
keyAlgorithm: "ECDSA"; keyAlgorithm: "ECDSA";
keyCurve: "P-256"; keyCurve: "P-256";

View File

@@ -1095,7 +1095,7 @@ export class CipherService implements CipherServiceAbstraction {
model.login.fido2Key, model.login.fido2Key,
cipher.login.fido2Key, cipher.login.fido2Key,
{ {
nonDiscoverableId: null, credentialId: null,
keyType: null, keyType: null,
keyAlgorithm: null, keyAlgorithm: null,
keyCurve: null, keyCurve: null,
@@ -1168,6 +1168,7 @@ export class CipherService implements CipherServiceAbstraction {
model.fido2Key, model.fido2Key,
cipher.fido2Key, cipher.fido2Key,
{ {
credentialId: null,
keyType: null, keyType: null,
keyAlgorithm: null, keyAlgorithm: null,
keyCurve: null, keyCurve: null,

View File

@@ -108,12 +108,12 @@ describe("FidoAuthenticatorService", () => {
beforeEach(async () => { beforeEach(async () => {
excludedCipher = createCipherView( excludedCipher = createCipherView(
{ type: CipherType.Login }, { type: CipherType.Login },
{ nonDiscoverableId: Utils.newGuid() } { credentialId: Utils.newGuid() }
); );
params = await createParams({ params = await createParams({
excludeCredentialDescriptorList: [ excludeCredentialDescriptorList: [
{ {
id: guidToRawFormat(excludedCipher.login.fido2Key.nonDiscoverableId), id: guidToRawFormat(excludedCipher.login.fido2Key.credentialId),
type: "public-key", type: "public-key",
}, },
], ],
@@ -187,7 +187,10 @@ describe("FidoAuthenticatorService", () => {
excludedCipherView = createCipherView(); excludedCipherView = createCipherView();
params = await createParams({ params = await createParams({
excludeCredentialDescriptorList: [ excludeCredentialDescriptorList: [
{ id: guidToRawFormat(excludedCipherView.id), type: "public-key" }, {
id: guidToRawFormat(excludedCipherView.fido2Key.credentialId),
type: "public-key",
},
], ],
}); });
cipherService.get.mockImplementation(async (id) => cipherService.get.mockImplementation(async (id) =>
@@ -313,7 +316,7 @@ describe("FidoAuthenticatorService", () => {
name: params.rpEntity.name, name: params.rpEntity.name,
fido2Key: expect.objectContaining({ fido2Key: expect.objectContaining({
nonDiscoverableId: null, credentialId: expect.anything(),
keyType: "public-key", keyType: "public-key",
keyAlgorithm: "ECDSA", keyAlgorithm: "ECDSA",
keyCurve: "P-256", keyCurve: "P-256",
@@ -412,7 +415,7 @@ describe("FidoAuthenticatorService", () => {
login: expect.objectContaining({ login: expect.objectContaining({
fido2Key: expect.objectContaining({ fido2Key: expect.objectContaining({
nonDiscoverableId: expect.anything(), credentialId: expect.anything(),
keyType: "public-key", keyType: "public-key",
keyAlgorithm: "ECDSA", keyAlgorithm: "ECDSA",
keyCurve: "P-256", keyCurve: "P-256",
@@ -462,12 +465,8 @@ describe("FidoAuthenticatorService", () => {
requireResidentKey ? "discoverable" : "non-discoverable" requireResidentKey ? "discoverable" : "non-discoverable"
} credential`, () => { } credential`, () => {
const cipherId = "75280e7e-a72e-4d6c-bf1e-d37238352f9b"; const cipherId = "75280e7e-a72e-4d6c-bf1e-d37238352f9b";
const cipherIdBytes = new Uint8Array([ const credentialId = "52217b91-73f1-4fea-b3f2-54a7959fd5aa";
0x75, 0x28, 0x0e, 0x7e, 0xa7, 0x2e, 0x4d, 0x6c, 0xbf, 0x1e, 0xd3, 0x72, 0x38, 0x35, 0x2f, const credentialIdBytes = new Uint8Array([
0x9b,
]);
const nonDiscoverableId = "52217b91-73f1-4fea-b3f2-54a7959fd5aa";
const nonDiscoverableIdBytes = new Uint8Array([
0x52, 0x21, 0x7b, 0x91, 0x73, 0xf1, 0x4f, 0xea, 0xb3, 0xf2, 0x54, 0xa7, 0x95, 0x9f, 0xd5, 0x52, 0x21, 0x7b, 0x91, 0x73, 0xf1, 0x4f, 0xea, 0xb3, 0xf2, 0x54, 0xa7, 0x95, 0x9f, 0xd5,
0xaa, 0xaa,
]); ]);
@@ -490,7 +489,9 @@ describe("FidoAuthenticatorService", () => {
cipherService.getAllDecrypted.mockResolvedValue([await cipher]); cipherService.getAllDecrypted.mockResolvedValue([await cipher]);
cipherService.encrypt.mockImplementation(async (cipher) => { cipherService.encrypt.mockImplementation(async (cipher) => {
if (!requireResidentKey) { if (!requireResidentKey) {
cipher.login.fido2Key.nonDiscoverableId = nonDiscoverableId; // Replace id for testability cipher.login.fido2Key.credentialId = credentialId; // Replace id for testability
} else {
cipher.fido2Key.credentialId = credentialId;
} }
return {} as any; return {} as any;
}); });
@@ -535,11 +536,7 @@ describe("FidoAuthenticatorService", () => {
expect(counter).toEqual(new Uint8Array([0, 0, 0, 0])); // 0 because of new counter expect(counter).toEqual(new Uint8Array([0, 0, 0, 0])); // 0 because of new counter
expect(aaguid).toEqual(AAGUID); expect(aaguid).toEqual(AAGUID);
expect(credentialIdLength).toEqual(new Uint8Array([0, 16])); // 16 bytes because we're using GUIDs expect(credentialIdLength).toEqual(new Uint8Array([0, 16])); // 16 bytes because we're using GUIDs
if (requireResidentKey) { expect(credentialId).toEqual(credentialIdBytes);
expect(credentialId).toEqual(cipherIdBytes);
} else {
expect(credentialId).toEqual(nonDiscoverableIdBytes);
}
}); });
}); });
} }
@@ -658,7 +655,7 @@ describe("FidoAuthenticatorService", () => {
it("should inform user if credential exists but rpId does not match", async () => { it("should inform user if credential exists but rpId does not match", async () => {
const cipher = await createCipherView({ type: CipherType.Login }); const cipher = await createCipherView({ type: CipherType.Login });
cipher.login.fido2Key.nonDiscoverableId = credentialId; cipher.login.fido2Key.credentialId = credentialId;
cipher.login.fido2Key.rpId = "mismatch-rpid"; cipher.login.fido2Key.rpId = "mismatch-rpid";
cipherService.getAllDecrypted.mockResolvedValue([cipher]); cipherService.getAllDecrypted.mockResolvedValue([cipher]);
userInterfaceSession.informCredentialNotFound.mockResolvedValue(); userInterfaceSession.informCredentialNotFound.mockResolvedValue();
@@ -701,11 +698,11 @@ describe("FidoAuthenticatorService", () => {
ciphers = [ ciphers = [
await createCipherView( await createCipherView(
{ type: CipherType.Login }, { type: CipherType.Login },
{ nonDiscoverableId: credentialIds[0], rpId: RpId } { credentialId: credentialIds[0], rpId: RpId }
), ),
await createCipherView( await createCipherView(
{ type: CipherType.Fido2Key, id: credentialIds[1] }, { type: CipherType.Fido2Key },
{ rpId: RpId } { credentialId: credentialIds[1], rpId: RpId }
), ),
]; ];
params = await createParams({ params = await createParams({
@@ -770,11 +767,11 @@ describe("FidoAuthenticatorService", () => {
ciphers = credentialIds.map((id) => ciphers = credentialIds.map((id) =>
createCipherView( createCipherView(
{ type: CipherType.Fido2Key }, { type: CipherType.Fido2Key },
{ rpId: RpId, counter: 9000, keyValue } { credentialId: id, rpId: RpId, counter: 9000, keyValue }
) )
); );
fido2Keys = ciphers.map((c) => c.fido2Key); fido2Keys = ciphers.map((c) => c.fido2Key);
selectedCredentialId = ciphers[0].id; selectedCredentialId = credentialIds[0];
params = await createParams({ params = await createParams({
allowCredentialDescriptorList: undefined, allowCredentialDescriptorList: undefined,
rpId: RpId, rpId: RpId,
@@ -783,7 +780,7 @@ describe("FidoAuthenticatorService", () => {
ciphers = credentialIds.map((id) => ciphers = credentialIds.map((id) =>
createCipherView( createCipherView(
{ type: CipherType.Login }, { type: CipherType.Login },
{ nonDiscoverableId: id, rpId: RpId, counter: 9000 } { credentialId: id, rpId: RpId, counter: 9000 }
) )
); );
fido2Keys = ciphers.map((c) => c.login.fido2Key); fido2Keys = ciphers.map((c) => c.login.fido2Key);
@@ -938,7 +935,7 @@ function createCipherView(
cipher.localData = {}; cipher.localData = {};
const fido2KeyView = new Fido2KeyView(); const fido2KeyView = new Fido2KeyView();
fido2KeyView.nonDiscoverableId = fido2Key.nonDiscoverableId; fido2KeyView.credentialId = fido2Key.credentialId ?? Utils.newGuid();
fido2KeyView.rpId = fido2Key.rpId ?? RpId; fido2KeyView.rpId = fido2Key.rpId ?? RpId;
fido2KeyView.counter = fido2Key.counter ?? 0; fido2KeyView.counter = fido2Key.counter ?? 0;
fido2KeyView.userHandle = fido2Key.userHandle ?? Fido2Utils.bufferToString(randomBytes(16)); fido2KeyView.userHandle = fido2Key.userHandle ?? Fido2Utils.bufferToString(randomBytes(16));

View File

@@ -96,6 +96,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
let fido2Key: Fido2KeyView; let fido2Key: Fido2KeyView;
let keyPair: CryptoKeyPair; let keyPair: CryptoKeyPair;
let userVerified = false; let userVerified = false;
let credentialId: string;
if (params.requireResidentKey) { if (params.requireResidentKey) {
const response = await userInterfaceSession.confirmNewCredential( const response = await userInterfaceSession.confirmNewCredential(
{ {
@@ -132,6 +133,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
const encrypted = await this.cipherService.encrypt(cipher); const encrypted = await this.cipherService.encrypt(cipher);
await this.cipherService.createWithServer(encrypted); // encrypted.id is assigned inside here await this.cipherService.createWithServer(encrypted); // encrypted.id is assigned inside here
cipher.id = encrypted.id; cipher.id = encrypted.id;
credentialId = cipher.fido2Key.credentialId;
} catch (error) { } catch (error) {
this.logService?.error( this.logService?.error(
`[Fido2Authenticator] Aborting because of unknown error when creating discoverable credential: ${error}` `[Fido2Authenticator] Aborting because of unknown error when creating discoverable credential: ${error}`
@@ -172,6 +174,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
cipher.login.fido2Key = fido2Key = await createKeyView(params, keyPair.privateKey); cipher.login.fido2Key = fido2Key = await createKeyView(params, keyPair.privateKey);
const reencrypted = await this.cipherService.encrypt(cipher); const reencrypted = await this.cipherService.encrypt(cipher);
await this.cipherService.updateWithServer(reencrypted); await this.cipherService.updateWithServer(reencrypted);
credentialId = cipher.login.fido2Key.credentialId;
} catch (error) { } catch (error) {
this.logService?.error( this.logService?.error(
`[Fido2Authenticator] Aborting because of unknown error when creating non-discoverable credential: ${error}` `[Fido2Authenticator] Aborting because of unknown error when creating non-discoverable credential: ${error}`
@@ -180,9 +183,6 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
} }
} }
const credentialId =
cipher.type === CipherType.Fido2Key ? cipher.id : cipher.login.fido2Key.nonDiscoverableId;
const authData = await generateAuthData({ const authData = await generateAuthData({
rpId: params.rpEntity.id, rpId: params.rpEntity.id,
credentialId: guidToRawFormat(credentialId), credentialId: guidToRawFormat(credentialId),
@@ -279,10 +279,7 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
selectedCipher.type === CipherType.Login selectedCipher.type === CipherType.Login
? selectedCipher.login.fido2Key ? selectedCipher.login.fido2Key
: selectedCipher.fido2Key; : selectedCipher.fido2Key;
const selectedCredentialId = const selectedCredentialId = selectedFido2Key.credentialId;
selectedCipher.type === CipherType.Login
? selectedFido2Key.nonDiscoverableId
: selectedCipher.id;
++selectedFido2Key.counter; ++selectedFido2Key.counter;
@@ -349,10 +346,10 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
(cipher) => (cipher) =>
!cipher.isDeleted && !cipher.isDeleted &&
cipher.organizationId == undefined && cipher.organizationId == undefined &&
((cipher.type === CipherType.Fido2Key && ids.includes(cipher.id)) || ((cipher.type === CipherType.Fido2Key && ids.includes(cipher.fido2Key.credentialId)) ||
(cipher.type === CipherType.Login && (cipher.type === CipherType.Login &&
cipher.login.fido2Key != undefined && cipher.login.fido2Key != undefined &&
ids.includes(cipher.login.fido2Key.nonDiscoverableId))) ids.includes(cipher.login.fido2Key.credentialId)))
) )
.map((cipher) => cipher.id); .map((cipher) => cipher.id);
} }
@@ -381,10 +378,10 @@ export class Fido2AuthenticatorService implements Fido2AuthenticatorServiceAbstr
cipher.type === CipherType.Login && cipher.type === CipherType.Login &&
cipher.login.fido2Key != undefined && cipher.login.fido2Key != undefined &&
cipher.login.fido2Key.rpId === rpId && cipher.login.fido2Key.rpId === rpId &&
ids.includes(cipher.login.fido2Key.nonDiscoverableId)) || ids.includes(cipher.login.fido2Key.credentialId)) ||
(cipher.type === CipherType.Fido2Key && (cipher.type === CipherType.Fido2Key &&
cipher.fido2Key.rpId === rpId && cipher.fido2Key.rpId === rpId &&
ids.includes(cipher.id)) ids.includes(cipher.fido2Key.credentialId))
); );
} }
@@ -418,7 +415,7 @@ async function createKeyView(
const pkcs8Key = await crypto.subtle.exportKey("pkcs8", keyValue); const pkcs8Key = await crypto.subtle.exportKey("pkcs8", keyValue);
const fido2Key = new Fido2KeyView(); const fido2Key = new Fido2KeyView();
fido2Key.nonDiscoverableId = params.requireResidentKey ? null : Utils.newGuid(); fido2Key.credentialId = Utils.newGuid();
fido2Key.keyType = "public-key"; fido2Key.keyType = "public-key";
fido2Key.keyAlgorithm = "ECDSA"; fido2Key.keyAlgorithm = "ECDSA";
fido2Key.keyCurve = "P-256"; fido2Key.keyCurve = "P-256";