agate

Simple gemini server for static files
git clone https://github.com/mbrubeck/agate.git
Log | Files | Refs | README

commit 2213b055dcf3978da3f8f81d7ec500611be23bf8
parent d24db6358305b1594b5081eb08cbc6da417a7cfa
Author: Johann150 <johann.galle@protonmail.com>
Date:   Sat, 27 Mar 2021 00:52:50 +0100

add automatic certificate generation

Diffstat:
MCargo.lock | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
MCargo.toml | 1+
Msrc/certificates.rs | 55+++++++++++++++++++++++--------------------------------
Msrc/main.rs | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Atests/data/.certificates/cert.der | 0
Dtests/data/.certificates/cert.pem | 29-----------------------------
Atests/data/.certificates/key.der | 0
Dtests/data/.certificates/key.rsa | 52----------------------------------------------------
Atests/data/cert_missing/key.der | 0
Dtests/data/cert_missing/key.rsa | 52----------------------------------------------------
Atests/data/key_missing/cert.der | 0
Dtests/data/key_missing/cert.pem | 29-----------------------------
Mtests/data/multicert/create_certs.sh | 8++++----
Atests/data/multicert/example.com/cert.der | 0
Dtests/data/multicert/example.com/cert.pem | 28----------------------------
Atests/data/multicert/example.com/key.der | 0
Dtests/data/multicert/example.com/key.rsa | 52----------------------------------------------------
Atests/data/multicert/example.org/cert.der | 0
Dtests/data/multicert/example.org/cert.pem | 28----------------------------
Atests/data/multicert/example.org/key.der | 0
Dtests/data/multicert/example.org/key.rsa | 52----------------------------------------------------
Mtests/tests.rs | 123++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
22 files changed, 251 insertions(+), 422 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -14,6 +14,7 @@ dependencies = [ "mime_guess", "once_cell", "percent-encoding", + "rcgen", "rustls", "tokio", "tokio-rustls", @@ -23,9 +24,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.39" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] name = "atty" @@ -75,6 +76,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] name = "configparser" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -251,6 +262,25 @@ dependencies = [ ] [[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -267,6 +297,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] +name = "pem" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb" +dependencies = [ + "base64", + "once_cell", + "regex", +] + +[[package]] name = "percent-encoding" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -297,6 +338,33 @@ dependencies = [ ] [[package]] +name = "rcgen" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cb7a2dc0e5307189b6933a61290ff06b65b35bdcaae2b2c50a0c3e355cb118e" +dependencies = [ + "chrono", + "pem", + "ring", + "yasna", +] + +[[package]] +name = "regex" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" + +[[package]] name = "ring" version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -342,9 +410,9 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "syn" -version = "1.0.64" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663" dependencies = [ "proc-macro2", "quote", @@ -619,3 +687,12 @@ dependencies = [ "ring", "untrusted", ] + +[[package]] +name = "yasna" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de7bff972b4f2a06c85f6d8454b09df153af7e3a4ec2aac81db1b105b684ddb" +dependencies = [ + "chrono", +] diff --git a/Cargo.toml b/Cargo.toml @@ -20,6 +20,7 @@ log = "0.4" mime_guess = "2.0" once_cell = "1.5" percent-encoding = "2.1" +rcgen = { version = "0.8.9", features = ["pem"] } rustls = "0.19.0" tokio-rustls = "0.22.0" tokio = { version = "1.2", features = ["fs", "io-util", "net", "rt-multi-thread", "sync"] } diff --git a/src/certificates.rs b/src/certificates.rs @@ -1,14 +1,11 @@ use { rustls::{ - internal::pemfile::{certs, pkcs8_private_keys}, - sign::{CertifiedKey, RSASigningKey}, + sign::{any_supported_type, CertifiedKey}, ResolvesServerCert, }, std::{ ffi::OsStr, fmt::{Display, Formatter}, - fs::File, - io::BufReader, path::Path, sync::Arc, }, @@ -23,17 +20,17 @@ pub(crate) struct CertStore { certs: Vec<(String, CertifiedKey)>, } -static CERT_FILE_NAME: &str = "cert.pem"; -static KEY_FILE_NAME: &str = "key.rsa"; +pub static CERT_FILE_NAME: &str = "cert.der"; +pub static KEY_FILE_NAME: &str = "key.der"; #[derive(Debug)] pub enum CertLoadError { /// could not access the certificate root directory NoReadCertDir, + /// no certificates or keys were found + Empty, /// the specified domain name cannot be processed correctly BadDomain(String), - /// The key file for the given domain does not contain any suitable keys. - NoKeys(String), /// the key file for the specified domain is bad (e.g. does not contain a /// key or is invalid) BadKey(String), @@ -55,17 +52,13 @@ impl Display for CertLoadError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { Self::NoReadCertDir => write!(f, "Could not read from certificate directory."), + Self::Empty => write!(f, "No keys or certificates were found in the given directory.\nSpecify the --hostname option to generate these automatically."), Self::BadDomain(domain) if !domain.is_ascii() => write!( f, "The domain name {} cannot be processed, it must be punycoded.", domain ), Self::BadDomain(domain) => write!(f, "The domain name {} cannot be processed.", domain), - Self::NoKeys(domain) => write!( - f, - "The key file for {} does not contain any suitable key.", - domain - ), Self::BadKey(domain) => write!(f, "The key file for {} is malformed.", domain), Self::BadCert(domain, e) => { write!(f, "The certificate file for {} is malformed: {}", domain, e) @@ -97,29 +90,25 @@ fn load_domain(certs_dir: &Path, domain: String) -> Result<CertifiedKey, CertLoa CertLoadError::MissingCert(domain) }); } - - let cert_chain = match certs(&mut BufReader::new(File::open(&path).unwrap())) { - Ok(cert) => cert, - Err(()) => return Err(CertLoadError::BadCert(domain, String::new())), - }; + let cert = rustls::Certificate( + std::fs::read(&path).map_err(|_| CertLoadError::MissingCert(domain.clone()))?, + ); // load key from file path.set_file_name(KEY_FILE_NAME); if !path.is_file() { return Err(CertLoadError::MissingKey(domain)); } - let key = match pkcs8_private_keys(&mut BufReader::new(File::open(&path).unwrap())) { - Ok(mut keys) if !keys.is_empty() => keys.remove(0), - Ok(_) => return Err(CertLoadError::NoKeys(domain)), - Err(()) => return Err(CertLoadError::BadKey(domain)), - }; + let key = rustls::PrivateKey( + std::fs::read(&path).map_err(|_| CertLoadError::MissingKey(domain.clone()))?, + ); // transform key to correct format - let key = match RSASigningKey::new(&key) { + let key = match any_supported_type(&key) { Ok(key) => key, Err(()) => return Err(CertLoadError::BadKey(domain)), }; - Ok(CertifiedKey::new(cert_chain, Arc::new(Box::new(key)))) + Ok(CertifiedKey::new(vec![cert], Arc::new(key))) } impl CertStore { @@ -135,14 +124,12 @@ impl CertStore { let mut certs = vec![]; // Try to load fallback certificate and key directly from the top level - // certificate directory. It will be loaded as the `.` domain. - match load_domain(certs_dir, ".".to_string()) { + // certificate directory. + match load_domain(certs_dir, String::new()) { Err(CertLoadError::EmptyDomain(_)) => { /* there are no fallback keys */ } - Err(CertLoadError::NoReadCertDir) => unreachable!(), - Err(CertLoadError::BadDomain(_)) => unreachable!(), - Err(CertLoadError::NoKeys(_)) => { - return Err(CertLoadError::NoKeys("fallback".to_string())) - } + Err(CertLoadError::Empty) + | Err(CertLoadError::NoReadCertDir) + | Err(CertLoadError::BadDomain(_)) => unreachable!(), Err(CertLoadError::BadKey(_)) => { return Err(CertLoadError::BadKey("fallback".to_string())) } @@ -188,6 +175,10 @@ impl CertStore { certs.push((filename, key)); } + if certs.is_empty() { + return Err(CertLoadError::Empty); + } + certs.sort_unstable_by(|(a, _), (b, _)| { // Try to match as many domain segments as possible. If one is a // substring of the other, the `zip` will only compare the smaller diff --git a/src/main.rs b/src/main.rs @@ -7,12 +7,15 @@ use metadata::{FileOptions, PresetMeta}; use { once_cell::sync::Lazy, percent_encoding::{percent_decode_str, percent_encode, AsciiSet, CONTROLS}, + rcgen::{Certificate, CertificateParams, DnType}, rustls::{NoClientAuth, ServerConfig}, std::{ borrow::Cow, error::Error, ffi::OsStr, fmt::Write, + fs::{self, File}, + io::Write as _, net::SocketAddr, path::{Path, PathBuf}, sync::Arc, @@ -132,20 +135,88 @@ fn args() -> Result<Args> { "central-conf", "Use a central .meta file in the content root directory. Decentral config files will be ignored.", ); + opts.optflag( + "", + "ecdsa", + "Generate keys using the ecdsa signature algorithm instead of the default ed25519.", + ); let matches = opts.parse(&args[1..]).map_err(|f| f.to_string())?; + if matches.opt_present("h") { eprintln!("{}", opts.usage(&format!("Usage: {} [options]", &args[0]))); std::process::exit(0); } + if matches.opt_present("V") { eprintln!("agate {}", env!("CARGO_PKG_VERSION")); std::process::exit(0); } + + let certs_path = check_path(matches.opt_get_default("certs", ".certificates".into())?)?; + let certs = match certificates::CertStore::load_from(&certs_path) { + Ok(certs) => Some(certs), + Err(certificates::CertLoadError::Empty) if matches.opt_present("hostname") => { + // we will generate certificates in the next step + None + } + Err(e) => return Err(e.into()), + }; + + let mut reload_certs = false; let mut hostnames = vec![]; for s in matches.opt_strs("hostname") { - hostnames.push(Host::parse(&s)?); + let hostname = Host::parse(&s)?; + + // check if we have a certificate for that domain + if let Host::Domain(ref domain) = hostname { + if !matches!(certs, Some(ref certs) if certs.has_domain(domain)) { + eprintln!("no certificate or key found for {:?}, generating...", s); + + let mut cert_params = CertificateParams::new(vec![domain.clone()]); + cert_params + .distinguished_name + .push(DnType::CommonName, domain); + + // <CertificateParams as Default>::default() already implements a + // date in the far future from the time of writing: 4096-01-01 + + if !matches.opt_present("ecdsa") { + cert_params.alg = &rcgen::PKCS_ED25519; + } + + // generate the certificate with the configuration + let cert = Certificate::from_params(cert_params)?; + + fs::create_dir(certs_path.join(domain))?; + // write certificate data to disk + let mut cert_file = File::create(certs_path.join(format!( + "{}/{}", + domain, + certificates::CERT_FILE_NAME + )))?; + cert_file.write_all(&cert.serialize_der()?)?; + let mut key_file = File::create(certs_path.join(format!( + "{}/{}", + domain, + certificates::KEY_FILE_NAME + )))?; + key_file.write_all(&cert.serialize_private_key_der())?; + + reload_certs = true; + } + } + + hostnames.push(hostname); } + + // if new certificates were generated, reload the certificate store + let certs = if reload_certs { + certificates::CertStore::load_from(&certs_path)? + } else { + certs.unwrap() + }; + let mut addrs = vec![]; for i in matches.opt_strs("addr") { addrs.push(i.parse()?); @@ -157,14 +228,10 @@ fn args() -> Result<Args> { ]; } - let certs = Arc::new(certificates::CertStore::load_from(&check_path( - matches.opt_get_default("certs", ".certificates".into())?, - )?)?); - Ok(Args { addrs, content_dir: check_path(matches.opt_get_default("content", "content".into())?)?, - certs, + certs: Arc::new(certs), hostnames, language: matches.opt_str("lang"), serve_secret: matches.opt_present("serve-secret"), diff --git a/tests/data/.certificates/cert.der b/tests/data/.certificates/cert.der Binary files differ. diff --git a/tests/data/.certificates/cert.pem b/tests/data/.certificates/cert.pem @@ -1,29 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFCTCCAvGgAwIBAgIUP60wPmdZzVFdc9c1ReFbzcWk9CwwDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMTEwODE0MzE1NloXDTMwMTEw -NjE0MzE1NlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA+3+qGCFlrKMqyCl7uO7QJ+ILZx94swlcxaO1Vo2plau/ -rLFksNTm9EeT5kfovgE8UIXyuwQWZOoxOouaX30t3SUt1qhM2tJw+bkgN+M02LSX -i67AbjqJXWeJs+yQL64RVdM3c13Qow6EBqkOPSViISNtp09GKufKgePW6ptb8fk2 -o1yA7inQicCX7YRf/bF4q5qjOBrDjswDH8W1N5Vn8XVNa1ydLQZWUh/299WZ7jQg -LgIFiJ9RL9qhtl9FlSvN3yeRnny3AX4bk+I666vmleqAB8579QCT7wcGIVatPX71 -b0xZxayCZHNzcWTI4nZI2CO5b4T88F9qztM8NzBC/OvNKVPAiTrFwMnlxg3oqbe9 -Evqep2Ut/n5aKjkgeWDHUI57VoAWJEfPWPKuJhIPnmokf5RRzjqGa3invivnYzD2 -Jna0RMUNfA3CjVpdt/c4/59kKU3Z848uzZLrw2cmX+KZpv9LuCnfUqOnEsmwhoxr -ZaZqb8wuF7nm7aPwO85SXiIIZdppm6N1TIZTOOJ0HpDutZiKs9nZKoBoH+5KkCkr -76P0Y+bvA+DdxZ0V0Jvyar5QskJac3hbpO7xSc9cgNXytwsX7iusbnJTIY6Nr4DQ -sGogRY2/3gJ6zPv27VHykxlyMeJ3nRK5bE7k6rpCUQjrpVXb9GVbFZ1uv9LeIfkC -AwEAAaNTMFEwHQYDVR0OBBYEFI7IjwaA0gwpeZXl5x7Knw8i4STDMB8GA1UdIwQY -MBaAFI7IjwaA0gwpeZXl5x7Knw8i4STDMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI -hvcNAQELBQADggIBANQJ+WuQ8UZsk86t7jTS9K2Igit22ImXhdddDHHbBrbdLXoN -g4IXij8mEJqfPyqZhT49S23booihvJOyhT/RgRB6LI/hBuV1vTwARmIRU4WhZAh0 -xIwVCqniDp6Rgf6OEOYgLGk11CEv7vMfPZYbLddDY1HvmSl8l087CLEQ37WRb51M -5Quhsrny441s6aTn8I7c9WY2H/CUmlF8byoLuIl2MpR5bQN17binfsJZPYkKaMyJ -5URM0nCVUEr+o/1znYsQJYa+GSVEsJJ6OyS7TMSoFJlVFslOxbdPzNkdcL6jxpXN -B0rCrC1gTaQynxTOoQ56N8Z74V9xoXNd0ZwaSgEWfeM++YOyk3qgfvhobd0F8rTD -8+dvMN7eI+N8P+S+VCnX9YzrQIZyTwEhHK9fXLlcqoiAhpizgGhlGctiZ1MmpzT2 -aqFmLOCKpcQLyofsSLSFbhV2/w8rJbS1kTlrzwQLzaJvtLVy+ZZdQFP49Vj8Lb7n -3Oos/YeNoGhJoTWX7S2nQBChYMsSUA15+IS7RN0b+cJroHESsqCkbp07M20zhztz -fDWdYFh+o4V2lF9ecnqV7MwTvz9WxpchcUfQgENrJ3dgTn35hsZOMM2anwFWrmG+ -KVyFMhWNnZB1E530Nsu9cNHntqc3sFBdJebrFED9gOFErt5Vou8btjIqPm/Y ------END CERTIFICATE----- diff --git a/tests/data/.certificates/key.der b/tests/data/.certificates/key.der Binary files differ. diff --git a/tests/data/.certificates/key.rsa b/tests/data/.certificates/key.rsa @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -tPwNvAOh6tUMmDlbRt+xdpFmU238jA== ------END PRIVATE KEY----- diff --git a/tests/data/cert_missing/key.der b/tests/data/cert_missing/key.der Binary files differ. diff --git a/tests/data/cert_missing/key.rsa b/tests/data/cert_missing/key.rsa @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQD7f6oYIWWsoyrI -KXu47tAn4gtnH3izCVzFo7VWjamVq7+ssWSw1Ob0R5PmR+i+ATxQhfK7BBZk6jE6 -i5pffS3dJS3WqEza0nD5uSA34zTYtJeLrsBuOoldZ4mz7JAvrhFV0zdzXdCjDoQG -qQ49JWIhI22nT0Yq58qB49bqm1vx+TajXIDuKdCJwJfthF/9sXirmqM4GsOOzAMf -xbU3lWfxdU1rXJ0tBlZSH/b31ZnuNCAuAgWIn1Ev2qG2X0WVK83fJ5GefLcBfhuT -4jrrq+aV6oAHznv1AJPvBwYhVq09fvVvTFnFrIJkc3NxZMjidkjYI7lvhPzwX2rO -0zw3MEL8680pU8CJOsXAyeXGDeipt70S+p6nZS3+floqOSB5YMdQjntWgBYkR89Y -8q4mEg+eaiR/lFHOOoZreKe+K+djMPYmdrRExQ18DcKNWl239zj/n2QpTdnzjy7N -kuvDZyZf4pmm/0u4Kd9So6cSybCGjGtlpmpvzC4Xuebto/A7zlJeIghl2mmbo3VM -hlM44nQekO61mIqz2dkqgGgf7kqQKSvvo/Rj5u8D4N3FnRXQm/JqvlCyQlpzeFuk -7vFJz1yA1fK3CxfuK6xuclMhjo2vgNCwaiBFjb/eAnrM+/btUfKTGXIx4nedErls -TuTqukJRCOulVdv0ZVsVnW6/0t4h+QIDAQABAoICAF7c+LvBXSiRI0H8474N1lY0 -3Tg4lr5xeZzS80OCi8T404PAJcrNg5AAr7jcxt1keeulmrkQAaJu88Kxhbke7n3L -2E5vjQ288wA+4/gwq25SMBdwAwWQ7t9cfoRvZrOVZNSKpw/NAzV99C7O9Z/6ydjW -FDZXoI/ufmQgHKDBmRzcc8+KxNcQzqgnDSd6FvsKRgn0ejxfXAQwz7zcRk6A/IQH -SvyEIoUpLsYraGxzFWzUHI8+E/hEn8r9HKI9rXFm5HCX7EVrpVvaxWwymSbr4D4M -Bd7r87WmUiaG77kDiLT5fnpMwk/dkhFxusm6ykshcriUQQ3fi8jfNNpusvfeLGWa -4IcwkWPGd5EWNjM1eqeCfh79FAdJe8sEYf2pAkT8LVNT23J/jsL5dsLy3VFQ6svV -NReDnaWBxw92Xh/zqmo7L7/zGaLKXJPSQYHlnDUuYBOxoKhnzDY7P1XWk3STKDan -1rwSelBb/9Z/KGgeg92YlHrYOspw7JaCaYbzpsi8vCS+ZrTrbQ0UoHUAVKgRkTsG -pgUvlbX+RL1+nweGmjenDYEGn5MsPhoKgJFhJLgqqdo3ZTruEazU9Q5xLZDhWz82 -hxJKm3WFAqIL8Q5Wd22z7+DjS9YLuHYB+o9dSbqR0UOiyvYb+eL8gkvPtlvnE0yC -iWl1SDg25iWmbQz1X7EBAoIBAQD+AImpGYgRhIglB2MSz9LPLEC9lGZX6ZznfS91 -1tc5iPcqqKQ3VBCJWnCNOTh5RXlau0s/+vE6zKytSiWrzgkTBMkd18xPTy6c5O4J -XUCArZHx+GoXooOkSPxcLM1IGElTpHT/4Ua4KrGzMpdI8khHLDfiXeUL9mlgYrho -rLjArOo/1pBURYfNSay+bmTB/CzoS+0EXYc6fCNhNvE8fOkCCdPiwrpUjuZyYzmR -pkU1XVOzgqLEqBadywXfp6NeyRBVWO9OxWcJ63smwWCJz/KcTYhBAG5TH/959O6z -115Q7tst+amhBZLgOvHnYJ1S/dK1fU4PDRAm6dEW7kqeFd11AoIBAQD9ehX2SVdo -RHT69H4ItMpYWiBUtAwOEE5d5RPVrjtFtSh/V1pZ+jjGTyqTL5+885o1A6q2Nkrc -d8kYG5VVaGkjJEibCk6px0TWN2Lt73Q0ixNbBmcjxsjRp4EfHvMR/5IqvSZNuUjy -8j3dFHgeB6/PFY283Z9XbMrcFZeEsL4rljF+/XCX2ZeMIUBU93cbZr80o1LgcwpI -Qw61g6Kfjwm6jJEws3doxcmAGSkbR4PzZyRI8lLlIEWWccRG1k34J7s2eDfk8O6F -awv/pgcyFQQwl3zMXmCDNvdHkHV7EDu0gZc8WEuKBTA9tOfokkQmp4rbvMGqtJJm -OfYFZZR/YU31AoIBAHUulFPiRocmaJUEum1kWbJgjSGpRCoMyel2NJ4d1r9hc/5H -PTOVYeesRL6yhl5Uce8s90N2JzJkWMm9qnF/pWoTzCErfMOeGTgi2bqSPf7flLRY -UcHDpQ326g4wUSiQo8ul1KB0MucmM0Mj9O2fcT78pG+Xt+Lz9JuWD9Oi0714SL3Y -5E8soMFR2xMj5PIlwCYPWTKpX4jY2o2wBk1Mp0bcd9dm1QXLw39ETbvnRIihHMt1 -Wlh137E+h+At+83v3swxMn5Zzfain/c6QapyuE/p6RFr/Hn3Cisel716f7XA7Hdi -diKmaqNuLkn7pbkzBrHaNFf3Q9tgBamZl+0k0z0CggEAAuOgWnVNjL+zAaVFxn2h -DM7CLZT7yjE/Y2yYBEh/HnVJJ+JsAjiK6x+94X2aeYHhURdgm8EUq1ymKyMtWZLe -F+ty9Glyqha+Xx60fvfKwEqRhukUxeCfK1yYaS1mId9i4B/Vzu78uOAv+lQgZl86 -Dsc1HWD9TvbLfSS13GpTUJXerI7g+KofQxah8BX+Ao7yQPxXln1ZMaeqBEGi2eS8 -fKbbhM2W39fZSx9+S3ROObkEPdydO0VZ5bQYQ6JvsxNo298U7AQfA+BLe7d9v4Fj -0dX4MzAkM3qt6N/ppuRxecY8XhC3k7Qpb5qfRhRcuIASYhzNrE9wl7+zYS5eOfF2 -/QKCAQEAyOKjglWIpOul3EIOF2D0O6fkulxLfUya6URok00p3CxFXlFdDXwTzC9R -TNYMVE0WrxnXk1KT7ave4PJRFKMNk/PxbMQbtji9m3mWlZsM2vNNQ9nuWnrfOAha -plI7XBPJ4NNapl/RAFVhu3WVHG4CaYiqWPR3dMBi1/2Uk7EhZjhuJ8/AsJz5v7iO -Nv0ydQX7ZisNwf1eksL7odZjGcm/PNOxdAnFI67DuXo4YvyMjzovhTgm0s4yrecC -OMkrvwvefnzUQKV8m9na8pPG+ZJd518oK8nuk9UMgwsJnCWEVgzVjzRIxv7AElrO -tPwNvAOh6tUMmDlbRt+xdpFmU238jA== ------END PRIVATE KEY----- diff --git a/tests/data/key_missing/cert.der b/tests/data/key_missing/cert.der Binary files differ. diff --git a/tests/data/key_missing/cert.pem b/tests/data/key_missing/cert.pem @@ -1,29 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFCTCCAvGgAwIBAgIUP60wPmdZzVFdc9c1ReFbzcWk9CwwDQYJKoZIhvcNAQEL -BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMTEwODE0MzE1NloXDTMwMTEw -NjE0MzE1NlowFDESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA+3+qGCFlrKMqyCl7uO7QJ+ILZx94swlcxaO1Vo2plau/ -rLFksNTm9EeT5kfovgE8UIXyuwQWZOoxOouaX30t3SUt1qhM2tJw+bkgN+M02LSX -i67AbjqJXWeJs+yQL64RVdM3c13Qow6EBqkOPSViISNtp09GKufKgePW6ptb8fk2 -o1yA7inQicCX7YRf/bF4q5qjOBrDjswDH8W1N5Vn8XVNa1ydLQZWUh/299WZ7jQg -LgIFiJ9RL9qhtl9FlSvN3yeRnny3AX4bk+I666vmleqAB8579QCT7wcGIVatPX71 -b0xZxayCZHNzcWTI4nZI2CO5b4T88F9qztM8NzBC/OvNKVPAiTrFwMnlxg3oqbe9 -Evqep2Ut/n5aKjkgeWDHUI57VoAWJEfPWPKuJhIPnmokf5RRzjqGa3invivnYzD2 -Jna0RMUNfA3CjVpdt/c4/59kKU3Z848uzZLrw2cmX+KZpv9LuCnfUqOnEsmwhoxr -ZaZqb8wuF7nm7aPwO85SXiIIZdppm6N1TIZTOOJ0HpDutZiKs9nZKoBoH+5KkCkr -76P0Y+bvA+DdxZ0V0Jvyar5QskJac3hbpO7xSc9cgNXytwsX7iusbnJTIY6Nr4DQ -sGogRY2/3gJ6zPv27VHykxlyMeJ3nRK5bE7k6rpCUQjrpVXb9GVbFZ1uv9LeIfkC -AwEAAaNTMFEwHQYDVR0OBBYEFI7IjwaA0gwpeZXl5x7Knw8i4STDMB8GA1UdIwQY -MBaAFI7IjwaA0gwpeZXl5x7Knw8i4STDMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI -hvcNAQELBQADggIBANQJ+WuQ8UZsk86t7jTS9K2Igit22ImXhdddDHHbBrbdLXoN -g4IXij8mEJqfPyqZhT49S23booihvJOyhT/RgRB6LI/hBuV1vTwARmIRU4WhZAh0 -xIwVCqniDp6Rgf6OEOYgLGk11CEv7vMfPZYbLddDY1HvmSl8l087CLEQ37WRb51M -5Quhsrny441s6aTn8I7c9WY2H/CUmlF8byoLuIl2MpR5bQN17binfsJZPYkKaMyJ -5URM0nCVUEr+o/1znYsQJYa+GSVEsJJ6OyS7TMSoFJlVFslOxbdPzNkdcL6jxpXN -B0rCrC1gTaQynxTOoQ56N8Z74V9xoXNd0ZwaSgEWfeM++YOyk3qgfvhobd0F8rTD -8+dvMN7eI+N8P+S+VCnX9YzrQIZyTwEhHK9fXLlcqoiAhpizgGhlGctiZ1MmpzT2 -aqFmLOCKpcQLyofsSLSFbhV2/w8rJbS1kTlrzwQLzaJvtLVy+ZZdQFP49Vj8Lb7n -3Oos/YeNoGhJoTWX7S2nQBChYMsSUA15+IS7RN0b+cJroHESsqCkbp07M20zhztz -fDWdYFh+o4V2lF9ecnqV7MwTvz9WxpchcUfQgENrJ3dgTn35hsZOMM2anwFWrmG+ -KVyFMhWNnZB1E530Nsu9cNHntqc3sFBdJebrFED9gOFErt5Vou8btjIqPm/Y ------END CERTIFICATE----- diff --git a/tests/data/multicert/create_certs.sh b/tests/data/multicert/create_certs.sh @@ -5,7 +5,7 @@ mkdir -p example.com example.org for domain in "example.com" "example.org" do # create private key -openssl genpkey -out $domain/key.rsa -algorithm RSA -pkeyopt rsa_keygen_bits:4096 +openssl genpkey -outform DER -out $domain/key.der -algorithm RSA -pkeyopt rsa_keygen_bits:4096 # create config file: # the generated certificates must not be CA-capable, otherwise rustls complains @@ -26,10 +26,10 @@ commonName = $domain subjectAltName = DNS:$domain EOT -openssl req -new -sha256 -out request.csr -key $domain/key.rsa -config openssl.conf +openssl req -new -sha256 -out request.csr -key $domain/key.der -keyform DER -config openssl.conf -openssl x509 -req -sha256 -days 3650 -in request.csr -out $domain/cert.pem \ - -extensions req_ext -extfile openssl.conf -signkey $domain/key.rsa +openssl x509 -req -sha256 -days 3650 -in request.csr -outform DER -out $domain/cert.der \ + -extensions req_ext -extfile openssl.conf -signkey $domain/key.der -keyform DER done # clean up diff --git a/tests/data/multicert/example.com/cert.der b/tests/data/multicert/example.com/cert.der Binary files differ. diff --git a/tests/data/multicert/example.com/cert.pem b/tests/data/multicert/example.com/cert.pem @@ -1,28 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIE1DCCArygAwIBAgIUDZjgSq0hJCJPEjCho3BZxrR0S2AwDQYJKoZIhvcNAQEL -BQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMjEwMzExMjEyMDA5WhcNMzEw -MzA5MjEyMDA5WjAWMRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAKCvZP1hCE3kzcjHrRpmsB22qmz1zq5AyiviJfKA -bL/CoPxiH/t53ZxtKH2SKwF9l3YpMc+pVP0BsgNOXIaQyX0cS5Nq0mgrPnShGQlq -8M/8DzqKaoOYBBxxODaw25BWTq0ljWj0Sz3ksa91ayxK/whfK1rmNzKjyIYzvbdO -j6qIEXYFHyFqzLXOpunj2s+nZKwKxX0GWkM2qB8mwLHOq0JNufYDkzPvyiZPru1N -23SoMiCEGu0uRjvHalg8ehuRito20UeD1HHfy6Gr/S1nzNumRTD0iMpySNMpz/cf -d6/9u/C7pC73qc4hfXerS02ffwEm+ulQEDwZ7QiS8CbSIfkLyG93O1LXr6fhqLPi -505wCia9V2Iq93zlGUBP/zDqaMoISwohKFvrvpYlQG4LI8b0j+To9YOFwSsekPZf -4rfOLIBwPsE8knAycnN7D2GYXeuo3tMh4lPKgV7IoG6CUzRLoZ8pGIZnjVqO0I5R -1w5CU48RqlL+tsYdNSphBBKPLnUro9WOG9UIKo3C0ccij86vLU/9L2gGT//oTIUN -suR9e8eoK8Yos+fef3+vOWgbeK+Isi09Hq70j0vatACtWBE6Z7ROhW2ytiD3LD5g -MN7Yk5mEV6t/y0dhDffIjvBS4tS+idWr2jvt0KgRE2JzV6iMAg7C0fdCYg1WuQer -1GWZAgMBAAGjGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUuY29tMA0GCSqGSIb3DQEB -CwUAA4ICAQAmfm4cDU6SVxzMgInZcwPIW7NTSzly7WzCHhaGYqkgCrEmu+2DEKzq -c8lIe5SBHQCs6y8LRdNAJ9I3dMnXw9x97/lrKwg9+C6xnjqcDYRG3DzGsAz0OF1A -AWboIdnPSnHeicmDK0C4i7/VghJmpozcOF0HCnfo0zDhhyCOAhv7fT3TCk/kDCJd -uQA2EJRwnvrfbuhddFzpdkoZJQeSsPmJvTqQoAap8tKxmrkDo6GZSVRMFelCL5e0 -6nQQQfb5Qo97/lHHXfP9JycYc+AqRzvuc6bZiEJG2FeWJb3QCOTULfAbpksem6WA -tNtJ4Vv/snX0Wcy6zmTxXH0HbFmXM2Xdd2adiZVQU++Ck8jrzxHUtiG08E0VnXvQ -nABixB7aWQkDWCCR3k4QBBsGSPCIQ15d8RsC1HGxTs7zmGE2ic3rWEgzGkpaIvIN -aai5cmRey/mRIauWrG+juOHemSQ4WlLeSnDixcrlQP63WkKf9j4yKgUjbRULT/LO -QjH4n7ckoj3d+CGIvlQN94tn0xM38iya+43ytC0LUFNYd+BjxkFZI5kKaFh6vYmZ -tKjrL496Jd/L3knjIRTPh1L6TpINSYFhMqzXHFJNsRViI/4YtiilJlo5NX18ejMO -mYLcKU4xS9u7rmBpQyIFmwlLCYAh8X1yKAvezLzeGy0x9+iramaOPg== ------END CERTIFICATE----- diff --git a/tests/data/multicert/example.com/key.der b/tests/data/multicert/example.com/key.der Binary files differ. diff --git a/tests/data/multicert/example.com/key.rsa b/tests/data/multicert/example.com/key.rsa @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -q+T6LY6tbtpB+11HBnD4I79WCYf4DA== ------END PRIVATE KEY----- diff --git a/tests/data/multicert/example.org/cert.der b/tests/data/multicert/example.org/cert.der Binary files differ. diff --git a/tests/data/multicert/example.org/cert.pem b/tests/data/multicert/example.org/cert.pem @@ -1,28 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIE1DCCArygAwIBAgIUVpgbY7cDU3z0VcZgYV14fgF0qcswDQYJKoZIhvcNAQEL -BQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5vcmcwHhcNMjEwMzExMjEyMDA5WhcNMzEw -MzA5MjEyMDA5WjAWMRQwEgYDVQQDDAtleGFtcGxlLm9yZzCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAK0MOqzesRj6psy6XMcQz72jUCiaKTP/bamWyaDx -AcM0S0McCl0dpXpeID6+i4l/fQKP3OjJIH7pC55mRxjJZVWdhoSdvW/5/dli/uxp -o5pHH6a9ktnvOXHgw8kkbp3DVvu4JpJvuoKd67dll931sO5nVCCTJkNwg+/QhP+R -I43JuZKZVOQpsY7f3sZl6ASJuThgifxlCF0mrsabx+Yk0Ug6SLAIson/OHeGaCiB -Xlj0+kCxFGWsFHOTy55HHJKuGvtadc/MJdGrVCUUHjq3Les8wQXuzQUG+8QJOm2h -tVkWXJRZtumUUHVi+rqWRRBO1yLih5r/Yv8qN5Ba+c4AQcT0uDyKd3ar6SjRgWDU -ZoJbA0Ar4ydGlkQu9KZVY2Z20Hx+R+xKmzz6BwnKS3X8BnOYhprwOlZNY6qCpygq -wiDtMJfI210kDeXSuURXfWvrrOQRhO4fQzmrg4o7DsF2WOU9kY7fgxY9ObTUTp24 -j2g2p/I5S0JHRpmQhYIXU1UErbb3JqUGrOueUf5fdIu0VWWjXAbGsl4WkzXZGBbS -VkKQ4oArLa7BFbJkC/+z8ttTanIyPI5SKNDGXWRRR5fB/r9t5I6X5Ep0+c+zE4so -Jj7SKv6ygvnKoHckuaBCaNJB4Pq9fv7IFZzf5bo3CGSlJi1NTtAB32I+k2ZGqVBX -Yh3HAgMBAAGjGjAYMBYGA1UdEQQPMA2CC2V4YW1wbGUub3JnMA0GCSqGSIb3DQEB -CwUAA4ICAQBBG6f0T9nQfHV0G0bmTPUVbAVJuYtiDBSBOP/uactOWsmw65GPq1k8 -UAYmqYfm5kWl8tsjNWzt8mfm+mQVVGp0c+OM2ltAQ03GPpZzkZLtHpTiOZ/1mcP3 -D3kInj5jUOp/8k7ZWawsOhJcKP5n8ZQYTjKPvo3lD3lDXQVNyHtO/2IwjFeiiD1F -fx1ZQ2ohLD9f88KkUyYrujzJyCvjyTOF195PrJBLPlho40R+A0AJTm0VBTU3I33l -G+8twaVzcspGKFOwpwuLpFXPby6H1nrmc7/En/nzYniSmCjTU/dOsHVZRHxB0T7t -WjsPrDA6SHtmvic0Avk3dxEKRHyzSwiL57lSeZnqovm06DfbGyL7rb7VIrAvNE5I -eZUforj6QsNUQENb46LqgQkQ/vStGZ7jHFM81PeW/r/J0XmjU/SG2y8op1gT98Qz -jThR5uA2fw2BTIulQq4awQC0K5uXlmMuiliip2MleDp67y9q7z9oxahY/umdw4ki -8I76mZKe+9QipBVPilLWZy9lJyPvZgpr3oZMyHKWUR1D30hVeFpRG5kyvSt115GC -EHXAUbp//AlrWNBLoPLeXoqrZNUfdDiUaQ1wqB7OgUkB1dCzp0XsSTGo6ryDyjd7 -d39ID7e3QFP8zCuFEcmB8AmE09zAGeAZXFMA+xXWV3H7DQIwVSkOwA== ------END CERTIFICATE----- diff --git a/tests/data/multicert/example.org/key.der b/tests/data/multicert/example.org/key.der Binary files differ. diff --git a/tests/data/multicert/example.org/key.rsa b/tests/data/multicert/example.org/key.rsa @@ -1,52 +0,0 @@ ------BEGIN PRIVATE KEY----- -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 -BVksLv0EVzq2MyO+yTR1M8Y+0KBK5dx8 ------END PRIVATE KEY----- diff --git a/tests/tests.rs b/tests/tests.rs @@ -1,11 +1,11 @@ use anyhow::anyhow; use gemini_fetch::{Header, Page, Status}; -use std::io::Read; +use std::io::{BufRead, BufReader, Read}; use std::net::{SocketAddr, ToSocketAddrs}; use std::process::{Command, Stdio}; use url::Url; -static BINARY_PATH: &'static str = env!("CARGO_BIN_EXE_agate"); +static BINARY_PATH: &str = env!("CARGO_BIN_EXE_agate"); fn addr(port: u16) -> SocketAddr { use std::net::{IpAddr, Ipv4Addr}; @@ -19,7 +19,6 @@ fn addr(port: u16) -> SocketAddr { struct Server { server: std::process::Child, - buf: u8, // is set when output is collected by stop() output: Option<Result<(), String>>, } @@ -31,47 +30,67 @@ impl Server { .stderr(Stdio::piped()) .current_dir(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/data")) .args(args) + .env("RUST_LOG", "debug") .spawn() .expect("failed to start binary"); - // the first output is when Agate is listening, so we only have to wait - // until the first byte is output - let mut buffer = [0; 1]; - server - .stderr - .as_mut() - .unwrap() - .read_exact(&mut buffer) - .unwrap(); + // We can be sure that agate is listening because it logs a message saying so. + let mut reader = BufReader::new(server.stderr.as_mut().unwrap()); + let mut buffer = String::new(); + while matches!(reader.read_line(&mut buffer), Ok(i) if i>0) { + print!("log: {}", buffer); + if buffer.contains("Listening") { + break; + } + + buffer.clear(); + } + + if matches!(server.try_wait(), Ok(Some(_)) | Err(_)) { + panic!("Server did not start properly"); + } Self { server, - buf: buffer[0], output: None, } } pub fn stop(&mut self) -> Result<(), String> { // try to stop the server - if let Some(output) = self.output.clone() { - return output; + if let Some(output) = self.output.as_ref() { + return output.clone(); } self.output = Some(match self.server.try_wait() { Err(e) => Err(format!("cannot access orchestrated program: {:?}", e)), - // everything fine, still running as expected, kill it now - Ok(None) => Ok(self.server.kill().unwrap()), + Ok(None) => { + // everything fine, still running as expected, kill it now + self.server.kill().unwrap(); + + let mut reader = BufReader::new(self.server.stderr.as_mut().unwrap()); + let mut buffer = String::new(); + while matches!(reader.read_line(&mut buffer), Ok(i) if i>0) { + print!("log: {}", buffer); + if buffer.contains("Listening") { + break; + } + } + Ok(()) + } Ok(Some(_)) => { - // forward stderr so we have a chance to understand the problem - let buffer = std::iter::once(Ok(self.buf)) - .chain(self.server.stderr.take().unwrap().bytes()) - .collect::<Result<Vec<u8>, _>>() - .unwrap(); - - Err(String::from_utf8_lossy(&buffer).into_owned()) + let mut reader = BufReader::new(self.server.stderr.as_mut().unwrap()); + let mut buffer = String::new(); + while matches!(reader.read_line(&mut buffer), Ok(i) if i>0) { + print!("log: {}", buffer); + if buffer.contains("Listening") { + break; + } + } + Err(buffer) } }); - return self.output.clone().unwrap(); + self.output.clone().unwrap() } } @@ -84,7 +103,7 @@ impl Drop for Server { // server was already stopped } else { // we are panicking and a potential error was not handled - self.stop().unwrap_or_else(|e| eprintln!("{:?}", e)); + self.stop().unwrap_or_else(|e| eprintln!("{}", e)); } } } @@ -395,37 +414,27 @@ mod multicert { use super::*; #[test] + #[should_panic] fn cert_missing() { let mut server = Server::new(&["--addr", "[::]:1979", "--certs", "cert_missing"]); // wait for the server to stop, it should crash let _ = server.server.wait(); - - assert!(server - .stop() - .unwrap_err() - .to_string() - .contains("certificate file for fallback is missing")); } #[test] + #[should_panic] fn key_missing() { let mut server = Server::new(&["--addr", "[::]:1980", "--certs", "key_missing"]); // wait for the server to stop, it should crash let _ = server.server.wait(); - - assert!(server - .stop() - .unwrap_err() - .to_string() - .contains("key file for fallback is missing")); } #[test] fn example_com() { - use rustls::ClientSession; - use std::io::{Cursor, Write}; + use rustls::{Certificate, ClientSession}; + use std::io::Write; use std::net::TcpStream; let mut server = Server::new(&["--addr", "[::]:1981", "--certs", "multicert"]); @@ -433,10 +442,13 @@ mod multicert { let mut config = rustls::ClientConfig::new(); config .root_store - .add_pem_file(&mut Cursor::new(include_bytes!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/tests/data/multicert/example.com/cert.pem" - )))) + .add(&Certificate( + include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/data/multicert/example.com/cert.der" + )) + .to_vec(), + )) .unwrap(); let dns_name = webpki::DNSNameRef::try_from_ascii_str("example.com").unwrap(); @@ -447,15 +459,15 @@ mod multicert { write!(tls, "gemini://example.com/\r\n").unwrap(); let mut buf = [0; 10]; - tls.read(&mut buf).unwrap(); + let _ = tls.read(&mut buf); - server.stop().unwrap() + server.stop().unwrap(); } #[test] fn example_org() { - use rustls::ClientSession; - use std::io::{Cursor, Write}; + use rustls::{Certificate, ClientSession}; + use std::io::Write; use std::net::TcpStream; let mut server = Server::new(&["--addr", "[::]:1982", "--certs", "multicert"]); @@ -463,10 +475,13 @@ mod multicert { let mut config = rustls::ClientConfig::new(); config .root_store - .add_pem_file(&mut Cursor::new(include_bytes!(concat!( - env!("CARGO_MANIFEST_DIR"), - "/tests/data/multicert/example.org/cert.pem" - )))) + .add(&Certificate( + include_bytes!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/tests/data/multicert/example.org/cert.der" + )) + .to_vec(), + )) .unwrap(); let dns_name = webpki::DNSNameRef::try_from_ascii_str("example.org").unwrap(); @@ -477,8 +492,8 @@ mod multicert { write!(tls, "gemini://example.org/\r\n").unwrap(); let mut buf = [0; 10]; - tls.read(&mut buf).unwrap(); + let _ = tls.read(&mut buf); - server.stop().unwrap() + server.stop().unwrap(); } }