feat: make crypto and TLS certificate verify backends opt-in (#1054)

This commit is contained in:
Paolo Barbolini
2025-02-23 09:32:47 +01:00
committed by GitHub
parent 8a6f1dab0e
commit 75716ca269
17 changed files with 399 additions and 209 deletions

View File

@@ -57,12 +57,12 @@ jobs:
- name: Setup cache - name: Setup cache
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@v2
- name: Install cargo hack - name: Install cargo hack
run: cargo install cargo-hack --debug run: cargo install cargo-hack --debug
- name: Check with cargo hack - name: Check with cargo hack
run: cargo hack check --feature-powerset --depth 3 run: cargo hack check --feature-powerset --depth 3 --at-least-one-of aws-lc-rs,ring --at-least-one-of rustls-native-certs,webpki-roots
test: test:
name: test / ${{ matrix.name }} name: test / ${{ matrix.name }}
@@ -90,7 +90,7 @@ jobs:
- name: Setup cache - name: Setup cache
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@v2
- name: Install postfix - name: Install postfix
run: | run: |
DEBIAN_FRONTEND=noninteractive sudo apt-get update DEBIAN_FRONTEND=noninteractive sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get -y install postfix DEBIAN_FRONTEND=noninteractive sudo apt-get -y install postfix
@@ -119,10 +119,10 @@ jobs:
run: cargo test run: cargo test
- name: Test with all features (-native-tls) - name: Test with all features (-native-tls)
run: cargo test --no-default-features --features async-std1,async-std1-rustls-tls,boring-tls,builder,dkim,file-transport,file-transport-envelope,hostname,mime03,pool,rustls-native-certs,rustls-tls,sendmail-transport,smtp-transport,tokio1,tokio1-boring-tls,tokio1-rustls-tls,tracing run: cargo test --no-default-features --features async-std1,async-std1-rustls,aws-lc-rs,rustls-native-certs,boring-tls,builder,dkim,file-transport,file-transport-envelope,hostname,mime03,pool,rustls-native-certs,rustls,sendmail-transport,smtp-transport,tokio1,tokio1-boring-tls,tokio1-rustls,tracing
- name: Test with all features (-boring-tls) - name: Test with all features (-boring-tls)
run: cargo test --no-default-features --features async-std1,async-std1-rustls-tls,builder,dkim,file-transport,file-transport-envelope,hostname,mime03,native-tls,pool,rustls-native-certs,rustls-tls,sendmail-transport,smtp-transport,tokio1,tokio1-native-tls,tokio1-rustls-tls,tracing run: cargo test --no-default-features --features async-std1,async-std1-rustls,aws-lc-rs,rustls-native-certs,builder,dkim,file-transport,file-transport-envelope,hostname,mime03,native-tls,pool,rustls-native-certs,rustls,sendmail-transport,smtp-transport,tokio1,tokio1-native-tls,tokio1-rustls,tracing
# coverage: # coverage:
# name: Coverage # name: Coverage

128
Cargo.lock generated
View File

@@ -241,6 +241,47 @@ version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]]
name = "aws-lc-fips-sys"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29003a681b2b9465c1139bfb726da452a841a8b025f35953f3bce71139f10b21"
dependencies = [
"bindgen 0.69.5",
"cc",
"cmake",
"dunce",
"fs_extra",
"paste",
"regex",
]
[[package]]
name = "aws-lc-rs"
version = "1.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd755adf9707cf671e31d944a189be3deaaeee11c8bc1d669bb8022ac90fbd0"
dependencies = [
"aws-lc-fips-sys",
"aws-lc-sys",
"paste",
"zeroize",
]
[[package]]
name = "aws-lc-sys"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f9dd2e03ee80ca2822dd6ea431163d2ef259f2066a4d6ccaca6d9dcb386aa43"
dependencies = [
"bindgen 0.69.5",
"cc",
"cmake",
"dunce",
"fs_extra",
"paste",
]
[[package]] [[package]]
name = "backtrace" name = "backtrace"
version = "0.3.74" version = "0.3.74"
@@ -268,6 +309,29 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "bindgen"
version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
dependencies = [
"bitflags",
"cexpr",
"clang-sys",
"itertools 0.10.5",
"lazy_static",
"lazycell",
"log",
"prettyplease",
"proc-macro2",
"quote",
"regex",
"rustc-hash",
"shlex",
"syn 2.0.89",
"which",
]
[[package]] [[package]]
name = "bindgen" name = "bindgen"
version = "0.70.1" version = "0.70.1"
@@ -335,7 +399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "777cf31ea10f7eb87d46b30848f8d7acbd65cb4a25cd51bee1808ef601de0416" checksum = "777cf31ea10f7eb87d46b30848f8d7acbd65cb4a25cd51bee1808ef601de0416"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bindgen", "bindgen 0.70.1",
"cmake", "cmake",
"fs_extra", "fs_extra",
"fslock", "fslock",
@@ -371,6 +435,8 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
dependencies = [ dependencies = [
"jobserver",
"libc",
"shlex", "shlex",
] ]
@@ -664,6 +730,12 @@ dependencies = [
"syn 2.0.89", "syn 2.0.89",
] ]
[[package]]
name = "dunce"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]] [[package]]
name = "ed25519" name = "ed25519"
version = "2.2.3" version = "2.2.3"
@@ -969,6 +1041,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc"
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
]
[[package]] [[package]]
name = "hostname" name = "hostname"
version = "0.4.0" version = "0.4.0"
@@ -1160,6 +1241,15 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "jobserver"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.72" version = "0.3.72"
@@ -1187,6 +1277,12 @@ dependencies = [
"spin", "spin",
] ]
[[package]]
name = "lazycell"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "lettre" name = "lettre"
version = "0.11.13" version = "0.11.13"
@@ -1509,6 +1605,12 @@ version = "2.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
[[package]]
name = "paste"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]] [[package]]
name = "pem-rfc7468" name = "pem-rfc7468"
version = "0.7.0" version = "0.7.0"
@@ -1636,6 +1738,16 @@ dependencies = [
"yansi", "yansi",
] ]
[[package]]
name = "prettyplease"
version = "0.2.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033"
dependencies = [
"proc-macro2",
"syn 2.0.89",
]
[[package]] [[package]]
name = "proc-macro-error" name = "proc-macro-error"
version = "1.0.4" version = "1.0.4"
@@ -1845,6 +1957,7 @@ version = "0.23.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f" checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f"
dependencies = [ dependencies = [
"aws-lc-rs",
"log", "log",
"once_cell", "once_cell",
"ring", "ring",
@@ -1878,6 +1991,7 @@ version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [ dependencies = [
"aws-lc-rs",
"ring", "ring",
"rustls-pki-types", "rustls-pki-types",
"untrusted", "untrusted",
@@ -2460,6 +2574,18 @@ dependencies = [
"rustls-pki-types", "rustls-pki-types",
] ]
[[package]]
name = "which"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
dependencies = [
"either",
"home",
"once_cell",
"rustix",
]
[[package]] [[package]]
name = "winapi" name = "winapi"
version = "0.3.9" version = "0.3.9"

View File

@@ -48,7 +48,7 @@ percent-encoding = { version = "2.3", optional = true }
## tls ## tls
native-tls = { version = "0.2.9", optional = true } # feature native-tls = { version = "0.2.9", optional = true } # feature
rustls = { version = "0.23.5", default-features = false, features = ["ring", "logging", "std", "tls12"], optional = true } rustls = { version = "0.23.5", default-features = false, features = ["logging", "std", "tls12"], optional = true }
rustls-native-certs = { version = "0.8", optional = true } rustls-native-certs = { version = "0.8", optional = true }
webpki-roots = { version = "0.26", optional = true } webpki-roots = { version = "0.26", optional = true }
boring = { version = "4", optional = true } boring = { version = "4", optional = true }
@@ -60,12 +60,12 @@ async-trait = { version = "0.1", optional = true }
## async-std ## async-std
async-std = { version = "1.8", optional = true } async-std = { version = "1.8", optional = true }
futures-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12", "ring"], optional = true } futures-rustls = { version = "0.26", default-features = false, features = ["logging", "tls12"], optional = true }
## tokio ## tokio
tokio1_crate = { package = "tokio", version = "1", optional = true } tokio1_crate = { package = "tokio", version = "1", optional = true }
tokio1_native_tls_crate = { package = "tokio-native-tls", version = "0.3", optional = true } tokio1_native_tls_crate = { package = "tokio-native-tls", version = "0.3", optional = true }
tokio1_rustls = { package = "tokio-rustls", version = "0.26", default-features = false, features = ["logging", "tls12", "ring"], optional = true } tokio1_rustls = { package = "tokio-rustls", version = "0.26", default-features = false, features = ["logging", "tls12"], optional = true }
tokio1_boring = { package = "tokio-boring", version = "4", optional = true } tokio1_boring = { package = "tokio-boring", version = "4", optional = true }
## dkim ## dkim
@@ -109,16 +109,26 @@ smtp-transport = ["dep:base64", "dep:nom", "dep:socket2", "dep:url", "dep:percen
pool = ["dep:futures-util"] pool = ["dep:futures-util"]
rustls-tls = ["dep:webpki-roots", "dep:rustls"] rustls = ["dep:rustls"]
aws-lc-rs = ["rustls?/aws-lc-rs"]
fips = ["aws-lc-rs", "rustls?/fips"]
ring = ["rustls?/ring"]
webpki-roots = ["dep:webpki-roots"]
# deprecated
rustls-tls = ["webpki-roots", "rustls", "ring"]
boring-tls = ["dep:boring"] boring-tls = ["dep:boring"]
# async # async
async-std1 = ["dep:async-std", "dep:async-trait", "dep:futures-io", "dep:futures-util"] async-std1 = ["dep:async-std", "dep:async-trait", "dep:futures-io", "dep:futures-util"]
async-std1-rustls-tls = ["async-std1", "rustls-tls", "dep:futures-rustls"] async-std1-rustls = ["async-std1", "rustls", "dep:futures-rustls"]
# deprecated
async-std1-rustls-tls = ["async-std1-rustls", "rustls-tls"]
tokio1 = ["dep:tokio1_crate", "dep:async-trait", "dep:futures-io", "dep:futures-util"] tokio1 = ["dep:tokio1_crate", "dep:async-trait", "dep:futures-io", "dep:futures-util"]
tokio1-native-tls = ["tokio1", "native-tls", "dep:tokio1_native_tls_crate"] tokio1-native-tls = ["tokio1", "native-tls", "dep:tokio1_native_tls_crate"]
tokio1-rustls-tls = ["tokio1", "rustls-tls", "dep:tokio1_rustls"] tokio1-rustls = ["tokio1", "rustls", "dep:tokio1_rustls"]
# deprecated
tokio1-rustls-tls = ["tokio1-rustls", "rustls-tls"]
tokio1-boring-tls = ["tokio1", "boring-tls", "dep:tokio1_boring"] tokio1-boring-tls = ["tokio1", "boring-tls", "dep:tokio1_boring"]
dkim = ["dep:base64", "dep:sha2", "dep:rsa", "dep:ed25519-dalek"] dkim = ["dep:base64", "dep:sha2", "dep:rsa", "dep:ed25519-dalek"]

View File

@@ -133,7 +133,7 @@ impl Executor for Tokio1Executor {
) -> Result<AsyncSmtpConnection, Error> { ) -> Result<AsyncSmtpConnection, Error> {
#[allow(clippy::match_single_binding)] #[allow(clippy::match_single_binding)]
let tls_parameters = match tls { let tls_parameters = match tls {
#[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))] #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls"))]
Tls::Wrapper(tls_parameters) => Some(tls_parameters.clone()), Tls::Wrapper(tls_parameters) => Some(tls_parameters.clone()),
_ => None, _ => None,
}; };
@@ -147,7 +147,7 @@ impl Executor for Tokio1Executor {
) )
.await?; .await?;
#[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls-tls"))] #[cfg(any(feature = "tokio1-native-tls", feature = "tokio1-rustls"))]
match tls { match tls {
Tls::Opportunistic(tls_parameters) => { Tls::Opportunistic(tls_parameters) => {
if conn.can_starttls() { if conn.can_starttls() {
@@ -230,7 +230,7 @@ impl Executor for AsyncStd1Executor {
) -> Result<AsyncSmtpConnection, Error> { ) -> Result<AsyncSmtpConnection, Error> {
#[allow(clippy::match_single_binding)] #[allow(clippy::match_single_binding)]
let tls_parameters = match tls { let tls_parameters = match tls {
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
Tls::Wrapper(tls_parameters) => Some(tls_parameters.clone()), Tls::Wrapper(tls_parameters) => Some(tls_parameters.clone()),
_ => None, _ => None,
}; };
@@ -243,7 +243,7 @@ impl Executor for AsyncStd1Executor {
) )
.await?; .await?;
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
match tls { match tls {
Tls::Opportunistic(tls_parameters) => { Tls::Opportunistic(tls_parameters) => {
if conn.can_starttls() { if conn.can_starttls() {

View File

@@ -64,13 +64,46 @@
//! //!
//! #### SMTP over TLS via the rustls crate //! #### SMTP over TLS via the rustls crate
//! //!
//! _Secure SMTP connections using TLS from the `rustls-tls` crate_ //! _Secure SMTP connections using TLS from the `rustls` crate_
//! //!
//! Rustls uses [ring] as the cryptography implementation. As a result, [not all Rust's targets are supported][ring-support]. //! * **rustls**: TLS support for the synchronous version of the API
//! * **tokio1-rustls**: TLS support for the `tokio1` async version of the API
//! * **async-std1-rustls**: TLS support for the `async-std1` async version of the API
//! //!
//! * **rustls-tls**: TLS support for the synchronous version of the API //! ##### rustls crypto backends
//! * **tokio1-rustls-tls**: TLS support for the `tokio1` async version of the API //!
//! * **async-std1-rustls-tls**: TLS support for the `async-std1` async version of the API //! _The crypto implementation to use with rustls_
//!
//! When the `rustls` feature is enabled, one of the following crypto backends MUST also
//! be enabled.
//!
//! * **aws-lc-rs**: use [AWS-LC] (via [`aws-lc-rs`]) as the `rustls` crypto backend
//! * **ring**: use [`ring`] as the `rustls` crypto backend
//!
//! When enabling `aws-lc-rs`, the `fips` feature can also be enabled to have
//! rustls use the FIPS certified module of AWS-LC.
//!
//! `aws-lc-rs` may require cmake on some platforms to compile.
//! `fips` always requires cmake and the Go compiler to compile.
//!
//! ##### rustls certificate verification backend
//!
//! _The TLS certificate verification backend to use with rustls_
//!
//! When the `rustls` feature is enabled, one of the following verification backends
//! MUST also be enabled.
//!
//! * **rustls-native-certs**: verify TLS certificates using the platform's native certificate store (see [`rustls-native-certs`])
//! * **webpki-roots**: verify TLS certificates against Mozilla's root certificates (see [`webpki-roots`])
//!
//! For the `rustls-native-certs` backend to work correctly, the following packages
//! will need to be installed in order for the build stage and the compiled program
//! to run properly.
//!
//! | Distro | Build-time packages | Runtime packages |
//! | ------------ | -------------------------- | ---------------------------- |
//! | Debian | none | `ca-certificates` |
//! | Alpine Linux | none | `ca-certificates` |
//! //!
//! ### Sendmail transport //! ### Sendmail transport
//! //!
@@ -115,8 +148,11 @@
//! [`ContentType`]: crate::message::header::ContentType //! [`ContentType`]: crate::message::header::ContentType
//! [tokio]: https://docs.rs/tokio/1 //! [tokio]: https://docs.rs/tokio/1
//! [async-std]: https://docs.rs/async-std/1 //! [async-std]: https://docs.rs/async-std/1
//! [ring]: https://github.com/briansmith/ring#ring //! [AWS-LC]: https://github.com/aws/aws-lc
//! [ring-support]: https://github.com/briansmith/ring#online-automated-testing //! [`aws-lc-rs`]: https://crates.io/crates/aws-lc-rs
//! [`ring`]: https://crates.io/crates/ring
//! [`rustls-native-certs`]: https://crates.io/crates/rustls-native-certs
//! [`webpki-roots`]: https://crates.io/crates/webpki-roots
//! [Tokio 1.x]: https://docs.rs/tokio/1 //! [Tokio 1.x]: https://docs.rs/tokio/1
//! [async-std 1.x]: https://docs.rs/async-std/1 //! [async-std 1.x]: https://docs.rs/async-std/1
//! [mime 0.3]: https://docs.rs/mime/0.3 //! [mime 0.3]: https://docs.rs/mime/0.3
@@ -163,6 +199,22 @@
#[cfg(not(lettre_ignore_tls_mismatch))] #[cfg(not(lettre_ignore_tls_mismatch))]
mod compiletime_checks { mod compiletime_checks {
#[cfg(all(feature = "rustls", not(feature = "aws-lc-rs"), not(feature = "ring")))]
compile_error!(
"feature `rustls` also requires either the `aws-lc-rs` or the `ring` feature to
be enabled"
);
#[cfg(all(
feature = "rustls",
not(feature = "rustls-native-certs"),
not(feature = "webpki-roots")
))]
compile_error!(
"feature `rustls` also requires either the `rustls-native-certs` or the `webpki-roots` feature to
be enabled"
);
#[cfg(all(feature = "native-tls", feature = "boring-tls"))] #[cfg(all(feature = "native-tls", feature = "boring-tls"))]
compile_error!("feature \"native-tls\" and feature \"boring-tls\" cannot be enabled at the same time, otherwise compile_error!("feature \"native-tls\" and feature \"boring-tls\" cannot be enabled at the same time, otherwise
the executable will fail to link."); the executable will fail to link.");
@@ -173,16 +225,12 @@ mod compiletime_checks {
not(feature = "tokio1-native-tls") not(feature = "tokio1-native-tls")
))] ))]
compile_error!("Lettre is being built with the `tokio1` and the `native-tls` features, but the `tokio1-native-tls` feature hasn't been turned on. compile_error!("Lettre is being built with the `tokio1` and the `native-tls` features, but the `tokio1-native-tls` feature hasn't been turned on.
If you were trying to opt into `rustls-tls` and did not activate `native-tls`, disable the default-features of lettre in `Cargo.toml` and manually add the required features. If you were trying to opt into `rustls` and did not activate `native-tls`, disable the default-features of lettre in `Cargo.toml` and manually add the required features.
Make sure to apply the same to any of your crate dependencies that use the `lettre` crate."); Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");
#[cfg(all( #[cfg(all(feature = "tokio1", feature = "rustls", not(feature = "tokio1-rustls")))]
feature = "tokio1", compile_error!("Lettre is being built with the `tokio1` and the `rustls` features, but the `tokio1-rustls` feature hasn't been turned on.
feature = "rustls-tls", If you'd like to use `native-tls` make sure that the `rustls` feature hasn't been enabled by mistake.
not(feature = "tokio1-rustls-tls")
))]
compile_error!("Lettre is being built with the `tokio1` and the `rustls-tls` features, but the `tokio1-rustls-tls` feature hasn't been turned on.
If you'd like to use `native-tls` make sure that the `rustls-tls` feature hasn't been enabled by mistake.
Make sure to apply the same to any of your crate dependencies that use the `lettre` crate."); Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");
#[cfg(all( #[cfg(all(
@@ -191,22 +239,22 @@ mod compiletime_checks {
not(feature = "tokio1-boring-tls") not(feature = "tokio1-boring-tls")
))] ))]
compile_error!("Lettre is being built with the `tokio1` and the `boring-tls` features, but the `tokio1-boring-tls` feature hasn't been turned on. compile_error!("Lettre is being built with the `tokio1` and the `boring-tls` features, but the `tokio1-boring-tls` feature hasn't been turned on.
If you'd like to use `boring-tls` make sure that the `rustls-tls` feature hasn't been enabled by mistake. If you'd like to use `boring-tls` make sure that the `rustls` feature hasn't been enabled by mistake.
Make sure to apply the same to any of your crate dependencies that use the `lettre` crate."); Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");
#[cfg(all(feature = "async-std1", feature = "native-tls",))] #[cfg(all(feature = "async-std1", feature = "native-tls"))]
compile_error!("Lettre is being built with the `async-std1` and the `native-tls` features, but the async-std integration doesn't support native-tls yet. compile_error!("Lettre is being built with the `async-std1` and the `native-tls` features, but the async-std integration doesn't support native-tls yet.
If you'd like to work on the issue please take a look at https://github.com/lettre/lettre/issues/576. If you'd like to work on the issue please take a look at https://github.com/lettre/lettre/issues/576.
If you were trying to opt into `rustls-tls` and did not activate `native-tls`, disable the default-features of lettre in `Cargo.toml` and manually add the required features. If you were trying to opt into `rustls` and did not activate `native-tls`, disable the default-features of lettre in `Cargo.toml` and manually add the required features.
Make sure to apply the same to any of your crate dependencies that use the `lettre` crate."); Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");
#[cfg(all( #[cfg(all(
feature = "async-std1", feature = "async-std1",
feature = "rustls-tls", feature = "rustls",
not(feature = "async-std1-rustls-tls") not(feature = "async-std1-rustls")
))] ))]
compile_error!("Lettre is being built with the `async-std1` and the `rustls-tls` features, but the `async-std1-rustls-tls` feature hasn't been turned on. compile_error!("Lettre is being built with the `async-std1` and the `rustls` features, but the `async-std1-rustls` feature hasn't been turned on.
If you'd like to use `native-tls` make sure that the `rustls-tls` hasn't been enabled by mistake. If you'd like to use `native-tls` make sure that the `rustls` hasn't been enabled by mistake.
Make sure to apply the same to any of your crate dependencies that use the `lettre` crate."); Make sure to apply the same to any of your crate dependencies that use the `lettre` crate.");
} }
@@ -219,6 +267,8 @@ mod executor;
#[cfg(feature = "builder")] #[cfg(feature = "builder")]
#[cfg_attr(docsrs, doc(cfg(feature = "builder")))] #[cfg_attr(docsrs, doc(cfg(feature = "builder")))]
pub mod message; pub mod message;
#[cfg(feature = "rustls")]
mod rustls_crypto;
mod time; mod time;
pub mod transport; pub mod transport;

