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 let Ok(pin_envelope) = (|| -> Result<PasswordProtectedKeyEnvelope, ()> {
273 let mut ctx = self.key_store().context_mut();
274 let pin: String = encrypted_pin
275 .decrypt(&mut ctx, SymmetricKeySlotId::User)
276 .map_err(|_| ())?;
277 PasswordProtectedKeyEnvelope::seal(
278 SymmetricKeySlotId::User,
279 pin.as_str(),
280 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
281 &ctx,
282 )
283 .map_err(|_| ())
284 })() else {
285 warn!("Failed to create PIN envelope");
286 return;
287 };
288
289 self.client
291 .km_state_bridge()
292 .set_ephemeral_pin_envelope(&pin_envelope)
293 .await;
294 }
295
296 pub async fn set_pin(&self, pin: String, lock_type: PinLockType) -> Result<(), ()> {
298 self.client
300 .km_state_bridge()
301 .clear_persistent_pin_envelope()
302 .await;
303 self.client
304 .km_state_bridge()
305 .clear_ephemeral_pin_envelope()
306 .await;
307 self.client.km_state_bridge().clear_encrypted_pin().await;
308
309 let pin_envelope: PasswordProtectedKeyEnvelope = PasswordProtectedKeyEnvelope::seal(
310 SymmetricKeySlotId::User,
311 pin.as_str(),
312 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
313 &self.key_store().context_mut(),
314 )
315 .map_err(|_| ())?;
316 let encrypted_pin = pin
317 .encrypt(
318 &mut self.key_store().context_mut(),
319 SymmetricKeySlotId::User,
320 )
321 .map_err(|_| ())?;
322
323 self.client
324 .km_state_bridge()
325 .set_encrypted_pin(&encrypted_pin)
326 .await;
327 self.client
328 .km_state_bridge()
329 .set_ephemeral_pin_envelope(&pin_envelope)
330 .await;
331
332 if lock_type == PinLockType::BeforeFirstUnlock {
333 self.client
334 .km_state_bridge()
335 .set_persistent_pin_envelope(&pin_envelope)
336 .await;
337 }
338
339 Ok(())
340 }
341
342 pub async fn unset_pin(&self) {
344 self.client
345 .km_state_bridge()
346 .clear_persistent_pin_envelope()
347 .await;
348 self.client
349 .km_state_bridge()
350 .clear_ephemeral_pin_envelope()
351 .await;
352 self.client.km_state_bridge().clear_encrypted_pin().await;
353 }
354
355 pub async fn get_pin_lock_type(&self) -> Option<PinLockType> {
357 if self
358 .client
359 .km_state_bridge()
360 .get_persistent_pin_envelope()
361 .await
362 .is_some()
363 {
364 return Some(PinLockType::BeforeFirstUnlock);
365 }
366
367 if self
371 .client
372 .km_state_bridge()
373 .get_encrypted_pin()
374 .await
375 .is_some()
376 {
377 return Some(PinLockType::AfterFirstUnlock);
378 }
379
380 None
381 }
382
383 pub async fn get_pin_status(&self) -> PinUnlockStatus {
388 match Self::get_pin_lock_type(self).await {
389 Some(PinLockType::BeforeFirstUnlock) => {
390 if self.get_active_pin_envelope().await.is_some() {
391 PinUnlockStatus::Available
392 } else {
393 PinUnlockStatus::NeedsUnlock
394 }
395 }
396 Some(PinLockType::AfterFirstUnlock) => {
397 if self
398 .client
399 .km_state_bridge()
400 .get_ephemeral_pin_envelope()
401 .await
402 .is_some()
403 {
404 PinUnlockStatus::Available
405 } else {
406 PinUnlockStatus::NeedsUnlock
409 }
410 }
411 None => PinUnlockStatus::NotSet,
412 }
413 }
414
415 pub async fn get_pin(&self) -> Option<String> {
417 let encrypted_pin = self.client.km_state_bridge().get_encrypted_pin().await?;
418 encrypted_pin
419 .decrypt(
420 &mut self.client.internal.get_key_store().context_mut(),
421 SymmetricKeySlotId::User,
422 )
423 .ok()
424 }
425
426 pub async fn validate_pin(&self, pin: String) -> bool {
428 let pin_envelope = self.get_active_pin_envelope().await;
429 let Some(pin_envelope) = pin_envelope else {
430 return false;
431 };
432
433 pin_envelope
434 .unseal(
435 pin.as_str(),
436 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
437 &mut self.key_store().context_mut(),
438 )
439 .is_ok()
440 }
441}
442
443#[cfg(test)]
444mod tests {
445 use bitwarden_crypto::{EncString, KeyId, SymmetricKeyAlgorithm};
446
447 use super::*;
448 use crate::key_management::{V2UpgradeToken, state_bridge::test_support::InMemoryStateBridge};
449
450 fn decrypt_encrypted_pin(client: &Client, encrypted_pin: &EncString) -> String {
451 encrypted_pin
452 .decrypt(
453 &mut client.internal.get_key_store().context_mut(),
454 SymmetricKeySlotId::User,
455 )
456 .expect("encrypted pin should decrypt successfully")
457 }
458
459 const TESTVECTOR_LEGACY_ENVELOPE_PIN: &str = "1234";
461 const TESTVECTOR_LEGACY_ENVELOPE: &[u8] = &[
474 132, 88, 52, 164, 1, 3, 3, 120, 34, 97, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 47,
475 120, 46, 98, 105, 116, 119, 97, 114, 100, 101, 110, 46, 108, 101, 103, 97, 99, 121, 45,
476 107, 101, 121, 58, 0, 1, 56, 129, 1, 58, 0, 1, 56, 128, 1, 161, 5, 76, 148, 49, 223, 205,
477 195, 252, 91, 216, 65, 200, 121, 104, 88, 80, 89, 120, 16, 161, 14, 97, 191, 97, 138, 42,
478 102, 234, 49, 186, 2, 255, 31, 4, 232, 178, 100, 53, 37, 181, 172, 129, 193, 51, 109, 8,
479 160, 29, 254, 181, 242, 102, 73, 229, 89, 150, 227, 252, 120, 156, 71, 202, 200, 241, 74,
480 241, 206, 16, 155, 83, 49, 242, 13, 209, 10, 217, 251, 164, 244, 69, 41, 52, 9, 192, 140,
481 248, 251, 244, 84, 154, 15, 100, 222, 102, 117, 185, 129, 131, 71, 161, 1, 58, 0, 1, 21,
482 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,
483 1, 21, 91, 4, 58, 0, 1, 21, 88, 80, 64, 184, 87, 20, 40, 186, 214, 56, 87, 53, 118, 100, 5,
484 21, 13, 3, 246,
485 ];
486
487 fn legacy_envelope() -> PasswordProtectedKeyEnvelope {
489 let envelope = PasswordProtectedKeyEnvelope::try_from(&TESTVECTOR_LEGACY_ENVELOPE.to_vec())
490 .expect("legacy envelope test vector parses");
491 assert_eq!(
492 envelope.contained_key_id().expect("readable"),
493 None,
494 "legacy envelope test vector must have no contained key id",
495 );
496 envelope
497 }
498
499 fn user_key_id(client: &Client) -> KeyId {
501 client
502 .internal
503 .get_key_store()
504 .context()
505 .get_symmetric_key_id(SymmetricKeySlotId::User)
506 .expect("user key present")
507 }
508
509 fn assert_envelope_wraps_user_key(
511 client: &Client,
512 envelope: &PasswordProtectedKeyEnvelope,
513 pin: &str,
514 expected_key_id: &KeyId,
515 ) {
516 assert_eq!(
517 envelope
518 .contained_key_id()
519 .expect("contained key id readable"),
520 Some(expected_key_id.clone()),
521 "envelope wraps a key other than the current user key",
522 );
523 let _ = envelope
524 .unseal(
525 pin,
526 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
527 &mut client.internal.get_key_store().context_mut(),
528 )
529 .expect("envelope unseals with the configured pin");
530 }
531
532 fn client_with_user_key() -> Client {
533 let client = Client::new(None);
534 client
535 .km_state_bridge()
536 .register_bridge(Box::new(InMemoryStateBridge::default()));
537 {
538 let key_store = client.internal.get_key_store();
539 let mut ctx = key_store.context_mut();
540 let user_key = ctx.make_symmetric_key(SymmetricKeyAlgorithm::XAes256Gcm);
541 ctx.persist_symmetric_key(user_key, SymmetricKeySlotId::User)
542 .expect("persisting user key should succeed");
543 }
544 client
545 }
546
547 fn seal_envelope(client: &Client, pin: &str) -> PasswordProtectedKeyEnvelope {
548 PasswordProtectedKeyEnvelope::seal(
549 SymmetricKeySlotId::User,
550 pin,
551 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
552 &client.internal.get_key_store().context_mut(),
553 )
554 .expect("seal succeeds")
555 }
556
557 #[tokio::test]
558 async fn set_pin_bfu_persists_both_envelopes() {
559 let client = client_with_user_key();
560 let user_key_id = user_key_id(&client);
561 let system = PinLockSystem::with_client(&client);
562
563 system
564 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
565 .await
566 .expect("set_pin succeeds");
567
568 let bridge = client.km_state_bridge();
569 let persistent = bridge
570 .get_persistent_pin_envelope()
571 .await
572 .expect("persistent envelope present");
573 let ephemeral = bridge
574 .get_ephemeral_pin_envelope()
575 .await
576 .expect("ephemeral envelope present");
577 let encrypted_pin = bridge
578 .get_encrypted_pin()
579 .await
580 .expect("encrypted pin present");
581
582 assert_envelope_wraps_user_key(&client, &persistent, "1234", &user_key_id);
583 assert_envelope_wraps_user_key(&client, &ephemeral, "1234", &user_key_id);
584 assert_eq!(decrypt_encrypted_pin(&client, &encrypted_pin), "1234");
585
586 assert_eq!(
587 system.get_pin_lock_type().await,
588 Some(PinLockType::BeforeFirstUnlock)
589 );
590 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
591 }
592
593 #[tokio::test]
594 async fn set_pin_afu_persists_only_ephemeral() {
595 let client = client_with_user_key();
596 let user_key_id = user_key_id(&client);
597 let system = PinLockSystem::with_client(&client);
598
599 system
600 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
601 .await
602 .expect("set_pin succeeds");
603
604 let bridge = client.km_state_bridge();
605 assert!(bridge.get_persistent_pin_envelope().await.is_none());
606 let ephemeral = bridge
607 .get_ephemeral_pin_envelope()
608 .await
609 .expect("ephemeral envelope present");
610 let encrypted_pin = bridge
611 .get_encrypted_pin()
612 .await
613 .expect("encrypted pin present");
614
615 assert_envelope_wraps_user_key(&client, &ephemeral, "1234", &user_key_id);
616 assert_eq!(decrypt_encrypted_pin(&client, &encrypted_pin), "1234");
617
618 assert_eq!(
619 system.get_pin_lock_type().await,
620 Some(PinLockType::AfterFirstUnlock)
621 );
622 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
623 }
624
625 #[tokio::test]
626 async fn set_pin_overwrites_existing_state() {
627 let client = client_with_user_key();
628 let system = PinLockSystem::with_client(&client);
629
630 system
631 .set_pin("first".into(), PinLockType::BeforeFirstUnlock)
632 .await
633 .expect("first set_pin");
634 system
635 .set_pin("second".into(), PinLockType::AfterFirstUnlock)
636 .await
637 .expect("second set_pin");
638
639 let bridge = client.km_state_bridge();
640 assert!(
641 bridge.get_persistent_pin_envelope().await.is_none(),
642 "switching to AFU must clear the persistent envelope"
643 );
644 assert_eq!(
645 system.get_pin_lock_type().await,
646 Some(PinLockType::AfterFirstUnlock)
647 );
648 assert!(system.validate_pin("second".into()).await);
649 assert!(!system.validate_pin("first".into()).await);
650 }
651
652 #[tokio::test]
653 async fn unset_pin_clears_all_state() {
654 let client = client_with_user_key();
655 let system = PinLockSystem::with_client(&client);
656
657 system
658 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
659 .await
660 .expect("set_pin succeeds");
661 system.unset_pin().await;
662
663 let bridge = client.km_state_bridge();
664 assert!(bridge.get_persistent_pin_envelope().await.is_none());
665 assert!(bridge.get_ephemeral_pin_envelope().await.is_none());
666 assert!(bridge.get_encrypted_pin().await.is_none());
667 assert_eq!(system.get_pin_lock_type().await, None);
668 assert_eq!(system.get_pin_status().await, PinUnlockStatus::NotSet);
669 }
670
671 #[tokio::test]
672 async fn unlock_with_correct_pin_persists_user_key() {
673 let client = client_with_user_key();
674 let system = PinLockSystem::with_client(&client);
675
676 let pre_unlock_user_key_id = user_key_id(&client);
677 system
679 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
680 .await
681 .expect("set_pin succeeds");
682 client.internal.get_key_store().clear();
683
684 assert!(system.unlock("1234").await.is_ok());
685 let post_unlock_user_key_id = user_key_id(&client);
686 assert_eq!(post_unlock_user_key_id, pre_unlock_user_key_id);
687 }
688
689 #[tokio::test]
690 async fn unlock_with_wrong_pin_returns_pin_wrong() {
691 let client = client_with_user_key();
692 let system = PinLockSystem::with_client(&client);
693 system
694 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
695 .await
696 .expect("set_pin succeeds");
697
698 assert!(matches!(
699 system.unlock("wrong").await,
700 Err(UnlockError::PinWrong)
701 ));
702 }
703
704 #[tokio::test]
705 async fn unlock_with_no_pin_set_returns_no_pin_set() {
706 let client = client_with_user_key();
707 let system = PinLockSystem::with_client(&client);
708
709 assert!(matches!(
710 system.unlock("anything").await,
711 Err(UnlockError::NoPinSet)
712 ));
713 }
714
715 #[tokio::test]
716 async fn unlock_prefers_ephemeral_envelope_over_persistent() {
717 let client = client_with_user_key();
718 let system = PinLockSystem::with_client(&client);
719 system
720 .set_pin("persistent".into(), PinLockType::BeforeFirstUnlock)
721 .await
722 .expect("set_pin succeeds");
723
724 let ephemeral = seal_envelope(&client, "ephemeral");
727 client
728 .km_state_bridge()
729 .set_ephemeral_pin_envelope(&ephemeral)
730 .await;
731
732 assert!(system.unlock("ephemeral").await.is_ok());
733 assert!(matches!(
734 system.unlock("persistent").await,
735 Err(UnlockError::PinWrong)
736 ));
737 }
738
739 #[tokio::test]
740 async fn get_pin_status_available_bfu() {
741 let client = client_with_user_key();
742 let system = PinLockSystem::with_client(&client);
743 system
744 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
745 .await
746 .expect("set_pin succeeds");
747
748 client
750 .km_state_bridge()
751 .clear_ephemeral_pin_envelope()
752 .await;
753
754 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
755 assert_eq!(
756 system.get_pin_lock_type().await,
757 Some(PinLockType::BeforeFirstUnlock)
758 );
759 }
760
761 #[tokio::test]
762 async fn on_unlock_rebuilds_ephemeral_envelope() {
763 let client = client_with_user_key();
764 let user_key_id = user_key_id(&client);
765 let system = PinLockSystem::with_client(&client);
766 system
767 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
768 .await
769 .expect("set_pin succeeds");
770 client
771 .km_state_bridge()
772 .clear_ephemeral_pin_envelope()
773 .await;
774 assert_eq!(system.get_pin_status().await, PinUnlockStatus::NeedsUnlock);
775
776 system.on_unlock().await;
777
778 let rebuilt = client
779 .km_state_bridge()
780 .get_ephemeral_pin_envelope()
781 .await
782 .expect("on_unlock should restore the ephemeral envelope");
783 assert_envelope_wraps_user_key(&client, &rebuilt, "1234", &user_key_id);
784 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
785 assert!(system.unlock("1234").await.is_ok());
786 }
787
788 #[tokio::test]
789 async fn on_unlock_is_noop_when_no_encrypted_pin() {
790 let client = client_with_user_key();
791 let system = PinLockSystem::with_client(&client);
792
793 system.on_unlock().await;
794
795 assert_eq!(system.get_pin_status().await, PinUnlockStatus::NotSet);
796 }
797
798 #[tokio::test]
799 async fn on_unlock_is_noop_when_bridge_not_registered() {
800 let client = Client::new(None);
801 let system = PinLockSystem::with_client(&client);
802
803 system.on_unlock().await;
805 }
806
807 #[tokio::test]
808 async fn get_pin_returns_set_pin() {
809 let client = client_with_user_key();
810 let system = PinLockSystem::with_client(&client);
811
812 assert_eq!(system.get_pin().await, None);
813
814 system
815 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
816 .await
817 .expect("set_pin succeeds");
818 assert_eq!(system.get_pin().await, Some("1234".to_owned()));
819
820 system.unset_pin().await;
821 assert_eq!(system.get_pin().await, None);
822 }
823
824 #[tokio::test]
825 async fn validate_pin_matches_only_correct_pin() {
826 let client = client_with_user_key();
827 let system = PinLockSystem::with_client(&client);
828
829 assert!(!system.validate_pin("anything".into()).await);
830
831 system
832 .set_pin("1234".into(), PinLockType::AfterFirstUnlock)
833 .await
834 .expect("set_pin succeeds");
835 assert!(system.validate_pin("1234".into()).await);
836 assert!(!system.validate_pin("wrong".into()).await);
837 }
838
839 struct V1State {
842 envelope: PasswordProtectedKeyEnvelope,
843 encrypted_pin: EncString,
844 token: V2UpgradeToken,
845 }
846
847 fn fresh_v1_state_with_v2_user_key(pin: &str) -> (Client, V1State) {
851 let client = Client::new(None);
852 client
853 .km_state_bridge()
854 .register_bridge(Box::new(InMemoryStateBridge::default()));
855
856 let state = {
857 let key_store = client.internal.get_key_store();
858 let mut ctx = key_store.context_mut();
859
860 let v1_local = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
861 let v2_local = ctx.make_symmetric_key(SymmetricKeyAlgorithm::XAes256Gcm);
862
863 let envelope = PasswordProtectedKeyEnvelope::seal(
864 v1_local,
865 pin,
866 PasswordProtectedKeyEnvelopeNamespace::PinUnlock,
867 &ctx,
868 )
869 .expect("v1 envelope seals");
870 let encrypted_pin = pin
871 .encrypt(&mut ctx, v1_local)
872 .expect("pin encrypts under v1 key");
873 let token =
874 V2UpgradeToken::create(v1_local, v2_local, &ctx).expect("upgrade token created");
875
876 ctx.persist_symmetric_key(v2_local, SymmetricKeySlotId::User)
877 .expect("persisting v2 user key succeeds");
878
879 V1State {
880 envelope,
881 encrypted_pin,
882 token,
883 }
884 };
885
886 (client, state)
887 }
888
889 fn client_with_v1_user_key() -> Client {
892 let client = Client::new(None);
893 client
894 .km_state_bridge()
895 .register_bridge(Box::new(InMemoryStateBridge::default()));
896 {
897 let key_store = client.internal.get_key_store();
898 let mut ctx = key_store.context_mut();
899 let user_key = ctx.generate_symmetric_key();
900 ctx.persist_symmetric_key(user_key, SymmetricKeySlotId::User)
901 .expect("persisting v1 user key should succeed");
902 }
903 client
904 }
905
906 fn assert_pin_envelopes_equal(
907 envelope_1: &PasswordProtectedKeyEnvelope,
908 envelope_2: &PasswordProtectedKeyEnvelope,
909 ) {
910 assert_eq!(
911 serde_json::to_string(envelope_1).expect("envelope serializes"),
912 serde_json::to_string(envelope_2).expect("envelope serializes"),
913 "envelopes should be identical",
914 );
915 }
916
917 async fn assert_pin_fully_unenrolled(client: &Client) {
918 let bridge = client.km_state_bridge();
919 assert!(bridge.get_persistent_pin_envelope().await.is_none());
920 assert!(bridge.get_ephemeral_pin_envelope().await.is_none());
921 assert!(bridge.get_encrypted_pin().await.is_none());
922 assert_eq!(
923 PinLockSystem::with_client(client).get_pin_status().await,
924 PinUnlockStatus::NotSet,
925 );
926 }
927
928 async fn store_v1_pin(client: &Client, state: &V1State, lock_type: &PinLockType) {
937 let bridge = client.km_state_bridge();
938 bridge.set_encrypted_pin(&state.encrypted_pin).await;
939 if *lock_type == PinLockType::BeforeFirstUnlock {
940 bridge.set_persistent_pin_envelope(&state.envelope).await;
941 }
942 }
943
944 #[tokio::test]
945 async fn migrate_without_pin_is_noop() {
946 let client = client_with_user_key();
947 let system = PinLockSystem::with_client(&client);
948
949 system
950 .migrate_pin_envelope_if_needed()
951 .await
952 .expect("migration succeeds");
953
954 assert_pin_fully_unenrolled(&client).await;
955 }
956
957 #[tokio::test]
959 async fn migrate_up_to_date_v2_pin_is_noop() {
960 let client = client_with_user_key();
961 let system = PinLockSystem::with_client(&client);
962 system
963 .set_pin("1234".into(), PinLockType::BeforeFirstUnlock)
964 .await
965 .expect("set_pin succeeds");
966
967 let bridge = client.km_state_bridge();
968 let persistent_before = bridge.get_persistent_pin_envelope().await.expect("present");
969 let encrypted_pin_before = bridge.get_encrypted_pin().await.expect("present");
970
971 system
972 .migrate_pin_envelope_if_needed()
973 .await
974 .expect("migration succeeds");
975
976 let persistent_after = bridge.get_persistent_pin_envelope().await.expect("present");
977 let encrypted_pin_after = bridge.get_encrypted_pin().await.expect("present");
978 assert_pin_envelopes_equal(&persistent_before, &persistent_after);
979 assert_eq!(
980 encrypted_pin_before.to_string(),
981 encrypted_pin_after.to_string()
982 );
983 }
984
985 #[tokio::test]
988 async fn migrate_up_to_date_v1_pin_is_noop() {
989 let client = client_with_v1_user_key();
990 let encrypted_pin = TESTVECTOR_LEGACY_ENVELOPE_PIN
991 .encrypt(
992 &mut client.internal.get_key_store().context_mut(),
993 SymmetricKeySlotId::User,
994 )
995 .expect("encrypt under v1 user key");
996
997 let bridge = client.km_state_bridge();
998 bridge.set_persistent_pin_envelope(&legacy_envelope()).await;
999 bridge.set_encrypted_pin(&encrypted_pin).await;
1000
1001 let system = PinLockSystem::with_client(&client);
1002 system
1003 .migrate_pin_envelope_if_needed()
1004 .await
1005 .expect("migration succeeds");
1006
1007 let persistent_after = bridge.get_persistent_pin_envelope().await.expect("present");
1008 let encrypted_pin_after = bridge.get_encrypted_pin().await.expect("present");
1009 assert_pin_envelopes_equal(&legacy_envelope(), &persistent_after);
1010 assert_eq!(encrypted_pin.to_string(), encrypted_pin_after.to_string());
1011 }
1012
1013 #[tokio::test]
1016 async fn migrate_v1_pin_with_v2_user_key_reenrolls() {
1017 for lock_type in [
1018 PinLockType::BeforeFirstUnlock,
1019 PinLockType::AfterFirstUnlock,
1020 ] {
1021 let pin = "1234";
1022 let (client, state) = fresh_v1_state_with_v2_user_key(pin);
1023 store_v1_pin(&client, &state, &lock_type).await;
1024 client
1025 .km_state_bridge()
1026 .set_v2_upgrade_token(&state.token)
1027 .await;
1028
1029 let system = PinLockSystem::with_client(&client);
1030 system
1031 .migrate_pin_envelope_if_needed()
1032 .await
1033 .expect("migration succeeds");
1034
1035 let bridge = client.km_state_bridge();
1036 let encrypted_pin = bridge.get_encrypted_pin().await.expect("present");
1037 let ephemeral = bridge.get_ephemeral_pin_envelope().await.expect("present");
1038
1039 assert_eq!(decrypt_encrypted_pin(&client, &encrypted_pin), pin);
1040 assert_envelope_wraps_user_key(&client, &ephemeral, pin, &user_key_id(&client));
1041 assert_eq!(system.get_pin_lock_type().await, Some(lock_type));
1042 assert!(system.unlock(pin).await.is_ok());
1043 }
1044 }
1045
1046 #[test]
1049 fn classify_v1_pin_with_key_id() {
1050 let user_key_id = KeyId::from([1; 16]);
1051 let other_key_id = KeyId::from([2; 16]);
1052
1053 assert_eq!(
1054 classify_encrypted_pin(
1055 Some(SymmetricKeyAlgorithm::Aes256CbcHmac),
1056 Some(&other_key_id),
1057 SymmetricKeyAlgorithm::XAes256Gcm,
1058 &user_key_id
1059 ),
1060 PinMigrationAction::MigrateV1ToV2,
1061 );
1062 assert_eq!(
1063 classify_encrypted_pin(
1064 Some(SymmetricKeyAlgorithm::Aes256CbcHmac),
1065 Some(&user_key_id),
1066 SymmetricKeyAlgorithm::Aes256CbcHmac,
1067 &user_key_id
1068 ),
1069 PinMigrationAction::UpToDate,
1070 );
1071 assert_eq!(
1072 classify_encrypted_pin(
1073 Some(SymmetricKeyAlgorithm::Aes256CbcHmac),
1074 Some(&other_key_id),
1075 SymmetricKeyAlgorithm::Aes256CbcHmac,
1076 &user_key_id
1077 ),
1078 PinMigrationAction::Failed(MigrationFailed::UnrecoverablePinKey),
1079 );
1080 }
1081
1082 #[tokio::test]
1084 async fn migrate_v2_pin_with_rotated_user_key_fails() {
1085 let client = client_with_user_key();
1086 let encrypted_pin = {
1087 let mut ctx = client.internal.get_key_store().context_mut();
1088 let other_v2 = ctx.make_symmetric_key(SymmetricKeyAlgorithm::XAes256Gcm);
1089 "1234"
1090 .encrypt(&mut ctx, other_v2)
1091 .expect("encrypt under other v2 key")
1092 };
1093 client
1094 .km_state_bridge()
1095 .set_encrypted_pin(&encrypted_pin)
1096 .await;
1097
1098 let system = PinLockSystem::with_client(&client);
1099 assert_eq!(
1100 system.migrate_pin_envelope_if_needed().await,
1101 Err(MigrationFailed::UnrecoverablePinKey),
1102 );
1103 }
1104
1105 #[tokio::test]
1106 async fn migrate_without_user_key_fails_locked() {
1107 let client = Client::new(None);
1108 client
1109 .km_state_bridge()
1110 .register_bridge(Box::new(InMemoryStateBridge::default()));
1111 let (_, state) = fresh_v1_state_with_v2_user_key("1234");
1112 client
1113 .km_state_bridge()
1114 .set_encrypted_pin(&state.encrypted_pin)
1115 .await;
1116
1117 let system = PinLockSystem::with_client(&client);
1118 assert_eq!(
1119 system.migrate_pin_envelope_if_needed().await,
1120 Err(MigrationFailed::Locked),
1121 );
1122 }
1123
1124 #[tokio::test]
1125 async fn migrate_envelope_without_encrypted_pin_fails() {
1126 let client = client_with_v1_user_key();
1127 client
1128 .km_state_bridge()
1129 .set_persistent_pin_envelope(&legacy_envelope())
1130 .await;
1131
1132 let system = PinLockSystem::with_client(&client);
1133 assert_eq!(
1134 system.migrate_pin_envelope_if_needed().await,
1135 Err(MigrationFailed::MissingEncryptedPin),
1136 );
1137 }
1138
1139 #[tokio::test]
1140 async fn migrate_v1_pin_without_token_fails() {
1141 let (client, state) = fresh_v1_state_with_v2_user_key("1234");
1142 store_v1_pin(&client, &state, &PinLockType::AfterFirstUnlock).await;
1143
1144 let system = PinLockSystem::with_client(&client);
1145 assert_eq!(
1146 system.migrate_pin_envelope_if_needed().await,
1147 Err(MigrationFailed::MissingV2UpgradeToken),
1148 );
1149 }
1150
1151 #[tokio::test]
1153 async fn migrate_v1_pin_with_mismatched_token_fails() {
1154 let (client, state) = fresh_v1_state_with_v2_user_key("1234");
1155 store_v1_pin(&client, &state, &PinLockType::AfterFirstUnlock).await;
1156
1157 let unrelated_token = {
1159 let mut ctx = client.internal.get_key_store().context_mut();
1160 let other_v1 = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
1161 V2UpgradeToken::create(other_v1, SymmetricKeySlotId::User, &ctx)
1162 .expect("unrelated token created")
1163 };
1164 client
1165 .km_state_bridge()
1166 .set_v2_upgrade_token(&unrelated_token)
1167 .await;
1168
1169 let system = PinLockSystem::with_client(&client);
1170 assert_eq!(
1171 system.migrate_pin_envelope_if_needed().await,
1172 Err(MigrationFailed::PinDecryption),
1173 );
1174 }
1175
1176 #[tokio::test]
1178 async fn on_unlock_restores_afu_pin_after_upgrade() {
1179 let pin = "1234";
1180 let (client, state) = fresh_v1_state_with_v2_user_key(pin);
1181 store_v1_pin(&client, &state, &PinLockType::AfterFirstUnlock).await;
1182 client
1183 .km_state_bridge()
1184 .set_v2_upgrade_token(&state.token)
1185 .await;
1186
1187 let system = PinLockSystem::with_client(&client);
1188 assert_eq!(system.get_pin_status().await, PinUnlockStatus::NeedsUnlock);
1189
1190 system.on_unlock().await;
1191
1192 assert_eq!(system.get_pin_status().await, PinUnlockStatus::Available);
1193 assert!(system.unlock(pin).await.is_ok());
1194 }
1195
1196 #[tokio::test]
1197 async fn on_unlock_unenrolls_when_migration_fails() {
1198 let (client, state) = fresh_v1_state_with_v2_user_key("1234");
1200 store_v1_pin(&client, &state, &PinLockType::BeforeFirstUnlock).await;
1201
1202 let system = PinLockSystem::with_client(&client);
1203 system.on_unlock().await;
1204
1205 assert_pin_fully_unenrolled(&client).await;
1206 }
1207}