1use fastcrypto::ed25519::{Ed25519PrivateKey, Ed25519PublicKey};
6use pkcs8::EncodePrivateKey;
7use rcgen::{CertificateParams, KeyPair};
8use rustls::pki_types::{CertificateDer, PrivateKeyDer};
9
10pub struct SelfSignedCertificate {
11 inner: rcgen::Certificate,
12 key: KeyPair,
13}
14
15impl SelfSignedCertificate {
16 pub fn new(private_key: Ed25519PrivateKey, server_name: &str) -> Self {
17 let (cert, key) = generate_self_signed_tls_certificate(private_key, server_name);
18 Self { inner: cert, key }
19 }
20
21 pub fn rustls_certificate(&self) -> CertificateDer<'static> {
22 self.inner.der().to_owned()
23 }
24
25 pub fn rustls_private_key(&self) -> PrivateKeyDer<'static> {
26 PrivateKeyDer::Pkcs8(self.key.serialize_der().into())
27 }
28
29 pub fn reqwest_identity(&self) -> reqwest::tls::Identity {
30 let pem = self.inner.pem() + &self.key.serialize_pem();
31 reqwest::tls::Identity::from_pem(pem.as_ref()).unwrap()
32 }
33
34 pub fn reqwest_certificate(&self) -> reqwest::tls::Certificate {
35 reqwest::tls::Certificate::from_der(self.inner.der()).unwrap()
36 }
37}
38
39fn generate_self_signed_tls_certificate(
40 private_key: Ed25519PrivateKey,
41 server_name: &str,
42) -> (rcgen::Certificate, KeyPair) {
43 let keypair = ed25519::KeypairBytes {
44 secret_key: private_key.0.to_bytes(),
45 public_key: None,
48 };
49
50 let pkcs8 = keypair.to_pkcs8_der().unwrap();
51 let key_der = PrivateKeyDer::Pkcs8(pkcs8.as_bytes().to_vec().into());
52 let keypair = KeyPair::from_der_and_sign_algo(&key_der, &rcgen::PKCS_ED25519).unwrap();
53
54 (generate_cert(&keypair, server_name), keypair)
55}
56
57fn generate_cert(keypair: &KeyPair, server_name: &str) -> rcgen::Certificate {
58 CertificateParams::new(vec![server_name.to_owned()])
59 .unwrap()
60 .self_signed(keypair)
61 .expect(
62 "unreachable! from_params should only fail if the key is incompatible with params.algo",
63 )
64}
65
66pub(crate) fn public_key_from_certificate(
67 certificate: &CertificateDer,
68) -> Result<Ed25519PublicKey, anyhow::Error> {
69 use fastcrypto::traits::ToFromBytes;
70 use x509_parser::{certificate::X509Certificate, prelude::FromDer};
71
72 let cert = X509Certificate::from_der(certificate.as_ref())
73 .map_err(|e| rustls::Error::General(e.to_string()))?;
74 let spki = cert.1.public_key();
75 let public_key_bytes =
76 <ed25519::pkcs8::PublicKeyBytes as pkcs8::DecodePublicKey>::from_public_key_der(spki.raw)
77 .map_err(|e| rustls::Error::General(format!("invalid ed25519 public key: {e}")))?;
78
79 let public_key = Ed25519PublicKey::from_bytes(public_key_bytes.as_ref())?;
80
81 Ok(public_key)
82}