14
src/rustls_crypto.rs Normal file
View File

@@ -0,0 +1,14 @@
use std::sync::Arc;
use rustls::crypto::CryptoProvider;
pub(crate) fn crypto_provider() -> Arc<CryptoProvider> {
CryptoProvider::get_default().cloned().unwrap_or_else(|| {
#[cfg(feature = "aws-lc-rs")]
let provider = rustls::crypto::aws_lc_rs::default_provider();
#[cfg(not(feature = "aws-lc-rs"))]
let provider = rustls::crypto::ring::default_provider();
Arc::new(provider)
})
}

View File

@@ -14,8 +14,8 @@ use super::pool::async_impl::Pool;
use super::PoolConfig; use super::PoolConfig;
#[cfg(any( #[cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "async-std1-rustls-tls" feature = "async-std1-rustls"
))] ))]
use super::Tls; use super::Tls;
use super::{ use super::{
@@ -111,15 +111,15 @@ where
/// to validate TLS certificates. /// to validate TLS certificates.
#[cfg(any( #[cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "async-std1-rustls-tls" feature = "async-std1-rustls"
))] ))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any( doc(cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "async-std1-rustls-tls" feature = "async-std1-rustls"
))) )))
)] )]
pub fn relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> { pub fn relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
@@ -145,15 +145,15 @@ where
/// or emails will be sent to the server, protecting from downgrade attacks. /// or emails will be sent to the server, protecting from downgrade attacks.
#[cfg(any( #[cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "async-std1-rustls-tls" feature = "async-std1-rustls"
))] ))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any( doc(cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "async-std1-rustls-tls" feature = "async-std1-rustls"
))) )))
)] )]
pub fn starttls_relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> { pub fn starttls_relay(relay: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
@@ -288,10 +288,10 @@ where
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn from_url(connection_url: &str) -> Result<AsyncSmtpTransportBuilder, Error> { pub fn from_url(connection_url: &str) -> Result<AsyncSmtpTransportBuilder, Error> {
super::connection_url::from_connection_url(connection_url) super::connection_url::from_connection_url(connection_url)
@@ -416,15 +416,15 @@ impl AsyncSmtpTransportBuilder {
/// lead to hard to debug IO errors coming from the TLS library. /// lead to hard to debug IO errors coming from the TLS library.
#[cfg(any( #[cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "async-std1-rustls-tls" feature = "async-std1-rustls"
))] ))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any( doc(cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "async-std1-rustls-tls" feature = "async-std1-rustls"
))) )))
)] )]
pub fn tls(mut self, tls: Tls) -> Self { pub fn tls(mut self, tls: Tls) -> Self {

View File

@@ -375,7 +375,7 @@ impl AsyncSmtpConnection {
} }
/// The X509 certificate of the server (DER encoded) /// The X509 certificate of the server (DER encoded)
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
pub fn peer_certificate(&self) -> Result<Vec<u8>, Error> { pub fn peer_certificate(&self) -> Result<Vec<u8>, Error> {
self.stream.get_ref().peer_certificate() self.stream.get_ref().peer_certificate()
} }
@@ -397,7 +397,7 @@ impl AsyncSmtpConnection {
} }
/// All the X509 certificates of the chain (DER encoded) /// All the X509 certificates of the chain (DER encoded)
#[cfg(any(feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "rustls", feature = "boring-tls"))]
pub fn certificate_chain(&self) -> Result<Vec<Vec<u8>>, Error> { pub fn certificate_chain(&self) -> Result<Vec<Vec<u8>>, Error> {
self.stream.get_ref().certificate_chain() self.stream.get_ref().certificate_chain()
} }

