-
Notifications
You must be signed in to change notification settings - Fork 717
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into cbmc_6_minimal
- Loading branch information
Showing
9 changed files
with
415 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
[package] | ||
name = "s2n-tls-hyper" | ||
description = "A compatbility crate allowing s2n-tls to be used with the hyper HTTP library" | ||
version = "0.0.1" | ||
authors = ["AWS s2n"] | ||
edition = "2021" | ||
rust-version = "1.63.0" | ||
repository = "https://github.com/aws/s2n-tls" | ||
license = "Apache-2.0" | ||
|
||
[features] | ||
default = [] | ||
|
||
[dependencies] | ||
s2n-tls = { version = "=0.2.9", path = "../s2n-tls" } | ||
s2n-tls-tokio = { version = "=0.2.9", path = "../s2n-tls-tokio" } | ||
hyper = { version = "1" } | ||
hyper-util = { version = "0.1", features = ["client-legacy", "tokio", "http1"] } | ||
tower-service = { version = "0.3" } | ||
http = { version= "1" } | ||
|
||
[dev-dependencies] | ||
tokio = { version = "1", features = ["macros", "test-util"] } | ||
http-body-util = "0.1" | ||
bytes = "1" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
`s2n-tls-hyper` provides compatibility structs for [hyper](https://hyper.rs/), allowing s2n-tls to be used as the underlying TLS implementation with hyper clients. | ||
|
||
This crate is currently being developed and is unstable. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use crate::{error::Error, stream::MaybeHttpsStream}; | ||
use http::uri::Uri; | ||
use hyper::rt::{Read, Write}; | ||
use hyper_util::{ | ||
client::legacy::connect::{Connection, HttpConnector}, | ||
rt::TokioIo, | ||
}; | ||
use s2n_tls::{config::Config, connection}; | ||
use s2n_tls_tokio::TlsConnector; | ||
use std::{ | ||
future::Future, | ||
pin::Pin, | ||
task::{Context, Poll}, | ||
}; | ||
use tower_service::Service; | ||
|
||
/// hyper-compatible connector used to negotiate HTTPS. | ||
/// | ||
/// hyper clients use a connector to send and receive HTTP requests over an underlying IO stream. By | ||
/// default, hyper provides `hyper_util::client::legacy::connect::HttpConnector` for this purpose, | ||
/// which sends and receives requests over TCP. The `HttpsConnector` struct wraps an HTTP connector, | ||
/// and uses it to negotiate TLS when the HTTPS scheme is in use. | ||
#[derive(Clone)] | ||
pub struct HttpsConnector<Http, Builder = Config> { | ||
http: Http, | ||
conn_builder: Builder, | ||
} | ||
|
||
impl<Builder> HttpsConnector<HttpConnector, Builder> | ||
where | ||
Builder: connection::Builder, | ||
<Builder as connection::Builder>::Output: Unpin, | ||
{ | ||
/// Creates a new `HttpsConnector`. | ||
/// | ||
/// `conn_builder` will be used to produce the s2n-tls Connections used for negotiating HTTPS, | ||
/// which can be an `s2n_tls::config::Config` or other `s2n_tls::connection::Builder`. | ||
/// | ||
/// This API creates an `HttpsConnector` using the default hyper `HttpConnector`. To use an | ||
/// existing HTTP connector, use `HttpsConnector::new_with_http()`. | ||
pub fn new(conn_builder: Builder) -> HttpsConnector<HttpConnector, Builder> { | ||
let mut http = HttpConnector::new(); | ||
|
||
// By default, the `HttpConnector` only allows the HTTP URI scheme to be used. To negotiate | ||
// HTTP over TLS via the HTTPS scheme, `enforce_http` must be disabled. | ||
http.enforce_http(false); | ||
|
||
Self { http, conn_builder } | ||
} | ||
} | ||
|
||
impl<Http, Builder> HttpsConnector<Http, Builder> | ||
where | ||
Builder: connection::Builder, | ||
<Builder as connection::Builder>::Output: Unpin, | ||
{ | ||
/// Creates a new `HttpsConnector`. | ||
/// | ||
/// `conn_builder` will be used to produce the s2n-tls Connections used for negotiating HTTPS, | ||
/// which can be an `s2n_tls::config::Config` or other `s2n_tls::connection::Builder`. | ||
/// | ||
/// This API allows an `HttpsConnector` to be constructed with an existing HTTP connector, as follows: | ||
/// ``` | ||
/// use s2n_tls_hyper::connector::HttpsConnector; | ||
/// use s2n_tls::config::Config; | ||
/// use hyper_util::client::legacy::connect::HttpConnector; | ||
/// | ||
/// let mut http = HttpConnector::new(); | ||
/// | ||
/// // Ensure that the HTTP connector permits the HTTPS scheme. | ||
/// http.enforce_http(false); | ||
/// | ||
/// let connector = HttpsConnector::new_with_http(http, Config::default()); | ||
/// ``` | ||
/// | ||
/// `HttpsConnector::new()` can be used to create the HTTP connector automatically. | ||
pub fn new_with_http(http: Http, conn_builder: Builder) -> HttpsConnector<Http, Builder> { | ||
Self { http, conn_builder } | ||
} | ||
} | ||
|
||
// hyper connectors MUST implement `hyper_util::client::legacy::connect::Connect`, which is an alias | ||
// for the `tower_service::Service` trait where `Service` is implemented for `http::uri::Uri`, and | ||
// `Service::Response` implements traits for compatibility with hyper: | ||
// https://docs.rs/hyper-util/latest/hyper_util/client/legacy/connect/trait.Connect.html | ||
// | ||
// The hyper compatibility traits for `Service::Response` are implemented in `MaybeHttpsStream`. | ||
impl<Http, Builder> Service<Uri> for HttpsConnector<Http, Builder> | ||
where | ||
Http: Service<Uri>, | ||
Http::Response: Read + Write + Connection + Unpin + Send + 'static, | ||
Http::Future: Send + 'static, | ||
Http::Error: Into<Box<dyn std::error::Error + Send + Sync>>, | ||
Builder: connection::Builder + Send + Sync + 'static, | ||
<Builder as connection::Builder>::Output: Unpin + Send, | ||
{ | ||
type Response = MaybeHttpsStream<Http::Response, Builder>; | ||
type Error = Error; | ||
type Future = Pin< | ||
Box<dyn Future<Output = Result<MaybeHttpsStream<Http::Response, Builder>, Error>> + Send>, | ||
>; | ||
|
||
fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> { | ||
match self.http.poll_ready(cx) { | ||
Poll::Ready(Ok(())) => Poll::Ready(Ok(())), | ||
Poll::Ready(Err(e)) => Poll::Ready(Err(Error::HttpError(e.into()))), | ||
Poll::Pending => Poll::Pending, | ||
} | ||
} | ||
|
||
fn call(&mut self, req: Uri) -> Self::Future { | ||
// Currently, the only supported stream type is TLS. If the application attempts to | ||
// negotiate HTTP over plain TCP, return an error. | ||
if req.scheme() == Some(&http::uri::Scheme::HTTP) { | ||
return Box::pin(async move { Err(Error::InvalidScheme) }); | ||
} | ||
|
||
let builder = self.conn_builder.clone(); | ||
let host = req.host().unwrap_or("").to_owned(); | ||
let call = self.http.call(req); | ||
Box::pin(async move { | ||
// `HttpsConnector` wraps an HTTP connector that also implements `Service<Uri>`. | ||
// `call()` is invoked on the wrapped connector to get the underlying hyper TCP stream, | ||
// which is converted into a tokio-compatible stream with `hyper_util::rt::TokioIo`. | ||
let tcp = call.await.map_err(|e| Error::HttpError(e.into()))?; | ||
let tcp = TokioIo::new(tcp); | ||
|
||
let connector = TlsConnector::new(builder); | ||
let tls = connector | ||
.connect(&host, tcp) | ||
.await | ||
.map_err(Error::TlsError)?; | ||
|
||
Ok(MaybeHttpsStream::Https(TokioIo::new(tls))) | ||
}) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use bytes::Bytes; | ||
use http_body_util::Empty; | ||
use hyper_util::{client::legacy::Client, rt::TokioExecutor}; | ||
use std::{error::Error as StdError, str::FromStr}; | ||
|
||
#[tokio::test] | ||
async fn test_unsecure_http() -> Result<(), Box<dyn StdError>> { | ||
let connector = HttpsConnector::new(Config::default()); | ||
let client: Client<_, Empty<Bytes>> = | ||
Client::builder(TokioExecutor::new()).build(connector); | ||
|
||
let uri = Uri::from_str("http://www.amazon.com")?; | ||
let error = client.get(uri).await.unwrap_err(); | ||
|
||
// Ensure that an InvalidScheme error is returned when HTTP over TCP is attempted. | ||
let error = error.source().unwrap().downcast_ref::<Error>().unwrap(); | ||
assert!(matches!(error, Error::InvalidScheme)); | ||
|
||
// Ensure that the error can produce a valid message | ||
assert!(!error.to_string().is_empty()); | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use std::fmt::{Display, Formatter}; | ||
|
||
/// Indicates which error occurred. | ||
#[derive(Debug)] | ||
#[non_exhaustive] | ||
pub enum Error { | ||
/// Indicates that the scheme in the URI provided to the `HttpsConnector` is invalid. | ||
InvalidScheme, | ||
/// Indicates that an error occurred in the underlying `HttpConnector`. | ||
HttpError(Box<dyn std::error::Error + Send + Sync>), | ||
/// Indicates that an error occurred in s2n-tls. | ||
TlsError(s2n_tls::error::Error), | ||
} | ||
|
||
impl Display for Error { | ||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { | ||
match self { | ||
Error::InvalidScheme => write!(f, "The provided URI contains an invalid scheme."), | ||
Error::HttpError(err) => write!(f, "{}", err), | ||
Error::TlsError(err) => write!(f, "{}", err), | ||
} | ||
} | ||
} | ||
|
||
impl std::error::Error for Error {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
#![warn(missing_docs)] | ||
|
||
//! This crate provides compatibility structs for the [hyper](https://hyper.rs/) HTTP library, | ||
//! allowing s2n-tls to be used as the underlying TLS implementation to negotiate HTTPS with hyper | ||
//! clients. | ||
//! | ||
//! `s2n-tls-hyper` provides an `HttpsConnector` struct which is compatible with the | ||
//! `hyper_util::client::legacy::Client` builder, allowing hyper clients to be constructed with | ||
//! configurable s2n-tls connections. The following example demonstrates how to construct a hyper | ||
//! client with s2n-tls: | ||
//! | ||
//! ``` | ||
//! use std::str::FromStr; | ||
//! use hyper_util::{ | ||
//! client::legacy::Client, | ||
//! rt::TokioExecutor, | ||
//! }; | ||
//! use s2n_tls_hyper::connector::HttpsConnector; | ||
//! use s2n_tls::config::Config; | ||
//! use bytes::Bytes; | ||
//! use http_body_util::Empty; | ||
//! use http::uri::Uri; | ||
//! | ||
//! // An `HttpsConnector` is built with an `s2n_tls::connection::Builder`, such as an | ||
//! // `s2n_tls::config::Config`, which allows for the underlying TLS connection to be configured. | ||
//! let config = Config::default(); | ||
//! | ||
//! // The `HttpsConnector` wraps hyper's `HttpConnector`. `HttpsConnector::new()` will create | ||
//! // a new `HttpConnector` to wrap. | ||
//! let connector = HttpsConnector::new(Config::default()); | ||
//! | ||
//! // The `HttpsConnector` can then be provided to the hyper Client builder, which can be used to | ||
//! // send HTTP requests over HTTPS by specifying the HTTPS scheme in the URL. | ||
//! let client: Client<_, Empty<Bytes>> = | ||
//! Client::builder(TokioExecutor::new()).build(connector); | ||
//! ``` | ||
/// Provides the `HttpsConnector` struct. | ||
pub mod connector; | ||
|
||
/// Provides errors returned by s2n-tls-hyper. | ||
pub mod error; | ||
|
||
mod stream; |
Oops, something went wrong.