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 #[instrument(skip(self), err)]
684 pub fn is_v1_symmetric_key(&self, key_id: Ids::Symmetric) -> Result<bool> {
685 let algorithm = self.get_symmetric_key_algorithm(key_id)?;
686 Ok(algorithm == SymmetricKeyAlgorithm::Aes256CbcHmac)
687 }
688
689 #[deprecated(note = "This function should ideally never be used outside this crate")]
695 pub fn set_private_key(&mut self, key_id: Ids::Private, key: PrivateKey) -> Result<()> {
696 if key_id.is_local() {
697 self.local_private_keys.upsert(key_id, key);
698 } else {
699 self.global_keys.get_mut()?.private_keys.upsert(key_id, key);
700 }
701 Ok(())
702 }
703
704 pub fn add_local_private_key(&mut self, key: PrivateKey) -> Ids::Private {
706 let key_id = Ids::Private::new_local(LocalId::new());
707 self.local_private_keys.upsert(key_id, key);
708 key_id
709 }
710
711 #[deprecated(note = "This function should ideally never be used outside this crate")]
717 pub fn set_signing_key(&mut self, key_id: Ids::Signing, key: SigningKey) -> Result<()> {
718 if key_id.is_local() {
719 self.local_signing_keys.upsert(key_id, key);
720 } else {
721 self.global_keys.get_mut()?.signing_keys.upsert(key_id, key);
722 }
723 Ok(())
724 }
725
726 pub fn add_local_signing_key(&mut self, key: SigningKey) -> Ids::Signing {
728 let key_id = Ids::Signing::new_local(LocalId::new());
729 self.local_signing_keys.upsert(key_id, key);
730 key_id
731 }
732
733 #[instrument(skip(self, data), err)]
734 pub(crate) fn decrypt_data_with_symmetric_key(
735 &self,
736 key: Ids::Symmetric,
737 data: &EncString,
738 ) -> Result<Vec<u8>> {
739 let key = self.get_symmetric_key(key)?;
740
741 match (data, key) {
742 (EncString::Aes256Cbc_B64 { .. }, SymmetricCryptoKey::Aes256CbcKey(_)) => {
743 Err(CryptoError::OperationNotSupported(
744 UnsupportedOperationError::DecryptionNotImplementedForKey,
745 ))
746 }
747 (
748 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
749 SymmetricCryptoKey::Aes256CbcHmacKey(key),
750 ) => crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key)
751 .map_err(|_| CryptoError::Decrypt),
752 (
753 EncString::Cose_Encrypt0_B64 { data },
754 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
755 ) => {
756 let (data, _) = crate::cose::decrypt_xchacha20_poly1305(
757 &CoseEncrypt0Bytes::from(data.clone()),
758 key,
759 )?;
760 Ok(data)
761 }
762 _ => {
763 tracing::warn!("Unsupported decryption operation for the given key and data");
764 Err(CryptoError::InvalidKey)
765 }
766 }
767 }
768
769 pub(crate) fn encrypt_data_with_symmetric_key(
770 &self,
771 key: Ids::Symmetric,
772 data: &[u8],
773 content_format: ContentFormat,
774 ) -> Result<EncString> {
775 let key = self.get_symmetric_key(key)?;
776 match key {
777 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
778 UnsupportedOperationError::EncryptionNotImplementedForKey,
779 )),
780 SymmetricCryptoKey::Aes256CbcHmacKey(key) => EncString::encrypt_aes256_hmac(data, key),
781 SymmetricCryptoKey::XChaCha20Poly1305Key(key) => {
782 if !key.supported_operations.contains(&KeyOperation::Encrypt) {
783 return Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt));
784 }
785 EncString::encrypt_xchacha20_poly1305(data, key, content_format)
786 }
787 }
788 }
789
790 pub fn sign<Message: Serialize>(
794 &self,
795 key: Ids::Signing,
796 message: &Message,
797 namespace: &crate::SigningNamespace,
798 ) -> Result<SignedObject> {
799 self.get_signing_key(key)?.sign(message, namespace)
800 }
801
802 #[allow(unused)]
806 pub(crate) fn sign_detached<Message: Serialize>(
807 &self,
808 key: Ids::Signing,
809 message: &Message,
810 namespace: &crate::SigningNamespace,
811 ) -> Result<(Signature, signing::SerializedMessage)> {
812 self.get_signing_key(key)?.sign_detached(message, namespace)
813 }
814
815 pub fn dangerous_get_v2_rotated_account_keys(
817 &self,
818 current_user_private_key_id: Ids::Private,
819 current_user_signing_key_id: Ids::Signing,
820 ) -> Result<RotatedUserKeys> {
821 #[expect(deprecated)]
822 crate::dangerous_get_v2_rotated_account_keys(
823 current_user_private_key_id,
824 current_user_signing_key_id,
825 self,
826 )
827 }
828
829 #[cfg(any(test, feature = "test-utils"))]
832 pub fn assert_symmetric_keys_equal(&self, key_id_1: Ids::Symmetric, key_id_2: Ids::Symmetric) {
833 let key_1 = self
834 .get_symmetric_key(key_id_1)
835 .expect("Key 1 should exist in context");
836 let key_2 = self
837 .get_symmetric_key(key_id_2)
838 .expect("Key 2 should exist in context");
839 if key_1 != key_2 {
840 panic!(
841 "Symmetric keys with ids {:?} and {:?} are not equal",
842 key_id_1, key_id_2,
843 );
844 }
845 }
846}
847
848#[cfg(test)]
849#[allow(deprecated)]
850mod tests {
851 use serde::{Deserialize, Serialize};
852
853 use crate::{
854 CompositeEncryptable, CoseKeyBytes, CoseSerializable, CryptoError, Decryptable, EncString,
855 KeyDecryptable, Pkcs8PrivateKeyBytes, PrivateKey, PublicKey, PublicKeyEncryptionAlgorithm,
856 SignatureAlgorithm, SigningKey, SigningNamespace, SymmetricCryptoKey,
857 SymmetricKeyAlgorithm,
858 store::{
859 KeyStore,
860 tests::{Data, DataView},
861 },
862 traits::tests::{TestIds, TestSigningKey, TestSymmKey},
863 };
864
865 #[test]
866 fn test_set_signing_key() {
867 let store: KeyStore<TestIds> = KeyStore::default();
868
869 let key_a0_id = TestSigningKey::A(0);
871 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
872 store
873 .context_mut()
874 .set_signing_key(key_a0_id, key_a0)
875 .unwrap();
876 }
877
878 #[test]
879 fn test_set_keys_for_encryption() {
880 let store: KeyStore<TestIds> = KeyStore::default();
881
882 let key_a0_id = TestSymmKey::A(0);
884 let mut ctx = store.context_mut();
885 let local_key_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
886 ctx.persist_symmetric_key(local_key_id, TestSymmKey::A(0))
887 .unwrap();
888
889 assert!(ctx.has_symmetric_key(key_a0_id));
890
891 let data = DataView("Hello, World!".to_string(), key_a0_id);
893 let _encrypted: Data = data.encrypt_composite(&mut ctx, key_a0_id).unwrap();
894 }
895
896 #[test]
897 fn test_key_encryption() {
898 let store: KeyStore<TestIds> = KeyStore::default();
899
900 let mut ctx = store.context();
901
902 let key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
904
905 assert!(ctx.has_symmetric_key(key_1_id));
906
907 let key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
909
910 assert!(ctx.has_symmetric_key(key_2_id));
911
912 let key_2_enc = ctx.wrap_symmetric_key(key_1_id, key_2_id).unwrap();
914
915 let new_key_id = ctx.unwrap_symmetric_key(key_1_id, &key_2_enc).unwrap();
917
918 let data = DataView("Hello, World!".to_string(), key_2_id);
922 let encrypted = data.encrypt_composite(&mut ctx, key_2_id).unwrap();
923
924 let decrypted1 = encrypted.decrypt(&mut ctx, key_2_id).unwrap();
925 let decrypted2 = encrypted.decrypt(&mut ctx, new_key_id).unwrap();
926
927 assert_eq!(decrypted1.0, decrypted2.0);
929 }
930
931 #[test]
932 fn test_wrap_unwrap() {
933 let store: KeyStore<TestIds> = KeyStore::default();
934 let mut ctx = store.context_mut();
935
936 let key_aes_1_id = TestSymmKey::A(1);
938 let local_key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
939 ctx.persist_symmetric_key(local_key_1_id, key_aes_1_id)
940 .unwrap();
941 let key_aes_2_id = TestSymmKey::A(2);
942 let local_key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
943 ctx.persist_symmetric_key(local_key_2_id, key_aes_2_id)
944 .unwrap();
945
946 let key_xchacha_3_id = TestSymmKey::A(3);
948 let key_xchacha_3 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
949 ctx.set_symmetric_key(key_xchacha_3_id, key_xchacha_3.clone())
950 .unwrap();
951 let key_xchacha_4_id = TestSymmKey::A(4);
952 let key_xchacha_4 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
953 ctx.set_symmetric_key(key_xchacha_4_id, key_xchacha_4.clone())
954 .unwrap();
955
956 let wrapped_key_1_2 = ctx.wrap_symmetric_key(key_aes_1_id, key_aes_2_id).unwrap();
958 let wrapped_key_1_3 = ctx
959 .wrap_symmetric_key(key_aes_1_id, key_xchacha_3_id)
960 .unwrap();
961 let wrapped_key_3_1 = ctx
962 .wrap_symmetric_key(key_xchacha_3_id, key_aes_1_id)
963 .unwrap();
964 let wrapped_key_3_4 = ctx
965 .wrap_symmetric_key(key_xchacha_3_id, key_xchacha_4_id)
966 .unwrap();
967
968 let _unwrapped_key_2 = ctx
970 .unwrap_symmetric_key(key_aes_1_id, &wrapped_key_1_2)
971 .unwrap();
972 let _unwrapped_key_3 = ctx
973 .unwrap_symmetric_key(key_aes_1_id, &wrapped_key_1_3)
974 .unwrap();
975 let _unwrapped_key_1 = ctx
976 .unwrap_symmetric_key(key_xchacha_3_id, &wrapped_key_3_1)
977 .unwrap();
978 let _unwrapped_key_4 = ctx
979 .unwrap_symmetric_key(key_xchacha_3_id, &wrapped_key_3_4)
980 .unwrap();
981 }
982
983 #[test]
984 fn test_signing() {
985 let store: KeyStore<TestIds> = KeyStore::default();
986
987 let key_a0_id = TestSigningKey::A(0);
989 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
990 let verifying_key = key_a0.to_verifying_key();
991 store
992 .context_mut()
993 .set_signing_key(key_a0_id, key_a0)
994 .unwrap();
995
996 assert!(store.context().has_signing_key(key_a0_id));
997
998 #[derive(Serialize, Deserialize)]
1000 struct TestData {
1001 data: String,
1002 }
1003 let signed_object = store
1004 .context()
1005 .sign(
1006 key_a0_id,
1007 &TestData {
1008 data: "Hello".to_string(),
1009 },
1010 &SigningNamespace::ExampleNamespace,
1011 )
1012 .unwrap();
1013 let payload: Result<TestData, CryptoError> =
1014 signed_object.verify_and_unwrap(&verifying_key, &SigningNamespace::ExampleNamespace);
1015 assert!(payload.is_ok());
1016
1017 let (signature, serialized_message) = store
1018 .context()
1019 .sign_detached(
1020 key_a0_id,
1021 &TestData {
1022 data: "Hello".to_string(),
1023 },
1024 &SigningNamespace::ExampleNamespace,
1025 )
1026 .unwrap();
1027 assert!(signature.verify(
1028 serialized_message.as_bytes(),
1029 &verifying_key,
1030 &SigningNamespace::ExampleNamespace
1031 ))
1032 }
1033
1034 #[test]
1035 fn test_account_key_rotation() {
1036 let store: KeyStore<TestIds> = KeyStore::default();
1037 let mut ctx = store.context_mut();
1038
1039 let current_user_signing_key_id = ctx.make_signing_key(SignatureAlgorithm::Ed25519);
1041 let current_user_private_key_id =
1042 ctx.make_private_key(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
1043
1044 let rotated_keys = ctx
1046 .dangerous_get_v2_rotated_account_keys(
1047 current_user_private_key_id,
1048 current_user_signing_key_id,
1049 )
1050 .unwrap();
1051
1052 assert_eq!(
1054 PublicKey::from_der(&rotated_keys.public_key)
1055 .unwrap()
1056 .to_der()
1057 .unwrap(),
1058 ctx.get_private_key(current_user_private_key_id)
1059 .unwrap()
1060 .to_public_key()
1061 .to_der()
1062 .unwrap()
1063 );
1064 let decrypted_private_key: Vec<u8> = rotated_keys
1065 .private_key
1066 .decrypt_with_key(&rotated_keys.user_key)
1067 .unwrap();
1068 let private_key =
1069 PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key)).unwrap();
1070 assert_eq!(
1071 private_key.to_der().unwrap(),
1072 ctx.get_private_key(current_user_private_key_id)
1073 .unwrap()
1074 .to_der()
1075 .unwrap()
1076 );
1077
1078 let decrypted_signing_key: Vec<u8> = rotated_keys
1080 .signing_key
1081 .decrypt_with_key(&rotated_keys.user_key)
1082 .unwrap();
1083 let signing_key =
1084 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
1085 assert_eq!(
1086 signing_key.to_cose(),
1087 ctx.get_signing_key(current_user_signing_key_id)
1088 .unwrap()
1089 .to_cose(),
1090 );
1091
1092 let signed_public_key = rotated_keys.signed_public_key;
1094 let unwrapped_key = signed_public_key
1095 .verify_and_unwrap(
1096 &ctx.get_signing_key(current_user_signing_key_id)
1097 .unwrap()
1098 .to_verifying_key(),
1099 )
1100 .unwrap();
1101 assert_eq!(
1102 unwrapped_key.to_der().unwrap(),
1103 ctx.get_private_key(current_user_private_key_id)
1104 .unwrap()
1105 .to_public_key()
1106 .to_der()
1107 .unwrap()
1108 );
1109 }
1110
1111 #[test]
1112 fn test_encrypt_fails_when_operation_not_allowed() {
1113 use coset::iana::KeyOperation;
1114 let store = KeyStore::<TestIds>::default();
1115 let mut ctx = store.context_mut();
1116 let key_id = TestSymmKey::A(0);
1117 let key = SymmetricCryptoKey::XChaCha20Poly1305Key(crate::XChaCha20Poly1305Key {
1119 key_id: [0u8; 16].into(),
1120 enc_key: Box::pin([0u8; 32].into()),
1121 supported_operations: vec![KeyOperation::Decrypt],
1122 });
1123 ctx.set_symmetric_key(key_id, key).unwrap();
1124 let data = DataView("should fail".to_string(), key_id);
1125 let result = data.encrypt_composite(&mut ctx, key_id);
1126 assert!(
1127 matches!(
1128 result,
1129 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1130 ),
1131 "Expected encrypt to fail with KeyOperationNotSupported",
1132 );
1133 }
1134
1135 #[test]
1136 fn test_move_key() {
1137 let store: KeyStore<TestIds> = KeyStore::default();
1138 let mut ctx = store.context_mut();
1139
1140 let key = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
1142
1143 assert!(ctx.has_symmetric_key(key));
1144
1145 let new_key_id = TestSymmKey::A(1);
1147 ctx.persist_symmetric_key(key, new_key_id).unwrap();
1148
1149 assert!(!ctx.has_symmetric_key(key));
1151 assert!(ctx.has_symmetric_key(new_key_id));
1152 }
1153
1154 #[test]
1155 fn test_encrypt_decrypt_data_fails_when_key_is_type_0() {
1156 let store = KeyStore::<TestIds>::default();
1157 let mut ctx = store.context_mut();
1158
1159 let key_id = TestSymmKey::A(0);
1160 let key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1161 enc_key: Box::pin([0u8; 32].into()),
1162 });
1163 ctx.set_symmetric_key_internal(key_id, key).unwrap();
1164
1165 let data_to_encrypt: Vec<u8> = vec![1, 2, 3, 4, 5];
1166 let result = ctx.encrypt_data_with_symmetric_key(
1167 key_id,
1168 &data_to_encrypt,
1169 crate::ContentFormat::OctetStream,
1170 );
1171 assert!(
1172 matches!(
1173 result,
1174 Err(CryptoError::OperationNotSupported(
1175 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1176 ))
1177 ),
1178 "Expected encrypt to fail when using deprecated type 0 keys",
1179 );
1180
1181 let data_to_decrypt = EncString::Aes256Cbc_B64 {
1182 iv: [0; 16],
1183 data: data_to_encrypt,
1184 }; let result = ctx.decrypt_data_with_symmetric_key(key_id, &data_to_decrypt);
1186 assert!(
1187 matches!(
1188 result,
1189 Err(CryptoError::OperationNotSupported(
1190 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1191 ))
1192 ),
1193 "Expected decrypt to fail when using deprecated type 0 keys",
1194 );
1195 }
1196
1197 #[test]
1198 fn test_wrap_unwrap_key_fails_when_key_is_type_0() {
1199 let store = KeyStore::<TestIds>::default();
1200 let mut ctx = store.context_mut();
1201
1202 let wrapping_key_id = TestSymmKey::A(0);
1203 let wrapping_key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1204 enc_key: Box::pin([0u8; 32].into()),
1205 });
1206 ctx.set_symmetric_key_internal(wrapping_key_id, wrapping_key)
1207 .unwrap();
1208
1209 let key_to_wrap_id = TestSymmKey::A(1);
1210 let key_to_wrap = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
1211 ctx.set_symmetric_key_internal(key_to_wrap_id, key_to_wrap)
1212 .unwrap();
1213
1214 let result = ctx.wrap_symmetric_key(wrapping_key_id, key_to_wrap_id);
1215 assert!(
1216 matches!(
1217 result,
1218 Err(CryptoError::OperationNotSupported(
1219 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1220 ))
1221 ),
1222 "Expected encrypt to fail when using deprecated type 0 keys",
1223 );
1224
1225 let wrapped_key = &EncString::Aes256Cbc_B64 {
1226 iv: [0; 16],
1227 data: vec![0],
1228 }; let result = ctx.unwrap_symmetric_key(wrapping_key_id, wrapped_key);
1230 assert!(
1231 matches!(
1232 result,
1233 Err(CryptoError::OperationNotSupported(
1234 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1235 ))
1236 ),
1237 "Expected decrypt to fail when using deprecated type 0 keys",
1238 );
1239 }
1240}