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,
15 RotatedUserKeys, Signature, SignatureAlgorithm, SignedObject, SignedPublicKey,
16 SignedPublicKeyMessage, SigningKey, SymmetricCryptoKey, SymmetricKeyAlgorithm, VerifyingKey,
17 derive_shareable_key, error::UnsupportedOperationError,
18 hazmat::symmetric_encryption::Aes256CbcHmacSha256, 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) 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, 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 pub fn dangerous_get_v2_rotated_account_keys(
862 &self,
863 current_user_private_key_id: Ids::Private,
864 current_user_signing_key_id: Ids::Signing,
865 ) -> Result<RotatedUserKeys> {
866 #[expect(deprecated)]
867 crate::dangerous_get_v2_rotated_account_keys(
868 current_user_private_key_id,
869 current_user_signing_key_id,
870 self,
871 )
872 }
873
874 #[cfg(any(test, feature = "test-utils"))]
877 pub fn assert_symmetric_keys_equal(&self, key_id_1: Ids::Symmetric, key_id_2: Ids::Symmetric) {
878 let key_1 = self
879 .get_symmetric_key(key_id_1)
880 .expect("Key 1 should exist in context");
881 let key_2 = self
882 .get_symmetric_key(key_id_2)
883 .expect("Key 2 should exist in context");
884 if key_1 != key_2 {
885 panic!(
886 "Symmetric keys with ids {:?} and {:?} are not equal",
887 key_id_1, key_id_2,
888 );
889 }
890 }
891
892 #[cfg(any(test, feature = "test-utils"))]
895 pub fn assert_symmetric_keys_not_equal(
896 &self,
897 key_id_1: Ids::Symmetric,
898 key_id_2: Ids::Symmetric,
899 ) {
900 let key_1 = self
901 .get_symmetric_key(key_id_1)
902 .expect("Key 1 should exist in context");
903 let key_2 = self
904 .get_symmetric_key(key_id_2)
905 .expect("Key 2 should exist in context");
906 if key_1 == key_2 {
907 panic!(
908 "Symmetric keys with ids {:?} and {:?} are equal",
909 key_id_1, key_id_2,
910 );
911 }
912 }
913}
914
915#[cfg(test)]
916#[allow(deprecated)]
917mod tests {
918 use serde::{Deserialize, Serialize};
919
920 use crate::{
921 CompositeEncryptable, CoseKeyBytes, CoseSerializable, CryptoError, Decryptable, EncString,
922 KeyDecryptable, Pkcs8PrivateKeyBytes, PrivateKey, PublicKey, PublicKeyEncryptionAlgorithm,
923 SignatureAlgorithm, SigningKey, SigningNamespace, SymmetricCryptoKey,
924 SymmetricKeyAlgorithm,
925 store::{
926 KeyStore,
927 tests::{Data, DataView},
928 },
929 traits::tests::{TestIds, TestSigningKey, TestSymmKey},
930 };
931
932 #[test]
933 fn test_set_signing_key() {
934 let store: KeyStore<TestIds> = KeyStore::default();
935
936 let key_a0_id = TestSigningKey::A(0);
938 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
939 store
940 .context_mut()
941 .set_signing_key(key_a0_id, key_a0)
942 .unwrap();
943 }
944
945 #[test]
946 fn test_set_keys_for_encryption() {
947 let store: KeyStore<TestIds> = KeyStore::default();
948
949 let key_a0_id = TestSymmKey::A(0);
951 let mut ctx = store.context_mut();
952 let local_key_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
953 ctx.persist_symmetric_key(local_key_id, TestSymmKey::A(0))
954 .unwrap();
955
956 assert!(ctx.has_symmetric_key(key_a0_id));
957
958 let data = DataView("Hello, World!".to_string(), key_a0_id);
960 let _encrypted: Data = data.encrypt_composite(&mut ctx, key_a0_id).unwrap();
961 }
962
963 #[test]
964 fn test_key_encryption() {
965 let store: KeyStore<TestIds> = KeyStore::default();
966
967 let mut ctx = store.context();
968
969 let key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
971
972 assert!(ctx.has_symmetric_key(key_1_id));
973
974 let key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
976
977 assert!(ctx.has_symmetric_key(key_2_id));
978
979 let key_2_enc = ctx.wrap_symmetric_key(key_1_id, key_2_id).unwrap();
981
982 let new_key_id = ctx.unwrap_symmetric_key(key_1_id, &key_2_enc).unwrap();
984
985 let data = DataView("Hello, World!".to_string(), key_2_id);
989 let encrypted = data.encrypt_composite(&mut ctx, key_2_id).unwrap();
990
991 let decrypted1 = encrypted.decrypt(&mut ctx, key_2_id).unwrap();
992 let decrypted2 = encrypted.decrypt(&mut ctx, new_key_id).unwrap();
993
994 assert_eq!(decrypted1.0, decrypted2.0);
996 }
997
998 #[test]
999 fn test_wrap_unwrap() {
1000 let store: KeyStore<TestIds> = KeyStore::default();
1001 let mut ctx = store.context_mut();
1002
1003 let cbc = TestSymmKey::A(1);
1004 let xchacha = TestSymmKey::A(2);
1005 let aes_gcm = TestSymmKey::A(3);
1006 let xaes = TestSymmKey::A(4);
1007 for (id, key) in [
1008 (
1009 cbc,
1010 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac),
1011 ),
1012 (
1013 xchacha,
1014 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XChaCha20Poly1305),
1015 ),
1016 (
1017 aes_gcm,
1018 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256Gcm),
1019 ),
1020 (
1021 xaes,
1022 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1023 ),
1024 ] {
1025 ctx.set_symmetric_key(id, key).unwrap();
1026 }
1027
1028 for (wrapping_key, wrapped_key) in [
1029 (cbc, cbc),
1030 (cbc, xchacha),
1031 (xchacha, cbc),
1032 (xchacha, xchacha),
1033 (xaes, cbc),
1034 (xaes, xchacha),
1035 (xaes, aes_gcm),
1036 (xaes, xaes),
1037 (cbc, xaes),
1038 (xchacha, xaes),
1039 ] {
1040 let encrypted = ctx.wrap_symmetric_key(wrapping_key, wrapped_key).unwrap();
1041 let unwrapped = ctx.unwrap_symmetric_key(wrapping_key, &encrypted).unwrap();
1042 ctx.assert_symmetric_keys_equal(unwrapped, wrapped_key);
1043 }
1044 }
1045
1046 #[test]
1047 fn test_signing() {
1048 let store: KeyStore<TestIds> = KeyStore::default();
1049
1050 let key_a0_id = TestSigningKey::A(0);
1052 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
1053 let verifying_key = key_a0.to_verifying_key();
1054 store
1055 .context_mut()
1056 .set_signing_key(key_a0_id, key_a0)
1057 .unwrap();
1058
1059 assert!(store.context().has_signing_key(key_a0_id));
1060
1061 #[derive(Serialize, Deserialize)]
1063 struct TestData {
1064 data: String,
1065 }
1066 let signed_object = store
1067 .context()
1068 .sign(
1069 key_a0_id,
1070 &TestData {
1071 data: "Hello".to_string(),
1072 },
1073 &SigningNamespace::ExampleNamespace,
1074 )
1075 .unwrap();
1076 let payload: Result<TestData, CryptoError> =
1077 signed_object.verify_and_unwrap(&verifying_key, &SigningNamespace::ExampleNamespace);
1078 assert!(payload.is_ok());
1079
1080 let (signature, serialized_message) = store
1081 .context()
1082 .sign_detached(
1083 key_a0_id,
1084 &TestData {
1085 data: "Hello".to_string(),
1086 },
1087 &SigningNamespace::ExampleNamespace,
1088 )
1089 .unwrap();
1090 assert!(signature.verify(
1091 serialized_message.as_bytes(),
1092 &verifying_key,
1093 &SigningNamespace::ExampleNamespace
1094 ))
1095 }
1096
1097 #[test]
1098 fn test_account_key_rotation() {
1099 let store: KeyStore<TestIds> = KeyStore::default();
1100 let mut ctx = store.context_mut();
1101
1102 let current_user_signing_key_id = ctx.make_signing_key(SignatureAlgorithm::Ed25519);
1104 let current_user_private_key_id =
1105 ctx.make_private_key(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
1106
1107 let rotated_keys = ctx
1109 .dangerous_get_v2_rotated_account_keys(
1110 current_user_private_key_id,
1111 current_user_signing_key_id,
1112 )
1113 .unwrap();
1114
1115 assert_eq!(
1117 PublicKey::from_der(&rotated_keys.public_key)
1118 .unwrap()
1119 .to_der()
1120 .unwrap(),
1121 ctx.get_private_key(current_user_private_key_id)
1122 .unwrap()
1123 .to_public_key()
1124 .to_der()
1125 .unwrap()
1126 );
1127 let decrypted_private_key: Vec<u8> = rotated_keys
1128 .private_key
1129 .decrypt_with_key(&rotated_keys.user_key)
1130 .unwrap();
1131 let private_key =
1132 PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key)).unwrap();
1133 assert_eq!(
1134 private_key.to_der().unwrap(),
1135 ctx.get_private_key(current_user_private_key_id)
1136 .unwrap()
1137 .to_der()
1138 .unwrap()
1139 );
1140
1141 let decrypted_signing_key: Vec<u8> = rotated_keys
1143 .signing_key
1144 .decrypt_with_key(&rotated_keys.user_key)
1145 .unwrap();
1146 let signing_key =
1147 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
1148 assert_eq!(
1149 signing_key.to_cose(),
1150 ctx.get_signing_key(current_user_signing_key_id)
1151 .unwrap()
1152 .to_cose(),
1153 );
1154
1155 let signed_public_key = rotated_keys.signed_public_key;
1157 let unwrapped_key = signed_public_key
1158 .verify_and_unwrap(
1159 &ctx.get_signing_key(current_user_signing_key_id)
1160 .unwrap()
1161 .to_verifying_key(),
1162 )
1163 .unwrap();
1164 assert_eq!(
1165 unwrapped_key.to_der().unwrap(),
1166 ctx.get_private_key(current_user_private_key_id)
1167 .unwrap()
1168 .to_public_key()
1169 .to_der()
1170 .unwrap()
1171 );
1172 }
1173
1174 #[test]
1175 fn test_encrypt_fails_when_operation_not_allowed() {
1176 use coset::iana::KeyOperation;
1177 let store = KeyStore::<TestIds>::default();
1178 let mut ctx = store.context_mut();
1179 let key_id = TestSymmKey::A(0);
1180 let key = SymmetricCryptoKey::XChaCha20Poly1305Key(crate::XChaCha20Poly1305Key {
1182 key_id: [0u8; 16].into(),
1183 enc_key: Box::pin([0u8; 32].into()),
1184 supported_operations: vec![KeyOperation::Decrypt],
1185 });
1186 ctx.set_symmetric_key(key_id, key).unwrap();
1187 let data = DataView("should fail".to_string(), key_id);
1188 let result = data.encrypt_composite(&mut ctx, key_id);
1189 assert!(
1190 matches!(
1191 result,
1192 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1193 ),
1194 "Expected encrypt to fail with KeyOperationNotSupported",
1195 );
1196 }
1197
1198 #[test]
1199 fn test_xaes_data_roundtrip_and_encrypt_operation() {
1200 use coset::iana::KeyOperation;
1201
1202 let store = KeyStore::<TestIds>::default();
1203 let mut ctx = store.context_mut();
1204 let key_id = TestSymmKey::A(0);
1205 ctx.set_symmetric_key(
1206 key_id,
1207 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1208 )
1209 .unwrap();
1210
1211 let plaintext = b"data encrypted directly by the key store";
1212 let encrypted = ctx
1213 .encrypt_data_with_symmetric_key(key_id, plaintext, crate::ContentFormat::OctetStream)
1214 .unwrap();
1215 assert_eq!(
1216 ctx.decrypt_data_with_symmetric_key(key_id, &encrypted)
1217 .unwrap(),
1218 plaintext
1219 );
1220
1221 let no_encrypt = TestSymmKey::A(1);
1222 ctx.set_symmetric_key(
1223 no_encrypt,
1224 SymmetricCryptoKey::XAes256GcmKey(crate::XAes256GcmKey {
1225 key_id: [1; 16].into(),
1226 enc_key: Box::pin([1; 32].into()),
1227 supported_operations: vec![KeyOperation::Decrypt],
1228 }),
1229 )
1230 .unwrap();
1231 assert!(matches!(
1232 ctx.encrypt_data_with_symmetric_key(
1233 no_encrypt,
1234 plaintext,
1235 crate::ContentFormat::OctetStream,
1236 ),
1237 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1238 ));
1239 }
1240
1241 #[test]
1242 fn test_xaes_key_store_rejects_unsupported_inputs() {
1243 let store = KeyStore::<TestIds>::default();
1244 let mut ctx = store.context_mut();
1245 let xaes = TestSymmKey::A(0);
1246 ctx.set_symmetric_key(
1247 xaes,
1248 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1249 )
1250 .unwrap();
1251
1252 let non_key = ctx
1253 .encrypt_data_with_symmetric_key(xaes, b"not a key", crate::ContentFormat::OctetStream)
1254 .unwrap();
1255 assert!(matches!(
1256 ctx.unwrap_symmetric_key(xaes, &non_key),
1257 Err(CryptoError::InvalidKey)
1258 ));
1259
1260 let legacy_data =
1261 EncString::encrypt_aes256_hmac(b"data", &crate::derive_symmetric_key("test key"))
1262 .unwrap();
1263 assert!(matches!(
1264 ctx.decrypt_data_with_symmetric_key(xaes, &legacy_data),
1265 Err(CryptoError::InvalidKey)
1266 ));
1267 }
1268
1269 #[test]
1270 fn test_move_key() {
1271 let store: KeyStore<TestIds> = KeyStore::default();
1272 let mut ctx = store.context_mut();
1273
1274 let key = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
1276
1277 assert!(ctx.has_symmetric_key(key));
1278
1279 let new_key_id = TestSymmKey::A(1);
1281 ctx.persist_symmetric_key(key, new_key_id).unwrap();
1282
1283 assert!(!ctx.has_symmetric_key(key));
1285 assert!(ctx.has_symmetric_key(new_key_id));
1286 }
1287
1288 #[test]
1289 fn test_encrypt_decrypt_data_fails_when_key_is_type_0() {
1290 let store = KeyStore::<TestIds>::default();
1291 let mut ctx = store.context_mut();
1292
1293 let key_id = TestSymmKey::A(0);
1294 let key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1295 enc_key: Box::pin([0u8; 32].into()),
1296 });
1297 ctx.set_symmetric_key_internal(key_id, key).unwrap();
1298
1299 let data_to_encrypt: Vec<u8> = vec![1, 2, 3, 4, 5];
1300 let result = ctx.encrypt_data_with_symmetric_key(
1301 key_id,
1302 &data_to_encrypt,
1303 crate::ContentFormat::OctetStream,
1304 );
1305 assert!(
1306 matches!(
1307 result,
1308 Err(CryptoError::OperationNotSupported(
1309 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1310 ))
1311 ),
1312 "Expected encrypt to fail when using deprecated type 0 keys",
1313 );
1314
1315 let data_to_decrypt = EncString::Aes256Cbc_B64 {
1316 iv: [0; 16],
1317 data: data_to_encrypt,
1318 }; let result = ctx.decrypt_data_with_symmetric_key(key_id, &data_to_decrypt);
1320 assert!(
1321 matches!(
1322 result,
1323 Err(CryptoError::OperationNotSupported(
1324 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1325 ))
1326 ),
1327 "Expected decrypt to fail when using deprecated type 0 keys",
1328 );
1329 }
1330
1331 #[test]
1333 fn test_decrypt_and_unwrap_fail_for_unparseable_enc_string() {
1334 let store = KeyStore::<TestIds>::default();
1335 let mut ctx = store.context_mut();
1336
1337 let key_id = TestSymmKey::A(0);
1338 ctx.set_symmetric_key_internal(key_id, SymmetricCryptoKey::make_aes256_cbc_hmac_key())
1339 .unwrap();
1340
1341 let unparseable: EncString = "2.AAECAw==|Y3Q=|AAECAw==".parse().unwrap();
1342
1343 assert!(matches!(
1344 ctx.decrypt_data_with_symmetric_key(key_id, &unparseable),
1345 Err(CryptoError::UnparseableEncString)
1346 ));
1347 assert!(matches!(
1348 ctx.unwrap_symmetric_key(key_id, &unparseable),
1349 Err(CryptoError::UnparseableEncString)
1350 ));
1351 }
1352
1353 #[test]
1354 fn test_wrap_unwrap_key_fails_when_key_is_type_0() {
1355 let store = KeyStore::<TestIds>::default();
1356 let mut ctx = store.context_mut();
1357
1358 let wrapping_key_id = TestSymmKey::A(0);
1359 let wrapping_key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1360 enc_key: Box::pin([0u8; 32].into()),
1361 });
1362 ctx.set_symmetric_key_internal(wrapping_key_id, wrapping_key)
1363 .unwrap();
1364
1365 let key_to_wrap_id = TestSymmKey::A(1);
1366 let key_to_wrap = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
1367 ctx.set_symmetric_key_internal(key_to_wrap_id, key_to_wrap)
1368 .unwrap();
1369
1370 let result = ctx.wrap_symmetric_key(wrapping_key_id, key_to_wrap_id);
1371 assert!(
1372 matches!(
1373 result,
1374 Err(CryptoError::OperationNotSupported(
1375 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1376 ))
1377 ),
1378 "Expected encrypt to fail when using deprecated type 0 keys",
1379 );
1380
1381 let wrapped_key = &EncString::Aes256Cbc_B64 {
1382 iv: [0; 16],
1383 data: vec![0],
1384 }; let result = ctx.unwrap_symmetric_key(wrapping_key_id, wrapped_key);
1386 assert!(
1387 matches!(
1388 result,
1389 Err(CryptoError::OperationNotSupported(
1390 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1391 ))
1392 ),
1393 "Expected decrypt to fail when using deprecated type 0 keys",
1394 );
1395 }
1396}