commit 2213b055dcf3978da3f8f81d7ec500611be23bf8
parent d24db6358305b1594b5081eb08cbc6da417a7cfa
Author: Johann150 <johann.galle@protonmail.com>
Date: Sat, 27 Mar 2021 00:52:50 +0100
add automatic certificate generation
Diffstat:
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-----
-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
-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-----
-MIIJRAIBADANBgkqhkiG9w0BAQEFAASCCS4wggkqAgEAAoICAQCtDDqs3rEY+qbM
-ulzHEM+9o1Aomikz/22plsmg8QHDNEtDHApdHaV6XiA+vouJf30Cj9zoySB+6Que
-ZkcYyWVVnYaEnb1v+f3ZYv7saaOaRx+mvZLZ7zlx4MPJJG6dw1b7uCaSb7qCneu3
-ZZfd9bDuZ1QgkyZDcIPv0IT/kSONybmSmVTkKbGO397GZegEibk4YIn8ZQhdJq7G
-m8fmJNFIOkiwCLKJ/zh3hmgogV5Y9PpAsRRlrBRzk8ueRxySrhr7WnXPzCXRq1Ql
-FB46ty3rPMEF7s0FBvvECTptobVZFlyUWbbplFB1Yvq6lkUQTtci4oea/2L/KjeQ
-WvnOAEHE9Lg8ind2q+ko0YFg1GaCWwNAK+MnRpZELvSmVWNmdtB8fkfsSps8+gcJ
-ykt1/AZzmIaa8DpWTWOqgqcoKsIg7TCXyNtdJA3l0rlEV31r66zkEYTuH0M5q4OK
-Ow7BdljlPZGO34MWPTm01E6duI9oNqfyOUtCR0aZkIWCF1NVBK229yalBqzrnlH+
-X3SLtFVlo1wGxrJeFpM12RgW0lZCkOKAKy2uwRWyZAv/s/LbU2pyMjyOUijQxl1k
-UUeXwf6/beSOl+RKdPnPsxOLKCY+0ir+soL5yqB3JLmgQmjSQeD6vX7+yBWc3+W6
-NwhkpSYtTU7QAd9iPpNmRqlQV2IdxwIDAQABAoICAAiUL6B8VclIO9awcoMH6VSc
-cQ/iPKKwSg57RDmvWQgFYqnMDRN6scZ0PiL+LUq+wELNQQVlWzAPe5z5sxKegWCS
-M6YFb+vKN/R7/OlZf1vZpM8OXOZi/rUPkIU7QiSeF4TZJ0hhM5zgGVx5M+M0F/Zp
-tvj6co4rWM8dxkopNtsDoiiLY3MAQiY0IQYy7SK0dTM/TffuRlDf5xA/jtRxBNMQ
-2KOperhup6z9Q9KmPzgnxPRKExnLQyRLsm+BVQBMk1fcrzSDCWjwlnZUHf+JL0SX
-OXaC1TUnmHmqf3QJ7USiYCqWnAPOb4KySn3Pj1L0paO8GT7s5EqEHEcSy4mT5664
-F6LsAkkxDY37bAQ4I6guEPb6+JjI+a7BtU82/LIb9tUIF3tLLN810JMRUFu0Pt1Z
-e84AlANH47NNcCjPcoHz8lcVBlNQ4JDi9yxZwwO+brFvwHVmzV7l3wCl/70ucsJy
-gwB1Eysizi41hqMpAtbhGe3nmgJs/S9+KjnjkvkzlqFaX6xaU5nTLpkEF1znsbiw
-FEHKEiIFn0hPPHb24PRm4ktyBoT65qaSB/GewVbvJN/CxPin5C1I9MzvzXv+rFn1
-NMkGJCmL40zwAUkm/1NTO8cvRG85s8ak7Y1IAmo67wUmuuoQQyo71Jef/JcVyk6c
-xuRRdMu5sp8nyyNcYOZZAoIBAQDWmGVqUYWm5sGWUkhRv6ct/ov6rhlEw9/4KJIa
-TkEN0G6rItTjCAHycywSomeeQv5waxdYjpAOOYxm166bvgGa6lkDmttIvyG2bzsX
-F9Xvc4+KbMPMG0Bn5M4IP/FPM+L/hA6r4z7MmU3PIotLSGRT9CMyfQzs228YLgdb
-OfRT3qxWeohWHHv91l62yJjJ2hCay89U/aq3C5oQ7RPuv8tj5V1H86kcRl0Emkly
-LkZLNVf1FykVn80SL0MquXhhsv4GrRedjbMhnWtqUuIohTOVqGe2tfkBu2OYpDuO
-T7eKi0I4Z1bzUOwfjoBsWuyJjhWGt9pGYS912An3r/htZirtAoIBAQDOb6gxTw5N
-1aVSgcdDE0A1/UsqYrICkqstGbJYjvQIj8YMyAGG7AAd5KN/cnNpJMyrNSmUhKAK
-I1OFCsloTa8VbDistxCJIqkK3wJ6/YnlBjQbyTPCbjPJ5Fj/U0AutqCYjRHifyAr
-GxUtSkZM+NxV/ggcKlDaLGiIH1/NmiTXlqFHyoxC4yhB0ZJeBj8az8THP3awgqjV
-idHzcYQBJEWMbn5/ysPlm3NCuQwqXpGvQ8P881P91CtnvmilxgDKt/fOOFA3n/jy
-YNFjmoL/bxA8L9Lc8Zpr1vHs++01V+JFxhLWPpiIAWavkkj0BvkQDzJmvLHI9SmG
-wR/DK9Z+kXEDAoIBAQDHUsw4Qbp7uTCs+IaV8AdP0HSihl2QIsQA02ZJqtAADc8N
-hI/qxMBSO6n/MPw/4whE0SPhLKIfpFKGH+XeYVFKXEwL7iWqX2Xn908SdyBOhq8Y
-K0h+Z/2dwsegoAv6vj4libq665ukHO1J7VMmvPn7hPPAbKi5xGRfODm7AYyw7k5z
-EONb4J9GunxFGPPZ4YO01IQi9G9CEDOtbxgpldpMUnofX/J/AdhacxivRs4iA01M
-qJOPs1uefWnM4HMxhDkxaEtcG4b8PSTNoGjSrE6qvr5+1m2Qr0amPD3ZRLA9rnX2
-v/3iiRKZiRo+CwJUDjZuaI0E/DZCJkWz265Lpy9NAoIBAQCoJu1i1Nl67ycOEOZF
-rb2k/KCocuI7FEtYnlDWsAL5olsZeCU+SKhDsUS4gHqfz7jjUJeBAZL3DxVuDn5G
-dtjB43g6v5c5jUESuNrlYfZb1nTFmVuO6YNH1bfkqmRiaKJiAK7rxs9mLVZPoOuo
-sSGQ7i6e+p0HShsPnjbEW+XcsjbHKqabqTrWeiX2brIiXdEU144Pcy6hWfTpjrKO
-14PLQwnJgFmXgssdM2xEaunSUKmpNm9ZF+UPSVsmhSWJ+tZgZSB6XtVCYTjOIELK
-XCZmUDI7hJVbeCdx+TecNuz6FsCrQSuvxSxmoQrJs5BW03ojk1phrclYmaEMsn2y
-dTgPAoIBAQCRe4y76djA0MY7QCm4HO06ZpZV7g0K1wzUrJdOc7+UAklFNVttTfAJ
-eTk7dVKcxJy8W/jBStuKXuBba76vn7Oas4J316HHz4w9NBgz9Gdbid9sbkDWfsF/
-AjzEtrwKKCydH2bxgJlj0kC3baemSib71HNilVuApLGhdCZAdWkxqkxAmSoMuhjx
-3CX66AKVyMMouk7GnuoUj67Ued5Bha54arDq1RZVWLa8JnGRoUkfzC5ukyYo3LcE
-SC15WJOUEGyqXGUwSrh9t1YLpViG6dARBnLuLjdRIvLVvEtgymvRwzb1fS4/wMH8
-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();
}
}