1use std::{
2 cell::Cell,
3 sync::{RwLockReadGuard, RwLockWriteGuard},
4};
5
6use coset::iana::KeyOperation;
7use serde::Serialize;
8use tracing::instrument;
9use zeroize::Zeroizing;
10
11use super::KeyStoreInner;
12use crate::{
13 BitwardenLegacyKeyBytes, ContentFormat, CoseEncrypt0Bytes, CoseKeyBytes, CoseSerializable,
14 CryptoError, EncString, KeyDecryptable, KeyEncryptable, KeyId, KeySlotId, KeySlotIds, LocalId,
15 Pkcs8PrivateKeyBytes, PrivateKey, PublicKey, PublicKeyEncryptionAlgorithm, Result,
16 RotatedUserKeys, Signature, SignatureAlgorithm, SignedObject, SignedPublicKey,
17 SignedPublicKeyMessage, SigningKey, SymmetricCryptoKey, SymmetricKeyAlgorithm, VerifyingKey,
18 derive_shareable_key, error::UnsupportedOperationError, signing, store::backend::StoreBackend,
19};
20
21#[must_use]
80pub struct KeyStoreContext<'a, Ids: KeySlotIds> {
81 pub(super) global_keys: GlobalKeys<'a, Ids>,
82
83 pub(super) local_symmetric_keys: Box<dyn StoreBackend<Ids::Symmetric>>,
84 pub(super) local_private_keys: Box<dyn StoreBackend<Ids::Private>>,
85 pub(super) local_signing_keys: Box<dyn StoreBackend<Ids::Signing>>,
86
87 pub(super) security_state_version: u64,
88
89 pub(super) _phantom: std::marker::PhantomData<(Cell<()>, RwLockReadGuard<'static, ()>)>,
91}
92
93pub(crate) enum GlobalKeys<'a, Ids: KeySlotIds> {
99 ReadOnly(RwLockReadGuard<'a, KeyStoreInner<Ids>>),
100 ReadWrite(RwLockWriteGuard<'a, KeyStoreInner<Ids>>),
101}
102
103impl<Ids: KeySlotIds> GlobalKeys<'_, Ids> {
104 pub fn get(&self) -> &KeyStoreInner<Ids> {
110 match self {
111 GlobalKeys::ReadOnly(keys) => keys,
112 GlobalKeys::ReadWrite(keys) => keys,
113 }
114 }
115
116 pub fn get_mut(&mut self) -> Result<&mut KeyStoreInner<Ids>> {
125 match self {
126 GlobalKeys::ReadOnly(_) => Err(CryptoError::ReadOnlyKeyStore),
127 GlobalKeys::ReadWrite(keys) => Ok(keys),
128 }
129 }
130}
131
132impl<Ids: KeySlotIds> KeyStoreContext<'_, Ids> {
133 pub fn clear_local(&mut self) {
137 self.local_symmetric_keys.clear();
138 self.local_private_keys.clear();
139 self.local_signing_keys.clear();
140 }
141
142 pub fn get_security_state_version(&self) -> u64 {
146 self.security_state_version
147 }
148
149 pub fn retain_symmetric_keys(&mut self, f: fn(Ids::Symmetric) -> bool) {
152 if let Ok(keys) = self.global_keys.get_mut() {
153 keys.symmetric_keys.retain(f);
154 }
155 self.local_symmetric_keys.retain(f);
156 }
157
158 pub fn retain_private_keys(&mut self, f: fn(Ids::Private) -> bool) {
161 if let Ok(keys) = self.global_keys.get_mut() {
162 keys.private_keys.retain(f);
163 }
164 self.local_private_keys.retain(f);
165 }
166
167 pub fn drop_symmetric_key(&mut self, key_id: Ids::Symmetric) -> Result<()> {
171 if key_id.is_local() {
172 self.local_symmetric_keys.remove(key_id);
173 } else {
174 self.global_keys.get_mut()?.symmetric_keys.remove(key_id);
175 }
176 Ok(())
177 }
178
179 pub fn drop_private_key(&mut self, key_id: Ids::Private) -> Result<()> {
183 if key_id.is_local() {
184 self.local_private_keys.remove(key_id);
185 } else {
186 self.global_keys.get_mut()?.private_keys.remove(key_id);
187 }
188 Ok(())
189 }
190
191 pub fn drop_signing_key(&mut self, key_id: Ids::Signing) -> Result<()> {
195 if key_id.is_local() {
196 self.local_signing_keys.remove(key_id);
197 } else {
198 self.global_keys.get_mut()?.signing_keys.remove(key_id);
199 }
200 Ok(())
201 }
202
203 #[instrument(skip(self, wrapped_key), err)]
216 pub fn unwrap_symmetric_key(
217 &mut self,
218 wrapping_key: Ids::Symmetric,
219 wrapped_key: &EncString,
220 ) -> Result<Ids::Symmetric> {
221 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
222
223 let key = match (wrapped_key, wrapping_key) {
224 (EncString::Aes256Cbc_B64 { .. }, SymmetricCryptoKey::Aes256CbcKey(_)) => {
225 return Err(CryptoError::OperationNotSupported(
226 UnsupportedOperationError::DecryptionNotImplementedForKey,
227 ));
228 }
229 (
230 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
231 SymmetricCryptoKey::Aes256CbcHmacKey(key),
232 ) => SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(
233 crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key)
234 .map_err(|_| CryptoError::Decrypt)?,
235 ))?,
236 (
237 EncString::Cose_Encrypt0_B64 { data },
238 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
239 ) => {
240 let (content_bytes, content_format) = crate::cose::decrypt_xchacha20_poly1305(
241 &CoseEncrypt0Bytes::from(data.clone()),
242 key,
243 )?;
244 match content_format {
245 ContentFormat::BitwardenLegacyKey => {
246 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(content_bytes))?
247 }
248 ContentFormat::CoseKey => SymmetricCryptoKey::try_from_cose(&content_bytes)?,
249 _ => return Err(CryptoError::InvalidKey),
250 }
251 }
252 _ => {
253 tracing::warn!(
254 "Unsupported unwrap operation for the given key and data {:?}, {:?}",
255 wrapping_key,
256 wrapped_key
257 );
258 return Err(CryptoError::InvalidKey);
259 }
260 };
261
262 let new_key_id = Ids::Symmetric::new_local(LocalId::new());
263
264 #[allow(deprecated)]
265 self.set_symmetric_key(new_key_id, key)?;
266
267 Ok(new_key_id)
269 }
270
271 pub fn persist_symmetric_key(
279 &mut self,
280 from: Ids::Symmetric,
281 to: Ids::Symmetric,
282 ) -> Result<()> {
283 if !from.is_local() || to.is_local() {
284 return Err(CryptoError::InvalidKeyStoreOperation);
285 }
286 let key = self.get_symmetric_key(from)?.to_owned();
287 self.drop_symmetric_key(from)?;
288 #[allow(deprecated)]
289 self.set_symmetric_key(to, key)?;
290 Ok(())
291 }
292
293 pub fn persist_private_key(&mut self, from: Ids::Private, to: Ids::Private) -> Result<()> {
301 if !from.is_local() || to.is_local() {
302 return Err(CryptoError::InvalidKeyStoreOperation);
303 }
304 let key = self.get_private_key(from)?.to_owned();
305 self.drop_private_key(from)?;
306 #[allow(deprecated)]
307 self.set_private_key(to, key)?;
308 Ok(())
309 }
310
311 pub fn persist_signing_key(&mut self, from: Ids::Signing, to: Ids::Signing) -> Result<()> {
318 if !from.is_local() || to.is_local() {
319 return Err(CryptoError::InvalidKeyStoreOperation);
320 }
321 let key = self.get_signing_key(from)?.to_owned();
322 self.drop_signing_key(from)?;
323 #[allow(deprecated)]
324 self.set_signing_key(to, key)?;
325 Ok(())
326 }
327
328 pub fn wrap_signing_key(
337 &self,
338 wrapping_key: Ids::Symmetric,
339 key_to_wrap: Ids::Signing,
340 ) -> Result<EncString> {
341 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
342 let signing_key = self.get_signing_key(key_to_wrap)?.to_owned();
343 signing_key.to_cose().encrypt_with_key(wrapping_key)
344 }
345
346 pub fn wrap_private_key(
354 &self,
355 wrapping_key: Ids::Symmetric,
356 key_to_wrap: Ids::Private,
357 ) -> Result<EncString> {
358 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
359 let private_key = self.get_private_key(key_to_wrap)?.to_owned();
360 private_key.to_der()?.encrypt_with_key(wrapping_key)
361 }
362
363 #[instrument(skip(self, wrapped_key), err)]
372 pub fn unwrap_private_key(
373 &mut self,
374 wrapping_key: Ids::Symmetric,
375 wrapped_key: &EncString,
376 ) -> Result<Ids::Private> {
377 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
378 let private_key_bytes: Vec<u8> = wrapped_key.decrypt_with_key(wrapping_key)?;
379 let private_key = PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(private_key_bytes))?;
380 Ok(self.add_local_private_key(private_key))
381 }
382
383 pub fn unwrap_signing_key(
392 &mut self,
393 wrapping_key: Ids::Symmetric,
394 wrapped_key: &EncString,
395 ) -> Result<Ids::Signing> {
396 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
397 let signing_key_bytes: Vec<u8> = wrapped_key.decrypt_with_key(wrapping_key)?;
398 let signing_key = SigningKey::from_cose(&CoseKeyBytes::from(signing_key_bytes))?;
399 Ok(self.add_local_signing_key(signing_key))
400 }
401
402 pub fn get_verifying_key(&self, signing_key_id: Ids::Signing) -> Result<VerifyingKey> {
410 let signing_key = self.get_signing_key(signing_key_id)?;
411 Ok(signing_key.to_verifying_key())
412 }
413
414 pub fn get_public_key(&self, private_key_id: Ids::Private) -> Result<PublicKey> {
421 let private_key = self.get_private_key(private_key_id)?;
422 Ok(private_key.to_public_key())
423 }
424
425 pub fn wrap_symmetric_key(
434 &self,
435 wrapping_key: Ids::Symmetric,
436 key_to_wrap: Ids::Symmetric,
437 ) -> Result<EncString> {
438 use SymmetricCryptoKey::*;
439
440 let wrapping_key_instance = self.get_symmetric_key(wrapping_key)?;
441 let key_to_wrap_instance = self.get_symmetric_key(key_to_wrap)?;
442 match (wrapping_key_instance, key_to_wrap_instance) {
448 (
449 Aes256CbcHmacKey(_),
450 Aes256CbcHmacKey(_) | Aes256CbcKey(_) | XChaCha20Poly1305Key(_),
451 ) => self.encrypt_data_with_symmetric_key(
452 wrapping_key,
453 key_to_wrap_instance
454 .to_encoded()
455 .as_ref()
456 .to_vec()
457 .as_slice(),
458 ContentFormat::BitwardenLegacyKey,
459 ),
460 (XChaCha20Poly1305Key(_), _) => {
461 let encoded = key_to_wrap_instance.to_encoded_raw();
462 let content_format = encoded.content_format();
463 self.encrypt_data_with_symmetric_key(
464 wrapping_key,
465 Into::<Vec<u8>>::into(encoded).as_slice(),
466 content_format,
467 )
468 }
469 _ => Err(CryptoError::OperationNotSupported(
470 UnsupportedOperationError::EncryptionNotImplementedForKey,
471 )),
472 }
473 }
474
475 pub fn has_symmetric_key(&self, key_id: Ids::Symmetric) -> bool {
477 self.get_symmetric_key(key_id).is_ok()
478 }
479
480 pub fn has_private_key(&self, key_id: Ids::Private) -> bool {
482 self.get_private_key(key_id).is_ok()
483 }
484
485 pub fn has_signing_key(&self, key_id: Ids::Signing) -> bool {
487 self.get_signing_key(key_id).is_ok()
488 }
489
490 pub fn generate_symmetric_key(&mut self) -> Ids::Symmetric {
492 self.add_local_symmetric_key(SymmetricCryptoKey::make_aes256_cbc_hmac_key())
493 }
494
495 pub fn make_symmetric_key(&mut self, algorithm: SymmetricKeyAlgorithm) -> Ids::Symmetric {
498 self.add_local_symmetric_key(SymmetricCryptoKey::make(algorithm))
499 }
500
501 pub fn make_private_key(&mut self, algorithm: PublicKeyEncryptionAlgorithm) -> Ids::Private {
504 self.add_local_private_key(PrivateKey::make(algorithm))
505 }
506
507 pub fn make_signing_key(&mut self, algorithm: SignatureAlgorithm) -> Ids::Signing {
510 self.add_local_signing_key(SigningKey::make(algorithm))
511 }
512
513 pub fn derive_shareable_key(
518 &mut self,
519 secret: Zeroizing<[u8; 16]>,
520 name: &str,
521 info: Option<&str>,
522 ) -> Result<Ids::Symmetric> {
523 let key_id = Ids::Symmetric::new_local(LocalId::new());
524 #[allow(deprecated)]
525 self.set_symmetric_key(
526 key_id,
527 SymmetricCryptoKey::Aes256CbcHmacKey(derive_shareable_key(secret, name, info)),
528 )?;
529 Ok(key_id)
530 }
531
532 #[deprecated(note = "This function should ideally never be used outside this crate")]
542 pub fn dangerous_get_symmetric_key(
543 &self,
544 key_id: Ids::Symmetric,
545 ) -> Result<&SymmetricCryptoKey> {
546 self.get_symmetric_key(key_id)
547 }
548
549 pub fn get_symmetric_key_id(&self, key_slot_id: Ids::Symmetric) -> Option<KeyId> {
551 let Ok(key) = self.get_symmetric_key(key_slot_id) else {
552 return None;
553 };
554 key.key_id()
555 }
556
557 #[deprecated(note = "This function should ideally never be used outside this crate")]
568 pub fn dangerous_get_signing_key(&self, key_id: Ids::Signing) -> Result<&SigningKey> {
569 self.get_signing_key(key_id)
570 }
571
572 #[deprecated(note = "This function should ideally never be used outside this crate")]
581 pub fn dangerous_get_private_key(&self, key_id: Ids::Private) -> Result<&PrivateKey> {
582 self.get_private_key(key_id)
583 }
584
585 pub fn make_signed_public_key(
589 &self,
590 private_key_id: Ids::Private,
591 signing_key_id: Ids::Signing,
592 ) -> Result<SignedPublicKey> {
593 let public_key = self.get_private_key(private_key_id)?.to_public_key();
594 let signing_key = self.get_signing_key(signing_key_id)?;
595 let signed_public_key =
596 SignedPublicKeyMessage::from_public_key(&public_key)?.sign(signing_key)?;
597 Ok(signed_public_key)
598 }
599
600 pub(crate) fn get_symmetric_key(&self, key_id: Ids::Symmetric) -> Result<&SymmetricCryptoKey> {
601 if key_id.is_local() {
602 self.local_symmetric_keys.get(key_id)
603 } else {
604 self.global_keys.get().symmetric_keys.get(key_id)
605 }
606 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
607 }
608
609 pub(super) fn get_private_key(&self, key_id: Ids::Private) -> Result<&PrivateKey> {
610 if key_id.is_local() {
611 self.local_private_keys.get(key_id)
612 } else {
613 self.global_keys.get().private_keys.get(key_id)
614 }
615 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
616 }
617
618 pub(super) fn get_signing_key(&self, key_id: Ids::Signing) -> Result<&SigningKey> {
619 if key_id.is_local() {
620 self.local_signing_keys.get(key_id)
621 } else {
622 self.global_keys.get().signing_keys.get(key_id)
623 }
624 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
625 }
626
627 #[deprecated(note = "This function should ideally never be used outside this crate")]
633 pub fn set_symmetric_key(
634 &mut self,
635 key_id: Ids::Symmetric,
636 key: SymmetricCryptoKey,
637 ) -> Result<()> {
638 self.set_symmetric_key_internal(key_id, key)
639 }
640
641 pub(crate) fn set_symmetric_key_internal(
642 &mut self,
643 key_id: Ids::Symmetric,
644 key: SymmetricCryptoKey,
645 ) -> Result<()> {
646 if key_id.is_local() {
647 self.local_symmetric_keys.upsert(key_id, key);
648 } else {
649 self.global_keys
650 .get_mut()?
651 .symmetric_keys
652 .upsert(key_id, key);
653 }
654 Ok(())
655 }
656
657 pub fn add_local_symmetric_key(&mut self, key: SymmetricCryptoKey) -> Ids::Symmetric {
659 let key_id = Ids::Symmetric::new_local(LocalId::new());
660 self.local_symmetric_keys.upsert(key_id, key);
661 key_id
662 }
663
664 pub fn get_symmetric_key_algorithm(
666 &self,
667 key_id: Ids::Symmetric,
668 ) -> Result<SymmetricKeyAlgorithm> {
669 let key = self.get_symmetric_key(key_id)?;
670 match key {
671 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
673 UnsupportedOperationError::EncryptionNotImplementedForKey,
674 )),
675 SymmetricCryptoKey::Aes256CbcHmacKey(_) => Ok(SymmetricKeyAlgorithm::Aes256CbcHmac),
676 SymmetricCryptoKey::XChaCha20Poly1305Key(_) => {
677 Ok(SymmetricKeyAlgorithm::XChaCha20Poly1305)
678 }
679 }
680 }
681
682 #[deprecated(note = "This function should ideally never be used outside this crate")]
688 pub fn set_private_key(&mut self, key_id: Ids::Private, key: PrivateKey) -> Result<()> {
689 if key_id.is_local() {
690 self.local_private_keys.upsert(key_id, key);
691 } else {
692 self.global_keys.get_mut()?.private_keys.upsert(key_id, key);
693 }
694 Ok(())
695 }
696
697 pub fn add_local_private_key(&mut self, key: PrivateKey) -> Ids::Private {
699 let key_id = Ids::Private::new_local(LocalId::new());
700 self.local_private_keys.upsert(key_id, key);
701 key_id
702 }
703
704 #[deprecated(note = "This function should ideally never be used outside this crate")]
710 pub fn set_signing_key(&mut self, key_id: Ids::Signing, key: SigningKey) -> Result<()> {
711 if key_id.is_local() {
712 self.local_signing_keys.upsert(key_id, key);
713 } else {
714 self.global_keys.get_mut()?.signing_keys.upsert(key_id, key);
715 }
716 Ok(())
717 }
718
719 pub fn add_local_signing_key(&mut self, key: SigningKey) -> Ids::Signing {
721 let key_id = Ids::Signing::new_local(LocalId::new());
722 self.local_signing_keys.upsert(key_id, key);
723 key_id
724 }
725
726 #[instrument(skip(self, data), err)]
727 pub(crate) fn decrypt_data_with_symmetric_key(
728 &self,
729 key: Ids::Symmetric,
730 data: &EncString,
731 ) -> Result<Vec<u8>> {
732 let key = self.get_symmetric_key(key)?;
733
734 match (data, key) {
735 (EncString::Aes256Cbc_B64 { .. }, SymmetricCryptoKey::Aes256CbcKey(_)) => {
736 Err(CryptoError::OperationNotSupported(
737 UnsupportedOperationError::DecryptionNotImplementedForKey,
738 ))
739 }
740 (
741 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
742 SymmetricCryptoKey::Aes256CbcHmacKey(key),
743 ) => crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key)
744 .map_err(|_| CryptoError::Decrypt),
745 (
746 EncString::Cose_Encrypt0_B64 { data },
747 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
748 ) => {
749 let (data, _) = crate::cose::decrypt_xchacha20_poly1305(
750 &CoseEncrypt0Bytes::from(data.clone()),
751 key,
752 )?;
753 Ok(data)
754 }
755 _ => {
756 tracing::warn!("Unsupported decryption operation for the given key and data");
757 Err(CryptoError::InvalidKey)
758 }
759 }
760 }
761
762 pub(crate) fn encrypt_data_with_symmetric_key(
763 &self,
764 key: Ids::Symmetric,
765 data: &[u8],
766 content_format: ContentFormat,
767 ) -> Result<EncString> {
768 let key = self.get_symmetric_key(key)?;
769 match key {
770 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
771 UnsupportedOperationError::EncryptionNotImplementedForKey,
772 )),
773 SymmetricCryptoKey::Aes256CbcHmacKey(key) => EncString::encrypt_aes256_hmac(data, key),
774 SymmetricCryptoKey::XChaCha20Poly1305Key(key) => {
775 if !key.supported_operations.contains(&KeyOperation::Encrypt) {
776 return Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt));
777 }
778 EncString::encrypt_xchacha20_poly1305(data, key, content_format)
779 }
780 }
781 }
782
783 pub fn sign<Message: Serialize>(
787 &self,
788 key: Ids::Signing,
789 message: &Message,
790 namespace: &crate::SigningNamespace,
791 ) -> Result<SignedObject> {
792 self.get_signing_key(key)?.sign(message, namespace)
793 }
794
795 #[allow(unused)]
799 pub(crate) fn sign_detached<Message: Serialize>(
800 &self,
801 key: Ids::Signing,
802 message: &Message,
803 namespace: &crate::SigningNamespace,
804 ) -> Result<(Signature, signing::SerializedMessage)> {
805 self.get_signing_key(key)?.sign_detached(message, namespace)
806 }
807
808 pub fn dangerous_get_v2_rotated_account_keys(
810 &self,
811 current_user_private_key_id: Ids::Private,
812 current_user_signing_key_id: Ids::Signing,
813 ) -> Result<RotatedUserKeys> {
814 #[expect(deprecated)]
815 crate::dangerous_get_v2_rotated_account_keys(
816 current_user_private_key_id,
817 current_user_signing_key_id,
818 self,
819 )
820 }
821
822 #[cfg(any(test, feature = "test-utils"))]
825 pub fn assert_symmetric_keys_equal(&self, key_id_1: Ids::Symmetric, key_id_2: Ids::Symmetric) {
826 let key_1 = self
827 .get_symmetric_key(key_id_1)
828 .expect("Key 1 should exist in context");
829 let key_2 = self
830 .get_symmetric_key(key_id_2)
831 .expect("Key 2 should exist in context");
832 if key_1 != key_2 {
833 panic!(
834 "Symmetric keys with ids {:?} and {:?} are not equal",
835 key_id_1, key_id_2,
836 );
837 }
838 }
839}
840
841#[cfg(test)]
842#[allow(deprecated)]
843mod tests {
844 use serde::{Deserialize, Serialize};
845
846 use crate::{
847 CompositeEncryptable, CoseKeyBytes, CoseSerializable, CryptoError, Decryptable, EncString,
848 KeyDecryptable, Pkcs8PrivateKeyBytes, PrivateKey, PublicKey, PublicKeyEncryptionAlgorithm,
849 SignatureAlgorithm, SigningKey, SigningNamespace, SymmetricCryptoKey,
850 SymmetricKeyAlgorithm,
851 store::{
852 KeyStore,
853 tests::{Data, DataView},
854 },
855 traits::tests::{TestIds, TestSigningKey, TestSymmKey},
856 };
857
858 #[test]
859 fn test_set_signing_key() {
860 let store: KeyStore<TestIds> = KeyStore::default();
861
862 let key_a0_id = TestSigningKey::A(0);
864 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
865 store
866 .context_mut()
867 .set_signing_key(key_a0_id, key_a0)
868 .unwrap();
869 }
870
871 #[test]
872 fn test_set_keys_for_encryption() {
873 let store: KeyStore<TestIds> = KeyStore::default();
874
875 let key_a0_id = TestSymmKey::A(0);
877 let mut ctx = store.context_mut();
878 let local_key_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
879 ctx.persist_symmetric_key(local_key_id, TestSymmKey::A(0))
880 .unwrap();
881
882 assert!(ctx.has_symmetric_key(key_a0_id));
883
884 let data = DataView("Hello, World!".to_string(), key_a0_id);
886 let _encrypted: Data = data.encrypt_composite(&mut ctx, key_a0_id).unwrap();
887 }
888
889 #[test]
890 fn test_key_encryption() {
891 let store: KeyStore<TestIds> = KeyStore::default();
892
893 let mut ctx = store.context();
894
895 let key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
897
898 assert!(ctx.has_symmetric_key(key_1_id));
899
900 let key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
902
903 assert!(ctx.has_symmetric_key(key_2_id));
904
905 let key_2_enc = ctx.wrap_symmetric_key(key_1_id, key_2_id).unwrap();
907
908 let new_key_id = ctx.unwrap_symmetric_key(key_1_id, &key_2_enc).unwrap();
910
911 let data = DataView("Hello, World!".to_string(), key_2_id);
915 let encrypted = data.encrypt_composite(&mut ctx, key_2_id).unwrap();
916
917 let decrypted1 = encrypted.decrypt(&mut ctx, key_2_id).unwrap();
918 let decrypted2 = encrypted.decrypt(&mut ctx, new_key_id).unwrap();
919
920 assert_eq!(decrypted1.0, decrypted2.0);
922 }
923
924 #[test]
925 fn test_wrap_unwrap() {
926 let store: KeyStore<TestIds> = KeyStore::default();
927 let mut ctx = store.context_mut();
928
929 let key_aes_1_id = TestSymmKey::A(1);
931 let local_key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
932 ctx.persist_symmetric_key(local_key_1_id, key_aes_1_id)
933 .unwrap();
934 let key_aes_2_id = TestSymmKey::A(2);
935 let local_key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
936 ctx.persist_symmetric_key(local_key_2_id, key_aes_2_id)
937 .unwrap();
938
939 let key_xchacha_3_id = TestSymmKey::A(3);
941 let key_xchacha_3 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
942 ctx.set_symmetric_key(key_xchacha_3_id, key_xchacha_3.clone())
943 .unwrap();
944 let key_xchacha_4_id = TestSymmKey::A(4);
945 let key_xchacha_4 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
946 ctx.set_symmetric_key(key_xchacha_4_id, key_xchacha_4.clone())
947 .unwrap();
948
949 let wrapped_key_1_2 = ctx.wrap_symmetric_key(key_aes_1_id, key_aes_2_id).unwrap();
951 let wrapped_key_1_3 = ctx
952 .wrap_symmetric_key(key_aes_1_id, key_xchacha_3_id)
953 .unwrap();
954 let wrapped_key_3_1 = ctx
955 .wrap_symmetric_key(key_xchacha_3_id, key_aes_1_id)
956 .unwrap();
957 let wrapped_key_3_4 = ctx
958 .wrap_symmetric_key(key_xchacha_3_id, key_xchacha_4_id)
959 .unwrap();
960
961 let _unwrapped_key_2 = ctx
963 .unwrap_symmetric_key(key_aes_1_id, &wrapped_key_1_2)
964 .unwrap();
965 let _unwrapped_key_3 = ctx
966 .unwrap_symmetric_key(key_aes_1_id, &wrapped_key_1_3)
967 .unwrap();
968 let _unwrapped_key_1 = ctx
969 .unwrap_symmetric_key(key_xchacha_3_id, &wrapped_key_3_1)
970 .unwrap();
971 let _unwrapped_key_4 = ctx
972 .unwrap_symmetric_key(key_xchacha_3_id, &wrapped_key_3_4)
973 .unwrap();
974 }
975
976 #[test]
977 fn test_signing() {
978 let store: KeyStore<TestIds> = KeyStore::default();
979
980 let key_a0_id = TestSigningKey::A(0);
982 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
983 let verifying_key = key_a0.to_verifying_key();
984 store
985 .context_mut()
986 .set_signing_key(key_a0_id, key_a0)
987 .unwrap();
988
989 assert!(store.context().has_signing_key(key_a0_id));
990
991 #[derive(Serialize, Deserialize)]
993 struct TestData {
994 data: String,
995 }
996 let signed_object = store
997 .context()
998 .sign(
999 key_a0_id,
1000 &TestData {
1001 data: "Hello".to_string(),
1002 },
1003 &SigningNamespace::ExampleNamespace,
1004 )
1005 .unwrap();
1006 let payload: Result<TestData, CryptoError> =
1007 signed_object.verify_and_unwrap(&verifying_key, &SigningNamespace::ExampleNamespace);
1008 assert!(payload.is_ok());
1009
1010 let (signature, serialized_message) = store
1011 .context()
1012 .sign_detached(
1013 key_a0_id,
1014 &TestData {
1015 data: "Hello".to_string(),
1016 },
1017 &SigningNamespace::ExampleNamespace,
1018 )
1019 .unwrap();
1020 assert!(signature.verify(
1021 serialized_message.as_bytes(),
1022 &verifying_key,
1023 &SigningNamespace::ExampleNamespace
1024 ))
1025 }
1026
1027 #[test]
1028 fn test_account_key_rotation() {
1029 let store: KeyStore<TestIds> = KeyStore::default();
1030 let mut ctx = store.context_mut();
1031
1032 let current_user_signing_key_id = ctx.make_signing_key(SignatureAlgorithm::Ed25519);
1034 let current_user_private_key_id =
1035 ctx.make_private_key(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
1036
1037 let rotated_keys = ctx
1039 .dangerous_get_v2_rotated_account_keys(
1040 current_user_private_key_id,
1041 current_user_signing_key_id,
1042 )
1043 .unwrap();
1044
1045 assert_eq!(
1047 PublicKey::from_der(&rotated_keys.public_key)
1048 .unwrap()
1049 .to_der()
1050 .unwrap(),
1051 ctx.get_private_key(current_user_private_key_id)
1052 .unwrap()
1053 .to_public_key()
1054 .to_der()
1055 .unwrap()
1056 );
1057 let decrypted_private_key: Vec<u8> = rotated_keys
1058 .private_key
1059 .decrypt_with_key(&rotated_keys.user_key)
1060 .unwrap();
1061 let private_key =
1062 PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key)).unwrap();
1063 assert_eq!(
1064 private_key.to_der().unwrap(),
1065 ctx.get_private_key(current_user_private_key_id)
1066 .unwrap()
1067 .to_der()
1068 .unwrap()
1069 );
1070
1071 let decrypted_signing_key: Vec<u8> = rotated_keys
1073 .signing_key
1074 .decrypt_with_key(&rotated_keys.user_key)
1075 .unwrap();
1076 let signing_key =
1077 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
1078 assert_eq!(
1079 signing_key.to_cose(),
1080 ctx.get_signing_key(current_user_signing_key_id)
1081 .unwrap()
1082 .to_cose(),
1083 );
1084
1085 let signed_public_key = rotated_keys.signed_public_key;
1087 let unwrapped_key = signed_public_key
1088 .verify_and_unwrap(
1089 &ctx.get_signing_key(current_user_signing_key_id)
1090 .unwrap()
1091 .to_verifying_key(),
1092 )
1093 .unwrap();
1094 assert_eq!(
1095 unwrapped_key.to_der().unwrap(),
1096 ctx.get_private_key(current_user_private_key_id)
1097 .unwrap()
1098 .to_public_key()
1099 .to_der()
1100 .unwrap()
1101 );
1102 }
1103
1104 #[test]
1105 fn test_encrypt_fails_when_operation_not_allowed() {
1106 use coset::iana::KeyOperation;
1107 let store = KeyStore::<TestIds>::default();
1108 let mut ctx = store.context_mut();
1109 let key_id = TestSymmKey::A(0);
1110 let key = SymmetricCryptoKey::XChaCha20Poly1305Key(crate::XChaCha20Poly1305Key {
1112 key_id: [0u8; 16].into(),
1113 enc_key: Box::pin([0u8; 32].into()),
1114 supported_operations: vec![KeyOperation::Decrypt],
1115 });
1116 ctx.set_symmetric_key(key_id, key).unwrap();
1117 let data = DataView("should fail".to_string(), key_id);
1118 let result = data.encrypt_composite(&mut ctx, key_id);
1119 assert!(
1120 matches!(
1121 result,
1122 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1123 ),
1124 "Expected encrypt to fail with KeyOperationNotSupported",
1125 );
1126 }
1127
1128 #[test]
1129 fn test_move_key() {
1130 let store: KeyStore<TestIds> = KeyStore::default();
1131 let mut ctx = store.context_mut();
1132
1133 let key = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
1135
1136 assert!(ctx.has_symmetric_key(key));
1137
1138 let new_key_id = TestSymmKey::A(1);
1140 ctx.persist_symmetric_key(key, new_key_id).unwrap();
1141
1142 assert!(!ctx.has_symmetric_key(key));
1144 assert!(ctx.has_symmetric_key(new_key_id));
1145 }
1146
1147 #[test]
1148 fn test_encrypt_decrypt_data_fails_when_key_is_type_0() {
1149 let store = KeyStore::<TestIds>::default();
1150 let mut ctx = store.context_mut();
1151
1152 let key_id = TestSymmKey::A(0);
1153 let key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1154 enc_key: Box::pin([0u8; 32].into()),
1155 });
1156 ctx.set_symmetric_key_internal(key_id, key).unwrap();
1157
1158 let data_to_encrypt: Vec<u8> = vec![1, 2, 3, 4, 5];
1159 let result = ctx.encrypt_data_with_symmetric_key(
1160 key_id,
1161 &data_to_encrypt,
1162 crate::ContentFormat::OctetStream,
1163 );
1164 assert!(
1165 matches!(
1166 result,
1167 Err(CryptoError::OperationNotSupported(
1168 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1169 ))
1170 ),
1171 "Expected encrypt to fail when using deprecated type 0 keys",
1172 );
1173
1174 let data_to_decrypt = EncString::Aes256Cbc_B64 {
1175 iv: [0; 16],
1176 data: data_to_encrypt,
1177 }; let result = ctx.decrypt_data_with_symmetric_key(key_id, &data_to_decrypt);
1179 assert!(
1180 matches!(
1181 result,
1182 Err(CryptoError::OperationNotSupported(
1183 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1184 ))
1185 ),
1186 "Expected decrypt to fail when using deprecated type 0 keys",
1187 );
1188 }
1189
1190 #[test]
1191 fn test_wrap_unwrap_key_fails_when_key_is_type_0() {
1192 let store = KeyStore::<TestIds>::default();
1193 let mut ctx = store.context_mut();
1194
1195 let wrapping_key_id = TestSymmKey::A(0);
1196 let wrapping_key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1197 enc_key: Box::pin([0u8; 32].into()),
1198 });
1199 ctx.set_symmetric_key_internal(wrapping_key_id, wrapping_key)
1200 .unwrap();
1201
1202 let key_to_wrap_id = TestSymmKey::A(1);
1203 let key_to_wrap = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
1204 ctx.set_symmetric_key_internal(key_to_wrap_id, key_to_wrap)
1205 .unwrap();
1206
1207 let result = ctx.wrap_symmetric_key(wrapping_key_id, key_to_wrap_id);
1208 assert!(
1209 matches!(
1210 result,
1211 Err(CryptoError::OperationNotSupported(
1212 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1213 ))
1214 ),
1215 "Expected encrypt to fail when using deprecated type 0 keys",
1216 );
1217
1218 let wrapped_key = &EncString::Aes256Cbc_B64 {
1219 iv: [0; 16],
1220 data: vec![0],
1221 }; let result = ctx.unwrap_symmetric_key(wrapping_key_id, wrapped_key);
1223 assert!(
1224 matches!(
1225 result,
1226 Err(CryptoError::OperationNotSupported(
1227 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1228 ))
1229 ),
1230 "Expected decrypt to fail when using deprecated type 0 keys",
1231 );
1232 }
1233}