Bug 1909581 - Upgrade warp to 0.3.7. r=supply-chain-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D217534
This commit is contained in:
Mike Hommey
2024-07-24 20:46:31 +00:00
parent 04829b30d6
commit 4d6bd24c4d
32 changed files with 1720 additions and 279 deletions

View File

@@ -95,11 +95,6 @@ git = "https://github.com/mozilla/neqo"
tag = "v0.8.1" tag = "v0.8.1"
replace-with = "vendored-sources" replace-with = "vendored-sources"
[source."git+https://github.com/seanmonstar/warp?rev=9d081461ae1167eb321585ce424f4fef6cf0092b"]
git = "https://github.com/seanmonstar/warp"
rev = "9d081461ae1167eb321585ce424f4fef6cf0092b"
replace-with = "vendored-sources"
[source."git+https://github.com/servo/unicode-bidi?rev=ca612daf1c08c53abe07327cb3e6ef6e0a760f0c"] [source."git+https://github.com/servo/unicode-bidi?rev=ca612daf1c08c53abe07327cb3e6ef6e0a760f0c"]
git = "https://github.com/servo/unicode-bidi" git = "https://github.com/servo/unicode-bidi"
rev = "ca612daf1c08c53abe07327cb3e6ef6e0a760f0c" rev = "ca612daf1c08c53abe07327cb3e6ef6e0a760f0c"

6
Cargo.lock generated
View File

