mod certificate;
mod certificate_chain;
pub(crate) mod private_key;
pub use certificate::Certificate;
pub use certificate_chain::CertificateChain;
pub use private_key::PrivateKey;
use rustls::sign::CertifiedKey;
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serializer};
use crate::error;
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct KeyPair {
certificate_chain: CertificateChain,
#[serde(deserialize_with = "deserialize_private_key")]
private_key: PrivateKey,
}
impl TryFrom<(CertificateChain, PrivateKey)> for KeyPair {
type Error = error::KeyPair;
fn try_from(
(certificate_chain, private_key): (CertificateChain, PrivateKey),
) -> Result<Self, Self::Error> {
Self::from_parts(certificate_chain, private_key)
}
}
impl KeyPair {
#[cfg(feature = "rcgen")]
#[allow(clippy::missing_panics_doc)]
pub fn new_self_signed<S: Into<String>>(domain: S) -> Self {
let key_pair = rcgen::generate_simple_self_signed([domain.into()])
.expect("`rcgen` failed generating a self-signed certificate");
let certificate = Certificate::unchecked_from_der(
key_pair
.serialize_der()
.expect("`rcgen` failed serializing a certificate"),
);
let certificate_chain = CertificateChain::unchecked_from_certificates([certificate]);
let private_key = PrivateKey::unchecked_from_der(key_pair.serialize_private_key_der());
Self {
certificate_chain,
private_key,
}
}
pub fn from_parts(
certificate_chain: CertificateChain,
private_key: PrivateKey,
) -> Result<Self, error::KeyPair> {
Ok(Self {
certificate_chain,
private_key,
})
}
#[must_use]
pub fn unchecked_from_parts(
certificate_chain: CertificateChain,
private_key: PrivateKey,
) -> Self {
Self {
certificate_chain,
private_key,
}
}
#[must_use]
pub const fn certificate_chain(&self) -> &CertificateChain {
&self.certificate_chain
}
#[must_use]
pub fn end_entity_certificate(&self) -> &Certificate {
self.certificate_chain.end_entity_certificate()
}
#[must_use]
pub const fn private_key(&self) -> &PrivateKey {
&self.private_key
}
#[must_use]
pub fn into_parts(self) -> (CertificateChain, PrivateKey) {
(self.certificate_chain, self.private_key)
}
#[must_use]
pub const fn parts(&self) -> (&CertificateChain, &PrivateKey) {
(&self.certificate_chain, &self.private_key)
}
pub(crate) fn into_rustls(self) -> CertifiedKey {
CertifiedKey::new(
self.certificate_chain.into_rustls(),
self.private_key.into_rustls_signing_key(),
)
}
}
pub trait Dangerous {
fn serialize<S: Serializer>(key_pair: &Self, serializer: S) -> Result<S::Ok, S::Error>;
}
impl Dangerous for KeyPair {
fn serialize<S: Serializer>(key_pair: &Self, serializer: S) -> Result<S::Ok, S::Error> {
let mut serializer = serializer.serialize_struct("KeyPair", 2)?;
serializer.serialize_field("certificate_chain", &key_pair.certificate_chain)?;
serializer.serialize_field(
"private_key",
private_key::Dangerous::as_ref(&key_pair.private_key),
)?;
serializer.end()
}
}
fn deserialize_private_key<'de, D>(deserializer: D) -> Result<PrivateKey, D::Error>
where
D: Deserializer<'de>,
{
Ok(PrivateKey::unchecked_from_der(Vec::<u8>::deserialize(
deserializer,
)?))
}
#[test]
fn serialize() -> anyhow::Result<()> {
use bincode::{config::DefaultOptions, Options, Serializer};
let key_pair = KeyPair::new_self_signed("test");
let mut buffer = Vec::new();
Dangerous::serialize(
&key_pair,
&mut Serializer::new(
&mut buffer,
DefaultOptions::default()
.with_fixint_encoding()
.allow_trailing_bytes(),
),
)?;
assert_eq!(key_pair, bincode::deserialize(&buffer)?);
Ok(())
}
#[test]
fn debug() {
let key_pair = KeyPair::new_self_signed("test");
assert_eq!(
format!(
"KeyPair {{ certificate_chain: {:?}, private_key: PrivateKey(\"[[redacted]]\") }}",
key_pair.certificate_chain()
),
format!("{:?}", key_pair)
);
}