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.to_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 _ => {
275 tracing::warn!(
276 "Unsupported unwrap operation for the given key and data {:?}, {:?}",
277 wrapping_key,
278 wrapped_key
279 );
280 return Err(CryptoError::InvalidKey);
281 }
282 };
283
284 let new_key_id = Ids::Symmetric::new_local(LocalId::new());
285
286 #[allow(deprecated)]
287 self.set_symmetric_key(new_key_id, key)?;
288
289 Ok(new_key_id)
291 }
292
293 pub fn persist_symmetric_key(
301 &mut self,
302 from: Ids::Symmetric,
303 to: Ids::Symmetric,
304 ) -> Result<()> {
305 if !from.is_local() || to.is_local() {
306 return Err(CryptoError::InvalidKeyStoreOperation);
307 }
308 let key = self.get_symmetric_key(from)?.to_owned();
309 self.drop_symmetric_key(from)?;
310 #[allow(deprecated)]
311 self.set_symmetric_key(to, key)?;
312 Ok(())
313 }
314
315 pub fn persist_private_key(&mut self, from: Ids::Private, to: Ids::Private) -> Result<()> {
323 if !from.is_local() || to.is_local() {
324 return Err(CryptoError::InvalidKeyStoreOperation);
325 }
326 let key = self.get_private_key(from)?.to_owned();
327 self.drop_private_key(from)?;
328 #[allow(deprecated)]
329 self.set_private_key(to, key)?;
330 Ok(())
331 }
332
333 pub fn persist_signing_key(&mut self, from: Ids::Signing, to: Ids::Signing) -> Result<()> {
340 if !from.is_local() || to.is_local() {
341 return Err(CryptoError::InvalidKeyStoreOperation);
342 }
343 let key = self.get_signing_key(from)?.to_owned();
344 self.drop_signing_key(from)?;
345 #[allow(deprecated)]
346 self.set_signing_key(to, key)?;
347 Ok(())
348 }
349
350 pub fn wrap_signing_key(
359 &self,
360 wrapping_key: Ids::Symmetric,
361 key_to_wrap: Ids::Signing,
362 ) -> Result<EncString> {
363 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
364 let signing_key = self.get_signing_key(key_to_wrap)?.to_owned();
365 signing_key.to_cose().encrypt_with_key(wrapping_key)
366 }
367
368 pub fn wrap_private_key(
376 &self,
377 wrapping_key: Ids::Symmetric,
378 key_to_wrap: Ids::Private,
379 ) -> Result<EncString> {
380 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
381 let private_key = self.get_private_key(key_to_wrap)?.to_owned();
382 private_key.to_der()?.encrypt_with_key(wrapping_key)
383 }
384
385 #[bitwarden_logging::instrument(err, fields(wrapping_key = ?wrapping_key))]
394 pub fn unwrap_private_key(
395 &mut self,
396 wrapping_key: Ids::Symmetric,
397 wrapped_key: &EncString,
398 ) -> Result<Ids::Private> {
399 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
400 let private_key_bytes: Vec<u8> = wrapped_key.decrypt_with_key(wrapping_key)?;
401 let private_key = PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(private_key_bytes))?;
402 Ok(self.add_local_private_key(private_key))
403 }
404
405 pub fn unwrap_signing_key(
414 &mut self,
415 wrapping_key: Ids::Symmetric,
416 wrapped_key: &EncString,
417 ) -> Result<Ids::Signing> {
418 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
419 let signing_key_bytes: Vec<u8> = wrapped_key.decrypt_with_key(wrapping_key)?;
420 let signing_key = SigningKey::from_cose(&CoseKeyBytes::from(signing_key_bytes))?;
421 Ok(self.add_local_signing_key(signing_key))
422 }
423
424 pub fn get_verifying_key(&self, signing_key_id: Ids::Signing) -> Result<VerifyingKey> {
432 let signing_key = self.get_signing_key(signing_key_id)?;
433 Ok(signing_key.to_verifying_key())
434 }
435
436 pub fn get_public_key(&self, private_key_id: Ids::Private) -> Result<PublicKey> {
443 let private_key = self.get_private_key(private_key_id)?;
444 Ok(private_key.to_public_key())
445 }
446
447 pub fn wrap_symmetric_key(
456 &self,
457 wrapping_key: Ids::Symmetric,
458 key_to_wrap: Ids::Symmetric,
459 ) -> Result<EncString> {
460 use SymmetricCryptoKey::*;
461
462 let wrapping_key_instance = self.get_symmetric_key(wrapping_key)?;
463 let key_to_wrap_instance = self.get_symmetric_key(key_to_wrap)?;
464 match (wrapping_key_instance, key_to_wrap_instance) {
469 (
470 Aes256CbcHmacKey(_),
471 Aes256CbcHmacKey(_)
472 | Aes256CbcKey(_)
473 | XChaCha20Poly1305Key(_)
474 | Aes256GcmKey(_)
475 | XAes256GcmKey(_),
476 ) => self.encrypt_data_with_symmetric_key(
477 wrapping_key,
478 key_to_wrap_instance
479 .to_encoded()
480 .as_ref()
481 .to_vec()
482 .as_slice(),
483 ContentFormat::BitwardenLegacyKey,
484 ),
485 (XChaCha20Poly1305Key(_), _) | (XAes256GcmKey(_), _) => {
486 let encoded = key_to_wrap_instance.to_encoded_raw();
487 let content_format = encoded.content_format();
488 self.encrypt_data_with_symmetric_key(
489 wrapping_key,
490 Into::<Vec<u8>>::into(encoded).as_slice(),
491 content_format,
492 )
493 }
494 _ => Err(CryptoError::OperationNotSupported(
495 UnsupportedOperationError::EncryptionNotImplementedForKey,
496 )),
497 }
498 }
499
500 pub fn has_symmetric_key(&self, key_id: Ids::Symmetric) -> bool {
502 self.get_symmetric_key(key_id).is_ok()
503 }
504
505 pub fn has_private_key(&self, key_id: Ids::Private) -> bool {
507 self.get_private_key(key_id).is_ok()
508 }
509
510 pub fn has_signing_key(&self, key_id: Ids::Signing) -> bool {
512 self.get_signing_key(key_id).is_ok()
513 }
514
515 pub fn generate_symmetric_key(&mut self) -> Ids::Symmetric {
517 self.add_local_symmetric_key(SymmetricCryptoKey::make_aes256_cbc_hmac_key())
518 }
519
520 pub fn make_symmetric_key(&mut self, algorithm: SymmetricKeyAlgorithm) -> Ids::Symmetric {
523 self.add_local_symmetric_key(SymmetricCryptoKey::make(algorithm))
524 }
525
526 pub fn make_private_key(&mut self, algorithm: PublicKeyEncryptionAlgorithm) -> Ids::Private {
529 self.add_local_private_key(PrivateKey::make(algorithm))
530 }
531
532 pub fn make_signing_key(&mut self, algorithm: SignatureAlgorithm) -> Ids::Signing {
535 self.add_local_signing_key(SigningKey::make(algorithm))
536 }
537
538 pub fn derive_shareable_key(
543 &mut self,
544 secret: Zeroizing<[u8; 16]>,
545 name: &str,
546 info: Option<&str>,
547 ) -> Result<Ids::Symmetric> {
548 let key_id = Ids::Symmetric::new_local(LocalId::new());
549 #[allow(deprecated)]
550 self.set_symmetric_key(
551 key_id,
552 SymmetricCryptoKey::Aes256CbcHmacKey(derive_shareable_key(secret, name, info)),
553 )?;
554 Ok(key_id)
555 }
556
557 #[deprecated(note = "This function should ideally never be used outside this crate")]
567 pub fn dangerous_get_symmetric_key(
568 &self,
569 key_id: Ids::Symmetric,
570 ) -> Result<&SymmetricCryptoKey> {
571 self.get_symmetric_key(key_id)
572 }
573
574 pub fn get_symmetric_key_id(&self, key_slot_id: Ids::Symmetric) -> Option<KeyId> {
576 let Ok(key) = self.get_symmetric_key(key_slot_id) else {
577 return None;
578 };
579 key.key_id()
580 }
581
582 #[deprecated(note = "This function should ideally never be used outside this crate")]
593 pub fn dangerous_get_signing_key(&self, key_id: Ids::Signing) -> Result<&SigningKey> {
594 self.get_signing_key(key_id)
595 }
596
597 #[deprecated(note = "This function should ideally never be used outside this crate")]
606 pub fn dangerous_get_private_key(&self, key_id: Ids::Private) -> Result<&PrivateKey> {
607 self.get_private_key(key_id)
608 }
609
610 pub fn make_signed_public_key(
614 &self,
615 private_key_id: Ids::Private,
616 signing_key_id: Ids::Signing,
617 ) -> Result<SignedPublicKey> {
618 let public_key = self.get_private_key(private_key_id)?.to_public_key();
619 let signing_key = self.get_signing_key(signing_key_id)?;
620 let signed_public_key =
621 SignedPublicKeyMessage::from_public_key(&public_key)?.sign(signing_key)?;
622 Ok(signed_public_key)
623 }
624
625 pub(crate) fn get_symmetric_key(&self, key_id: Ids::Symmetric) -> Result<&SymmetricCryptoKey> {
626 if key_id.is_local() {
627 self.local_symmetric_keys.get(key_id)
628 } else {
629 self.global_keys.get().symmetric_keys.get(key_id)
630 }
631 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
632 }
633
634 pub(super) fn get_private_key(&self, key_id: Ids::Private) -> Result<&PrivateKey> {
635 if key_id.is_local() {
636 self.local_private_keys.get(key_id)
637 } else {
638 self.global_keys.get().private_keys.get(key_id)
639 }
640 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
641 }
642
643 pub(super) fn get_signing_key(&self, key_id: Ids::Signing) -> Result<&SigningKey> {
644 if key_id.is_local() {
645 self.local_signing_keys.get(key_id)
646 } else {
647 self.global_keys.get().signing_keys.get(key_id)
648 }
649 .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
650 }
651
652 #[deprecated(note = "This function should ideally never be used outside this crate")]
658 pub fn set_symmetric_key(
659 &mut self,
660 key_id: Ids::Symmetric,
661 key: SymmetricCryptoKey,
662 ) -> Result<()> {
663 self.set_symmetric_key_internal(key_id, key)
664 }
665
666 pub(crate) fn set_symmetric_key_internal(
667 &mut self,
668 key_id: Ids::Symmetric,
669 key: SymmetricCryptoKey,
670 ) -> Result<()> {
671 if key_id.is_local() {
672 self.local_symmetric_keys.upsert(key_id, key);
673 } else {
674 self.global_keys
675 .get_mut()?
676 .symmetric_keys
677 .upsert(key_id, key);
678 }
679 Ok(())
680 }
681
682 pub fn add_local_symmetric_key(&mut self, key: SymmetricCryptoKey) -> Ids::Symmetric {
684 let key_id = Ids::Symmetric::new_local(LocalId::new());
685 self.local_symmetric_keys.upsert(key_id, key);
686 key_id
687 }
688
689 pub fn get_symmetric_key_algorithm(
691 &self,
692 key_id: Ids::Symmetric,
693 ) -> Result<SymmetricKeyAlgorithm> {
694 let key = self.get_symmetric_key(key_id)?;
695 match key {
696 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
698 UnsupportedOperationError::EncryptionNotImplementedForKey,
699 )),
700 SymmetricCryptoKey::Aes256CbcHmacKey(_) => Ok(SymmetricKeyAlgorithm::Aes256CbcHmac),
701 SymmetricCryptoKey::XChaCha20Poly1305Key(_) => {
702 Ok(SymmetricKeyAlgorithm::XChaCha20Poly1305)
703 }
704 SymmetricCryptoKey::Aes256GcmKey(_) => Ok(SymmetricKeyAlgorithm::Aes256Gcm),
705 SymmetricCryptoKey::XAes256GcmKey(_) => Ok(SymmetricKeyAlgorithm::XAes256Gcm),
706 }
707 }
708
709 #[bitwarden_logging::instrument(err, fields(key_id = ?key_id))]
711 pub fn is_v1_symmetric_key(&self, key_id: Ids::Symmetric) -> Result<bool> {
712 let algorithm = self.get_symmetric_key_algorithm(key_id)?;
713 Ok(algorithm == SymmetricKeyAlgorithm::Aes256CbcHmac)
714 }
715
716 #[deprecated(note = "This function should ideally never be used outside this crate")]
722 pub fn set_private_key(&mut self, key_id: Ids::Private, key: PrivateKey) -> Result<()> {
723 if key_id.is_local() {
724 self.local_private_keys.upsert(key_id, key);
725 } else {
726 self.global_keys.get_mut()?.private_keys.upsert(key_id, key);
727 }
728 Ok(())
729 }
730
731 pub fn add_local_private_key(&mut self, key: PrivateKey) -> Ids::Private {
733 let key_id = Ids::Private::new_local(LocalId::new());
734 self.local_private_keys.upsert(key_id, key);
735 key_id
736 }
737
738 #[deprecated(note = "This function should ideally never be used outside this crate")]
744 pub fn set_signing_key(&mut self, key_id: Ids::Signing, key: SigningKey) -> Result<()> {
745 if key_id.is_local() {
746 self.local_signing_keys.upsert(key_id, key);
747 } else {
748 self.global_keys.get_mut()?.signing_keys.upsert(key_id, key);
749 }
750 Ok(())
751 }
752
753 pub fn add_local_signing_key(&mut self, key: SigningKey) -> Ids::Signing {
755 let key_id = Ids::Signing::new_local(LocalId::new());
756 self.local_signing_keys.upsert(key_id, key);
757 key_id
758 }
759
760 #[bitwarden_logging::instrument(err, fields(key = ?key))]
761 pub(crate) fn decrypt_data_with_symmetric_key(
762 &self,
763 key: Ids::Symmetric,
764 data: &EncString,
765 ) -> Result<Vec<u8>> {
766 let key = self.get_symmetric_key(key)?;
767
768 match (data, key) {
769 (EncString::Aes256Cbc_B64 { .. }, SymmetricCryptoKey::Aes256CbcKey(_)) => {
770 Err(CryptoError::OperationNotSupported(
771 UnsupportedOperationError::DecryptionNotImplementedForKey,
772 ))
773 }
774 (
775 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
776 SymmetricCryptoKey::Aes256CbcHmacKey(key),
777 ) => Aes256CbcHmacSha256::decrypt(iv, data, mac, &key.to_composite_key())
778 .map_err(|_| CryptoError::Decrypt),
779 (
780 EncString::Cose_Encrypt0_B64 { data },
781 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
782 ) => {
783 let (data, _) = crate::cose::symmetric::decrypt_xchacha20_poly1305(
784 &CoseEncrypt0Bytes::from(data.clone()),
785 key,
786 )?;
787 Ok(data)
788 }
789 (EncString::Cose_Encrypt0_B64 { data }, SymmetricCryptoKey::XAes256GcmKey(key)) => {
790 let (data, _) = crate::cose::symmetric::decrypt_xaes256_gcm(
791 &CoseEncrypt0Bytes::from(data.clone()),
792 key,
793 )?;
794 Ok(data)
795 }
796 _ => {
797 tracing::warn!("Unsupported decryption operation for the given key and data");
798 Err(CryptoError::InvalidKey)
799 }
800 }
801 }
802
803 pub(crate) fn encrypt_data_with_symmetric_key(
804 &self,
805 key: Ids::Symmetric,
806 data: &[u8],
807 content_format: ContentFormat,
808 ) -> Result<EncString> {
809 let key = self.get_symmetric_key(key)?;
810 match key {
811 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
812 UnsupportedOperationError::EncryptionNotImplementedForKey,
813 )),
814 SymmetricCryptoKey::Aes256CbcHmacKey(key) => EncString::encrypt_aes256_hmac(data, key),
815 SymmetricCryptoKey::XChaCha20Poly1305Key(key) => {
816 if !key.supported_operations.contains(&KeyOperation::Encrypt) {
817 return Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt));
818 }
819 EncString::encrypt_xchacha20_poly1305(data, key, content_format)
820 }
821 SymmetricCryptoKey::Aes256GcmKey(_) => Err(CryptoError::OperationNotSupported(
822 UnsupportedOperationError::EncryptionNotImplementedForKey,
823 )),
824 SymmetricCryptoKey::XAes256GcmKey(key) => {
825 if !key.supported_operations.contains(&KeyOperation::Encrypt) {
826 return Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt));
827 }
828 EncString::encrypt_xaes256_gcm(data, key, content_format)
829 }
830 }
831 }
832
833 pub fn sign<Message: Serialize>(
837 &self,
838 key: Ids::Signing,
839 message: &Message,
840 namespace: &crate::SigningNamespace,
841 ) -> Result<SignedObject> {
842 self.get_signing_key(key)?.sign(message, namespace)
843 }
844
845 #[allow(unused)]
849 pub(crate) fn sign_detached<Message: Serialize>(
850 &self,
851 key: Ids::Signing,
852 message: &Message,
853 namespace: &crate::SigningNamespace,
854 ) -> Result<(Signature, signing::SerializedMessage)> {
855 self.get_signing_key(key)?.sign_detached(message, namespace)
856 }
857
858 pub fn dangerous_get_v2_rotated_account_keys(
860 &self,
861 current_user_private_key_id: Ids::Private,
862 current_user_signing_key_id: Ids::Signing,
863 ) -> Result<RotatedUserKeys> {
864 #[expect(deprecated)]
865 crate::dangerous_get_v2_rotated_account_keys(
866 current_user_private_key_id,
867 current_user_signing_key_id,
868 self,
869 )
870 }
871
872 #[cfg(any(test, feature = "test-utils"))]
875 pub fn assert_symmetric_keys_equal(&self, key_id_1: Ids::Symmetric, key_id_2: Ids::Symmetric) {
876 let key_1 = self
877 .get_symmetric_key(key_id_1)
878 .expect("Key 1 should exist in context");
879 let key_2 = self
880 .get_symmetric_key(key_id_2)
881 .expect("Key 2 should exist in context");
882 if key_1 != key_2 {
883 panic!(
884 "Symmetric keys with ids {:?} and {:?} are not equal",
885 key_id_1, key_id_2,
886 );
887 }
888 }
889
890 #[cfg(any(test, feature = "test-utils"))]
893 pub fn assert_symmetric_keys_not_equal(
894 &self,
895 key_id_1: Ids::Symmetric,
896 key_id_2: Ids::Symmetric,
897 ) {
898 let key_1 = self
899 .get_symmetric_key(key_id_1)
900 .expect("Key 1 should exist in context");
901 let key_2 = self
902 .get_symmetric_key(key_id_2)
903 .expect("Key 2 should exist in context");
904 if key_1 == key_2 {
905 panic!(
906 "Symmetric keys with ids {:?} and {:?} are equal",
907 key_id_1, key_id_2,
908 );
909 }
910 }
911}
912
913#[cfg(test)]
914#[allow(deprecated)]
915mod tests {
916 use serde::{Deserialize, Serialize};
917
918 use crate::{
919 CompositeEncryptable, CoseKeyBytes, CoseSerializable, CryptoError, Decryptable, EncString,
920 KeyDecryptable, Pkcs8PrivateKeyBytes, PrivateKey, PublicKey, PublicKeyEncryptionAlgorithm,
921 SignatureAlgorithm, SigningKey, SigningNamespace, SymmetricCryptoKey,
922 SymmetricKeyAlgorithm,
923 store::{
924 KeyStore,
925 tests::{Data, DataView},
926 },
927 traits::tests::{TestIds, TestSigningKey, TestSymmKey},
928 };
929
930 #[test]
931 fn test_set_signing_key() {
932 let store: KeyStore<TestIds> = KeyStore::default();
933
934 let key_a0_id = TestSigningKey::A(0);
936 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
937 store
938 .context_mut()
939 .set_signing_key(key_a0_id, key_a0)
940 .unwrap();
941 }
942
943 #[test]
944 fn test_set_keys_for_encryption() {
945 let store: KeyStore<TestIds> = KeyStore::default();
946
947 let key_a0_id = TestSymmKey::A(0);
949 let mut ctx = store.context_mut();
950 let local_key_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
951 ctx.persist_symmetric_key(local_key_id, TestSymmKey::A(0))
952 .unwrap();
953
954 assert!(ctx.has_symmetric_key(key_a0_id));
955
956 let data = DataView("Hello, World!".to_string(), key_a0_id);
958 let _encrypted: Data = data.encrypt_composite(&mut ctx, key_a0_id).unwrap();
959 }
960
961 #[test]
962 fn test_key_encryption() {
963 let store: KeyStore<TestIds> = KeyStore::default();
964
965 let mut ctx = store.context();
966
967 let key_1_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
969
970 assert!(ctx.has_symmetric_key(key_1_id));
971
972 let key_2_id = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
974
975 assert!(ctx.has_symmetric_key(key_2_id));
976
977 let key_2_enc = ctx.wrap_symmetric_key(key_1_id, key_2_id).unwrap();
979
980 let new_key_id = ctx.unwrap_symmetric_key(key_1_id, &key_2_enc).unwrap();
982
983 let data = DataView("Hello, World!".to_string(), key_2_id);
987 let encrypted = data.encrypt_composite(&mut ctx, key_2_id).unwrap();
988
989 let decrypted1 = encrypted.decrypt(&mut ctx, key_2_id).unwrap();
990 let decrypted2 = encrypted.decrypt(&mut ctx, new_key_id).unwrap();
991
992 assert_eq!(decrypted1.0, decrypted2.0);
994 }
995
996 #[test]
997 fn test_wrap_unwrap() {
998 let store: KeyStore<TestIds> = KeyStore::default();
999 let mut ctx = store.context_mut();
1000
1001 let cbc = TestSymmKey::A(1);
1002 let xchacha = TestSymmKey::A(2);
1003 let aes_gcm = TestSymmKey::A(3);
1004 let xaes = TestSymmKey::A(4);
1005 for (id, key) in [
1006 (
1007 cbc,
1008 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac),
1009 ),
1010 (
1011 xchacha,
1012 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XChaCha20Poly1305),
1013 ),
1014 (
1015 aes_gcm,
1016 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256Gcm),
1017 ),
1018 (
1019 xaes,
1020 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1021 ),
1022 ] {
1023 ctx.set_symmetric_key(id, key).unwrap();
1024 }
1025
1026 for (wrapping_key, wrapped_key) in [
1027 (cbc, cbc),
1028 (cbc, xchacha),
1029 (xchacha, cbc),
1030 (xchacha, xchacha),
1031 (xaes, cbc),
1032 (xaes, xchacha),
1033 (xaes, aes_gcm),
1034 (xaes, xaes),
1035 (cbc, xaes),
1036 (xchacha, xaes),
1037 ] {
1038 let encrypted = ctx.wrap_symmetric_key(wrapping_key, wrapped_key).unwrap();
1039 let unwrapped = ctx.unwrap_symmetric_key(wrapping_key, &encrypted).unwrap();
1040 ctx.assert_symmetric_keys_equal(unwrapped, wrapped_key);
1041 }
1042 }
1043
1044 #[test]
1045 fn test_signing() {
1046 let store: KeyStore<TestIds> = KeyStore::default();
1047
1048 let key_a0_id = TestSigningKey::A(0);
1050 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
1051 let verifying_key = key_a0.to_verifying_key();
1052 store
1053 .context_mut()
1054 .set_signing_key(key_a0_id, key_a0)
1055 .unwrap();
1056
1057 assert!(store.context().has_signing_key(key_a0_id));
1058
1059 #[derive(Serialize, Deserialize)]
1061 struct TestData {
1062 data: String,
1063 }
1064 let signed_object = store
1065 .context()
1066 .sign(
1067 key_a0_id,
1068 &TestData {
1069 data: "Hello".to_string(),
1070 },
1071 &SigningNamespace::ExampleNamespace,
1072 )
1073 .unwrap();
1074 let payload: Result<TestData, CryptoError> =
1075 signed_object.verify_and_unwrap(&verifying_key, &SigningNamespace::ExampleNamespace);
1076 assert!(payload.is_ok());
1077
1078 let (signature, serialized_message) = store
1079 .context()
1080 .sign_detached(
1081 key_a0_id,
1082 &TestData {
1083 data: "Hello".to_string(),
1084 },
1085 &SigningNamespace::ExampleNamespace,
1086 )
1087 .unwrap();
1088 assert!(signature.verify(
1089 serialized_message.as_bytes(),
1090 &verifying_key,
1091 &SigningNamespace::ExampleNamespace
1092 ))
1093 }
1094
1095 #[test]
1096 fn test_account_key_rotation() {
1097 let store: KeyStore<TestIds> = KeyStore::default();
1098 let mut ctx = store.context_mut();
1099
1100 let current_user_signing_key_id = ctx.make_signing_key(SignatureAlgorithm::Ed25519);
1102 let current_user_private_key_id =
1103 ctx.make_private_key(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
1104
1105 let rotated_keys = ctx
1107 .dangerous_get_v2_rotated_account_keys(
1108 current_user_private_key_id,
1109 current_user_signing_key_id,
1110 )
1111 .unwrap();
1112
1113 assert_eq!(
1115 PublicKey::from_der(&rotated_keys.public_key)
1116 .unwrap()
1117 .to_der()
1118 .unwrap(),
1119 ctx.get_private_key(current_user_private_key_id)
1120 .unwrap()
1121 .to_public_key()
1122 .to_der()
1123 .unwrap()
1124 );
1125 let decrypted_private_key: Vec<u8> = rotated_keys
1126 .private_key
1127 .decrypt_with_key(&rotated_keys.user_key)
1128 .unwrap();
1129 let private_key =
1130 PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key)).unwrap();
1131 assert_eq!(
1132 private_key.to_der().unwrap(),
1133 ctx.get_private_key(current_user_private_key_id)
1134 .unwrap()
1135 .to_der()
1136 .unwrap()
1137 );
1138
1139 let decrypted_signing_key: Vec<u8> = rotated_keys
1141 .signing_key
1142 .decrypt_with_key(&rotated_keys.user_key)
1143 .unwrap();
1144 let signing_key =
1145 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
1146 assert_eq!(
1147 signing_key.to_cose(),
1148 ctx.get_signing_key(current_user_signing_key_id)
1149 .unwrap()
1150 .to_cose(),
1151 );
1152
1153 let signed_public_key = rotated_keys.signed_public_key;
1155 let unwrapped_key = signed_public_key
1156 .verify_and_unwrap(
1157 &ctx.get_signing_key(current_user_signing_key_id)
1158 .unwrap()
1159 .to_verifying_key(),
1160 )
1161 .unwrap();
1162 assert_eq!(
1163 unwrapped_key.to_der().unwrap(),
1164 ctx.get_private_key(current_user_private_key_id)
1165 .unwrap()
1166 .to_public_key()
1167 .to_der()
1168 .unwrap()
1169 );
1170 }
1171
1172 #[test]
1173 fn test_encrypt_fails_when_operation_not_allowed() {
1174 use coset::iana::KeyOperation;
1175 let store = KeyStore::<TestIds>::default();
1176 let mut ctx = store.context_mut();
1177 let key_id = TestSymmKey::A(0);
1178 let key = SymmetricCryptoKey::XChaCha20Poly1305Key(crate::XChaCha20Poly1305Key {
1180 key_id: [0u8; 16].into(),
1181 enc_key: Box::pin([0u8; 32].into()),
1182 supported_operations: vec![KeyOperation::Decrypt],
1183 });
1184 ctx.set_symmetric_key(key_id, key).unwrap();
1185 let data = DataView("should fail".to_string(), key_id);
1186 let result = data.encrypt_composite(&mut ctx, key_id);
1187 assert!(
1188 matches!(
1189 result,
1190 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1191 ),
1192 "Expected encrypt to fail with KeyOperationNotSupported",
1193 );
1194 }
1195
1196 #[test]
1197 fn test_xaes_data_roundtrip_and_encrypt_operation() {
1198 use coset::iana::KeyOperation;
1199
1200 let store = KeyStore::<TestIds>::default();
1201 let mut ctx = store.context_mut();
1202 let key_id = TestSymmKey::A(0);
1203 ctx.set_symmetric_key(
1204 key_id,
1205 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1206 )
1207 .unwrap();
1208
1209 let plaintext = b"data encrypted directly by the key store";
1210 let encrypted = ctx
1211 .encrypt_data_with_symmetric_key(key_id, plaintext, crate::ContentFormat::OctetStream)
1212 .unwrap();
1213 assert_eq!(
1214 ctx.decrypt_data_with_symmetric_key(key_id, &encrypted)
1215 .unwrap(),
1216 plaintext
1217 );
1218
1219 let no_encrypt = TestSymmKey::A(1);
1220 ctx.set_symmetric_key(
1221 no_encrypt,
1222 SymmetricCryptoKey::XAes256GcmKey(crate::XAes256GcmKey {
1223 key_id: [1; 16].into(),
1224 enc_key: Box::pin([1; 32].into()),
1225 supported_operations: vec![KeyOperation::Decrypt],
1226 }),
1227 )
1228 .unwrap();
1229 assert!(matches!(
1230 ctx.encrypt_data_with_symmetric_key(
1231 no_encrypt,
1232 plaintext,
1233 crate::ContentFormat::OctetStream,
1234 ),
1235 Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
1236 ));
1237 }
1238
1239 #[test]
1240 fn test_xaes_key_store_rejects_unsupported_inputs() {
1241 let store = KeyStore::<TestIds>::default();
1242 let mut ctx = store.context_mut();
1243 let xaes = TestSymmKey::A(0);
1244 ctx.set_symmetric_key(
1245 xaes,
1246 SymmetricCryptoKey::make(SymmetricKeyAlgorithm::XAes256Gcm),
1247 )
1248 .unwrap();
1249
1250 let non_key = ctx
1251 .encrypt_data_with_symmetric_key(xaes, b"not a key", crate::ContentFormat::OctetStream)
1252 .unwrap();
1253 assert!(matches!(
1254 ctx.unwrap_symmetric_key(xaes, &non_key),
1255 Err(CryptoError::InvalidKey)
1256 ));
1257
1258 let legacy_data =
1259 EncString::encrypt_aes256_hmac(b"data", &crate::derive_symmetric_key("test key"))
1260 .unwrap();
1261 assert!(matches!(
1262 ctx.decrypt_data_with_symmetric_key(xaes, &legacy_data),
1263 Err(CryptoError::InvalidKey)
1264 ));
1265 }
1266
1267 #[test]
1268 fn test_move_key() {
1269 let store: KeyStore<TestIds> = KeyStore::default();
1270 let mut ctx = store.context_mut();
1271
1272 let key = ctx.make_symmetric_key(SymmetricKeyAlgorithm::Aes256CbcHmac);
1274
1275 assert!(ctx.has_symmetric_key(key));
1276
1277 let new_key_id = TestSymmKey::A(1);
1279 ctx.persist_symmetric_key(key, new_key_id).unwrap();
1280
1281 assert!(!ctx.has_symmetric_key(key));
1283 assert!(ctx.has_symmetric_key(new_key_id));
1284 }
1285
1286 #[test]
1287 fn test_encrypt_decrypt_data_fails_when_key_is_type_0() {
1288 let store = KeyStore::<TestIds>::default();
1289 let mut ctx = store.context_mut();
1290
1291 let key_id = TestSymmKey::A(0);
1292 let key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1293 enc_key: Box::pin([0u8; 32].into()),
1294 });
1295 ctx.set_symmetric_key_internal(key_id, key).unwrap();
1296
1297 let data_to_encrypt: Vec<u8> = vec![1, 2, 3, 4, 5];
1298 let result = ctx.encrypt_data_with_symmetric_key(
1299 key_id,
1300 &data_to_encrypt,
1301 crate::ContentFormat::OctetStream,
1302 );
1303 assert!(
1304 matches!(
1305 result,
1306 Err(CryptoError::OperationNotSupported(
1307 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1308 ))
1309 ),
1310 "Expected encrypt to fail when using deprecated type 0 keys",
1311 );
1312
1313 let data_to_decrypt = EncString::Aes256Cbc_B64 {
1314 iv: [0; 16],
1315 data: data_to_encrypt,
1316 }; let result = ctx.decrypt_data_with_symmetric_key(key_id, &data_to_decrypt);
1318 assert!(
1319 matches!(
1320 result,
1321 Err(CryptoError::OperationNotSupported(
1322 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1323 ))
1324 ),
1325 "Expected decrypt to fail when using deprecated type 0 keys",
1326 );
1327 }
1328
1329 #[test]
1330 fn test_wrap_unwrap_key_fails_when_key_is_type_0() {
1331 let store = KeyStore::<TestIds>::default();
1332 let mut ctx = store.context_mut();
1333
1334 let wrapping_key_id = TestSymmKey::A(0);
1335 let wrapping_key = SymmetricCryptoKey::Aes256CbcKey(crate::Aes256CbcKey {
1336 enc_key: Box::pin([0u8; 32].into()),
1337 });
1338 ctx.set_symmetric_key_internal(wrapping_key_id, wrapping_key)
1339 .unwrap();
1340
1341 let key_to_wrap_id = TestSymmKey::A(1);
1342 let key_to_wrap = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
1343 ctx.set_symmetric_key_internal(key_to_wrap_id, key_to_wrap)
1344 .unwrap();
1345
1346 let result = ctx.wrap_symmetric_key(wrapping_key_id, key_to_wrap_id);
1347 assert!(
1348 matches!(
1349 result,
1350 Err(CryptoError::OperationNotSupported(
1351 crate::error::UnsupportedOperationError::EncryptionNotImplementedForKey
1352 ))
1353 ),
1354 "Expected encrypt to fail when using deprecated type 0 keys",
1355 );
1356
1357 let wrapped_key = &EncString::Aes256Cbc_B64 {
1358 iv: [0; 16],
1359 data: vec![0],
1360 }; let result = ctx.unwrap_symmetric_key(wrapping_key_id, wrapped_key);
1362 assert!(
1363 matches!(
1364 result,
1365 Err(CryptoError::OperationNotSupported(
1366 crate::error::UnsupportedOperationError::DecryptionNotImplementedForKey
1367 ))
1368 ),
1369 "Expected decrypt to fail when using deprecated type 0 keys",
1370 );
1371 }
1372}