agate

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

commit 8809f9378cec51a36ec1eaf14727efc62eefbe88
parent b1c7564046d76cb1d8597eb0a044401467183ceb
Author: Matt Brubeck <mbrubeck@limpet.net>
Date:   Mon, 18 Dec 2023 07:56:52 -0800

Update to rustls 0.22

Diffstat:
MCargo.lock | 45+++++++--------------------------------------
MCargo.toml | 2+-
Msrc/certificates.rs | 44++++++++++++++++++++++++++++++++------------
Msrc/main.rs | 8++------
Mtests/tests.rs | 28++++++++++------------------
5 files changed, 52 insertions(+), 75 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ "rcgen", "rustls 0.22.1", "tokio", - "tokio-rustls 0.24.1", + "tokio-rustls 0.25.0", "url", ] @@ -492,24 +492,12 @@ dependencies = [ "base64 0.13.1", "log", "ring 0.16.20", - "sct 0.6.1", + "sct", "webpki", ] [[package]] name = "rustls" -version = "0.21.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" -dependencies = [ - "log", - "ring 0.17.7", - "rustls-webpki 0.101.7", - "sct 0.7.0", -] - -[[package]] -name = "rustls" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe6b63262c9fcac8659abfaa96cac103d28166d3ff3eaf8f412e19f3ae9e5a48" @@ -517,7 +505,7 @@ dependencies = [ "log", "ring 0.17.7", "rustls-pki-types", - "rustls-webpki 0.102.0", + "rustls-webpki", "subtle", "zeroize", ] @@ -530,16 +518,6 @@ checksum = "e7673e0aa20ee4937c6aacfc12bb8341cfbf054cdd21df6bec5fd0629fe9339b" [[package]] name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", -] - -[[package]] -name = "rustls-webpki" version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de2635c8bc2b88d367767c5de8ea1d8db9af3f6219eba28442242d9ab81d1b89" @@ -560,16 +538,6 @@ dependencies = [ ] [[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring 0.16.20", - "untrusted 0.7.1", -] - -[[package]] name = "serde" version = "1.0.192" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -740,11 +708,12 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" dependencies = [ - "rustls 0.21.10", + "rustls 0.22.1", + "rustls-pki-types", "tokio", ] diff --git a/Cargo.toml b/Cargo.toml @@ -23,7 +23,7 @@ once_cell = "1.19" percent-encoding = "2.3" rcgen = { version = "0.12.0" } rustls = "0.22.1" -tokio-rustls = "0.24.1" +tokio-rustls = "0.25.0" tokio = { version = "1.35", features = ["fs", "io-util", "net", "rt-multi-thread", "sync"] } url = "2.5.0" diff --git a/src/certificates.rs b/src/certificates.rs @@ -1,7 +1,9 @@ use { rustls::{ + crypto::ring::sign::any_supported_type, + pki_types::{self, CertificateDer, PrivateKeyDer}, server::{ClientHello, ResolvesServerCert}, - sign::{any_supported_type, CertifiedKey, SignError}, + sign::{CertifiedKey, SigningKey}, }, std::{ ffi::OsStr, @@ -13,6 +15,7 @@ use { /// A struct that holds all loaded certificates and the respective domain /// names. +#[derive(Debug)] pub(crate) struct CertStore { /// Stores the certificates and the domains they apply to, sorted by domain /// names, longest matches first @@ -30,7 +33,7 @@ pub enum CertLoadError { Empty, /// the key file for the specified domain is bad (e.g. does not contain a /// key or is invalid) - BadKey(String, SignError), + BadKey(String, rustls::Error), /// the key file for the specified domain is missing (but a certificate /// file was present) MissingKey(String), @@ -74,27 +77,44 @@ fn load_domain(certs_dir: &Path, domain: String) -> Result<CertifiedKey, CertLoa CertLoadError::MissingCert(domain) }); } - let cert = rustls::Certificate( + let cert = CertificateDer::from( 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() { + let Ok(der) = std::fs::read(&path) else { return Err(CertLoadError::MissingKey(domain)); - } - let key = rustls::PrivateKey( - std::fs::read(&path).map_err(|_| CertLoadError::MissingKey(domain.clone()))?, - ); + }; // transform key to correct format - let key = match any_supported_type(&key) { - Ok(key) => key, - Err(e) => return Err(CertLoadError::BadKey(domain, e)), - }; + let key = der_to_private_key(&der).map_err(|e| CertLoadError::BadKey(domain.clone(), e))?; + Ok(CertifiedKey::new(vec![cert], key)) } +/// We don't know the key type of the private key DER file, so try each +/// possible type until we find one that works. +/// +/// We should probably stop doing this and use a PEM file instead: +/// https://github.com/rustls/rustls/issues/1661 +fn der_to_private_key(der: &[u8]) -> Result<Arc<dyn SigningKey>, rustls::Error> { + let keys = [ + PrivateKeyDer::Pkcs1(pki_types::PrivatePkcs1KeyDer::from(der)), + PrivateKeyDer::Sec1(pki_types::PrivateSec1KeyDer::from(der)), + PrivateKeyDer::Pkcs8(pki_types::PrivatePkcs8KeyDer::from(der)), + ]; + + let mut err = None; + for key in keys { + match any_supported_type(&key) { + Ok(key) => return Ok(key), + Err(e) => err = Some(e), + } + } + Err(err.unwrap()) +} + impl CertStore { /// Load certificates from a certificate directory. /// Certificates should be stored in a folder for each hostname, for example diff --git a/src/main.rs b/src/main.rs @@ -408,13 +408,9 @@ static TLS: Lazy<TlsAcceptor> = Lazy::new(acceptor); fn acceptor() -> TlsAcceptor { let config = if ARGS.only_tls13 { - ServerConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - .with_protocol_versions(&[&rustls::version::TLS13]) - .expect("could not build server config") + ServerConfig::builder_with_protocol_versions(&[&rustls::version::TLS13]) } else { - ServerConfig::builder().with_safe_defaults() + ServerConfig::builder() } .with_no_client_auth() .with_cert_resolver(ARGS.certs.clone()); diff --git a/tests/tests.rs b/tests/tests.rs @@ -166,7 +166,7 @@ fn index_page() { #[cfg(unix)] #[test] fn index_page_unix() { - use rustls::{Certificate, ClientConnection, RootCertStore}; + use rustls::{pki_types::CertificateDer, ClientConnection, RootCertStore}; let sock_path = std::env::temp_dir().join("agate-test-unix-socket"); @@ -184,7 +184,7 @@ fn index_page_unix() { // set up TLS connection via unix socket let mut certs = RootCertStore::empty(); certs - .add(&Certificate( + .add(CertificateDer::from( include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/tests/data/multicert/example.com/cert.der" @@ -193,7 +193,6 @@ fn index_page_unix() { )) .unwrap(); let config = rustls::ClientConfig::builder() - .with_safe_defaults() .with_root_certificates(certs) .with_no_client_auth(); let mut session = ClientConnection::new( @@ -363,7 +362,7 @@ fn username() { #[test] /// - URLS with invalid hostnames are rejected fn percent_encode() { - use rustls::{Certificate, ClientConnection, RootCertStore}; + use rustls::{pki_types::CertificateDer, ClientConnection, RootCertStore}; use std::io::Write; use std::net::TcpStream; @@ -373,7 +372,7 @@ fn percent_encode() { let mut certs = RootCertStore::empty(); certs - .add(&Certificate( + .add(CertificateDer::from( include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/tests/data/multicert/example.com/cert.der" @@ -382,7 +381,6 @@ fn percent_encode() { )) .unwrap(); let config = rustls::ClientConfig::builder() - .with_safe_defaults() .with_root_certificates(certs) .with_no_client_auth(); @@ -533,12 +531,8 @@ fn explicit_tls_version() { let server = Server::new(&["-3"]); - let config = rustls::ClientConfig::builder() - .with_safe_default_cipher_suites() - .with_safe_default_kx_groups() - // try to connect using only TLS 1.2 - .with_protocol_versions(&[&rustls::version::TLS12]) - .unwrap() + // try to connect using only TLS 1.2 + let config = rustls::ClientConfig::builder_with_protocol_versions(&[&rustls::version::TLS12]) .with_root_certificates(RootCertStore::empty()) .with_no_client_auth(); @@ -636,7 +630,7 @@ mod multicert { #[test] fn example_com() { - use rustls::{Certificate, ClientConnection, RootCertStore}; + use rustls::{pki_types::CertificateDer, ClientConnection, RootCertStore}; use std::io::Write; use std::net::TcpStream; @@ -644,7 +638,7 @@ mod multicert { let mut certs = RootCertStore::empty(); certs - .add(&Certificate( + .add(CertificateDer::from( include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/tests/data/multicert/example.com/cert.der" @@ -653,7 +647,6 @@ mod multicert { )) .unwrap(); let config = rustls::ClientConfig::builder() - .with_safe_defaults() .with_root_certificates(certs) .with_no_client_auth(); @@ -675,7 +668,7 @@ mod multicert { #[test] fn example_org() { - use rustls::{Certificate, ClientConnection, RootCertStore}; + use rustls::{pki_types::CertificateDer, ClientConnection, RootCertStore}; use std::io::Write; use std::net::TcpStream; @@ -683,7 +676,7 @@ mod multicert { let mut certs = RootCertStore::empty(); certs - .add(&Certificate( + .add(CertificateDer::from( include_bytes!(concat!( env!("CARGO_MANIFEST_DIR"), "/tests/data/multicert/example.org/cert.der" @@ -692,7 +685,6 @@ mod multicert { )) .unwrap(); let config = rustls::ClientConfig::builder() - .with_safe_defaults() .with_root_certificates(certs) .with_no_client_auth();