diff --git a/Cargo.lock b/Cargo.lock index 4b99f35..0c672be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -375,7 +375,6 @@ dependencies = [ "log", "rustls", "rustls-native-certs", - "rustls-pemfile", "rustls-pki-types", "rustls-platform-verifier", "tokio", @@ -652,15 +651,6 @@ dependencies = [ "security-framework", ] -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "rustls-pki-types" version = "1.12.0" diff --git a/Cargo.toml b/Cargo.toml index cf10f44..cf9972c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ http = "1" hyper = { version = "1", default-features = false } hyper-util = { version = "0.1", default-features = false, features = ["client-legacy", "tokio"] } log = { version = "0.4.4", optional = true } -pki-types = { package = "rustls-pki-types", version = "1" } +pki-types = { package = "rustls-pki-types", version = "1", features = ["std"] } rustls-native-certs = { version = "0.8", optional = true } rustls-platform-verifier = { version = "0.6", optional = true } rustls = { version = "0.23", default-features = false } @@ -41,7 +41,6 @@ cfg-if = "1" http-body-util = "0.1" hyper-util = { version = "0.1", default-features = false, features = ["server-auto"] } rustls = { version = "0.23", default-features = false, features = ["tls12"] } -rustls-pemfile = "2" tokio = { version = "1.0", features = ["io-std", "macros", "net", "rt-multi-thread"] } [[example]] diff --git a/examples/client.rs b/examples/client.rs index 71c6888..764ed61 100644 --- a/examples/client.rs +++ b/examples/client.rs @@ -2,30 +2,24 @@ //! //! First parameter is the mandatory URL to GET. //! Second parameter is an optional path to CA store. + use http::Uri; use http_body_util::{BodyExt, Empty}; use hyper::body::Bytes; use hyper_rustls::ConfigBuilderExt; use hyper_util::{client::legacy::Client, rt::TokioExecutor}; -use rustls::RootCertStore; +use pki_types::{pem::PemObject, CertificateDer}; +use rustls::{ClientConfig, RootCertStore}; use std::str::FromStr; use std::{env, fs, io}; -fn main() { - // Send GET request and inspect result, with proper error handling. - if let Err(e) = run_client() { - eprintln!("FAILED: {e}"); - std::process::exit(1); - } -} - fn error(err: String) -> io::Error { io::Error::new(io::ErrorKind::Other, err) } #[tokio::main] -async fn run_client() -> io::Result<()> { +async fn main() -> io::Result<()> { // Set a process wide default crypto provider. #[cfg(feature = "ring")] let _ = rustls::crypto::ring::default_provider().install_default(); @@ -34,39 +28,29 @@ async fn run_client() -> io::Result<()> { // First parameter is target URL (mandatory). let url = match env::args().nth(1) { - Some(ref url) => Uri::from_str(url).map_err(|e| error(format!("{e}")))?, - None => { - println!("Usage: client "); - return Ok(()); - } - }; - - // Second parameter is custom Root-CA store (optional, defaults to native cert store). - let mut ca = match env::args().nth(2) { - Some(ref path) => { - let f = - fs::File::open(path).map_err(|e| error(format!("failed to open {path}: {e}")))?; - let rd = io::BufReader::new(f); - Some(rd) - } - None => None, + Some(u) => Uri::from_str(&u).map_err(|e| error(e.to_string()))?, + None => return Ok(()), }; // Prepare the TLS client config - let tls = match ca { - Some(ref mut rd) => { - // Read trust roots - let certs = rustls_pemfile::certs(rd).collect::, _>>()?; + let tls = match env::args().nth(2) { + Some(path) => { + let data = fs::read(&path).map_err(|e| error(format!("failed to open {path}: {e}")))?; + let mut roots = RootCertStore::empty(); - roots.add_parsable_certificates(certs); - // TLS client config using the custom CA store for lookups - rustls::ClientConfig::builder() + for cert in CertificateDer::pem_slice_iter(&data) { + let cert = cert.map_err(|e| error(format!("invalid PEM: {e}")))?; + roots.add_parsable_certificates([cert]); + } + + ClientConfig::builder() .with_root_certificates(roots) .with_no_client_auth() } // Default TLS client config with native roots - None => rustls::ClientConfig::builder() - .with_native_roots()? + None => ClientConfig::builder() + .with_native_roots() + .map_err(|e| error(e.to_string()))? .with_no_client_auth(), }; // Prepare the HTTPS connector @@ -79,27 +63,25 @@ async fn run_client() -> io::Result<()> { // Build the hyper client from the HTTPS connector. let client: Client<_, Empty> = Client::builder(TokioExecutor::new()).build(https); - // Prepare a chain of futures which sends a GET request, inspects - // the returned headers, collects the whole body and prints it to - // stdout. - let fut = async move { - let res = client - .get(url) - .await - .map_err(|e| error(format!("Could not get: {e:?}")))?; - println!("Status:\n{}", res.status()); - println!("Headers:\n{:#?}", res.headers()); + // Send the request and print the response. + let res = client + .get(url) + .await + .map_err(|e| error(format!("request failed: {e:?}")))?; - let body = res - .into_body() - .collect() - .await - .map_err(|e| error(format!("Could not get body: {e:?}")))? - .to_bytes(); - println!("Body:\n{}", String::from_utf8_lossy(&body)); + let status = res.status(); + let headers = res.headers().clone(); - Ok(()) - }; + let body = res + .into_body() + .collect() + .await + .map_err(|e| error(format!("body error: {e:?}")))? + .to_bytes(); + + println!("Status:\n{status}"); + println!("Headers:\n{headers:#?}"); + println!("Body:\n{}", String::from_utf8_lossy(&body)); - fut.await + Ok(()) } diff --git a/examples/server.rs b/examples/server.rs index 6cbcf45..84714d5 100644 --- a/examples/server.rs +++ b/examples/server.rs @@ -15,7 +15,7 @@ use hyper::body::{Bytes, Incoming}; use hyper::service::service_fn; use hyper_util::rt::{TokioExecutor, TokioIo}; use hyper_util::server::conn::auto::Builder; -use pki_types::{CertificateDer, PrivateKeyDer}; +use pki_types::{pem::PemObject, CertificateDer, PrivateKeyDer}; use rustls::ServerConfig; use tokio::net::TcpListener; use tokio_rustls::TlsAcceptor; @@ -114,25 +114,23 @@ async fn echo(req: Request) -> Result>, hyper::Er }; Ok(response) } - // Load public certificate from file. fn load_certs(filename: &str) -> io::Result>> { // Open certificate file. - let certfile = - fs::File::open(filename).map_err(|e| error(format!("failed to open {filename}: {e}")))?; - let mut reader = io::BufReader::new(certfile); + let data = fs::read(filename).map_err(|e| error(format!("failed to open {filename}: {e}")))?; // Load and return certificate. - rustls_pemfile::certs(&mut reader).collect() + CertificateDer::pem_slice_iter(&data) + .map(|cert| cert.map_err(|e| error(format!("invalid PEM in {filename}: {e}")))) + .collect() } // Load private key from file. fn load_private_key(filename: &str) -> io::Result> { // Open keyfile. - let keyfile = - fs::File::open(filename).map_err(|e| error(format!("failed to open {filename}: {e}")))?; - let mut reader = io::BufReader::new(keyfile); + let data = fs::read(filename).map_err(|e| error(format!("failed to open {filename}: {e}")))?; // Load and return a single private key. - rustls_pemfile::private_key(&mut reader).map(|key| key.unwrap()) + PrivateKeyDer::from_pem_slice(&data) + .map_err(|e| error(format!("invalid private key in {filename}: {e}"))) }