Skip to content

Commit 3001f8f

Browse files
authored
[PM-5693] Migrate SDK to KeyStore (#8)
## 🎟️ Tracking https://bitwarden.atlassian.net/browse/PM-5693 ## 📔 Objective Migrated from bitwarden/sdk-sm#1117 Migrate the codebase to the new KeyStore introduced in #7. EncryptionSettings was removed from Client, though it is still used to initialize the KeyStore. Ideally we'd move that initialization code over directly into the crypto crate but this PR is big enough as it is. There are still some things using keys directly and KeyEncryptable/KeyDecryptable, like MasterKey, PinKey, DeviceKey, private key fingerprint. Those would need to be migrated over on a separate PR. We need to remove the rest of the uses of SymmetricCryptoKey from the client crates, then we can remove the internal boxing they are doing, as the keys would be protected by the KeyStore instead. Secrets Manager code should be moved to using the Encryptable/Decryptable interface, as it's encrypting fields one by one, I'll look into doing that on a separate PR. ## ⏰ Reminders before review - Contributor guidelines followed - All formatters and local linters executed and passed - Written new unit and / or integration tests where applicable - Protected functional changes with optionality (feature flags) - Used internationalization (i18n) for all UI strings - CI builds passed - Communicated to DevOps any deployment requirements - Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team ## 🦮 Reviewer guidelines <!-- Suggested interactions but feel free to use (or not) as you desire! --> - 👍 (`:+1:`) or similar for great changes - 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info - ❓ (`:question:`) for questions - 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion - 🎨 (`:art:`) for suggestions / improvements - ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or concerns needing attention - 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or indications of technical debt - ⛏ (`:pick:`) for minor or nitpick changes
1 parent c89ea8e commit 3001f8f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+1391
-1158
lines changed

bitwarden_license/bitwarden-sm/src/projects/create.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bitwarden_api_api::models::ProjectCreateRequestModel;
2-
use bitwarden_core::Client;
3-
use bitwarden_crypto::KeyEncryptable;
2+
use bitwarden_core::{key_management::SymmetricKeyId, Client};
3+
use bitwarden_crypto::Encryptable;
44
use schemars::JsonSchema;
55
use serde::{Deserialize, Serialize};
66
use uuid::Uuid;
@@ -26,11 +26,16 @@ pub(crate) async fn create_project(
2626
) -> Result<ProjectResponse, SecretsManagerError> {
2727
input.validate()?;
2828

29-
let enc = client.internal.get_encryption_settings()?;
30-
let key = enc.get_key(&Some(input.organization_id))?;
29+
let key_store = client.internal.get_key_store();
30+
let key = SymmetricKeyId::Organization(input.organization_id);
3131

3232
let project = Some(ProjectCreateRequestModel {
33-
name: input.name.clone().trim().encrypt_with_key(key)?.to_string(),
33+
name: input
34+
.name
35+
.clone()
36+
.trim()
37+
.encrypt(&mut key_store.context(), key)?
38+
.to_string(),
3439
});
3540

3641
let config = client.internal.get_api_configurations().await;
@@ -41,7 +46,7 @@ pub(crate) async fn create_project(
4146
)
4247
.await?;
4348

44-
ProjectResponse::process_response(res, &enc)
49+
ProjectResponse::process_response(res, &mut key_store.context())
4550
}
4651

4752
#[cfg(test)]

bitwarden_license/bitwarden-sm/src/projects/get.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(crate) async fn get_project(
2020

2121
let res = bitwarden_api_api::apis::projects_api::projects_id_get(&config.api, input.id).await?;
2222

23-
let enc = client.internal.get_encryption_settings()?;
23+
let key_store = client.internal.get_key_store();
2424

25-
ProjectResponse::process_response(res, &enc)
25+
ProjectResponse::process_response(res, &mut key_store.context())
2626
}

bitwarden_license/bitwarden-sm/src/projects/list.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use bitwarden_api_api::models::ProjectResponseModelListResponseModel;
2-
use bitwarden_core::client::{encryption_settings::EncryptionSettings, Client};
2+
use bitwarden_core::{client::Client, key_management::KeyIds};
3+
use bitwarden_crypto::KeyStoreContext;
34
use schemars::JsonSchema;
45
use serde::{Deserialize, Serialize};
56
use uuid::Uuid;
@@ -24,9 +25,9 @@ pub(crate) async fn list_projects(
2425
)
2526
.await?;
2627

27-
let enc = client.internal.get_encryption_settings()?;
28+
let key_store = client.internal.get_key_store();
2829

29-
ProjectsResponse::process_response(res, &enc)
30+
ProjectsResponse::process_response(res, &mut key_store.context())
3031
}
3132

