1use std::{
2 cell::Cell,
3 sync::{RwLockReadGuard, RwLockWriteGuard},
4};
5
6use serde::Serialize;
7use zeroize::Zeroizing;
8
9use super::KeyStoreInner;
10use crate::{
11 derive_shareable_key, error::UnsupportedOperation, signing, store::backend::StoreBackend,
12 AsymmetricCryptoKey, BitwardenLegacyKeyBytes, ContentFormat, CryptoError, EncString, KeyId,
13 KeyIds, PublicKeyEncryptionAlgorithm, Result, RotatedUserKeys, Signature, SignatureAlgorithm,
14 SignedObject, SignedPublicKey, SignedPublicKeyMessage, SigningKey, SymmetricCryptoKey,
15 UnsignedSharedKey,
16};
17
18#[must_use]
73pub struct KeyStoreContext<'a, Ids: KeyIds> {
74 pub(super) global_keys: GlobalKeys<'a, Ids>,
75
76 pub(super) local_symmetric_keys: Box<dyn StoreBackend<Ids::Symmetric>>,
77 pub(super) local_asymmetric_keys: Box<dyn StoreBackend<Ids::Asymmetric>>,
78 pub(super) local_signing_keys: Box<dyn StoreBackend<Ids::Signing>>,
79
80 pub(super) _phantom: std::marker::PhantomData<(Cell<()>, RwLockReadGuard<'static, ()>)>,
82}
83
84pub(crate) enum GlobalKeys<'a, Ids: KeyIds> {
90 ReadOnly(RwLockReadGuard<'a, KeyStoreInner<Ids>>),
91 ReadWrite(RwLockWriteGuard<'a, KeyStoreInner<Ids>>),
92}
93
94impl<Ids: KeyIds> GlobalKeys<'_, Ids> {
95 pub fn get(&self) -> &KeyStoreInner<Ids> {
96 match self {
97 GlobalKeys::ReadOnly(keys) => keys,
98 GlobalKeys::ReadWrite(keys) => keys,
99 }
100 }
101
102 pub fn get_mut(&mut self) -> Result<&mut KeyStoreInner<Ids>> {
103 match self {
104 GlobalKeys::ReadOnly(_) => Err(CryptoError::ReadOnlyKeyStore),
105 GlobalKeys::ReadWrite(keys) => Ok(keys),
106 }
107 }
108}
109
110impl<Ids: KeyIds> KeyStoreContext<'_, Ids> {
111 pub fn clear_local(&mut self) {
115 self.local_symmetric_keys.clear();
116 self.local_asymmetric_keys.clear();
117 self.local_signing_keys.clear();
118 }
119
120 pub fn retain_symmetric_keys(&mut self, f: fn(Ids::Symmetric) -> bool) {
123 if let Ok(keys) = self.global_keys.get_mut() {
124 keys.symmetric_keys.retain(f);
125 }
126 self.local_symmetric_keys.retain(f);
127 }
128
129 pub fn retain_asymmetric_keys(&mut self, f: fn(Ids::Asymmetric) -> bool) {
132 if let Ok(keys) = self.global_keys.get_mut() {
133 keys.asymmetric_keys.retain(f);
134 }
135 self.local_asymmetric_keys.retain(f);
136 }
137
138 pub fn unwrap_symmetric_key(
151 &mut self,
152 wrapping_key: Ids::Symmetric,
153 new_key_id: Ids::Symmetric,
154 wrapped_key: &EncString,
155 ) -> Result<Ids::Symmetric> {
156 let wrapping_key = self.get_symmetric_key(wrapping_key)?;
157
158 let key = match (wrapped_key, wrapping_key) {
159 (EncString::Aes256Cbc_B64 { iv, data }, SymmetricCryptoKey::Aes256CbcKey(key)) => {
160 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(
161 crate::aes::decrypt_aes256(iv, data.clone(), &key.enc_key)?,
162 ))?
163 }
164 (
165 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
166 SymmetricCryptoKey::Aes256CbcHmacKey(key),
167 ) => SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(
168 crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key)?,
169 ))?,
170 (
171 EncString::Cose_Encrypt0_B64 { data },
172 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
173 ) => {
174 let (content_bytes, content_format) =
175 crate::cose::decrypt_xchacha20_poly1305(data, key)?;
176 match content_format {
177 ContentFormat::BitwardenLegacyKey => {
178 SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(content_bytes))?
179 }
180 ContentFormat::CoseKey => SymmetricCryptoKey::try_from_cose(&content_bytes)?,
181 _ => return Err(CryptoError::InvalidKey),
182 }
183 }
184 _ => return Err(CryptoError::InvalidKey),
185 };
186
187 #[allow(deprecated)]
188 self.set_symmetric_key(new_key_id, key)?;
189
190 Ok(new_key_id)
192 }
193
194 pub fn wrap_symmetric_key(
203 &self,
204 wrapping_key: Ids::Symmetric,
205 key_to_wrap: Ids::Symmetric,
206 ) -> Result<EncString> {
207 use SymmetricCryptoKey::*;
208
209 let wrapping_key_instance = self.get_symmetric_key(wrapping_key)?;
210 let key_to_wrap_instance = self.get_symmetric_key(key_to_wrap)?;
211 match (wrapping_key_instance, key_to_wrap_instance) {
217 (
218 Aes256CbcHmacKey(_),
219 Aes256CbcHmacKey(_) | Aes256CbcKey(_) | XChaCha20Poly1305Key(_),
220 ) => self.encrypt_data_with_symmetric_key(
221 wrapping_key,
222 key_to_wrap_instance
223 .to_encoded()
224 .as_ref()
225 .to_vec()
226 .as_slice(),
227 ContentFormat::BitwardenLegacyKey,
228 ),
229 (XChaCha20Poly1305Key(_), _) => {
230 let encoded = key_to_wrap_instance.to_encoded_raw();
231 let content_format = encoded.content_format();
232 self.encrypt_data_with_symmetric_key(
233 wrapping_key,
234 Into::<Vec<u8>>::into(encoded).as_slice(),
235 content_format,
236 )
237 }
238 _ => Err(CryptoError::OperationNotSupported(
239 UnsupportedOperation::EncryptionNotImplementedForKey,
240 )),
241 }
242 }
243
244 pub fn decapsulate_key_unsigned(
254 &mut self,
255 decapsulation_key: Ids::Asymmetric,
256 new_key_id: Ids::Symmetric,
257 encapsulated_shared_key: &UnsignedSharedKey,
258 ) -> Result<Ids::Symmetric> {
259 let decapsulation_key = self.get_asymmetric_key(decapsulation_key)?;
260 let decapsulated_key =
261 encapsulated_shared_key.decapsulate_key_unsigned(decapsulation_key)?;
262
263 #[allow(deprecated)]
264 self.set_symmetric_key(new_key_id, decapsulated_key)?;
265
266 Ok(new_key_id)
268 }
269
270 pub fn encapsulate_key_unsigned(
279 &self,
280 encapsulation_key: Ids::Asymmetric,
281 shared_key: Ids::Symmetric,
282 ) -> Result<UnsignedSharedKey> {
283 UnsignedSharedKey::encapsulate_key_unsigned(
284 self.get_symmetric_key(shared_key)?,
285 &self.get_asymmetric_key(encapsulation_key)?.to_public_key(),
286 )
287 }
288
289 pub fn has_symmetric_key(&self, key_id: Ids::Symmetric) -> bool {
291 self.get_symmetric_key(key_id).is_ok()
292 }
293
294 pub fn has_asymmetric_key(&self, key_id: Ids::Asymmetric) -> bool {
296 self.get_asymmetric_key(key_id).is_ok()
297 }
298
299 pub fn has_signing_key(&self, key_id: Ids::Signing) -> bool {
301 self.get_signing_key(key_id).is_ok()
302 }
303
304 pub fn generate_symmetric_key(&mut self, key_id: Ids::Symmetric) -> Result<Ids::Symmetric> {
306 let key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
307 #[allow(deprecated)]
308 self.set_symmetric_key(key_id, key)?;
309 Ok(key_id)
310 }
311
312 #[cfg(test)]
314 pub(crate) fn make_cose_symmetric_key(
315 &mut self,
316 key_id: Ids::Symmetric,
317 ) -> Result<Ids::Symmetric> {
318 let key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
319 #[allow(deprecated)]
320 self.set_symmetric_key(key_id, key)?;
321 Ok(key_id)
322 }
323
324 pub fn make_asymmetric_key(&mut self, key_id: Ids::Asymmetric) -> Result<Ids::Asymmetric> {
327 let key = AsymmetricCryptoKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
328 #[allow(deprecated)]
329 self.set_asymmetric_key(key_id, key)?;
330 Ok(key_id)
331 }
332
333 pub fn make_signing_key(&mut self, key_id: Ids::Signing) -> Result<Ids::Signing> {
336 let key = SigningKey::make(SignatureAlgorithm::default_algorithm());
337 #[allow(deprecated)]
338 self.set_signing_key(key_id, key)?;
339 Ok(key_id)
340 }
341
342 pub fn derive_shareable_key(
347 &mut self,
348 key_id: Ids::Symmetric,
349 secret: Zeroizing<[u8; 16]>,
350 name: &str,
351 info: Option<&str>,
352 ) -> Result<Ids::Symmetric> {
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 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 if key_id.is_local() {
432 self.local_symmetric_keys.upsert(key_id, key);
433 } else {
434 self.global_keys
435 .get_mut()?
436 .symmetric_keys
437 .upsert(key_id, key);
438 }
439 Ok(())
440 }
441
442 #[deprecated(note = "This function should ideally never be used outside this crate")]
443 #[allow(missing_docs)]
444 pub fn set_asymmetric_key(
445 &mut self,
446 key_id: Ids::Asymmetric,
447 key: AsymmetricCryptoKey,
448 ) -> Result<()> {
449 if key_id.is_local() {
450 self.local_asymmetric_keys.upsert(key_id, key);
451 } else {
452 self.global_keys
453 .get_mut()?
454 .asymmetric_keys
455 .upsert(key_id, key);
456 }
457 Ok(())
458 }
459
460 #[deprecated(note = "This function should ideally never be used outside this crate")]
462 pub fn set_signing_key(&mut self, key_id: Ids::Signing, key: SigningKey) -> Result<()> {
463 if key_id.is_local() {
464 self.local_signing_keys.upsert(key_id, key);
465 } else {
466 self.global_keys.get_mut()?.signing_keys.upsert(key_id, key);
467 }
468 Ok(())
469 }
470
471 pub(crate) fn decrypt_data_with_symmetric_key(
472 &self,
473 key: Ids::Symmetric,
474 data: &EncString,
475 ) -> Result<Vec<u8>> {
476 let key = self.get_symmetric_key(key)?;
477
478 match (data, key) {
479 (EncString::Aes256Cbc_B64 { iv, data }, SymmetricCryptoKey::Aes256CbcKey(key)) => {
480 crate::aes::decrypt_aes256(iv, data.clone(), &key.enc_key)
481 }
482 (
483 EncString::Aes256Cbc_HmacSha256_B64 { iv, mac, data },
484 SymmetricCryptoKey::Aes256CbcHmacKey(key),
485 ) => crate::aes::decrypt_aes256_hmac(iv, mac, data.clone(), &key.mac_key, &key.enc_key),
486 (
487 EncString::Cose_Encrypt0_B64 { data },
488 SymmetricCryptoKey::XChaCha20Poly1305Key(key),
489 ) => {
490 let (data, _) = crate::cose::decrypt_xchacha20_poly1305(data, key)?;
491 Ok(data)
492 }
493 _ => Err(CryptoError::InvalidKey),
494 }
495 }
496
497 pub(crate) fn encrypt_data_with_symmetric_key(
498 &self,
499 key: Ids::Symmetric,
500 data: &[u8],
501 content_format: ContentFormat,
502 ) -> Result<EncString> {
503 let key = self.get_symmetric_key(key)?;
504 match key {
505 SymmetricCryptoKey::Aes256CbcKey(_) => Err(CryptoError::OperationNotSupported(
506 UnsupportedOperation::EncryptionNotImplementedForKey,
507 )),
508 SymmetricCryptoKey::Aes256CbcHmacKey(key) => EncString::encrypt_aes256_hmac(data, key),
509 SymmetricCryptoKey::XChaCha20Poly1305Key(key) => {
510 EncString::encrypt_xchacha20_poly1305(data, key, content_format)
511 }
512 }
513 }
514
515 pub fn sign<Message: Serialize>(
519 &self,
520 key: Ids::Signing,
521 message: &Message,
522 namespace: &crate::SigningNamespace,
523 ) -> Result<SignedObject> {
524 self.get_signing_key(key)?.sign(message, namespace)
525 }
526
527 #[allow(unused)]
531 pub(crate) fn sign_detached<Message: Serialize>(
532 &self,
533 key: Ids::Signing,
534 message: &Message,
535 namespace: &crate::SigningNamespace,
536 ) -> Result<(Signature, signing::SerializedMessage)> {
537 self.get_signing_key(key)?.sign_detached(message, namespace)
538 }
539
540 pub fn dangerous_get_v2_rotated_account_keys(
542 &self,
543 current_user_private_key_id: Ids::Asymmetric,
544 current_user_signing_key_id: Ids::Signing,
545 ) -> Result<RotatedUserKeys> {
546 crate::dangerous_get_v2_rotated_account_keys(
547 current_user_private_key_id,
548 current_user_signing_key_id,
549 self,
550 )
551 }
552}
553
554#[cfg(test)]
555#[allow(deprecated)]
556mod tests {
557 use serde::{Deserialize, Serialize};
558
559 use crate::{
560 store::{
561 tests::{Data, DataView},
562 KeyStore,
563 },
564 traits::tests::{TestAsymmKey, TestIds, TestSigningKey, TestSymmKey},
565 AsymmetricCryptoKey, AsymmetricPublicCryptoKey, CompositeEncryptable, CoseKeyBytes,
566 CoseSerializable, CryptoError, Decryptable, KeyDecryptable, Pkcs8PrivateKeyBytes,
567 PublicKeyEncryptionAlgorithm, SignatureAlgorithm, SigningKey, SigningNamespace,
568 SymmetricCryptoKey,
569 };
570
571 #[test]
572 fn test_set_signing_key() {
573 let store: KeyStore<TestIds> = KeyStore::default();
574
575 let key_a0_id = TestSigningKey::A(0);
577 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
578 store
579 .context_mut()
580 .set_signing_key(key_a0_id, key_a0)
581 .unwrap();
582 }
583
584 #[test]
585 fn test_set_keys_for_encryption() {
586 let store: KeyStore<TestIds> = KeyStore::default();
587
588 let key_a0_id = TestSymmKey::A(0);
590 let key_a0 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
591
592 store
593 .context_mut()
594 .set_symmetric_key(TestSymmKey::A(0), key_a0.clone())
595 .unwrap();
596
597 assert!(store.context().has_symmetric_key(key_a0_id));
598
599 let data = DataView("Hello, World!".to_string(), key_a0_id);
601 let _encrypted: Data = data
602 .encrypt_composite(&mut store.context(), key_a0_id)
603 .unwrap();
604 }
605
606 #[test]
607 fn test_key_encryption() {
608 let store: KeyStore<TestIds> = KeyStore::default();
609
610 let mut ctx = store.context();
611
612 let key_1_id = TestSymmKey::C(1);
614 let key_1 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
615
616 ctx.set_symmetric_key(key_1_id, key_1.clone()).unwrap();
617
618 assert!(ctx.has_symmetric_key(key_1_id));
619
620 let key_2_id = TestSymmKey::C(2);
622 let key_2 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
623
624 ctx.set_symmetric_key(key_2_id, key_2.clone()).unwrap();
625
626 assert!(ctx.has_symmetric_key(key_2_id));
627
628 let key_2_enc = ctx.wrap_symmetric_key(key_1_id, key_2_id).unwrap();
630
631 let new_key_id = TestSymmKey::C(3);
633
634 ctx.unwrap_symmetric_key(key_1_id, new_key_id, &key_2_enc)
635 .unwrap();
636
637 let data = DataView("Hello, World!".to_string(), key_2_id);
641 let encrypted = data.encrypt_composite(&mut ctx, key_2_id).unwrap();
642
643 let decrypted1 = encrypted.decrypt(&mut ctx, key_2_id).unwrap();
644 let decrypted2 = encrypted.decrypt(&mut ctx, new_key_id).unwrap();
645
646 assert_eq!(decrypted1.0, decrypted2.0);
648 }
649
650 #[test]
651 fn test_wrap_unwrap() {
652 let store: KeyStore<TestIds> = KeyStore::default();
653 let mut ctx = store.context_mut();
654
655 let key_aes_1_id = TestSymmKey::A(1);
657 let key_aes_1 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
658 ctx.set_symmetric_key(key_aes_1_id, key_aes_1.clone())
659 .unwrap();
660 let key_aes_2_id = TestSymmKey::A(2);
661 let key_aes_2 = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
662 ctx.set_symmetric_key(key_aes_2_id, key_aes_2.clone())
663 .unwrap();
664
665 let key_xchacha_3_id = TestSymmKey::A(3);
667 let key_xchacha_3 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
668 ctx.set_symmetric_key(key_xchacha_3_id, key_xchacha_3.clone())
669 .unwrap();
670 let key_xchacha_4_id = TestSymmKey::A(4);
671 let key_xchacha_4 = SymmetricCryptoKey::make_xchacha20_poly1305_key();
672 ctx.set_symmetric_key(key_xchacha_4_id, key_xchacha_4.clone())
673 .unwrap();
674
675 let wrapped_key_1_2 = ctx.wrap_symmetric_key(key_aes_1_id, key_aes_2_id).unwrap();
677 let wrapped_key_1_3 = ctx
678 .wrap_symmetric_key(key_aes_1_id, key_xchacha_3_id)
679 .unwrap();
680 let wrapped_key_3_1 = ctx
681 .wrap_symmetric_key(key_xchacha_3_id, key_aes_1_id)
682 .unwrap();
683 let wrapped_key_3_4 = ctx
684 .wrap_symmetric_key(key_xchacha_3_id, key_xchacha_4_id)
685 .unwrap();
686
687 let unwrapped_key_2 = ctx
689 .unwrap_symmetric_key(key_aes_1_id, key_aes_2_id, &wrapped_key_1_2)
690 .unwrap();
691 let unwrapped_key_3 = ctx
692 .unwrap_symmetric_key(key_aes_1_id, key_xchacha_3_id, &wrapped_key_1_3)
693 .unwrap();
694 let unwrapped_key_1 = ctx
695 .unwrap_symmetric_key(key_xchacha_3_id, key_aes_1_id, &wrapped_key_3_1)
696 .unwrap();
697 let unwrapped_key_4 = ctx
698 .unwrap_symmetric_key(key_xchacha_3_id, key_xchacha_4_id, &wrapped_key_3_4)
699 .unwrap();
700
701 assert_eq!(unwrapped_key_2, key_aes_2_id);
703 assert_eq!(unwrapped_key_3, key_xchacha_3_id);
704 assert_eq!(unwrapped_key_1, key_aes_1_id);
705 assert_eq!(unwrapped_key_4, key_xchacha_4_id);
706 }
707
708 #[test]
709 fn test_signing() {
710 let store: KeyStore<TestIds> = KeyStore::default();
711
712 let key_a0_id = TestSigningKey::A(0);
714 let key_a0 = SigningKey::make(SignatureAlgorithm::Ed25519);
715 let verifying_key = key_a0.to_verifying_key();
716 store
717 .context_mut()
718 .set_signing_key(key_a0_id, key_a0)
719 .unwrap();
720
721 assert!(store.context().has_signing_key(key_a0_id));
722
723 #[derive(Serialize, Deserialize)]
725 struct TestData {
726 data: String,
727 }
728 let signed_object = store
729 .context()
730 .sign(
731 key_a0_id,
732 &TestData {
733 data: "Hello".to_string(),
734 },
735 &SigningNamespace::ExampleNamespace,
736 )
737 .unwrap();
738 let payload: Result<TestData, CryptoError> =
739 signed_object.verify_and_unwrap(&verifying_key, &SigningNamespace::ExampleNamespace);
740 assert!(payload.is_ok());
741
742 let (signature, serialized_message) = store
743 .context()
744 .sign_detached(
745 key_a0_id,
746 &TestData {
747 data: "Hello".to_string(),
748 },
749 &SigningNamespace::ExampleNamespace,
750 )
751 .unwrap();
752 assert!(signature.verify(
753 serialized_message.as_bytes(),
754 &verifying_key,
755 &SigningNamespace::ExampleNamespace
756 ))
757 }
758
759 #[test]
760 fn test_account_key_rotation() {
761 let store: KeyStore<TestIds> = KeyStore::default();
762 let mut ctx = store.context_mut();
763
764 let current_user_private_key_id = TestAsymmKey::A(0);
766 let current_user_signing_key_id = TestSigningKey::A(0);
767
768 ctx.generate_symmetric_key(TestSymmKey::A(0)).unwrap();
770 ctx.make_signing_key(current_user_signing_key_id).unwrap();
771 ctx.set_asymmetric_key(
772 current_user_private_key_id,
773 AsymmetricCryptoKey::make(PublicKeyEncryptionAlgorithm::RsaOaepSha1),
774 )
775 .unwrap();
776
777 let rotated_keys = ctx
779 .dangerous_get_v2_rotated_account_keys(
780 current_user_private_key_id,
781 current_user_signing_key_id,
782 )
783 .unwrap();
784
785 assert_eq!(
787 AsymmetricPublicCryptoKey::from_der(&rotated_keys.public_key)
788 .unwrap()
789 .to_der()
790 .unwrap(),
791 ctx.get_asymmetric_key(current_user_private_key_id)
792 .unwrap()
793 .to_public_key()
794 .to_der()
795 .unwrap()
796 );
797 let decrypted_private_key: Vec<u8> = rotated_keys
798 .private_key
799 .decrypt_with_key(&rotated_keys.user_key)
800 .unwrap();
801 let private_key =
802 AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key))
803 .unwrap();
804 assert_eq!(
805 private_key.to_der().unwrap(),
806 ctx.get_asymmetric_key(current_user_private_key_id)
807 .unwrap()
808 .to_der()
809 .unwrap()
810 );
811
812 let decrypted_signing_key: Vec<u8> = rotated_keys
814 .signing_key
815 .decrypt_with_key(&rotated_keys.user_key)
816 .unwrap();
817 let signing_key =
818 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
819 assert_eq!(
820 signing_key.to_cose(),
821 ctx.get_signing_key(current_user_signing_key_id)
822 .unwrap()
823 .to_cose(),
824 );
825
826 let signed_public_key = rotated_keys.signed_public_key;
828 let unwrapped_key = signed_public_key
829 .verify_and_unwrap(
830 &ctx.get_signing_key(current_user_signing_key_id)
831 .unwrap()
832 .to_verifying_key(),
833 )
834 .unwrap();
835 assert_eq!(
836 unwrapped_key.to_der().unwrap(),
837 ctx.get_asymmetric_key(current_user_private_key_id)
838 .unwrap()
839 .to_public_key()
840 .to_der()
841 .unwrap()
842 );
843 }
844}