1use std::{
2    cell::Cell,
3    sync::{RwLockReadGuard, RwLockWriteGuard},
4};
5
6use coset::iana::KeyOperation;
7use serde::Serialize;
8use zeroize::Zeroizing;
9
10use super::KeyStoreInner;
11use crate::{
12    AsymmetricCryptoKey, BitwardenLegacyKeyBytes, ContentFormat, CoseEncrypt0Bytes, CryptoError,
13    EncString, KeyId, KeyIds, LocalId, PublicKeyEncryptionAlgorithm, Result, RotatedUserKeys,
14    Signature, SignatureAlgorithm, SignedObject, SignedPublicKey, SignedPublicKeyMessage,
15    SigningKey, SymmetricCryptoKey, UnsignedSharedKey, derive_shareable_key,
16    error::UnsupportedOperationError, signing, store::backend::StoreBackend,
17};
18
19#[must_use]
78pub struct KeyStoreContext<'a, Ids: KeyIds> {
79    pub(super) global_keys: GlobalKeys<'a, Ids>,
80
81    pub(super) local_symmetric_keys: Box<dyn StoreBackend<Ids::Symmetric>>,
82    pub(super) local_asymmetric_keys: Box<dyn StoreBackend<Ids::Asymmetric>>,
83    pub(super) local_signing_keys: Box<dyn StoreBackend<Ids::Signing>>,
84
85    pub(super) _phantom: std::marker::PhantomData<(Cell<()>, RwLockReadGuard<'static, ()>)>,
87}
88
89pub(crate) enum GlobalKeys<'a, Ids: KeyIds> {
95    ReadOnly(RwLockReadGuard<'a, KeyStoreInner<Ids>>),
96    ReadWrite(RwLockWriteGuard<'a, KeyStoreInner<Ids>>),
97}
98
99impl<Ids: KeyIds> GlobalKeys<'_, Ids> {
100    pub fn get(&self) -> &KeyStoreInner<Ids> {
101        match self {
102            GlobalKeys::ReadOnly(keys) => keys,
103            GlobalKeys::ReadWrite(keys) => keys,
104        }
105    }
106
107    pub fn get_mut(&mut self) -> Result<&mut KeyStoreInner<Ids>> {
108        match self {
109            GlobalKeys::ReadOnly(_) => Err(CryptoError::ReadOnlyKeyStore),
110            GlobalKeys::ReadWrite(keys) => Ok(keys),
111        }
112    }
113}
114
115impl<Ids: KeyIds> KeyStoreContext<'_, Ids> {
116    pub fn clear_local(&mut self) {
120        self.local_symmetric_keys.clear();
121        self.local_asymmetric_keys.clear();
122        self.local_signing_keys.clear();
123    }
124
125    pub fn retain_symmetric_keys(&mut self, f: fn(Ids::Symmetric) -> bool) {
128        if let Ok(keys) = self.global_keys.get_mut() {
129            keys.symmetric_keys.retain(f);
130        }
131        self.local_symmetric_keys.retain(f);
132    }
133
134    pub fn retain_asymmetric_keys(&mut self, f: fn(Ids::Asymmetric) -> bool) {
137        if let Ok(keys) = self.global_keys.get_mut() {
138            keys.asymmetric_keys.retain(f);
139        }
140        self.local_asymmetric_keys.retain(f);
141    }
142
143    pub fn unwrap_symmetric_key(
156        &mut self,
157        wrapping_key: Ids::Symmetric,
158        wrapped_key: &EncString,
159    ) -> Result<Ids::Symmetric> {
160        let wrapping_key = self.get_symmetric_key(wrapping_key)?;
161
162        let key = match (wrapped_key, wrapping_key) {
163            (EncString::Aes256Cbc_B64 { iv, data }, SymmetricCryptoKey::Aes256CbcKey(key)) => {
164                SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(
165                    crate::aes::decrypt_aes256(iv, data.clone(), &key.enc_key)?,
166                ))?
167            }
168            (
169                EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
170                SymmetricCryptoKey::Aes256CbcHmacKey(key),
171            ) => SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(
172                crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key)?,
173            ))?,
174            (
175                EncString::Cose_Encrypt0_B64 { data },
176                SymmetricCryptoKey::XChaCha20Poly1305Key(key),
177            ) => {
178                let (content_bytes, content_format) = crate::cose::decrypt_xchacha20_poly1305(
179                    &CoseEncrypt0Bytes::from(data.clone()),
180                    key,
181                )?;
182                match content_format {
183                    ContentFormat::BitwardenLegacyKey => {
184                        SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(content_bytes))?
185                    }
186                    ContentFormat::CoseKey => SymmetricCryptoKey::try_from_cose(&content_bytes)?,
187                    _ => return Err(CryptoError::InvalidKey),
188                }
189            }
190            _ => return Err(CryptoError::InvalidKey),
191        };
192
193        let new_key_id = Ids::Symmetric::new_local(LocalId::new());
194
195        #[allow(deprecated)]
196        self.set_symmetric_key(new_key_id, key)?;
197
198        Ok(new_key_id)
200    }
201
202    pub fn wrap_symmetric_key(
211        &self,
212        wrapping_key: Ids::Symmetric,
213        key_to_wrap: Ids::Symmetric,
214    ) -> Result<EncString> {
215        use SymmetricCryptoKey::*;
216
217        let wrapping_key_instance = self.get_symmetric_key(wrapping_key)?;
218        let key_to_wrap_instance = self.get_symmetric_key(key_to_wrap)?;
219        match (wrapping_key_instance, key_to_wrap_instance) {
225            (
226                Aes256CbcHmacKey(_),
227                Aes256CbcHmacKey(_) | Aes256CbcKey(_) | XChaCha20Poly1305Key(_),
228            ) => self.encrypt_data_with_symmetric_key(
229                wrapping_key,
230                key_to_wrap_instance
231                    .to_encoded()
232                    .as_ref()
233                    .to_vec()
234                    .as_slice(),
235                ContentFormat::BitwardenLegacyKey,
236            ),
237            (XChaCha20Poly1305Key(_), _) => {
238                let encoded = key_to_wrap_instance.to_encoded_raw();
239                let content_format = encoded.content_format();
240                self.encrypt_data_with_symmetric_key(
241                    wrapping_key,
242                    Into::<Vec<u8>>::into(encoded).as_slice(),
243                    content_format,
244                )
245            }
246            _ => Err(CryptoError::OperationNotSupported(
247                UnsupportedOperationError::EncryptionNotImplementedForKey,
248            )),
249        }
250    }
251
252    pub fn decapsulate_key_unsigned(
262        &mut self,
263        decapsulation_key: Ids::Asymmetric,
264        new_key_id: Ids::Symmetric,
265        encapsulated_shared_key: &UnsignedSharedKey,
266    ) -> Result<Ids::Symmetric> {
267        let decapsulation_key = self.get_asymmetric_key(decapsulation_key)?;
268        let decapsulated_key =
269            encapsulated_shared_key.decapsulate_key_unsigned(decapsulation_key)?;
270
271        #[allow(deprecated)]
272        self.set_symmetric_key(new_key_id, decapsulated_key)?;
273
274        Ok(new_key_id)
276    }
277
278    pub fn encapsulate_key_unsigned(
287        &self,
288        encapsulation_key: Ids::Asymmetric,
289        shared_key: Ids::Symmetric,
290    ) -> Result<UnsignedSharedKey> {
291        UnsignedSharedKey::encapsulate_key_unsigned(
292            self.get_symmetric_key(shared_key)?,
293            &self.get_asymmetric_key(encapsulation_key)?.to_public_key(),
294        )
295    }
296
297    pub fn has_symmetric_key(&self, key_id: Ids::Symmetric) -> bool {
299        self.get_symmetric_key(key_id).is_ok()
300    }
301
302    pub fn has_asymmetric_key(&self, key_id: Ids::Asymmetric) -> bool {
304        self.get_asymmetric_key(key_id).is_ok()
305    }
306
307    pub fn has_signing_key(&self, key_id: Ids::Signing) -> bool {
309        self.get_signing_key(key_id).is_ok()
310    }
311
312    pub fn generate_symmetric_key(&mut self) -> Ids::Symmetric {
314        self.add_local_symmetric_key(SymmetricCryptoKey::make_aes256_cbc_hmac_key())
315    }
316
317    #[cfg(test)]
319    pub(crate) fn make_cose_symmetric_key(
320        &mut self,
321        key_id: Ids::Symmetric,
322    ) -> Result<Ids::Symmetric> {
323        let key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
324        #[allow(deprecated)]
325        self.set_symmetric_key(key_id, key)?;
326        Ok(key_id)
327    }
328
329    pub fn make_asymmetric_key(&mut self) -> Result<Ids::Asymmetric> {
332        let key = AsymmetricCryptoKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
333        self.add_local_asymmetric_key(key)
334    }
335
336    pub fn make_signing_key(&mut self) -> Result<Ids::Signing> {
339        self.add_local_signing_key(SigningKey::make(SignatureAlgorithm::default_algorithm()))
340    }
341
342    pub fn derive_shareable_key(
347        &mut self,
348        secret: Zeroizing<[u8; 16]>,
349        name: &str,
350        info: Option<&str>,
351    ) -> Result<Ids::Symmetric> {
352        let key_id = Ids::Symmetric::new_local(LocalId::new());
353        #[allow(deprecated)]
354        self.set_symmetric_key(
355            key_id,
356            SymmetricCryptoKey::Aes256CbcHmacKey(derive_shareable_key(secret, name, info)),
357        )?;
358        Ok(key_id)
359    }
360
361    #[deprecated(note = "This function should ideally never be used outside this crate")]
362    #[allow(missing_docs)]
363    pub fn dangerous_get_symmetric_key(
364        &self,
365        key_id: Ids::Symmetric,
366    ) -> Result<&SymmetricCryptoKey> {
367        self.get_symmetric_key(key_id)
368    }
369
370    #[deprecated(note = "This function should ideally never be used outside this crate")]
371    #[allow(missing_docs)]
372    pub fn dangerous_get_asymmetric_key(
373        &self,
374        key_id: Ids::Asymmetric,
375    ) -> Result<&AsymmetricCryptoKey> {
376        self.get_asymmetric_key(key_id)
377    }
378
379    pub fn make_signed_public_key(
383        &self,
384        private_key_id: Ids::Asymmetric,
385        signing_key_id: Ids::Signing,
386    ) -> Result<SignedPublicKey> {
387        let public_key = self.get_asymmetric_key(private_key_id)?.to_public_key();
388        let signing_key = self.get_signing_key(signing_key_id)?;
389        let signed_public_key =
390            SignedPublicKeyMessage::from_public_key(&public_key)?.sign(signing_key)?;
391        Ok(signed_public_key)
392    }
393
394    pub(crate) fn get_symmetric_key(&self, key_id: Ids::Symmetric) -> Result<&SymmetricCryptoKey> {
395        if key_id.is_local() {
396            self.local_symmetric_keys.get(key_id)
397        } else {
398            self.global_keys.get().symmetric_keys.get(key_id)
399        }
400        .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
401    }
402
403    pub(super) fn get_asymmetric_key(
404        &self,
405        key_id: Ids::Asymmetric,
406    ) -> Result<&AsymmetricCryptoKey> {
407        if key_id.is_local() {
408            self.local_asymmetric_keys.get(key_id)
409        } else {
410            self.global_keys.get().asymmetric_keys.get(key_id)
411        }
412        .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
413    }
414
415    pub(super) fn get_signing_key(&self, key_id: Ids::Signing) -> Result<&SigningKey> {
416        if key_id.is_local() {
417            self.local_signing_keys.get(key_id)
418        } else {
419            self.global_keys.get().signing_keys.get(key_id)
420        }
421        .ok_or_else(|| crate::CryptoError::MissingKeyId(format!("{key_id:?}")))
422    }
423
424    #[deprecated(note = "This function should ideally never be used outside this crate")]
425    #[allow(missing_docs)]
426    pub fn set_symmetric_key(
427        &mut self,
428        key_id: Ids::Symmetric,
429        key: SymmetricCryptoKey,
430    ) -> Result<()> {
431        self.set_symmetric_key_internal(key_id, key)
432    }
433
434    pub(crate) fn set_symmetric_key_internal(
435        &mut self,
436        key_id: Ids::Symmetric,
437        key: SymmetricCryptoKey,
438    ) -> Result<()> {
439        if key_id.is_local() {
440            self.local_symmetric_keys.upsert(key_id, key);
441        } else {
442            self.global_keys
443                .get_mut()?
444                .symmetric_keys
445                .upsert(key_id, key);
446        }
447        Ok(())
448    }
449
450    pub fn add_local_symmetric_key(&mut self, key: SymmetricCryptoKey) -> Ids::Symmetric {
452        let key_id = Ids::Symmetric::new_local(LocalId::new());
453        self.local_symmetric_keys.upsert(key_id, key);
454        key_id
455    }
456
457    #[deprecated(note = "This function should ideally never be used outside this crate")]
458    #[allow(missing_docs)]
459    pub fn set_asymmetric_key(
460        &mut self,
461        key_id: Ids::Asymmetric,
462        key: AsymmetricCryptoKey,
463    ) -> Result<()> {
464        if key_id.is_local() {
465            self.local_asymmetric_keys.upsert(key_id, key);
466        } else {
467            self.global_keys
468                .get_mut()?
469                .asymmetric_keys
470                .upsert(key_id, key);
471        }
472        Ok(())
473    }
474
475    pub fn add_local_asymmetric_key(
477        &mut self,
478        key: AsymmetricCryptoKey,
479    ) -> Result<Ids::Asymmetric> {
480        let key_id = Ids::Asymmetric::new_local(LocalId::new());
481        self.local_asymmetric_keys.upsert(key_id, key);
482        Ok(key_id)
483    }
484
485    #[deprecated(note = "This function should ideally never be used outside this crate")]
487    pub fn set_signing_key(&mut self, key_id: Ids::Signing, key: SigningKey) -> Result<()> {
488        if key_id.is_local() {
489            self.local_signing_keys.upsert(key_id, key);
490        } else {
491            self.global_keys.get_mut()?.signing_keys.upsert(key_id, key);
492        }
493        Ok(())
494    }
495
496    pub fn add_local_signing_key(&mut self, key: SigningKey) -> Result<Ids::Signing> {
498        let key_id = Ids::Signing::new_local(LocalId::new());
499        self.local_signing_keys.upsert(key_id, key);
500        Ok(key_id)
501    }
502
503    pub(crate) fn decrypt_data_with_symmetric_key(
504        &self,
505        key: Ids::Symmetric,
506        data: &EncString,
507    ) -> Result<Vec<u8>> {
508        let key = self.get_symmetric_key(key)?;
509
510        match (data, key) {
511            (EncString::Aes256Cbc_B64 { iv, data }, SymmetricCryptoKey::Aes256CbcKey(key)) => {
512                crate::aes::decrypt_aes256(iv, data.clone(), &key.enc_key)
513            }
514            (
515                EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
516                SymmetricCryptoKey::Aes256CbcHmacKey(key),
517            ) => crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key),
518            (
519                EncString::Cose_Encrypt0_B64 { data },
520                SymmetricCryptoKey::XChaCha20Poly1305Key(key),
521            ) => {
522                let (data, _) = crate::cose::decrypt_xchacha20_poly1305(
523                    &CoseEncrypt0Bytes::from(data.clone()),
524                    key,
525                )?;
526                Ok(data)
527            }
528            _ => Err(CryptoError::InvalidKey),
529        }
530    }
531
532    pub(crate) fn encrypt_data_with_symmetric_key(
533        &self,
534        key: Ids::Symmetric,
535        data: &[u8],
536        content_format: ContentFormat,
537    ) -> Result<EncString> {
538        let key = self.get_symmetric_key(key)?;
539        match key {
540            SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
541                UnsupportedOperationError::EncryptionNotImplementedForKey,
542            )),
543            SymmetricCryptoKey::Aes256CbcHmacKey(key) => EncString::encrypt_aes256_hmac(data, key),
544            SymmetricCryptoKey::XChaCha20Poly1305Key(key) => {
545                if !key.supported_operations.contains(&KeyOperation::Encrypt) {
546                    return Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt));
547                }
548                EncString::encrypt_xchacha20_poly1305(data, key, content_format)
549            }
550        }
551    }
552
553    pub fn sign<Message: Serialize>(
557        &self,
558        key: Ids::Signing,
559        message: &Message,
560        namespace: &crate::SigningNamespace,
561    ) -> Result<SignedObject> {
562        self.get_signing_key(key)?.sign(message, namespace)
563    }
564
565    #[allow(unused)]
569    pub(crate) fn sign_detached<Message: Serialize>(
570        &self,
571        key: Ids::Signing,
572        message: &Message,
573        namespace: &crate::SigningNamespace,
574    ) -> Result<(Signature, signing::SerializedMessage)> {
575        self.get_signing_key(key)?.sign_detached(message, namespace)
576    }
577
578    pub fn dangerous_get_v2_rotated_account_keys(
580        &self,
581        current_user_private_key_id: Ids::Asymmetric,
582        current_user_signing_key_id: Ids::Signing,
583    ) -> Result<RotatedUserKeys> {
584        crate::dangerous_get_v2_rotated_account_keys(
585            current_user_private_key_id,
586            current_user_signing_key_id,
587            self,
588        )
589    }
590}
591
592#[cfg(test)]
593#[allow(deprecated)]
594mod tests {
595    use serde::{Deserialize, Serialize};
596
597    use crate::{
598        AsymmetricCryptoKey, AsymmetricPublicCryptoKey, CompositeEncryptable, CoseKeyBytes,
599        CoseSerializable, CryptoError, Decryptable, KeyDecryptable, LocalId, Pkcs8PrivateKeyBytes,
600        SignatureAlgorithm, SigningKey, SigningNamespace, SymmetricCryptoKey,
601        store::{
602            KeyStore,
603            tests::{Data, DataView},
604        },
605        traits::tests::{TestIds, TestSigningKey, TestSymmKey},
606    };
607
608    #[test]
609    fn test_set_signing_key() {
610        let store: KeyStore<TestIds> = KeyStore::default();
611
612        let key_a0_id = TestSigningKey::A(0);
614        let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
615        store
616            .context_mut()
617            .set_signing_key(key_a0_id, key_a0)
618            .unwrap();
619    }
620
621    #[test]
622    fn test_set_keys_for_encryption() {
623        let store: KeyStore<TestIds> = KeyStore::default();
624
625        let key_a0_id = TestSymmKey::A(0);
627        let key_a0 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
628
629        store
630            .context_mut()
631            .set_symmetric_key(TestSymmKey::A(0), key_a0.clone())
632            .unwrap();
633
634        assert!(store.context().has_symmetric_key(key_a0_id));
635
636        let data = DataView("Hello, World!".to_string(), key_a0_id);
638        let _encrypted: Data = data
639            .encrypt_composite(&mut store.context(), key_a0_id)
640            .unwrap();
641    }
642
643    #[test]
644    fn test_key_encryption() {
645        let store: KeyStore<TestIds> = KeyStore::default();
646        let local = LocalId::new();
647
648        let mut ctx = store.context();
649
650        let key_1_id = TestSymmKey::C(local);
652        let key_1 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
653
654        ctx.set_symmetric_key(key_1_id, key_1.clone()).unwrap();
655
656        assert!(ctx.has_symmetric_key(key_1_id));
657
658        let key_2_id = TestSymmKey::C(local);
660        let key_2 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
661
662        ctx.set_symmetric_key(key_2_id, key_2.clone()).unwrap();
663
664        assert!(ctx.has_symmetric_key(key_2_id));
665
666        let key_2_enc = ctx.wrap_symmetric_key(key_1_id, key_2_id).unwrap();
668
669        let new_key_id = ctx.unwrap_symmetric_key(key_1_id, &key_2_enc).unwrap();
671
672        let data = DataView("Hello, World!".to_string(), key_2_id);
676        let encrypted = data.encrypt_composite(&mut ctx, key_2_id).unwrap();
677
678        let decrypted1 = encrypted.decrypt(&mut ctx, key_2_id).unwrap();
679        let decrypted2 = encrypted.decrypt(&mut ctx, new_key_id).unwrap();
680
681        assert_eq!(decrypted1.0, decrypted2.0);
683    }
684
685    #[test]
686    fn test_wrap_unwrap() {
687        let store: KeyStore<TestIds> = KeyStore::default();
688        let mut ctx = store.context_mut();
689
690        let key_aes_1_id = TestSymmKey::A(1);
692        let key_aes_1 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
693        ctx.set_symmetric_key(key_aes_1_id, key_aes_1.clone())
694            .unwrap();
695        let key_aes_2_id = TestSymmKey::A(2);
696        let key_aes_2 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
697        ctx.set_symmetric_key(key_aes_2_id, key_aes_2.clone())
698            .unwrap();
699
700        let key_xchacha_3_id = TestSymmKey::A(3);
702        let key_xchacha_3 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
703        ctx.set_symmetric_key(key_xchacha_3_id, key_xchacha_3.clone())
704            .unwrap();
705        let key_xchacha_4_id = TestSymmKey::A(4);
706        let key_xchacha_4 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
707        ctx.set_symmetric_key(key_xchacha_4_id, key_xchacha_4.clone())
708            .unwrap();
709
710        let wrapped_key_1_2 = ctx.wrap_symmetric_key(key_aes_1_id, key_aes_2_id).unwrap();
712        let wrapped_key_1_3 = ctx
713            .wrap_symmetric_key(key_aes_1_id, key_xchacha_3_id)
714            .unwrap();
715        let wrapped_key_3_1 = ctx
716            .wrap_symmetric_key(key_xchacha_3_id, key_aes_1_id)
717            .unwrap();
718        let wrapped_key_3_4 = ctx
719            .wrap_symmetric_key(key_xchacha_3_id, key_xchacha_4_id)
720            .unwrap();
721
722        let _unwrapped_key_2 = ctx
724            .unwrap_symmetric_key(key_aes_1_id, &wrapped_key_1_2)
725            .unwrap();
726        let _unwrapped_key_3 = ctx
727            .unwrap_symmetric_key(key_aes_1_id, &wrapped_key_1_3)
728            .unwrap();
729        let _unwrapped_key_1 = ctx
730            .unwrap_symmetric_key(key_xchacha_3_id, &wrapped_key_3_1)
731            .unwrap();
732        let _unwrapped_key_4 = ctx
733            .unwrap_symmetric_key(key_xchacha_3_id, &wrapped_key_3_4)
734            .unwrap();
735    }
736
737    #[test]
738    fn test_signing() {
739        let store: KeyStore<TestIds> = KeyStore::default();
740
741        let key_a0_id = TestSigningKey::A(0);
743        let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
744        let verifying_key = key_a0.to_verifying_key();
745        store
746            .context_mut()
747            .set_signing_key(key_a0_id, key_a0)
748            .unwrap();
749
750        assert!(store.context().has_signing_key(key_a0_id));
751
752        #[derive(Serialize, Deserialize)]
754        struct TestData {
755            data: String,
756        }
757        let signed_object = store
758            .context()
759            .sign(
760                key_a0_id,
761                &TestData {
762                    data: "Hello".to_string(),
763                },
764                &SigningNamespace::ExampleNamespace,
765            )
766            .unwrap();
767        let payload: Result<TestData, CryptoError> =
768            signed_object.verify_and_unwrap(&verifying_key, &SigningNamespace::ExampleNamespace);
769        assert!(payload.is_ok());
770
771        let (signature, serialized_message) = store
772            .context()
773            .sign_detached(
774                key_a0_id,
775                &TestData {
776                    data: "Hello".to_string(),
777                },
778                &SigningNamespace::ExampleNamespace,
779            )
780            .unwrap();
781        assert!(signature.verify(
782            serialized_message.as_bytes(),
783            &verifying_key,
784            &SigningNamespace::ExampleNamespace
785        ))
786    }
787
788    #[test]
789    fn test_account_key_rotation() {
790        let store: KeyStore<TestIds> = KeyStore::default();
791        let mut ctx = store.context_mut();
792
793        let current_user_signing_key_id = ctx.make_signing_key().unwrap();
795        let current_user_private_key_id = ctx.make_asymmetric_key().unwrap();
796
797        let rotated_keys = ctx
799            .dangerous_get_v2_rotated_account_keys(
800                current_user_private_key_id,
801                current_user_signing_key_id,
802            )
803            .unwrap();
804
805        assert_eq!(
807            AsymmetricPublicCryptoKey::from_der(&rotated_keys.public_key)
808                .unwrap()
809                .to_der()
810                .unwrap(),
811            ctx.get_asymmetric_key(current_user_private_key_id)
812                .unwrap()
813                .to_public_key()
814                .to_der()
815                .unwrap()
816        );
817        let decrypted_private_key: Vec<u8> = rotated_keys
818            .private_key
819            .decrypt_with_key(&rotated_keys.user_key)
820            .unwrap();
821        let private_key =
822            AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key))
823                .unwrap();
824        assert_eq!(
825            private_key.to_der().unwrap(),
826            ctx.get_asymmetric_key(current_user_private_key_id)
827                .unwrap()
828                .to_der()
829                .unwrap()
830        );
831
832        let decrypted_signing_key: Vec<u8> = rotated_keys
834            .signing_key
835            .decrypt_with_key(&rotated_keys.user_key)
836            .unwrap();
837        let signing_key =
838            SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
839        assert_eq!(
840            signing_key.to_cose(),
841            ctx.get_signing_key(current_user_signing_key_id)
842                .unwrap()
843                .to_cose(),
844        );
845
846        let signed_public_key = rotated_keys.signed_public_key;
848        let unwrapped_key = signed_public_key
849            .verify_and_unwrap(
850                &ctx.get_signing_key(current_user_signing_key_id)
851                    .unwrap()
852                    .to_verifying_key(),
853            )
854            .unwrap();
855        assert_eq!(
856            unwrapped_key.to_der().unwrap(),
857            ctx.get_asymmetric_key(current_user_private_key_id)
858                .unwrap()
859                .to_public_key()
860                .to_der()
861                .unwrap()
862        );
863    }
864
865    #[test]
866    fn test_encrypt_fails_when_operation_not_allowed() {
867        use coset::iana::KeyOperation;
868        let store = KeyStore::<TestIds>::default();
869        let mut ctx = store.context_mut();
870        let key_id = TestSymmKey::A(0);
871        let key = SymmetricCryptoKey::XChaCha20Poly1305Key(crate::XChaCha20Poly1305Key {
873            key_id: [0u8; 16],
874            enc_key: Box::pin([0u8; 32].into()),
875            supported_operations: vec![KeyOperation::Decrypt],
876        });
877        ctx.set_symmetric_key(key_id, key).unwrap();
878        let data = DataView("should fail".to_string(), key_id);
879        let result = data.encrypt_composite(&mut ctx, key_id);
880        assert!(
881            matches!(
882                result,
883                Err(CryptoError::KeyOperationNotSupported(KeyOperation::Encrypt))
884            ),
885            "Expected encrypt to fail with KeyOperationNotSupported",
886        );
887    }
888}