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
23#[deprecated(note = "Use AccountCryptographicState::rotate instead")]
25pub fn dangerous_get_v2_rotated_account_keys<Ids: KeyIds>(
26 current_user_private_key_id: Ids::Private,
27 current_user_signing_key_id: Ids::Signing,
28 ctx: &KeyStoreContext<Ids>,
29) -> Result<RotatedUserKeys, CryptoError> {
30 let user_key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
31
32 let current_private_key = ctx.get_private_key(current_user_private_key_id)?;
33 let current_signing_key = ctx.get_signing_key(current_user_signing_key_id)?;
34
35 let current_public_key = ¤t_private_key.to_public_key();
36 let signed_public_key =
37 SignedPublicKeyMessage::from_public_key(current_public_key)?.sign(current_signing_key)?;
38
39 Ok(RotatedUserKeys {
40 verifying_key: current_signing_key.to_verifying_key().to_cose(),
41 signing_key: current_signing_key.to_cose().encrypt_with_key(&user_key)?,
42 signed_public_key,
43 public_key: current_public_key.to_der()?,
44 private_key: current_private_key.to_der()?.encrypt_with_key(&user_key)?,
45 user_key,
46 })
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52 use crate::{
53 KeyDecryptable, KeyStore, Pkcs8PrivateKeyBytes, PrivateKey, PublicKeyEncryptionAlgorithm,
54 SignatureAlgorithm, SigningKey, traits::tests::TestIds,
55 };
56
57 #[test]
58 fn test_account_key_rotation() {
59 let store: KeyStore<TestIds> = KeyStore::default();
60 let mut ctx = store.context_mut();
61
62 let current_user_signing_key_id = ctx.make_signing_key(SignatureAlgorithm::Ed25519);
64 let current_user_private_key_id =
65 ctx.make_private_key(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
66
67 #[expect(deprecated)]
69 let rotated_keys = dangerous_get_v2_rotated_account_keys(
70 current_user_private_key_id,
71 current_user_signing_key_id,
72 &ctx,
73 )
74 .unwrap();
75
76 assert_eq!(
78 rotated_keys.public_key,
79 ctx.get_private_key(current_user_private_key_id)
80 .unwrap()
81 .to_public_key()
82 .to_der()
83 .unwrap()
84 );
85 let decrypted_private_key: Vec<u8> = rotated_keys
86 .private_key
87 .decrypt_with_key(&rotated_keys.user_key)
88 .unwrap();
89 let private_key =
90 PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key)).unwrap();
91 assert_eq!(
92 private_key.to_der().unwrap(),
93 ctx.get_private_key(current_user_private_key_id)
94 .unwrap()
95 .to_der()
96 .unwrap()
97 );
98
99 let decrypted_signing_key: Vec<u8> = rotated_keys
101 .signing_key
102 .decrypt_with_key(&rotated_keys.user_key)
103 .unwrap();
104 let signing_key =
105 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
106 assert_eq!(
107 signing_key.to_cose(),
108 ctx.get_signing_key(current_user_signing_key_id)
109 .unwrap()
110 .to_cose(),
111 );
112
113 let signed_public_key = rotated_keys.signed_public_key;
115 let unwrapped_key = signed_public_key
116 .verify_and_unwrap(
117 &ctx.get_signing_key(current_user_signing_key_id)
118 .unwrap()
119 .to_verifying_key(),
120 )
121 .unwrap();
122 assert_eq!(
123 unwrapped_key.to_der().unwrap(),
124 ctx.get_private_key(current_user_private_key_id)
125 .unwrap()
126 .to_public_key()
127 .to_der()
128 .unwrap()
129 );
130 }
131}