1pub mod cert_server;
2
3use std::{
4 path::Path,
5 sync::Arc,
6 time::{Duration, SystemTime},
7};
8
9use async_trait::async_trait;
10use bytes::Bytes;
11use http::uri::Authority;
12use moka::future::Cache;
13use openssl::{
14 asn1::{Asn1Integer, Asn1Time},
15 bn::BigNum,
16 hash::MessageDigest,
17 pkey::{PKey, Private},
18 rand,
19 x509::{
20 extension::{BasicConstraints, KeyUsage, SubjectAlternativeName},
21 X509Builder, X509NameBuilder, X509,
22 },
23};
24use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs1KeyDer};
25use tokio_rustls::rustls::ServerConfig;
26
27const TTL_SECS: i64 = 365 * 24 * 60 * 60;
28const CACHE_TTL: u64 = TTL_SECS as u64 / 2;
29const NOT_BEFORE_OFFSET: i64 = 60;
30const CA_TTL_SECS: i64 = 10 * 365 * 24 * 60 * 60;
31
32#[async_trait]
33pub trait CertificateAuthority: Send + Sync + 'static {
34 async fn gen_server_config(
35 &self,
36 authority: &Authority,
37 ) -> Result<Arc<ServerConfig>, crate::error::Error>;
38}
39
40#[derive(Clone)]
41pub struct Ssl {
42 pkey: PKey<Private>,
43 private_key_der: Vec<u8>,
44 ca_cert: X509,
45 ca_cert_pem: Bytes,
46 hash: MessageDigest,
47 cache: Cache<Authority, Arc<ServerConfig>>,
48}
49
50impl Ssl {
51 pub fn load_or_generate(dir: &Path) -> Result<Self, crate::error::Error> {
52 std::fs::create_dir_all(dir)?;
53
54 let cert_path = dir.join("proxelar-ca.pem");
55 let key_path = dir.join("proxelar-ca.key");
56
57 let (pkey, ca_cert) = if cert_path.exists() && key_path.exists() {
58 tracing::info!("Loading CA certificate from {}", dir.display());
59 let key_pem = std::fs::read(&key_path)?;
60 let cert_pem = std::fs::read(&cert_path)?;
61 let pkey = PKey::private_key_from_pem(&key_pem)?;
62 let ca_cert = X509::from_pem(&cert_pem)?;
63
64 if !ca_cert.public_key()?.public_eq(&pkey) {
66 return Err(crate::error::Error::Other(
67 "CA certificate does not match private key".into(),
68 ));
69 }
70
71 (pkey, ca_cert)
72 } else {
73 tracing::info!("Generating new CA certificate in {}", dir.display());
74 let (pkey, ca_cert) = generate_ca()?;
75
76 let key_pem = pkey.private_key_to_pem_pkcs8()?;
77 let cert_pem = ca_cert.to_pem()?;
78
79 std::fs::write(&key_path, &key_pem)?;
80 #[cfg(unix)]
81 {
82 use std::os::unix::fs::PermissionsExt;
83 std::fs::set_permissions(&key_path, std::fs::Permissions::from_mode(0o600))?;
84 }
85 std::fs::write(&cert_path, &cert_pem)?;
86
87 (pkey, ca_cert)
88 };
89
90 let ca_cert_pem = Bytes::from(ca_cert.to_pem()?);
91
92 let private_key_der = pkey.rsa()?.private_key_to_der()?;
93
94 Ok(Self {
95 pkey,
96 private_key_der,
97 ca_cert,
98 ca_cert_pem,
99 hash: MessageDigest::sha256(),
100 cache: Cache::builder()
101 .max_capacity(1_000)
102 .time_to_live(Duration::from_secs(CACHE_TTL))
103 .build(),
104 })
105 }
106
107 pub fn ca_cert_pem(&self) -> Bytes {
108 self.ca_cert_pem.clone()
109 }
110
111 fn gen_cert(
112 &self,
113 authority: &Authority,
114 ) -> Result<CertificateDer<'static>, crate::error::Error> {
115 let mut name_builder = X509NameBuilder::new()?;
116 name_builder.append_entry_by_text("CN", authority.host())?;
117 let name = name_builder.build();
118
119 let mut x509_builder = X509Builder::new()?;
120 x509_builder.set_subject_name(&name)?;
121 x509_builder.set_version(2)?;
122
123 let not_before = SystemTime::now()
124 .duration_since(SystemTime::UNIX_EPOCH)?
125 .as_secs() as i64
126 - NOT_BEFORE_OFFSET;
127 x509_builder.set_not_before(Asn1Time::from_unix(not_before)?.as_ref())?;
128 x509_builder.set_not_after(Asn1Time::from_unix(not_before + TTL_SECS)?.as_ref())?;
129
130 x509_builder.set_pubkey(&self.pkey)?;
131 x509_builder.set_issuer_name(self.ca_cert.subject_name())?;
132
133 let alternative_name = SubjectAlternativeName::new()
134 .dns(authority.host())
135 .build(&x509_builder.x509v3_context(Some(&self.ca_cert), None))?;
136 x509_builder.append_extension(alternative_name)?;
137
138 let mut serial_number = [0; 16];
139 rand::rand_bytes(&mut serial_number)?;
140
141 let serial_number = BigNum::from_slice(&serial_number)?;
142 let serial_number = Asn1Integer::from_bn(&serial_number)?;
143 x509_builder.set_serial_number(&serial_number)?;
144
145 x509_builder.sign(&self.pkey, self.hash)?;
146 let x509 = x509_builder.build();
147 Ok(CertificateDer::from(x509.to_der()?))
148 }
149}
150
151fn generate_ca() -> Result<(PKey<Private>, X509), crate::error::Error> {
152 let rsa = openssl::rsa::Rsa::generate(4096)?;
153 let pkey = PKey::from_rsa(rsa)?;
154
155 let mut name_builder = X509NameBuilder::new()?;
156 name_builder.append_entry_by_text("CN", "proxelar")?;
157 name_builder.append_entry_by_text("O", "Proxelar")?;
158 let name = name_builder.build();
159
160 let mut builder = X509Builder::new()?;
161 builder.set_version(2)?;
162 builder.set_subject_name(&name)?;
163 builder.set_issuer_name(&name)?;
164 builder.set_pubkey(&pkey)?;
165
166 let not_before = SystemTime::now()
167 .duration_since(SystemTime::UNIX_EPOCH)?
168 .as_secs() as i64
169 - NOT_BEFORE_OFFSET;
170 builder.set_not_before(Asn1Time::from_unix(not_before)?.as_ref())?;
171 builder.set_not_after(Asn1Time::from_unix(not_before + CA_TTL_SECS)?.as_ref())?;
172
173 let mut serial_number = [0; 16];
174 rand::rand_bytes(&mut serial_number)?;
175 let serial_number = BigNum::from_slice(&serial_number)?;
176 let serial_number = Asn1Integer::from_bn(&serial_number)?;
177 builder.set_serial_number(&serial_number)?;
178
179 let basic_constraints = BasicConstraints::new().critical().ca().build()?;
180 builder.append_extension(basic_constraints)?;
181
182 let key_usage = KeyUsage::new()
183 .critical()
184 .key_cert_sign()
185 .crl_sign()
186 .build()?;
187 builder.append_extension(key_usage)?;
188
189 builder.sign(&pkey, MessageDigest::sha512())?;
190 let cert = builder.build();
191
192 Ok((pkey, cert))
193}
194
195#[async_trait]
196impl CertificateAuthority for Ssl {
197 async fn gen_server_config(
198 &self,
199 authority: &Authority,
200 ) -> Result<Arc<ServerConfig>, crate::error::Error> {
201 if let Some(server_cfg) = self.cache.get(authority).await {
202 tracing::debug!("Using cached server config for {authority}");
203 return Ok(server_cfg);
204 }
205 tracing::debug!("Generating server config for {authority}");
206
207 let certs = vec![self.gen_cert(authority)?];
208
209 let private_key =
210 PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from(self.private_key_der.clone()));
211
212 let mut server_cfg = ServerConfig::builder()
213 .with_no_client_auth()
214 .with_single_cert(certs, private_key)?;
215
216 server_cfg.alpn_protocols = vec![b"http/1.1".to_vec()];
217
218 let server_cfg = Arc::new(server_cfg);
219
220 self.cache
221 .insert(authority.clone(), Arc::clone(&server_cfg))
222 .await;
223
224 Ok(server_cfg)
225 }
226}