3233
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
@@ -38,14 +39,14 @@ pub struct ProjectsResponse {
3839
impl ProjectsResponse {
3940
pub(crate) fn process_response(
4041
response: ProjectResponseModelListResponseModel,
41-
enc: &EncryptionSettings,
42+
ctx: &mut KeyStoreContext<KeyIds>,
4243
) -> Result<Self, SecretsManagerError> {
4344
let data = response.data.unwrap_or_default();
4445

4546
Ok(ProjectsResponse {
4647
data: data
4748
.into_iter()
48-
.map(|r| ProjectResponse::process_response(r, enc))
49+
.map(|r| ProjectResponse::process_response(r, ctx))
4950
.collect::<Result<_, _>>()?,
5051
})
5152
}

bitwarden_license/bitwarden-sm/src/projects/project_response.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use bitwarden_api_api::models::ProjectResponseModel;
2-
use bitwarden_core::{client::encryption_settings::EncryptionSettings, require};
3-
use bitwarden_crypto::{EncString, KeyDecryptable};
2+
use bitwarden_core::{
3+
key_management::{KeyIds, SymmetricKeyId},
4+
require,
5+
};
6+
use bitwarden_crypto::{Decryptable, EncString, KeyStoreContext};
47
use chrono::{DateTime, Utc};
58
use schemars::JsonSchema;
69
use serde::{Deserialize, Serialize};
@@ -21,14 +24,14 @@ pub struct ProjectResponse {
2124
impl ProjectResponse {
2225
pub(crate) fn process_response(
2326
response: ProjectResponseModel,
24-
enc: &EncryptionSettings,
27+
ctx: &mut KeyStoreContext<KeyIds>,
2528
) -> Result<Self, SecretsManagerError> {
2629
let organization_id = require!(response.organization_id);
27-
let enc_key = enc.get_key(&Some(organization_id))?;
30+
let key = SymmetricKeyId::Organization(organization_id);
2831

2932
let name = require!(response.name)
3033
.parse::<EncString>()?
31-
.decrypt_with_key(enc_key)?;
34+
.decrypt(ctx, key)?;
3235

3336
Ok(ProjectResponse {
3437
id: require!(response.id),

bitwarden_license/bitwarden-sm/src/projects/update.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bitwarden_api_api::models::ProjectUpdateRequestModel;
2-
use bitwarden_core::Client;
3-
use bitwarden_crypto::KeyEncryptable;
2+
use bitwarden_core::{key_management::SymmetricKeyId, Client};
3+
use bitwarden_crypto::Encryptable;
44
use schemars::JsonSchema;
55
use serde::{Deserialize, Serialize};
66
use uuid::Uuid;
@@ -28,19 +28,24 @@ pub(crate) async fn update_project(
2828
) -> Result<ProjectResponse, SecretsManagerError> {
2929
input.validate()?;
3030

31-
let enc = client.internal.get_encryption_settings()?;
32-
let key = enc.get_key(&Some(input.organization_id))?;
31+
let key_store = client.internal.get_key_store();
32+
let key = SymmetricKeyId::Organization(input.organization_id);
3333

3434
let project = Some(ProjectUpdateRequestModel {
35-
name: input.name.clone().trim().encrypt_with_key(key)?.to_string(),
35+
name: input
36+
.name
37+
.clone()
38+
.trim()
39+
.encrypt(&mut key_store.context(), key)?
40+
.to_string(),
3641
});
3742

3843
let config = client.internal.get_api_configurations().await;
3944
let res =
4045
bitwarden_api_api::apis::projects_api::projects_id_put(&config.api, input.id, project)
4146
.await?;
4247

43-
ProjectResponse::process_response(res, &enc)
48+
ProjectResponse::process_response(res, &mut key_store.context())
4449
}
4550

4651
#[cfg(test)]

bitwarden_license/bitwarden-sm/src/secrets/create.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bitwarden_api_api::models::SecretCreateRequestModel;
2-
use bitwarden_core::Client;
3-
use bitwarden_crypto::KeyEncryptable;
2+
use bitwarden_core::{key_management::SymmetricKeyId, Client};
3+
use bitwarden_crypto::Encryptable;
44
use schemars::JsonSchema;
55
use serde::{Deserialize, Serialize};
66
use uuid::Uuid;
@@ -34,16 +34,24 @@ pub(crate) async fn create_secret(
3434
) -> Result<SecretResponse, SecretsManagerError> {
3535
input.validate()?;
3636

37-
let enc = client.internal.get_encryption_settings()?;
38-
let key = enc.get_key(&Some(input.organization_id))?;
39-
40-
let secret = Some(SecretCreateRequestModel {
41-
key: input.key.clone().trim().encrypt_with_key(key)?.to_string(),
42-
value: input.value.clone().encrypt_with_key(key)?.to_string(),
43-
note: input.note.clone().trim().encrypt_with_key(key)?.to_string(),
44-
project_ids: input.project_ids.clone(),
45-
access_policies_requests: None,
46-
});
37+
let key_store = client.internal.get_key_store();
38+
let key = SymmetricKeyId::Organization(input.organization_id);
39+
40+
let secret = {
41+
let mut ctx = key_store.context();
42+
Some(SecretCreateRequestModel {
43+
key: input.key.clone().trim().encrypt(&mut ctx, key)?.to_string(),
44+
value: input.value.clone().encrypt(&mut ctx, key)?.to_string(),
45+
note: input
46+
.note
47+
.clone()
48+
.trim()
49+
.encrypt(&mut ctx, key)?
50+
.to_string(),
51+
project_ids: input.project_ids.clone(),
52+
access_policies_requests: None,
53+
})
54+
};
4755

4856
let config = client.internal.get_api_configurations().await;
4957
let res = bitwarden_api_api::apis::secrets_api::organizations_organization_id_secrets_post(
@@ -53,7 +61,7 @@ pub(crate) async fn create_secret(
5361
)
5462
.await?;
5563

56-
SecretResponse::process_response(res, &enc)
64+
SecretResponse::process_response(res, &mut key_store.context())
5765
}
5866

5967
#[cfg(test)]

bitwarden_license/bitwarden-sm/src/secrets/get.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub(crate) async fn get_secret(
1919
let config = client.internal.get_api_configurations().await;
2020
let res = bitwarden_api_api::apis::secrets_api::secrets_id_get(&config.api, input.id).await?;
2121

22-
let enc = client.internal.get_encryption_settings()?;
22+
let key_store = client.internal.get_key_store();
2323

24-
SecretResponse::process_response(res, &enc)
24+
SecretResponse::process_response(res, &mut key_store.context())
2525
}

bitwarden_license/bitwarden-sm/src/secrets/get_by_ids.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub(crate) async fn get_secrets_by_ids(
2424
let res =
2525
bitwarden_api_api::apis::secrets_api::secrets_get_by_ids_post(&config.api, request).await?;
2626

27-
let enc = client.internal.get_encryption_settings()?;
27+
let key_store = client.internal.get_key_store();
2828

29-
SecretsResponse::process_response(res, &enc)
29+
SecretsResponse::process_response(res, &mut key_store.context())
3030
}

bitwarden_license/bitwarden-sm/src/secrets/list.rs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use bitwarden_api_api::models::{
22
SecretWithProjectsListResponseModel, SecretsWithProjectsInnerSecret,
33
};
44
use bitwarden_core::{
5-
client::{encryption_settings::EncryptionSettings, Client},
5+
client::Client,
6+
key_management::{KeyIds, SymmetricKeyId},
67
require,
78
};
8-
use bitwarden_crypto::{EncString, KeyDecryptable};
9+
use bitwarden_crypto::{Decryptable, EncString, KeyStoreContext};
910
use schemars::JsonSchema;
1011
use serde::{Deserialize, Serialize};
1112
use uuid::Uuid;
@@ -30,9 +31,9 @@ pub(crate) async fn list_secrets(
3031
)
3132
.await?;
3233

33-
let enc = client.internal.get_encryption_settings()?;
34+
let key_store = client.internal.get_key_store();
3435

35-
SecretIdentifiersResponse::process_response(res, &enc)
36+
SecretIdentifiersResponse::process_response(res, &mut key_store.context())
3637
}
3738

3839
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
@@ -53,9 +54,9 @@ pub(crate) async fn list_secrets_by_project(
5354
)
5455
.await?;
5556

56-
let enc = client.internal.get_encryption_settings()?;
57+
let key_store = client.internal.get_key_store();
5758

58-
SecretIdentifiersResponse::process_response(res, &enc)
59+
SecretIdentifiersResponse::process_response(res, &mut key_store.context())
5960
}
6061

6162
#[derive(Serialize, Deserialize, Debug, JsonSchema)]
@@ -67,14 +68,14 @@ pub struct SecretIdentifiersResponse {
6768
impl SecretIdentifiersResponse {
6869
pub(crate) fn process_response(
6970
response: SecretWithProjectsListResponseModel,
70-
enc: &EncryptionSettings,
71+
ctx: &mut KeyStoreContext<KeyIds>,
7172
) -> Result<SecretIdentifiersResponse, SecretsManagerError> {
7273
Ok(SecretIdentifiersResponse {
7374
data: response
7475
.secrets
7576
.unwrap_or_default()
7677
.into_iter()
77-
.map(|r| SecretIdentifierResponse::process_response(r, enc))
78+
.map(|r| SecretIdentifierResponse::process_response(r, ctx))
7879
.collect::<Result<_, _>>()?,
7980
})
8081
}
@@ -92,14 +93,14 @@ pub struct SecretIdentifierResponse {
9293
impl SecretIdentifierResponse {
9394
pub(crate) fn process_response(
9495
response: SecretsWithProjectsInnerSecret,
95-
enc: &EncryptionSettings,
96+
ctx: &mut KeyStoreContext<KeyIds>,
9697
) -> Result<SecretIdentifierResponse, SecretsManagerError> {
9798
let organization_id = require!(response.organization_id);
98-
let enc_key = enc.get_key(&Some(organization_id))?;
99+
let enc_key = SymmetricKeyId::Organization(organization_id);
99100

100101
let key = require!(response.key)
101102
.parse::<EncString>()?
102-
.decrypt_with_key(enc_key)?;
103+
.decrypt(ctx, enc_key)?;
103104

104105
Ok(SecretIdentifierResponse {
105106
id: require!(response.id),

bitwarden_license/bitwarden-sm/src/secrets/secret_response.rs

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
use bitwarden_api_api::models::{
22
BaseSecretResponseModel, BaseSecretResponseModelListResponseModel, SecretResponseModel,
33
};
4-
use bitwarden_core::{client::encryption_settings::EncryptionSettings, require};
5-
use bitwarden_crypto::{EncString, KeyDecryptable};
4+
use bitwarden_core::{
5+
key_management::{KeyIds, SymmetricKeyId},
6+
require,
7+
};
8+
use bitwarden_crypto::{Decryptable, EncString, KeyStoreContext};
69
use chrono::{DateTime, Utc};
710
use schemars::JsonSchema;
811
use serde::{Deserialize, Serialize};
@@ -28,7 +31,7 @@ pub struct SecretResponse {
2831
impl SecretResponse {
2932
pub(crate) fn process_response(
3033
response: SecretResponseModel,
31-
enc: &EncryptionSettings,
34+
ctx: &mut KeyStoreContext<KeyIds>,
3235
) -> Result<SecretResponse, SecretsManagerError> {
3336
let base = BaseSecretResponseModel {
3437
object: response.object,
@@ -41,24 +44,26 @@ impl SecretResponse {
4144
revision_date: response.revision_date,
4245
projects: response.projects,
4346
};
44-
Self::process_base_response(base, enc)
47+
Self::process_base_response(base, ctx)
4548
}
4649
pub(crate) fn process_base_response(
4750
response: BaseSecretResponseModel,
48-
enc: &EncryptionSettings,
51+
ctx: &mut KeyStoreContext<KeyIds>,
4952
) -> Result<SecretResponse, SecretsManagerError> {
50-
let org_id = response.organization_id;
51-
let enc_key = enc.get_key(&org_id)?;
53+
let organization_id = require!(response.organization_id);
54+
let enc_key = SymmetricKeyId::Organization(organization_id);
5255

5356
let key = require!(response.key)
5457
.parse::<EncString>()?
55-
.decrypt_with_key(enc_key)?;
58+
.decrypt(ctx, enc_key)?;
59+
5660
let value = require!(response.value)
5761
.parse::<EncString>()?
58-
.decrypt_with_key(enc_key)?;
62+
.decrypt(ctx, enc_key)?;
63+
5964
let note = require!(response.note)
6065
.parse::<EncString>()?
61-
.decrypt_with_key(enc_key)?;
66+
.decrypt(ctx, enc_key)?;
6267

6368
let project = response
6469
.projects
@@ -67,7 +72,7 @@ impl SecretResponse {
6772

6873
Ok(SecretResponse {
6974
id: require!(response.id),
70-
organization_id: require!(org_id),
75+
organization_id,
7176
project_id: project,
7277
key,
7378
value,
@@ -88,14 +93,14 @@ pub struct SecretsResponse {
8893
impl SecretsResponse {
8994
pub(crate) fn process_response(
9095
response: BaseSecretResponseModelListResponseModel,
91-
enc: &EncryptionSettings,
96+
ctx: &mut KeyStoreContext<KeyIds>,
9297
) -> Result<SecretsResponse, SecretsManagerError> {
9398
Ok(SecretsResponse {
9499
data: response
95100
.data
96101
.unwrap_or_default()
97102
.into_iter()
98-
.map(|r| SecretResponse::process_base_response(r, enc))
103+
.map(|r| SecretResponse::process_base_response(r, ctx))
99104
.collect::<Result<_, _>>()?,
100105
})
101106
}

0 commit comments

Comments
 (0)