1use std::{
2 cell::Cell,
3 sync::{RwLockReadGuard, RwLockWriteGuard},
4};
5
6use coset::iana::KeyOperation;
7use serde::Serialize;
8use zeroize::Zeroizing;
9
10use super::KeyStoreInner;
11use crate::{
12 AsymmetricCryptoKey, AsymmetricPublicCryptoKey, BitwardenLegacyKeyBytes, ContentFormat,
13 CoseEncrypt0Bytes, CoseKeyBytes, CoseSerializable, CryptoError, EncString, KeyDecryptable,
14 KeyEncryptable, KeyId, KeyIds, LocalId, Pkcs8PrivateKeyBytes, PublicKeyEncryptionAlgorithm,
15 Result, RotatedUserKeys, Signature, SignatureAlgorithm, SignedObject, SignedPublicKey,
16 SignedPublicKeyMessage, SigningKey, SymmetricCryptoKey, SymmetricKeyAlgorithm,
17 UnsignedSharedKey, VerifyingKey, derive_shareable_key, error::UnsupportedOperationError,
18 signing, store::backend::StoreBackend,
19};
20
21#[must_use]
80pub struct KeyStoreContext<'a, Ids: KeyIds> {
81 pub(super) global_keys: GlobalKeys<'a, Ids>,
82
83 pub(super) local_symmetric_keys: Box<dyn StoreBackend<Ids::Symmetric>>,
84 pub(super) local_asymmetric_keys: Box<dyn StoreBackend<Ids::Asymmetric>>,
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: KeyIds> {
99 ReadOnly(RwLockReadGuard<'a, KeyStoreInner<Ids>>),
100 ReadWrite(RwLockWriteGuard<'a, KeyStoreInner<Ids>>),
101}
102
103impl<Ids: KeyIds> 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: KeyIds> KeyStoreContext<'_, Ids> {
133 pub fn clear_local(&mut self) {
137 self.local_symmetric_keys.clear();
138 self.local_asymmetric_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_asymmetric_keys(&mut self, f: fn(Ids::Asymmetric) -> bool) {
161 if let Ok(keys) = self.global_keys.get_mut() {
162 keys.asymmetric_keys.retain(f);
163 }
164 self.local_asymmetric_keys.retain(f);
165 }
166
167 fn drop_symmetric_key(&mut self, key_id: Ids::Symmetric) -> Result<()> {
168 if key_id.is_local() {
169 self.local_symmetric_keys.remove(key_id);
170 } else {
171 self.global_keys.get_mut()?.symmetric_keys.remove(key_id);
172 }
173 Ok(())
174 }
175
176 fn drop_asymmetric_key(&mut self, key_id: Ids::Asymmetric) -> Result<()> {
177 if key_id.is_local() {
178 self.local_asymmetric_keys.remove(key_id);
179 } else {
180 self.global_keys.get_mut()?.asymmetric_keys.remove(key_id);
181 }
182 Ok(())
183 }
184
185 fn drop_signing_key(&mut self, key_id: Ids::Signing) -> Result<()> {
186 if key_id.is_local() {
187 self.local_signing_keys.remove(key_id);
188 } else {
189 self.global_keys.get_mut()?.signing_keys.remove(key_id);
190 }
191 Ok(())
192 }
193
194 pub fn unwrap_symmetric_key(
207 &mut self,
208 wrapping_key: Ids::Symmetric,
209 wrapped_key: &EncString,
210 ) -> Result<Ids::Symmetric> {
211 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
212
213 let key = match (wrapped_key, wrapping_key) {
214 (EncString::Aes256Cbc_B64 { iv, data }, SymmetricCryptoKey::Aes256CbcKey(key)) => {
215 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(
216 crate::aes::decrypt_aes256(iv, data.clone(), &key.enc_key)?,
217 ))?
218 }
219 (
220 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
221 SymmetricCryptoKey::Aes256CbcHmacKey(key),
222 ) => SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(
223 crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key)?,
224 ))?,
225 (
226 EncString::Cose_Encrypt0_B64 { data },
227 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
228 ) => {
229 let (content_bytes, content_format) = crate::cose::decrypt_xchacha20_poly1305(
230 &CoseEncrypt0Bytes::from(data.clone()),
231 key,
232 )?;
233 match content_format {
234 ContentFormat::BitwardenLegacyKey => {
235 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(content_bytes))?
236 }
237 ContentFormat::CoseKey => SymmetricCryptoKey::try_from_cose(&content_bytes)?,
238 _ => return Err(CryptoError::InvalidKey),
239 }
240 }
241 _ => return Err(CryptoError::InvalidKey),
242 };
243
244 let new_key_id = Ids::Symmetric::new_local(LocalId::new());
245
246 #[allow(deprecated)]
247 self.set_symmetric_key(new_key_id, key)?;
248
249 Ok(new_key_id)
251 }
252
253 pub fn persist_symmetric_key(
261 &mut self,
262 from: Ids::Symmetric,
263 to: Ids::Symmetric,
264 ) -> Result<()> {
265 if !from.is_local() || to.is_local() {
266 return Err(CryptoError::InvalidKeyStoreOperation);
267 }
268 let key = self.get_symmetric_key(from)?.to_owned();
269 self.drop_symmetric_key(from)?;
270 #[allow(deprecated)]
271 self.set_symmetric_key(to, key)?;
272 Ok(())
273 }
274
275 pub fn persist_asymmetric_key(
283 &mut self,
284 from: Ids::Asymmetric,
285 to: Ids::Asymmetric,
286 ) -> Result<()> {
287 if !from.is_local() || to.is_local() {
288 return Err(CryptoError::InvalidKeyStoreOperation);
289 }
290 let key = self.get_asymmetric_key(from)?.to_owned();
291 self.drop_asymmetric_key(from)?;
292 #[allow(deprecated)]
293 self.set_asymmetric_key(to, key)?;
294 Ok(())
295 }
296
297 pub fn persist_signing_key(&mut self, from: Ids::Signing, to: Ids::Signing) -> Result<()> {
304 if !from.is_local() || to.is_local() {
305 return Err(CryptoError::InvalidKeyStoreOperation);
306 }
307 let key = self.get_signing_key(from)?.to_owned();
308 self.drop_signing_key(from)?;
309 #[allow(deprecated)]
310 self.set_signing_key(to, key)?;
311 Ok(())
312 }
313
314 pub fn wrap_signing_key(
323 &self,
324 wrapping_key: Ids::Symmetric,
325 key_to_wrap: Ids::Signing,
326 ) -> Result<EncString> {
327 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
328 let signing_key = self.get_signing_key(key_to_wrap)?.to_owned();
329 signing_key.to_cose().encrypt_with_key(wrapping_key)
330 }
331
332 pub fn wrap_private_key(
340 &self,
341 wrapping_key: Ids::Symmetric,
342 key_to_wrap: Ids::Asymmetric,
343 ) -> Result<EncString> {
344 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
345 let private_key = self.get_asymmetric_key(key_to_wrap)?.to_owned();
346 private_key.to_der()?.encrypt_with_key(wrapping_key)
347 }
348
349 pub fn unwrap_private_key(
358 &mut self,
359 wrapping_key: Ids::Symmetric,
360 wrapped_key: &EncString,
361 ) -> Result<Ids::Asymmetric> {
362 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
363 let private_key_bytes: Vec<u8> = wrapped_key.decrypt_with_key(wrapping_key)?;
364 let private_key =
365 AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(private_key_bytes))?;
366 self.add_local_asymmetric_key(private_key)
367 }
368
369 pub fn unwrap_signing_key(
378 &mut self,
379 wrapping_key: Ids::Symmetric,
380 wrapped_key: &EncString,
381 ) -> Result<Ids::Signing> {
382 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
383 let signing_key_bytes: Vec<u8> = wrapped_key.decrypt_with_key(wrapping_key)?;
384 let signing_key = SigningKey::from_cose(&CoseKeyBytes::from(signing_key_bytes))?;
385 self.add_local_signing_key(signing_key)
386 }
387
388 pub fn get_verifying_key(&self, signing_key_id: Ids::Signing) -> Result<VerifyingKey> {
396 let signing_key = self.get_signing_key(signing_key_id)?;
397 Ok(signing_key.to_verifying_key())
398 }
399
400 pub fn get_public_key(
407 &self,
408 asymmetric_key_id: Ids::Asymmetric,
409 ) -> Result<AsymmetricPublicCryptoKey> {
410 let asymmetric_key = self.get_asymmetric_key(asymmetric_key_id)?;
411 Ok(asymmetric_key.to_public_key())
412 }
413
414 pub fn wrap_symmetric_key(
423 &self,
424 wrapping_key: Ids::Symmetric,
425 key_to_wrap: Ids::Symmetric,
426 ) -> Result<EncString> {
427 use SymmetricCryptoKey::*;
428
429 let wrapping_key_instance = self.get_symmetric_key(wrapping_key)?;
430 let key_to_wrap_instance = self.get_symmetric_key(key_to_wrap)?;
431 match (wrapping_key_instance, key_to_wrap_instance) {
437 (
438 Aes256CbcHmacKey(_),
439 Aes256CbcHmacKey(_) | Aes256CbcKey(_) | XChaCha20Poly1305Key(_),
440 ) => self.encrypt_data_with_symmetric_key(
441 wrapping_key,
442 key_to_wrap_instance
443 .to_encoded()
444 .as_ref()
445 .to_vec()
446 .as_slice(),
447 ContentFormat::BitwardenLegacyKey,
448 ),
449 (XChaCha20Poly1305Key(_), _) => {
450 let encoded = key_to_wrap_instance.to_encoded_raw();
451 let content_format = encoded.content_format();
452 self.encrypt_data_with_symmetric_key(
453 wrapping_key,
454 Into::<Vec<u8>>::into(encoded).as_slice(),
455 content_format,
456 )
457 }
458 _ => Err(CryptoError::OperationNotSupported(
459 UnsupportedOperationError::EncryptionNotImplementedForKey,
460 )),
461 }
462 }
463
464 pub fn decapsulate_key_unsigned(
474 &mut self,
475 decapsulation_key: Ids::Asymmetric,
476 new_key_id: Ids::Symmetric,
477 encapsulated_shared_key: &UnsignedSharedKey,
478 ) -> Result<Ids::Symmetric> {
479 let decapsulation_key = self.get_asymmetric_key(decapsulation_key)?;
480 let decapsulated_key =
481 encapsulated_shared_key.decapsulate_key_unsigned(decapsulation_key)?;
482
483 #[allow(deprecated)]
484 self.set_symmetric_key(new_key_id, decapsulated_key)?;
485
486 Ok(new_key_id)
488 }
489
490 pub fn encapsulate_key_unsigned(
499 &self,
500 encapsulation_key: Ids::Asymmetric,
501 shared_key: Ids::Symmetric,
502 ) -> Result<UnsignedSharedKey> {
503 UnsignedSharedKey::encapsulate_key_unsigned(
504 self.get_symmetric_key(shared_key)?,
505 &self.get_asymmetric_key(encapsulation_key)?.to_public_key(),
506 )
507 }
508
509 pub fn has_symmetric_key(&self, key_id: Ids::Symmetric) -> bool {
511 self.get_symmetric_key(key_id).is_ok()
512 }
513
514 pub fn has_asymmetric_key(&self, key_id: Ids::Asymmetric) -> bool {
516 self.get_asymmetric_key(key_id).is_ok()
517 }
518
519 pub fn has_signing_key(&self, key_id: Ids::Signing) -> bool {
521 self.get_signing_key(key_id).is_ok()
522 }
523
524 pub fn generate_symmetric_key(&mut self) -> Ids::Symmetric {
526 self.add_local_symmetric_key(SymmetricCryptoKey::make_aes256_cbc_hmac_key())
527 }
528
529 pub fn make_symmetric_key(&mut self, algorithm: SymmetricKeyAlgorithm) -> Ids::Symmetric {
532 self.add_local_symmetric_key(SymmetricCryptoKey::make(algorithm))
533 }
534
535 pub fn make_private_key(
538 &mut self,
539 algorithm: PublicKeyEncryptionAlgorithm,
540 ) -> Result<Ids::Asymmetric> {
541 self.add_local_asymmetric_key(AsymmetricCryptoKey::make(algorithm))
542 }
543
544 pub fn make_signing_key(&mut self, algorithm: SignatureAlgorithm) -> Result<Ids::Signing> {
547 self.add_local_signing_key(SigningKey::make(algorithm))
548 }
549
550 pub fn make_asymmetric_key(&mut self) -> Result<Ids::Asymmetric> {
553 let key = AsymmetricCryptoKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
554 self.add_local_asymmetric_key(key)
555 }
556
557 pub fn derive_shareable_key(
562 &mut self,
563 secret: Zeroizing<[u8; 16]>,
564 name: &str,
565 info: Option<&str>,
566 ) -> Result<Ids::Symmetric> {
567 let key_id = Ids::Symmetric::new_local(LocalId::new());
568 #[allow(deprecated)]
569 self.set_symmetric_key(
570 key_id,
571 SymmetricCryptoKey::Aes256CbcHmacKey(derive_shareable_key(secret, name, info)),
572 )?;
573 Ok(key_id)
574 }
575
576 #[deprecated(note = "This function should ideally never be used outside this crate")]
586 pub fn dangerous_get_symmetric_key(
587 &self,
588 key_id: Ids::Symmetric,
589 ) -> Result<&SymmetricCryptoKey> {
590 self.get_symmetric_key(key_id)
591 }
592
593 #[deprecated(note = "This function should ideally never be used outside this crate")]
602 pub fn dangerous_get_asymmetric_key(
603 &self,
604 key_id: Ids::Asymmetric,
605 ) -> Result<&AsymmetricCryptoKey> {
606 self.get_asymmetric_key(key_id)
607 }
608
609 pub fn make_signed_public_key(
613 &self,
614 private_key_id: Ids::Asymmetric,
615 signing_key_id: Ids::Signing,
616 ) -> Result<SignedPublicKey> {
617 let public_key = self.get_asymmetric_key(private_key_id)?.to_public_key();
618 let signing_key = self.get_signing_key(signing_key_id)?;
619 let signed_public_key =
620 SignedPublicKeyMessage::from_public_key(&public_key)?.sign(signing_key)?;
621 Ok(signed_public_key)
622 }
623
624 pub(crate) fn get_symmetric_key(&self, key_id: Ids::Symmetric) -> Result<&SymmetricCryptoKey> {
625 if key_id.is_local() {
626 self.local_symmetric_keys.get(key_id)
627 } else {
628 self.global_keys.get().symmetric_keys.get(key_id)
629 }
630 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
631 }
632
633 pub(super) fn get_asymmetric_key(
634 &self,
635 key_id: Ids::Asymmetric,
636 ) -> Result<&AsymmetricCryptoKey> {
637 if key_id.is_local() {
638 self.local_asymmetric_keys.get(key_id)
639 } else {
640 self.global_keys.get().asymmetric_keys.get(key_id)
641 }
642 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
643 }
644
645 pub(super) fn get_signing_key(&self, key_id: Ids::Signing) -> Result<&SigningKey> {
646 if key_id.is_local() {
647 self.local_signing_keys.get(key_id)
648 } else {
649 self.global_keys.get().signing_keys.get(key_id)
650 }
651 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
652 }
653
654 #[deprecated(note = "This function should ideally never be used outside this crate")]
660 pub fn set_symmetric_key(
661 &mut self,
662 key_id: Ids::Symmetric,
663 key: SymmetricCryptoKey,
664 ) -> Result<()> {
665 self.set_symmetric_key_internal(key_id, key)
666 }
667
668 pub(crate) fn set_symmetric_key_internal(
669 &mut self,
670 key_id: Ids::Symmetric,
671 key: SymmetricCryptoKey,
672 ) -> Result<()> {
673 if key_id.is_local() {
674 self.local_symmetric_keys.upsert(key_id, key);
675 } else {
676 self.global_keys
677 .get_mut()?
678 .symmetric_keys
679 .upsert(key_id, key);
680 }
681 Ok(())
682 }
683
684 pub fn add_local_symmetric_key(&mut self, key: SymmetricCryptoKey) -> Ids::Symmetric {
686 let key_id = Ids::Symmetric::new_local(LocalId::new());
687 self.local_symmetric_keys.upsert(key_id, key);
688 key_id
689 }
690
691 pub fn get_symmetric_key_algorithm(
693 &self,
694 key_id: Ids::Symmetric,
695 ) -> Result<SymmetricKeyAlgorithm> {
696 let key = self.get_symmetric_key(key_id)?;
697 match key {
698 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
700 UnsupportedOperationError::EncryptionNotImplementedForKey,
701 )),
702 SymmetricCryptoKey::Aes256CbcHmacKey(_) => Ok(SymmetricKeyAlgorithm::Aes256CbcHmac),
703 SymmetricCryptoKey::XChaCha20Poly1305Key(_) => {
704 Ok(SymmetricKeyAlgorithm::XChaCha20Poly1305)
705 }
706 }
707 }
708
709 #[deprecated(note = "This function should ideally never be used outside this crate")]
715 pub fn set_asymmetric_key(
716 &mut self,
717 key_id: Ids::Asymmetric,
718 key: AsymmetricCryptoKey,
719 ) -> Result<()> {
720 if key_id.is_local() {
721 self.local_asymmetric_keys.upsert(key_id, key);
722 } else {
723 self.global_keys
724 .get_mut()?
725 .asymmetric_keys
726 .upsert(key_id, key);
727 }
728 Ok(())
729 }
730
731 pub fn add_local_asymmetric_key(
733 &mut self,
734 key: AsymmetricCryptoKey,
735 ) -> Result<Ids::Asymmetric> {
736 let key_id = Ids::Asymmetric::new_local(LocalId::new());
737 self.local_asymmetric_keys.upsert(key_id, key);
738 Ok(key_id)
739 }
740
741 #[deprecated(note = "This function should ideally never be used outside this crate")]
747 pub fn set_signing_key(&mut self, key_id: Ids::Signing, key: SigningKey) -> Result<()> {
748 if key_id.is_local() {
749 self.local_signing_keys.upsert(key_id, key);
750 } else {
751 self.global_keys.get_mut()?.signing_keys.upsert(key_id, key);
752 }
753 Ok(())
754 }
755
756 pub fn add_local_signing_key(&mut self, key: SigningKey) -> Result<Ids::Signing> {
758 let key_id = Ids::Signing::new_local(LocalId::new());
759 self.local_signing_keys.upsert(key_id, key);
760 Ok(key_id)
761 }
762
763 pub(crate) fn decrypt_data_with_symmetric_key(
764 &self,
765 key: Ids::Symmetric,
766 data: &EncString,
767 ) -> Result<Vec<u8>> {
768 let key = self.get_symmetric_key(key)?;
769
770 match (data, key) {
771 (EncString::Aes256Cbc_B64 { iv, data }, SymmetricCryptoKey::Aes256CbcKey(key)) => {
772 crate::aes::decrypt_aes256(iv, data.clone(), &key.enc_key)
773 }
774 (
775 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
776 SymmetricCryptoKey::Aes256CbcHmacKey(key),
777 ) => crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key),
778 (
779 EncString::Cose_Encrypt0_B64 { data },
780 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
781 ) => {
782 let (data, _) = crate::cose::decrypt_xchacha20_poly1305(
783 &CoseEncrypt0Bytes::from(data.clone()),
784 key,
785 )?;
786 Ok(data)
787 }
788 _ => Err(CryptoError::InvalidKey),
789 }
790 }
791
792 pub(crate) fn encrypt_data_with_symmetric_key(
793 &self,
794 key: Ids::Symmetric,
795 data: &[u8],
796 content_format: ContentFormat,
797 ) -> Result<EncString> {
798 let key = self.get_symmetric_key(key)?;
799 match key {
800 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
801 UnsupportedOperationError::EncryptionNotImplementedForKey,
802 )),
803 SymmetricCryptoKey::Aes256CbcHmacKey(key) => EncString::encrypt_aes256_hmac(data, key),
804 SymmetricCryptoKey::XChaCha20Poly1305Key(key) => {
805 if !key.supported_operations.contains(&KeyOperation::Encrypt) {
806 return Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt));
807 }
808 EncString::encrypt_xchacha20_poly1305(data, key, content_format)
809 }
810 }
811 }
812
813 pub fn sign<Message: Serialize>(
817 &self,
818 key: Ids::Signing,
819 message: &Message,
820 namespace: &crate::SigningNamespace,
821 ) -> Result<SignedObject> {
822 self.get_signing_key(key)?.sign(message, namespace)
823 }
824
825 #[allow(unused)]
829 pub(crate) fn sign_detached<Message: Serialize>(
830 &self,
831 key: Ids::Signing,
832 message: &Message,
833 namespace: &crate::SigningNamespace,
834 ) -> Result<(Signature, signing::SerializedMessage)> {
835 self.get_signing_key(key)?.sign_detached(message, namespace)
836 }
837
838 pub fn dangerous_get_v2_rotated_account_keys(
840 &self,
841 current_user_private_key_id: Ids::Asymmetric,
842 current_user_signing_key_id: Ids::Signing,
843 ) -> Result<RotatedUserKeys> {
844 crate::dangerous_get_v2_rotated_account_keys(
845 current_user_private_key_id,
846 current_user_signing_key_id,
847 self,
848 )
849 }
850}
851
852#[cfg(test)]
853#[allow(deprecated)]
854mod tests {
855 use serde::{Deserialize, Serialize};
856
857 use crate::{
858 AsymmetricCryptoKey, AsymmetricPublicCryptoKey, CompositeEncryptable, CoseKeyBytes,
859 CoseSerializable, CryptoError, Decryptable, KeyDecryptable, Pkcs8PrivateKeyBytes,
860 SignatureAlgorithm, SigningKey, SigningNamespace, SymmetricCryptoKey,
861 SymmetricKeyAlgorithm,
862 store::{
863 KeyStore,
864 tests::{Data, DataView},
865 },
866 traits::tests::{TestIds, TestSigningKey, TestSymmKey},
867 };
868
869 #[test]
870 fn test_set_signing_key() {
871 let store: KeyStore<TestIds> = KeyStore::default();
872
873 let key_a0_id = TestSigningKey::A(0);
875 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
876 store
877 .context_mut()
878 .set_signing_key(key_a0_id, key_a0)
879 .unwrap();
880 }
881
882 #[test]
883 fn test_set_keys_for_encryption() {
884 let store: KeyStore<TestIds> = KeyStore::default();
885
886 let key_a0_id = TestSymmKey::A(0);
888 let mut ctx = store.context_mut();
889 let local_key_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
890 ctx.persist_symmetric_key(local_key_id, TestSymmKey::A(0))
891 .unwrap();
892
893 assert!(ctx.has_symmetric_key(key_a0_id));
894
895 let data = DataView("Hello, World!".to_string(), key_a0_id);
897 let _encrypted: Data = data.encrypt_composite(&mut ctx, key_a0_id).unwrap();
898 }
899
900 #[test]
901 fn test_key_encryption() {
902 let store: KeyStore<TestIds> = KeyStore::default();
903
904 let mut ctx = store.context();
905
906 let key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
908
909 assert!(ctx.has_symmetric_key(key_1_id));
910
911 let key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
913
914 assert!(ctx.has_symmetric_key(key_2_id));
915
916 let key_2_enc = ctx.wrap_symmetric_key(key_1_id, key_2_id).unwrap();
918
919 let new_key_id = ctx.unwrap_symmetric_key(key_1_id, &key_2_enc).unwrap();
921
922 let data = DataView("Hello, World!".to_string(), key_2_id);
926 let encrypted = data.encrypt_composite(&mut ctx, key_2_id).unwrap();
927
928 let decrypted1 = encrypted.decrypt(&mut ctx, key_2_id).unwrap();
929 let decrypted2 = encrypted.decrypt(&mut ctx, new_key_id).unwrap();
930
931 assert_eq!(decrypted1.0, decrypted2.0);
933 }
934
935 #[test]
936 fn test_wrap_unwrap() {
937 let store: KeyStore<TestIds> = KeyStore::default();
938 let mut ctx = store.context_mut();
939
940 let key_aes_1_id = TestSymmKey::A(1);
942 let local_key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
943 ctx.persist_symmetric_key(local_key_1_id, key_aes_1_id)
944 .unwrap();
945 let key_aes_2_id = TestSymmKey::A(2);
946 let local_key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
947 ctx.persist_symmetric_key(local_key_2_id, key_aes_2_id)
948 .unwrap();
949
950 let key_xchacha_3_id = TestSymmKey::A(3);
952 let key_xchacha_3 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
953 ctx.set_symmetric_key(key_xchacha_3_id, key_xchacha_3.clone())
954 .unwrap();
955 let key_xchacha_4_id = TestSymmKey::A(4);
956 let key_xchacha_4 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
957 ctx.set_symmetric_key(key_xchacha_4_id, key_xchacha_4.clone())
958 .unwrap();
959
960 let wrapped_key_1_2 = ctx.wrap_symmetric_key(key_aes_1_id, key_aes_2_id).unwrap();
962 let wrapped_key_1_3 = ctx
963 .wrap_symmetric_key(key_aes_1_id, key_xchacha_3_id)
964 .unwrap();
965 let wrapped_key_3_1 = ctx
966 .wrap_symmetric_key(key_xchacha_3_id, key_aes_1_id)
967 .unwrap();
968 let wrapped_key_3_4 = ctx
969 .wrap_symmetric_key(key_xchacha_3_id, key_xchacha_4_id)
970 .unwrap();
971
972 let _unwrapped_key_2 = ctx
974 .unwrap_symmetric_key(key_aes_1_id, &wrapped_key_1_2)
975 .unwrap();
976 let _unwrapped_key_3 = ctx
977 .unwrap_symmetric_key(key_aes_1_id, &wrapped_key_1_3)
978 .unwrap();
979 let _unwrapped_key_1 = ctx
980 .unwrap_symmetric_key(key_xchacha_3_id, &wrapped_key_3_1)
981 .unwrap();
982 let _unwrapped_key_4 = ctx
983 .unwrap_symmetric_key(key_xchacha_3_id, &wrapped_key_3_4)
984 .unwrap();
985 }
986
987 #[test]
988 fn test_signing() {
989 let store: KeyStore<TestIds> = KeyStore::default();
990
991 let key_a0_id = TestSigningKey::A(0);
993 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
994 let verifying_key = key_a0.to_verifying_key();
995 store
996 .context_mut()
997 .set_signing_key(key_a0_id, key_a0)
998 .unwrap();
999
1000 assert!(store.context().has_signing_key(key_a0_id));
1001
1002 #[derive(Serialize, Deserialize)]
1004 struct TestData {
1005 data: String,
1006 }
1007 let signed_object = store
1008 .context()
1009 .sign(
1010 key_a0_id,
1011 &TestData {
1012 data: "Hello".to_string(),
1013 },
1014 &SigningNamespace::ExampleNamespace,
1015 )
1016 .unwrap();
1017 let payload: Result<TestData, CryptoError> =
1018 signed_object.verify_and_unwrap(&verifying_key, &SigningNamespace::ExampleNamespace);
1019 assert!(payload.is_ok());
1020
1021 let (signature, serialized_message) = store
1022 .context()
1023 .sign_detached(
1024 key_a0_id,
1025 &TestData {
1026 data: "Hello".to_string(),
1027 },
1028 &SigningNamespace::ExampleNamespace,
1029 )
1030 .unwrap();
1031 assert!(signature.verify(
1032 serialized_message.as_bytes(),
1033 &verifying_key,
1034 &SigningNamespace::ExampleNamespace
1035 ))
1036 }
1037
1038 #[test]
1039 fn test_account_key_rotation() {
1040 let store: KeyStore<TestIds> = KeyStore::default();
1041 let mut ctx = store.context_mut();
1042
1043 let current_user_signing_key_id =
1045 ctx.make_signing_key(SignatureAlgorithm::Ed25519).unwrap();
1046 let current_user_private_key_id = ctx.make_asymmetric_key().unwrap();
1047
1048 let rotated_keys = ctx
1050 .dangerous_get_v2_rotated_account_keys(
1051 current_user_private_key_id,
1052 current_user_signing_key_id,
1053 )
1054 .unwrap();
1055
1056 assert_eq!(
1058 AsymmetricPublicCryptoKey::from_der(&rotated_keys.public_key)
1059 .unwrap()
1060 .to_der()
1061 .unwrap(),
1062 ctx.get_asymmetric_key(current_user_private_key_id)
1063 .unwrap()
1064 .to_public_key()
1065 .to_der()
1066 .unwrap()
1067 );
1068 let decrypted_private_key: Vec<u8> = rotated_keys
1069 .private_key
1070 .decrypt_with_key(&rotated_keys.user_key)
1071 .unwrap();
1072 let private_key =
1073 AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key))
1074 .unwrap();
1075 assert_eq!(
1076 private_key.to_der().unwrap(),
1077 ctx.get_asymmetric_key(current_user_private_key_id)
1078 .unwrap()
1079 .to_der()
1080 .unwrap()
1081 );
1082
1083 let decrypted_signing_key: Vec<u8> = rotated_keys
1085 .signing_key
1086 .decrypt_with_key(&rotated_keys.user_key)
1087 .unwrap();
1088 let signing_key =
1089 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
1090 assert_eq!(
1091 signing_key.to_cose(),
1092 ctx.get_signing_key(current_user_signing_key_id)
1093 .unwrap()
1094 .to_cose(),
1095 );
1096
1097 let signed_public_key = rotated_keys.signed_public_key;
1099 let unwrapped_key = signed_public_key
1100 .verify_and_unwrap(
1101 &ctx.get_signing_key(current_user_signing_key_id)
1102 .unwrap()
1103 .to_verifying_key(),
1104 )
1105 .unwrap();
1106 assert_eq!(
1107 unwrapped_key.to_der().unwrap(),
1108 ctx.get_asymmetric_key(current_user_private_key_id)
1109 .unwrap()
1110 .to_public_key()
1111 .to_der()
1112 .unwrap()
1113 );
1114 }
1115
1116 #[test]
1117 fn test_encrypt_fails_when_operation_not_allowed() {
1118 use coset::iana::KeyOperation;
1119 let store = KeyStore::<TestIds>::default();
1120 let mut ctx = store.context_mut();
1121 let key_id = TestSymmKey::A(0);
1122 let key = SymmetricCryptoKey::XChaCha20Poly1305Key(crate::XChaCha20Poly1305Key {
1124 key_id: [0u8; 16],
1125 enc_key: Box::pin([0u8; 32].into()),
1126 supported_operations: vec![KeyOperation::Decrypt],
1127 });
1128 ctx.set_symmetric_key(key_id, key).unwrap();
1129 let data = DataView("should fail".to_string(), key_id);
1130 let result = data.encrypt_composite(&mut ctx, key_id);
1131 assert!(
1132 matches!(
1133 result,
1134 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1135 ),
1136 "Expected encrypt to fail with KeyOperationNotSupported",
1137 );
1138 }
1139
1140 #[test]
1141 fn test_move_key() {
1142 let store: KeyStore<TestIds> = KeyStore::default();
1143 let mut ctx = store.context_mut();
1144
1145 let key = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
1147
1148 assert!(ctx.has_symmetric_key(key));
1149
1150 let new_key_id = TestSymmKey::A(1);
1152 ctx.persist_symmetric_key(key, new_key_id).unwrap();
1153
1154 assert!(!ctx.has_symmetric_key(key));
1156 assert!(ctx.has_symmetric_key(new_key_id));
1157 }
1158}