use crate::keys::newtypes::{PayloadBytes, PrivateKeyBytes, SignatureBytes};
use crate::keys::{KeyAlgorithm, KeyId, KeyPair, KeyRole, PublicKey};
use crate::signatures::PublicKeysRepository;
use crate::Error;
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct EphemeralKeyPair {
public: PublicKey,
private: PrivateKeyBytes<'static>,
}
impl PublicKeysRepository for EphemeralKeyPair {
fn get<'a>(&'a self, _id: &KeyId) -> Option<&'a PublicKey> {
Some(&self.public)
}
}
impl EphemeralKeyPair {
pub fn generate(
algorithm: KeyAlgorithm,
role: KeyRole,
expiry: Option<OffsetDateTime>,
) -> Result<Self, Error> {
let private = algorithm.methods().generate_private_key()?;
Ok(EphemeralKeyPair {
public: PublicKey {
role,
algorithm,
expiry,
public: algorithm
.methods()
.derive_public_key_from_private_key(&private)?,
},
private,
})
}
}
impl KeyPair for EphemeralKeyPair {
fn public(&self) -> &PublicKey {
&self.public
}
async fn sign(&self, data: &PayloadBytes<'_>) -> Result<SignatureBytes<'static>, Error> {
self.public.algorithm.methods().sign(&self.private, data)
}
}
#[cfg(test)]
mod tests {
use super::*;
const ALGORITHM: KeyAlgorithm = KeyAlgorithm::EcdsaP256Sha256Asn1SpkiDer;
#[test]
fn test_unique_keys_are_generated() {
assert_ne!(
EphemeralKeyPair::generate(ALGORITHM, KeyRole::Root, None)
.unwrap()
.private,
EphemeralKeyPair::generate(ALGORITHM, KeyRole::Root, None)
.unwrap()
.private
);
}
#[test]
fn test_key_with_unknown_algorithm_is_not_generated() {
assert!(matches!(
EphemeralKeyPair::generate(KeyAlgorithm::Unknown, KeyRole::Root, None),
Err(Error::UnsupportedKey),
));
}
#[test]
fn test_public_key_is_expected() {
let key = EphemeralKeyPair::generate(ALGORITHM, KeyRole::Root, None).unwrap();
let public = key.public();
assert_eq!(public.role, KeyRole::Root);
assert_eq!(public.algorithm, ALGORITHM);
assert_eq!(
public.public,
ALGORITHM
.methods()
.derive_public_key_from_private_key(&key.private)
.unwrap()
);
}
#[tokio::test]
async fn test_signatures_are_valid() {
let key = EphemeralKeyPair::generate(ALGORITHM, KeyRole::Root, None).unwrap();
let data = PayloadBytes::borrowed(b"Hello world");
let signature = key.sign(&data).await.unwrap();
assert!(ALGORITHM
.methods()
.verify(&key.public.public, &data, &signature)
.is_ok());
}
#[tokio::test]
async fn test_sign_with_unknown_algorithm_fails() {
let mut key = EphemeralKeyPair::generate(ALGORITHM, KeyRole::Root, None).unwrap();
key.public.algorithm = KeyAlgorithm::Unknown;
assert!(matches!(
key.sign(&PayloadBytes::borrowed(b"Hello world")).await,
Err(Error::UnsupportedKey)
));
}
}