diff --git a/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.ts b/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.ts index a9eba08be8c..dc2f4596521 100644 --- a/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.ts +++ b/apps/web/src/app/auth/core/services/registration/web-registration-finish.service.ts @@ -18,7 +18,9 @@ import { EncryptedString, EncString, } from "@bitwarden/common/key-management/crypto/models/enc-string"; +import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; +import { UserKey } from "@bitwarden/common/types/key"; import { KeyService } from "@bitwarden/key-management"; export class WebRegistrationFinishService @@ -28,12 +30,13 @@ export class WebRegistrationFinishService constructor( protected keyService: KeyService, protected accountApiService: AccountApiService, + protected masterPasswordService: MasterPasswordServiceAbstraction, private organizationInviteService: OrganizationInviteService, private policyApiService: PolicyApiServiceAbstraction, private logService: LogService, private policyService: PolicyService, ) { - super(keyService, accountApiService); + super(keyService, accountApiService, masterPasswordService); } override async getOrgNameFromOrgInvite(): Promise { @@ -78,6 +81,7 @@ export class WebRegistrationFinishService // Note: the org invite token and email verification are mutually exclusive. Only one will be present. override async buildRegisterRequest( + newUserKey: UserKey, email: string, passwordInputResult: PasswordInputResult, encryptedUserKey: EncryptedString, @@ -90,6 +94,7 @@ export class WebRegistrationFinishService providerUserId?: string, ): Promise { const registerRequest = await super.buildRegisterRequest( + newUserKey, email, passwordInputResult, encryptedUserKey, diff --git a/apps/web/src/app/core/core.module.ts b/apps/web/src/app/core/core.module.ts index 661d14502fe..2f672ce614c 100644 --- a/apps/web/src/app/core/core.module.ts +++ b/apps/web/src/app/core/core.module.ts @@ -73,7 +73,10 @@ import { ProcessReloadServiceAbstraction } from "@bitwarden/common/key-managemen import { AccountCryptographicStateService } from "@bitwarden/common/key-management/account-cryptography/account-cryptographic-state.service"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { EncryptService } from "@bitwarden/common/key-management/crypto/abstractions/encrypt.service"; -import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { + InternalMasterPasswordServiceAbstraction, + MasterPasswordServiceAbstraction, +} from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { SessionTimeoutTypeService } from "@bitwarden/common/key-management/session-timeout"; import { VaultTimeout, @@ -286,6 +289,7 @@ const safeProviders: SafeProvider[] = [ deps: [ KeyServiceAbstraction, AccountApiServiceAbstraction, + MasterPasswordServiceAbstraction, OrganizationInviteService, PolicyApiServiceAbstraction, LogService, diff --git a/libs/angular/src/services/jslib-services.module.ts b/libs/angular/src/services/jslib-services.module.ts index 5eaac4033eb..442c5ceca92 100644 --- a/libs/angular/src/services/jslib-services.module.ts +++ b/libs/angular/src/services/jslib-services.module.ts @@ -1598,7 +1598,7 @@ const safeProviders: SafeProvider[] = [ safeProvider({ provide: RegistrationFinishServiceAbstraction, useClass: DefaultRegistrationFinishService, - deps: [KeyService, AccountApiServiceAbstraction], + deps: [KeyService, AccountApiServiceAbstraction, MasterPasswordServiceAbstraction], }), safeProvider({ provide: TwoFactorAuthComponentService, diff --git a/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.spec.ts b/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.spec.ts index 608e0ac64b9..376ea669aad 100644 --- a/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.spec.ts +++ b/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.spec.ts @@ -2,6 +2,11 @@ import { MockProxy, mock } from "jest-mock-extended"; import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service"; import { EncString } from "@bitwarden/common/key-management/crypto/models/enc-string"; +import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; +import { + MasterPasswordUnlockData, + MasterPasswordSalt, +} from "@bitwarden/common/key-management/master-password/types/master-password.types"; import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key"; import { CsprngArray } from "@bitwarden/common/types/csprng"; import { MasterKey, UserKey } from "@bitwarden/common/types/key"; @@ -16,12 +21,18 @@ describe("DefaultRegistrationFinishService", () => { let keyService: MockProxy; let accountApiService: MockProxy; + let masterPasswordService: MockProxy; beforeEach(() => { keyService = mock(); accountApiService = mock(); + masterPasswordService = mock(); - service = new DefaultRegistrationFinishService(keyService, accountApiService); + service = new DefaultRegistrationFinishService( + keyService, + accountApiService, + masterPasswordService, + ); }); it("instantiates", () => { @@ -74,6 +85,7 @@ describe("DefaultRegistrationFinishService", () => { it("throws an error if the user key cannot be created", async () => { keyService.makeUserKey.mockResolvedValue([null, null]); + masterPasswordService.emailToSalt.mockReturnValue("salt" as unknown as MasterPasswordSalt); await expect(service.finishRegistration(email, passwordInputResult)).rejects.toThrow( "User key could not be created", @@ -84,6 +96,19 @@ describe("DefaultRegistrationFinishService", () => { keyService.makeUserKey.mockResolvedValue([userKey, userKeyEncString]); keyService.makeKeyPair.mockResolvedValue(userKeyPair); accountApiService.registerFinish.mockResolvedValue(); + masterPasswordService.emailToSalt.mockReturnValue("salt" as unknown as MasterPasswordSalt); + masterPasswordService.makeMasterPasswordAuthenticationData.mockResolvedValue({ + salt: "salt" as unknown as MasterPasswordSalt, + kdf: DEFAULT_KDF_CONFIG, + masterPasswordAuthenticationHash: "authHash" as unknown as string, + }); + masterPasswordService.makeMasterPasswordUnlockData.mockResolvedValue( + new MasterPasswordUnlockData( + "salt" as unknown as MasterPasswordSalt, + DEFAULT_KDF_CONFIG, + new EncString("wrapped") as unknown as any, + ), + ); await service.finishRegistration(email, passwordInputResult, emailVerificationToken); diff --git a/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.ts b/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.ts index 2bef5670ac3..132048f838d 100644 --- a/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.ts +++ b/libs/auth/src/angular/registration/registration-finish/default-registration-finish.service.ts @@ -7,7 +7,9 @@ import { EncryptedString, EncString, } from "@bitwarden/common/key-management/crypto/models/enc-string"; +import { MasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { KeysRequest } from "@bitwarden/common/models/request/keys.request"; +import { UserKey } from "@bitwarden/common/types/key"; import { KeyService } from "@bitwarden/key-management"; import { PasswordInputResult } from "../../input-password/password-input-result"; @@ -18,6 +20,7 @@ export class DefaultRegistrationFinishService implements RegistrationFinishServi constructor( protected keyService: KeyService, protected accountApiService: AccountApiService, + protected masterPasswordService: MasterPasswordServiceAbstraction, ) {} getOrgNameFromOrgInvite(): Promise { @@ -48,6 +51,7 @@ export class DefaultRegistrationFinishService implements RegistrationFinishServi const userAsymmetricKeys = await this.keyService.makeKeyPair(newUserKey); const registerRequest = await this.buildRegisterRequest( + newUserKey, email, passwordInputResult, newEncUserKey.encryptedString, @@ -64,6 +68,7 @@ export class DefaultRegistrationFinishService implements RegistrationFinishServi } protected async buildRegisterRequest( + newUserKey: UserKey, email: string, passwordInputResult: PasswordInputResult, encryptedUserKey: EncryptedString, @@ -80,14 +85,32 @@ export class DefaultRegistrationFinishService implements RegistrationFinishServi userAsymmetricKeys[1].encryptedString, ); + // Get salt value, for now we derive it from the email but this could change to be random bytes + // in the future once the email and salt are separated. + const salt = this.masterPasswordService.emailToSalt(email); + + const masterPasswordAuthentication = + await this.masterPasswordService.makeMasterPasswordAuthenticationData( + passwordInputResult.newPassword, + passwordInputResult.kdfConfig, + salt, + ); + + const masterPasswordUnlock = await this.masterPasswordService.makeMasterPasswordUnlockData( + passwordInputResult.newPassword, + passwordInputResult.kdfConfig, + salt, + newUserKey, + ); + const registerFinishRequest = new RegisterFinishRequest( email, passwordInputResult.newServerMasterKeyHash, passwordInputResult.newPasswordHint, encryptedUserKey, userAsymmetricKeysRequest, - passwordInputResult.kdfConfig.kdfType, - passwordInputResult.kdfConfig.iterations, + masterPasswordAuthentication, + masterPasswordUnlock, ); if (emailVerificationToken) { diff --git a/libs/common/src/auth/models/request/registration/register-finish.request.ts b/libs/common/src/auth/models/request/registration/register-finish.request.ts index b388e8aee49..c76008b8108 100644 --- a/libs/common/src/auth/models/request/registration/register-finish.request.ts +++ b/libs/common/src/auth/models/request/registration/register-finish.request.ts @@ -1,8 +1,8 @@ -// This import has been flagged as unallowed for this class. It may be involved in a circular dependency loop. -// eslint-disable-next-line no-restricted-imports -import { KdfType } from "@bitwarden/key-management"; - import { EncryptedString } from "../../../../key-management/crypto/models/enc-string"; +import { + MasterPasswordAuthenticationData, + MasterPasswordUnlockData, +} from "../../../../key-management/master-password/types/master-password.types"; import { KeysRequest } from "../../../../models/request/keys.request"; export class RegisterFinishRequest { @@ -15,10 +15,8 @@ export class RegisterFinishRequest { public userSymmetricKey: EncryptedString, public userAsymmetricKeys: KeysRequest, - public kdf: KdfType, - public kdfIterations: number, - public kdfMemory?: number, - public kdfParallelism?: number, + public masterPasswordAuthentication: MasterPasswordAuthenticationData, + public masterPasswordUnlock: MasterPasswordUnlockData, public emailVerificationToken?: string, public orgSponsoredFreeFamilyPlanToken?: string,