From 64c9fa54eeeb119b756633339ba925ef98efea8b Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 20 Oct 2020 12:21:01 +0200 Subject: [PATCH] Add rustls support --- Cargo.lock | 114 +++++++++++++++++++++++++++++++++++++-- Cargo.toml | 4 ++ README.md | 14 +++-- sqlx-bench/Cargo.toml | 4 ++ sqlx-bench/README.md | 2 +- sqlx-core/Cargo.toml | 13 +++-- sqlx-core/src/error.rs | 8 +++ sqlx-core/src/net/tls.rs | 21 +++++--- sqlx-macros/Cargo.toml | 4 ++ sqlx-rt/Cargo.toml | 7 +++ sqlx-rt/src/lib.rs | 30 +++++++++-- src/lib.rs | 4 +- 12 files changed, 202 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb147bfe40..2031a91d41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,6 +113,17 @@ dependencies = [ "url", ] +[[package]] +name = "async-rustls" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c238bd34d425674d8003b8d674cc04baf74e1b71802f3c62451e3bf86f2858ef" +dependencies = [ + "futures-lite 1.11.1", + "rustls", + "webpki", +] + [[package]] name = "async-std" version = "1.6.2" @@ -251,9 +262,9 @@ checksum = "d2468ff7bf85066b4a3678fede6fe66db31846d753ff0adfbfab2c6a6e81612b" dependencies = [ "async-channel", "atomic-waker", - "futures-lite", + "futures-lite 0.1.9", "once_cell", - "parking", + "parking 1.0.6", "waker-fn", ] @@ -676,9 +687,12 @@ checksum = "829694371bd7bbc6aee17c4ff624aad8bf9f4dc06c6f9f6071eaa08c89530d10" [[package]] name = "fastrand" -version = "1.3.3" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36a9cb09840f81cd211e435d00a4e487edd263dc3c8ff815c32dd76ad668ebed" +checksum = "ca5faf057445ce5c9d4329e382b2ce7ca38550ef3b73a5348362d5f24e0c7fe3" +dependencies = [ + "instant", +] [[package]] name = "fnv" @@ -775,7 +789,22 @@ dependencies = [ "futures-core", "futures-io", "memchr", - "parking", + "parking 1.0.6", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381a7ad57b1bad34693f63f6f377e1abded7a9c85c9d3eb6771e11c60aaadab9" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "memchr", + "parking 2.0.0", "pin-project-lite", "waker-fn", ] @@ -1373,6 +1402,12 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cb300f271742d4a2a66c01b6b2fa0c83dfebd2e0bf11addb879a3547b4ed87c" +[[package]] +name = "parking" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" + [[package]] name = "parking_lot" version = "0.11.0" @@ -1687,6 +1722,21 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ring" +version = "0.16.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "952cd6b98c85bbc30efa1ba5783b8abf12fec8b3287ffa52605b9432313e34e4" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi 0.3.9", +] + [[package]] name = "rsa" version = "0.3.0" @@ -1728,6 +1778,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustls" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81" +dependencies = [ + "base64 0.12.3", + "log", + "ring", + "sct", + "webpki", +] + [[package]] name = "ryu" version = "1.0.5" @@ -1765,6 +1828,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3042af939fca8c3453b7af0f1c66e533a15a86169e39de2657310ade8f98d3c" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "0.4.4" @@ -2077,6 +2150,7 @@ dependencies = [ "time 0.2.16", "url", "uuid", + "webpki", "whoami", ] @@ -2153,10 +2227,12 @@ dependencies = [ "actix-rt", "actix-threadpool", "async-native-tls", + "async-rustls", "async-std", "once_cell", "tokio", "tokio-native-tls", + "tokio-rustls", ] [[package]] @@ -2522,6 +2598,18 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a" +dependencies = [ + "futures-core", + "rustls", + "tokio", + "webpki", +] + [[package]] name = "toml" version = "0.5.6" @@ -2587,6 +2675,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.1.1" @@ -2721,6 +2815,16 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab146130f5f790d45f82aeeb09e55a256573373ec64409fc19a6fb82fb1032ae" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "wepoll-sys-stjepang" version = "1.0.6" diff --git a/Cargo.toml b/Cargo.toml index 8d2705f5c9..89801991d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,10 @@ runtime-actix-native-tls = [ "sqlx-core/runtime-actix-native-tls", "sqlx-macros/ runtime-async-std-native-tls = [ "sqlx-core/runtime-async-std-native-tls", "sqlx-macros/runtime-async-std-native-tls", "_rt-async-std" ] runtime-tokio-native-tls = [ "sqlx-core/runtime-tokio-native-tls", "sqlx-macros/runtime-tokio-native-tls", "_rt-tokio" ] +runtime-actix-rustls = [ "sqlx-core/runtime-actix-rustls", "sqlx-macros/runtime-actix-rustls", "_rt-actix" ] +runtime-async-std-rustls = [ "sqlx-core/runtime-async-std-rustls", "sqlx-macros/runtime-async-std-rustls", "_rt-async-std" ] +runtime-tokio-rustls = [ "sqlx-core/runtime-tokio-rustls", "sqlx-macros/runtime-tokio-rustls", "_rt-tokio" ] + # for conditional compilation _rt-actix = [] _rt-async-std = [] diff --git a/README.md b/README.md index 7d09992743..833559d1dc 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ SQLx is an async, pure Rust SQL crate featuring compile-time check * **Pure Rust**. The Postgres and MySQL/MariaDB drivers are written in pure Rust using **zero** unsafe†† code. - * **Runtime Agnostic**. Works on different runtimes ([async-std](https://crates.io/crates/async-std) / [tokio](https://crates.io/crates/tokio) / [actix](https://crates.io/crates/actix-rt)). + * **Runtime Agnostic**. Works on different runtimes ([async-std](https://crates.io/crates/async-std) / [tokio](https://crates.io/crates/tokio) / [actix](https://crates.io/crates/actix-rt)) and TLS backends ([native-tls](https://crates.io/crates/native-tls), [rustls](https://crates.io/crates/rustls)). † The SQLite driver uses the libsqlite3 C library as SQLite is an embedded database (the only way we could be pure Rust for SQLite is by porting _all_ of SQLite to Rust). @@ -109,12 +109,14 @@ SQLx is compatible with the [`async-std`], [`tokio`] and [`actix`] runtimes. [`tokio`]: https://github.com/tokio-rs/tokio [`actix`]: https://github.com/actix/actix-net -By default, you get `async-std`. If you want a different runtime or TLS backend, just disable the default features and activate the corresponding feature, for example for tokio: +You can also select between [`native-tls`] and [`rustls`] for the TLS backend. + +By default, you get `async-std` + `native-tls`. If you want a different runtime or TLS backend, just disable the default features and activate the corresponding feature, for example for tokio + rustls: ```toml # Cargo.toml [dependencies] -sqlx = { version = "0.4.0-beta.1", default-features = false, features = [ "runtime-tokio-native-tls", "macros" ] } +sqlx = { version = "0.4.0-beta.1", default-features = false, features = [ "runtime-tokio-rustls", "macros" ] } ``` The runtime and TLS backend not being separate feature sets to select is a workaround for a [Cargo issue](https://github.com/rust-lang/cargo/issues/3494). @@ -123,10 +125,16 @@ sqlx = { version = "0.4.0-beta.1", default-features = false, features = [ "runti * `runtime-async-std-native-tls` (on by default): Use the `async-std` runtime and `native-tls` TLS backend. + * `runtime-async-std-rustls`: Use the `async-std` runtime and `rustls` TLS backend. + * `runtime-tokio-native-tls`: Use the `tokio` runtime and `native-tls` TLS backend. + * `runtime-tokio-rustls`: Use the `tokio` runtime and `rustls` TLS backend. + * `runtime-actix-native-tls`: Use the `actix` runtime and `native-tls` TLS backend. + * `runtime-actix-rustls`: Use the `actix` runtime and `rustls` TLS backend. + * `postgres`: Add support for the Postgres database server. * `mysql`: Add support for the MySQL (and MariaDB) database server. diff --git a/sqlx-bench/Cargo.toml b/sqlx-bench/Cargo.toml index ea945a114a..9e3f123327 100644 --- a/sqlx-bench/Cargo.toml +++ b/sqlx-bench/Cargo.toml @@ -10,6 +10,10 @@ runtime-actix-native-tls = [ "sqlx/runtime-actix-native-tls", "sqlx-rt/runtime-a runtime-async-std-native-tls = [ "sqlx/runtime-async-std-native-tls", "sqlx-rt/runtime-async-std-native-tls" ] runtime-tokio-native-tls = [ "sqlx/runtime-tokio-native-tls", "sqlx-rt/runtime-tokio-native-tls" ] +runtime-actix-rustls = [ "sqlx/runtime-actix-rustls", "sqlx-rt/runtime-actix-rustls" ] +runtime-async-std-rustls = [ "sqlx/runtime-async-std-rustls", "sqlx-rt/runtime-async-std-rustls" ] +runtime-tokio-rustls = [ "sqlx/runtime-tokio-rustls", "sqlx-rt/runtime-tokio-rustls" ] + postgres = ["sqlx/postgres"] [dependencies] diff --git a/sqlx-bench/README.md b/sqlx-bench/README.md index c769eb5be9..ca21933631 100644 --- a/sqlx-bench/README.md +++ b/sqlx-bench/README.md @@ -24,7 +24,7 @@ You must choose a runtime to execute the benchmarks on; the feature flags are th ```bash cargo bench --features runtime-tokio-native-tls -cargo bench --features runtime-async-std-native-tls +cargo bench --features runtime-async-std-rustls ``` When complete, the benchmark results will be in `target/criterion/`. diff --git a/sqlx-core/Cargo.toml b/sqlx-core/Cargo.toml index f4db49fa7a..dc52d18fe1 100644 --- a/sqlx-core/Cargo.toml +++ b/sqlx-core/Cargo.toml @@ -34,14 +34,20 @@ decimal = [ "rust_decimal", "num-bigint" ] json = [ "serde", "serde_json" ] # runtimes -runtime-actix-native-tls = [ "sqlx-rt/runtime-actix-native-tls", "_rt-actix" ] -runtime-async-std-native-tls = [ "sqlx-rt/runtime-async-std-native-tls", "_rt-async-std" ] -runtime-tokio-native-tls = [ "sqlx-rt/runtime-tokio-native-tls", "_rt-tokio" ] +runtime-actix-native-tls = [ "sqlx-rt/runtime-actix-native-tls", "_tls-native-tls", "_rt-actix" ] +runtime-async-std-native-tls = [ "sqlx-rt/runtime-async-std-native-tls", "_tls-native-tls", "_rt-async-std" ] +runtime-tokio-native-tls = [ "sqlx-rt/runtime-tokio-native-tls", "_tls-native-tls", "_rt-tokio" ] + +runtime-actix-rustls = [ "sqlx-rt/runtime-actix-rustls", "_tls-rustls", "_rt-actix" ] +runtime-async-std-rustls = [ "sqlx-rt/runtime-async-std-rustls", "_tls-rustls", "_rt-async-std" ] +runtime-tokio-rustls = [ "sqlx-rt/runtime-tokio-rustls", "_tls-rustls", "_rt-tokio" ] # for conditional compilation _rt-actix = [] _rt-async-std = [] _rt-tokio = [] +_tls-native-tls = [] +_tls-rustls = [ "webpki" ] # support offline/decoupled building (enables serialization of `Describe`) offline = [ "serde", "either/serde" ] @@ -98,3 +104,4 @@ uuid = { version = "0.8.1", default-features = false, optional = true, features whoami = "0.9.0" stringprep = "0.1.2" lru-cache = "0.1.2" +webpki = { version = "0.21.3", optional = true } diff --git a/sqlx-core/src/error.rs b/sqlx-core/src/error.rs index ff9b05edd2..5d1022529c 100644 --- a/sqlx-core/src/error.rs +++ b/sqlx-core/src/error.rs @@ -240,6 +240,14 @@ impl From for Error { } } +#[cfg(feature = "_tls-rustls")] +impl From for Error { + #[inline] + fn from(error: webpki::InvalidDNSNameError) -> Self { + Error::Tls(Box::new(error)) + } +} + // Format an error message as a `Protocol` error macro_rules! err_protocol { ($expr:expr) => { diff --git a/sqlx-core/src/net/tls.rs b/sqlx-core/src/net/tls.rs index 89c1b91d31..27549449c7 100644 --- a/sqlx-core/src/net/tls.rs +++ b/sqlx-core/src/net/tls.rs @@ -44,6 +44,9 @@ where } }; + #[cfg(feature = "_tls-rustls")] + let host = webpki::DNSNameRef::try_from_ascii_str(host)?; + *self = MaybeTlsStream::Tls( connector .connect(host, stream) @@ -166,12 +169,15 @@ where match self { MaybeTlsStream::Raw(s) => s, - #[cfg(not(feature = "_rt-async-std"))] - MaybeTlsStream::Tls(s) => s.get_ref().get_ref().get_ref(), + #[cfg(feature = "_tls-rustls")] + MaybeTlsStream::Tls(s) => s.get_ref().0, - #[cfg(feature = "_rt-async-std")] + #[cfg(all(feature = "_rt-async-std", feature = "_tls-native-tls"))] MaybeTlsStream::Tls(s) => s.get_ref(), + #[cfg(all(not(feature = "_rt-async-std"), feature = "_tls-native-tls"))] + MaybeTlsStream::Tls(s) => s.get_ref().get_ref().get_ref(), + MaybeTlsStream::Upgrading => panic!(io::Error::from(io::ErrorKind::ConnectionAborted)), } } @@ -185,12 +191,15 @@ where match self { MaybeTlsStream::Raw(s) => s, - #[cfg(not(feature = "_rt-async-std"))] - MaybeTlsStream::Tls(s) => s.get_mut().get_mut().get_mut(), + #[cfg(feature = "_tls-rustls")] + MaybeTlsStream::Tls(s) => s.get_mut().0, - #[cfg(feature = "_rt-async-std")] + #[cfg(all(feature = "_rt-async-std", feature = "_tls-native-tls"))] MaybeTlsStream::Tls(s) => s.get_mut(), + #[cfg(all(not(feature = "_rt-async-std"), feature = "_tls-native-tls"))] + MaybeTlsStream::Tls(s) => s.get_mut().get_mut().get_mut(), + MaybeTlsStream::Upgrading => panic!(io::Error::from(io::ErrorKind::ConnectionAborted)), } } diff --git a/sqlx-macros/Cargo.toml b/sqlx-macros/Cargo.toml index e2578bf854..e713eac1da 100644 --- a/sqlx-macros/Cargo.toml +++ b/sqlx-macros/Cargo.toml @@ -24,6 +24,10 @@ runtime-actix-native-tls = [ "sqlx-core/runtime-actix-native-tls", "sqlx-rt/runt runtime-async-std-native-tls = [ "sqlx-core/runtime-async-std-native-tls", "sqlx-rt/runtime-async-std-native-tls", "_rt-async-std" ] runtime-tokio-native-tls = [ "sqlx-core/runtime-tokio-native-tls", "sqlx-rt/runtime-tokio-native-tls", "_rt-tokio" ] +runtime-actix-rustls = [ "sqlx-core/runtime-actix-rustls", "sqlx-rt/runtime-actix-rustls", "_rt-actix" ] +runtime-async-std-rustls = [ "sqlx-core/runtime-async-std-rustls", "sqlx-rt/runtime-async-std-rustls", "_rt-async-std" ] +runtime-tokio-rustls = [ "sqlx-core/runtime-tokio-rustls", "sqlx-rt/runtime-tokio-rustls", "_rt-tokio" ] + # for conditional compilation _rt-actix = [] _rt-async-std = [] diff --git a/sqlx-rt/Cargo.toml b/sqlx-rt/Cargo.toml index 43434c9f59..cab3ba258c 100644 --- a/sqlx-rt/Cargo.toml +++ b/sqlx-rt/Cargo.toml @@ -15,17 +15,24 @@ runtime-actix-native-tls = [ "_rt-actix", "_tls-native-tls", "tokio-native-tls" runtime-async-std-native-tls = [ "_rt-async-std", "_tls-native-tls", "async-native-tls" ] runtime-tokio-native-tls = [ "_rt-tokio", "_tls-native-tls", "tokio-native-tls" ] +runtime-actix-rustls = [ "_rt-actix", "_tls-rustls", "tokio-rustls" ] +runtime-async-std-rustls = [ "_rt-async-std", "_tls-rustls", "async-rustls" ] +runtime-tokio-rustls = [ "_rt-tokio", "_tls-rustls", "tokio-rustls" ] + # Not used directly and not re-exported from sqlx _rt-actix = [ "actix-rt", "actix-threadpool", "tokio", "once_cell" ] _rt-async-std = [ "async-std" ] _rt-tokio = [ "tokio", "once_cell" ] _tls-native-tls = [ ] +_tls-rustls = [ ] [dependencies] async-native-tls = { version = "0.3.3", optional = true } +async-rustls = { version = "0.1.0", optional = true } actix-rt = { version = "1.1.1", optional = true } actix-threadpool = { version = "0.3.2", optional = true } async-std = { version = "1.6.0", features = [ "unstable" ], optional = true } tokio = { version = "0.2.21", optional = true, features = [ "blocking", "stream", "fs", "tcp", "uds", "macros", "rt-core", "rt-threaded", "time", "dns", "io-util" ] } tokio-native-tls = { version = "0.1.0", optional = true } +tokio-rustls = { version = "0.14.0", optional = true } once_cell = { version = "1.4", features = ["std"], optional = true } diff --git a/sqlx-rt/src/lib.rs b/sqlx-rt/src/lib.rs index 83d99e7789..0bc47eb64e 100644 --- a/sqlx-rt/src/lib.rs +++ b/sqlx-rt/src/lib.rs @@ -2,20 +2,26 @@ feature = "runtime-actix-native-tls", feature = "runtime-async-std-native-tls", feature = "runtime-tokio-native-tls", + feature = "runtime-actix-rustls", + feature = "runtime-async-std-rustls", + feature = "runtime-tokio-rustls", )))] compile_error!( "one of the features ['runtime-actix-native-tls', 'runtime-async-std-native-tls', \ - 'runtime-tokio-native-tls'] must be enabled" + 'runtime-tokio-native-tls', 'runtime-actix-rustls', 'runtime-async-std-rustls', \ + 'runtime-tokio-rustls'] must be enabled" ); #[cfg(any( all(feature = "_rt-actix", feature = "_rt-async-std"), all(feature = "_rt-actix", feature = "_rt-tokio"), all(feature = "_rt-async-std", feature = "_rt-tokio"), + all(feature = "_tls-native-tls", feature = "_tls-rustls"), ))] compile_error!( "only one of ['runtime-actix-native-tls', 'runtime-async-std-native-tls', \ - 'runtime-tokio-native-tls'] can be enabled" + 'runtime-tokio-native-tls', 'runtime-actix-rustls', 'runtime-async-std-rustls', \ + 'runtime-tokio-rustls'] can be enabled" ); // @@ -75,10 +81,17 @@ mod tokio_runtime { #[cfg(all( feature = "_tls-native-tls", any(feature = "_rt-tokio", feature = "_rt-actix"), - not(feature = "_rt-async-std"), + not(any(feature = "_tls-rustls", feature = "_rt-async-std")), ))] pub use tokio_native_tls::{TlsConnector, TlsStream}; +#[cfg(all( + feature = "_tls-rustls", + any(feature = "_rt-tokio", feature = "_rt-actix"), + not(any(feature = "_tls-native-tls", feature = "_rt-async-std")), +))] +pub use tokio_rustls::{client::TlsStream, TlsConnector}; + // // tokio // @@ -167,3 +180,14 @@ where #[cfg(all(feature = "async-native-tls", not(feature = "tokio-native-tls")))] pub use async_native_tls::{TlsConnector, TlsStream}; + +#[cfg(all( + feature = "_tls-rustls", + feature = "_rt-async-std", + not(any( + feature = "_tls-native-tls", + feature = "_rt-tokio", + feature = "_rt-actix" + )), +))] +pub use async_rustls::{client::TlsStream, TlsConnector}; diff --git a/src/lib.rs b/src/lib.rs index 0808435610..e2a404b074 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,8 +7,8 @@ ))] compile_error!( "the features 'runtime-actix', 'runtime-async-std' and 'runtime-tokio' have been removed in - favor of new features 'runtime-{rt}-{tls}' where rt is one of 'actix', 'async-std' and - 'tokio'." + favor of new features 'runtime-{rt}-{tls}' where rt is one of 'actix', 'async-std' and 'tokio' + and 'tls' is one of 'native-tls' and 'rustls'." ); pub use sqlx_core::acquire::Acquire;