1
0
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:
Jared Snider
2023-05-25 14:17:19 -04:00
committed by GitHub
parent b9d3b0aff7
commit 0fcfe883b5
20 changed files with 613 additions and 27 deletions

View File

@@ -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,

View File

@@ -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,

View File

@@ -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);
}
}

View File

@@ -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,