mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
Feature/[PM-1378] - Trusted Device Encryption - Establish trust logic for all clients (#5339)
* PM1378 - (1) Create state service methods for securely storing a device symmetric key while following existing pattern of DuckDuckGoKey generation (2) Create makeDeviceKey method on crypto service which leverages the new state service methods for storing the device key. * PM-1378 - Document CSPRNG types w/ comments explaining what they are and when they should be used. * PM-1378 - TODO to add tests for makeDeviceKey method * PM-1378 - Create Devices API service for creating and updating device encrypted master keys + move models according to latest code standards ( I think) * PM-1378 - TODO clean up - DeviceResponse properly moved next to device api service abstraction per ADR 0013 * PM-1378 - CryptoService makeDeviceKey test written * PM-1378 - Tweak crypto service makeDeviceKey test to leverage a describe for the function to better group related code. * PM-1378 - Move known devices call out of API service and into new devices-api.service and update all references. All clients building. * PM-1378 - Comment clean up * PM-1378 - Refactor out master key naming as that is a reserved specific key generated from the MP key derivation process + use same property on request object as back end. * PM-1378 - Missed a use of master key * PM-1378 - More abstraction updates to remove master key. * PM-1378 - Convert crypto service makeDeviceKey into getDeviceKey method to consolidate service logic based on PR feedback * PM-1378- Updating makeDeviceKey --> getDeviceKey tests to match updated code * PM-1378 - Current work on updating establish trusted device logic in light of new encryption mechanisms (introduction of a device asymmetric key pair in order to allow for key rotation while maintaining trusted devices) * PM-1378 - (1) CryptoService.TrustDevice() naming refactors (2) Lots of test additions and tweaks for trustDevice() * PM-1378 - Updated TrustedDeviceKeysRequest names to be consistent across the client side board. * PM-1378 - Move trusted device crypto service methods out of crypto service into new DeviceCryptoService for better single responsibility design * PM-1378 - (1) Add getDeviceByIdentifier endpoint to devices api as will need it later (2) Update TrustedDeviceKeysRequest and DeviceResponse models to match latest server side generic encrypted key names * PM-1378 - PR feedback fix - use JSDOC comments and move from abstraction to implementation * PM-1378 - Per PR feedback, makeDeviceKey should be private - updated tests with workaround. * PM-1378- Per PR feedback, refactored deviceKey to use partialKey dict so we can associate userId with specific device keys. * PM-1378 - Replace deviceId with deviceIdentifier per PR feedback * PM-1378 - Remove unnecessary createTrustedDeviceKey methods * PM-1378 - Update device crypto service to leverage updateTrustedDeviceKeys + update tests * PM-1378 - Update trustDevice logic - (1) Use getEncKey to get user symmetric key as it's the correct method and (2) Attempt to retrieve the userSymKey earlier on and short circuit if it is not found. * PM-1378 - Replace deviceId with deviceIdentifier because they are not the same thing * PM-1378 - Per PR feedback, (1) on web/browser extension, store device key in local storage under account.keys existing structure (2) on desktop, store deviceKey in secure storage. (3) Exempt account.keys.deviceKey from being cleared on account reset * PM-1378 - Desktop testing revealed that I forgot to add userId existence and options reconciliation checks back * PM-1378 - Per discussion with Jake, create DeviceKey custom type which is really just an opaque<SymmetricCryptoKey> so we can more easily differentiate between key types. * PM-1378 - Update symmetric-crypto-key.ts opaque DeviceKey to properly setup Opaque type. * PM-1378 - Fix wrong return type for getDeviceKey on DeviceCryptoServiceAbstraction per PR feedback
This commit is contained in:
@@ -3,9 +3,9 @@ import { FormBuilder } from "@angular/forms";
|
||||
import { ActivatedRoute, Router } from "@angular/router";
|
||||
|
||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AppIdService } from "@bitwarden/common/abstractions/appId.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/abstractions/devices/devices-api.service.abstraction";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
@@ -27,7 +27,7 @@ import { flagEnabled } from "../../flags";
|
||||
export class LoginComponent extends BaseLoginComponent {
|
||||
showPasswordless = false;
|
||||
constructor(
|
||||
apiService: ApiService,
|
||||
devicesApiService: DevicesApiServiceAbstraction,
|
||||
appIdService: AppIdService,
|
||||
authService: AuthService,
|
||||
router: Router,
|
||||
@@ -46,7 +46,7 @@ export class LoginComponent extends BaseLoginComponent {
|
||||
loginService: LoginService
|
||||
) {
|
||||
super(
|
||||
apiService,
|
||||
devicesApiService,
|
||||
appIdService,
|
||||
authService,
|
||||
router,
|
||||
|
||||
@@ -6,10 +6,10 @@ import { Subject, takeUntil } from "rxjs";
|
||||
import { EnvironmentSelectorComponent } from "@bitwarden/angular/auth/components/environment-selector.component";
|
||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
||||
import { ModalService } from "@bitwarden/angular/services/modal.service";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AppIdService } from "@bitwarden/common/abstractions/appId.service";
|
||||
import { BroadcasterService } from "@bitwarden/common/abstractions/broadcaster.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/abstractions/devices/devices-api.service.abstraction";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
@@ -52,7 +52,7 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
|
||||
}
|
||||
|
||||
constructor(
|
||||
apiService: ApiService,
|
||||
devicesApiService: DevicesApiServiceAbstraction,
|
||||
appIdService: AppIdService,
|
||||
authService: AuthService,
|
||||
router: Router,
|
||||
@@ -74,7 +74,7 @@ export class LoginComponent extends BaseLoginComponent implements OnDestroy {
|
||||
loginService: LoginService
|
||||
) {
|
||||
super(
|
||||
apiService,
|
||||
devicesApiService,
|
||||
appIdService,
|
||||
authService,
|
||||
router,
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/models/domain/enc-string";
|
||||
import { GlobalState } from "@bitwarden/common/models/domain/global-state";
|
||||
import { StorageOptions } from "@bitwarden/common/models/domain/storage-options";
|
||||
import {
|
||||
DeviceKey,
|
||||
SymmetricCryptoKey,
|
||||
} from "@bitwarden/common/models/domain/symmetric-crypto-key";
|
||||
import { StateService as BaseStateService } from "@bitwarden/common/services/state.service";
|
||||
|
||||
import { Account } from "../models/account";
|
||||
@@ -11,6 +16,10 @@ export class ElectronStateService
|
||||
extends BaseStateService<GlobalState, Account>
|
||||
implements ElectronStateServiceAbstraction
|
||||
{
|
||||
private partialKeys = {
|
||||
deviceKey: "_deviceKey",
|
||||
};
|
||||
|
||||
async addAccount(account: Account) {
|
||||
// Apply desktop overides to default account values
|
||||
account = new Account(account);
|
||||
@@ -77,4 +86,27 @@ export class ElectronStateService
|
||||
this.reconcileOptions(options, await this.defaultOnDiskOptions())
|
||||
);
|
||||
}
|
||||
|
||||
override async getDeviceKey(options?: StorageOptions): Promise<DeviceKey | null> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const b64DeviceKey = await this.secureStorageService.get<string>(
|
||||
`${options.userId}${this.partialKeys.deviceKey}`,
|
||||
options
|
||||
);
|
||||
|
||||
return new SymmetricCryptoKey(Utils.fromB64ToArray(b64DeviceKey).buffer) as DeviceKey;
|
||||
}
|
||||
|
||||
override async setDeviceKey(value: DeviceKey, options?: StorageOptions): Promise<void> {
|
||||
options = this.reconcileOptions(options, await this.defaultSecureStorageOptions());
|
||||
if (options?.userId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.saveSecureStorageKey(this.partialKeys.deviceKey, value.keyB64, options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,9 @@ import { Subject, takeUntil } from "rxjs";
|
||||
import { first } from "rxjs/operators";
|
||||
|
||||
import { LoginComponent as BaseLoginComponent } from "@bitwarden/angular/auth/components/login.component";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AppIdService } from "@bitwarden/common/abstractions/appId.service";
|
||||
import { CryptoFunctionService } from "@bitwarden/common/abstractions/cryptoFunction.service";
|
||||
import { DevicesApiServiceAbstraction } from "@bitwarden/common/abstractions/devices/devices-api.service.abstraction";
|
||||
import { EnvironmentService } from "@bitwarden/common/abstractions/environment.service";
|
||||
import { FormValidationErrorsService } from "@bitwarden/common/abstractions/formValidationErrors.service";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
@@ -41,7 +41,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
constructor(
|
||||
apiService: ApiService,
|
||||
devicesApiService: DevicesApiServiceAbstraction,
|
||||
appIdService: AppIdService,
|
||||
authService: AuthService,
|
||||
router: Router,
|
||||
@@ -63,7 +63,7 @@ export class LoginComponent extends BaseLoginComponent implements OnInit, OnDest
|
||||
loginService: LoginService
|
||||
) {
|
||||
super(
|
||||
apiService,
|
||||
devicesApiService,
|
||||
appIdService,
|
||||
authService,
|
||||
router,
|
||||
|
||||
Reference in New Issue
Block a user