use crate::{
CoseKeyBytes, CoseSerializable, CryptoError, EncString, KeyEncryptable, KeySlotIds,
KeyStoreContext, SignedPublicKey, SignedPublicKeyMessage, SpkiPublicKeyBytes,
SymmetricCryptoKey,
};
pub struct RotatedUserKeys {
pub user_key: SymmetricCryptoKey,
pub verifying_key: CoseKeyBytes,
pub signing_key: EncString,
pub signed_public_key: SignedPublicKey,
pub public_key: SpkiPublicKeyBytes,
pub private_key: EncString,
}
#[deprecated(note = "Use AccountCryptographicState::rotate instead")]
pub fn dangerous_get_v2_rotated_account_keys<Ids: KeySlotIds>(
current_user_private_key_id: Ids::Private,
current_user_signing_key_id: Ids::Signing,
ctx: &KeyStoreContext<Ids>,
) -> Result<RotatedUserKeys, CryptoError> {
let user_key = SymmetricCryptoKey::make_xchacha20_poly1305_key();
let current_private_key = ctx.get_private_key(current_user_private_key_id)?;
let current_signing_key = ctx.get_signing_key(current_user_signing_key_id)?;
let current_public_key = ¤t_private_key.to_public_key();
let signed_public_key =
SignedPublicKeyMessage::from_public_key(current_public_key)?.sign(current_signing_key)?;
Ok(RotatedUserKeys {
verifying_key: current_signing_key.to_verifying_key().to_cose(),
signing_key: current_signing_key.to_cose().encrypt_with_key(&user_key)?,
signed_public_key,
public_key: current_public_key.to_der()?,
private_key: current_private_key.to_der()?.encrypt_with_key(&user_key)?,
user_key,
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
KeyDecryptable, KeyStore, Pkcs8PrivateKeyBytes, PrivateKey, PublicKeyEncryptionAlgorithm,
SignatureAlgorithm, SigningKey, traits::tests::TestIds,
};
#[test]
fn test_account_key_rotation() {
let store: KeyStore<TestIds> = KeyStore::default();
let mut ctx = store.context_mut();
let current_user_signing_key_id = ctx.make_signing_key(SignatureAlgorithm::Ed25519);
let current_user_private_key_id =
ctx.make_private_key(PublicKeyEncryptionAlgorithm::RsaOaepSha1);
#[expect(deprecated)]
let rotated_keys = dangerous_get_v2_rotated_account_keys(
current_user_private_key_id,
current_user_signing_key_id,
&ctx,
)
.unwrap();
assert_eq!(
rotated_keys.public_key,
ctx.get_private_key(current_user_private_key_id)
.unwrap()
.to_public_key()
.to_der()
.unwrap()
);
let decrypted_private_key: Vec<u8> = rotated_keys
.private_key
.decrypt_with_key(&rotated_keys.user_key)
.unwrap();
let private_key =
PrivateKey::from_der(&Pkcs8PrivateKeyBytes::from(decrypted_private_key)).unwrap();
assert_eq!(
private_key.to_der().unwrap(),
ctx.get_private_key(current_user_private_key_id)
.unwrap()
.to_der()
.unwrap()
);
let decrypted_signing_key: Vec<u8> = rotated_keys
.signing_key
.decrypt_with_key(&rotated_keys.user_key)
.unwrap();
let signing_key =
SigningKey::from_cose(&CoseKeyBytes::from(decrypted_signing_key)).unwrap();
assert_eq!(
signing_key.to_cose(),
ctx.get_signing_key(current_user_signing_key_id)
.unwrap()
.to_cose(),
);
let signed_public_key = rotated_keys.signed_public_key;
let unwrapped_key = signed_public_key
.verify_and_unwrap(
&ctx.get_signing_key(current_user_signing_key_id)
.unwrap()
.to_verifying_key(),
)
.unwrap();
assert_eq!(
unwrapped_key.to_der().unwrap(),
ctx.get_private_key(current_user_private_key_id)
.unwrap()
.to_public_key()
.to_der()
.unwrap()
);
}
}