1use bitwarden_crypto::{
11 Decryptable, KeyId, KeyStore, PrimitiveEncryptable, SymmetricKeyAlgorithm,
12 safe::{PasswordProtectedKeyEnvelope, PasswordProtectedKeyEnvelopeNamespace},
13};
14use serde::{Deserialize, Serialize};
15use tracing::warn;
16
17use crate::{
18 Client,
19 key_management::{KeySlotIds, SymmetricKeySlotId},
20};
21
22#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
27#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
28#[bitwarden_ffi::wasm_record]
29pub enum PinLockType {
30 BeforeFirstUnlock,
32 AfterFirstUnlock,
35}
36
37#[derive(Clone, Serialize, Deserialize, Debug, PartialEq, Eq)]
38#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
39#[bitwarden_ffi::wasm_record]
40pub enum PinUnlockStatus {
42 Available,
45 NeedsUnlock,
47 NotSet,
49}
50
51pub(crate) enum UnlockError {
52 NoPinSet,
53 PinWrong,
54 InternalError,
55}
56
57#[derive(Debug, PartialEq, Eq)]
58pub(crate) enum MigrationFailed {
59 Locked,
61 UnrecoverablePinKey,
64 UnsupportedPinEncryption,
66 MissingV2UpgradeToken,
68 MissingEncryptedPin,
70 PinDecryption,
72 Reenrollment,
74}
75
76#[derive(Debug, PartialEq, Eq)]
79enum PinMigrationAction {
80 UpToDate,
82 MigrateV1ToV2,
85 Failed(MigrationFailed),
87}
88
89fn classify_encrypted_pin(
96 pin_algorithm: Option<SymmetricKeyAlgorithm>,
97 pin_key_id: Option<&KeyId>,
98 user_key_algorithm: SymmetricKeyAlgorithm,
99 user_key_id: &KeyId,
100) -> PinMigrationAction {
101 let Some(pin_algorithm) = pin_algorithm else {
102 return PinMigrationAction::Failed(MigrationFailed::UnsupportedPinEncryption);
103 };
104
105 let pin_is_v1 = pin_algorithm == SymmetricKeyAlgorithm::Aes256CbcHmac;
106 let user_key_is_v1 = user_key_algorithm == SymmetricKeyAlgorithm::Aes256CbcHmac;
107 if pin_is_v1 && !user_key_is_v1 {
108 return PinMigrationAction::MigrateV1ToV2;
109 }
110
111 match pin_key_id {
112 Some(pin_key_id) if pin_key_id == user_key_id => PinMigrationAction::UpToDate,
113 None if pin_is_v1 => PinMigrationAction::UpToDate,
114 _ => PinMigrationAction::Failed(MigrationFailed::UnrecoverablePinKey),
115 }
116}
117
118pub struct PinLockSystem<'a> {
122 client: &'a Client,
123}
124
125impl PinLockSystem<'_> {
126 fn key_store(&self) -> &KeyStore<KeySlotIds> {
127 self.client.internal.get_key_store()
128 }
129
130 pub fn with_client(client: &Client) -> PinLockSystem<'_> {
132 PinLockSystem { client }
133 }
134
135 async fn get_active_pin_envelope(&self) -> Option<PasswordProtectedKeyEnvelope> {
139 let mut pin_protected_key_envelope = self
140 .client
141 .km_state_bridge()
142 .get_ephemeral_pin_envelope()
143 .await;
144 if pin_protected_key_envelope.is_none() {
145 pin_protected_key_envelope = self
146 .client
147 .km_state_bridge()
148 .get_persistent_pin_envelope()
149 .await;
150 }
151 pin_protected_key_envelope
152 }
153
154 pub(crate) async fn unlock(&self, pin: &str) -> Result<(), UnlockError> {
160 let pin_envelope = Self::get_active_pin_envelope(self)
161 .await
162 .ok_or(UnlockError::NoPinSet)?;
163
164 let mut ctx = self.key_store().context_mut();
166 let key_slot = pin_envelope
167 .unseal(
168 pin,
169 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
170 &mut ctx,
171 )
172 .map_err(|e| match e {
173 bitwarden_crypto::safe::PasswordProtectedKeyEnvelopeError::WrongPassword => {
174 UnlockError::PinWrong
175 }
176 _ => UnlockError::InternalError,
177 })?;
178
179 ctx.persist_symmetric_key(key_slot, SymmetricKeySlotId::User)
182 .map_err(|_| UnlockError::InternalError)
183 }
184
185 async fn migrate_pin_envelope_if_needed(&self) -> Result<(), MigrationFailed> {
192 let Some(lock_type) = self.get_pin_lock_type().await else {
194 return Ok(());
195 };
196 let encrypted_pin = self
197 .client
198 .km_state_bridge()
199 .get_encrypted_pin()
200 .await
201 .ok_or(MigrationFailed::MissingEncryptedPin)?;
202
203 let (user_key_id, user_key_algorithm) = {
205 let ctx = self.key_store().context();
206 (
207 ctx.get_symmetric_key_id(SymmetricKeySlotId::User)
208 .ok_or(MigrationFailed::Locked)?,
209 ctx.get_symmetric_key_algorithm(SymmetricKeySlotId::User)
210 .map_err(|_| MigrationFailed::Locked)?,
211 )
212 };
213
214 match classify_encrypted_pin(
215 encrypted_pin.algorithm(),
216 encrypted_pin.key_id().as_ref(),
217 user_key_algorithm,
218 &user_key_id,
219 ) {
220 PinMigrationAction::UpToDate => return Ok(()),
221 PinMigrationAction::Failed(error) => return Err(error),
222 PinMigrationAction::MigrateV1ToV2 => {}
223 }
224
225 let token = self
226 .client
227 .km_state_bridge()
228 .get_v2_upgrade_token()
229 .await
230 .ok_or(MigrationFailed::MissingV2UpgradeToken)?;
231
232 let pin: String = {
234 let mut ctx = self.key_store().context_mut();
235 let v1_slot = token
236 .unwrap_v1(SymmetricKeySlotId::User, &mut ctx)
237 .map_err(|_| MigrationFailed::PinDecryption)?;
238 encrypted_pin
239 .decrypt(&mut ctx, v1_slot)
240 .map_err(|_| MigrationFailed::PinDecryption)?
241 };
242
243 self.set_pin(pin, lock_type)
245 .await
246 .map_err(|_| MigrationFailed::Reenrollment)
247 }
248
249 pub(crate) async fn on_unlock(&self) {
253 if !self.client.km_state_bridge().is_bridge_registered() {
255 return;
256 }
257
258 if let Err(e) = self.migrate_pin_envelope_if_needed().await {
259 warn!("PIN migration failed: {e:?}, unenrolling PIN");
260 self.unset_pin().await;
261 return;
262 }
263
264 let encrypted_pin = self.client.km_state_bridge().get_encrypted_pin().await;
265
266 let Some(encrypted_pin) = encrypted_pin else {
268 return;
269 };
270
271 if let Some(existing_envelope) = self
275 .client
276 .km_state_bridge()
277 .get_ephemeral_pin_envelope()
278 .await
279 {
280 let user_key_id = self
281 .key_store()
282 .context()
283 .get_symmetric_key_id(SymmetricKeySlotId::User);
284 if user_key_id.is_some()
285 && existing_envelope.contained_key_id().ok().flatten() == user_key_id
286 {
287 return;
288 }
289 }
290
291 let Ok(pin_envelope) = (|| -> Result<PasswordProtectedKeyEnvelope, ()> {
293 let mut ctx = self.key_store().context_mut();
294 let pin: String = encrypted_pin
295 .decrypt(&mut ctx, SymmetricKeySlotId::User)
296 .map_err(|_| ())?;
297 PasswordProtectedKeyEnvelope::seal(
298 SymmetricKeySlotId::User,
299 pin.as_str(),
300 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
301 &ctx,
302 )
303 .map_err(|_| ())
304 })() else {
305 warn!("Failed to create PIN envelope");
306 return;
307 };
308
309 self.client
311 .km_state_bridge()
312 .set_ephemeral_pin_envelope(&pin_envelope)
313 .await;
314 }
315
316 pub async fn set_pin(&self, pin: String, lock_type: PinLockType) -> Result<(), ()> {
318 self.client
320 .km_state_bridge()
321 .clear_persistent_pin_envelope()
322 .await;
323 self.client
324 .km_state_bridge()
325 .clear_ephemeral_pin_envelope()
326 .await;
327 self.client.km_state_bridge().clear_encrypted_pin().await;
328
329 let pin_envelope: PasswordProtectedKeyEnvelope = PasswordProtectedKeyEnvelope::seal(
330 SymmetricKeySlotId::User,
331 pin.as_str(),
332 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
333 &self.key_store().context_mut(),
334 )
335 .map_err(|_| ())?;
336 let encrypted_pin = pin
337 .encrypt(
338 &mut self.key_store().context_mut(),
339 SymmetricKeySlotId::User,
340 )
341 .map_err(|_| ())?;
342
343 self.client
344 .km_state_bridge()
345 .set_encrypted_pin(&encrypted_pin)
346 .await;
347 self.client
348 .km_state_bridge()
349 .set_ephemeral_pin_envelope(&pin_envelope)
350 .await;
351
352 if lock_type == PinLockType::BeforeFirstUnlock {
353 self.client
354 .km_state_bridge()
355 .set_persistent_pin_envelope(&pin_envelope)
356 .await;
357 }
358
359 Ok(())
360 }
361
362 pub async fn unset_pin(&self) {
364 self.client
365 .km_state_bridge()
366 .clear_persistent_pin_envelope()
367 .await;
368 self.client
369 .km_state_bridge()
370 .clear_ephemeral_pin_envelope()
371 .await;
372 self.client.km_state_bridge().clear_encrypted_pin().await;
373 }
374
375 pub async fn get_pin_lock_type(&self) -> Option<PinLockType> {
377 if self
378 .client
379 .km_state_bridge()
380 .get_persistent_pin_envelope()
381 .await
382 .is_some()
383 {
384 return Some(PinLockType::BeforeFirstUnlock);
385 }
386
387 if self
391 .client
392 .km_state_bridge()
393 .get_encrypted_pin()
394 .await
395 .is_some()
396 {
397 return Some(PinLockType::AfterFirstUnlock);
398 }
399
400 None
401 }
402
403 pub async fn get_pin_status(&self) -> PinUnlockStatus {
408 match Self::get_pin_lock_type(self).await {
409 Some(PinLockType::BeforeFirstUnlock) => {
410 if self.get_active_pin_envelope().await.is_some() {
411 PinUnlockStatus::Available
412 } else {
413 PinUnlockStatus::NeedsUnlock
414 }
415 }
416 Some(PinLockType::AfterFirstUnlock) => {
417 if self
418 .client
419 .km_state_bridge()
420 .get_ephemeral_pin_envelope()
421 .await
422 .is_some()
423 {
424 PinUnlockStatus::Available
425 } else {
426 PinUnlockStatus::NeedsUnlock
429 }
430 }
431 None => PinUnlockStatus::NotSet,
432 }
433 }
434
435 pub async fn get_pin(&self) -> Option<String> {
437 let encrypted_pin = self.client.km_state_bridge().get_encrypted_pin().await?;
438 encrypted_pin
439 .decrypt(
440 &mut self.client.internal.get_key_store().context_mut(),
441 SymmetricKeySlotId::User,
442 )
443 .ok()
444 }
445
446 pub async fn validate_pin(&self, pin: String) -> bool {
448 let pin_envelope = self.get_active_pin_envelope().await;
449 let Some(pin_envelope) = pin_envelope else {
450 return false;
451 };
452
453 pin_envelope
454 .unseal(
455 pin.as_str(),
456 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
457 &mut self.key_store().context_mut(),
458 )
459 .is_ok()
460 }
461}
462
463#[cfg(test)]
464mod tests {
465 use bitwarden_crypto::{EncString, KeyId, SymmetricKeyAlgorithm};
466
467 use super::*;
468 use crate::key_management::{V2UpgradeToken, state_bridge::test_support::InMemoryStateBridge};
469
470 fn decrypt_encrypted_pin(client: &Client, encrypted_pin: &EncString) -> String {
471 encrypted_pin
472 .decrypt(
473 &mut client.internal.get_key_store().context_mut(),
474 SymmetricKeySlotId::User,
475 )
476 .expect("encrypted pin should decrypt successfully")
477 }
478
479 const TESTVECTOR_LEGACY_ENVELOPE_PIN: &str = "1234";
481 const TESTVECTOR_LEGACY_ENVELOPE: &[u8] = &[
494 132, 88, 52, 164, 1, 3, 3, 120, 34, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47,
495 120, 46, 98, 105, 116, 119, 97, 114, 100, 101, 110, 46, 108, 101, 103, 97, 99, 121, 45,
496 107, 101, 121, 58, 0, 1, 56, 129, 1, 58, 0, 1, 56, 128, 1, 161, 5, 76, 148, 49, 223, 205,
497 195, 252, 91, 216, 65, 200, 121, 104, 88, 80, 89, 120, 16, 161, 14, 97, 191, 97, 138, 42,
498 102, 234, 49, 186, 2, 255, 31, 4, 232, 178, 100, 53, 37, 181, 172, 129, 193, 51, 109, 8,
499 160, 29, 254, 181, 242, 102, 73, 229, 89, 150, 227, 252, 120, 156, 71, 202, 200, 241, 74,
500 241, 206, 16, 155, 83, 49, 242, 13, 209, 10, 217, 251, 164, 244, 69, 41, 52, 9, 192, 140,
501 248, 251, 244, 84, 154, 15, 100, 222, 102, 117, 185, 129, 131, 71, 161, 1, 58, 0, 1, 21,
502 87, 165, 1, 58, 0, 1, 21, 87, 58, 0, 1, 21, 89, 3, 58, 0, 1, 21, 90, 26, 0, 1, 0, 0, 58, 0,
503 1, 21, 91, 4, 58, 0, 1, 21, 88, 80, 64, 184, 87, 20, 40, 186, 214, 56, 87, 53, 118, 100, 5,
504 21, 13, 3, 246,
505 ];
506
507 fn legacy_envelope() -> PasswordProtectedKeyEnvelope {
509 let envelope = PasswordProtectedKeyEnvelope::try_from(&TESTVECTOR_LEGACY_ENVELOPE.to_vec())
510 .expect("legacy envelope test vector parses");
511 assert_eq!(
512 envelope.contained_key_id().expect("readable"),
513 None,
514 "legacy envelope test vector must have no contained key id",
515 );
516 envelope
517 }
518
519 fn user_key_id(client: &Client) -> KeyId {
521 client
522 .internal
523 .get_key_store()
524 .context()
525 .get_symmetric_key_id(SymmetricKeySlotId::User)
526 .expect("user key present")
527 }
528
529 fn assert_envelope_wraps_user_key(
531 client: &Client,
532 envelope: &PasswordProtectedKeyEnvelope,
533 pin: &str,
534 expected_key_id: &KeyId,
535 ) {
536 assert_eq!(
537 envelope
538 .contained_key_id()
539 .expect("contained key id readable"),
540 Some(expected_key_id.clone()),
541 "envelope wraps a key other than the current user key",
542 );
543 let _ = envelope
544 .unseal(
545 pin,
546 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
547 &mut client.internal.get_key_store().context_mut(),
548 )
549 .expect("envelope unseals with the configured pin");
550 }
551
552 fn client_with_user_key() -> Client {
553 let client = Client::new(None);
554 client
555 .km_state_bridge()
556 .register_bridge(Box::new(InMemoryStateBridge::default()));
557 {
558 let key_store = client.internal.get_key_store();
559 let mut ctx = key_store.context_mut();
560 let user_key = ctx.make_symmetric_key(SymmetricKeyAlgorithm::XAes256Gcm);
561 ctx.persist_symmetric_key(user_key, SymmetricKeySlotId::User)
562 .expect("persisting user key should succeed");
563 }
564 client
565 }
566
567 fn seal_envelope(client: &Client, pin: &str) -> PasswordProtectedKeyEnvelope {
568 PasswordProtectedKeyEnvelope::seal(
569 SymmetricKeySlotId::User,
570 pin,
571 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
572 &client.internal.get_key_store().context_mut(),
573 )
574 .expect("seal succeeds")
575 }
576
577 #[tokio::test]
578 async fn set_pin_bfu_persists_both_envelopes() {
579 let client = client_with_user_key();
580 let user_key_id = user_key_id(&client);
581 let system = PinLockSystem::with_client(&client);
582
583 system
584 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
585 .await
586 .expect("set_pin succeeds");
587
588 let bridge = client.km_state_bridge();
589 let persistent = bridge
590 .get_persistent_pin_envelope()
591 .await
592 .expect("persistent envelope present");
593 let ephemeral = bridge
594 .get_ephemeral_pin_envelope()
595 .await
596 .expect("ephemeral envelope present");
597 let encrypted_pin = bridge
598 .get_encrypted_pin()
599 .await
600 .expect("encrypted pin present");
601
602 assert_envelope_wraps_user_key(&client, &persistent, "1234", &user_key_id);
603 assert_envelope_wraps_user_key(&client, &ephemeral, "1234", &user_key_id);
604 assert_eq!(decrypt_encrypted_pin(&client, &encrypted_pin), "1234");
605
606 assert_eq!(
607 system.get_pin_lock_type().await,
608 Some(PinLockType::BeforeFirstUnlock)
609 );
610 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
611 }
612
613 #[tokio::test]
614 async fn set_pin_afu_persists_only_ephemeral() {
615 let client = client_with_user_key();
616 let user_key_id = user_key_id(&client);
617 let system = PinLockSystem::with_client(&client);
618
619 system
620 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
621 .await
622 .expect("set_pin succeeds");
623
624 let bridge = client.km_state_bridge();
625 assert!(bridge.get_persistent_pin_envelope().await.is_none());
626 let ephemeral = bridge
627 .get_ephemeral_pin_envelope()
628 .await
629 .expect("ephemeral envelope present");
630 let encrypted_pin = bridge
631 .get_encrypted_pin()
632 .await
633 .expect("encrypted pin present");
634
635 assert_envelope_wraps_user_key(&client, &ephemeral, "1234", &user_key_id);
636 assert_eq!(decrypt_encrypted_pin(&client, &encrypted_pin), "1234");
637
638 assert_eq!(
639 system.get_pin_lock_type().await,
640 Some(PinLockType::AfterFirstUnlock)
641 );
642 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
643 }
644
645 #[tokio::test]
646 async fn set_pin_overwrites_existing_state() {
647 let client = client_with_user_key();
648 let system = PinLockSystem::with_client(&client);
649
650 system
651 .set_pin("first".into(), PinLockType::BeforeFirstUnlock)
652 .await
653 .expect("first set_pin");
654 system
655 .set_pin("second".into(), PinLockType::AfterFirstUnlock)
656 .await
657 .expect("second set_pin");
658
659 let bridge = client.km_state_bridge();
660 assert!(
661 bridge.get_persistent_pin_envelope().await.is_none(),
662 "switching to AFU must clear the persistent envelope"
663 );
664 assert_eq!(
665 system.get_pin_lock_type().await,
666 Some(PinLockType::AfterFirstUnlock)
667 );
668 assert!(system.validate_pin("second".into()).await);
669 assert!(!system.validate_pin("first".into()).await);
670 }
671
672 #[tokio::test]
673 async fn unset_pin_clears_all_state() {
674 let client = client_with_user_key();
675 let system = PinLockSystem::with_client(&client);
676
677 system
678 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
679 .await
680 .expect("set_pin succeeds");
681 system.unset_pin().await;
682
683 let bridge = client.km_state_bridge();
684 assert!(bridge.get_persistent_pin_envelope().await.is_none());
685 assert!(bridge.get_ephemeral_pin_envelope().await.is_none());
686 assert!(bridge.get_encrypted_pin().await.is_none());
687 assert_eq!(system.get_pin_lock_type().await, None);
688 assert_eq!(system.get_pin_status().await, PinUnlockStatus::NotSet);
689 }
690
691 #[tokio::test]
692 async fn unlock_with_correct_pin_persists_user_key() {
693 let client = client_with_user_key();
694 let system = PinLockSystem::with_client(&client);
695
696 let pre_unlock_user_key_id = user_key_id(&client);
697 system
699 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
700 .await
701 .expect("set_pin succeeds");
702 client.internal.get_key_store().clear();
703
704 assert!(system.unlock("1234").await.is_ok());
705 let post_unlock_user_key_id = user_key_id(&client);
706 assert_eq!(post_unlock_user_key_id, pre_unlock_user_key_id);
707 }
708
709 #[tokio::test]
710 async fn unlock_with_wrong_pin_returns_pin_wrong() {
711 let client = client_with_user_key();
712 let system = PinLockSystem::with_client(&client);
713 system
714 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
715 .await
716 .expect("set_pin succeeds");
717
718 assert!(matches!(
719 system.unlock("wrong").await,
720 Err(UnlockError::PinWrong)
721 ));
722 }
723
724 #[tokio::test]
725 async fn unlock_with_no_pin_set_returns_no_pin_set() {
726 let client = client_with_user_key();
727 let system = PinLockSystem::with_client(&client);
728
729 assert!(matches!(
730 system.unlock("anything").await,
731 Err(UnlockError::NoPinSet)
732 ));
733 }
734
735 #[tokio::test]
736 async fn unlock_prefers_ephemeral_envelope_over_persistent() {
737 let client = client_with_user_key();
738 let system = PinLockSystem::with_client(&client);
739 system
740 .set_pin("persistent".into(), PinLockType::BeforeFirstUnlock)
741 .await
742 .expect("set_pin succeeds");
743
744 let ephemeral = seal_envelope(&client, "ephemeral");
747 client
748 .km_state_bridge()
749 .set_ephemeral_pin_envelope(&ephemeral)
750 .await;
751
752 assert!(system.unlock("ephemeral").await.is_ok());
753 assert!(matches!(
754 system.unlock("persistent").await,
755 Err(UnlockError::PinWrong)
756 ));
757 }
758
759 #[tokio::test]
760 async fn get_pin_status_available_bfu() {
761 let client = client_with_user_key();
762 let system = PinLockSystem::with_client(&client);
763 system
764 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
765 .await
766 .expect("set_pin succeeds");
767
768 client
770 .km_state_bridge()
771 .clear_ephemeral_pin_envelope()
772 .await;
773
774 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
775 assert_eq!(
776 system.get_pin_lock_type().await,
777 Some(PinLockType::BeforeFirstUnlock)
778 );
779 }
780
781 #[tokio::test]
782 async fn on_unlock_rebuilds_ephemeral_envelope() {
783 let client = client_with_user_key();
784 let user_key_id = user_key_id(&client);
785 let system = PinLockSystem::with_client(&client);
786 system
787 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
788 .await
789 .expect("set_pin succeeds");
790 client
791 .km_state_bridge()
792 .clear_ephemeral_pin_envelope()
793 .await;
794 assert_eq!(system.get_pin_status().await, PinUnlockStatus::NeedsUnlock);
795
796 system.on_unlock().await;
797
798 let rebuilt = client
799 .km_state_bridge()
800 .get_ephemeral_pin_envelope()
801 .await
802 .expect("on_unlock should restore the ephemeral envelope");
803 assert_envelope_wraps_user_key(&client, &rebuilt, "1234", &user_key_id);
804 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
805 assert!(system.unlock("1234").await.is_ok());
806 }
807
808 #[tokio::test]
809 async fn on_unlock_keeps_ephemeral_envelope_for_current_user_key() {
810 let client = client_with_user_key();
811 let system = PinLockSystem::with_client(&client);
812 system
813 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
814 .await
815 .expect("set_pin succeeds");
816 let before = client
817 .km_state_bridge()
818 .get_ephemeral_pin_envelope()
819 .await
820 .expect("set_pin stores an ephemeral envelope");
821
822 system.on_unlock().await;
823
824 let after = client
825 .km_state_bridge()
826 .get_ephemeral_pin_envelope()
827 .await
828 .expect("the ephemeral envelope is kept");
829 assert_eq!(Vec::<u8>::from(&before), Vec::<u8>::from(&after));
830 assert!(system.unlock("1234").await.is_ok());
831 }
832
833 #[tokio::test]
834 async fn on_unlock_rebuilds_ephemeral_envelope_for_other_user_key() {
835 let client = client_with_user_key();
836 let user_key_id = user_key_id(&client);
837 let system = PinLockSystem::with_client(&client);
838 system
839 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
840 .await
841 .expect("set_pin succeeds");
842
843 let other_client = client_with_user_key();
844 PinLockSystem::with_client(&other_client)
845 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
846 .await
847 .expect("set_pin succeeds");
848 let foreign_envelope = other_client
849 .km_state_bridge()
850 .get_ephemeral_pin_envelope()
851 .await
852 .expect("set_pin stores an ephemeral envelope");
853 client
854 .km_state_bridge()
855 .set_ephemeral_pin_envelope(&foreign_envelope)
856 .await;
857
858 system.on_unlock().await;
859
860 let rebuilt = client
861 .km_state_bridge()
862 .get_ephemeral_pin_envelope()
863 .await
864 .expect("on_unlock should restore the ephemeral envelope");
865 assert_envelope_wraps_user_key(&client, &rebuilt, "1234", &user_key_id);
866 assert!(system.unlock("1234").await.is_ok());
867 }
868
869 #[tokio::test]
870 async fn on_unlock_is_noop_when_no_encrypted_pin() {
871 let client = client_with_user_key();
872 let system = PinLockSystem::with_client(&client);
873
874 system.on_unlock().await;
875
876 assert_eq!(system.get_pin_status().await, PinUnlockStatus::NotSet);
877 }
878
879 #[tokio::test]
880 async fn on_unlock_is_noop_when_bridge_not_registered() {
881 let client = Client::new(None);
882 let system = PinLockSystem::with_client(&client);
883
884 system.on_unlock().await;
886 }
887
888 #[tokio::test]
889 async fn get_pin_returns_set_pin() {
890 let client = client_with_user_key();
891 let system = PinLockSystem::with_client(&client);
892
893 assert_eq!(system.get_pin().await, None);
894
895 system
896 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
897 .await
898 .expect("set_pin succeeds");
899 assert_eq!(system.get_pin().await, Some("1234".to_owned()));
900
901 system.unset_pin().await;
902 assert_eq!(system.get_pin().await, None);
903 }
904
905 #[tokio::test]
906 async fn validate_pin_matches_only_correct_pin() {
907 let client = client_with_user_key();
908 let system = PinLockSystem::with_client(&client);
909
910 assert!(!system.validate_pin("anything".into()).await);
911
912 system
913 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
914 .await
915 .expect("set_pin succeeds");
916 assert!(system.validate_pin("1234".into()).await);
917 assert!(!system.validate_pin("wrong".into()).await);
918 }
919
920 struct V1State {
923 envelope: PasswordProtectedKeyEnvelope,
924 encrypted_pin: EncString,
925 token: V2UpgradeToken,
926 }
927
928 fn fresh_v1_state_with_v2_user_key(pin: &str) -> (Client, V1State) {
932 let client = Client::new(None);
933 client
934 .km_state_bridge()
935 .register_bridge(Box::new(InMemoryStateBridge::default()));
936
937 let state = {
938 let key_store = client.internal.get_key_store();
939 let mut ctx = key_store.context_mut();
940
941 let v1_local = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
942 let v2_local = ctx.make_symmetric_key(SymmetricKeyAlgorithm::XAes256Gcm);
943
944 let envelope = PasswordProtectedKeyEnvelope::seal(
945 v1_local,
946 pin,
947 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
948 &ctx,
949 )
950 .expect("v1 envelope seals");
951 let encrypted_pin = pin
952 .encrypt(&mut ctx, v1_local)
953 .expect("pin encrypts under v1 key");
954 let token =
955 V2UpgradeToken::create(v1_local, v2_local, &ctx).expect("upgrade token created");
956
957 ctx.persist_symmetric_key(v2_local, SymmetricKeySlotId::User)
958 .expect("persisting v2 user key succeeds");
959
960 V1State {
961 envelope,
962 encrypted_pin,
963 token,
964 }
965 };
966
967 (client, state)
968 }
969
970 fn client_with_v1_user_key() -> Client {
973 let client = Client::new(None);
974 client
975 .km_state_bridge()
976 .register_bridge(Box::new(InMemoryStateBridge::default()));
977 {
978 let key_store = client.internal.get_key_store();
979 let mut ctx = key_store.context_mut();
980 let user_key = ctx.generate_symmetric_key();
981 ctx.persist_symmetric_key(user_key, SymmetricKeySlotId::User)
982 .expect("persisting v1 user key should succeed");
983 }
984 client
985 }
986
987 fn assert_pin_envelopes_equal(
988 envelope_1: &PasswordProtectedKeyEnvelope,
989 envelope_2: &PasswordProtectedKeyEnvelope,
990 ) {
991 assert_eq!(
992 serde_json::to_string(envelope_1).expect("envelope serializes"),
993 serde_json::to_string(envelope_2).expect("envelope serializes"),
994 "envelopes should be identical",
995 );
996 }
997
998 async fn assert_pin_fully_unenrolled(client: &Client) {
999 let bridge = client.km_state_bridge();
1000 assert!(bridge.get_persistent_pin_envelope().await.is_none());
1001 assert!(bridge.get_ephemeral_pin_envelope().await.is_none());
1002 assert!(bridge.get_encrypted_pin().await.is_none());
1003 assert_eq!(
1004 PinLockSystem::with_client(client).get_pin_status().await,
1005 PinUnlockStatus::NotSet,
1006 );
1007 }
1008
1009 async fn store_v1_pin(client: &Client, state: &V1State, lock_type: &PinLockType) {
1018 let bridge = client.km_state_bridge();
1019 bridge.set_encrypted_pin(&state.encrypted_pin).await;
1020 if *lock_type == PinLockType::BeforeFirstUnlock {
1021 bridge.set_persistent_pin_envelope(&state.envelope).await;
1022 }
1023 }
1024
1025 #[tokio::test]
1026 async fn migrate_without_pin_is_noop() {
1027 let client = client_with_user_key();
1028 let system = PinLockSystem::with_client(&client);
1029
1030 system
1031 .migrate_pin_envelope_if_needed()
1032 .await
1033 .expect("migration succeeds");
1034
1035 assert_pin_fully_unenrolled(&client).await;
1036 }
1037
1038 #[tokio::test]
1040 async fn migrate_up_to_date_v2_pin_is_noop() {
1041 let client = client_with_user_key();
1042 let system = PinLockSystem::with_client(&client);
1043 system
1044 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
1045 .await
1046 .expect("set_pin succeeds");
1047
1048 let bridge = client.km_state_bridge();
1049 let persistent_before = bridge.get_persistent_pin_envelope().await.expect("present");
1050 let encrypted_pin_before = bridge.get_encrypted_pin().await.expect("present");
1051
1052 system
1053 .migrate_pin_envelope_if_needed()
1054 .await
1055 .expect("migration succeeds");
1056
1057 let persistent_after = bridge.get_persistent_pin_envelope().await.expect("present");
1058 let encrypted_pin_after = bridge.get_encrypted_pin().await.expect("present");
1059 assert_pin_envelopes_equal(&persistent_before, &persistent_after);
1060 assert_eq!(
1061 encrypted_pin_before.to_string(),
1062 encrypted_pin_after.to_string()
1063 );
1064 }
1065
1066 #[tokio::test]
1069 async fn migrate_up_to_date_v1_pin_is_noop() {
1070 let client = client_with_v1_user_key();
1071 let encrypted_pin = TESTVECTOR_LEGACY_ENVELOPE_PIN
1072 .encrypt(
1073 &mut client.internal.get_key_store().context_mut(),
1074 SymmetricKeySlotId::User,
1075 )
1076 .expect("encrypt under v1 user key");
1077
1078 let bridge = client.km_state_bridge();
1079 bridge.set_persistent_pin_envelope(&legacy_envelope()).await;
1080 bridge.set_encrypted_pin(&encrypted_pin).await;
1081
1082 let system = PinLockSystem::with_client(&client);
1083 system
1084 .migrate_pin_envelope_if_needed()
1085 .await
1086 .expect("migration succeeds");
1087
1088 let persistent_after = bridge.get_persistent_pin_envelope().await.expect("present");
1089 let encrypted_pin_after = bridge.get_encrypted_pin().await.expect("present");
1090 assert_pin_envelopes_equal(&legacy_envelope(), &persistent_after);
1091 assert_eq!(encrypted_pin.to_string(), encrypted_pin_after.to_string());
1092 }
1093
1094 #[tokio::test]
1097 async fn migrate_v1_pin_with_v2_user_key_reenrolls() {
1098 for lock_type in [
1099 PinLockType::BeforeFirstUnlock,
1100 PinLockType::AfterFirstUnlock,
1101 ] {
1102 let pin = "1234";
1103 let (client, state) = fresh_v1_state_with_v2_user_key(pin);
1104 store_v1_pin(&client, &state, &lock_type).await;
1105 client
1106 .km_state_bridge()
1107 .set_v2_upgrade_token(&state.token)
1108 .await;
1109
1110 let system = PinLockSystem::with_client(&client);
1111 system
1112 .migrate_pin_envelope_if_needed()
1113 .await
1114 .expect("migration succeeds");
1115
1116 let bridge = client.km_state_bridge();
1117 let encrypted_pin = bridge.get_encrypted_pin().await.expect("present");
1118 let ephemeral = bridge.get_ephemeral_pin_envelope().await.expect("present");
1119
1120 assert_eq!(decrypt_encrypted_pin(&client, &encrypted_pin), pin);
1121 assert_envelope_wraps_user_key(&client, &ephemeral, pin, &user_key_id(&client));
1122 assert_eq!(system.get_pin_lock_type().await, Some(lock_type));
1123 assert!(system.unlock(pin).await.is_ok());
1124 }
1125 }
1126
1127 #[test]
1130 fn classify_v1_pin_with_key_id() {
1131 let user_key_id = KeyId::from([1; 16]);
1132 let other_key_id = KeyId::from([2; 16]);
1133
1134 assert_eq!(
1135 classify_encrypted_pin(
1136 Some(SymmetricKeyAlgorithm::Aes256CbcHmac),
1137 Some(&other_key_id),
1138 SymmetricKeyAlgorithm::XAes256Gcm,
1139 &user_key_id
1140 ),
1141 PinMigrationAction::MigrateV1ToV2,
1142 );
1143 assert_eq!(
1144 classify_encrypted_pin(
1145 Some(SymmetricKeyAlgorithm::Aes256CbcHmac),
1146 Some(&user_key_id),
1147 SymmetricKeyAlgorithm::Aes256CbcHmac,
1148 &user_key_id
1149 ),
1150 PinMigrationAction::UpToDate,
1151 );
1152 assert_eq!(
1153 classify_encrypted_pin(
1154 Some(SymmetricKeyAlgorithm::Aes256CbcHmac),
1155 Some(&other_key_id),
1156 SymmetricKeyAlgorithm::Aes256CbcHmac,
1157 &user_key_id
1158 ),
1159 PinMigrationAction::Failed(MigrationFailed::UnrecoverablePinKey),
1160 );
1161 }
1162
1163 #[tokio::test]
1165 async fn migrate_v2_pin_with_rotated_user_key_fails() {
1166 let client = client_with_user_key();
1167 let encrypted_pin = {
1168 let mut ctx = client.internal.get_key_store().context_mut();
1169 let other_v2 = ctx.make_symmetric_key(SymmetricKeyAlgorithm::XAes256Gcm);
1170 "1234"
1171 .encrypt(&mut ctx, other_v2)
1172 .expect("encrypt under other v2 key")
1173 };
1174 client
1175 .km_state_bridge()
1176 .set_encrypted_pin(&encrypted_pin)
1177 .await;
1178
1179 let system = PinLockSystem::with_client(&client);
1180 assert_eq!(
1181 system.migrate_pin_envelope_if_needed().await,
1182 Err(MigrationFailed::UnrecoverablePinKey),
1183 );
1184 }
1185
1186 #[tokio::test]
1187 async fn migrate_without_user_key_fails_locked() {
1188 let client = Client::new(None);
1189 client
1190 .km_state_bridge()
1191 .register_bridge(Box::new(InMemoryStateBridge::default()));
1192 let (_, state) = fresh_v1_state_with_v2_user_key("1234");
1193 client
1194 .km_state_bridge()
1195 .set_encrypted_pin(&state.encrypted_pin)
1196 .await;
1197
1198 let system = PinLockSystem::with_client(&client);
1199 assert_eq!(
1200 system.migrate_pin_envelope_if_needed().await,
1201 Err(MigrationFailed::Locked),
1202 );
1203 }
1204
1205 #[tokio::test]
1206 async fn migrate_envelope_without_encrypted_pin_fails() {
1207 let client = client_with_v1_user_key();
1208 client
1209 .km_state_bridge()
1210 .set_persistent_pin_envelope(&legacy_envelope())
1211 .await;
1212
1213 let system = PinLockSystem::with_client(&client);
1214 assert_eq!(
1215 system.migrate_pin_envelope_if_needed().await,
1216 Err(MigrationFailed::MissingEncryptedPin),
1217 );
1218 }
1219
1220 #[tokio::test]
1221 async fn migrate_v1_pin_without_token_fails() {
1222 let (client, state) = fresh_v1_state_with_v2_user_key("1234");
1223 store_v1_pin(&client, &state, &PinLockType::AfterFirstUnlock).await;
1224
1225 let system = PinLockSystem::with_client(&client);
1226 assert_eq!(
1227 system.migrate_pin_envelope_if_needed().await,
1228 Err(MigrationFailed::MissingV2UpgradeToken),
1229 );
1230 }
1231
1232 #[tokio::test]
1234 async fn migrate_v1_pin_with_mismatched_token_fails() {
1235 let (client, state) = fresh_v1_state_with_v2_user_key("1234");
1236 store_v1_pin(&client, &state, &PinLockType::AfterFirstUnlock).await;
1237
1238 let unrelated_token = {
1240 let mut ctx = client.internal.get_key_store().context_mut();
1241 let other_v1 = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
1242 V2UpgradeToken::create(other_v1, SymmetricKeySlotId::User, &ctx)
1243 .expect("unrelated token created")
1244 };
1245 client
1246 .km_state_bridge()
1247 .set_v2_upgrade_token(&unrelated_token)
1248 .await;
1249
1250 let system = PinLockSystem::with_client(&client);
1251 assert_eq!(
1252 system.migrate_pin_envelope_if_needed().await,
1253 Err(MigrationFailed::PinDecryption),
1254 );
1255 }
1256
1257 #[tokio::test]
1259 async fn on_unlock_restores_afu_pin_after_upgrade() {
1260 let pin = "1234";
1261 let (client, state) = fresh_v1_state_with_v2_user_key(pin);
1262 store_v1_pin(&client, &state, &PinLockType::AfterFirstUnlock).await;
1263 client
1264 .km_state_bridge()
1265 .set_v2_upgrade_token(&state.token)
1266 .await;
1267
1268 let system = PinLockSystem::with_client(&client);
1269 assert_eq!(system.get_pin_status().await, PinUnlockStatus::NeedsUnlock);
1270
1271 system.on_unlock().await;
1272
1273 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
1274 assert!(system.unlock(pin).await.is_ok());
1275 }
1276
1277 #[tokio::test]
1278 async fn on_unlock_unenrolls_when_migration_fails() {
1279 let (client, state) = fresh_v1_state_with_v2_user_key("1234");
1281 store_v1_pin(&client, &state, &PinLockType::BeforeFirstUnlock).await;
1282
1283 let system = PinLockSystem::with_client(&client);
1284 system.on_unlock().await;
1285
1286 assert_pin_fully_unenrolled(&client).await;
1287 }
1288}