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, SignatureAlgorithm,
53 SigningKey, 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 =
63 ctx.make_signing_key(SignatureAlgorithm::Ed25519).unwrap();
64 let current_user_private_key_id = ctx.make_asymmetric_key().unwrap();
65
66 let rotated_keys = dangerous_get_v2_rotated_account_keys(
68 current_user_private_key_id,
69 current_user_signing_key_id,
70 &ctx,
71 )
72 .unwrap();
73
74 assert_eq!(
76 rotated_keys.public_key,
77 ctx.get_asymmetric_key(current_user_private_key_id)
78 .unwrap()
79 .to_public_key()
80 .to_der()
81 .unwrap()
82 );
83 let decrypted_private_key: Vec<u8> = rotated_keys
84 .private_key
85 .decrypt_with_key(&rotated_keys.user_key)
86 .unwrap();
87 let private_key =
88 AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key))
89 .unwrap();
90 assert_eq!(
91 private_key.to_der().unwrap(),
92 ctx.get_asymmetric_key(current_user_private_key_id)
93 .unwrap()
94 .to_der()
95 .unwrap()
96 );
97
98 let decrypted_signing_key: Vec<u8> = rotated_keys
100 .signing_key
101 .decrypt_with_key(&rotated_keys.user_key)
102 .unwrap();
103 let signing_key =
104 SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
105 assert_eq!(
106 signing_key.to_cose(),
107 ctx.get_signing_key(current_user_signing_key_id)
108 .unwrap()
109 .to_cose(),
110 );
111
112 let signed_public_key = rotated_keys.signed_public_key;
114 let unwrapped_key = signed_public_key
115 .verify_and_unwrap(
116 &ctx.get_signing_key(current_user_signing_key_id)
117 .unwrap()
118 .to_verifying_key(),
119 )
120 .unwrap();
121 assert_eq!(
122 unwrapped_key.to_der().unwrap(),
123 ctx.get_asymmetric_key(current_user_private_key_id)
124 .unwrap()
125 .to_public_key()
126 .to_der()
127 .unwrap()
128 );
129 }
130}