use rand::{CryptoRng, Rng};
use webrtc::peer_connection::certificate::RTCCertificate;
use crate::tokio::fingerprint::Fingerprint;
#[derive(Debug, Clone, PartialEq)]
pub struct Certificate {
inner: RTCCertificate,
}
impl Certificate {
#[allow(clippy::unnecessary_wraps)]
pub fn generate<R>(_rng: &mut R) -> Result<Self, Error>
where
R: CryptoRng + Rng,
{
let keypair = rcgen::KeyPair::generate().expect("keypair to be able to be generated");
Ok(Self {
inner: RTCCertificate::from_key_pair(keypair).expect("default params to work"),
})
}
pub fn fingerprint(&self) -> Fingerprint {
let fingerprints = self.inner.get_fingerprints();
let sha256_fingerprint = fingerprints
.iter()
.find(|f| f.algorithm == "sha-256")
.expect("a SHA-256 fingerprint");
Fingerprint::try_from_rtc_dtls(sha256_fingerprint).expect("we filtered by sha-256")
}
#[cfg(feature = "pem")]
pub fn from_pem(pem_str: &str) -> Result<Self, Error> {
Ok(Self {
inner: RTCCertificate::from_pem(pem_str).map_err(Kind::InvalidPEM)?,
})
}
#[cfg(feature = "pem")]
pub fn serialize_pem(&self) -> String {
self.inner.serialize_pem()
}
pub(crate) fn to_rtc_certificate(&self) -> RTCCertificate {
self.inner.clone()
}
}
#[derive(thiserror::Error, Debug)]
#[error("Failed to generate certificate")]
pub struct Error(#[from] Kind);
#[derive(thiserror::Error, Debug)]
enum Kind {
#[error(transparent)]
InvalidPEM(#[from] webrtc::Error),
}
#[cfg(all(test, feature = "pem"))]
mod test {
use rand::thread_rng;
use super::*;
#[test]
fn test_certificate_serialize_pem_and_from_pem() {
let cert = Certificate::generate(&mut thread_rng()).unwrap();
let pem = cert.serialize_pem();
let loaded_cert = Certificate::from_pem(&pem).unwrap();
assert_eq!(loaded_cert, cert)
}
}