Skip to content

Commit 5bf6322

Browse files
authored
[PM-29846] Fix init when private key is corrupt (#614)
## 🎟️ Tracking <!-- Paste the link to the Jira or GitHub issue or otherwise describe / point to where this change is coming from. --> https://bitwarden.atlassian.net/browse/PM-29846 ## 📔 Objective <!-- Describe what the purpose of this PR is, for example what bug you're fixing or new feature you're adding. --> #563 change the init process which now always requires a valid private key. This does not work for users that have a broken private key, and until those are fixed before unlock, these need to be supported in the SDK for V1. ## 🚨 Breaking Changes <!-- Does this PR introduce any breaking changes? If so, please describe the impact and migration path for clients. If you're unsure, the automated TypeScript compatibility check will run when you open/update this PR and provide feedback. For breaking changes: 1. Describe what changed in the client interface 2. Explain why the change was necessary 3. Provide migration steps for client developers 4. Link to any paired client PRs if needed Otherwise, you can remove this section. --> ## ⏰ 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 9b1a39e commit 5bf6322

File tree

1 file changed

+53
-5
lines changed

1 file changed

+53
-5
lines changed

crates/bitwarden-core/src/key_management/account_cryptographic_state.rs

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,16 @@ impl WrappedAccountCryptographicState {
229229
return Err(AccountCryptographyInitializationError::WrongUserKeyType);
230230
}
231231

232-
let private_key_id = ctx
233-
.unwrap_private_key(user_key, private_key)
234-
.map_err(|_| AccountCryptographyInitializationError::WrongUserKey)?;
232+
// Some users have unreadable V1 private keys. In this case, we set no keys to
233+
// state.
234+
if let Ok(private_key_id) = ctx.unwrap_private_key(user_key, private_key) {
235+
ctx.persist_asymmetric_key(private_key_id, AsymmetricKeyId::UserPrivateKey)?;
236+
} else {
237+
tracing::warn!(
238+
"V1 private key could not be unwrapped, skipping setting private key"
239+
);
240+
}
235241

236-
ctx.persist_asymmetric_key(private_key_id, AsymmetricKeyId::UserPrivateKey)?;
237242
ctx.persist_symmetric_key(user_key, SymmetricKeyId::User)?;
238243
}
239244
WrappedAccountCryptographicState::V2 {
@@ -338,7 +343,7 @@ impl WrappedAccountCryptographicState {
338343
mod tests {
339344
use std::{str::FromStr, sync::RwLock};
340345

341-
use bitwarden_crypto::KeyStore;
346+
use bitwarden_crypto::{KeyStore, PrimitiveEncryptable};
342347

343348
use super::*;
344349
use crate::key_management::{AsymmetricKeyId, SigningKeyId, SymmetricKeyId};
@@ -512,4 +517,47 @@ mod tests {
512517
model.security_state.unwrap().security_version as u64
513518
);
514519
}
520+
521+
#[test]
522+
fn test_set_to_context_v1_corrupt_private_key() {
523+
// Test that a V1 account with a corrupt private key (valid EncString but invalid key data)
524+
// can still initialize, but skips setting the private key
525+
let temp_store: KeyStore<KeyIds> = KeyStore::default();
526+
let mut temp_ctx = temp_store.context_mut();
527+
528+
let user_key = temp_ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
529+
let corrupt_private_key = "not a private key"
530+
.encrypt(&mut temp_ctx, user_key)
531+
.unwrap();
532+
533+
// Construct the V1 wrapped state with corrupt private key
534+
let wrapped = WrappedAccountCryptographicState::V1 {
535+
private_key: corrupt_private_key,
536+
};
537+
538+
#[expect(deprecated)]
539+
let user_key_material = temp_ctx
540+
.dangerous_get_symmetric_key(user_key)
541+
.unwrap()
542+
.to_owned();
543+
drop(temp_ctx);
544+
drop(temp_store);
545+
546+
// Now attempt to set this wrapped state into a fresh store
547+
let store: KeyStore<KeyIds> = KeyStore::default();
548+
let mut ctx = store.context_mut();
549+
let user_key = ctx.add_local_symmetric_key(user_key_material);
550+
let security_state = RwLock::new(None);
551+
552+
wrapped
553+
.set_to_context(&security_state, user_key, &store, ctx)
554+
.unwrap();
555+
556+
let ctx = store.context();
557+
558+
// The user symmetric key should be set
559+
assert!(ctx.has_symmetric_key(SymmetricKeyId::User));
560+
// But the private key should NOT be set (due to corruption)
561+
assert!(!ctx.has_asymmetric_key(AsymmetricKeyId::UserPrivateKey));
562+
}
515563
}

0 commit comments

Comments
 (0)