diff --git a/Cargo.toml b/Cargo.toml index 72688e58..c33aeec8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ members = [ "boring", "boring-sys", "tokio-boring", - "hyper-boring" ] resolver = "2" @@ -37,12 +36,6 @@ futures = "0.3" tokio = "1" anyhow = "1" antidote = "1.0.0" -http1 = { package = "http", version = "1" } -http-body-util = "0.1.2" -http0 = { package = "http", version = "0.2" } -hyper1 = { package = "hyper", version = "1" } -hyper-util = "0.1.6" -hyper0 = { package = "hyper", version = "0.14", default-features = false } linked_hash_set = "0.1" openssl-macros = "0.1.1" tower = { version = "0.4", default-features = false, features = ["util"] } diff --git a/hyper-boring/.gitignore b/hyper-boring/.gitignore deleted file mode 100644 index 582014fd..00000000 --- a/hyper-boring/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -target/ -Cargo.lock -.vscode/ -.idea/ -*.iml diff --git a/hyper-boring/Cargo.toml b/hyper-boring/Cargo.toml deleted file mode 100644 index 2b706537..00000000 --- a/hyper-boring/Cargo.toml +++ /dev/null @@ -1,72 +0,0 @@ -[package] -name = "hyper-boring" -version = { workspace = true } -authors = ["Steven Fackler ", "Ivan Nikulin "] -edition = { workspace = true } -description = "Hyper TLS support via BoringSSL" -license = "MIT OR Apache-2.0" -repository = { workspace = true } -documentation = "https://docs.rs/hyper-boring" -readme = "README.md" -exclude = ["test/*"] -rust-version = "1.80" - -[package.metadata.docs.rs] -features = ["pq-experimental"] -rustdoc-args = ["--cfg", "docsrs"] - -[features] -default = ["runtime", "hyper1-runtime"] - -runtime = [] -# `hyper1` + `runtime`. -hyper1-runtime = ["hyper1", "dep:tower"] -# `hyper0` + `runtime`. -hyper0-runtime = ["hyper0", "hyper0/runtime"] - -# Use a FIPS-validated version of boringssl. -fips = ["tokio-boring/fips"] - -# Link with precompiled FIPS-validated `bcm.o` module. -fips-link-precompiled = ["tokio-boring/fips-link-precompiled"] - -# Enables experimental post-quantum crypto (https://blog.cloudflare.com/post-quantum-for-all/) -pq-experimental = ["tokio-boring/pq-experimental"] - -# Enable Hyper 1 support. -hyper1 = ["dep:hyper1", "dep:http1", "dep:hyper-util", "dep:tower-service"] -# Enable Hyper 0 support. -hyper0 = ["dep:hyper0", "dep:http0"] - -[dependencies] -antidote = { workspace = true } -http1 = { workspace = true, optional = true } -http0 = { workspace = true, optional = true } -hyper1 = { workspace = true, optional = true } -hyper-util = { workspace = true, optional = true, features = ["client", "client-legacy"] } -hyper0 = { workspace = true, optional = true, features = ["client"] } -linked_hash_set = { workspace = true } -boring = { workspace = true } -tokio = { workspace = true } -tokio-boring = { workspace = true } -tower = { workspace = true, optional = true } -tower-layer = { workspace = true } -tower-service = { workspace = true, optional = true } - -[dev-dependencies] -bytes = { workspace = true } -http-body-util = { workspace = true } -hyper-util = { workspace = true, features = ["http1", "http2", "service", "tokio"] } -hyper1 = { workspace = true, features = ["server"] } -hyper0 = { workspace = true, features = [ "full" ] } -tokio = { workspace = true, features = [ "full" ] } -tower = { workspace = true, features = ["util"] } -futures = { workspace = true } - -[package.metadata.release] -pre-release-hook = [ - "git-cliff", - "--workdir", "..", - "-o", "../RELEASE_NOTES", - "--tag", "{{version}}" -] diff --git a/hyper-boring/LICENSE-APACHE b/hyper-boring/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/hyper-boring/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/hyper-boring/LICENSE-MIT b/hyper-boring/LICENSE-MIT deleted file mode 100644 index c1073587..00000000 --- a/hyper-boring/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-2016 Steven Fackler -Copyright (c) 2020 Ivan Nikulin - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/hyper-boring/README.md b/hyper-boring/README.md deleted file mode 100644 index 10bf1994..00000000 --- a/hyper-boring/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# hyper-boring - -[Documentation](https://docs.rs/hyper-boring) - -Hyper SSL support via BoringSSL. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. - -## Accolades - -The project is based on a fork of [hyper-openssl](https://github.com/sfackler/hyper-openssl). \ No newline at end of file diff --git a/hyper-boring/src/cache.rs b/hyper-boring/src/cache.rs deleted file mode 100644 index 185c3dc4..00000000 --- a/hyper-boring/src/cache.rs +++ /dev/null @@ -1,101 +0,0 @@ -use boring::ssl::SslVersion; -use boring::ssl::{SslSession, SslSessionRef}; -use linked_hash_set::LinkedHashSet; -use std::borrow::Borrow; -use std::collections::hash_map::{Entry, HashMap}; -use std::hash::{Hash, Hasher}; - -#[derive(Hash, PartialEq, Eq, Clone)] -pub struct SessionKey { - pub host: String, - pub port: u16, -} - -#[derive(Clone)] -struct HashSession(SslSession); - -impl PartialEq for HashSession { - fn eq(&self, other: &HashSession) -> bool { - self.0.id() == other.0.id() - } -} - -impl Eq for HashSession {} - -impl Hash for HashSession { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - self.0.id().hash(state); - } -} - -impl Borrow<[u8]> for HashSession { - fn borrow(&self) -> &[u8] { - self.0.id() - } -} - -pub struct SessionCache { - sessions: HashMap>, - reverse: HashMap, - /// Maximum capacity of LinkedHashSet per SessionKey - per_key_session_capacity: usize, -} - -impl SessionCache { - pub fn with_capacity(per_key_session_capacity: usize) -> SessionCache { - SessionCache { - sessions: HashMap::new(), - reverse: HashMap::new(), - per_key_session_capacity, - } - } - - pub fn insert(&mut self, key: SessionKey, session: SslSession) { - let session = HashSession(session); - - let sessions = self.sessions.entry(key.clone()).or_default(); - - // if sessions exceed capacity, discard oldest - if sessions.len() >= self.per_key_session_capacity { - if let Some(hash) = sessions.pop_front() { - self.reverse.remove(&hash); - } - } - - sessions.insert(session.clone()); - self.reverse.insert(session, key); - } - - pub fn get(&mut self, key: &SessionKey) -> Option { - let session = { - let sessions = self.sessions.get_mut(key)?; - sessions.front().cloned()?.0 - }; - - // https://tools.ietf.org/html/rfc8446#appendix-C.4 - // OpenSSL will remove the session from its cache after the handshake completes anyway, but this ensures - // that concurrent handshakes don't end up with the same session. - if session.protocol_version() == SslVersion::TLS1_3 { - self.remove(&session); - } - - Some(session) - } - - pub fn remove(&mut self, session: &SslSessionRef) { - let key = match self.reverse.remove(session.id()) { - Some(key) => key, - None => return, - }; - - if let Entry::Occupied(mut sessions) = self.sessions.entry(key) { - sessions.get_mut().remove(session.id()); - if sessions.get().is_empty() { - sessions.remove(); - } - } - } -} diff --git a/hyper-boring/src/lib.rs b/hyper-boring/src/lib.rs deleted file mode 100644 index e66aa955..00000000 --- a/hyper-boring/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! Hyper SSL support via OpenSSL. -#![warn(missing_docs)] -#![cfg_attr(docsrs, feature(doc_auto_cfg))] - -use crate::cache::SessionKey; -use boring::error::ErrorStack; -use boring::ex_data::Index; -use boring::ssl::Ssl; -use std::fmt; -use std::sync::LazyLock; -use tokio_boring::SslStream; - -mod cache; -/// Hyper 0 support. -#[cfg(feature = "hyper0")] -pub mod v0; -#[cfg(feature = "hyper1")] -mod v1; - -#[cfg(feature = "hyper1")] -pub use self::v1::*; - -fn key_index() -> Result, ErrorStack> { - static IDX: LazyLock> = LazyLock::new(|| Ssl::new_ex_index().unwrap()); - Ok(*IDX) -} - -/// Settings for [`HttpsLayer`] -pub struct HttpsLayerSettings { - session_cache_capacity: usize, -} - -impl HttpsLayerSettings { - /// Constructs an [`HttpsLayerSettingsBuilder`] for configuring settings - pub fn builder() -> HttpsLayerSettingsBuilder { - HttpsLayerSettingsBuilder(HttpsLayerSettings::default()) - } -} - -impl Default for HttpsLayerSettings { - fn default() -> Self { - Self { - session_cache_capacity: 8, - } - } -} - -/// Builder for [`HttpsLayerSettings`] -pub struct HttpsLayerSettingsBuilder(HttpsLayerSettings); - -impl HttpsLayerSettingsBuilder { - /// Sets maximum number of sessions to cache. Session capacity is per session key (domain). - /// Defaults to 8. - pub fn set_session_cache_capacity(&mut self, capacity: usize) { - self.0.session_cache_capacity = capacity; - } - - /// Consumes the builder, returning a new [`HttpsLayerSettings`] - pub fn build(self) -> HttpsLayerSettings { - self.0 - } -} - -/// A stream which may be wrapped with TLS. -pub enum MaybeHttpsStream { - /// A raw HTTP stream. - Http(T), - /// An SSL-wrapped HTTP stream. - Https(SslStream), -} - -impl fmt::Debug for MaybeHttpsStream { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - MaybeHttpsStream::Http(..) => f.pad("Http(..)"), - MaybeHttpsStream::Https(..) => f.pad("Https(..)"), - } - } -} diff --git a/hyper-boring/src/v0.rs b/hyper-boring/src/v0.rs deleted file mode 100644 index dcb9f9ac..00000000 --- a/hyper-boring/src/v0.rs +++ /dev/null @@ -1,345 +0,0 @@ -use crate::cache::{SessionCache, SessionKey}; -use crate::{key_index, HttpsLayerSettings, MaybeHttpsStream}; -use antidote::Mutex; -use boring::error::ErrorStack; -use boring::ssl::{ - ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslRef, - SslSessionCacheMode, -}; -use http0::uri::Scheme; -use hyper0::client::connect::{Connected, Connection}; -use hyper0::client::HttpConnector; -use hyper0::service::Service; -use hyper0::Uri; -use std::error::Error; -use std::future::Future; -use std::net; -use std::pin::Pin; -use std::sync::Arc; -use std::task::{Context, Poll}; -use std::{fmt, io}; -use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; -use tower_layer::Layer; - -/// A Connector using OpenSSL to support `http` and `https` schemes. -#[derive(Clone)] -pub struct HttpsConnector { - http: T, - inner: Inner, -} - -#[cfg(feature = "runtime")] -impl HttpsConnector { - /// Creates a a new `HttpsConnector` using default settings. - /// - /// The Hyper `HttpConnector` is used to perform the TCP socket connection. ALPN is configured to support both - /// HTTP/2 and HTTP/1.1. - /// - /// Requires the `runtime` Cargo feature. - pub fn new() -> Result, ErrorStack> { - let mut http = HttpConnector::new(); - http.enforce_http(false); - - HttpsLayer::new().map(|l| l.layer(http)) - } -} - -impl HttpsConnector -where - S: Service + Send, - S::Error: Into>, - S::Future: Unpin + Send + 'static, - T: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, -{ - /// Creates a new `HttpsConnector`. - /// - /// The session cache configuration of `ssl` will be overwritten. - pub fn with_connector( - http: S, - ssl: SslConnectorBuilder, - ) -> Result, ErrorStack> { - HttpsLayer::with_connector(ssl).map(|l| l.layer(http)) - } - - /// Registers a callback which can customize the configuration of each connection. - /// - /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), - /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] - /// instead. - pub fn set_callback(&mut self, callback: F) - where - F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.callback = Some(Arc::new(callback)); - } - - /// Registers a callback which can customize the `Ssl` of each connection. - pub fn set_ssl_callback(&mut self, callback: F) - where - F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.ssl_callback = Some(Arc::new(callback)); - } -} - -/// A layer which wraps services in an `HttpsConnector`. -pub struct HttpsLayer { - inner: Inner, -} - -#[derive(Clone)] -struct Inner { - ssl: SslConnector, - cache: Arc>, - callback: Option, - ssl_callback: Option, -} - -type Callback = - Arc Result<(), ErrorStack> + Sync + Send>; -type SslCallback = Arc Result<(), ErrorStack> + Sync + Send>; - -impl HttpsLayer { - /// Creates a new `HttpsLayer` with default settings. - /// - /// ALPN is configured to support both HTTP/1 and HTTP/1.1. - pub fn new() -> Result { - let mut ssl = SslConnector::builder(SslMethod::tls())?; - - ssl.set_alpn_protos(b"\x02h2\x08http/1.1")?; - - Self::with_connector(ssl) - } - - /// Creates a new `HttpsLayer`. - /// - /// The session cache configuration of `ssl` will be overwritten. - pub fn with_connector(ssl: SslConnectorBuilder) -> Result { - Self::with_connector_and_settings(ssl, Default::default()) - } - - /// Creates a new `HttpsLayer` with settings - pub fn with_connector_and_settings( - mut ssl: SslConnectorBuilder, - settings: HttpsLayerSettings, - ) -> Result { - let cache = Arc::new(Mutex::new(SessionCache::with_capacity( - settings.session_cache_capacity, - ))); - - ssl.set_session_cache_mode(SslSessionCacheMode::CLIENT); - - ssl.set_new_session_callback({ - let cache = cache.clone(); - move |ssl, session| { - if let Some(key) = key_index().ok().and_then(|idx| ssl.ex_data(idx)) { - cache.lock().insert(key.clone(), session); - } - } - }); - - Ok(HttpsLayer { - inner: Inner { - ssl: ssl.build(), - cache, - callback: None, - ssl_callback: None, - }, - }) - } - - /// Registers a callback which can customize the configuration of each connection. - /// - /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), - /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] - /// instead. - pub fn set_callback(&mut self, callback: F) - where - F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.callback = Some(Arc::new(callback)); - } - - /// Registers a callback which can customize the `Ssl` of each connection. - pub fn set_ssl_callback(&mut self, callback: F) - where - F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.ssl_callback = Some(Arc::new(callback)); - } -} - -impl Layer for HttpsLayer { - type Service = HttpsConnector; - - fn layer(&self, inner: S) -> HttpsConnector { - HttpsConnector { - http: inner, - inner: self.inner.clone(), - } - } -} - -impl Inner { - fn setup_ssl(&self, uri: &Uri, host: &str) -> Result { - let mut conf = self.ssl.configure()?; - - if let Some(ref callback) = self.callback { - callback(&mut conf, uri)?; - } - - let key = SessionKey { - host: host.to_string(), - port: uri.port_u16().unwrap_or(443), - }; - - if let Some(session) = self.cache.lock().get(&key) { - unsafe { - conf.set_session(&session)?; - } - } - - let idx = key_index()?; - conf.set_ex_data(idx, key); - - let mut ssl = conf.into_ssl(host)?; - - if let Some(ref ssl_callback) = self.ssl_callback { - ssl_callback(&mut ssl, uri)?; - } - - Ok(ssl) - } -} - -impl Service for HttpsConnector -where - S: Service + Send, - S::Error: Into>, - S::Future: Unpin + Send + 'static, - S::Response: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, -{ - type Response = MaybeHttpsStream; - type Error = Box; - #[allow(clippy::type_complexity)] - type Future = Pin> + Send>>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.http.poll_ready(cx).map_err(Into::into) - } - - fn call(&mut self, uri: Uri) -> Self::Future { - let is_tls_scheme = uri - .scheme() - .map(|s| s == &Scheme::HTTPS || s.as_str() == "wss") - .unwrap_or(false); - - let tls_setup = if is_tls_scheme { - Some((self.inner.clone(), uri.clone())) - } else { - None - }; - - let connect = self.http.call(uri); - - let f = async { - let conn = connect.await.map_err(Into::into)?; - - let (inner, uri) = match tls_setup { - Some((inner, uri)) => (inner, uri), - None => return Ok(MaybeHttpsStream::Http(conn)), - }; - - let mut host = uri.host().ok_or("URI missing host")?; - - // If `host` is an IPv6 address, we must strip away the square brackets that surround - // it (otherwise, boring will fail to parse the host as an IP address, eventually - // causing the handshake to fail due a hostname verification error). - if !host.is_empty() { - let last = host.len() - 1; - let mut chars = host.chars(); - - if let (Some('['), Some(']')) = (chars.next(), chars.last()) { - if host[1..last].parse::().is_ok() { - host = &host[1..last]; - } - } - } - - let ssl = inner.setup_ssl(&uri, host)?; - let stream = tokio_boring::SslStreamBuilder::new(ssl, conn) - .connect() - .await?; - - Ok(MaybeHttpsStream::Https(stream)) - }; - - Box::pin(f) - } -} - -impl Connection for MaybeHttpsStream -where - T: Connection, -{ - fn connected(&self) -> Connected { - match self { - MaybeHttpsStream::Http(s) => s.connected(), - MaybeHttpsStream::Https(s) => { - let mut connected = s.get_ref().connected(); - - if s.ssl().selected_alpn_protocol() == Some(b"h2") { - connected = connected.negotiated_h2(); - } - - connected - } - } - } -} - -impl AsyncRead for MaybeHttpsStream -where - T: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_read( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &mut ReadBuf<'_>, - ) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_read(ctx, buf), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_read(ctx, buf), - } - } -} - -impl AsyncWrite for MaybeHttpsStream -where - T: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_write( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_write(ctx, buf), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_write(ctx, buf), - } - } - - fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_flush(ctx), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_flush(ctx), - } - } - - fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(s) => Pin::new(s).poll_shutdown(ctx), - MaybeHttpsStream::Https(s) => Pin::new(s).poll_shutdown(ctx), - } - } -} diff --git a/hyper-boring/src/v1.rs b/hyper-boring/src/v1.rs deleted file mode 100644 index 45654c51..00000000 --- a/hyper-boring/src/v1.rs +++ /dev/null @@ -1,364 +0,0 @@ -use crate::cache::{SessionCache, SessionKey}; -use crate::{key_index, HttpsLayerSettings, MaybeHttpsStream}; -use antidote::Mutex; -use boring::error::ErrorStack; -use boring::ssl::{ - ConnectConfiguration, Ssl, SslConnector, SslConnectorBuilder, SslMethod, SslRef, - SslSessionCacheMode, -}; -use http1::uri::Scheme; -use http1::Uri; -use hyper1::rt::{Read, ReadBufCursor, Write}; -use hyper_util::client::legacy::connect::{Connected, Connection, HttpConnector}; -use hyper_util::rt::TokioIo; -use std::error::Error; -use std::fmt; -use std::future::Future; -use std::pin::Pin; -use std::sync::Arc; -use std::task::{Context, Poll}; -use std::{io, net}; -use tokio::io::{AsyncRead, AsyncWrite}; -use tokio::net::TcpStream; -#[cfg(all(feature = "runtime", feature = "hyper1-runtime"))] -use tower::util::MapResponse; -#[cfg(all(feature = "runtime", feature = "hyper1-runtime"))] -use tower::ServiceExt; -use tower_layer::Layer; -use tower_service::Service; - -/// A Connector using BoringSSL to support `http` and `https` schemes. -#[derive(Clone)] -pub struct HttpsConnector { - http: T, - inner: Inner, -} - -/// Specialized version of [`HttpConnector`] with responses wrapped with -/// [`TokioIo::new`] in order to bring back compatibility with Tokio traits. -pub type TokioHttpConnector = - MapResponse) -> TokioIo>>; - -#[cfg(all(feature = "runtime", feature = "hyper1-runtime"))] -impl HttpsConnector { - /// Creates a a new `HttpsConnector` using default settings. - /// - /// The Hyper `HttpConnector` is used to perform the TCP socket connection. ALPN is configured to support both - /// HTTP/2 and HTTP/1.1. - /// - /// Requires the `runtime` Cargo feature. - pub fn new() -> Result { - let mut http = HttpConnector::new(); - http.enforce_http(false); - - HttpsLayer::new().map(|l| l.layer(http.map_response(TokioIo::new as _))) - } -} - -impl HttpsConnector -where - S: Service + Send, - S::Error: Into>, - S::Future: Unpin + Send + 'static, - T: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, -{ - /// Creates a new `HttpsConnector`. - /// - /// The session cache configuration of `ssl` will be overwritten. - /// - /// If the provided service's response type does not fit the trait - /// requirements because it is closer to the Hyper ecosystem than the Tokio - /// one, wrapping your responses with [`TokioIo`] should work. - pub fn with_connector( - http: S, - ssl: SslConnectorBuilder, - ) -> Result, ErrorStack> { - HttpsLayer::with_connector(ssl).map(|l| l.layer(http)) - } - - /// Registers a callback which can customize the configuration of each connection. - /// - /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), - /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] - /// instead. - pub fn set_callback(&mut self, callback: F) - where - F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.callback = Some(Arc::new(callback)); - } - - /// Registers a callback which can customize the `Ssl` of each connection. - pub fn set_ssl_callback(&mut self, callback: F) - where - F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.ssl_callback = Some(Arc::new(callback)); - } -} - -/// A layer which wraps services in an `HttpsConnector`. -pub struct HttpsLayer { - inner: Inner, -} - -#[derive(Clone)] -struct Inner { - ssl: SslConnector, - cache: Arc>, - callback: Option, - ssl_callback: Option, -} - -type Callback = - Arc Result<(), ErrorStack> + Sync + Send>; -type SslCallback = Arc Result<(), ErrorStack> + Sync + Send>; - -impl HttpsLayer { - /// Creates a new `HttpsLayer` with default settings. - /// - /// ALPN is configured to support both HTTP/1 and HTTP/1.1. - pub fn new() -> Result { - let mut ssl = SslConnector::builder(SslMethod::tls())?; - - ssl.set_alpn_protos(b"\x02h2\x08http/1.1")?; - - Self::with_connector(ssl) - } - - /// Creates a new `HttpsLayer`. - /// - /// The session cache configuration of `ssl` will be overwritten. - pub fn with_connector(ssl: SslConnectorBuilder) -> Result { - Self::with_connector_and_settings(ssl, Default::default()) - } - - /// Creates a new `HttpsLayer` with settings - pub fn with_connector_and_settings( - mut ssl: SslConnectorBuilder, - settings: HttpsLayerSettings, - ) -> Result { - let cache = Arc::new(Mutex::new(SessionCache::with_capacity( - settings.session_cache_capacity, - ))); - - ssl.set_session_cache_mode(SslSessionCacheMode::CLIENT); - - ssl.set_new_session_callback({ - let cache = cache.clone(); - move |ssl, session| { - if let Some(key) = key_index().ok().and_then(|idx| ssl.ex_data(idx)) { - cache.lock().insert(key.clone(), session); - } - } - }); - - Ok(HttpsLayer { - inner: Inner { - ssl: ssl.build(), - cache, - callback: None, - ssl_callback: None, - }, - }) - } - - /// Registers a callback which can customize the configuration of each connection. - /// - /// Unsuitable to change verify hostflags (with `config.param_mut().set_hostflags(…)`), - /// as they are reset after the callback is executed. Use [`Self::set_ssl_callback`] - /// instead. - pub fn set_callback(&mut self, callback: F) - where - F: Fn(&mut ConnectConfiguration, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.callback = Some(Arc::new(callback)); - } - - /// Registers a callback which can customize the `Ssl` of each connection. - pub fn set_ssl_callback(&mut self, callback: F) - where - F: Fn(&mut SslRef, &Uri) -> Result<(), ErrorStack> + 'static + Sync + Send, - { - self.inner.ssl_callback = Some(Arc::new(callback)); - } -} - -impl Layer for HttpsLayer { - type Service = HttpsConnector; - - fn layer(&self, inner: S) -> HttpsConnector { - HttpsConnector { - http: inner, - inner: self.inner.clone(), - } - } -} - -impl Inner { - fn setup_ssl(&self, uri: &Uri, host: &str) -> Result { - let mut conf = self.ssl.configure()?; - - if let Some(ref callback) = self.callback { - callback(&mut conf, uri)?; - } - - let key = SessionKey { - host: host.to_string(), - port: uri.port_u16().unwrap_or(443), - }; - - if let Some(session) = self.cache.lock().get(&key) { - unsafe { - conf.set_session(&session)?; - } - } - - let idx = key_index()?; - conf.set_ex_data(idx, key); - - let mut ssl = conf.into_ssl(host)?; - - if let Some(ref ssl_callback) = self.ssl_callback { - ssl_callback(&mut ssl, uri)?; - } - - Ok(ssl) - } -} - -impl Service for HttpsConnector -where - S: Service + Send, - S::Error: Into>, - S::Future: Unpin + Send + 'static, - T: AsyncRead + AsyncWrite + Connection + Unpin + fmt::Debug + Sync + Send + 'static, -{ - type Response = MaybeHttpsStream; - type Error = Box; - #[allow(clippy::type_complexity)] - type Future = Pin> + Send>>; - - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.http.poll_ready(cx).map_err(Into::into) - } - - fn call(&mut self, uri: Uri) -> Self::Future { - let is_tls_scheme = uri - .scheme() - .map(|s| s == &Scheme::HTTPS || s.as_str() == "wss") - .unwrap_or(false); - - let tls_setup = if is_tls_scheme { - Some((self.inner.clone(), uri.clone())) - } else { - None - }; - - let connect = self.http.call(uri); - - let f = async { - let conn = connect.await.map_err(Into::into)?; - - let (inner, uri) = match tls_setup { - Some((inner, uri)) => (inner, uri), - None => return Ok(MaybeHttpsStream::Http(conn)), - }; - - let mut host = uri.host().ok_or("URI missing host")?; - - // If `host` is an IPv6 address, we must strip away the square brackets that surround - // it (otherwise, boring will fail to parse the host as an IP address, eventually - // causing the handshake to fail due a hostname verification error). - if !host.is_empty() { - let last = host.len() - 1; - let mut chars = host.chars(); - - if let (Some('['), Some(']')) = (chars.next(), chars.last()) { - if host[1..last].parse::().is_ok() { - host = &host[1..last]; - } - } - } - - let ssl = inner.setup_ssl(&uri, host)?; - let stream = tokio_boring::SslStreamBuilder::new(ssl, conn) - .connect() - .await?; - - Ok(MaybeHttpsStream::Https(stream)) - }; - - Box::pin(f) - } -} - -impl Connection for MaybeHttpsStream -where - T: Connection, -{ - fn connected(&self) -> Connected { - match self { - MaybeHttpsStream::Http(s) => s.connected(), - MaybeHttpsStream::Https(s) => { - let mut connected = s.get_ref().connected(); - - if s.ssl().selected_alpn_protocol() == Some(b"h2") { - connected = connected.negotiated_h2(); - } - - connected - } - } - } -} - -impl Read for MaybeHttpsStream -where - T: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_read( - mut self: Pin<&mut Self>, - cx: &mut Context<'_>, - buf: ReadBufCursor<'_>, - ) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(inner) => Pin::new(&mut TokioIo::new(inner)).poll_read(cx, buf), - MaybeHttpsStream::Https(inner) => Pin::new(&mut TokioIo::new(inner)).poll_read(cx, buf), - } - } -} - -impl Write for MaybeHttpsStream -where - T: AsyncRead + AsyncWrite + Unpin, -{ - fn poll_write( - mut self: Pin<&mut Self>, - ctx: &mut Context<'_>, - buf: &[u8], - ) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(inner) => { - Pin::new(&mut TokioIo::new(inner)).poll_write(ctx, buf) - } - MaybeHttpsStream::Https(inner) => { - Pin::new(&mut TokioIo::new(inner)).poll_write(ctx, buf) - } - } - } - - fn poll_flush(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(inner) => Pin::new(&mut TokioIo::new(inner)).poll_flush(ctx), - MaybeHttpsStream::Https(inner) => Pin::new(&mut TokioIo::new(inner)).poll_flush(ctx), - } - } - - fn poll_shutdown(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll> { - match &mut *self { - MaybeHttpsStream::Http(inner) => Pin::new(&mut TokioIo::new(inner)).poll_shutdown(ctx), - MaybeHttpsStream::Https(inner) => Pin::new(&mut TokioIo::new(inner)).poll_shutdown(ctx), - } - } -} diff --git a/hyper-boring/tests/test/cert.pem b/hyper-boring/tests/test/cert.pem deleted file mode 100644 index 032fe60e..00000000 --- a/hyper-boring/tests/test/cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG -A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 -IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub -3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ -mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 -TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI -ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y -euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq -hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM -6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE -wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY -oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 -dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp -HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== ------END CERTIFICATE----- diff --git a/hyper-boring/tests/test/key.pem b/hyper-boring/tests/test/key.pem deleted file mode 100644 index d381795d..00000000 --- a/hyper-boring/tests/test/key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo9CWMRLMXo1CF -/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 -kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS -wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM -jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT -Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt -OzboKgs1AgMBAAECggEBAKLj6IOJBKXolczpzb8UkyAjAkGBektcseV07gelJ/fk -3z0LuWPv5p12E/HlXB24vU2x/ikUbbP3eMsawRzDEahQqmNmPEkYAYUAy/Qpi9GN -DYvn3LqDec4jVgeQKS+p9H2DzUpTogp8zR2//yzbuWBg2+F//xh7vU0S0RQCziPM -x7RSBgbhxSfChfEJbS2sDnzfh0jRQmoY95iFv7puet1FJtzdZ4fgCd1RqmC2lFM5 -H0eZtN/Cz19lieVs0b996DErdEBqClVZO00eYbRozCDaBzRU3ybB/dMrGJxhkkXm -wb3kWMtziH9qOYsostuHIFu8eKFLloKxFnq2R4DGxOECgYEA2KUIZISOeGJSBcLJ -JAUK2gvgXPNo4HHWIwOA9xeN3ZJlsnPlffXQNnm6t1st1V2gfMm9I2n0m/F0y2B/ -n/XGSa8bghfPA9l0c2h58lkL3JQJR/paa8ycTz+YZPrznEyN7Qa0RrJXUvZv9lQL -Hc3+FHcSHgMqDV2f2bHAEu9YGi0CgYEAx6VEIPNvrHFgjo/jk1RTuk+m0xEWQsZL -Cs+izQMr2TaeJn8LG+93AvFuYn0J0nT3WuStLPrUg8i4IhSS6lf1tId5ivIZPm4r -YwMyblBJXhnHbk7Uqodjfw/3s6V2HAu++B7hTdyVr9DFuST9uv4m8bkPV8rfX1jE -I2rAPVWvgikCgYB+wNAQP547wQrMZBLbCDg5KwmyWJfb+b6X7czexOEz6humNTjo -YZHYzY/5B1fhpk3ntQD8X1nGg5caBvOk21+QbOtjShrM3cXMYCw5JvBRtitX+Zo9 -yBEMLOE0877ki8XeEDYZxu5gk98d+D4oygUGZEQtWxyXhVepPt5qNa8OYQKBgQDH -RVgZI6KFlqzv3wMh3PutbS9wYQ+9GrtwUQuIYe/0YSW9+vSVr5E0qNKrD28sV39F -hBauXLady0yvB6YUrjMbPFW+sCMuQzyfGWPO4+g3OrfqjFiM1ZIkE0YEU9Tt7XNx -qTDtTI1D7bhNMnTnniI1B6ge0und+3XafAThs5L48QKBgQCTTpfqMt8kU3tcI9sf -0MK03y7kA76d5uw0pZbWFy7KI4qnzWutCzb+FMPWWsoFtLJLPZy//u/ZCUVFVa4d -0Y/ASNQIESVPXFLAltlLo4MSmsg1vCBsbviEEaPeEjvMrgki93pYtd/aOSgkYC1T -mEq154s5rmqh+h+XRIf7Au0SLw== ------END PRIVATE KEY----- diff --git a/hyper-boring/tests/test/root-ca.pem b/hyper-boring/tests/test/root-ca.pem deleted file mode 100644 index 4ec2f538..00000000 --- a/hyper-boring/tests/test/root-ca.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G -ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV -eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr -7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92 -aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc -klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN -XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow -DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn -BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv -Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3 -AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy -OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3 -mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9 -GA== ------END CERTIFICATE----- diff --git a/hyper-boring/tests/v0.rs b/hyper-boring/tests/v0.rs deleted file mode 100644 index 0a681e55..00000000 --- a/hyper-boring/tests/v0.rs +++ /dev/null @@ -1,158 +0,0 @@ -#![cfg(feature = "hyper0")] - -use boring::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod}; -use futures::StreamExt; -use hyper0::client::HttpConnector; -use hyper0::server::conn::Http; -use hyper0::{service, Response}; -use hyper0::{Body, Client}; -use hyper_boring::v0::HttpsConnector; -use std::convert::Infallible; -use std::{io, iter}; -use tokio::net::TcpListener; - -#[tokio::test] -#[cfg(feature = "runtime")] -async fn google() { - let ssl = HttpsConnector::new().unwrap(); - let client = Client::builder() - .pool_max_idle_per_host(0) - .build::<_, Body>(ssl); - - for _ in 0..3 { - let resp = client - .get("https://www.google.com".parse().unwrap()) - .await - .expect("connection should succeed"); - let mut body = resp.into_body(); - while body.next().await.transpose().unwrap().is_some() {} - } -} - -#[tokio::test] -async fn localhost() { - let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = listener.local_addr().unwrap(); - let port = addr.port(); - - let server = async move { - let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - acceptor.set_session_id_context(b"test").unwrap(); - acceptor - .set_private_key_file("tests/test/key.pem", SslFiletype::PEM) - .unwrap(); - acceptor - .set_certificate_chain_file("tests/test/cert.pem") - .unwrap(); - let acceptor = acceptor.build(); - - for _ in 0..3 { - let stream = listener.accept().await.unwrap().0; - let stream = tokio_boring::accept(&acceptor, stream).await.unwrap(); - - let service = - service::service_fn(|_| async { Ok::<_, io::Error>(Response::new(Body::empty())) }); - - Http::new() - .http1_keep_alive(false) - .serve_connection(stream, service) - .await - .unwrap(); - } - }; - tokio::spawn(server); - - let resolver = - tower::service_fn(move |_name| async move { Ok::<_, Infallible>(iter::once(addr)) }); - - let mut connector = HttpConnector::new_with_resolver(resolver); - - connector.enforce_http(false); - - let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - - ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); - - use std::fs::File; - use std::io::Write; - - let file = File::create("../target/keyfile.log").unwrap(); - ssl.set_keylog_callback(move |_, line| { - let _ = writeln!(&file, "{}", line); - }); - - let ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); - let client = Client::builder().build::<_, Body>(ssl); - - for _ in 0..3 { - let resp = client - .get(format!("https://foobar.com:{}", port).parse().unwrap()) - .await - .unwrap(); - assert!(resp.status().is_success(), "{}", resp.status()); - let mut body = resp.into_body(); - while body.next().await.transpose().unwrap().is_some() {} - } -} - -#[tokio::test] -async fn alpn_h2() { - use boring::ssl::{self, AlpnError}; - - let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = listener.local_addr().unwrap(); - let port = addr.port(); - - let server = async move { - let mut acceptor = SslAcceptor::mozilla_modern(SslMethod::tls()).unwrap(); - acceptor - .set_certificate_chain_file("tests/test/cert.pem") - .unwrap(); - acceptor - .set_private_key_file("tests/test/key.pem", SslFiletype::PEM) - .unwrap(); - acceptor.set_alpn_select_callback(|_, client| { - ssl::select_next_proto(b"\x02h2", client).ok_or(AlpnError::NOACK) - }); - let acceptor = acceptor.build(); - - let stream = listener.accept().await.unwrap().0; - let stream = tokio_boring::accept(&acceptor, stream).await.unwrap(); - assert_eq!(stream.ssl().selected_alpn_protocol().unwrap(), b"h2"); - - let service = - service::service_fn(|_| async { Ok::<_, io::Error>(Response::new(Body::empty())) }); - - Http::new() - .http2_only(true) - .serve_connection(stream, service) - .await - .unwrap(); - }; - tokio::spawn(server); - - let resolver = - tower::service_fn(move |_name| async move { Ok::<_, Infallible>(iter::once(addr)) }); - - let mut connector = HttpConnector::new_with_resolver(resolver); - - connector.enforce_http(false); - - let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - - ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); - - let mut ssl = HttpsConnector::with_connector(connector, ssl).unwrap(); - - ssl.set_ssl_callback(|ssl, _| ssl.set_alpn_protos(b"\x02h2\x08http/1.1")); - - let client = Client::builder().build::<_, Body>(ssl); - - let resp = client - .get(format!("https://foobar.com:{}", port).parse().unwrap()) - .await - .unwrap(); - assert!(resp.status().is_success(), "{}", resp.status()); - let mut body = resp.into_body(); - while body.next().await.transpose().unwrap().is_some() {} -} diff --git a/hyper-boring/tests/v1.rs b/hyper-boring/tests/v1.rs deleted file mode 100644 index 3e8273dd..00000000 --- a/hyper-boring/tests/v1.rs +++ /dev/null @@ -1,162 +0,0 @@ -#![cfg(feature = "hyper1")] - -use boring::ssl::{SslAcceptor, SslConnector, SslFiletype, SslMethod}; -use bytes::Bytes; -use futures::StreamExt; -use http_body_util::{BodyStream, Empty}; -use hyper1::{service, Response}; -use hyper_boring::HttpsConnector; -use hyper_util::client::legacy::connect::HttpConnector; -use hyper_util::client::legacy::Client; -use hyper_util::rt::{TokioExecutor, TokioIo}; -use std::convert::Infallible; -use std::{io, iter}; -use tokio::net::TcpListener; -use tower::ServiceExt; - -#[tokio::test] -async fn google() { - let ssl = HttpsConnector::new().unwrap(); - let client = Client::builder(TokioExecutor::new()) - .pool_max_idle_per_host(0) - .build::<_, Empty>(ssl); - - for _ in 0..3 { - let resp = client - .get("https://www.google.com".parse().unwrap()) - .await - .expect("connection should succeed"); - let mut body = BodyStream::new(resp.into_body()); - while body.next().await.transpose().unwrap().is_some() {} - } -} - -#[tokio::test] -async fn localhost() { - let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = listener.local_addr().unwrap(); - let port = addr.port(); - - let server = async move { - let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - acceptor.set_session_id_context(b"test").unwrap(); - acceptor - .set_private_key_file("tests/test/key.pem", SslFiletype::PEM) - .unwrap(); - acceptor - .set_certificate_chain_file("tests/test/cert.pem") - .unwrap(); - let acceptor = acceptor.build(); - - for _ in 0..3 { - let stream = listener.accept().await.unwrap().0; - let stream = tokio_boring::accept(&acceptor, stream).await.unwrap(); - - let service = service::service_fn(|_| async { - Ok::<_, io::Error>(Response::new(>::new())) - }); - - hyper1::server::conn::http1::Builder::new() - .keep_alive(false) - .serve_connection(TokioIo::new(stream), service) - .await - .unwrap(); - } - }; - tokio::spawn(server); - - let resolver = - tower::service_fn(move |_name| async move { Ok::<_, Infallible>(iter::once(addr)) }); - - let mut connector = HttpConnector::new_with_resolver(resolver); - - connector.enforce_http(false); - - let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - - ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); - - use std::fs::File; - use std::io::Write; - - let file = File::create("../target/keyfile.log").unwrap(); - ssl.set_keylog_callback(move |_, line| { - let _ = writeln!(&file, "{}", line); - }); - - let ssl = HttpsConnector::with_connector(connector.map_response(TokioIo::new), ssl).unwrap(); - let client = Client::builder(TokioExecutor::new()).build::<_, Empty>(ssl); - - for _ in 0..3 { - let resp = client - .get(format!("https://foobar.com:{}", port).parse().unwrap()) - .await - .unwrap(); - assert!(resp.status().is_success(), "{}", resp.status()); - let mut body = BodyStream::new(resp.into_body()); - while body.next().await.transpose().unwrap().is_some() {} - } -} - -#[tokio::test] -async fn alpn_h2() { - use boring::ssl::{self, AlpnError}; - - let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); - let addr = listener.local_addr().unwrap(); - let port = addr.port(); - - let server = async move { - let mut acceptor = SslAcceptor::mozilla_modern(SslMethod::tls()).unwrap(); - acceptor - .set_certificate_chain_file("tests/test/cert.pem") - .unwrap(); - acceptor - .set_private_key_file("tests/test/key.pem", SslFiletype::PEM) - .unwrap(); - acceptor.set_alpn_select_callback(|_, client| { - ssl::select_next_proto(b"\x02h2", client).ok_or(AlpnError::NOACK) - }); - let acceptor = acceptor.build(); - - let stream = listener.accept().await.unwrap().0; - let stream = tokio_boring::accept(&acceptor, stream).await.unwrap(); - assert_eq!(stream.ssl().selected_alpn_protocol().unwrap(), b"h2"); - - let service = service::service_fn(|_| async { - Ok::<_, io::Error>(Response::new(>::new())) - }); - - hyper1::server::conn::http2::Builder::new(TokioExecutor::new()) - .serve_connection(TokioIo::new(stream), service) - .await - .unwrap(); - }; - tokio::spawn(server); - - let resolver = - tower::service_fn(move |_name| async move { Ok::<_, Infallible>(iter::once(addr)) }); - - let mut connector = HttpConnector::new_with_resolver(resolver); - - connector.enforce_http(false); - - let mut ssl = SslConnector::builder(SslMethod::tls()).unwrap(); - - ssl.set_ca_file("tests/test/root-ca.pem").unwrap(); - - let mut ssl = - HttpsConnector::with_connector(connector.map_response(TokioIo::new), ssl).unwrap(); - - ssl.set_ssl_callback(|ssl, _| ssl.set_alpn_protos(b"\x02h2\x08http/1.1")); - - let client = Client::builder(TokioExecutor::new()).build::<_, Empty>(ssl); - - let resp = client - .get(format!("https://foobar.com:{}", port).parse().unwrap()) - .await - .unwrap(); - assert!(resp.status().is_success(), "{}", resp.status()); - let mut body = BodyStream::new(resp.into_body()); - while body.next().await.transpose().unwrap().is_some() {} -}