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