bitwarden_crypto/store/
key_rotation.rs1use crate::{
2 CoseKeyBytes, CoseSerializable, CryptoError, EncString, KeyEncryptable, KeyIds,
3 KeyStoreContext, SignedPublicKey, SignedPublicKeyMessage, SpkiPublicKeyBytes,
4 SymmetricCryptoKey,
5};
6
7pub struct RotatedUserKeys {
9 pub user_key: SymmetricCryptoKey,
11 pub verifying_key: CoseKeyBytes,
13 pub signing_key: EncString,
15 pub signed_public_key: SignedPublicKey,
17 pub public_key: SpkiPublicKeyBytes,
19 pub private_key: EncString,
21}
22
23pub fn dangerous_get_v2_rotated_account_keys<Ids: KeyIds>(
25 current_user_private_key_id: Ids::Asymmetric,
26 current_user_signing_key_id: Ids::Signing,
27 ctx: &KeyStoreContext<Ids>,
28) -> Result<RotatedUserKeys, CryptoError> {
29 let user_key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
30
31 let current_private_key = ctx.get_asymmetric_key(current_user_private_key_id)?;
32 let current_signing_key = ctx.get_signing_key(current_user_signing_key_id)?;
33
34 let current_public_key = ¤t_private_key.to_public_key();
35 let signed_public_key =
36 SignedPublicKeyMessage::from_public_key(current_public_key)?.sign(current_signing_key)?;
37
38 Ok(RotatedUserKeys {
39 verifying_key: current_signing_key.to_verifying_key().to_cose(),
40 signing_key: current_signing_key.to_cose().encrypt_with_key(&user_key)?,
41 signed_public_key,
42 public_key: current_public_key.to_der()?,
43 private_key: current_private_key.to_der()?.encrypt_with_key(&user_key)?,
44 user_key,
45 })
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use crate::{
52 AsymmetricCryptoKey, KeyDecryptable, KeyStore, Pkcs8PrivateKeyBytes, SigningKey,
53 traits::tests::TestIds,
54 };
55
56 #[test]
57 fn test_account_key_rotation() {
58 let store: KeyStore<TestIds> = KeyStore::default();
59 let mut ctx = store.context_mut();
60
61 let current_user_signing_key_id = ctx.make_signing_key().unwrap();
63 let current_user_private_key_id = ctx.make_asymmetric_key().unwrap();
64
65 let rotated_keys = dangerous_get_v2_rotated_account_keys(
67 current_user_private_key_id,
68 current_user_signing_key_id,
69 &ctx,
70 )
71 .unwrap();
72
73 assert_eq!(
75 rotated_keys.public_key,
76 ctx.get_asymmetric_key(current_user_private_key_id)
77 .unwrap()
78 .to_public_key()
79 .to_der()
80 .unwrap()
81 );
82 let decrypted_private_key: Vec<u8> = rotated_keys
83 .private_key
84 .decrypt_with_key(&rotated_keys.user_key)
85 .unwrap();
86 let private_key =
87 AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key))
88 .unwrap();
89 assert_eq!(
90 private_key.to_der().unwrap(),
91 ctx.get_asymmetric_key(current_user_private_key_id)
92 .unwrap()
93 .to_der()
94 .unwrap()
95 );
96
97 let decrypted_signing_key: Vec<u8> = rotated_keys
99 .signing_key
100 .decrypt_with_key(&rotated_keys.user_key)
101 .unwrap();
102 let signing_key =
103 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
104 assert_eq!(
105 signing_key.to_cose(),
106 ctx.get_signing_key(current_user_signing_key_id)
107 .unwrap()
108 .to_cose(),
109 );
110
111 let signed_public_key = rotated_keys.signed_public_key;
113 let unwrapped_key = signed_public_key
114 .verify_and_unwrap(
115 &ctx.get_signing_key(current_user_signing_key_id)
116 .unwrap()
117 .to_verifying_key(),
118 )
119 .unwrap();
120 assert_eq!(
121 unwrapped_key.to_der().unwrap(),
122 ctx.get_asymmetric_key(current_user_private_key_id)
123 .unwrap()
124 .to_public_key()
125 .to_der()
126 .unwrap()
127 );
128 }
129}