@@ -6513,8 +6513,9 @@ dependencies = [
[[package]] [[package]]
name = "warp" name = "warp"
version = "0.3.6" version = "0.3.7"
source = "git+https://github.com/seanmonstar/warp?rev=9d081461ae1167eb321585ce424f4fef6cf0092b#9d081461ae1167eb321585ce424f4fef6cf0092b" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4378d202ff965b011c64817db11d5829506d3404edeadb61f190d111da3f231c"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-channel", "futures-channel",
@@ -6532,7 +6533,6 @@ dependencies = [
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"tokio", "tokio",
"tokio-stream",
"tokio-util", "tokio-util",
"tower-service", "tower-service",
"tracing", "tracing",

View File

@@ -210,8 +210,6 @@ icu_capi = { path = "intl/icu_capi" }
icu_segmenter_data = { path = "intl/icu_segmenter_data" } icu_segmenter_data = { path = "intl/icu_segmenter_data" }
libudev-sys = { path = "dom/webauthn/libudev-sys" } libudev-sys = { path = "dom/webauthn/libudev-sys" }
midir = { git = "https://github.com/mozilla/midir.git", rev = "85156e360a37d851734118104619f86bd18e94c6" } midir = { git = "https://github.com/mozilla/midir.git", rev = "85156e360a37d851734118104619f86bd18e94c6" }
# warp 0.3.6 + https://github.com/seanmonstar/warp/pull/1069
warp = { git = "https://github.com/seanmonstar/warp", rev = "9d081461ae1167eb321585ce424f4fef6cf0092b" }
# Allow webrender to have a versioned dependency on the older crate on crates.io # Allow webrender to have a versioned dependency on the older crate on crates.io
# in order to build standalone. # in order to build standalone.
malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" } malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" }

View File

@@ -4837,16 +4837,6 @@ who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-run" criteria = "safe-to-run"
delta = "0.3.2 -> 0.3.3" delta = "0.3.2 -> 0.3.3"
[[audits.warp]]
who = "Bobby Holley <bobbyholley@gmail.com>"
criteria = "safe-to-run"
delta = "0.3.3 -> 0.3.3@git:4af45fae95bc98b0eba1ef0db17e1dac471bb23d"
[[audits.warp]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-run"
delta = "0.3.6 -> 0.3.6@git:9d081461ae1167eb321585ce424f4fef6cf0092b"
[[audits.wasm-encoder]] [[audits.wasm-encoder]]
who = "Ryan Hunt <rhunt@eqrion.net>" who = "Ryan Hunt <rhunt@eqrion.net>"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"

View File

@@ -202,10 +202,6 @@ audit-as-crates-io = true
audit-as-crates-io = false audit-as-crates-io = false
notes = "This is a first-party crate, maintained by the appservices team, which is entirely unrelated to the crates.io package of the same name." notes = "This is a first-party crate, maintained by the appservices team, which is entirely unrelated to the crates.io package of the same name."
[policy.warp]
audit-as-crates-io = true
notes = "This is a third-party crate, with an extra patch."
[policy.webdriver] [policy.webdriver]
audit-as-crates-io = false audit-as-crates-io = false
criteria = "safe-to-run" criteria = "safe-to-run"

View File

@@ -941,6 +941,13 @@ user-id = 359
user-login = "seanmonstar" user-login = "seanmonstar"
user-name = "Sean McArthur" user-name = "Sean McArthur"
[[publisher.warp]]
version = "0.3.7"
when = "2024-04-05"
user-id = 359
user-login = "seanmonstar"
user-name = "Sean McArthur"
[[publisher.wasi]] [[publisher.wasi]]
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
when = "2022-01-19" when = "2022-01-19"

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
github: [seanmonstar]

View File

@@ -1,36 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Version**
List the versions of all `warp` crates you are using. The easiest way to get
this information is using `cargo-tree`.
`cargo install cargo-tree`
(see install here: https://github.com/sfackler/cargo-tree)
Then:
`cargo tree | grep warp`
**Platform**
The output of `uname -a` (UNIX), or version and 32 or 64-bit (Windows)
**Description**
Enter your issue details here.
One way to structure the description:
[short summary of the bug]
I tried this code:
[code sample that causes the bug]
I expected to see this happen: [explanation]
Instead, this happened: [explanation]

View File

@@ -1,6 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Question
url: https://discord.gg/RFsPjyt
about: 'Please post your question on the #warp discord channel. You may
also be able to find help at https://users.rust-lang.org/.'

View File

@@ -1,20 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: feature
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

@@ -1,74 +0,0 @@
name: CI
on:
pull_request:
push:
branches:
- master
jobs:
style:
name: Check Style
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- run: cargo fmt --all --check
test:
name: Test
needs: [style]
runs-on: ubuntu-latest
strategy:
matrix:
build: [stable, beta, nightly, tls, no-default-features, compression]
include:
- build: beta
rust: beta
- build: nightly
rust: nightly
benches: true
- build: tls
features: "--features tls"
- build: no-default-features
features: "--no-default-features"
- build: compression
features: "--features compression"
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust || 'stable' }}
- name: Test
run: cargo test ${{ matrix.features }}
- name: Test all benches
if: matrix.benches
run: cargo test --benches ${{ matrix.features }}
doc:
name: Build docs
needs: [style, test]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Rust
uses: dtolnay/rust-toolchain@nightly
- name: cargo doc
run: cargo rustdoc -- -D broken_intra_doc_links

View File

@@ -1,3 +1,10 @@
### v0.3.7 (April 5, 2024)
- **Features**:
- Add ecc private key support to `tls()` config.
- **Fixes**:
- Several dependency upgrades.
### v0.3.6 (September 27, 2023) ### v0.3.6 (September 27, 2023)
- **Features**: - **Features**:

1525
third_party/rust/warp/Cargo.lock generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -12,7 +12,7 @@
[package] [package]
edition = "2018" edition = "2018"
name = "warp" name = "warp"
version = "0.3.6" version = "0.3.7"
authors = ["Sean McArthur <sean@seanmonstar.com>"] authors = ["Sean McArthur <sean@seanmonstar.com>"]
autoexamples = true autoexamples = true
autotests = true autotests = true
@@ -70,27 +70,14 @@ required-features = ["multipart"]
name = "ws" name = "ws"
required-features = ["websocket"] required-features = ["websocket"]
[dependencies]
bytes = "1.0"
headers = "0.3"
http = "0.2"
log = "0.4"
mime = "0.3"
mime_guess = "2.0.0"
percent-encoding = "2.1"
pin-project = "1.0"
scoped-tls = "1.0"
serde = "1.0"
serde_json = "1.0"
serde_urlencoded = "0.7"
tokio-stream = "0.1.1"
tower-service = "0.3"
[dependencies.async-compression] [dependencies.async-compression]
version = "0.3.7" version = "0.4.5"
features = ["tokio"] features = ["tokio"]
optional = true optional = true
[dependencies.bytes]
version = "1.0"
[dependencies.futures-channel] [dependencies.futures-channel]
version = "0.3.17" version = "0.3.17"
features = ["sink"] features = ["sink"]
@@ -100,6 +87,12 @@ version = "0.3"
features = ["sink"] features = ["sink"]
default-features = false default-features = false
[dependencies.headers]
version = "0.3.5"
[dependencies.http]
version = "0.2"
[dependencies.hyper] [dependencies.hyper]
version = "0.14" version = "0.14"
features = [ features = [
@@ -111,14 +104,41 @@ features = [
"client", "client",
] ]
[dependencies.log]
version = "0.4"
[dependencies.mime]
version = "0.3"
[dependencies.mime_guess]
version = "2.0.0"
[dependencies.multer] [dependencies.multer]
version = "2.1.0" version = "2.1.0"
optional = true optional = true
[dependencies.rustls-pemfile] [dependencies.percent-encoding]
version = "2.1"
[dependencies.pin-project]
version = "1.0" version = "1.0"
[dependencies.rustls-pemfile]
version = "2.0"
optional = true optional = true
[dependencies.scoped-tls]
version = "1.0"
[dependencies.serde]
version = "1.0"
[dependencies.serde_json]
version = "1.0"
[dependencies.serde_urlencoded]
version = "0.7.1"
[dependencies.tokio] [dependencies.tokio]
version = "1.0" version = "1.0"
features = [ features = [
@@ -128,17 +148,20 @@ features = [
] ]
[dependencies.tokio-rustls] [dependencies.tokio-rustls]
version = "0.24" version = "0.25"
optional = true optional = true
[dependencies.tokio-tungstenite] [dependencies.tokio-tungstenite]
version = "0.20" version = "0.21"
optional = true optional = true
[dependencies.tokio-util] [dependencies.tokio-util]
version = "0.7" version = "0.7.1"
features = ["io"] features = ["io"]
[dependencies.tower-service]
version = "0.3"
[dependencies.tracing] [dependencies.tracing]
version = "0.1.21" version = "0.1.21"
features = [ features = [
@@ -147,12 +170,17 @@ features = [
] ]
default-features = false default-features = false
[dev-dependencies] [dev-dependencies.handlebars]
handlebars = "4.0" version = "5.0"
listenfd = "1.0"
pretty_env_logger = "0.5" [dev-dependencies.listenfd]
serde_derive = "1.0" version = "1.0"
tracing-log = "0.1"
[dev-dependencies.pretty_env_logger]
version = "0.5"
[dev-dependencies.serde_derive]
version = "1.0"
[dev-dependencies.tokio] [dev-dependencies.tokio]
version = "1.0" version = "1.0"
@@ -165,6 +193,9 @@ features = [
version = "0.1.1" version = "0.1.1"
features = ["net"] features = ["net"]
[dev-dependencies.tracing-log]
version = "0.2"
[dev-dependencies.tracing-subscriber] [dev-dependencies.tracing-subscriber]
version = "0.3" version = "0.3"
features = ["env-filter"] features = ["env-filter"]

View File

@@ -13,8 +13,12 @@ async fn main() {
warp::serve(routes) warp::serve(routes)
.tls() .tls()
// RSA
.cert_path("examples/tls/cert.pem") .cert_path("examples/tls/cert.pem")
.key_path("examples/tls/key.rsa") .key_path("examples/tls/key.rsa")
// ECC
// .cert_path("examples/tls/cert.ecc.pem")
// .key_path("examples/tls/key.ecc")
.run(([127, 0, 0, 1], 3030)) .run(([127, 0, 0, 1], 3030))
.await; .await;
} }

View File

@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBtDCCAVoCCQDFz95/8CeJaDAKBggqhkjOPQQDAjBiMQswCQYDVQQGEwJERTEQ
MA4GA1UECAwHR2VybWFueTEQMA4GA1UEBwwHTGVpcHppZzESMBAGA1UEAwwJbG9j
YWwuZGV2MRswGQYJKoZIhvcNAQkBFgxoaUBsb2NhbC5kZXYwHhcNMjMwNTI4MTk0
NzA4WhcNMjYwNTI3MTk0NzA4WjBiMQswCQYDVQQGEwJERTEQMA4GA1UECAwHR2Vy
bWFueTEQMA4GA1UEBwwHTGVpcHppZzESMBAGA1UEAwwJbG9jYWwuZGV2MRswGQYJ
KoZIhvcNAQkBFgxoaUBsb2NhbC5kZXYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
AATZR4F60X+iHjeD6kySZfXljNckDb22QYQ76Ts4GFYWkdDstU6yehxyER+MZWsm
UnTE/Gy3mnpSmMzoSBfoKRmHMAoGCCqGSM49BAMCA0gAMEUCIQChOTwbAYlx6zg0
yc3Oc+zrNY8Yd8oRUD+cG/wdz+gN/wIgP199zXAPXiYUFFd1CnIYmWJSglaOUbYj
ZP/ixZR9HQs=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIPwp3LAnLEyWe2lLz66Y3QCCJ/BEMJheTM0shZnnSw6toAoGCCqGSM49
AwEHoUQDQgAE2UeBetF/oh43g+pMkmX15YzXJA29tkGEO+k7OBhWFpHQ7LVOsnoc
chEfjGVrJlJ0xPxst5p6UpjM6EgX6CkZhw==
-----END EC PRIVATE KEY-----

View File

@@ -12,10 +12,7 @@ use futures_util::{future, ready, Stream, TryFutureExt};
use headers::ContentLength; use headers::ContentLength;
use http::header::CONTENT_TYPE; use http::header::CONTENT_TYPE;
use hyper::Body; use hyper::Body;
use mime;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde_json;
use serde_urlencoded;
use crate::filter::{filter_fn, filter_fn_one, Filter, FilterBase}; use crate::filter::{filter_fn, filter_fn_one, Filter, FilterBase};
use crate::reject::{self, Rejection}; use crate::reject::{self, Rejection};

View File

@@ -9,10 +9,7 @@ use std::sync::Arc;
use headers::{ use headers::{
AccessControlAllowHeaders, AccessControlAllowMethods, AccessControlExposeHeaders, HeaderMapExt, AccessControlAllowHeaders, AccessControlAllowMethods, AccessControlExposeHeaders, HeaderMapExt,
}; };
use http::{ use http::header::{self, HeaderName, HeaderValue};
self,
header::{self, HeaderName, HeaderValue},
};
use crate::filter::{Filter, WrapSealed}; use crate::filter::{Filter, WrapSealed};
use crate::reject::{CombineRejection, Rejection}; use crate::reject::{CombineRejection, Rejection};

View File

@@ -19,7 +19,6 @@ use headers::{
}; };
use http::StatusCode; use http::StatusCode;
use hyper::Body; use hyper::Body;
use mime_guess;
use percent_encoding::percent_decode_str; use percent_encoding::percent_decode_str;
use tokio::fs::File as TkFile; use tokio::fs::File as TkFile;
use tokio::io::AsyncSeekExt; use tokio::io::AsyncSeekExt;

View File

@@ -4,7 +4,7 @@ use std::fmt;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use http::{self, header, StatusCode}; use http::{header, StatusCode};
use crate::filter::{Filter, WrapSealed}; use crate::filter::{Filter, WrapSealed};
use crate::reject::IsReject; use crate::reject::IsReject;

View File

@@ -120,7 +120,7 @@ impl Stream for FormData {
match self.inner.poll_next_field(cx) { match self.inner.poll_next_field(cx) {
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
Poll::Ready(Ok(Some(part))) => { Poll::Ready(Ok(Some(part))) => {
if part.name().is_some() { if part.name().is_some() || part.file_name().is_some() {
Poll::Ready(Some(Ok(Part { part }))) Poll::Ready(Some(Ok(Part { part })))
} else { } else {
Poll::Ready(Some(Err(crate::Error::new(MultipartFieldMissingName)))) Poll::Ready(Some(Err(crate::Error::new(MultipartFieldMissingName))))
@@ -137,7 +137,9 @@ impl Stream for FormData {
impl Part { impl Part {
/// Get the name of this part. /// Get the name of this part.
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
self.part.name().expect("checked for name previously") self.part
.name()
.unwrap_or_else(|| self.part.file_name().expect("checked for name previously"))
} }
/// Get the filename of this part, if present. /// Get the filename of this part, if present.
@@ -174,7 +176,7 @@ impl Part {
impl fmt::Debug for Part { impl fmt::Debug for Part {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut builder = f.debug_struct("Part"); let mut builder = f.debug_struct("Part");
builder.field("name", &self.part.name()); builder.field("name", &self.name());
if let Some(ref filename) = self.part.file_name() { if let Some(ref filename) = self.part.file_name() {
builder.field("filename", filename); builder.field("filename", filename);

View File

@@ -2,7 +2,6 @@
use futures_util::future; use futures_util::future;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde_urlencoded;
use crate::filter::{filter_fn_one, Filter, One}; use crate::filter::{filter_fn_one, Filter, One};
use crate::reject::{self, Rejection}; use crate::reject::{self, Rejection};

View File

@@ -55,7 +55,7 @@ use futures_util::{future, Stream, TryStream, TryStreamExt};
use http::header::{HeaderValue, CACHE_CONTROL, CONTENT_TYPE}; use http::header::{HeaderValue, CACHE_CONTROL, CONTENT_TYPE};
use hyper::Body; use hyper::Body;
use pin_project::pin_project; use pin_project::pin_project;
use serde_json::{self, Error}; use serde_json::Error;
use tokio::time::{self, Sleep}; use tokio::time::{self, Sleep};
use self::sealed::SseError; use self::sealed::SseError;

View File

@@ -12,7 +12,7 @@ use tracing::Span;
use std::net::SocketAddr; use std::net::SocketAddr;
use http::{self, header}; use http::header;
use crate::filter::{Filter, WrapSealed}; use crate::filter::{Filter, WrapSealed};
use crate::reject::IsReject; use crate::reject::IsReject;

View File

@@ -12,7 +12,6 @@ use crate::reject::Rejection;
use crate::reply::{Reply, Response}; use crate::reply::{Reply, Response};
use futures_util::{future, ready, FutureExt, Sink, Stream, TryFutureExt}; use futures_util::{future, ready, FutureExt, Sink, Stream, TryFutureExt};
use headers::{Connection, HeaderMapExt, SecWebsocketAccept, SecWebsocketKey, Upgrade}; use headers::{Connection, HeaderMapExt, SecWebsocketAccept, SecWebsocketKey, Upgrade};
use http;
use hyper::upgrade::OnUpgrade; use hyper::upgrade::OnUpgrade;
use tokio_tungstenite::{ use tokio_tungstenite::{
tungstenite::protocol::{self, WebSocketConfig}, tungstenite::protocol::{self, WebSocketConfig},

View File

@@ -1,4 +1,3 @@
#![doc(html_root_url = "https://docs.rs/warp/0.3.6")]
#![deny(missing_docs)] #![deny(missing_docs)]
#![deny(missing_debug_implementations)] #![deny(missing_debug_implementations)]
#![deny(rust_2018_idioms)] #![deny(rust_2018_idioms)]

View File

@@ -62,7 +62,6 @@ use std::error::Error as StdError;
use std::fmt; use std::fmt;
use http::{ use http::{
self,
header::{HeaderValue, CONTENT_TYPE}, header::{HeaderValue, CONTENT_TYPE},
StatusCode, StatusCode,
}; };
@@ -707,7 +706,6 @@ mod sealed {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use http::StatusCode;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
struct Left; struct Left;
@@ -826,7 +824,7 @@ mod tests {
} }
#[derive(Debug)] #[derive(Debug)]
struct X(u32); struct X(#[allow(unused)] u32);
impl Reject for X {} impl Reject for X {}
fn combine_n<F, R>(n: u32, new_reject: F) -> Rejection fn combine_n<F, R>(n: u32, new_reject: F) -> Rejection

View File

@@ -35,15 +35,12 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::error::Error as StdError;
use std::fmt;
use crate::generic::{Either, One}; use crate::generic::{Either, One};
use http::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use http::header::{HeaderName, HeaderValue, CONTENT_TYPE};
use http::StatusCode; use http::StatusCode;
use hyper::Body; use hyper::Body;
use serde::Serialize; use serde::Serialize;
use serde_json;
// This re-export just looks weird in docs... // This re-export just looks weird in docs...
pub(crate) use self::sealed::Reply_; pub(crate) use self::sealed::Reply_;
@@ -131,17 +128,6 @@ impl Reply for Json {
} }
} }
#[derive(Debug)]
pub(crate) struct ReplyJsonError;
impl fmt::Display for ReplyJsonError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("warp::reply::json() failed")
}
}
impl StdError for ReplyJsonError {}
/// Reply with a body and `content-type` set to `text/html; charset=utf-8`. /// Reply with a body and `content-type` set to `text/html; charset=utf-8`.
/// ///
/// # Example /// # Example

View File

@@ -104,7 +104,6 @@ use http::{
Response, Response,
}; };
use serde::Serialize; use serde::Serialize;
use serde_json;
#[cfg(feature = "websocket")] #[cfg(feature = "websocket")]
use tokio::sync::oneshot; use tokio::sync::oneshot;

View File

@@ -12,12 +12,10 @@ use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use futures_util::ready; use futures_util::ready;
use hyper::server::accept::Accept; use hyper::server::accept::Accept;
use hyper::server::conn::{AddrIncoming, AddrStream}; use hyper::server::conn::{AddrIncoming, AddrStream};
use tokio_rustls::rustls::server::WebPkiClientVerifier;
use tokio_rustls::rustls::{Error as TlsError, RootCertStore, ServerConfig};
use crate::transport::Transport; use crate::transport::Transport;
use tokio_rustls::rustls::{
server::{AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, NoClientAuth},
Certificate, Error as TlsError, PrivateKey, RootCertStore, ServerConfig,
};
/// Represents errors that can occur building the TlsConfig /// Represents errors that can occur building the TlsConfig
#[derive(Debug)] #[derive(Debug)]
@@ -25,10 +23,12 @@ pub(crate) enum TlsConfigError {
Io(io::Error), Io(io::Error),
/// An Error parsing the Certificate /// An Error parsing the Certificate
CertParseError, CertParseError,
/// An Error parsing a Pkcs8 key /// Identity PEM is invalid
Pkcs8ParseError, InvalidIdentityPem,
/// An Error parsing a Rsa key /// Identity PEM is missing a private key such as RSA, ECC or PKCS8
RsaParseError, MissingPrivateKey,
/// Unknown private key format
UnknownPrivateKeyFormat,
/// An error from an empty key /// An error from an empty key
EmptyKey, EmptyKey,
/// An error from an invalid key /// An error from an invalid key
@@ -40,8 +40,12 @@ impl fmt::Display for TlsConfigError {
match self { match self {
TlsConfigError::Io(err) => err.fmt(f), TlsConfigError::Io(err) => err.fmt(f),
TlsConfigError::CertParseError => write!(f, "certificate parse error"), TlsConfigError::CertParseError => write!(f, "certificate parse error"),
TlsConfigError::Pkcs8ParseError => write!(f, "pkcs8 parse error"), TlsConfigError::UnknownPrivateKeyFormat => write!(f, "unknown private key format"),
TlsConfigError::RsaParseError => write!(f, "rsa parse error"), TlsConfigError::MissingPrivateKey => write!(
f,
"Identity PEM is missing a private key such as RSA, ECC or PKCS8"
),
TlsConfigError::InvalidIdentityPem => write!(f, "identity PEM is invalid"),
TlsConfigError::EmptyKey => write!(f, "key contains no private key"), TlsConfigError::EmptyKey => write!(f, "key contains no private key"),
TlsConfigError::InvalidKey(err) => write!(f, "key contains an invalid key, {}", err), TlsConfigError::InvalidKey(err) => write!(f, "key contains an invalid key, {}", err),
} }
@@ -170,37 +174,34 @@ impl TlsConfigBuilder {
pub(crate) fn build(mut self) -> Result<ServerConfig, TlsConfigError> { pub(crate) fn build(mut self) -> Result<ServerConfig, TlsConfigError> {
let mut cert_rdr = BufReader::new(self.cert); let mut cert_rdr = BufReader::new(self.cert);
let cert = rustls_pemfile::certs(&mut cert_rdr) let cert = rustls_pemfile::certs(&mut cert_rdr)
.map_err(|_e| TlsConfigError::CertParseError)? .collect::<Result<Vec<_>, _>>()
.into_iter() .map_err(|_e| TlsConfigError::CertParseError)?;
.map(Certificate)
.collect();
let key = { let mut key_vec = Vec::new();
// convert it to Vec<u8> to allow reading it again if key is RSA self.key
let mut key_vec = Vec::new(); .read_to_end(&mut key_vec)
self.key .map_err(TlsConfigError::Io)?;
.read_to_end(&mut key_vec)
.map_err(TlsConfigError::Io)?;
if key_vec.is_empty() { if key_vec.is_empty() {
return Err(TlsConfigError::EmptyKey); return Err(TlsConfigError::EmptyKey);
} }
let mut pkcs8 = rustls_pemfile::pkcs8_private_keys(&mut key_vec.as_slice()) let mut key_opt = None;
.map_err(|_e| TlsConfigError::Pkcs8ParseError)?; let mut key_cur = std::io::Cursor::new(key_vec);
for item in rustls_pemfile::read_all(&mut key_cur)
if !pkcs8.is_empty() { .collect::<Result<Vec<_>, _>>()
PrivateKey(pkcs8.remove(0)) .map_err(|_e| TlsConfigError::InvalidIdentityPem)?
} else { {
let mut rsa = rustls_pemfile::rsa_private_keys(&mut key_vec.as_slice()) match item {
.map_err(|_e| TlsConfigError::RsaParseError)?; rustls_pemfile::Item::Pkcs1Key(k) => key_opt = Some(k.into()),
rustls_pemfile::Item::Pkcs8Key(k) => key_opt = Some(k.into()),
if !rsa.is_empty() { rustls_pemfile::Item::Sec1Key(k) => key_opt = Some(k.into()),
PrivateKey(rsa.remove(0)) _ => return Err(TlsConfigError::UnknownPrivateKeyFormat),
} else {
return Err(TlsConfigError::EmptyKey);
}
} }
}
let key = match key_opt {
Some(v) => v,
_ => return Err(TlsConfigError::MissingPrivateKey),
}; };
fn read_trust_anchor( fn read_trust_anchor(
@@ -208,11 +209,13 @@ impl TlsConfigBuilder {
) -> Result<RootCertStore, TlsConfigError> { ) -> Result<RootCertStore, TlsConfigError> {
let trust_anchors = { let trust_anchors = {
let mut reader = BufReader::new(trust_anchor); let mut reader = BufReader::new(trust_anchor);
rustls_pemfile::certs(&mut reader).map_err(TlsConfigError::Io)? rustls_pemfile::certs(&mut reader)
.collect::<Result<Vec<_>, _>>()
.map_err(TlsConfigError::Io)?
}; };
let mut store = RootCertStore::empty(); let mut store = RootCertStore::empty();
let (added, _skipped) = store.add_parsable_certificates(&trust_anchors); let (added, _skipped) = store.add_parsable_certificates(trust_anchors);
if added == 0 { if added == 0 {
return Err(TlsConfigError::CertParseError); return Err(TlsConfigError::CertParseError);
} }
@@ -220,23 +223,32 @@ impl TlsConfigBuilder {
Ok(store) Ok(store)
} }
let client_auth = match self.client_auth { let config = {
TlsClientAuth::Off => NoClientAuth::boxed(), let builder = ServerConfig::builder();
TlsClientAuth::Optional(trust_anchor) => { let mut config = match self.client_auth {
AllowAnyAnonymousOrAuthenticatedClient::new(read_trust_anchor(trust_anchor)?) TlsClientAuth::Off => builder.with_no_client_auth(),
.boxed() TlsClientAuth::Optional(trust_anchor) => {
} let verifier =
TlsClientAuth::Required(trust_anchor) => { WebPkiClientVerifier::builder(read_trust_anchor(trust_anchor)?.into())
AllowAnyAuthenticatedClient::new(read_trust_anchor(trust_anchor)?).boxed() .allow_unauthenticated()
.build()
.map_err(|_| TlsConfigError::CertParseError)?;
builder.with_client_cert_verifier(verifier)
}
TlsClientAuth::Required(trust_anchor) => {
let verifier =
WebPkiClientVerifier::builder(read_trust_anchor(trust_anchor)?.into())
.build()
.map_err(|_| TlsConfigError::CertParseError)?;
builder.with_client_cert_verifier(verifier)
}
} }
.with_single_cert_with_ocsp(cert, key, self.ocsp_resp)
.map_err(TlsConfigError::InvalidKey)?;
config.alpn_protocols = vec!["h2".into(), "http/1.1".into()];
config
}; };
let mut config = ServerConfig::builder()
.with_safe_defaults()
.with_client_cert_verifier(client_auth)
.with_single_cert_with_ocsp_and_sct(cert, key, self.ocsp_resp, Vec::new())
.map_err(TlsConfigError::InvalidKey)?;
config.alpn_protocols = vec!["h2".into(), "http/1.1".into()];
Ok(config) Ok(config)
} }
} }
@@ -409,4 +421,25 @@ mod tests {
.build() .build()
.unwrap(); .unwrap();
} }
#[test]
fn file_ecc_cert_key() {
TlsConfigBuilder::new()
.key_path("examples/tls/key.ecc")
.cert_path("examples/tls/cert.ecc.pem")
.build()
.unwrap();
}
#[test]
fn bytes_ecc_cert_key() {
let key = include_str!("../examples/tls/key.ecc");
let cert = include_str!("../examples/tls/cert.ecc.pem");
TlsConfigBuilder::new()
.key(key.as_bytes())
.cert(cert.as_bytes())
.build()
.unwrap();
}
} }