View File

@@ -12,9 +12,9 @@ use futures_io::{
AsyncRead as FuturesAsyncRead, AsyncWrite as FuturesAsyncWrite, Error as IoError, ErrorKind, AsyncRead as FuturesAsyncRead, AsyncWrite as FuturesAsyncWrite, Error as IoError, ErrorKind,
Result as IoResult, Result as IoResult,
}; };
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
use futures_rustls::client::TlsStream as AsyncStd1RustlsTlsStream; use futures_rustls::client::TlsStream as AsyncStd1RustlsTlsStream;
#[cfg(any(feature = "tokio1-rustls-tls", feature = "async-std1-rustls-tls"))] #[cfg(any(feature = "tokio1-rustls", feature = "async-std1-rustls"))]
use rustls::pki_types::ServerName; use rustls::pki_types::ServerName;
#[cfg(feature = "tokio1-boring-tls")] #[cfg(feature = "tokio1-boring-tls")]
use tokio1_boring::SslStream as Tokio1SslStream; use tokio1_boring::SslStream as Tokio1SslStream;
@@ -27,14 +27,14 @@ use tokio1_crate::net::{
}; };
#[cfg(feature = "tokio1-native-tls")] #[cfg(feature = "tokio1-native-tls")]
use tokio1_native_tls_crate::TlsStream as Tokio1TlsStream; use tokio1_native_tls_crate::TlsStream as Tokio1TlsStream;
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
use tokio1_rustls::client::TlsStream as Tokio1RustlsTlsStream; use tokio1_rustls::client::TlsStream as Tokio1RustlsTlsStream;
#[cfg(any( #[cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "tokio1-boring-tls", feature = "tokio1-boring-tls",
feature = "async-std1-rustls-tls" feature = "async-std1-rustls"
))] ))]
use super::InnerTlsParameters; use super::InnerTlsParameters;
use super::TlsParameters; use super::TlsParameters;
@@ -78,7 +78,7 @@ enum InnerAsyncNetworkStream {
#[cfg(feature = "tokio1-native-tls")] #[cfg(feature = "tokio1-native-tls")]
Tokio1NativeTls(Tokio1TlsStream<Box<dyn AsyncTokioStream>>), Tokio1NativeTls(Tokio1TlsStream<Box<dyn AsyncTokioStream>>),
/// Encrypted Tokio 1.x TCP stream /// Encrypted Tokio 1.x TCP stream
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
Tokio1RustlsTls(Tokio1RustlsTlsStream<Box<dyn AsyncTokioStream>>), Tokio1RustlsTls(Tokio1RustlsTlsStream<Box<dyn AsyncTokioStream>>),
/// Encrypted Tokio 1.x TCP stream /// Encrypted Tokio 1.x TCP stream
#[cfg(feature = "tokio1-boring-tls")] #[cfg(feature = "tokio1-boring-tls")]
@@ -87,7 +87,7 @@ enum InnerAsyncNetworkStream {
#[cfg(feature = "async-std1")] #[cfg(feature = "async-std1")]
AsyncStd1Tcp(AsyncStd1TcpStream), AsyncStd1Tcp(AsyncStd1TcpStream),
/// Encrypted Tokio 1.x TCP stream /// Encrypted Tokio 1.x TCP stream
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
AsyncStd1RustlsTls(AsyncStd1RustlsTlsStream<AsyncStd1TcpStream>), AsyncStd1RustlsTls(AsyncStd1RustlsTlsStream<AsyncStd1TcpStream>),
/// Can't be built /// Can't be built
None, None,
@@ -112,13 +112,13 @@ impl AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio1NativeTls(s) => { InnerAsyncNetworkStream::Tokio1NativeTls(s) => {
s.get_ref().get_ref().get_ref().peer_addr() s.get_ref().get_ref().get_ref().peer_addr()
} }
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(s) => s.get_ref().0.peer_addr(), InnerAsyncNetworkStream::Tokio1RustlsTls(s) => s.get_ref().0.peer_addr(),
#[cfg(feature = "tokio1-boring-tls")] #[cfg(feature = "tokio1-boring-tls")]
InnerAsyncNetworkStream::Tokio1BoringTls(s) => s.get_ref().peer_addr(), InnerAsyncNetworkStream::Tokio1BoringTls(s) => s.get_ref().peer_addr(),
#[cfg(feature = "async-std1")] #[cfg(feature = "async-std1")]
InnerAsyncNetworkStream::AsyncStd1Tcp(s) => s.peer_addr(), InnerAsyncNetworkStream::AsyncStd1Tcp(s) => s.peer_addr(),
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => s.get_ref().0.peer_addr(), InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => s.get_ref().0.peer_addr(),
InnerAsyncNetworkStream::None => { InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built"); debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
@@ -258,18 +258,18 @@ impl AsyncNetworkStream {
feature = "tokio1", feature = "tokio1",
not(any( not(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "tokio1-boring-tls" feature = "tokio1-boring-tls"
)) ))
))] ))]
InnerAsyncNetworkStream::Tokio1Tcp(_) => { InnerAsyncNetworkStream::Tokio1Tcp(_) => {
let _ = tls_parameters; let _ = tls_parameters;
panic!("Trying to upgrade an AsyncNetworkStream without having enabled either the tokio1-native-tls or the tokio1-rustls-tls feature"); panic!("Trying to upgrade an AsyncNetworkStream without having enabled either the tokio1-native-tls or the tokio1-rustls feature");
} }
#[cfg(any( #[cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "tokio1-boring-tls" feature = "tokio1-boring-tls"
))] ))]
InnerAsyncNetworkStream::Tokio1Tcp(_) => { InnerAsyncNetworkStream::Tokio1Tcp(_) => {
@@ -284,13 +284,13 @@ impl AsyncNetworkStream {
.map_err(error::connection)?; .map_err(error::connection)?;
Ok(()) Ok(())
} }
#[cfg(all(feature = "async-std1", not(feature = "async-std1-rustls-tls")))] #[cfg(all(feature = "async-std1", not(feature = "async-std1-rustls")))]
InnerAsyncNetworkStream::AsyncStd1Tcp(_) => { InnerAsyncNetworkStream::AsyncStd1Tcp(_) => {
let _ = tls_parameters; let _ = tls_parameters;
panic!("Trying to upgrade an AsyncNetworkStream without having enabled the async-std1-rustls-tls feature"); panic!("Trying to upgrade an AsyncNetworkStream without having enabled the async-std1-rustls feature");
} }
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1Tcp(_) => { InnerAsyncNetworkStream::AsyncStd1Tcp(_) => {
// get owned TcpStream // get owned TcpStream
let tcp_stream = mem::replace(&mut self.inner, InnerAsyncNetworkStream::None); let tcp_stream = mem::replace(&mut self.inner, InnerAsyncNetworkStream::None);
@@ -310,7 +310,7 @@ impl AsyncNetworkStream {
#[allow(unused_variables)] #[allow(unused_variables)]
#[cfg(any( #[cfg(any(
feature = "tokio1-native-tls", feature = "tokio1-native-tls",
feature = "tokio1-rustls-tls", feature = "tokio1-rustls",
feature = "tokio1-boring-tls" feature = "tokio1-boring-tls"
))] ))]
async fn upgrade_tokio1_tls( async fn upgrade_tokio1_tls(
@@ -337,12 +337,12 @@ impl AsyncNetworkStream {
Ok(InnerAsyncNetworkStream::Tokio1NativeTls(stream)) Ok(InnerAsyncNetworkStream::Tokio1NativeTls(stream))
}; };
} }
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerTlsParameters::RustlsTls(config) => { InnerTlsParameters::RustlsTls(config) => {
#[cfg(not(feature = "tokio1-rustls-tls"))] #[cfg(not(feature = "tokio1-rustls"))]
panic!("built without the tokio1-rustls-tls feature"); panic!("built without the tokio1-rustls feature");
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
return { return {
use tokio1_rustls::TlsConnector; use tokio1_rustls::TlsConnector;
@@ -377,7 +377,7 @@ impl AsyncNetworkStream {
} }
#[allow(unused_variables)] #[allow(unused_variables)]
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
async fn upgrade_asyncstd1_tls( async fn upgrade_asyncstd1_tls(
tcp_stream: AsyncStd1TcpStream, tcp_stream: AsyncStd1TcpStream,
mut tls_parameters: TlsParameters, mut tls_parameters: TlsParameters,
@@ -389,12 +389,12 @@ impl AsyncNetworkStream {
InnerTlsParameters::NativeTls(connector) => { InnerTlsParameters::NativeTls(connector) => {
panic!("native-tls isn't supported with async-std yet. See https://github.com/lettre/lettre/pull/531#issuecomment-757893531"); panic!("native-tls isn't supported with async-std yet. See https://github.com/lettre/lettre/pull/531#issuecomment-757893531");
} }
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerTlsParameters::RustlsTls(config) => { InnerTlsParameters::RustlsTls(config) => {
#[cfg(not(feature = "async-std1-rustls-tls"))] #[cfg(not(feature = "async-std1-rustls"))]
panic!("built without the async-std1-rustls-tls feature"); panic!("built without the async-std1-rustls feature");
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
return { return {
use futures_rustls::TlsConnector; use futures_rustls::TlsConnector;
@@ -422,13 +422,13 @@ impl AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio1Tcp(_) => false, InnerAsyncNetworkStream::Tokio1Tcp(_) => false,
#[cfg(feature = "tokio1-native-tls")] #[cfg(feature = "tokio1-native-tls")]
InnerAsyncNetworkStream::Tokio1NativeTls(_) => true, InnerAsyncNetworkStream::Tokio1NativeTls(_) => true,
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(_) => true, InnerAsyncNetworkStream::Tokio1RustlsTls(_) => true,
#[cfg(feature = "tokio1-boring-tls")] #[cfg(feature = "tokio1-boring-tls")]
InnerAsyncNetworkStream::Tokio1BoringTls(_) => true, InnerAsyncNetworkStream::Tokio1BoringTls(_) => true,
#[cfg(feature = "async-std1")] #[cfg(feature = "async-std1")]
InnerAsyncNetworkStream::AsyncStd1Tcp(_) => false, InnerAsyncNetworkStream::AsyncStd1Tcp(_) => false,
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(_) => true, InnerAsyncNetworkStream::AsyncStd1RustlsTls(_) => true,
InnerAsyncNetworkStream::None => false, InnerAsyncNetworkStream::None => false,
} }
@@ -443,7 +443,7 @@ impl AsyncNetworkStream {
} }
#[cfg(feature = "tokio1-native-tls")] #[cfg(feature = "tokio1-native-tls")]
InnerAsyncNetworkStream::Tokio1NativeTls(_) => panic!("Unsupported"), InnerAsyncNetworkStream::Tokio1NativeTls(_) => panic!("Unsupported"),
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(_) => panic!("Unsupported"), InnerAsyncNetworkStream::Tokio1RustlsTls(_) => panic!("Unsupported"),
#[cfg(feature = "tokio1-boring-tls")] #[cfg(feature = "tokio1-boring-tls")]
InnerAsyncNetworkStream::Tokio1BoringTls(stream) => { InnerAsyncNetworkStream::Tokio1BoringTls(stream) => {
@@ -453,7 +453,7 @@ impl AsyncNetworkStream {
InnerAsyncNetworkStream::AsyncStd1Tcp(_) => { InnerAsyncNetworkStream::AsyncStd1Tcp(_) => {
Err(error::client("Connection is not encrypted")) Err(error::client("Connection is not encrypted"))
} }
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(_) => panic!("Unsupported"), InnerAsyncNetworkStream::AsyncStd1RustlsTls(_) => panic!("Unsupported"),
InnerAsyncNetworkStream::None => panic!("InnerNetworkStream::None must never be built"), InnerAsyncNetworkStream::None => panic!("InnerNetworkStream::None must never be built"),
} }
@@ -466,7 +466,7 @@ impl AsyncNetworkStream {
} }
#[cfg(feature = "tokio1-native-tls")] #[cfg(feature = "tokio1-native-tls")]
InnerAsyncNetworkStream::Tokio1NativeTls(_) => panic!("Unsupported"), InnerAsyncNetworkStream::Tokio1NativeTls(_) => panic!("Unsupported"),
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(stream) => Ok(stream InnerAsyncNetworkStream::Tokio1RustlsTls(stream) => Ok(stream
.get_ref() .get_ref()
.1 .1
@@ -487,7 +487,7 @@ impl AsyncNetworkStream {
InnerAsyncNetworkStream::AsyncStd1Tcp(_) => { InnerAsyncNetworkStream::AsyncStd1Tcp(_) => {
Err(error::client("Connection is not encrypted")) Err(error::client("Connection is not encrypted"))
} }
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(stream) => Ok(stream InnerAsyncNetworkStream::AsyncStd1RustlsTls(stream) => Ok(stream
.get_ref() .get_ref()
.1 .1
@@ -514,7 +514,7 @@ impl AsyncNetworkStream {
.unwrap() .unwrap()
.to_der() .to_der()
.map_err(error::tls)?), .map_err(error::tls)?),
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(stream) => Ok(stream InnerAsyncNetworkStream::Tokio1RustlsTls(stream) => Ok(stream
.get_ref() .get_ref()
.1 .1
@@ -534,7 +534,7 @@ impl AsyncNetworkStream {
InnerAsyncNetworkStream::AsyncStd1Tcp(_) => { InnerAsyncNetworkStream::AsyncStd1Tcp(_) => {
Err(error::client("Connection is not encrypted")) Err(error::client("Connection is not encrypted"))
} }
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(stream) => Ok(stream InnerAsyncNetworkStream::AsyncStd1RustlsTls(stream) => Ok(stream
.get_ref() .get_ref()
.1 .1
@@ -574,7 +574,7 @@ impl FuturesAsyncRead for AsyncNetworkStream {
Poll::Pending => Poll::Pending, Poll::Pending => Poll::Pending,
} }
} }
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(s) => { InnerAsyncNetworkStream::Tokio1RustlsTls(s) => {
let mut b = Tokio1ReadBuf::new(buf); let mut b = Tokio1ReadBuf::new(buf);
match Pin::new(s).poll_read(cx, &mut b) { match Pin::new(s).poll_read(cx, &mut b) {
@@ -594,7 +594,7 @@ impl FuturesAsyncRead for AsyncNetworkStream {
} }
#[cfg(feature = "async-std1")] #[cfg(feature = "async-std1")]
InnerAsyncNetworkStream::AsyncStd1Tcp(s) => Pin::new(s).poll_read(cx, buf), InnerAsyncNetworkStream::AsyncStd1Tcp(s) => Pin::new(s).poll_read(cx, buf),
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => Pin::new(s).poll_read(cx, buf), InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => Pin::new(s).poll_read(cx, buf),
InnerAsyncNetworkStream::None => { InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built"); debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
@@ -616,13 +616,13 @@ impl FuturesAsyncWrite for AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio1Tcp(s) => Pin::new(s).poll_write(cx, buf), InnerAsyncNetworkStream::Tokio1Tcp(s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "tokio1-native-tls")] #[cfg(feature = "tokio1-native-tls")]
InnerAsyncNetworkStream::Tokio1NativeTls(s) => Pin::new(s).poll_write(cx, buf), InnerAsyncNetworkStream::Tokio1NativeTls(s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(s) => Pin::new(s).poll_write(cx, buf), InnerAsyncNetworkStream::Tokio1RustlsTls(s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "tokio1-boring-tls")] #[cfg(feature = "tokio1-boring-tls")]
InnerAsyncNetworkStream::Tokio1BoringTls(s) => Pin::new(s).poll_write(cx, buf), InnerAsyncNetworkStream::Tokio1BoringTls(s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "async-std1")] #[cfg(feature = "async-std1")]
InnerAsyncNetworkStream::AsyncStd1Tcp(s) => Pin::new(s).poll_write(cx, buf), InnerAsyncNetworkStream::AsyncStd1Tcp(s) => Pin::new(s).poll_write(cx, buf),
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => Pin::new(s).poll_write(cx, buf), InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => Pin::new(s).poll_write(cx, buf),
InnerAsyncNetworkStream::None => { InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built"); debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
@@ -637,13 +637,13 @@ impl FuturesAsyncWrite for AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio1Tcp(s) => Pin::new(s).poll_flush(cx), InnerAsyncNetworkStream::Tokio1Tcp(s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "tokio1-native-tls")] #[cfg(feature = "tokio1-native-tls")]
InnerAsyncNetworkStream::Tokio1NativeTls(s) => Pin::new(s).poll_flush(cx), InnerAsyncNetworkStream::Tokio1NativeTls(s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(s) => Pin::new(s).poll_flush(cx), InnerAsyncNetworkStream::Tokio1RustlsTls(s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "tokio1-boring-tls")] #[cfg(feature = "tokio1-boring-tls")]
InnerAsyncNetworkStream::Tokio1BoringTls(s) => Pin::new(s).poll_flush(cx), InnerAsyncNetworkStream::Tokio1BoringTls(s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "async-std1")] #[cfg(feature = "async-std1")]
InnerAsyncNetworkStream::AsyncStd1Tcp(s) => Pin::new(s).poll_flush(cx), InnerAsyncNetworkStream::AsyncStd1Tcp(s) => Pin::new(s).poll_flush(cx),
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => Pin::new(s).poll_flush(cx), InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => Pin::new(s).poll_flush(cx),
InnerAsyncNetworkStream::None => { InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built"); debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");
@@ -658,13 +658,13 @@ impl FuturesAsyncWrite for AsyncNetworkStream {
InnerAsyncNetworkStream::Tokio1Tcp(s) => Pin::new(s).poll_shutdown(cx), InnerAsyncNetworkStream::Tokio1Tcp(s) => Pin::new(s).poll_shutdown(cx),
#[cfg(feature = "tokio1-native-tls")] #[cfg(feature = "tokio1-native-tls")]
InnerAsyncNetworkStream::Tokio1NativeTls(s) => Pin::new(s).poll_shutdown(cx), InnerAsyncNetworkStream::Tokio1NativeTls(s) => Pin::new(s).poll_shutdown(cx),
#[cfg(feature = "tokio1-rustls-tls")] #[cfg(feature = "tokio1-rustls")]
InnerAsyncNetworkStream::Tokio1RustlsTls(s) => Pin::new(s).poll_shutdown(cx), InnerAsyncNetworkStream::Tokio1RustlsTls(s) => Pin::new(s).poll_shutdown(cx),
#[cfg(feature = "tokio1-boring-tls")] #[cfg(feature = "tokio1-boring-tls")]
InnerAsyncNetworkStream::Tokio1BoringTls(s) => Pin::new(s).poll_shutdown(cx), InnerAsyncNetworkStream::Tokio1BoringTls(s) => Pin::new(s).poll_shutdown(cx),
#[cfg(feature = "async-std1")] #[cfg(feature = "async-std1")]
InnerAsyncNetworkStream::AsyncStd1Tcp(s) => Pin::new(s).poll_close(cx), InnerAsyncNetworkStream::AsyncStd1Tcp(s) => Pin::new(s).poll_close(cx),
#[cfg(feature = "async-std1-rustls-tls")] #[cfg(feature = "async-std1-rustls")]
InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => Pin::new(s).poll_close(cx), InnerAsyncNetworkStream::AsyncStd1RustlsTls(s) => Pin::new(s).poll_close(cx),
InnerAsyncNetworkStream::None => { InnerAsyncNetworkStream::None => {
debug_assert!(false, "InnerAsyncNetworkStream::None must never be built"); debug_assert!(false, "InnerAsyncNetworkStream::None must never be built");

View File

@@ -143,7 +143,7 @@ impl SmtpConnection {
hello_name: &ClientId, hello_name: &ClientId,
) -> Result<(), Error> { ) -> Result<(), Error> {
if self.server_info.supports_feature(Extension::StartTls) { if self.server_info.supports_feature(Extension::StartTls) {
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
{ {
try_smtp!(self.command(Starttls), self); try_smtp!(self.command(Starttls), self);
self.stream.get_mut().upgrade_tls(tls_parameters)?; self.stream.get_mut().upgrade_tls(tls_parameters)?;
@@ -153,11 +153,7 @@ impl SmtpConnection {
try_smtp!(self.ehlo(hello_name), self); try_smtp!(self.ehlo(hello_name), self);
Ok(()) Ok(())
} }
#[cfg(not(any( #[cfg(not(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))]
feature = "native-tls",
feature = "rustls-tls",
feature = "boring-tls"
)))]
// This should never happen as `Tls` can only be created // This should never happen as `Tls` can only be created
// when a TLS library is enabled // when a TLS library is enabled
unreachable!("TLS support required but not supported"); unreachable!("TLS support required but not supported");
@@ -303,7 +299,7 @@ impl SmtpConnection {
} }
/// The X509 certificate of the server (DER encoded) /// The X509 certificate of the server (DER encoded)
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
pub fn peer_certificate(&self) -> Result<Vec<u8>, Error> { pub fn peer_certificate(&self) -> Result<Vec<u8>, Error> {
self.stream.get_ref().peer_certificate() self.stream.get_ref().peer_certificate()
} }
@@ -325,7 +321,7 @@ impl SmtpConnection {
} }
/// All the X509 certificates of the chain (DER encoded) /// All the X509 certificates of the chain (DER encoded)
#[cfg(any(feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "rustls", feature = "boring-tls"))]
pub fn certificate_chain(&self) -> Result<Vec<Vec<u8>>, Error> { pub fn certificate_chain(&self) -> Result<Vec<Vec<u8>>, Error> {
self.stream.get_ref().certificate_chain() self.stream.get_ref().certificate_chain()
} }

View File

@@ -33,9 +33,9 @@ pub use self::async_net::AsyncNetworkStream;
#[cfg(feature = "tokio1")] #[cfg(feature = "tokio1")]
pub use self::async_net::AsyncTokioStream; pub use self::async_net::AsyncTokioStream;
use self::net::NetworkStream; use self::net::NetworkStream;
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
pub(super) use self::tls::InnerTlsParameters; pub(super) use self::tls::InnerTlsParameters;
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
pub use self::tls::TlsVersion; pub use self::tls::TlsVersion;
pub use self::{ pub use self::{
connection::SmtpConnection, connection::SmtpConnection,

View File

@@ -1,4 +1,4 @@
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
use std::sync::Arc; use std::sync::Arc;
use std::{ use std::{
io::{self, Read, Write}, io::{self, Read, Write},
@@ -11,11 +11,11 @@ use std::{
use boring::ssl::SslStream; use boring::ssl::SslStream;
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
use native_tls::TlsStream; use native_tls::TlsStream;
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
use rustls::{pki_types::ServerName, ClientConnection, StreamOwned}; use rustls::{pki_types::ServerName, ClientConnection, StreamOwned};
use socket2::{Domain, Protocol, Type}; use socket2::{Domain, Protocol, Type};
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
use super::InnerTlsParameters; use super::InnerTlsParameters;
use super::TlsParameters; use super::TlsParameters;
use crate::transport::smtp::{error, Error}; use crate::transport::smtp::{error, Error};
@@ -36,7 +36,7 @@ enum InnerNetworkStream {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
NativeTls(TlsStream<TcpStream>), NativeTls(TlsStream<TcpStream>),
/// Encrypted TCP stream /// Encrypted TCP stream
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
RustlsTls(StreamOwned<ClientConnection, TcpStream>), RustlsTls(StreamOwned<ClientConnection, TcpStream>),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
BoringTls(SslStream<TcpStream>), BoringTls(SslStream<TcpStream>),
@@ -59,7 +59,7 @@ impl NetworkStream {
InnerNetworkStream::Tcp(s) => s.peer_addr(), InnerNetworkStream::Tcp(s) => s.peer_addr(),
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(s) => s.get_ref().peer_addr(), InnerNetworkStream::NativeTls(s) => s.get_ref().peer_addr(),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(s) => s.get_ref().peer_addr(), InnerNetworkStream::RustlsTls(s) => s.get_ref().peer_addr(),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(s) => s.get_ref().peer_addr(), InnerNetworkStream::BoringTls(s) => s.get_ref().peer_addr(),
@@ -79,7 +79,7 @@ impl NetworkStream {
InnerNetworkStream::Tcp(s) => s.shutdown(how), InnerNetworkStream::Tcp(s) => s.shutdown(how),
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(s) => s.get_ref().shutdown(how), InnerNetworkStream::NativeTls(s) => s.get_ref().shutdown(how),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(s) => s.get_ref().shutdown(how), InnerNetworkStream::RustlsTls(s) => s.get_ref().shutdown(how),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(s) => s.get_ref().shutdown(how), InnerNetworkStream::BoringTls(s) => s.get_ref().shutdown(how),
@@ -146,17 +146,13 @@ impl NetworkStream {
pub fn upgrade_tls(&mut self, tls_parameters: &TlsParameters) -> Result<(), Error> { pub fn upgrade_tls(&mut self, tls_parameters: &TlsParameters) -> Result<(), Error> {
match &self.inner { match &self.inner {
#[cfg(not(any( #[cfg(not(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))]
feature = "native-tls",
feature = "rustls-tls",
feature = "boring-tls"
)))]
InnerNetworkStream::Tcp(_) => { InnerNetworkStream::Tcp(_) => {
let _ = tls_parameters; let _ = tls_parameters;
panic!("Trying to upgrade an NetworkStream without having enabled either the native-tls or the rustls-tls feature"); panic!("Trying to upgrade an NetworkStream without having enabled either the `native-tls` or the `rustls` feature");
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
InnerNetworkStream::Tcp(_) => { InnerNetworkStream::Tcp(_) => {
// get owned TcpStream // get owned TcpStream
let tcp_stream = mem::replace(&mut self.inner, InnerNetworkStream::None); let tcp_stream = mem::replace(&mut self.inner, InnerNetworkStream::None);
@@ -171,7 +167,7 @@ impl NetworkStream {
} }
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
fn upgrade_tls_impl( fn upgrade_tls_impl(
tcp_stream: TcpStream, tcp_stream: TcpStream,
tls_parameters: &TlsParameters, tls_parameters: &TlsParameters,
@@ -184,7 +180,7 @@ impl NetworkStream {
.map_err(error::connection)?; .map_err(error::connection)?;
InnerNetworkStream::NativeTls(stream) InnerNetworkStream::NativeTls(stream)
} }
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerTlsParameters::RustlsTls(connector) => { InnerTlsParameters::RustlsTls(connector) => {
let domain = ServerName::try_from(tls_parameters.domain()) let domain = ServerName::try_from(tls_parameters.domain())
.map_err(|_| error::connection("domain isn't a valid DNS name"))?; .map_err(|_| error::connection("domain isn't a valid DNS name"))?;
@@ -211,7 +207,7 @@ impl NetworkStream {
InnerNetworkStream::Tcp(_) => false, InnerNetworkStream::Tcp(_) => false,
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(_) => true, InnerNetworkStream::NativeTls(_) => true,
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(_) => true, InnerNetworkStream::RustlsTls(_) => true,
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(_) => true, InnerNetworkStream::BoringTls(_) => true,
@@ -228,7 +224,7 @@ impl NetworkStream {
InnerNetworkStream::Tcp(_) => Err(error::client("Connection is not encrypted")), InnerNetworkStream::Tcp(_) => Err(error::client("Connection is not encrypted")),
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(_) => panic!("Unsupported"), InnerNetworkStream::NativeTls(_) => panic!("Unsupported"),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(_) => panic!("Unsupported"), InnerNetworkStream::RustlsTls(_) => panic!("Unsupported"),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(stream) => { InnerNetworkStream::BoringTls(stream) => {
@@ -238,13 +234,13 @@ impl NetworkStream {
} }
} }
#[cfg(any(feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "rustls", feature = "boring-tls"))]
pub fn certificate_chain(&self) -> Result<Vec<Vec<u8>>, Error> { pub fn certificate_chain(&self) -> Result<Vec<Vec<u8>>, Error> {
match &self.inner { match &self.inner {
InnerNetworkStream::Tcp(_) => Err(error::client("Connection is not encrypted")), InnerNetworkStream::Tcp(_) => Err(error::client("Connection is not encrypted")),
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(_) => panic!("Unsupported"), InnerNetworkStream::NativeTls(_) => panic!("Unsupported"),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(stream) => Ok(stream InnerNetworkStream::RustlsTls(stream) => Ok(stream
.conn .conn
.peer_certificates() .peer_certificates()
@@ -264,7 +260,7 @@ impl NetworkStream {
} }
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
pub fn peer_certificate(&self) -> Result<Vec<u8>, Error> { pub fn peer_certificate(&self) -> Result<Vec<u8>, Error> {
match &self.inner { match &self.inner {
InnerNetworkStream::Tcp(_) => Err(error::client("Connection is not encrypted")), InnerNetworkStream::Tcp(_) => Err(error::client("Connection is not encrypted")),
@@ -275,7 +271,7 @@ impl NetworkStream {
.unwrap() .unwrap()
.to_der() .to_der()
.map_err(error::tls)?), .map_err(error::tls)?),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(stream) => Ok(stream InnerNetworkStream::RustlsTls(stream) => Ok(stream
.conn .conn
.peer_certificates() .peer_certificates()
@@ -299,7 +295,7 @@ impl NetworkStream {
InnerNetworkStream::Tcp(stream) => stream.set_read_timeout(duration), InnerNetworkStream::Tcp(stream) => stream.set_read_timeout(duration),
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(stream) => stream.get_ref().set_read_timeout(duration), InnerNetworkStream::NativeTls(stream) => stream.get_ref().set_read_timeout(duration),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(stream) => stream.get_ref().set_read_timeout(duration), InnerNetworkStream::RustlsTls(stream) => stream.get_ref().set_read_timeout(duration),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(stream) => stream.get_ref().set_read_timeout(duration), InnerNetworkStream::BoringTls(stream) => stream.get_ref().set_read_timeout(duration),
@@ -317,7 +313,7 @@ impl NetworkStream {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(stream) => stream.get_ref().set_write_timeout(duration), InnerNetworkStream::NativeTls(stream) => stream.get_ref().set_write_timeout(duration),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(stream) => stream.get_ref().set_write_timeout(duration), InnerNetworkStream::RustlsTls(stream) => stream.get_ref().set_write_timeout(duration),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(stream) => stream.get_ref().set_write_timeout(duration), InnerNetworkStream::BoringTls(stream) => stream.get_ref().set_write_timeout(duration),
@@ -335,7 +331,7 @@ impl Read for NetworkStream {
InnerNetworkStream::Tcp(s) => s.read(buf), InnerNetworkStream::Tcp(s) => s.read(buf),
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(s) => s.read(buf), InnerNetworkStream::NativeTls(s) => s.read(buf),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(s) => s.read(buf), InnerNetworkStream::RustlsTls(s) => s.read(buf),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(s) => s.read(buf), InnerNetworkStream::BoringTls(s) => s.read(buf),
@@ -353,7 +349,7 @@ impl Write for NetworkStream {
InnerNetworkStream::Tcp(s) => s.write(buf), InnerNetworkStream::Tcp(s) => s.write(buf),
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(s) => s.write(buf), InnerNetworkStream::NativeTls(s) => s.write(buf),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(s) => s.write(buf), InnerNetworkStream::RustlsTls(s) => s.write(buf),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(s) => s.write(buf), InnerNetworkStream::BoringTls(s) => s.write(buf),
@@ -369,7 +365,7 @@ impl Write for NetworkStream {
InnerNetworkStream::Tcp(s) => s.flush(), InnerNetworkStream::Tcp(s) => s.flush(),
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
InnerNetworkStream::NativeTls(s) => s.flush(), InnerNetworkStream::NativeTls(s) => s.flush(),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
InnerNetworkStream::RustlsTls(s) => s.flush(), InnerNetworkStream::RustlsTls(s) => s.flush(),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
InnerNetworkStream::BoringTls(s) => s.flush(), InnerNetworkStream::BoringTls(s) => s.flush(),

View File

@@ -1,5 +1,5 @@
use std::fmt::{self, Debug}; use std::fmt::{self, Debug};
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
use std::sync::Arc; use std::sync::Arc;
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
@@ -10,7 +10,7 @@ use boring::{
}; };
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
use native_tls::{Protocol, TlsConnector}; use native_tls::{Protocol, TlsConnector};
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
use rustls::{ use rustls::{
client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}, client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier},
crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider}, crypto::{verify_tls12_signature, verify_tls13_signature, CryptoProvider},
@@ -19,13 +19,13 @@ use rustls::{
ClientConfig, DigitallySignedStruct, Error as TlsError, RootCertStore, SignatureScheme, ClientConfig, DigitallySignedStruct, Error as TlsError, RootCertStore, SignatureScheme,
}; };
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
use crate::transport::smtp::{error, Error}; use crate::transport::smtp::{error, Error};
/// TLS protocol versions. /// TLS protocol versions.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
#[non_exhaustive] #[non_exhaustive]
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
pub enum TlsVersion { pub enum TlsVersion {
/// TLS 1.0 /// TLS 1.0
/// ///
@@ -85,10 +85,10 @@ pub enum Tls {
/// ///
/// Warning: A malicious intermediary could intercept the `STARTTLS` flag, /// Warning: A malicious intermediary could intercept the `STARTTLS` flag,
/// causing lettre to believe the server only supports plaintext connections. /// causing lettre to believe the server only supports plaintext connections.
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
Opportunistic(TlsParameters), Opportunistic(TlsParameters),
/// Begin with a plaintext connection and require `STARTTLS` for security. /// Begin with a plaintext connection and require `STARTTLS` for security.
@@ -100,10 +100,10 @@ pub enum Tls {
/// Unlike [`Tls::Opportunistic`], this option is secure against MITM attacks. /// Unlike [`Tls::Opportunistic`], this option is secure against MITM attacks.
/// For optimal security and performance, consider using [`Tls::Wrapper`] instead, /// For optimal security and performance, consider using [`Tls::Wrapper`] instead,
/// as it requires fewer roundtrips to establish a secure connection. /// as it requires fewer roundtrips to establish a secure connection.
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
Required(TlsParameters), Required(TlsParameters),
/// Establish a connection wrapped in TLS from the start. /// Establish a connection wrapped in TLS from the start.
@@ -113,10 +113,10 @@ pub enum Tls {
/// transmitting any sensitive data. /// transmitting any sensitive data.
/// ///
/// This is the fastest and most secure option for establishing a connection. /// This is the fastest and most secure option for establishing a connection.
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
Wrapper(TlsParameters), Wrapper(TlsParameters),
} }
@@ -125,11 +125,11 @@ impl Debug for Tls {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self { match &self {
Self::None => f.pad("None"), Self::None => f.pad("None"),
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
Self::Opportunistic(_) => f.pad("Opportunistic"), Self::Opportunistic(_) => f.pad("Opportunistic"),
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
Self::Required(_) => f.pad("Required"), Self::Required(_) => f.pad("Required"),
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
Self::Wrapper(_) => f.pad("Wrapper"), Self::Wrapper(_) => f.pad("Wrapper"),
} }
} }
@@ -153,7 +153,7 @@ pub enum CertificateStore {
/// Use a hardcoded set of Mozilla roots via the `webpki-roots` crate. /// Use a hardcoded set of Mozilla roots via the `webpki-roots` crate.
/// ///
/// This option is only available in the rustls backend. /// This option is only available in the rustls backend.
#[cfg(feature = "rustls-tls")] #[cfg(all(feature = "rustls", feature = "webpki-roots"))]
WebpkiRoots, WebpkiRoots,
/// Don't use any system certificates. /// Don't use any system certificates.
None, None,
@@ -178,7 +178,7 @@ pub struct TlsParametersBuilder {
identity: Option<Identity>, identity: Option<Identity>,
accept_invalid_hostnames: bool, accept_invalid_hostnames: bool,
accept_invalid_certs: bool, accept_invalid_certs: bool,
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
min_tls_version: TlsVersion, min_tls_version: TlsVersion,
} }
@@ -192,7 +192,7 @@ impl TlsParametersBuilder {
identity: None, identity: None,
accept_invalid_hostnames: false, accept_invalid_hostnames: false,
accept_invalid_certs: false, accept_invalid_certs: false,
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
min_tls_version: TlsVersion::Tlsv12, min_tls_version: TlsVersion::Tlsv12,
} }
} }
@@ -230,10 +230,10 @@ impl TlsParametersBuilder {
/// including those from other sites, are trusted. /// including those from other sites, are trusted.
/// ///
/// This method introduces significant vulnerabilities to man-in-the-middle attacks. /// This method introduces significant vulnerabilities to man-in-the-middle attacks.
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn dangerous_accept_invalid_hostnames(mut self, accept_invalid_hostnames: bool) -> Self { pub fn dangerous_accept_invalid_hostnames(mut self, accept_invalid_hostnames: bool) -> Self {
self.accept_invalid_hostnames = accept_invalid_hostnames; self.accept_invalid_hostnames = accept_invalid_hostnames;
@@ -243,7 +243,7 @@ impl TlsParametersBuilder {
/// Controls which minimum TLS version is allowed /// Controls which minimum TLS version is allowed
/// ///
/// Defaults to [`Tlsv12`][TlsVersion::Tlsv12]. /// Defaults to [`Tlsv12`][TlsVersion::Tlsv12].
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
pub fn set_min_tls_version(mut self, min_tls_version: TlsVersion) -> Self { pub fn set_min_tls_version(mut self, min_tls_version: TlsVersion) -> Self {
self.min_tls_version = min_tls_version; self.min_tls_version = min_tls_version;
self self
@@ -272,17 +272,17 @@ impl TlsParametersBuilder {
/// Creates a new `TlsParameters` using native-tls, boring-tls or rustls /// Creates a new `TlsParameters` using native-tls, boring-tls or rustls
/// depending on which one is available /// depending on which one is available
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn build(self) -> Result<TlsParameters, Error> { pub fn build(self) -> Result<TlsParameters, Error> {
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
return self.build_rustls(); return self.build_rustls();
#[cfg(all(not(feature = "rustls-tls"), feature = "native-tls"))] #[cfg(all(not(feature = "rustls"), feature = "native-tls"))]
return self.build_native(); return self.build_native();
#[cfg(all(not(feature = "rustls-tls"), feature = "boring-tls"))] #[cfg(all(not(feature = "rustls"), feature = "boring-tls"))]
return self.build_boring(); return self.build_boring();
} }
@@ -396,8 +396,8 @@ impl TlsParametersBuilder {
} }
/// Creates a new `TlsParameters` using rustls with the provided configuration /// Creates a new `TlsParameters` using rustls with the provided configuration
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))] #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
pub fn build_rustls(self) -> Result<TlsParameters, Error> { pub fn build_rustls(self) -> Result<TlsParameters, Error> {
let just_version3 = &[&rustls::version::TLS13]; let just_version3 = &[&rustls::version::TLS13];
let supported_versions = match self.min_tls_version { let supported_versions = match self.min_tls_version {
@@ -411,9 +411,7 @@ impl TlsParametersBuilder {
TlsVersion::Tlsv13 => just_version3, TlsVersion::Tlsv13 => just_version3,
}; };
let crypto_provider = CryptoProvider::get_default() let crypto_provider = crate::rustls_crypto::crypto_provider();
.cloned()
.unwrap_or_else(|| Arc::new(rustls::crypto::ring::default_provider()));
let tls = ClientConfig::builder_with_provider(Arc::clone(&crypto_provider)) let tls = ClientConfig::builder_with_provider(Arc::clone(&crypto_provider))
.with_protocol_versions(supported_versions) .with_protocol_versions(supported_versions)
.map_err(error::tls)?; .map_err(error::tls)?;
@@ -436,7 +434,7 @@ impl TlsParametersBuilder {
let _ = (errors_len, added, ignored); let _ = (errors_len, added, ignored);
} }
#[cfg(feature = "rustls-tls")] #[cfg(all(feature = "rustls", feature = "webpki-roots"))]
fn load_webpki_roots(store: &mut RootCertStore) { fn load_webpki_roots(store: &mut RootCertStore) {
store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned()); store.extend(webpki_roots::TLS_SERVER_ROOTS.iter().cloned());
} }
@@ -445,10 +443,10 @@ impl TlsParametersBuilder {
CertificateStore::Default => { CertificateStore::Default => {
#[cfg(feature = "rustls-native-certs")] #[cfg(feature = "rustls-native-certs")]
load_native_roots(&mut root_cert_store); load_native_roots(&mut root_cert_store);
#[cfg(not(feature = "rustls-native-certs"))] #[cfg(all(not(feature = "rustls-native-certs"), feature = "webpki-roots"))]
load_webpki_roots(&mut root_cert_store); load_webpki_roots(&mut root_cert_store);
} }
#[cfg(feature = "rustls-tls")] #[cfg(all(feature = "rustls", feature = "webpki-roots"))]
CertificateStore::WebpkiRoots => { CertificateStore::WebpkiRoots => {
load_webpki_roots(&mut root_cert_store); load_webpki_roots(&mut root_cert_store);
} }
@@ -495,7 +493,7 @@ impl TlsParametersBuilder {
pub enum InnerTlsParameters { pub enum InnerTlsParameters {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
NativeTls(TlsConnector), NativeTls(TlsConnector),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
RustlsTls(Arc<ClientConfig>), RustlsTls(Arc<ClientConfig>),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
BoringTls(SslConnector), BoringTls(SslConnector),
@@ -504,10 +502,10 @@ pub enum InnerTlsParameters {
impl TlsParameters { impl TlsParameters {
/// Creates a new `TlsParameters` using native-tls or rustls /// Creates a new `TlsParameters` using native-tls or rustls
/// depending on which one is available /// depending on which one is available
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn new(domain: String) -> Result<Self, Error> { pub fn new(domain: String) -> Result<Self, Error> {
TlsParametersBuilder::new(domain).build() TlsParametersBuilder::new(domain).build()
@@ -526,8 +524,8 @@ impl TlsParameters {
} }
/// Creates a new `TlsParameters` using rustls /// Creates a new `TlsParameters` using rustls
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
#[cfg_attr(docsrs, doc(cfg(feature = "rustls-tls")))] #[cfg_attr(docsrs, doc(cfg(feature = "rustls")))]
pub fn new_rustls(domain: String) -> Result<Self, Error> { pub fn new_rustls(domain: String) -> Result<Self, Error> {
TlsParametersBuilder::new(domain).build_rustls() TlsParametersBuilder::new(domain).build_rustls()
} }
@@ -550,13 +548,13 @@ impl TlsParameters {
pub struct Certificate { pub struct Certificate {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
native_tls: native_tls::Certificate, native_tls: native_tls::Certificate,
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
rustls: Vec<CertificateDer<'static>>, rustls: Vec<CertificateDer<'static>>,
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
boring_tls: boring::x509::X509, boring_tls: boring::x509::X509,
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
impl Certificate { impl Certificate {
/// Create a `Certificate` from a DER encoded certificate /// Create a `Certificate` from a DER encoded certificate
pub fn from_der(der: Vec<u8>) -> Result<Self, Error> { pub fn from_der(der: Vec<u8>) -> Result<Self, Error> {
@@ -569,7 +567,7 @@ impl Certificate {
Ok(Self { Ok(Self {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
native_tls: native_tls_cert, native_tls: native_tls_cert,
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
rustls: vec![der.into()], rustls: vec![der.into()],
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
boring_tls: boring_tls_cert, boring_tls: boring_tls_cert,
@@ -584,7 +582,7 @@ impl Certificate {
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
let boring_tls_cert = boring::x509::X509::from_pem(pem).map_err(error::tls)?; let boring_tls_cert = boring::x509::X509::from_pem(pem).map_err(error::tls)?;
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
let rustls_cert = { let rustls_cert = {
CertificateDer::pem_slice_iter(pem) CertificateDer::pem_slice_iter(pem)
.collect::<Result<Vec<_>, pki_types::pem::Error>>() .collect::<Result<Vec<_>, pki_types::pem::Error>>()
@@ -594,7 +592,7 @@ impl Certificate {
Ok(Self { Ok(Self {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
native_tls: native_tls_cert, native_tls: native_tls_cert,
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
rustls: rustls_cert, rustls: rustls_cert,
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
boring_tls: boring_tls_cert, boring_tls: boring_tls_cert,
@@ -613,7 +611,7 @@ impl Debug for Certificate {
pub struct Identity { pub struct Identity {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
native_tls: native_tls::Identity, native_tls: native_tls::Identity,
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
rustls_tls: (Vec<CertificateDer<'static>>, PrivateKeyDer<'static>), rustls_tls: (Vec<CertificateDer<'static>>, PrivateKeyDer<'static>),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
boring_tls: (boring::x509::X509, PKey<boring::pkey::Private>), boring_tls: (boring::x509::X509, PKey<boring::pkey::Private>),
@@ -630,7 +628,7 @@ impl Clone for Identity {
Identity { Identity {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
native_tls: self.native_tls.clone(), native_tls: self.native_tls.clone(),
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
rustls_tls: (self.rustls_tls.0.clone(), self.rustls_tls.1.clone_key()), rustls_tls: (self.rustls_tls.0.clone(), self.rustls_tls.1.clone_key()),
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
boring_tls: (self.boring_tls.0.clone(), self.boring_tls.1.clone()), boring_tls: (self.boring_tls.0.clone(), self.boring_tls.1.clone()),
@@ -638,13 +636,13 @@ impl Clone for Identity {
} }
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
impl Identity { impl Identity {
pub fn from_pem(pem: &[u8], key: &[u8]) -> Result<Self, Error> { pub fn from_pem(pem: &[u8], key: &[u8]) -> Result<Self, Error> {
Ok(Self { Ok(Self {
#[cfg(feature = "native-tls")] #[cfg(feature = "native-tls")]
native_tls: Identity::from_pem_native_tls(pem, key)?, native_tls: Identity::from_pem_native_tls(pem, key)?,
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
rustls_tls: Identity::from_pem_rustls_tls(pem, key)?, rustls_tls: Identity::from_pem_rustls_tls(pem, key)?,
#[cfg(feature = "boring-tls")] #[cfg(feature = "boring-tls")]
boring_tls: Identity::from_pem_boring_tls(pem, key)?, boring_tls: Identity::from_pem_boring_tls(pem, key)?,
@@ -656,7 +654,7 @@ impl Identity {
native_tls::Identity::from_pkcs8(pem, key).map_err(error::tls) native_tls::Identity::from_pkcs8(pem, key).map_err(error::tls)
} }
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
fn from_pem_rustls_tls( fn from_pem_rustls_tls(
pem: &[u8], pem: &[u8],
key: &[u8], key: &[u8],
@@ -683,7 +681,7 @@ impl Identity {
} }
} }
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
#[derive(Debug)] #[derive(Debug)]
struct InvalidCertsVerifier { struct InvalidCertsVerifier {
ignore_invalid_hostnames: bool, ignore_invalid_hostnames: bool,
@@ -692,7 +690,7 @@ struct InvalidCertsVerifier {
crypto_provider: Arc<CryptoProvider>, crypto_provider: Arc<CryptoProvider>,
} }
#[cfg(feature = "rustls-tls")] #[cfg(feature = "rustls")]
impl ServerCertVerifier for InvalidCertsVerifier { impl ServerCertVerifier for InvalidCertsVerifier {
fn verify_server_cert( fn verify_server_cert(
&self, &self,

View File

@@ -2,7 +2,7 @@ use std::borrow::Cow;
use url::Url; use url::Url;
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
use super::client::{Tls, TlsParameters}; use super::client::{Tls, TlsParameters};
#[cfg(any(feature = "tokio1", feature = "async-std1"))] #[cfg(any(feature = "tokio1", feature = "async-std1"))]
use super::AsyncSmtpTransportBuilder; use super::AsyncSmtpTransportBuilder;
@@ -82,19 +82,19 @@ pub(crate) fn from_connection_url<B: TransportBuilder>(connection_url: &str) ->
("smtp", None) => { ("smtp", None) => {
builder = builder.port(connection_url.port().unwrap_or(SMTP_PORT)); builder = builder.port(connection_url.port().unwrap_or(SMTP_PORT));
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
("smtp", Some("required")) => { ("smtp", Some("required")) => {
builder = builder builder = builder
.port(connection_url.port().unwrap_or(SUBMISSION_PORT)) .port(connection_url.port().unwrap_or(SUBMISSION_PORT))
.tls(Tls::Required(TlsParameters::new(host.into())?)); .tls(Tls::Required(TlsParameters::new(host.into())?));
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
("smtp", Some("opportunistic")) => { ("smtp", Some("opportunistic")) => {
builder = builder builder = builder
.port(connection_url.port().unwrap_or(SUBMISSION_PORT)) .port(connection_url.port().unwrap_or(SUBMISSION_PORT))
.tls(Tls::Opportunistic(TlsParameters::new(host.into())?)); .tls(Tls::Opportunistic(TlsParameters::new(host.into())?));
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
("smtps", _) => { ("smtps", _) => {
builder = builder builder = builder
.port(connection_url.port().unwrap_or(SUBMISSIONS_PORT)) .port(connection_url.port().unwrap_or(SUBMISSIONS_PORT))

View File

@@ -68,10 +68,10 @@ impl Error {
} }
/// Returns true if the error is from TLS /// Returns true if the error is from TLS
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn is_tls(&self) -> bool { pub fn is_tls(&self) -> bool {
matches!(self.inner.kind, Kind::Tls) matches!(self.inner.kind, Kind::Tls)
@@ -107,9 +107,9 @@ pub(crate) enum Kind {
/// TLS error /// TLS error
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
Tls, Tls,
} }
@@ -134,7 +134,7 @@ impl fmt::Display for Error {
Kind::Client => f.write_str("internal client error")?, Kind::Client => f.write_str("internal client error")?,
Kind::Network => f.write_str("network error")?, Kind::Network => f.write_str("network error")?,
Kind::Connection => f.write_str("Connection error")?, Kind::Connection => f.write_str("Connection error")?,
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
Kind::Tls => f.write_str("tls error")?, Kind::Tls => f.write_str("tls error")?,
Kind::Transient(code) => { Kind::Transient(code) => {
write!(f, "transient error ({code})")?; write!(f, "transient error ({code})")?;
@@ -185,7 +185,7 @@ pub(crate) fn connection<E: Into<BoxError>>(e: E) -> Error {
Error::new(Kind::Connection, Some(e)) Error::new(Kind::Connection, Some(e))
} }
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
pub(crate) fn tls<E: Into<BoxError>>(e: E) -> Error { pub(crate) fn tls<E: Into<BoxError>>(e: E) -> Error {
Error::new(Kind::Tls, Some(e)) Error::new(Kind::Tls, Some(e))
} }

View File

@@ -32,7 +32,7 @@
//! do the following: //! do the following:
//! //!
//! ```rust,no_run //! ```rust,no_run
//! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls-tls")))] //! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls")))]
//! # fn test() -> Result<(), Box<dyn std::error::Error>> { //! # fn test() -> Result<(), Box<dyn std::error::Error>> {
//! use lettre::{ //! use lettre::{
//! message::header::ContentType, //! message::header::ContentType,
@@ -73,7 +73,7 @@
//! For more information take a look at [`SmtpTransport::from_url`] or [`AsyncSmtpTransport::from_url`]. //! For more information take a look at [`SmtpTransport::from_url`] or [`AsyncSmtpTransport::from_url`].
//! //!
//! ```rust,no_run //! ```rust,no_run
//! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls-tls")))] //! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls")))]
//! # fn test() -> Result<(), Box<dyn std::error::Error>> { //! # fn test() -> Result<(), Box<dyn std::error::Error>> {
//! use lettre::{ //! use lettre::{
//! message::header::ContentType, //! message::header::ContentType,
@@ -101,7 +101,7 @@
//! #### Advanced configuration with custom TLS settings //! #### Advanced configuration with custom TLS settings
//! //!
//! ```rust,no_run //! ```rust,no_run
//! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls-tls")))] //! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls")))]
//! # fn test() -> Result<(), Box<dyn std::error::Error>> { //! # fn test() -> Result<(), Box<dyn std::error::Error>> {
//! use std::fs; //! use std::fs;
//! //!
@@ -146,7 +146,7 @@
//! In a webserver context it may go about this: //! In a webserver context it may go about this:
//! //!
//! ```rust,no_run //! ```rust,no_run
//! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls-tls")))] //! # #[cfg(all(feature = "builder", any(feature = "native-tls", feature = "rustls")))]
//! # fn test() { //! # fn test() {
//! use lettre::{ //! use lettre::{
//! message::header::ContentType, //! message::header::ContentType,
@@ -199,7 +199,7 @@ pub use self::{
error::Error, error::Error,
transport::{SmtpTransport, SmtpTransportBuilder}, transport::{SmtpTransport, SmtpTransportBuilder},
}; };
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
use crate::transport::smtp::client::TlsParameters; use crate::transport::smtp::client::TlsParameters;
use crate::transport::smtp::{ use crate::transport::smtp::{
authentication::{Credentials, Mechanism, DEFAULT_MECHANISMS}, authentication::{Credentials, Mechanism, DEFAULT_MECHANISMS},

View File

@@ -7,7 +7,7 @@ use super::pool::sync_impl::Pool;
#[cfg(feature = "pool")] #[cfg(feature = "pool")]
use super::PoolConfig; use super::PoolConfig;
use super::{ClientId, Credentials, Error, Mechanism, Response, SmtpConnection, SmtpInfo}; use super::{ClientId, Credentials, Error, Mechanism, Response, SmtpConnection, SmtpInfo};
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
use super::{Tls, TlsParameters, SUBMISSIONS_PORT, SUBMISSION_PORT}; use super::{Tls, TlsParameters, SUBMISSIONS_PORT, SUBMISSION_PORT};
use crate::{address::Envelope, Transport}; use crate::{address::Envelope, Transport};
@@ -77,10 +77,10 @@ impl SmtpTransport {
/// ///
/// Creates an encrypted transport over submissions port, using the provided domain /// Creates an encrypted transport over submissions port, using the provided domain
/// to validate TLS certificates. /// to validate TLS certificates.
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn relay(relay: &str) -> Result<SmtpTransportBuilder, Error> { pub fn relay(relay: &str) -> Result<SmtpTransportBuilder, Error> {
let tls_parameters = TlsParameters::new(relay.into())?; let tls_parameters = TlsParameters::new(relay.into())?;
@@ -101,10 +101,10 @@ impl SmtpTransport {
/// ///
/// An error is returned if the connection can't be upgraded. No credentials /// An error is returned if the connection can't be upgraded. No credentials
/// or emails will be sent to the server, protecting from downgrade attacks. /// or emails will be sent to the server, protecting from downgrade attacks.
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn starttls_relay(relay: &str) -> Result<SmtpTransportBuilder, Error> { pub fn starttls_relay(relay: &str) -> Result<SmtpTransportBuilder, Error> {
let tls_parameters = TlsParameters::new(relay.into())?; let tls_parameters = TlsParameters::new(relay.into())?;
@@ -230,10 +230,10 @@ impl SmtpTransport {
/// # Ok(()) /// # Ok(())
/// # } /// # }
/// ``` /// ```
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn from_url(connection_url: &str) -> Result<SmtpTransportBuilder, Error> { pub fn from_url(connection_url: &str) -> Result<SmtpTransportBuilder, Error> {
super::connection_url::from_connection_url(connection_url) super::connection_url::from_connection_url(connection_url)
@@ -333,10 +333,10 @@ impl SmtpTransportBuilder {
/// ///
/// Using the wrong [`Tls`] and [`Self::port`] combination may /// Using the wrong [`Tls`] and [`Self::port`] combination may
/// lead to hard to debug IO errors coming from the TLS library. /// lead to hard to debug IO errors coming from the TLS library.
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
#[cfg_attr( #[cfg_attr(
docsrs, docsrs,
doc(cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))) doc(cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls")))
)] )]
pub fn tls(mut self, tls: Tls) -> Self { pub fn tls(mut self, tls: Tls) -> Self {
self.info.tls = tls; self.info.tls = tls;
@@ -380,7 +380,7 @@ impl SmtpClient {
pub fn connection(&self) -> Result<SmtpConnection, Error> { pub fn connection(&self) -> Result<SmtpConnection, Error> {
#[allow(clippy::match_single_binding)] #[allow(clippy::match_single_binding)]
let tls_parameters = match &self.info.tls { let tls_parameters = match &self.info.tls {
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
Tls::Wrapper(tls_parameters) => Some(tls_parameters), Tls::Wrapper(tls_parameters) => Some(tls_parameters),
_ => None, _ => None,
}; };
@@ -394,7 +394,7 @@ impl SmtpClient {
None, None,
)?; )?;
#[cfg(any(feature = "native-tls", feature = "rustls-tls", feature = "boring-tls"))] #[cfg(any(feature = "native-tls", feature = "rustls", feature = "boring-tls"))]
match &self.info.tls { match &self.info.tls {
Tls::Opportunistic(tls_parameters) => { Tls::Opportunistic(tls_parameters) => {
if conn.can_starttls() { if conn.can_starttls() {