itsi-server 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ed95c9c3d6f98ecc1b489a6a250e6d2fd4e20c592e8a5eb70e88daae63d22dc2
4
- data.tar.gz: 41ed850e9779845be4cbd2fbf47d0a42d8b08054c9581434431c54fd931c3fb8
3
+ metadata.gz: be27a619d6a8c35a088332bb467aaf1c15f1e146eefcb9eea4e2bfa30400a1a3
4
+ data.tar.gz: ac488266fb7e70c0e5a75ad8a14c0788d73a8e2c06df32c4e8968172477950c2
5
5
  SHA512:
6
- metadata.gz: fcdb9213a107523d7bba3728341d072c8c09ee6a8d3d250489a98445236ec0330a14e737e6e7876c26d1836d782efbdd91cdaa828a6d4d7e7c89830a701e93d2
7
- data.tar.gz: f2f3ad35ec63079df46f2b7387e6325b25191c9b0a42d695096b5c56c9d7fe73010bd3a76350a9f9e11e512b4abf650bc1d212addd25a3ac03485674ef7670b8
6
+ metadata.gz: 1b5e765780844d7ab418246aa44481bad579de73fcdb1b19001327456f4d643c5f7dbce310965dae975895ca98388dfeeaa74ab67542000c3d48cfb41e5a473e
7
+ data.tar.gz: 8cdc7c721573ec281918d80d33870636326c53e7a59b3c4752215a2c5c1da67df8461aff3dd933d56400a813811668b4ab92a6bcae3ca9ffa8e50fcededda8fd
@@ -65,6 +65,7 @@ impl From<ItsiError> for magnus::Error {
65
65
  ItsiError::ClientConnectionClosed => {
66
66
  magnus::Error::new(magnus::exception::eof_error(), CLIENT_CONNECTION_CLOSED)
67
67
  }
68
+ ItsiError::Pass() => magnus::Error::new(magnus::exception::interrupt(), "Pass"),
68
69
  }
69
70
  }
70
71
  }
@@ -19,4 +19,6 @@ pub enum ItsiError {
19
19
  Jump(String),
20
20
  #[error("Break")]
21
21
  Break(),
22
+ #[error("Pass")]
23
+ Pass(),
22
24
  }
@@ -17,7 +17,7 @@ itsi_error = { path = "../itsi_error" }
17
17
  socket2 = "0.5.8"
18
18
  parking_lot = "0.12.3"
19
19
  rustls-pemfile = "2.2.0"
20
- tokio-rustls = "0.23"
20
+ tokio-rustls = "0.26.2"
21
21
  bytes = "1.3"
22
22
  rcgen = { version = "0.13.2", features = ["x509-parser", "pem"] }
23
23
  base64 = "0.22.1"
@@ -39,3 +39,8 @@ httparse = "1.10.1"
39
39
  async-channel = "2.3.1"
40
40
  tempfile = "3.18.0"
41
41
  sysinfo = "0.33.1"
