1use std::{
2 cell::Cell,
3 sync::{RwLockReadGuard, RwLockWriteGuard},
4};
5
6use coset::iana::KeyOperation;
7use serde::Serialize;
8use zeroize::Zeroizing;
9
10use super::{CipherSuite, KeyStoreInner};
11use crate::{
12 BitwardenLegacyKeyBytes, ContentFormat, CoseEncrypt0Bytes, CoseKeyBytes, CoseSerializable,
13 CryptoError, EncString, KeyDecryptable, KeyEncryptable, KeyId, KeySlotId, KeySlotIds, LocalId,
14 Pkcs8PrivateKeyBytes, PrivateKey, PublicKey, PublicKeyEncryptionAlgorithm, Result, Signature,
15 SignatureAlgorithm, SignedObject, SignedPublicKey, SignedPublicKeyMessage, SigningKey,
16 SymmetricCryptoKey, SymmetricKeyAlgorithm, VerifyingKey, derive_shareable_key,
17 error::UnsupportedOperationError, hazmat::symmetric_encryption::Aes256CbcHmacSha256, signing,
18 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) cipher_suite: CipherSuite,
90
91 pub(super) _phantom: std::marker::PhantomData<(Cell<()>, RwLockReadGuard<'static, ()>)>,
93}
94
95pub(crate) enum GlobalKeys<'a, Ids: KeySlotIds> {
101 ReadOnly(RwLockReadGuard<'a, KeyStoreInner<Ids>>),
102 ReadWrite(RwLockWriteGuard<'a, KeyStoreInner<Ids>>),
103}
104
105impl<Ids: KeySlotIds> GlobalKeys<'_, Ids> {
106 pub fn get(&self) -> &KeyStoreInner<Ids> {
112 match self {
113 GlobalKeys::ReadOnly(keys) => keys,
114 GlobalKeys::ReadWrite(keys) => keys,
115 }
116 }
117
118 pub fn get_mut(&mut self) -> Result<&mut KeyStoreInner<Ids>> {
127 match self {
128 GlobalKeys::ReadOnly(_) => Err(CryptoError::ReadOnlyKeyStore),
129 GlobalKeys::ReadWrite(keys) => Ok(keys),
130 }
131 }
132}
133
134impl<Ids: KeySlotIds> KeyStoreContext<'_, Ids> {
135 pub fn clear_local(&mut self) {
139 self.local_symmetric_keys.clear();
140 self.local_private_keys.clear();
141 self.local_signing_keys.clear();
142 }
143
144 pub fn get_security_state_version(&self) -> u64 {
148 self.security_state_version
149 }
150
151 pub fn cipher_suite(&self) -> CipherSuite {
154 self.cipher_suite
155 }
156
157 pub fn retain_symmetric_keys(&mut self, f: fn(Ids::Symmetric) -> bool) {
160 if let Ok(keys) = self.global_keys.get_mut() {
161 keys.symmetric_keys.retain(f);
162 }
163 self.local_symmetric_keys.retain(f);
164 }
165
166 pub fn retain_private_keys(&mut self, f: fn(Ids::Private) -> bool) {
169 if let Ok(keys) = self.global_keys.get_mut() {
170 keys.private_keys.retain(f);
171 }
172 self.local_private_keys.retain(f);
173 }
174
175 pub fn drop_symmetric_key(&mut self, key_id: Ids::Symmetric) -> Result<()> {
179 if key_id.is_local() {
180 self.local_symmetric_keys.remove(key_id);
181 } else {
182 self.global_keys.get_mut()?.symmetric_keys.remove(key_id);
183 }
184 Ok(())
185 }
186
187 pub fn drop_private_key(&mut self, key_id: Ids::Private) -> Result<()> {
191 if key_id.is_local() {
192 self.local_private_keys.remove(key_id);
193 } else {
194 self.global_keys.get_mut()?.private_keys.remove(key_id);
195 }
196 Ok(())
197 }
198
199 pub fn drop_signing_key(&mut self, key_id: Ids::Signing) -> Result<()> {
203 if key_id.is_local() {
204 self.local_signing_keys.remove(key_id);
205 } else {
206 self.global_keys.get_mut()?.signing_keys.remove(key_id);
207 }
208 Ok(())
209 }
210
211 #[bitwarden_logging::instrument(err, fields(wrapping_key = ?wrapping_key))]
224 pub fn unwrap_symmetric_key(
225 &mut self,
226 wrapping_key: Ids::Symmetric,
227 wrapped_key: &EncString,
228 ) -> Result<Ids::Symmetric> {
229 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
230
231 let key = match (wrapped_key, wrapping_key) {
232 (EncString::Aes256Cbc_B64 { .. }, SymmetricCryptoKey::Aes256CbcKey(_)) => {
233 return Err(CryptoError::OperationNotSupported(
234 UnsupportedOperationError::DecryptionNotImplementedForKey,
235 ));
236 }
237 (
238 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
239 SymmetricCryptoKey::Aes256CbcHmacKey(key),
240 ) => SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(
241 Aes256CbcHmacSha256::decrypt(iv, data, mac, key.as_composite_key())
242 .map_err(|_| CryptoError::Decrypt)?,
243 ))?,
244 (
245 EncString::Cose_Encrypt0_B64 { data },
246 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
247 ) => {
248 let (content_bytes, content_format) =
249 crate::cose::symmetric::decrypt_xchacha20_poly1305(
250 &CoseEncrypt0Bytes::from(data.clone()),
251 key,
252 )?;
253 match content_format {
254 ContentFormat::BitwardenLegacyKey => {
255 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(content_bytes))?
256 }
257 ContentFormat::CoseKey => SymmetricCryptoKey::try_from_cose(&content_bytes)?,
258 _ => return Err(CryptoError::InvalidKey),
259 }
260 }
261 (EncString::Cose_Encrypt0_B64 { data }, SymmetricCryptoKey::XAes256GcmKey(key)) => {
262 let (content_bytes, content_format) = crate::cose::symmetric::decrypt_xaes256_gcm(
263 &CoseEncrypt0Bytes::from(data.clone()),
264 key,
265 )?;
266 match content_format {
267 ContentFormat::BitwardenLegacyKey => {
268 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(content_bytes))?
269 }
270 ContentFormat::CoseKey => SymmetricCryptoKey::try_from_cose(&content_bytes)?,
271 _ => return Err(CryptoError::InvalidKey),
272 }
273 }
274 (EncString::Unparseable { .. }, _) => return Err(CryptoError::UnparseableEncString),
275 _ => {
276 tracing::warn!(
277 "Unsupported unwrap operation for the given key and data {:?}, {:?}",
278 wrapping_key,
279 wrapped_key
280 );
281 return Err(CryptoError::InvalidKey);
282 }
283 };
284
285 let new_key_id = Ids::Symmetric::new_local(LocalId::new());
286
287 #[allow(deprecated)]
288 self.set_symmetric_key(new_key_id, key)?;
289
290 Ok(new_key_id)
292 }
293
294 pub fn persist_symmetric_key(
302 &mut self,
303 from: Ids::Symmetric,
304 to: Ids::Symmetric,
305 ) -> Result<()> {
306 if !from.is_local() || to.is_local() {
307 return Err(CryptoError::InvalidKeyStoreOperation);
308 }
309 let key = self.get_symmetric_key(from)?.to_owned();
310 self.drop_symmetric_key(from)?;
311 #[allow(deprecated)]
312 self.set_symmetric_key(to, key)?;
313 Ok(())
314 }
315
316 pub fn persist_private_key(&mut self, from: Ids::Private, to: Ids::Private) -> Result<()> {
324 if !from.is_local() || to.is_local() {
325 return Err(CryptoError::InvalidKeyStoreOperation);
326 }
327 let key = self.get_private_key(from)?.to_owned();
328 self.drop_private_key(from)?;
329 #[allow(deprecated)]
330 self.set_private_key(to, key)?;
331 Ok(())
332 }
333
334 pub fn persist_signing_key(&mut self, from: Ids::Signing, to: Ids::Signing) -> Result<()> {
341 if !from.is_local() || to.is_local() {
342 return Err(CryptoError::InvalidKeyStoreOperation);
343 }
344 let key = self.get_signing_key(from)?.to_owned();
345 self.drop_signing_key(from)?;
346 #[allow(deprecated)]
347 self.set_signing_key(to, key)?;
348 Ok(())
349 }
350
351 pub fn wrap_signing_key(
360 &self,
361 wrapping_key: Ids::Symmetric,
362 key_to_wrap: Ids::Signing,
363 ) -> Result<EncString> {
364 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
365 let signing_key = self.get_signing_key(key_to_wrap)?.to_owned();
366 signing_key.to_cose().encrypt_with_key(wrapping_key)
367 }
368
369 pub fn wrap_private_key(
377 &self,
378 wrapping_key: Ids::Symmetric,
379 key_to_wrap: Ids::Private,
380 ) -> Result<EncString> {
381 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
382 let private_key = self.get_private_key(key_to_wrap)?.to_owned();
383 private_key.to_der()?.encrypt_with_key(wrapping_key)
384 }
385
386 #[bitwarden_logging::instrument(err, fields(wrapping_key = ?wrapping_key))]
395 pub fn unwrap_private_key(
396 &mut self,
397 wrapping_key: Ids::Symmetric,
398 wrapped_key: &EncString,
399 ) -> Result<Ids::Private> {
400 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
401 let private_key_bytes: Vec<u8> = wrapped_key.decrypt_with_key(wrapping_key)?;
402 let private_key = PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(private_key_bytes))?;
403 Ok(self.add_local_private_key(private_key))
404 }
405
406 pub fn unwrap_signing_key(
415 &mut self,
416 wrapping_key: Ids::Symmetric,
417 wrapped_key: &EncString,
418 ) -> Result<Ids::Signing> {
419 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
420 let signing_key_bytes: Vec<u8> = wrapped_key.decrypt_with_key(wrapping_key)?;
421 let signing_key = SigningKey::from_cose(&CoseKeyBytes::from(signing_key_bytes))?;
422 Ok(self.add_local_signing_key(signing_key))
423 }
424
425 pub fn get_verifying_key(&self, signing_key_id: Ids::Signing) -> Result<VerifyingKey> {
433 let signing_key = self.get_signing_key(signing_key_id)?;
434 Ok(signing_key.to_verifying_key())
435 }
436
437 pub fn get_public_key(&self, private_key_id: Ids::Private) -> Result<PublicKey> {
444 let private_key = self.get_private_key(private_key_id)?;
445 Ok(private_key.to_public_key())
446 }
447
448 pub fn wrap_symmetric_key(
457 &self,
458 wrapping_key: Ids::Symmetric,
459 key_to_wrap: Ids::Symmetric,
460 ) -> Result<EncString> {
461 use SymmetricCryptoKey::*;
462
463 let wrapping_key_instance = self.get_symmetric_key(wrapping_key)?;
464 let key_to_wrap_instance = self.get_symmetric_key(key_to_wrap)?;
465 match (wrapping_key_instance, key_to_wrap_instance) {
470 (
471 Aes256CbcHmacKey(_),
472 Aes256CbcHmacKey(_)
473 | Aes256CbcKey(_)
474 | XChaCha20Poly1305Key(_)
475 | Aes256GcmKey(_)
476 | XAes256GcmKey(_),
477 ) => self.encrypt_data_with_symmetric_key(
478 wrapping_key,
479 key_to_wrap_instance
480 .to_encoded()
481 .as_ref()
482 .to_vec()
483 .as_slice(),
484 ContentFormat::BitwardenLegacyKey,
485 ),
486 (XChaCha20Poly1305Key(_), _) | (XAes256GcmKey(_), _) => {
487 let encoded = key_to_wrap_instance.to_encoded_raw();
488 let content_format = encoded.content_format();
489 self.encrypt_data_with_symmetric_key(
490 wrapping_key,
491 Into::<Vec<u8>>::into(encoded).as_slice(),
492 content_format,
493 )
494 }
495 _ => Err(CryptoError::OperationNotSupported(
496 UnsupportedOperationError::EncryptionNotImplementedForKey,
497 )),
498 }
499 }
500
501 pub fn has_symmetric_key(&self, key_id: Ids::Symmetric) -> bool {
503 self.get_symmetric_key(key_id).is_ok()
504 }
505
506 pub fn has_private_key(&self, key_id: Ids::Private) -> bool {
508 self.get_private_key(key_id).is_ok()
509 }
510
511 pub fn has_signing_key(&self, key_id: Ids::Signing) -> bool {
513 self.get_signing_key(key_id).is_ok()
514 }
515
516 pub fn generate_symmetric_key(&mut self) -> Ids::Symmetric {
518 self.add_local_symmetric_key(SymmetricCryptoKey::make_aes256_cbc_hmac_key())
519 }
520
521 pub fn make_symmetric_key(&mut self, algorithm: SymmetricKeyAlgorithm) -> Ids::Symmetric {
524 self.add_local_symmetric_key(SymmetricCryptoKey::make(algorithm))
525 }
526
527 pub fn make_private_key(&mut self, algorithm: PublicKeyEncryptionAlgorithm) -> Ids::Private {
530 self.add_local_private_key(PrivateKey::make(algorithm))
531 }
532
533 pub fn make_signing_key(&mut self, algorithm: SignatureAlgorithm) -> Ids::Signing {
536 self.add_local_signing_key(SigningKey::make(algorithm))
537 }
538
539 pub fn derive_shareable_key(
544 &mut self,
545 secret: Zeroizing<[u8; 16]>,
546 name: &str,
547 info: Option<&str>,
548 ) -> Result<Ids::Symmetric> {
549 let key_id = Ids::Symmetric::new_local(LocalId::new());
550 #[allow(deprecated)]
551 self.set_symmetric_key(
552 key_id,
553 SymmetricCryptoKey::Aes256CbcHmacKey(derive_shareable_key(secret, name, info)),
554 )?;
555 Ok(key_id)
556 }
557
558 #[deprecated(note = "This function should ideally never be used outside this crate")]
568 pub fn dangerous_get_symmetric_key(
569 &self,
570 key_id: Ids::Symmetric,
571 ) -> Result<&SymmetricCryptoKey> {
572 self.get_symmetric_key(key_id)
573 }
574
575 pub fn get_symmetric_key_id(&self, key_slot_id: Ids::Symmetric) -> Option<KeyId> {
577 let Ok(key) = self.get_symmetric_key(key_slot_id) else {
578 return None;
579 };
580 key.key_id()
581 }
582
583 #[deprecated(note = "This function should ideally never be used outside this crate")]
594 pub fn dangerous_get_signing_key(&self, key_id: Ids::Signing) -> Result<&SigningKey> {
595 self.get_signing_key(key_id)
596 }
597
598 #[deprecated(note = "This function should ideally never be used outside this crate")]
607 pub fn dangerous_get_private_key(&self, key_id: Ids::Private) -> Result<&PrivateKey> {
608 self.get_private_key(key_id)
609 }
610
611 pub fn make_signed_public_key(
615 &self,
616 private_key_id: Ids::Private,
617 signing_key_id: Ids::Signing,
618 ) -> Result<SignedPublicKey> {
619 let public_key = self.get_private_key(private_key_id)?.to_public_key();
620 let signing_key = self.get_signing_key(signing_key_id)?;
621 let signed_public_key =
622 SignedPublicKeyMessage::from_public_key(&public_key)?.sign(signing_key)?;
623 Ok(signed_public_key)
624 }
625
626 pub(crate) fn get_symmetric_key(&self, key_id: Ids::Symmetric) -> Result<&SymmetricCryptoKey> {
627 if key_id.is_local() {
628 self.local_symmetric_keys.get(key_id)
629 } else {
630 self.global_keys.get().symmetric_keys.get(key_id)
631 }
632 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
633 }
634
635 pub(super) fn get_private_key(&self, key_id: Ids::Private) -> Result<&PrivateKey> {
636 if key_id.is_local() {
637 self.local_private_keys.get(key_id)
638 } else {
639 self.global_keys.get().private_keys.get(key_id)
640 }
641 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
642 }
643
644 pub(super) fn get_signing_key(&self, key_id: Ids::Signing) -> Result<&SigningKey> {
645 if key_id.is_local() {
646 self.local_signing_keys.get(key_id)
647 } else {
648 self.global_keys.get().signing_keys.get(key_id)
649 }
650 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
651 }
652
653 #[deprecated(note = "This function should ideally never be used outside this crate")]
659 pub fn set_symmetric_key(
660 &mut self,
661 key_id: Ids::Symmetric,
662 key: SymmetricCryptoKey,
663 ) -> Result<()> {
664 self.set_symmetric_key_internal(key_id, key)
665 }
666
667 pub(crate) fn set_symmetric_key_internal(
668 &mut self,
669 key_id: Ids::Symmetric,
670 key: SymmetricCryptoKey,
671 ) -> Result<()> {
672 if key_id.is_local() {
673 self.local_symmetric_keys.upsert(key_id, key);
674 } else {
675 self.global_keys
676 .get_mut()?
677 .symmetric_keys
678 .upsert(key_id, key);
679 }
680 Ok(())
681 }
682
683 pub fn add_local_symmetric_key(&mut self, key: SymmetricCryptoKey) -> Ids::Symmetric {
685 let key_id = Ids::Symmetric::new_local(LocalId::new());
686 self.local_symmetric_keys.upsert(key_id, key);
687 key_id
688 }
689
690 pub fn get_symmetric_key_algorithm(
692 &self,
693 key_id: Ids::Symmetric,
694 ) -> Result<SymmetricKeyAlgorithm> {
695 let key = self.get_symmetric_key(key_id)?;
696 match key {
697 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
699 UnsupportedOperationError::EncryptionNotImplementedForKey,
700 )),
701 SymmetricCryptoKey::Aes256CbcHmacKey(_) => Ok(SymmetricKeyAlgorithm::Aes256CbcHmac),
702 SymmetricCryptoKey::XChaCha20Poly1305Key(_) => {
703 Ok(SymmetricKeyAlgorithm::XChaCha20Poly1305)
704 }
705 SymmetricCryptoKey::Aes256GcmKey(_) => Ok(SymmetricKeyAlgorithm::Aes256Gcm),
706 SymmetricCryptoKey::XAes256GcmKey(_) => Ok(SymmetricKeyAlgorithm::XAes256Gcm),
707 }
708 }
709
710 #[bitwarden_logging::instrument(err, fields(key_id = ?key_id))]
712 pub fn is_v1_symmetric_key(&self, key_id: Ids::Symmetric) -> Result<bool> {
713 let algorithm = self.get_symmetric_key_algorithm(key_id)?;
714 Ok(algorithm == SymmetricKeyAlgorithm::Aes256CbcHmac)
715 }
716
717 #[deprecated(note = "This function should ideally never be used outside this crate")]
723 pub fn set_private_key(&mut self, key_id: Ids::Private, key: PrivateKey) -> Result<()> {
724 if key_id.is_local() {
725 self.local_private_keys.upsert(key_id, key);
726 } else {
727 self.global_keys.get_mut()?.private_keys.upsert(key_id, key);
728 }
729 Ok(())
730 }
731
732 pub fn add_local_private_key(&mut self, key: PrivateKey) -> Ids::Private {
734 let key_id = Ids::Private::new_local(LocalId::new());
735 self.local_private_keys.upsert(key_id, key);
736 key_id
737 }
738
739 #[deprecated(note = "This function should ideally never be used outside this crate")]
745 pub fn set_signing_key(&mut self, key_id: Ids::Signing, key: SigningKey) -> Result<()> {
746 if key_id.is_local() {
747 self.local_signing_keys.upsert(key_id, key);
748 } else {
749 self.global_keys.get_mut()?.signing_keys.upsert(key_id, key);
750 }
751 Ok(())
752 }
753
754 pub fn add_local_signing_key(&mut self, key: SigningKey) -> Ids::Signing {
756 let key_id = Ids::Signing::new_local(LocalId::new());
757 self.local_signing_keys.upsert(key_id, key);
758 key_id
759 }
760
761 #[bitwarden_logging::instrument(err, level = "debug", fields(key = ?key))]
762 pub(crate) fn decrypt_data_with_symmetric_key(
763 &self,
764 key: Ids::Symmetric,
765 data: &EncString,
766 ) -> Result<Vec<u8>> {
767 let key = self.get_symmetric_key(key)?;
768
769 match (data, key) {
770 (EncString::Aes256Cbc_B64 { .. }, SymmetricCryptoKey::Aes256CbcKey(_)) => {
771 Err(CryptoError::OperationNotSupported(
772 UnsupportedOperationError::DecryptionNotImplementedForKey,
773 ))
774 }
775 (
776 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
777 SymmetricCryptoKey::Aes256CbcHmacKey(key),
778 ) => Aes256CbcHmacSha256::decrypt(iv, data, mac, key.as_composite_key())
779 .map_err(|_| CryptoError::Decrypt),
780 (
781 EncString::Cose_Encrypt0_B64 { data },
782 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
783 ) => {
784 let (data, _) = crate::cose::symmetric::decrypt_xchacha20_poly1305(
785 &CoseEncrypt0Bytes::from(data.clone()),
786 key,
787 )?;
788 Ok(data)
789 }
790 (EncString::Cose_Encrypt0_B64 { data }, SymmetricCryptoKey::XAes256GcmKey(key)) => {
791 let (data, _) = crate::cose::symmetric::decrypt_xaes256_gcm(
792 &CoseEncrypt0Bytes::from(data.clone()),
793 key,
794 )?;
795 Ok(data)
796 }
797 (EncString::Unparseable { .. }, _) => Err(CryptoError::UnparseableEncString),
798 _ => {
799 tracing::warn!("Unsupported decryption operation for the given key and data");
800 Err(CryptoError::InvalidKey)
801 }
802 }
803 }
804
805 pub(crate) fn encrypt_data_with_symmetric_key(
806 &self,
807 key: Ids::Symmetric,
808 data: &[u8],
809 content_format: ContentFormat,
810 ) -> Result<EncString> {
811 let key = self.get_symmetric_key(key)?;
812 match key {
813 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
814 UnsupportedOperationError::EncryptionNotImplementedForKey,
815 )),
816 SymmetricCryptoKey::Aes256CbcHmacKey(key) => EncString::encrypt_aes256_hmac(data, key),
817 SymmetricCryptoKey::XChaCha20Poly1305Key(key) => {
818 if !key.supported_operations.contains(&KeyOperation::Encrypt) {
819 return Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt));
820 }
821 EncString::encrypt_xchacha20_poly1305(data, key, content_format)
822 }
823 SymmetricCryptoKey::Aes256GcmKey(_) => Err(CryptoError::OperationNotSupported(
824 UnsupportedOperationError::EncryptionNotImplementedForKey,
825 )),
826 SymmetricCryptoKey::XAes256GcmKey(key) => {
827 if !key.supported_operations.contains(&KeyOperation::Encrypt) {
828 return Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt));
829 }
830 EncString::encrypt_xaes256_gcm(data, key, content_format)
831 }
832 }
833 }
834
835 pub fn sign<Message: Serialize>(
839 &self,
840 key: Ids::Signing,
841 message: &Message,
842 namespace: &crate::SigningNamespace,
843 ) -> Result<SignedObject> {
844 self.get_signing_key(key)?.sign(message, namespace)
845 }
846
847 #[allow(unused)]
851 pub(crate) fn sign_detached<Message: Serialize>(
852 &self,
853 key: Ids::Signing,
854 message: &Message,
855 namespace: &crate::SigningNamespace,
856 ) -> Result<(Signature, signing::SerializedMessage)> {
857 self.get_signing_key(key)?.sign_detached(message, namespace)
858 }
859
860 #[cfg(any(test, feature = "test-utils"))]
863 pub fn assert_symmetric_keys_equal(&self, key_id_1: Ids::Symmetric, key_id_2: Ids::Symmetric) {
864 let key_1 = self
865 .get_symmetric_key(key_id_1)
866 .expect("Key 1 should exist in context");
867 let key_2 = self
868 .get_symmetric_key(key_id_2)
869 .expect("Key 2 should exist in context");
870 if key_1 != key_2 {
871 panic!(
872 "Symmetric keys with ids {:?} and {:?} are not equal",
873 key_id_1, key_id_2,
874 );
875 }
876 }
877
878 #[cfg(any(test, feature = "test-utils"))]
881 pub fn assert_symmetric_keys_not_equal(
882 &self,
883 key_id_1: Ids::Symmetric,
884 key_id_2: Ids::Symmetric,
885 ) {
886 let key_1 = self
887 .get_symmetric_key(key_id_1)
888 .expect("Key 1 should exist in context");
889 let key_2 = self
890 .get_symmetric_key(key_id_2)
891 .expect("Key 2 should exist in context");
892 if key_1 == key_2 {
893 panic!(
894 "Symmetric keys with ids {:?} and {:?} are equal",
895 key_id_1, key_id_2,
896 );
897 }
898 }
899}
900
901#[cfg(test)]
902#[allow(deprecated)]
903mod tests {
904 use serde::{Deserialize, Serialize};
905
906 use crate::{
907 CompositeEncryptable, CryptoError, Decryptable, EncString, SignatureAlgorithm, SigningKey,
908 SigningNamespace, SymmetricCryptoKey, SymmetricKeyAlgorithm,
909 store::{
910 KeyStore,
911 tests::{Data, DataView},
912 },
913 traits::tests::{TestIds, TestSigningKey, TestSymmKey},
914 };
915
916 #[test]
917 fn test_set_signing_key() {
918 let store: KeyStore<TestIds> = KeyStore::default();
919
920 let key_a0_id = TestSigningKey::A(0);
922 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
923 store
924 .context_mut()
925 .set_signing_key(key_a0_id, key_a0)
926 .unwrap();
927 }
928
929 #[test]
930 fn test_set_keys_for_encryption() {
931 let store: KeyStore<TestIds> = KeyStore::default();
932
933 let key_a0_id = TestSymmKey::A(0);
935 let mut ctx = store.context_mut();
936 let local_key_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
937 ctx.persist_symmetric_key(local_key_id, TestSymmKey::A(0))
938 .unwrap();
939
940 assert!(ctx.has_symmetric_key(key_a0_id));
941
942 let data = DataView("Hello, World!".to_string(), key_a0_id);
944 let _encrypted: Data = data.encrypt_composite(&mut ctx, key_a0_id).unwrap();
945 }
946
947 #[test]
948 fn test_key_encryption() {
949 let store: KeyStore<TestIds> = KeyStore::default();
950
951 let mut ctx = store.context();
952
953 let key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
955
956 assert!(ctx.has_symmetric_key(key_1_id));
957
958 let key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
960
961 assert!(ctx.has_symmetric_key(key_2_id));
962
963 let key_2_enc = ctx.wrap_symmetric_key(key_1_id, key_2_id).unwrap();
965
966 let new_key_id = ctx.unwrap_symmetric_key(key_1_id, &key_2_enc).unwrap();
968
969 let data = DataView("Hello, World!".to_string(), key_2_id);
973 let encrypted = data.encrypt_composite(&mut ctx, key_2_id).unwrap();
974
975 let decrypted1 = encrypted.decrypt(&mut ctx, key_2_id).unwrap();
976 let decrypted2 = encrypted.decrypt(&mut ctx, new_key_id).unwrap();
977
978 assert_eq!(decrypted1.0, decrypted2.0);
980 }
981
982 #[test]
983 fn test_wrap_unwrap() {
984 let store: KeyStore<TestIds> = KeyStore::default();
985 let mut ctx = store.context_mut();
986
987 let cbc = TestSymmKey::A(1);
988 let xchacha = TestSymmKey::A(2);
989 let aes_gcm = TestSymmKey::A(3);
990 let xaes = TestSymmKey::A(4);
991 for (id, key) in [
992 (
993 cbc,
994 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac),
995 ),
996 (
997 xchacha,
998 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XChaCha20Poly1305),
999 ),
1000 (
1001 aes_gcm,
1002 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256Gcm),
1003 ),
1004 (
1005 xaes,
1006 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1007 ),
1008 ] {
1009 ctx.set_symmetric_key(id, key).unwrap();
1010 }
1011
1012 for (wrapping_key, wrapped_key) in [
1013 (cbc, cbc),
1014 (cbc, xchacha),
1015 (xchacha, cbc),
1016 (xchacha, xchacha),
1017 (xaes, cbc),
1018 (xaes, xchacha),
1019 (xaes, aes_gcm),
1020 (xaes, xaes),
1021 (cbc, xaes),
1022 (xchacha, xaes),
1023 ] {
1024 let encrypted = ctx.wrap_symmetric_key(wrapping_key, wrapped_key).unwrap();
1025 let unwrapped = ctx.unwrap_symmetric_key(wrapping_key, &encrypted).unwrap();
1026 ctx.assert_symmetric_keys_equal(unwrapped, wrapped_key);
1027 }
1028 }
1029
1030 #[test]
1031 fn test_signing() {
1032 let store: KeyStore<TestIds> = KeyStore::default();
1033
1034 let key_a0_id = TestSigningKey::A(0);
1036 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
1037 let verifying_key = key_a0.to_verifying_key();
1038 store
1039 .context_mut()
1040 .set_signing_key(key_a0_id, key_a0)
1041 .unwrap();
1042
1043 assert!(store.context().has_signing_key(key_a0_id));
1044
1045 #[derive(Serialize, Deserialize)]
1047 struct TestData {
1048 data: String,
1049 }
1050 let signed_object = store
1051 .context()
1052 .sign(
1053 key_a0_id,
1054 &TestData {
1055 data: "Hello".to_string(),
1056 },
1057 &SigningNamespace::ExampleNamespace,
1058 )
1059 .unwrap();
1060 let payload: Result<TestData, CryptoError> =
1061 signed_object.verify_and_unwrap(&verifying_key, &SigningNamespace::ExampleNamespace);
1062 assert!(payload.is_ok());
1063
1064 let (signature, serialized_message) = store
1065 .context()
1066 .sign_detached(
1067 key_a0_id,
1068 &TestData {
1069 data: "Hello".to_string(),
1070 },
1071 &SigningNamespace::ExampleNamespace,
1072 )
1073 .unwrap();
1074 assert!(signature.verify(
1075 serialized_message.as_bytes(),
1076 &verifying_key,
1077 &SigningNamespace::ExampleNamespace
1078 ))
1079 }
1080
1081 #[test]
1082 fn test_encrypt_fails_when_operation_not_allowed() {
1083 use coset::iana::KeyOperation;
1084 let store = KeyStore::<TestIds>::default();
1085 let mut ctx = store.context_mut();
1086 let key_id = TestSymmKey::A(0);
1087 let key = SymmetricCryptoKey::XChaCha20Poly1305Key(crate::XChaCha20Poly1305Key {
1089 key_id: [0u8; 16].into(),
1090 enc_key: Box::pin([0u8; 32].into()),
1091 supported_operations: vec![KeyOperation::Decrypt],
1092 });
1093 ctx.set_symmetric_key(key_id, key).unwrap();
1094 let data = DataView("should fail".to_string(), key_id);
1095 let result = data.encrypt_composite(&mut ctx, key_id);
1096 assert!(
1097 matches!(
1098 result,
1099 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1100 ),
1101 "Expected encrypt to fail with KeyOperationNotSupported",
1102 );
1103 }
1104
1105 #[test]
1106 fn test_xaes_data_roundtrip_and_encrypt_operation() {
1107 use coset::iana::KeyOperation;
1108
1109 let store = KeyStore::<TestIds>::default();
1110 let mut ctx = store.context_mut();
1111 let key_id = TestSymmKey::A(0);
1112 ctx.set_symmetric_key(
1113 key_id,
1114 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1115 )
1116 .unwrap();
1117
1118 let plaintext = b"data encrypted directly by the key store";
1119 let encrypted = ctx
1120 .encrypt_data_with_symmetric_key(key_id, plaintext, crate::ContentFormat::OctetStream)
1121 .unwrap();
1122 assert_eq!(
1123 ctx.decrypt_data_with_symmetric_key(key_id, &encrypted)
1124 .unwrap(),
1125 plaintext
1126 );
1127
1128 let no_encrypt = TestSymmKey::A(1);
1129 ctx.set_symmetric_key(
1130 no_encrypt,
1131 SymmetricCryptoKey::XAes256GcmKey(crate::XAes256GcmKey {
1132 key_id: [1; 16].into(),
1133 enc_key: Box::pin([1; 32].into()),
1134 supported_operations: vec![KeyOperation::Decrypt],
1135 }),
1136 )
1137 .unwrap();
1138 assert!(matches!(
1139 ctx.encrypt_data_with_symmetric_key(
1140 no_encrypt,
1141 plaintext,
1142 crate::ContentFormat::OctetStream,
1143 ),
1144 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1145 ));
1146 }
1147
1148 #[test]
1149 fn test_xaes_key_store_rejects_unsupported_inputs() {
1150 let store = KeyStore::<TestIds>::default();
1151 let mut ctx = store.context_mut();
1152 let xaes = TestSymmKey::A(0);
1153 ctx.set_symmetric_key(
1154 xaes,
1155 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1156 )
1157 .unwrap();
1158
1159 let non_key = ctx
1160 .encrypt_data_with_symmetric_key(xaes, b"not a key", crate::ContentFormat::OctetStream)
1161 .unwrap();
1162 assert!(matches!(
1163 ctx.unwrap_symmetric_key(xaes, &non_key),
1164 Err(CryptoError::InvalidKey)
1165 ));
1166
1167 let legacy_data =
1168 EncString::encrypt_aes256_hmac(b"data", &crate::derive_symmetric_key("test key"))
1169 .unwrap();
1170 assert!(matches!(
1171 ctx.decrypt_data_with_symmetric_key(xaes, &legacy_data),
1172 Err(CryptoError::InvalidKey)
1173 ));
1174 }
1175
1176 #[test]
1177 fn test_move_key() {
1178 let store: KeyStore<TestIds> = KeyStore::default();
1179 let mut ctx = store.context_mut();
1180
1181 let key = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
1183
1184 assert!(ctx.has_symmetric_key(key));
1185
1186 let new_key_id = TestSymmKey::A(1);
1188 ctx.persist_symmetric_key(key, new_key_id).unwrap();
1189
1190 assert!(!ctx.has_symmetric_key(key));
1192 assert!(ctx.has_symmetric_key(new_key_id));
1193 }
1194
1195 #[test]
1196 fn test_encrypt_decrypt_data_fails_when_key_is_type_0() {
1197 let store = KeyStore::<TestIds>::default();
1198 let mut ctx = store.context_mut();
1199
1200 let key_id = TestSymmKey::A(0);
1201 let key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1202 enc_key: Box::pin([0u8; 32].into()),
1203 });
1204 ctx.set_symmetric_key_internal(key_id, key).unwrap();
1205
1206 let data_to_encrypt: Vec<u8> = vec![1, 2, 3, 4, 5];
1207 let result = ctx.encrypt_data_with_symmetric_key(
1208 key_id,
1209 &data_to_encrypt,
1210 crate::ContentFormat::OctetStream,
1211 );
1212 assert!(
1213 matches!(
1214 result,
1215 Err(CryptoError::OperationNotSupported(
1216 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1217 ))
1218 ),
1219 "Expected encrypt to fail when using deprecated type 0 keys",
1220 );
1221
1222 let data_to_decrypt = EncString::Aes256Cbc_B64 {
1223 iv: [0; 16],
1224 data: data_to_encrypt,
1225 }; let result = ctx.decrypt_data_with_symmetric_key(key_id, &data_to_decrypt);
1227 assert!(
1228 matches!(
1229 result,
1230 Err(CryptoError::OperationNotSupported(
1231 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1232 ))
1233 ),
1234 "Expected decrypt to fail when using deprecated type 0 keys",
1235 );
1236 }
1237
1238 #[test]
1240 fn test_decrypt_and_unwrap_fail_for_unparseable_enc_string() {
1241 let store = KeyStore::<TestIds>::default();
1242 let mut ctx = store.context_mut();
1243
1244 let key_id = TestSymmKey::A(0);
1245 ctx.set_symmetric_key_internal(key_id, SymmetricCryptoKey::make_aes256_cbc_hmac_key())
1246 .unwrap();
1247
1248 let unparseable: EncString = "2.AAECAw==|Y3Q=|AAECAw==".parse().unwrap();
1249
1250 assert!(matches!(
1251 ctx.decrypt_data_with_symmetric_key(key_id, &unparseable),
1252 Err(CryptoError::UnparseableEncString)
1253 ));
1254 assert!(matches!(
1255 ctx.unwrap_symmetric_key(key_id, &unparseable),
1256 Err(CryptoError::UnparseableEncString)
1257 ));
1258 }
1259
1260 #[test]
1261 fn test_wrap_unwrap_key_fails_when_key_is_type_0() {
1262 let store = KeyStore::<TestIds>::default();
1263 let mut ctx = store.context_mut();
1264
1265 let wrapping_key_id = TestSymmKey::A(0);
1266 let wrapping_key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1267 enc_key: Box::pin([0u8; 32].into()),
1268 });
1269 ctx.set_symmetric_key_internal(wrapping_key_id, wrapping_key)
1270 .unwrap();
1271
1272 let key_to_wrap_id = TestSymmKey::A(1);
1273 let key_to_wrap = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
1274 ctx.set_symmetric_key_internal(key_to_wrap_id, key_to_wrap)
1275 .unwrap();
1276
1277 let result = ctx.wrap_symmetric_key(wrapping_key_id, key_to_wrap_id);
1278 assert!(
1279 matches!(
1280 result,
1281 Err(CryptoError::OperationNotSupported(
1282 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1283 ))
1284 ),
1285 "Expected encrypt to fail when using deprecated type 0 keys",
1286 );
1287
1288 let wrapped_key = &EncString::Aes256Cbc_B64 {
1289 iv: [0; 16],
1290 data: vec![0],
1291 }; let result = ctx.unwrap_symmetric_key(wrapping_key_id, wrapped_key);
1293 assert!(
1294 matches!(
1295 result,
1296 Err(CryptoError::OperationNotSupported(
1297 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1298 ))
1299 ),
1300 "Expected decrypt to fail when using deprecated type 0 keys",
1301 );
1302 }
1303}