From 7fa6333a0cdc6b7786b767e93ff73042ac365680 Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Sat, 13 Feb 2021 17:16:36 +0000 Subject: [PATCH] use rcgen for tls key generation (#1989) --- .github/workflows/ci.yml | 10 ++- Cargo.toml | 10 +-- actix-http/Cargo.toml | 1 + actix-http/tests/test_openssl.rs | 61 +++++++------- actix-http/tests/test_rustls.rs | 45 +++++----- awc/tests/test_connector.rs | 27 +++--- awc/tests/test_ssl_client.rs | 27 +++--- src/lib.rs | 4 +- src/middleware/compat.rs | 11 ++- src/request.rs | 2 + src/test.rs | 5 +- tests/cert.pem | 19 ----- tests/key.pem | 28 ------- tests/test_httpserver.rs | 23 ++++-- tests/test_server.rs | 138 ++++++++++++++++++++----------- 15 files changed, 226 insertions(+), 185 deletions(-) delete mode 100644 tests/cert.pem delete mode 100644 tests/key.pem diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55af5a38..0126238e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,11 +40,17 @@ jobs: - name: Cache Dependencies uses: Swatinem/rust-cache@v1.0.1 + - name: Install cargo-hack + uses: actions-rs/cargo@v1 + with: + command: install + args: cargo-hack + - name: check minimal uses: actions-rs/cargo@v1 with: - command: check - args: --workspace --no-default-features --tests + command: hack + args: --clean-per-run check --workspace --no-default-features --tests - name: check full uses: actions-rs/cargo@v1 diff --git a/Cargo.toml b/Cargo.toml index 64b447e1..1a1b8645 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -118,13 +118,13 @@ features = ["vendored"] optional = true [dev-dependencies] -actix = { version = "0.11.0-beta.2", default-features = false } -rand = "0.8" -env_logger = "0.8" -serde_derive = "1.0" brotli2 = "0.3.2" -flate2 = "1.0.13" criterion = "0.3" +env_logger = "0.8" +flate2 = "1.0.13" +rand = "0.8" +rcgen = "0.8" +serde_derive = "1.0" [profile.release] lto = true diff --git a/actix-http/Cargo.toml b/actix-http/Cargo.toml index 0e6916a0..69a344d4 100644 --- a/actix-http/Cargo.toml +++ b/actix-http/Cargo.toml @@ -95,6 +95,7 @@ actix-http-test = { version = "3.0.0-beta.2", features = ["openssl"] } actix-tls = { version = "3.0.0-beta.2", features = ["openssl"] } criterion = "0.3" env_logger = "0.8" +rcgen = "0.8" serde_derive = "1.0" tls-openssl = { version = "0.10", package = "openssl" } tls-rustls = { version = "0.19", package = "rustls" } diff --git a/actix-http/tests/test_openssl.rs b/actix-http/tests/test_openssl.rs index 188516f8..f44968ba 100644 --- a/actix-http/tests/test_openssl.rs +++ b/actix-http/tests/test_openssl.rs @@ -14,7 +14,11 @@ use actix_service::{fn_service, ServiceFactoryExt}; use bytes::{Bytes, BytesMut}; use futures_util::future::{err, ok, ready}; use futures_util::stream::{once, Stream, StreamExt}; -use openssl::ssl::{AlpnError, SslAcceptor, SslFiletype, SslMethod}; +use openssl::{ + pkey::PKey, + ssl::{SslAcceptor, SslMethod}, + x509::X509, +}; async fn load_body(stream: S) -> Result where @@ -34,29 +38,26 @@ where Ok(body) } -fn ssl_acceptor() -> SslAcceptor { - // load ssl keys +fn tls_config() -> SslAcceptor { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap(); + let cert_file = cert.serialize_pem().unwrap(); + let key_file = cert.serialize_private_key_pem(); + let cert = X509::from_pem(cert_file.as_bytes()).unwrap(); + let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap(); + let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - builder - .set_private_key_file("../tests/key.pem", SslFiletype::PEM) - .unwrap(); - builder - .set_certificate_chain_file("../tests/cert.pem") - .unwrap(); + builder.set_certificate(&cert).unwrap(); + builder.set_private_key(&key).unwrap(); + builder.set_alpn_select_callback(|_, protos| { const H2: &[u8] = b"\x02h2"; - const H11: &[u8] = b"\x08http/1.1"; if protos.windows(3).any(|window| window == H2) { Ok(b"h2") - } else if protos.windows(9).any(|window| window == H11) { - Ok(b"http/1.1") } else { - Err(AlpnError::NOACK) + Err(openssl::ssl::AlpnError::NOACK) } }); - builder - .set_alpn_protos(b"\x08http/1.1\x02h2") - .expect("Can not contrust SslAcceptor"); + builder.set_alpn_protos(b"\x02h2").unwrap(); builder.build() } @@ -66,7 +67,7 @@ async fn test_h2() -> io::Result<()> { let srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, Error>(Response::Ok().finish())) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -85,7 +86,7 @@ async fn test_h2_1() -> io::Result<()> { assert_eq!(req.version(), Version::HTTP_2); ok::<_, Error>(Response::Ok().finish()) }) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -104,7 +105,7 @@ async fn test_h2_body() -> io::Result<()> { let body = load_body(req.take_payload()).await?; Ok::<_, Error>(Response::Ok().body(body)) }) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -133,7 +134,7 @@ async fn test_h2_content_length() { ]; ok::<_, ()>(Response::new(statuses[indx])) }) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -195,7 +196,7 @@ async fn test_h2_headers() { } ok::<_, ()>(builder.body(data.clone())) }) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }).await; @@ -234,7 +235,7 @@ async fn test_h2_body2() { let mut srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, ()>(Response::Ok().body(STR))) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -252,7 +253,7 @@ async fn test_h2_head_empty() { let mut srv = test_server(move || { HttpService::build() .finish(|_| ok::<_, ()>(Response::Ok().body(STR))) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -276,7 +277,7 @@ async fn test_h2_head_binary() { let mut srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, ()>(Response::Ok().body(STR))) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -299,7 +300,7 @@ async fn test_h2_head_binary2() { let srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, ()>(Response::Ok().body(STR))) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -323,7 +324,7 @@ async fn test_h2_body_length() { Response::Ok().body(body::SizedStream::new(STR.len() as u64, body)), ) }) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -348,7 +349,7 @@ async fn test_h2_body_chunked_explicit() { .streaming(body), ) }) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -376,7 +377,7 @@ async fn test_h2_response_http_error_handling() { .body(STR), ) })) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -394,7 +395,7 @@ async fn test_h2_service_error() { let mut srv = test_server(move || { HttpService::build() .h2(|_| err::(ErrorBadRequest("error"))) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; @@ -418,7 +419,7 @@ async fn test_h2_on_connect() { assert!(req.extensions().contains::()); ok::<_, ()>(Response::Ok().finish()) }) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; diff --git a/actix-http/tests/test_rustls.rs b/actix-http/tests/test_rustls.rs index 59ffcfeb..a3640091 100644 --- a/actix-http/tests/test_rustls.rs +++ b/actix-http/tests/test_rustls.rs @@ -31,14 +31,19 @@ where Ok(body) } -fn ssl_acceptor() -> RustlsServerConfig { - // load ssl keys +fn tls_config() -> RustlsServerConfig { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap(); + let cert_file = cert.serialize_pem().unwrap(); + let key_file = cert.serialize_private_key_pem(); + let mut config = RustlsServerConfig::new(NoClientAuth::new()); - let cert_file = &mut BufReader::new(File::open("../tests/cert.pem").unwrap()); - let key_file = &mut BufReader::new(File::open("../tests/key.pem").unwrap()); + let cert_file = &mut BufReader::new(cert_file.as_bytes()); + let key_file = &mut BufReader::new(key_file.as_bytes()); + let cert_chain = certs(cert_file).unwrap(); let mut keys = pkcs8_private_keys(key_file).unwrap(); config.set_single_cert(cert_chain, keys.remove(0)).unwrap(); + config } @@ -47,7 +52,7 @@ async fn test_h1() -> io::Result<()> { let srv = test_server(move || { HttpService::build() .h1(|_| future::ok::<_, Error>(Response::Ok().finish())) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -61,7 +66,7 @@ async fn test_h2() -> io::Result<()> { let srv = test_server(move || { HttpService::build() .h2(|_| future::ok::<_, Error>(Response::Ok().finish())) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -79,7 +84,7 @@ async fn test_h1_1() -> io::Result<()> { assert_eq!(req.version(), Version::HTTP_11); future::ok::<_, Error>(Response::Ok().finish()) }) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -97,7 +102,7 @@ async fn test_h2_1() -> io::Result<()> { assert_eq!(req.version(), Version::HTTP_2); future::ok::<_, Error>(Response::Ok().finish()) }) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -115,7 +120,7 @@ async fn test_h2_body1() -> io::Result<()> { let body = load_body(req.take_payload()).await?; Ok::<_, Error>(Response::Ok().body(body)) }) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -143,7 +148,7 @@ async fn test_h2_content_length() { ]; future::ok::<_, ()>(Response::new(statuses[indx])) }) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -203,7 +208,7 @@ async fn test_h2_headers() { } future::ok::<_, ()>(config.body(data.clone())) }) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }).await; let response = srv.sget("/").send().await.unwrap(); @@ -241,7 +246,7 @@ async fn test_h2_body2() { let mut srv = test_server(move || { HttpService::build() .h2(|_| future::ok::<_, ()>(Response::Ok().body(STR))) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -258,7 +263,7 @@ async fn test_h2_head_empty() { let mut srv = test_server(move || { HttpService::build() .finish(|_| ok::<_, ()>(Response::Ok().body(STR))) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -284,7 +289,7 @@ async fn test_h2_head_binary() { let mut srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, ()>(Response::Ok().body(STR))) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -309,7 +314,7 @@ async fn test_h2_head_binary2() { let srv = test_server(move || { HttpService::build() .h2(|_| ok::<_, ()>(Response::Ok().body(STR))) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -335,7 +340,7 @@ async fn test_h2_body_length() { Response::Ok().body(body::SizedStream::new(STR.len() as u64, body)), ) }) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -359,7 +364,7 @@ async fn test_h2_body_chunked_explicit() { .streaming(body), ) }) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -388,7 +393,7 @@ async fn test_h2_response_http_error_handling() { ) })) })) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -405,7 +410,7 @@ async fn test_h2_service_error() { let mut srv = test_server(move || { HttpService::build() .h2(|_| err::(error::ErrorBadRequest("error"))) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; @@ -422,7 +427,7 @@ async fn test_h1_service_error() { let mut srv = test_server(move || { HttpService::build() .h1(|_| err::(error::ErrorBadRequest("error"))) - .rustls(ssl_acceptor()) + .rustls(tls_config()) }) .await; diff --git a/awc/tests/test_connector.rs b/awc/tests/test_connector.rs index 4e4fa583..fd725506 100644 --- a/awc/tests/test_connector.rs +++ b/awc/tests/test_connector.rs @@ -7,17 +7,23 @@ use actix_http_test::test_server; use actix_service::{map_config, ServiceFactoryExt}; use actix_web::http::Version; use actix_web::{dev::AppConfig, web, App, HttpResponse}; -use openssl::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslVerifyMode}; +use openssl::{ + pkey::PKey, + ssl::{SslAcceptor, SslConnector, SslMethod, SslVerifyMode}, + x509::X509, +}; + +fn tls_config() -> SslAcceptor { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap(); + let cert_file = cert.serialize_pem().unwrap(); + let key_file = cert.serialize_private_key_pem(); + let cert = X509::from_pem(cert_file.as_bytes()).unwrap(); + let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap(); -fn ssl_acceptor() -> SslAcceptor { - // load ssl keys let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - builder - .set_private_key_file("../tests/key.pem", SslFiletype::PEM) - .unwrap(); - builder - .set_certificate_chain_file("../tests/cert.pem") - .unwrap(); + builder.set_certificate(&cert).unwrap(); + builder.set_private_key(&key).unwrap(); + builder.set_alpn_select_callback(|_, protos| { const H2: &[u8] = b"\x02h2"; if protos.windows(3).any(|window| window == H2) { @@ -27,6 +33,7 @@ fn ssl_acceptor() -> SslAcceptor { } }); builder.set_alpn_protos(b"\x02h2").unwrap(); + builder.build() } @@ -38,7 +45,7 @@ async fn test_connection_window_size() { App::new().service(web::resource("/").route(web::to(HttpResponse::Ok))), |_| AppConfig::default(), )) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()) }) .await; diff --git a/awc/tests/test_ssl_client.rs b/awc/tests/test_ssl_client.rs index b93c729e..08aa125c 100644 --- a/awc/tests/test_ssl_client.rs +++ b/awc/tests/test_ssl_client.rs @@ -11,17 +11,23 @@ use actix_service::{map_config, pipeline_factory, ServiceFactoryExt}; use actix_web::http::Version; use actix_web::{dev::AppConfig, web, App, HttpResponse}; use futures_util::future::ok; -use openssl::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod, SslVerifyMode}; +use openssl::{ + pkey::PKey, + ssl::{SslAcceptor, SslConnector, SslMethod, SslVerifyMode}, + x509::X509, +}; + +fn tls_config() -> SslAcceptor { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap(); + let cert_file = cert.serialize_pem().unwrap(); + let key_file = cert.serialize_private_key_pem(); + let cert = X509::from_pem(cert_file.as_bytes()).unwrap(); + let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap(); -fn ssl_acceptor() -> SslAcceptor { - // load ssl keys let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - builder - .set_private_key_file("../tests/key.pem", SslFiletype::PEM) - .unwrap(); - builder - .set_certificate_chain_file("../tests/cert.pem") - .unwrap(); + builder.set_certificate(&cert).unwrap(); + builder.set_private_key(&key).unwrap(); + builder.set_alpn_select_callback(|_, protos| { const H2: &[u8] = b"\x02h2"; if protos.windows(3).any(|window| window == H2) { @@ -31,6 +37,7 @@ fn ssl_acceptor() -> SslAcceptor { } }); builder.set_alpn_protos(b"\x02h2").unwrap(); + builder.build() } @@ -51,7 +58,7 @@ async fn test_connection_reuse_h2() { App::new().service(web::resource("/").route(web::to(HttpResponse::Ok))), |_| AppConfig::default(), )) - .openssl(ssl_acceptor()) + .openssl(tls_config()) .map_err(|_| ()), ) }) diff --git a/src/lib.rs b/src/lib.rs index 73390a55..16b2ab18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -99,8 +99,10 @@ pub mod test; pub(crate) mod types; pub mod web; +#[cfg(feature = "cookies")] +pub use actix_http::cookie; pub use actix_http::Response as HttpResponse; -pub use actix_http::{body, cookie, http, Error, HttpMessage, ResponseError, Result}; +pub use actix_http::{body, http, Error, HttpMessage, ResponseError, Result}; pub use actix_rt as rt; pub use actix_web_codegen::*; diff --git a/src/middleware/compat.rs b/src/middleware/compat.rs index 97742e92..6f60264b 100644 --- a/src/middleware/compat.rs +++ b/src/middleware/compat.rs @@ -123,18 +123,24 @@ impl MapServiceResponseBody for ServiceRespons #[cfg(test)] mod tests { + // easier to code when cookies feature is disabled + #![allow(unused_imports)] + use super::*; use actix_service::IntoService; use crate::dev::ServiceRequest; use crate::http::StatusCode; - use crate::middleware::{Compress, Condition, Logger}; + use crate::middleware::{self, Condition, Logger}; use crate::test::{call_service, init_service, TestRequest}; use crate::{web, App, HttpResponse}; #[actix_rt::test] + #[cfg(feature = "cookies")] async fn test_scope_middleware() { + use crate::middleware::Compress; + let logger = Logger::default(); let compress = Compress::default(); @@ -154,7 +160,10 @@ mod tests { } #[actix_rt::test] + #[cfg(feature = "cookies")] async fn test_resource_scope_middleware() { + use crate::middleware::Compress; + let logger = Logger::default(); let compress = Compress::default(); diff --git a/src/request.rs b/src/request.rs index d62fca30..514b7466 100644 --- a/src/request.rs +++ b/src/request.rs @@ -429,12 +429,14 @@ mod tests { } #[test] + #[cfg(feature = "cookies")] fn test_no_request_cookies() { let req = TestRequest::default().to_http_request(); assert!(req.cookies().unwrap().is_empty()); } #[test] + #[cfg(feature = "cookies")] fn test_request_cookies() { let req = TestRequest::default() .append_header((header::COOKIE, "cookie1=value1")) diff --git a/src/test.rs b/src/test.rs index d576838d..2ec4252b 100644 --- a/src/test.rs +++ b/src/test.rs @@ -6,10 +6,12 @@ use std::sync::mpsc; use std::{fmt, net, thread, time}; use actix_codec::{AsyncRead, AsyncWrite, Framed}; +#[cfg(feature = "cookies")] +use actix_http::cookie::Cookie; use actix_http::http::header::{ContentType, IntoHeaderPair}; use actix_http::http::{Method, StatusCode, Uri, Version}; use actix_http::test::TestRequest as HttpTestRequest; -use actix_http::{cookie::Cookie, ws, Extensions, HttpService, Request}; +use actix_http::{ws, Extensions, HttpService, Request}; use actix_router::{Path, ResourceDef, Url}; use actix_rt::{time::sleep, System}; use actix_service::{map_config, IntoService, IntoServiceFactory, Service, ServiceFactory}; @@ -438,6 +440,7 @@ impl TestRequest { } /// Set cookie for this request. + #[cfg(feature = "cookies")] pub fn cookie(mut self, cookie: Cookie<'_>) -> Self { self.req.cookie(cookie); self diff --git a/tests/cert.pem b/tests/cert.pem deleted file mode 100644 index 0eeb6721..00000000 --- a/tests/cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDEDCCAfgCCQCQdmIZc/Ib/jANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJ1 -czELMAkGA1UECAwCY2ExCzAJBgNVBAcMAnNmMSEwHwYJKoZIhvcNAQkBFhJmYWZo -cmQ5MUBnbWFpbC5jb20wHhcNMTkxMTE5MTEwNjU1WhcNMjkxMTE2MTEwNjU1WjBK -MQswCQYDVQQGEwJ1czELMAkGA1UECAwCY2ExCzAJBgNVBAcMAnNmMSEwHwYJKoZI -hvcNAQkBFhJmYWZocmQ5MUBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB -DwAwggEKAoIBAQDcnaz12CKzUL7248V7Axhms/O9UQXfAdw0yolEfC3P5jADa/1C -+kLWKjAc2coqDSbGsrsR6KiH2g06Kunx+tSGqUO+Sct7HEehmxndiSwx/hfMWezy -XRe/olcHFTeCk/Tllz4xGEplhPua6GLhJygLOhAMiV8cwCYrgyPqsDduExLDFCqc -K2xntIPreumXpiE3QY4+MWyteiJko4IWDFf/UwwsdCY5MlFfw1F/Uv9vz7FfOfvu -GccHd/ex8cOwotUqd6emZb+0bVE24Sv8U+yLnHIVx/tOkxgMAnJEpAnf2G3Wp3zU -b2GJosbmfGaf+xTfnGGhTLLL7kCtva+NvZr5AgMBAAEwDQYJKoZIhvcNAQELBQAD -ggEBANftoL8zDGrjCwWvct8kOOqset2ukK8vjIGwfm88CKsy0IfSochNz2qeIu9R -ZuO7c0pfjmRkir9ZQdq9vXgG3ccL9UstFsferPH9W3YJ83kgXg3fa0EmCiN/0hwz -6Ij1ZBiN1j3+d6+PJPgyYFNu2nGwox5mJ9+aRAGe0/9c63PEOY8P2TI4HsiPmYSl -fFR8k/03vr6e+rTKW85BgctjvYKe/TnFxeCQ7dZ+na7vlEtch4tNmy6O/vEk2kCt -5jW0DUxhmRsv2wGmfFRI0+LotHjoXQQZi6nN5aGL3odaGF3gYwIVlZNd3AdkwDQz -BzG0ZwXuDDV9bSs3MfWEWcy4xuU= ------END CERTIFICATE----- diff --git a/tests/key.pem b/tests/key.pem deleted file mode 100644 index a6d30816..00000000 --- a/tests/key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDcnaz12CKzUL72 -48V7Axhms/O9UQXfAdw0yolEfC3P5jADa/1C+kLWKjAc2coqDSbGsrsR6KiH2g06 -Kunx+tSGqUO+Sct7HEehmxndiSwx/hfMWezyXRe/olcHFTeCk/Tllz4xGEplhPua -6GLhJygLOhAMiV8cwCYrgyPqsDduExLDFCqcK2xntIPreumXpiE3QY4+MWyteiJk -o4IWDFf/UwwsdCY5MlFfw1F/Uv9vz7FfOfvuGccHd/ex8cOwotUqd6emZb+0bVE2 -4Sv8U+yLnHIVx/tOkxgMAnJEpAnf2G3Wp3zUb2GJosbmfGaf+xTfnGGhTLLL7kCt -va+NvZr5AgMBAAECggEBAKoU0UwzVgVCQgca8Jt2dnBvWYDhnxIfYAI/BvaKedMm -1ms87OKfB7oOiksjyI0E2JklH72dzZf2jm4CuZt5UjGC+xwPzlTaJ4s6hQVbBHyC -NRyxU1BCXtW5tThbrhD4OjxqjmLRJEIB9OunLtwAEQoeuFLB8Va7+HFhR+Zd9k3f -7aVA93pC5A50NRbZlke4miJ3Q8n7ZF0+UmxkBfm3fbqLk7aMWkoEKwLLTadjRlu1 -bBp0YDStX66I/p1kujqBOdh6VpPvxFOa1sV9pq0jeiGc9YfSkzRSKzIn8GoyviFB -fHeszQdNlcnrSDSNnMABAw+ZpxUO7SCaftjwejEmKZUCgYEA+TY43VpmV95eY7eo -WKwGepiHE0fwQLuKGELmZdZI80tFi73oZMuiB5WzwmkaKGcJmm7KGE9KEvHQCo9j -xvmktBR0VEZH8pmVfun+4h6+0H7m/NKMBBeOyv/IK8jBgHjkkB6e6nmeR7CqTxCw -tf9tbajl1QN8gNzXZSjBDT/lanMCgYEA4qANOKOSiEARtgwyXQeeSJcM2uPv6zF3 -ffM7vjSedtuEOHUSVeyBP/W8KDt7zyPppO/WNbURHS+HV0maS9yyj6zpVS2HGmbs -3fetswsQ+zYVdokW89x4oc2z4XOGHd1LcSlyhRwPt0u2g1E9L0irwTQLWU0npFmG -PRf7sN9+LeMCgYAGkDUDL2ROoB6gRa/7Vdx90hKMoXJkYgwLA4gJ2pDlR3A3c/Lw -5KQJyxmG3zm/IqeQF6be6QesZA30mT4peV2rGHbP2WH/s6fKReNelSy1VQJEWk8x -tGUgV4gwDwN5nLV4TjYlOrq+bJqvpmLhCC8bmj0jVQosYqSRl3cuICasnQKBgGlV -VO/Xb1su1EyWPK5qxRIeSxZOTYw2sMB01nbgxCqge0M2fvA6/hQ5ZlwY0cIEgits -YlcSMsMq/TAAANxz1vbaupUhlSMbZcsBvNV0Nk9c4vr2Wxm7hsJF9u66IEMvQUp2 -pkjiMxfR9CHzF4orr9EcHI5EQ0Grbq5kwFKEfoRbAoGAcWoFPILeJOlp2yW/Ds3E -g2fQdI9BAamtEZEaslJmZMmsDTg5ACPcDkOSFEQIaJ7wLPXeZy74FVk/NrY5F8Gz -bjX9OD/xzwp852yW5L9r62vYJakAlXef5jI6CFdYKDDCcarU0S7W5k6kq9n+wrBR -i1NklYmUAMr2q59uJA5zsic= ------END PRIVATE KEY----- diff --git a/tests/test_httpserver.rs b/tests/test_httpserver.rs index 34d57008..3aa1d36b 100644 --- a/tests/test_httpserver.rs +++ b/tests/test_httpserver.rs @@ -73,15 +73,22 @@ async fn test_start() { #[cfg(feature = "openssl")] fn ssl_acceptor() -> std::io::Result { - use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; - // load ssl keys + use openssl::{ + pkey::PKey, + ssl::{SslAcceptor, SslMethod}, + x509::X509, + }; + + let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap(); + let cert_file = cert.serialize_pem().unwrap(); + let key_file = cert.serialize_private_key_pem(); + let cert = X509::from_pem(cert_file.as_bytes()).unwrap(); + let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap(); + let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - builder - .set_private_key_file("tests/key.pem", SslFiletype::PEM) - .unwrap(); - builder - .set_certificate_chain_file("tests/cert.pem") - .unwrap(); + builder.set_certificate(&cert).unwrap(); + builder.set_private_key(&key).unwrap(); + Ok(builder) } diff --git a/tests/test_server.rs b/tests/test_server.rs index c2e627a3..2466730f 100644 --- a/tests/test_server.rs +++ b/tests/test_server.rs @@ -21,6 +21,11 @@ use flate2::{ Compression, }; use futures_util::ready; +use openssl::{ + pkey::PKey, + ssl::{SslAcceptor, SslMethod}, + x509::X509, +}; use rand::{distributions::Alphanumeric, Rng}; use actix_web::dev::BodyEncoding; @@ -49,6 +54,30 @@ const STR: &str = "Hello World Hello World Hello World Hello World Hello World \ Hello World Hello World Hello World Hello World Hello World \ Hello World Hello World Hello World Hello World Hello World"; +fn openssl_config() -> SslAcceptor { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap(); + let cert_file = cert.serialize_pem().unwrap(); + let key_file = cert.serialize_private_key_pem(); + let cert = X509::from_pem(cert_file.as_bytes()).unwrap(); + let key = PKey::private_key_from_pem(key_file.as_bytes()).unwrap(); + + let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + builder.set_certificate(&cert).unwrap(); + builder.set_private_key(&key).unwrap(); + + builder.set_alpn_select_callback(|_, protos| { + const H2: &[u8] = b"\x02h2"; + if protos.windows(3).any(|window| window == H2) { + Ok(b"h2") + } else { + Err(openssl::ssl::AlpnError::NOACK) + } + }); + builder.set_alpn_protos(b"\x02h2").unwrap(); + + builder.build() +} + struct TestBody { data: Bytes, chunk_size: usize, @@ -700,18 +729,8 @@ async fn test_brotli_encoding_large() { #[cfg(feature = "openssl")] #[actix_rt::test] async fn test_brotli_encoding_large_openssl() { - // load ssl keys - use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; - let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - builder - .set_private_key_file("tests/key.pem", SslFiletype::PEM) - .unwrap(); - builder - .set_certificate_chain_file("tests/cert.pem") - .unwrap(); - let data = STR.repeat(10); - let srv = test::start_with(test::config().openssl(builder.build()), move || { + let srv = test::start_with(test::config().openssl(openssl_config()), move || { App::new().service(web::resource("/").route(web::to(|bytes: Bytes| { HttpResponse::Ok() .encoding(actix_web::http::ContentEncoding::Identity) @@ -739,53 +758,72 @@ async fn test_brotli_encoding_large_openssl() { } #[cfg(all(feature = "rustls", feature = "openssl"))] -#[actix_rt::test] -async fn test_reading_deflate_encoding_large_random_rustls() { - use rustls::internal::pemfile::{certs, pkcs8_private_keys}; - use rustls::{NoClientAuth, ServerConfig}; - use std::fs::File; +mod plus_rustls { use std::io::BufReader; - let data = rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(160_000) - .map(char::from) - .collect::(); + use rustls::{ + internal::pemfile::{certs, pkcs8_private_keys}, + NoClientAuth, ServerConfig as RustlsServerConfig, + }; - // load ssl keys - let mut config = ServerConfig::new(NoClientAuth::new()); - let cert_file = &mut BufReader::new(File::open("tests/cert.pem").unwrap()); - let key_file = &mut BufReader::new(File::open("tests/key.pem").unwrap()); - let cert_chain = certs(cert_file).unwrap(); - let mut keys = pkcs8_private_keys(key_file).unwrap(); - config.set_single_cert(cert_chain, keys.remove(0)).unwrap(); + use super::*; - let srv = test::start_with(test::config().rustls(config), || { - App::new().service(web::resource("/").route(web::to(|bytes: Bytes| { - HttpResponse::Ok() - .encoding(actix_web::http::ContentEncoding::Identity) - .body(bytes) - }))) - }); + fn rustls_config() -> RustlsServerConfig { + let cert = rcgen::generate_simple_self_signed(vec!["localhost".to_owned()]).unwrap(); + let cert_file = cert.serialize_pem().unwrap(); + let key_file = cert.serialize_private_key_pem(); - // encode data - let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); - e.write_all(data.as_ref()).unwrap(); - let enc = e.finish().unwrap(); + let mut config = RustlsServerConfig::new(NoClientAuth::new()); + let cert_file = &mut BufReader::new(cert_file.as_bytes()); + let key_file = &mut BufReader::new(key_file.as_bytes()); - // client request - let req = srv - .post("/") - .insert_header((actix_web::http::header::CONTENT_ENCODING, "deflate")) - .send_stream(TestBody::new(Bytes::from(enc), 1024)); + let cert_chain = certs(cert_file).unwrap(); + let mut keys = pkcs8_private_keys(key_file).unwrap(); + config.set_single_cert(cert_chain, keys.remove(0)).unwrap(); - let mut response = req.await.unwrap(); - assert!(response.status().is_success()); + config + } - // read response - let bytes = response.body().await.unwrap(); - assert_eq!(bytes.len(), data.len()); - assert_eq!(bytes, Bytes::from(data)); + #[actix_rt::test] + async fn test_reading_deflate_encoding_large_random_rustls() { + use rustls::internal::pemfile::{certs, pkcs8_private_keys}; + use rustls::{NoClientAuth, ServerConfig}; + use std::fs::File; + use std::io::BufReader; + + let data = rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(160_000) + .map(char::from) + .collect::(); + + let srv = test::start_with(test::config().rustls(rustls_config()), || { + App::new().service(web::resource("/").route(web::to(|bytes: Bytes| { + HttpResponse::Ok() + .encoding(actix_web::http::ContentEncoding::Identity) + .body(bytes) + }))) + }); + + // encode data + let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); + e.write_all(data.as_ref()).unwrap(); + let enc = e.finish().unwrap(); + + // client request + let req = srv + .post("/") + .insert_header((actix_web::http::header::CONTENT_ENCODING, "deflate")) + .send_stream(TestBody::new(Bytes::from(enc), 1024)); + + let mut response = req.await.unwrap(); + assert!(response.status().is_success()); + + // read response + let bytes = response.body().await.unwrap(); + assert_eq!(bytes.len(), data.len()); + assert_eq!(bytes, Bytes::from(data)); + } } #[actix_rt::test]