42
+ tokio-rustls-acme = "0.6.0"
43
+ rustls = "0.23.23"
44
+ fs2 = "0.4.3"
45
+ ring = "0.17.14"
46
+ async-trait = "0.1.87"
@@ -56,6 +56,9 @@ pub fn log_error(msg: String) {
56
56
  #[magnus::init]
57
57
  fn init(ruby: &Ruby) -> Result<()> {
58
58
  itsi_tracing::init();
59
+ rustls::crypto::aws_lc_rs::default_provider()
60
+ .install_default()
61
+ .ok();
59
62
 
60
63
  let itsi = ruby.get_inner(&ITSI_MODULE);
61
64
  itsi.define_singleton_method("log_debug", function!(log_debug, 1))?;
@@ -1,4 +1,7 @@
1
- use super::{bind_protocol::BindProtocol, tls::configure_tls};
1
+ use super::{
2
+ bind_protocol::BindProtocol,
3
+ tls::{configure_tls, ItsiTlsAcceptor},
4
+ };
2
5
  use itsi_error::ItsiError;
3
6
  use std::{
4
7
  collections::HashMap,
@@ -6,8 +9,6 @@ use std::{
6
9
  path::PathBuf,
7
10
  str::FromStr,
8
11
  };
9
- use tokio_rustls::rustls::ServerConfig;
10
-
11
12
  #[derive(Debug, Clone)]
12
13
  pub enum BindAddress {
13
14
  Ip(IpAddr),
@@ -26,7 +27,7 @@ pub struct Bind {
26
27
  pub address: BindAddress,
27
28
  pub port: Option<u16>, // None for Unix Sockets
28
29
  pub protocol: BindProtocol,
29
- pub tls_config: Option<ServerConfig>,
30
+ pub tls_config: Option<ItsiTlsAcceptor>,
30
31
  }
31
32
 
32
33
  impl std::fmt::Debug for Bind {
@@ -1,7 +1,8 @@
1
1
  use super::bind::{Bind, BindAddress};
2
2
  use super::bind_protocol::BindProtocol;
3
3
  use super::io_stream::IoStream;
4
- use itsi_error::Result;
4
+ use super::tls::ItsiTlsAcceptor;
5
+ use itsi_error::{ItsiError, Result};
5
6
  use itsi_tracing::info;
6
7
  use socket2::{Domain, Protocol, Socket, Type};
7
8
  use std::net::{IpAddr, SocketAddr, TcpListener};
@@ -11,12 +12,14 @@ use tokio::net::TcpListener as TokioTcpListener;
11
12
  use tokio::net::UnixListener as TokioUnixListener;
12
13
  use tokio::net::{unix, TcpStream, UnixStream};
13
14
  use tokio_rustls::TlsAcceptor;
15
+ use tokio_stream::StreamExt;
16
+ use tracing::error;
14
17
 
15
18
  pub(crate) enum Listener {
16
19
  Tcp(TcpListener),
17
- TcpTls((TcpListener, TlsAcceptor)),
20
+ TcpTls((TcpListener, ItsiTlsAcceptor)),
18
21
  Unix(UnixListener),
19
- UnixTls((UnixListener, TlsAcceptor)),
22
+ UnixTls((UnixListener, ItsiTlsAcceptor)),
20
23
  }
21
24
 
22
25
  pub(crate) enum TokioListener {
@@ -27,7 +30,7 @@ pub(crate) enum TokioListener {
27
30
  },
28
31
  TcpTls {
29
32
  listener: TokioTcpListener,
30
- acceptor: TlsAcceptor,
33
+ acceptor: ItsiTlsAcceptor,
31
34
  host: String,
32
35
  port: u16,
33
36
  },
@@ -36,7 +39,7 @@ pub(crate) enum TokioListener {
36
39
  },
37
40
  UnixTls {
38
41
  listener: TokioUnixListener,
39
- acceptor: TlsAcceptor,
42
+ acceptor: ItsiTlsAcceptor,
40
43
  },
41
44
  }
42
45
 
@@ -67,9 +70,49 @@ impl TokioListener {
67
70
  Self::to_tokio_io(Stream::TcpStream(tcp_stream), None).await
68
71
  }
69
72
 
70
- async fn accept_tls(listener: &TokioTcpListener, acceptor: &TlsAcceptor) -> Result<IoStream> {
73
+ pub async fn spawn_state_task(&self) {
74
+ if let TokioListener::TcpTls {
75
+ acceptor: ItsiTlsAcceptor::Automatic(_acme_acceptor, state, _server_config),
76
+ ..
77
+ } = self
78
+ {
79
+ let mut state = state.lock().await;
80
+ loop {
81
+ match StreamExt::next(&mut *state).await {
82
+ Some(event) => info!("Received acme event: {:?}", event),
83
+ None => error!("Received no acme event"),
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ async fn accept_tls(
90
+ listener: &TokioTcpListener,
91
+ acceptor: &ItsiTlsAcceptor,
92
+ ) -> Result<IoStream> {
71
93
  let tcp_stream = listener.accept().await?;
72
- Self::to_tokio_io(Stream::TcpStream(tcp_stream), Some(acceptor)).await
94
+ match acceptor {
95
+ ItsiTlsAcceptor::Manual(tls_acceptor) => {
96
+ Self::to_tokio_io(Stream::TcpStream(tcp_stream), Some(tls_acceptor)).await
97
+ }
98
+ ItsiTlsAcceptor::Automatic(acme_acceptor, _, rustls_config) => {
99
+ let accept_future = acme_acceptor.accept(tcp_stream.0);
100
+ match accept_future.await {
101
+ Ok(None) => Err(ItsiError::Pass()),
102
+ Ok(Some(start_handshake)) => {
103
+ let tls_stream = start_handshake.into_stream(rustls_config.clone()).await?;
104
+ Ok(IoStream::TcpTls {
105
+ stream: tls_stream,
106
+ addr: SockAddr::Tcp(Arc::new(tcp_stream.1)),
107
+ })
108
+ }
109
+ Err(error) => {
110
+ error!(error = format!("{:?}", error));
111
+ Err(ItsiError::Pass())
112
+ }
113
+ }
114
+ }
115
+ }
73
116
  }
74
117
 
75
118
  async fn accept_unix(listener: &TokioUnixListener) -> Result<IoStream> {
@@ -79,10 +122,20 @@ impl TokioListener {
79
122
 
80
123
  async fn accept_unix_tls(
81
124
  listener: &TokioUnixListener,
82
- acceptor: &TlsAcceptor,
125
+ acceptor: &ItsiTlsAcceptor,
83
126
  ) -> Result<IoStream> {
84
127
  let unix_stream = listener.accept().await?;
85
- Self::to_tokio_io(Stream::UnixStream(unix_stream), Some(acceptor)).await
128
+ match acceptor {
129
+ ItsiTlsAcceptor::Manual(tls_acceptor) => {
130
+ Self::to_tokio_io(Stream::UnixStream(unix_stream), Some(tls_acceptor)).await
131
+ }
132
+ ItsiTlsAcceptor::Automatic(_, _, _) => {
133
+ error!("Automatic TLS not supported on Unix sockets");
134
+ Err(ItsiError::UnsupportedProtocol(
135
+ "Automatic TLS on Unix Sockets".to_owned(),
136
+ ))
137
+ }
138
+ }
86
139
  }
87
140
 
88
141
  async fn to_tokio_io(
@@ -229,16 +282,12 @@ impl TryFrom<Bind> for Listener {
229
282
  BindProtocol::Http => Listener::Tcp(connect_tcp_socket(addr, bind.port.unwrap())?),
230
283
  BindProtocol::Https => {
231
284
  let tcp_listener = connect_tcp_socket(addr, bind.port.unwrap())?;
232
- let tls_acceptor = TlsAcceptor::from(Arc::new(bind.tls_config.unwrap()));
233
- Listener::TcpTls((tcp_listener, tls_acceptor))
285
+ Listener::TcpTls((tcp_listener, bind.tls_config.unwrap()))
234
286
  }
235
287
  _ => unreachable!(),
236
288
  },
237
289
  BindAddress::UnixSocket(path) => match bind.tls_config {
238
- Some(tls_config) => {
239
- let tls_acceptor = TlsAcceptor::from(Arc::new(tls_config));
240
- Listener::UnixTls((connect_unix_socket(&path)?, tls_acceptor))
241
- }
290
+ Some(tls_config) => Listener::UnixTls((connect_unix_socket(&path)?, tls_config)),
242
291
  None => Listener::Unix(connect_unix_socket(&path)?),
243
292
  },
244
293
  };
@@ -253,9 +302,11 @@ fn connect_tcp_socket(addr: IpAddr, port: u16) -> Result<TcpListener> {
253
302
  };
254
303
  let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
255
304
  let socket_address: SocketAddr = SocketAddr::new(addr, port);
305
+ socket.set_reuse_port(true).ok();
306
+ socket.set_reuse_address(true).ok();
256
307
  socket.set_nonblocking(true).ok();
257
308
  socket.set_nodelay(true).ok();
258
- socket.set_recv_buffer_size(1_048_576).ok();
309
+ socket.set_recv_buffer_size(262_144).ok();
259
310
  socket.bind(&socket_address.into())?;
260
311
  socket.listen(1024)?;
261
312
  Ok(socket.into())
@@ -265,6 +316,7 @@ fn connect_unix_socket(path: &PathBuf) -> Result<UnixListener> {
265
316
  let _ = std::fs::remove_file(path);
266
317
  let socket = Socket::new(Domain::UNIX, Type::STREAM, None)?;
267
318
  socket.set_nonblocking(true).ok();
319
+
268
320
  let socket_address = socket2::SockAddr::unix(path)?;
269
321
 
270
322
  info!("Binding to {:?}", path);
@@ -95,6 +95,12 @@ impl SingleMode {
95
95
  let self_ref = self_ref.clone();
96
96
  let listener = listener.clone();
97
97
  let (shutdown_sender, mut shutdown_receiver) = tokio::sync::watch::channel::<RunningPhase>(RunningPhase::Running);
98
+ let listener_clone = listener.clone();
99
+
100
+ tokio::spawn(async move {
101
+ listener_clone.spawn_state_task().await;
102
+ });
103
+
98
104
  listener_task_set.spawn(async move {
99
105
  let strategy = self_ref.clone();
100
106
  loop {
@@ -0,0 +1,94 @@
1
+ use async_trait::async_trait;
2
+ use fs2::FileExt; // for lock_exclusive, unlock
3
+ use std::fs::OpenOptions;
4
+ use std::io::Error as IoError;
5
+ use std::path::{Path, PathBuf};
6
+ use tokio_rustls_acme::caches::DirCache;
7
+ use tokio_rustls_acme::{AccountCache, CertCache};
8
+
9
+ /// A wrapper around DirCache that locks a file before writing cert/account data.
10
+ pub struct LockedDirCache<P: AsRef<Path> + Send + Sync> {
11
+ inner: DirCache<P>,
12
+ lock_path: PathBuf,
13
+ }
14
+
15
+ impl<P: AsRef<Path> + Send + Sync> LockedDirCache<P> {
16
+ pub fn new(dir: P) -> Self {
17
+ let dir_path = dir.as_ref().to_path_buf();
18
+ let lock_path = dir_path.join(".acme.lock");
19
+ Self {
20
+ inner: DirCache::new(dir),
21
+ lock_path,
22
+ }
23
+ }
24
+
25
+ fn lock_exclusive(&self) -> Result<std::fs::File, IoError> {
26
+ let lockfile = OpenOptions::new()
27
+ .write(true)
28
+ .truncate(true)
29
+ .open(&self.lock_path)?;
30
+ lockfile.lock_exclusive()?;
31
+ Ok(lockfile)
32
+ }
33
+ }
34
+
35
+ #[async_trait]
36
+ impl<P: AsRef<Path> + Send + Sync> CertCache for LockedDirCache<P> {
37
+ type EC = IoError;
38
+
39
+ async fn load_cert(
40
+ &self,
41
+ domains: &[String],
42
+ directory_url: &str,
43
+ ) -> Result<Option<Vec<u8>>, Self::EC> {
44
+ // Just delegate to the inner DirCache
45
+ self.inner.load_cert(domains, directory_url).await
46
+ }
47
+
48
+ async fn store_cert(
49
+ &self,
50
+ domains: &[String],
51
+ directory_url: &str,
52
+ cert: &[u8],
53
+ ) -> Result<(), Self::EC> {
54
+ // Acquire the lock before storing
55
+ let lockfile = self.lock_exclusive()?;
56
+
57
+ // Perform the store operation
58
+ let result = self.inner.store_cert(domains, directory_url, cert).await;
59
+
60
+ // Unlock and return
61
+ let _ = fs2::FileExt::unlock(&lockfile);
62
+ result
63
+ }
64
+ }
65
+
66
+ #[async_trait]
67
+ impl<P: AsRef<Path> + Send + Sync> AccountCache for LockedDirCache<P> {
68
+ type EA = IoError;
69
+
70
+ async fn load_account(
71
+ &self,
72
+ contact: &[String],
73
+ directory_url: &str,
74
+ ) -> Result<Option<Vec<u8>>, Self::EA> {
75
+ self.inner.load_account(contact, directory_url).await
76
+ }
77
+
78
+ async fn store_account(
79
+ &self,
80
+ contact: &[String],
81
+ directory_url: &str,
82
+ account: &[u8],
83
+ ) -> Result<(), Self::EA> {
84
+ let lockfile = self.lock_exclusive()?;
85
+
86
+ let result = self
87
+ .inner
88
+ .store_account(contact, directory_url, account)
89
+ .await;
90
+
91
+ let _ = fs2::FileExt::unlock(&lockfile);
92
+ result
93
+ }
94
+ }
@@ -1,21 +1,70 @@
1
1
  use base64::{engine::general_purpose, Engine as _};
2
2
  use itsi_error::Result;
3
- use itsi_tracing::{info, warn};
3
+ use itsi_tracing::info;
4
+ use locked_dir_cache::LockedDirCache;
4
5
  use rcgen::{CertificateParams, DnType, KeyPair, SanType};
6
+ use rustls::pki_types::{CertificateDer, PrivateKeyDer};
5
7
  use rustls_pemfile::{certs, pkcs8_private_keys};
6
- use std::{collections::HashMap, fs, io::BufReader};
7
- use tokio_rustls::rustls::{Certificate, PrivateKey, ServerConfig};
8
-
8
+ use std::{
9
+ collections::HashMap,
10
+ env, fs,
11
+ io::{BufReader, Error},
12
+ sync::Arc,
13
+ };
14
+ use tokio::sync::Mutex;
15
+ use tokio_rustls::{rustls::ServerConfig, TlsAcceptor};
16
+ use tokio_rustls_acme::{AcmeAcceptor, AcmeConfig, AcmeState};
17
+ mod locked_dir_cache;
9
18
  const ITS_CA_CERT: &str = include_str!("./itsi_ca/itsi_ca.crt");
10
19
  const ITS_CA_KEY: &str = include_str!("./itsi_ca/itsi_ca.key");
11
20
 
21
+ #[derive(Clone)]
22
+ pub enum ItsiTlsAcceptor {
23
+ Manual(TlsAcceptor),
24
+ Automatic(
25
+ AcmeAcceptor,
26
+ Arc<Mutex<AcmeState<Error>>>,
27
+ Arc<ServerConfig>,
28
+ ),
29
+ }
30
+
12
31
  // Generates a TLS configuration based on either :
13
32
  // * Input "cert" and "key" options (either paths or Base64-encoded strings) or
14
33
  // * Performs automatic certificate generation/retrieval. Generated certs use an internal self-signed Isti CA.
15
34
  // If a non-local host or optional domain parameter is provided,
16
35
  // an automated certificate will attempt to be fetched using let's encrypt.
17
- pub fn configure_tls(host: &str, query_params: &HashMap<String, String>) -> Result<ServerConfig> {
18
- info!("TLS Options {:?}", query_params);
36
+ pub fn configure_tls(
37
+ host: &str,
38
+ query_params: &HashMap<String, String>,
39
+ ) -> Result<ItsiTlsAcceptor> {
40
+ let domains = query_params
41
+ .get("domains")
42
+ .map(|v| v.split(',').map(String::from).collect::<Vec<_>>());
43
+
44
+ if query_params.get("cert").is_none() || query_params.get("key").is_none() {
45
+ if let Some(domains) = domains {
46
+ let directory_url = env::var("ACME_DIRECTORY_URL")
47
+ .unwrap_or_else(|_| "https://acme-v02.api.letsencrypt.org/directory".to_string());
48
+ info!(
49
+ domains = format!("{:?}", domains),
50
+ directory_url, "Requesting acme cert"
51
+ );
52
+ let acme_state = AcmeConfig::new(domains)
53
+ .contact(["mailto:wc@pico.net.nz"])
54
+ .cache(LockedDirCache::new("./rustls_acme_cache"))
55
+ .directory(directory_url)
56
+ .state();
57
+ let rustls_config = ServerConfig::builder()
58
+ .with_no_client_auth()
59
+ .with_cert_resolver(acme_state.resolver());
60
+ let acceptor = acme_state.acceptor();
61
+ return Ok(ItsiTlsAcceptor::Automatic(
62
+ acceptor,
63
+ Arc::new(Mutex::new(acme_state)),
64
+ Arc::new(rustls_config),
65
+ ));
66
+ }
67
+ }
19
68
  let (certs, key) = if let (Some(cert_path), Some(key_path)) =
20
69
  (query_params.get("cert"), query_params.get("key"))
21
70
  {
@@ -24,36 +73,19 @@ pub fn configure_tls(host: &str, query_params: &HashMap<String, String>) -> Resu
24
73
  let key = load_private_key(key_path);
25
74
  (certs, key)
26
75
  } else {
27
- let domains_param = query_params
28
- .get("domains")
29
- .map(|v| v.split(',').map(String::from).collect());
30
- let host_string = host.to_string();
31
- let domains = domains_param.or_else(|| {
32
- if host_string != "localhost" {
33
- Some(vec![host_string])
34
- } else {
35
- None
36
- }
37
- });
38
-
39
- if let Some(domains) = domains {
40
- retrieve_acme_cert(domains)?
41
- } else {
42
- generate_ca_signed_cert(vec![host.to_owned()])?
43
- }
76
+ generate_ca_signed_cert(vec![host.to_owned()])?
44
77
  };
45
78
 
46
79
  let mut config = ServerConfig::builder()
47
- .with_safe_defaults()
48
80
  .with_no_client_auth()
49
81
  .with_single_cert(certs, key)
50
82
  .expect("Failed to build TLS config");
51
83
 
52
84
  config.alpn_protocols = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
53
- Ok(config)
85
+ Ok(ItsiTlsAcceptor::Manual(TlsAcceptor::from(Arc::new(config))))
54
86
  }
55
87
 
56
- pub fn load_certs(path: &str) -> Vec<Certificate> {
88
+ pub fn load_certs(path: &str) -> Vec<CertificateDer<'static>> {
57
89
  let data = if let Some(stripped) = path.strip_prefix("base64:") {
58
90
  general_purpose::STANDARD
59
91
  .decode(stripped)
@@ -71,14 +103,20 @@ pub fn load_certs(path: &str) -> Vec<Certificate> {
71
103
  })
72
104
  .collect::<Result<_>>()
73
105
  .expect("Failed to parse certificate file");
74
- certs_der.into_iter().map(Certificate).collect()
106
+ certs_der
107
+ .into_iter()
108
+ .map(|vec| {
109
+ // Convert the owned Vec<u8> into a CertificateDer and force 'static.
110
+ unsafe { std::mem::transmute(CertificateDer::from(vec)) }
111
+ })
112
+ .collect()
75
113
  } else {
76
- vec![Certificate(data)]
114
+ vec![CertificateDer::from(data)]
77
115
  }
78
116
  }
79
117
 
80
118
  /// Loads a private key from a file or Base64.
81
- pub fn load_private_key(path: &str) -> PrivateKey {
119
+ pub fn load_private_key(path: &str) -> PrivateKeyDer<'static> {
82
120
  let key_data = if let Some(stripped) = path.strip_prefix("base64:") {
83
121
  general_purpose::STANDARD
84
122
  .decode(stripped)
@@ -97,13 +135,15 @@ pub fn load_private_key(path: &str) -> PrivateKey {
97
135
  .collect::<Result<_>>()
98
136
  .expect("Failed to parse private key");
99
137
  if !keys.is_empty() {
100
- return PrivateKey(keys[0].clone());
138
+ return PrivateKeyDer::try_from(keys[0].clone()).unwrap();
101
139
  }
102
140
  }
103
- PrivateKey(key_data)
141
+ PrivateKeyDer::try_from(key_data).unwrap()
104
142
  }
105
143
 
106
- pub fn generate_ca_signed_cert(domains: Vec<String>) -> Result<(Vec<Certificate>, PrivateKey)> {
144
+ pub fn generate_ca_signed_cert(
145
+ domains: Vec<String>,
146
+ ) -> Result<(Vec<CertificateDer<'static>>, PrivateKeyDer<'static>)> {
107
147
  info!("Generating New Itsi CA - Self signed Certificate. Use `itsi ca export` to export the CA certificate for import into your local trust store.");
108
148
 
109
149
  let ca_kp = KeyPair::from_pem(ITS_CA_KEY).expect("Failed to load embedded CA key");
@@ -140,13 +180,10 @@ pub fn generate_ca_signed_cert(domains: Vec<String>) -> Result<(Vec<Certificate>
140
180
 
141
181
  let ee_cert = ee_params.signed_by(&ee_key, &ca_cert, &ca_kp).unwrap();
142
182
  let ee_cert_der = ee_cert.der().to_vec();
143
- let ee_cert = Certificate(ee_cert_der);
144
- let ca_cert = Certificate(ca_cert.der().to_vec());
145
- Ok((vec![ee_cert, ca_cert], PrivateKey(ee_key.serialize_der())))
146
- }
147
-
148
- /// TODO: Retrieves an ACME certificate for a given domain.
149
- pub fn retrieve_acme_cert(domains: Vec<String>) -> Result<(Vec<Certificate>, PrivateKey)> {
150
- warn!("Retrieving ACME cert for {}", domains.join(", "));
151
- generate_ca_signed_cert(domains)
183
+ let ee_cert = CertificateDer::from(ee_cert_der);
184
+ let ca_cert = CertificateDer::from(ca_cert.der().to_vec());
185
+ Ok((
186
+ vec![ee_cert, ca_cert],
187
+ PrivateKeyDer::try_from(ee_key.serialize_der()).unwrap(),
188
+ ))
152
189
  }
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Itsi
4
4
  class Server
5
- VERSION = "0.1.3"
5
+ VERSION = "0.1.5"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itsi-server
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wouter Coppieters
@@ -96,6 +96,7 @@ files:
96
96
  - ext/itsi_server/src/server/signal.rs
97
97
  - ext/itsi_server/src/server/thread_worker.rs
98
98
  - ext/itsi_server/src/server/tls.rs
99
+ - ext/itsi_server/src/server/tls/locked_dir_cache.rs
99
100
  - ext/itsi_tracing/Cargo.lock
100
101
  - ext/itsi_tracing/Cargo.toml
101
102
  - ext/itsi_tracing/src/lib.rs