From 38d246d886953dcf3fa2ca233ff85cd002c2879d Mon Sep 17 00:00:00 2001 From: Matt Mastracci Date: Fri, 31 Jan 2025 09:34:55 -0500 Subject: [PATCH] Add a server mode to gel-stream (#8282) This adds a server mode to `gel-stream`, gated on a feature. We wrap up a significant amount of network and TLS complexity behind two simple concepts: the `Connector` and the `Acceptor`. OpenSSL and Rustls are supported for both client and server modes. Tests were added to ensure that they work with all combinations (which also shook out some additional bugs). In addition, synchronous lookup of TLS parameters by SNI is supported -- async lookup will probably be necessary in the future but is currently not implemented yet. In addition, `tests/certs` were regenerated as one of the certs wasn't v3, so rustls didn't like it. Note that client-side certificate validation is implemented, but there is no current way to read the accepted certificate on the server side. This will be added in a later patch. Accept and connect have similar APIs. Both also have TLS override forms where keys, verification modes and more may be specified. ``` let mut acceptor = Acceptor::new_tcp(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0)) .bind() .await?; let addr = acceptor.local_address()?; let accept_task = tokio::spawn(async move { let mut connection = acceptor.next().await.unwrap().unwrap(); let mut buf = String::new(); connection.read_to_string(&mut buf).await.unwrap(); assert_eq!(buf, "Hello, world!"); }); let connect_task = tokio::spawn(async move { let target = Target::new_resolved(addr); let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); stm.write_all(b"Hello, world!").await?; Ok::<_, std::io::Error>(()) }); ``` --- Cargo.lock | 398 ++++++------ rust/auth/src/lib.rs | 5 +- rust/gel-stream/Cargo.toml | 34 +- rust/gel-stream/src/client/connection.rs | 31 +- rust/gel-stream/src/client/mod.rs | 594 ------------------ rust/gel-stream/src/client/openssl.rs | 177 ------ rust/gel-stream/src/client/stream.rs | 240 ------- rust/gel-stream/src/common/mod.rs | 16 + rust/gel-stream/src/common/openssl.rs | 521 +++++++++++++++ .../src/{client => common}/rustls.rs | 285 ++++++--- rust/gel-stream/src/common/stream.rs | 343 ++++++++++ .../src/{client => common}/target.rs | 15 +- rust/gel-stream/src/common/tls.rs | 259 ++++++++ .../src/{client => common}/tokio_stream.rs | 79 ++- rust/gel-stream/src/lib.rs | 128 +++- rust/gel-stream/src/server/acceptor.rs | 178 ++++++ rust/gel-stream/src/server/mod.rs | 6 + rust/gel-stream/tests/socket.rs | 66 ++ rust/gel-stream/tests/tls.rs | 451 +++++++++++++ rust/pgrust/Cargo.toml | 3 +- rust/pgrust/examples/connect.rs | 2 +- rust/pgrust/src/connection/conn.rs | 4 +- rust/pgrust/src/connection/dsn/host.rs | 2 +- rust/pgrust/src/connection/mod.rs | 3 +- rust/pgrust/src/connection/raw_conn.rs | 37 +- rust/pgrust/src/handshake/edgedb_server.rs | 2 + rust/pgrust/src/handshake/mod.rs | 2 +- rust/pgrust/src/python.rs | 2 +- rust/pgrust/tests/query_real_postgres.rs | 2 +- rust/pgrust/tests/real_postgres.rs | 2 +- tests/certs/ca.cert.pem | 58 +- tests/certs/ca.crl.pem | 30 +- tests/certs/ca.key.pem | 100 +-- tests/certs/client.cert.pem | 65 +- tests/certs/client.csr.pem | 46 +- tests/certs/client.key.pem | 100 +-- tests/certs/client.key.protected.pem | 104 +-- tests/certs/client_ca.cert.pem | 56 +- tests/certs/client_ca.cert.srl | 2 +- tests/certs/client_ca.key.pem | 100 +-- tests/certs/gen.sh | 2 +- tests/certs/server.cert.pem | 54 +- tests/certs/server.key.pem | 100 +-- 43 files changed, 2922 insertions(+), 1782 deletions(-) delete mode 100644 rust/gel-stream/src/client/openssl.rs delete mode 100644 rust/gel-stream/src/client/stream.rs create mode 100644 rust/gel-stream/src/common/mod.rs create mode 100644 rust/gel-stream/src/common/openssl.rs rename rust/gel-stream/src/{client => common}/rustls.rs (53%) create mode 100644 rust/gel-stream/src/common/stream.rs rename rust/gel-stream/src/{client => common}/target.rs (97%) create mode 100644 rust/gel-stream/src/common/tls.rs rename rust/gel-stream/src/{client => common}/tokio_stream.rs (61%) create mode 100644 rust/gel-stream/src/server/acceptor.rs create mode 100644 rust/gel-stream/src/server/mod.rs create mode 100644 rust/gel-stream/tests/socket.rs create mode 100644 rust/gel-stream/tests/tls.rs diff --git a/Cargo.lock b/Cargo.lock index 46ad27739c5..1eab733d036 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,37 +4,19 @@ version = 3 [[package]] name = "addr2line" -version = "0.22.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "adler2" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -61,15 +43,15 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", @@ -82,49 +64,49 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.8" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ "anstyle", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" [[package]] name = "append-only-vec" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d9f7083455f1a474276ccd32374958d2cb591024aac45101c7623b10271347" +checksum = "7992085ec035cfe96992dd31bfd495a2ebd31969bb95f624471cb6c0b349e571" [[package]] name = "approx" @@ -149,9 +131,9 @@ checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" [[package]] name = "async-compression" -version = "0.4.13" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e614738943d3f68c628ae3dbce7c3daffb196665f82f8c8ea6b65de73c79429" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" dependencies = [ "brotli", "flate2", @@ -180,23 +162,23 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" -version = "0.3.73" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ "addr2line", - "cc", "cfg-if", "libc", - "miniz_oxide 0.7.4", + "miniz_oxide", "object", "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] @@ -213,9 +195,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bigdecimal" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" +checksum = "8f850665a0385e070b64c38d2354e6c104c8479c59868d1e48a0c13ee2c7a1c1" dependencies = [ "autocfg", "libm", @@ -287,9 +269,9 @@ checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bytemuck" -version = "1.17.1" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] @@ -313,9 +295,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "captive_postgres" @@ -340,9 +322,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.15" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ "shlex", ] @@ -367,18 +349,18 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "clap" -version = "4.5.16" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.5.15" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -388,9 +370,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.13" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ "heck", "proc-macro2", @@ -400,15 +382,15 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "combine" @@ -456,7 +438,7 @@ dependencies = [ "statrs", "strum", "test-log", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -500,9 +482,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -595,7 +577,7 @@ dependencies = [ "derive_more", "paste", "pretty_assertions", - "thiserror 1.0.63", + "thiserror 1.0.69", "uuid", ] @@ -657,13 +639,13 @@ dependencies = [ "combine 3.8.1", "num-bigint 0.2.6", "num-traits", - "thiserror 1.0.63", + "thiserror 1.0.69", ] [[package]] name = "edgedb-errors" version = "0.4.2" -source = "git+https://github.com/edgedb/edgedb-rust#b38fb4af07ae0017329eb3cce30ca37fe12acd29" +source = "git+https://github.com/edgedb/edgedb-rust#84c2fa7d78fe8dbbc8e3e4da136ad2eff2f2e465" dependencies = [ "bytes", ] @@ -671,7 +653,7 @@ dependencies = [ [[package]] name = "edgedb-protocol" version = "0.6.1" -source = "git+https://github.com/edgedb/edgedb-rust#b38fb4af07ae0017329eb3cce30ca37fe12acd29" +source = "git+https://github.com/edgedb/edgedb-rust#84c2fa7d78fe8dbbc8e3e4da136ad2eff2f2e465" dependencies = [ "bigdecimal", "bitflags", @@ -701,7 +683,7 @@ dependencies = [ "serde_json", "sha2", "snafu", - "thiserror 1.0.63", + "thiserror 1.0.69", "unicode-width", ] @@ -830,18 +812,18 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "flate2" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide 0.8.0", + "miniz_oxide", ] [[package]] @@ -850,6 +832,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -876,9 +864,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -891,9 +879,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -901,15 +889,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -918,15 +906,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", @@ -935,15 +923,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -953,9 +941,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -975,6 +963,8 @@ version = "0.1.0" dependencies = [ "derive_more", "foreign-types", + "futures", + "gel-stream", "hickory-resolver", "ntest", "openssl", @@ -1055,9 +1045,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" @@ -1075,7 +1065,7 @@ dependencies = [ "num-traits", "pretty_assertions", "pyo3", - "thiserror 1.0.63", + "thiserror 1.0.69", ] [[package]] @@ -1099,12 +1089,13 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "ahash", "allocator-api2", + "equivalent", + "foldhash", ] [[package]] @@ -1151,7 +1142,7 @@ dependencies = [ "ipnet", "once_cell", "rand", - "thiserror 1.0.63", + "thiserror 1.0.69", "tinyvec", "tokio", "tracing", @@ -1174,7 +1165,7 @@ dependencies = [ "rand", "resolv-conf", "smallvec", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", ] @@ -1256,9 +1247,9 @@ checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", @@ -1452,9 +1443,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", @@ -1492,9 +1483,9 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "iter-read" -version = "0.3.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c397ca3ea05ad509c4ec451fea28b4771236a376ca1c69fd5143aae0cf8f93c4" +checksum = "071ed4cc1afd86650602c7b11aa2e1ce30762a1c27193201cb5cee9c6ebb1294" [[package]] name = "itertools" @@ -1516,9 +1507,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jni" @@ -1531,7 +1522,7 @@ dependencies = [ "combine 4.6.7", "jni-sys", "log", - "thiserror 1.0.63", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -1559,15 +1550,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.165" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e" [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "linked-hash-map" @@ -1605,9 +1596,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ "hashbrown", ] @@ -1679,15 +1670,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" -[[package]] -name = "miniz_oxide" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" -dependencies = [ - "adler", -] - [[package]] name = "miniz_oxide" version = "0.8.0" @@ -1891,24 +1873,24 @@ dependencies = [ [[package]] name = "object" -version = "0.36.3" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags", "cfg-if", @@ -1937,9 +1919,9 @@ source = "git+https://github.com/edgedb/openssl-probe/?rev=e5ed593600d1f81286295 [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -2016,7 +1998,7 @@ dependencies = [ "serde", "serde_derive", "test-log", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tokio-openssl", "tracing", @@ -2068,9 +2050,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -2080,15 +2062,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "ppv-lite86" @@ -2101,9 +2083,9 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ "diff", "yansi", @@ -2198,7 +2180,7 @@ dependencies = [ "nix", "pyo3", "scopeguard", - "thiserror 1.0.63", + "thiserror 1.0.69", "tokio", "tracing", "tracing-subscriber", @@ -2348,14 +2330,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -2369,13 +2351,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2386,9 +2368,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "relative-path" @@ -2574,9 +2556,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.35" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags", "errno", @@ -2659,9 +2641,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-tokio-stream" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22557157d7395bc30727745b365d923f1ecc230c4c80b176545f3f4f08c46e33" +checksum = "faa7dc7c991d9164e55bbf1558029eb5b84d32cc4d61a7df5b8641b2deedc4b3" dependencies = [ "futures", "rustls", @@ -2682,9 +2664,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -2712,9 +2694,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ "windows-sys 0.59.0", ] @@ -2756,18 +2738,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.209" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde-pickle" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762ad136a26407c6a80825813600ceeab5e613660d93d79a41f0ec877171e71" +checksum = "b641fdc8bcf2781ee78b30c599700d64ad4f412976143e4c5d0b9df906bb4843" dependencies = [ "byteorder", "iter-read", @@ -2778,9 +2760,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.209" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -2789,9 +2771,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap", "itoa", @@ -2894,9 +2876,9 @@ dependencies = [ [[package]] name = "snafu" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b835cb902660db3415a672d862905e791e54d306c6e8189168c7f3d9ae1c79d" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" dependencies = [ "backtrace", "snafu-derive", @@ -2904,9 +2886,9 @@ dependencies = [ [[package]] name = "snafu-derive" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d1e02fca405f6280643174a50c942219f0bbf4dbf7d480f1dd864d6f211ae5" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" dependencies = [ "heck", "proc-macro2", @@ -3015,9 +2997,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -3041,15 +3023,15 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.11.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -3076,11 +3058,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.63", + "thiserror-impl 1.0.69", ] [[package]] @@ -3094,9 +3076,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -3221,9 +3203,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.20" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ "indexmap", "toml_datetime", @@ -3281,9 +3263,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -3332,36 +3314,36 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "unindent" @@ -3415,9 +3397,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" [[package]] name = "valuable" @@ -3537,9 +3519,9 @@ checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "wasm-streams" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ "futures-util", "js-sys", @@ -3589,9 +3571,9 @@ dependencies = [ [[package]] name = "wide" -version = "0.7.28" +version = "0.7.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b828f995bf1e9622031f8009f8481a85406ce1f4d4588ff746d872043e855690" +checksum = "58e6db2670d2be78525979e9a5f9c69d296fd7d670549fe9ebf70f8708cb5019" dependencies = [ "bytemuck", "safe_arch", @@ -3880,9 +3862,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -3920,9 +3902,9 @@ dependencies = [ [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" diff --git a/rust/auth/src/lib.rs b/rust/auth/src/lib.rs index b4b51a700d3..4310b15e060 100644 --- a/rust/auth/src/lib.rs +++ b/rust/auth/src/lib.rs @@ -34,7 +34,7 @@ pub enum AuthType { ScramSha256, } -#[derive(Debug, Clone)] +#[derive(derive_more::Debug, Clone)] pub enum CredentialData { /// A credential that always succeeds, regardless of input password. Due to /// the design of SCRAM-SHA-256, this cannot be used with that auth type. @@ -42,10 +42,13 @@ pub enum CredentialData { /// A credential that always fails, regardless of the input password. Deny, /// A plain-text password. + #[debug("Plain(...)")] Plain(String), /// A stored MD5 hash + salt. + #[debug("Md5(...)")] Md5(md5::StoredHash), /// A stored SCRAM-SHA-256 key. + #[debug("Scram(...)")] Scram(scram::StoredKey), } diff --git a/rust/gel-stream/Cargo.toml b/rust/gel-stream/Cargo.toml index 164d21125bd..d18dacf3a6e 100644 --- a/rust/gel-stream/Cargo.toml +++ b/rust/gel-stream/Cargo.toml @@ -7,7 +7,9 @@ description = "A library for streaming data between clients and servers." [features] # rustls or openssl imply tokio, and tokio is the only stream we support # at this time. -default = ["tokio", "rustls"] +default = ["tokio"] +client = [] +server = [] tokio = ["dep:tokio"] rustls = ["tokio", "dep:rustls", "dep:rustls-tokio-stream", "dep:rustls-platform-verifier", "dep:webpki"] openssl = ["tokio", "dep:openssl", "dep:tokio-openssl", "dep:foreign-types", "dep:openssl-sys"] @@ -17,29 +19,39 @@ __manual_tests = [] [dependencies] derive_more = { version = "1", features = ["full"] } thiserror = "2" -rustls-pki-types = "1" +futures = "0.3" -tokio = { version = "1", optional = true, features = ["full"] } +# Given that this library may be used in multiple contexts, we want to limit the +# features we enable by default. + +rustls-pki-types = { version = "1", default-features = false, features = ["std"] } + +# feature = "tokio" +tokio = { version = "1", optional = true, default-features = false, features = ["net", "rt"] } +hickory-resolver = { version = "0.24.2", optional = true, default-features = false, features = ["tokio-runtime", "system-config"] } + +# feature = "rustls" rustls = { version = "0.23", optional = true, default-features = false, features = ["ring", "logging", "std", "tls12"] } -openssl = { version = "0.10.55", optional = true } -tokio-openssl = { version = "0.6.5", optional = true } -hickory-resolver = { version = "0.24.2", optional = true } -rustls-tokio-stream = { version = "0.3.0", optional = true } +rustls-tokio-stream = { version = "0.5.0", optional = true } rustls-platform-verifier = { version = "0.5.0", optional = true } webpki = { version = "0.22", optional = true } +# feature = "openssl" +openssl = { version = "0.10.55", optional = true, default-features = false } +tokio-openssl = { version = "0.6.5", optional = true, default-features = false } # Get these from openssl -foreign-types = { version = "*", optional = true } -openssl-sys = { version = "*", optional = true } +foreign-types = { version = "*", optional = true, default-features = false } +openssl-sys = { version = "*", optional = true, default-features = false } [dev-dependencies] +# Run tests with all features enabled +gel-stream = { workspace = true, features = ["client", "server", "tokio", "rustls", "openssl"] } + tokio = { version = "1", features = ["full"] } tempfile = "3" ntest = "0.9.3" rustls-pemfile = "2" - rstest = "0.24.0" -rustls-tokio-stream = "0.3.0" [lints] workspace = true diff --git a/rust/gel-stream/src/client/connection.rs b/rust/gel-stream/src/client/connection.rs index 4b358d4e8a8..a51611ea453 100644 --- a/rust/gel-stream/src/client/connection.rs +++ b/rust/gel-stream/src/client/connection.rs @@ -1,27 +1,37 @@ +use std::marker::PhantomData; use std::net::SocketAddr; -use super::stream::UpgradableStream; -use super::target::{MaybeResolvedTarget, ResolvedTarget}; -use super::tokio_stream::Resolver; -use super::{ConnectionError, Ssl, Target, TlsInit}; +use crate::common::tokio_stream::{Resolver, TokioStream}; +use crate::{ConnectionError, Ssl, StreamUpgrade, TlsDriver, UpgradableStream}; +use crate::{MaybeResolvedTarget, ResolvedTarget, Target}; -type Connection = UpgradableStream>; +type Connection = UpgradableStream; /// A connector can be used to connect multiple times to the same target. -pub struct Connector { +#[allow(private_bounds)] +pub struct Connector { target: Target, resolver: Resolver, + driver: PhantomData, } -impl Connector { +impl Connector { pub fn new(target: Target) -> Result { + Self::new_explicit(target) + } +} + +#[allow(private_bounds)] +impl Connector { + pub fn new_explicit(target: Target) -> Result { Ok(Self { target, resolver: Resolver::new()?, + driver: PhantomData, }) } - pub async fn connect(&self) -> Result { + pub async fn connect(&self) -> Result, ConnectionError> { let stream = match self.target.maybe_resolved() { MaybeResolvedTarget::Resolved(target) => target.connect().await?, MaybeResolvedTarget::Unresolved(host, port, _) => { @@ -36,13 +46,14 @@ impl Connector { }; if let Some(ssl) = self.target.maybe_ssl() { - let mut stm = UpgradableStream::new(stream, Some(Ssl::init(ssl, self.target.name())?)); + let ssl = D::init_client(ssl, self.target.name())?; + let mut stm = UpgradableStream::new_client(stream, Some(ssl)); if !self.target.is_starttls() { stm.secure_upgrade().await?; } Ok(stm) } else { - Ok(UpgradableStream::new(stream, None)) + Ok(UpgradableStream::new_client(stream, None)) } } } diff --git a/rust/gel-stream/src/client/mod.rs b/rust/gel-stream/src/client/mod.rs index 4f1688e18ab..93d91fc99a6 100644 --- a/rust/gel-stream/src/client/mod.rs +++ b/rust/gel-stream/src/client/mod.rs @@ -1,597 +1,3 @@ -use std::borrow::Cow; - -#[cfg(feature = "openssl")] -pub mod openssl; -#[cfg(feature = "rustls")] -pub mod rustls; -#[cfg(feature = "tokio")] -pub mod tokio_stream; - -pub mod stream; - mod connection; -pub(crate) mod target; pub use connection::Connector; -pub use target::{ResolvedTarget, Target, TargetName}; - -macro_rules! __invalid_state { - ($error:literal) => {{ - eprintln!( - "Invalid connection state: {}\n{}", - $error, - ::std::backtrace::Backtrace::capture() - ); - #[allow(deprecated)] - $crate::client::ConnectionError::__InvalidState - }}; -} -pub(crate) use __invalid_state as invalid_state; -use rustls_pki_types::{CertificateDer, CertificateRevocationListDer, PrivateKeyDer, ServerName}; - -#[derive(Debug, thiserror::Error)] -pub enum ConnectionError { - /// Invalid state error, suggesting a logic error in code rather than a server or client failure. - /// Use the `invalid_state!` macro instead which will print a backtrace. - #[error("Invalid state")] - #[deprecated = "Use invalid_state!"] - __InvalidState, - - /// I/O error encountered during connection operations. - #[error("I/O error: {0}")] - Io(#[from] std::io::Error), - - /// UTF-8 decoding error. - #[error("UTF8 error: {0}")] - Utf8Error(#[from] std::str::Utf8Error), - - /// SSL-related error. - #[error("SSL error: {0}")] - SslError(#[from] SslError), -} - -#[derive(Debug, thiserror::Error)] -pub enum SslError { - #[error("SSL is not supported by this client transport")] - SslUnsupportedByClient, - - #[cfg(feature = "openssl")] - #[error("OpenSSL error: {0}")] - OpenSslError(#[from] ::openssl::ssl::Error), - #[cfg(feature = "openssl")] - #[error("OpenSSL error: {0}")] - OpenSslErrorStack(#[from] ::openssl::error::ErrorStack), - #[cfg(feature = "openssl")] - #[error("OpenSSL certificate verification error: {0}")] - OpenSslErrorVerify(#[from] ::openssl::x509::X509VerifyResult), - - #[cfg(feature = "rustls")] - #[error("Rustls error: {0}")] - RustlsError(#[from] ::rustls::Error), - - #[cfg(feature = "rustls")] - #[error("Webpki error: {0}")] - WebpkiError(::webpki::Error), - - #[cfg(feature = "rustls")] - #[error("Verifier builder error: {0}")] - VerifierBuilderError(#[from] ::rustls::server::VerifierBuilderError), - - #[error("Invalid DNS name: {0}")] - InvalidDnsNameError(#[from] ::rustls_pki_types::InvalidDnsNameError), - - #[error("SSL I/O error: {0}")] - SslIoError(#[from] std::io::Error), -} - -impl SslError { - /// Returns a common error for any time of crypto backend. - pub fn common_error(&self) -> Option { - match self { - #[cfg(feature = "rustls")] - SslError::RustlsError(::rustls::Error::InvalidCertificate(cert_err)) => { - match cert_err { - ::rustls::CertificateError::NotValidForName => { - Some(CommonError::InvalidCertificateForName) - } - ::rustls::CertificateError::Revoked => Some(CommonError::CertificateRevoked), - ::rustls::CertificateError::Expired => Some(CommonError::CertificateExpired), - ::rustls::CertificateError::UnknownIssuer => Some(CommonError::InvalidIssuer), - _ => None, - } - } - #[cfg(feature = "openssl")] - SslError::OpenSslErrorVerify(e) => match e.as_raw() { - openssl_sys::X509_V_ERR_HOSTNAME_MISMATCH => { - Some(CommonError::InvalidCertificateForName) - } - openssl_sys::X509_V_ERR_IP_ADDRESS_MISMATCH => { - Some(CommonError::InvalidCertificateForName) - } - openssl_sys::X509_V_ERR_CERT_REVOKED => Some(CommonError::CertificateRevoked), - openssl_sys::X509_V_ERR_CERT_HAS_EXPIRED => Some(CommonError::CertificateExpired), - openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT - | openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY => { - Some(CommonError::InvalidIssuer) - } - _ => None, - }, - _ => None, - } - } -} - -#[derive(Debug, thiserror::Error, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] -pub enum CommonError { - #[error("The certificate's subject name(s) do not match the name of the host")] - InvalidCertificateForName, - #[error("The certificate has been revoked")] - CertificateRevoked, - #[error("The certificate has expired")] - CertificateExpired, - #[error("The certificate was issued by an untrusted authority")] - InvalidIssuer, -} - -// Note that we choose rustls when both openssl and rustls are enabled. - -#[cfg(all(feature = "openssl", not(feature = "rustls")))] -pub type Ssl = ::openssl::ssl::Ssl; -#[cfg(feature = "rustls")] -pub type Ssl = ::rustls::ClientConnection; - -#[cfg(feature = "tokio")] -pub type Stream = tokio_stream::TokioStream; - -/// Verification modes for TLS that are a superset of both PostgreSQL and EdgeDB/Gel. -/// -/// Postgres offers six levels: `disable`, `allow`, `prefer`, `require`, `verify-ca` and `verify-full`. -/// -/// EdgeDB/Gel offers three levels: `insecure`, `no_host_verification' and 'strict'. -/// -/// This table maps the various levels: -/// -/// | Postgres | EdgeDB/Gel | `TlsServerCertVerify` enum | -/// | -------- | ----------- | ----------------- | -/// | require | insecure | `Insecure` | -/// | verify-ca | no_host_verification | `IgnoreHostname` | -/// | verify-full | strict | `VerifyFull` | -/// -/// Note that both EdgeDB/Gel and Postgres may alter certificate validation levels -/// when custom root certificates are provided. This must be done in the -/// `TlsParameters` struct by the caller. -#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] -pub enum TlsServerCertVerify { - /// Do not verify the server's certificate. Only confirm that the server is - /// using TLS. - Insecure, - /// Verify the server's certificate using the CA (ignore hostname). - IgnoreHostname, - /// Verify the server's certificate using the CA and hostname. - #[default] - VerifyFull, -} - -#[derive(Debug, Clone, Default, PartialEq, Eq)] -pub enum TlsCert { - /// Use the system's default certificate. - #[default] - System, - /// Use a custom root certificate only. - Custom(CertificateDer<'static>), -} - -#[derive(Default, Debug, PartialEq, Eq)] -pub struct TlsParameters { - pub server_cert_verify: TlsServerCertVerify, - pub cert: Option>, - pub key: Option>, - pub root_cert: TlsCert, - pub crl: Vec>, - pub min_protocol_version: Option, - pub max_protocol_version: Option, - pub enable_keylog: bool, - pub sni_override: Option>, - pub alpn: Option]>>, -} - -impl TlsParameters { - pub fn insecure() -> Self { - Self { - server_cert_verify: TlsServerCertVerify::Insecure, - ..Default::default() - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum SslVersion { - Tls1, - Tls1_1, - Tls1_2, - Tls1_3, -} - -trait TlsInit { - type Tls; - fn init(params: &TlsParameters, name: Option) -> Result; -} - -#[cfg(test)] -mod tests { - use std::{net::SocketAddr, sync::Arc}; - - use tokio::io::{AsyncReadExt, AsyncWriteExt}; - - use super::*; - - #[cfg(unix)] - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_unix() -> Result<(), std::io::Error> { - use tokio::io::AsyncReadExt; - - let tempdir = tempfile::tempdir().unwrap(); - let path = tempdir.path().join("gel-stream-test"); - - // Create a unix socket and connect to it - let socket = tokio::net::UnixListener::bind(&path)?; - - let accept_task = tokio::spawn(async move { - let (mut stream, _) = socket.accept().await.unwrap(); - let mut buf = String::new(); - stream.read_to_string(&mut buf).await.unwrap(); - assert_eq!(buf, "Hello, world!"); - }); - - let connect_task = tokio::spawn(async { - let target = Target::new_unix_path(path)?; - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp() -> Result<(), std::io::Error> { - // Create a TCP listener on a random port - let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await?; - let addr = listener.local_addr()?; - - let accept_task = tokio::spawn(async move { - let (mut stream, _) = listener.accept().await.unwrap(); - let mut buf = String::new(); - stream.read_to_string(&mut buf).await.unwrap(); - assert_eq!(buf, "Hello, world!"); - }); - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp(("127.0.0.1", addr.port())); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - fn load_test_cert() -> rustls_pki_types::CertificateDer<'static> { - rustls_pemfile::certs( - &mut include_str!("../../../../tests/certs/server.cert.pem").as_bytes(), - ) - .next() - .unwrap() - .unwrap() - } - - fn load_test_ca() -> rustls_pki_types::CertificateDer<'static> { - rustls_pemfile::certs(&mut include_str!("../../../../tests/certs/ca.cert.pem").as_bytes()) - .next() - .unwrap() - .unwrap() - } - - fn load_test_key() -> rustls_pki_types::PrivateKeyDer<'static> { - rustls_pemfile::private_key( - &mut include_str!("../../../../tests/certs/server.key.pem").as_bytes(), - ) - .unwrap() - .unwrap() - } - - fn load_test_crls() -> Vec> { - rustls_pemfile::crls(&mut include_str!("../../../../tests/certs/ca.crl.pem").as_bytes()) - .collect::, _>>() - .unwrap() - } - - async fn spawn_tls_server( - expected_hostname: Option<&str>, - server_alpn: Option<&[&str]>, - expected_alpn: Option<&str>, - ) -> Result< - ( - SocketAddr, - tokio::task::JoinHandle>, - ), - std::io::Error, - > { - use ::rustls::{ServerConfig, ServerConnection}; - - let _ = ::rustls::crypto::ring::default_provider().install_default(); - - // Create a TCP listener on a random port - let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await?; - let addr = listener.local_addr()?; - - // Load TLS cert and key - let cert = load_test_cert(); - let key = load_test_key(); - - // Configure rustls server - let mut config = ServerConfig::builder() - .with_no_client_auth() - .with_single_cert(vec![cert], key) - .unwrap(); - config.alpn_protocols = server_alpn - .map(|alpn| alpn.iter().map(|s| s.as_bytes().to_vec()).collect()) - .unwrap_or_default(); - - let tls_config = Arc::new(config); - let expected_alpn = expected_alpn.map(|alpn| alpn.as_bytes().to_vec()); - let expected_hostname = expected_hostname.map(|sni| sni.to_string()); - let accept_task = tokio::spawn(async move { - let (tcp_stream, _) = listener.accept().await.unwrap(); - let tls_conn = ServerConnection::new(tls_config).unwrap(); - let mut stream = - rustls_tokio_stream::TlsStream::new_server_side_from(tcp_stream, tls_conn, None); - let handshake = stream.handshake().await?; - eprintln!("handshake: {:?}", handshake); - assert_eq!(handshake.alpn, expected_alpn); - assert_eq!(handshake.sni, expected_hostname); - let mut buf = String::new(); - stream.read_to_string(&mut buf).await.unwrap(); - assert_eq!(buf, "Hello, world!"); - stream.shutdown().await?; - Ok::<_, std::io::Error>(()) - }); - Ok((addr, accept_task)) - } - - /// The certificate is not valid for 127.0.0.1, so the connection should fail. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_verify_full_fails() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(None, None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - ..Default::default() - }, - ); - let stm = Connector::new(target).unwrap().connect().await; - assert!( - matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::InvalidIssuer)), - "{stm:?}" - ); - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap_err(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - /// The certificate is not valid for 127.0.0.1, so the connection should fail. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_verify_full_fails_name() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(None, None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - root_cert: TlsCert::Custom(load_test_ca()), - ..Default::default() - }, - ); - let stm = Connector::new(target).unwrap().connect().await; - assert!( - matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::InvalidCertificateForName)), - "{stm:?}" - ); - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap_err(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - /// The certificate is valid for "localhost", so the connection should succeed. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_verify_full_ok() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(Some("localhost"), None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("localhost", addr.port()), - TlsParameters { - root_cert: TlsCert::Custom(load_test_ca()), - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await?; - stm.write_all(b"Hello, world!").await?; - stm.shutdown().await?; - Ok::<_, ConnectionError>(()) - }); - - accept_task.await.unwrap().unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_insecure() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(None, None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - server_cert_verify: TlsServerCertVerify::Insecure, - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await?; - stm.shutdown().await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_crl() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(Some("localhost"), None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("localhost", addr.port()), - TlsParameters { - root_cert: TlsCert::Custom(load_test_ca()), - crl: load_test_crls(), - ..Default::default() - }, - ); - let stm = Connector::new(target).unwrap().connect().await; - assert!( - matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::CertificateRevoked)), - "{stm:?}" - ); - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap_err(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - /// Test that we can override the SNI. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_sni_override() -> Result<(), std::io::Error> { - let (addr, accept_task) = spawn_tls_server(Some("www.google.com"), None, None).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - server_cert_verify: TlsServerCertVerify::Insecure, - sni_override: Some(Cow::Borrowed("www.google.com")), - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await.unwrap(); - stm.shutdown().await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - /// Test that we can override the ALPN. - #[tokio::test] - #[ntest::timeout(30_000)] - async fn test_target_tcp_tls_alpn_override() -> Result<(), std::io::Error> { - let (addr, accept_task) = - spawn_tls_server(None, Some(&["nope", "accepted"]), Some("accepted")).await?; - - let connect_task = tokio::spawn(async move { - let target = Target::new_tcp_tls( - ("127.0.0.1", addr.port()), - TlsParameters { - server_cert_verify: TlsServerCertVerify::Insecure, - alpn: Some(Cow::Borrowed(&[ - Cow::Borrowed("accepted"), - Cow::Borrowed("fake"), - ])), - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"Hello, world!").await.unwrap(); - stm.shutdown().await?; - Ok::<_, std::io::Error>(()) - }); - - accept_task.await.unwrap().unwrap(); - connect_task.await.unwrap().unwrap(); - - Ok(()) - } - - #[cfg(feature = "__manual_tests")] - #[tokio::test] - async fn test_live_server_manual_google_com() { - let target = Target::new_tcp_tls(("www.google.com", 443), TlsParameters::default()); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"GET / HTTP/1.0\r\n\r\n").await.unwrap(); - // HTTP/1. ..... - assert_eq!(stm.read_u8().await.unwrap(), b'H'); - } - - /// Normally connecting to Google's IP will send an invalid SNI and fail. - /// This test ensures that we can override the SNI to the correct hostname. - #[cfg(feature = "__manual_tests")] - #[tokio::test] - async fn test_live_server_google_com_override_sni() { - use std::net::ToSocketAddrs; - - let addr = "www.google.com:443" - .to_socket_addrs() - .unwrap() - .into_iter() - .next() - .unwrap(); - let target = Target::new_tcp_tls( - addr, - TlsParameters { - sni_override: Some(Cow::Borrowed("www.google.com")), - ..Default::default() - }, - ); - let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); - stm.write_all(b"GET / HTTP/1.0\r\n\r\n").await.unwrap(); - // HTTP/1. ..... - assert_eq!(stm.read_u8().await.unwrap(), b'H'); - } -} diff --git a/rust/gel-stream/src/client/openssl.rs b/rust/gel-stream/src/client/openssl.rs deleted file mode 100644 index b020b4026e5..00000000000 --- a/rust/gel-stream/src/client/openssl.rs +++ /dev/null @@ -1,177 +0,0 @@ -use std::pin::Pin; - -use openssl::{ - ssl::{SslContextBuilder, SslMethod, SslVerifyMode}, - x509::{verify::X509VerifyFlags, X509VerifyResult}, -}; -use rustls_pki_types::ServerName; - -use super::{ - stream::{Stream, StreamWithUpgrade}, - SslError, SslVersion, TlsCert, TlsInit, TlsParameters, TlsServerCertVerify, -}; - -impl StreamWithUpgrade for (S, Option) { - type Base = S; - type Config = openssl::ssl::Ssl; - type Upgrade = tokio_openssl::SslStream; - - async fn secure_upgrade(self) -> Result - where - Self: Sized, - { - let Some(tls) = self.1 else { - return Err(super::SslError::SslUnsupportedByClient); - }; - - let mut stream = tokio_openssl::SslStream::new(tls, self.0)?; - let res = Pin::new(&mut stream).do_handshake().await; - if res.is_err() { - if stream.ssl().verify_result() != X509VerifyResult::OK { - return Err(SslError::OpenSslErrorVerify(stream.ssl().verify_result())); - } - } - res.map_err(SslError::OpenSslError)?; - Ok(stream) - } -} - -impl From for openssl::ssl::SslVersion { - fn from(val: SslVersion) -> Self { - match val { - SslVersion::Tls1 => openssl::ssl::SslVersion::TLS1, - SslVersion::Tls1_1 => openssl::ssl::SslVersion::TLS1_1, - SslVersion::Tls1_2 => openssl::ssl::SslVersion::TLS1_2, - SslVersion::Tls1_3 => openssl::ssl::SslVersion::TLS1_3, - } - } -} - -impl TlsInit for openssl::ssl::Ssl { - type Tls = openssl::ssl::Ssl; - - fn init(parameters: &TlsParameters, name: Option) -> Result { - let TlsParameters { - server_cert_verify, - root_cert, - cert, - key, - crl, - min_protocol_version, - max_protocol_version, - alpn, - sni_override, - enable_keylog, - } = parameters; - - let mut ssl = SslContextBuilder::new(SslMethod::tls_client())?; - - // Load root cert - if let TlsCert::Custom(root) = root_cert { - let root = openssl::x509::X509::from_der(root.as_ref())?; - ssl.cert_store_mut().add_cert(root)?; - ssl.set_verify(SslVerifyMode::PEER); - } else if *server_cert_verify == TlsServerCertVerify::Insecure { - ssl.set_verify(SslVerifyMode::NONE); - } - - // Load CRL - if !crl.is_empty() { - // The openssl crate doesn't yet have add_crl, so we need to use the raw FFI - use foreign_types::ForeignTypeRef; - let ptr = ssl.cert_store_mut().as_ptr(); - - extern "C" { - pub fn X509_STORE_add_crl( - store: *mut openssl_sys::X509_STORE, - x: *mut openssl_sys::X509_CRL, - ) -> openssl_sys::c_int; - } - - for crl in crl { - let crl = openssl::x509::X509Crl::from_der(crl.as_ref())?; - let crl_ptr = crl.as_ptr(); - let res = unsafe { X509_STORE_add_crl(ptr, crl_ptr) }; - if res != 1 { - return Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Failed to add CRL to store", - ) - .into()); - } - } - - ssl.verify_param_mut() - .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?; - ssl.cert_store_mut() - .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?; - } - - // Load certificate chain and private key - if let (Some(cert), Some(key)) = (cert.as_ref(), key.as_ref()) { - let builder = openssl::x509::X509::from_der(cert.as_ref())?; - ssl.set_certificate(&builder)?; - let builder = openssl::pkey::PKey::private_key_from_pem(&key.secret_der())?; - ssl.set_private_key(&builder)?; - } - - // Configure hostname verification - if *server_cert_verify == TlsServerCertVerify::VerifyFull { - ssl.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT); - } - - ssl.set_min_proto_version(min_protocol_version.map(|s| s.into()))?; - ssl.set_max_proto_version(max_protocol_version.map(|s| s.into()))?; - - // Configure key log filename - if *enable_keylog { - if let Ok(path) = std::env::var("SSLKEYLOGFILE") { - // "The callback is invoked whenever TLS key material is generated, and is passed a line of NSS SSLKEYLOGFILE-formatted text. - // This can be used by tools like Wireshark to decrypt message traffic. The line does not contain a trailing newline. - ssl.set_keylog_callback(move |_ssl, msg| { - let Ok(mut file) = std::fs::OpenOptions::new().append(true).open(&path) else { - return; - }; - let _ = std::io::Write::write_all(&mut file, msg.as_bytes()); - }); - } - } - - if *server_cert_verify == TlsServerCertVerify::VerifyFull { - if let Some(hostname) = sni_override { - ssl.verify_param_mut().set_host(hostname)?; - } else if let Some(ServerName::DnsName(hostname)) = &name { - ssl.verify_param_mut().set_host(hostname.as_ref())?; - } else if let Some(ServerName::IpAddress(ip)) = &name { - ssl.verify_param_mut().set_ip((*ip).into())?; - } - } - - let mut ssl = openssl::ssl::Ssl::new(&ssl.build())?; - ssl.set_connect_state(); - - // Set hostname if it's not an IP address - if let Some(hostname) = sni_override { - ssl.set_hostname(hostname)?; - } else if let Some(ServerName::DnsName(hostname)) = &name { - ssl.set_hostname(hostname.as_ref())?; - } - - if let Some(alpn) = alpn { - let alpn = alpn - .iter() - .map(|s| { - let bytes = s.as_bytes(); - let mut vec = Vec::with_capacity(bytes.len() + 1); - vec.push(bytes.len() as u8); - vec.extend_from_slice(bytes); - vec - }) - .flatten() - .collect::>(); - ssl.set_alpn_protos(&alpn)?; - } - - Ok(ssl) - } -} diff --git a/rust/gel-stream/src/client/stream.rs b/rust/gel-stream/src/client/stream.rs deleted file mode 100644 index f8e175895ef..00000000000 --- a/rust/gel-stream/src/client/stream.rs +++ /dev/null @@ -1,240 +0,0 @@ -use super::{invalid_state, ConnectionError, SslError}; -use std::pin::Pin; - -pub trait Stream: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin {} -impl Stream for T where T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin {} - -/// A trait for streams that can be upgraded to a secure connection. -/// -/// This trait is usually implemented by tuples that represent a connection that can be -/// upgraded from an insecure to a secure state, typically through SSL/TLS. -pub trait StreamWithUpgrade: Unpin { - type Base: Stream; - type Upgrade: Stream; - type Config: Unpin; - - /// Perform a secure upgrade operation and return the new, wrapped connection. - #[allow(async_fn_in_trait)] - async fn secure_upgrade(self) -> Result - where - Self: Sized; -} - -impl StreamWithUpgrade for (S, ()) { - type Base = S; - type Upgrade = S; - type Config = (); - - async fn secure_upgrade(self) -> Result - where - Self: Sized, - { - Err(SslError::SslUnsupportedByClient) - } -} - -#[derive(derive_more::Debug)] -pub struct UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - inner: UpgradableStreamInner, -} - -impl From<(B, C)> for UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - #[inline(always)] - fn from(value: (B, C)) -> Self { - Self::new(value.0, value.1) - } -} - -impl UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - #[inline(always)] - pub fn new(base: B, config: C) -> Self { - UpgradableStream { - inner: UpgradableStreamInner::Base(base, config), - } - } - - pub async fn secure_upgrade(&mut self) -> Result<(), ConnectionError> - where - (B, C): StreamWithUpgrade, - { - match std::mem::replace(&mut self.inner, UpgradableStreamInner::Upgrading) { - UpgradableStreamInner::Base(base, config) => { - self.inner = - UpgradableStreamInner::Upgraded((base, config).secure_upgrade().await?); - Ok(()) - } - UpgradableStreamInner::Upgraded(..) => Err(invalid_state!( - "Attempted to upgrade an already upgraded stream" - )), - UpgradableStreamInner::Upgrading => Err(invalid_state!( - "Attempted to upgrade a stream that is already in the process of upgrading" - )), - } - } - - /// Convert the inner stream into a choice between the base and the upgraded stream. - /// - /// If the inner stream is in the process of upgrading, return an error containing `self`. - pub fn into_choice(self) -> Result, Self> { - match self.inner { - UpgradableStreamInner::Base(base, _) => Ok(UpgradableStreamChoice::Base(base)), - UpgradableStreamInner::Upgraded(upgraded) => { - Ok(UpgradableStreamChoice::Upgrade(upgraded)) - } - UpgradableStreamInner::Upgrading => Err(self), - } - } -} - -impl tokio::io::AsyncRead for UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - #[inline(always)] - fn poll_read( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - buf: &mut tokio::io::ReadBuf<'_>, - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_read(cx, buf), - UpgradableStreamInner::Upgraded(upgraded) => Pin::new(upgraded).poll_read(cx, buf), - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot read while upgrading", - ))), - } - } -} - -impl tokio::io::AsyncWrite for UpgradableStream -where - (B, C): StreamWithUpgrade, -{ - #[inline(always)] - fn poll_write( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - buf: &[u8], - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_write(cx, buf), - UpgradableStreamInner::Upgraded(upgraded) => Pin::new(upgraded).poll_write(cx, buf), - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot write while upgrading", - ))), - } - } - - #[inline(always)] - fn poll_flush( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_flush(cx), - UpgradableStreamInner::Upgraded(upgraded) => Pin::new(upgraded).poll_flush(cx), - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot flush while upgrading", - ))), - } - } - - #[inline(always)] - fn poll_shutdown( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_shutdown(cx), - UpgradableStreamInner::Upgraded(upgraded) => Pin::new(upgraded).poll_shutdown(cx), - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot shutdown while upgrading", - ))), - } - } - - #[inline(always)] - fn is_write_vectored(&self) -> bool { - match &self.inner { - UpgradableStreamInner::Base(base, _) => base.is_write_vectored(), - UpgradableStreamInner::Upgraded(upgraded) => upgraded.is_write_vectored(), - UpgradableStreamInner::Upgrading => false, - } - } - - #[inline(always)] - fn poll_write_vectored( - self: Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - bufs: &[std::io::IoSlice<'_>], - ) -> std::task::Poll> { - let inner = &mut self.get_mut().inner; - match inner { - UpgradableStreamInner::Base(base, _) => Pin::new(base).poll_write_vectored(cx, bufs), - UpgradableStreamInner::Upgraded(upgraded) => { - Pin::new(upgraded).poll_write_vectored(cx, bufs) - } - UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Cannot write vectored while upgrading", - ))), - } - } -} - -#[derive(derive_more::Debug)] -enum UpgradableStreamInner -where - (B, C): StreamWithUpgrade, -{ - #[debug("Base(..)")] - Base(B, C), - #[debug("Upgraded(..)")] - Upgraded(<(B, C) as StreamWithUpgrade>::Upgrade), - #[debug("Upgrading")] - Upgrading, -} - -#[derive(derive_more::Debug)] -pub enum UpgradableStreamChoice -where - (B, C): StreamWithUpgrade, -{ - #[debug("Base(..)")] - Base(B), - #[debug("Upgrade(..)")] - Upgrade(<(B, C) as StreamWithUpgrade>::Upgrade), -} - -impl UpgradableStreamChoice -where - (B, C): StreamWithUpgrade, - B: 'static, - <(B, C) as StreamWithUpgrade>::Base: 'static, - <(B, C) as StreamWithUpgrade>::Upgrade: 'static, -{ - /// Take the inner stream as a boxed `Stream` - pub fn into_boxed(self) -> Box { - match self { - UpgradableStreamChoice::Base(base) => Box::new(base), - UpgradableStreamChoice::Upgrade(upgrade) => Box::new(upgrade), - } - } -} diff --git a/rust/gel-stream/src/common/mod.rs b/rust/gel-stream/src/common/mod.rs new file mode 100644 index 00000000000..c2a6bed0368 --- /dev/null +++ b/rust/gel-stream/src/common/mod.rs @@ -0,0 +1,16 @@ +pub mod stream; +pub mod target; +pub mod tls; + +#[cfg(feature = "openssl")] +pub mod openssl; +#[cfg(feature = "rustls")] +pub mod rustls; +#[cfg(feature = "tokio")] +pub mod tokio_stream; + +#[cfg(feature = "tokio")] +pub type BaseStream = tokio_stream::TokioStream; + +#[cfg(not(feature = "tokio"))] +pub type BaseStream = (); diff --git a/rust/gel-stream/src/common/openssl.rs b/rust/gel-stream/src/common/openssl.rs new file mode 100644 index 00000000000..40d39587fc6 --- /dev/null +++ b/rust/gel-stream/src/common/openssl.rs @@ -0,0 +1,521 @@ +use openssl::{ + ssl::{ + AlpnError, NameType, SniError, Ssl, SslAcceptor, SslContextBuilder, SslMethod, SslRef, + SslVerifyMode, + }, + x509::{verify::X509VerifyFlags, X509VerifyResult}, +}; +use rustls_pki_types::ServerName; +use std::{ + borrow::Cow, + io::IoSlice, + pin::Pin, + sync::{Arc, Mutex, MutexGuard, OnceLock}, + task::{ready, Poll}, +}; +use tokio::{ + io::{AsyncRead, AsyncWrite, ReadBuf}, + net::TcpStream, +}; + +use crate::{ + RewindStream, SslError, SslVersion, Stream, TlsCert, TlsClientCertVerify, TlsDriver, + TlsHandshake, TlsParameters, TlsServerCertVerify, TlsServerParameterProvider, + TlsServerParameters, +}; + +use super::tokio_stream::TokioStream; + +#[derive(Debug, Clone, Default)] +struct HandshakeData { + server_alpn: Option>, + handshake: TlsHandshake, +} + +impl HandshakeData { + fn from_ssl(ssl: &SslRef) -> Option> { + let Some(handshake) = ssl.ex_data(get_ssl_ex_data_index()) else { + return None; + }; + let Ok(handshake) = handshake.lock() else { + return None; + }; + Some(handshake) + } +} + +static SSL_EX_DATA_INDEX: OnceLock>>> = + OnceLock::new(); + +fn get_ssl_ex_data_index() -> openssl::ex_data::Index>> { + *SSL_EX_DATA_INDEX + .get_or_init(|| Ssl::new_ex_index().expect("Failed to create SSL ex_data index")) +} + +#[derive(Default)] + +pub struct OpensslDriver; + +pub struct TlsStream(tokio_openssl::SslStream); + +impl AsyncRead for TlsStream { + #[inline(always)] + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> std::task::Poll> { + Pin::new(&mut self.0).poll_read(cx, buf) + } +} + +impl AsyncWrite for TlsStream { + #[inline(always)] + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + Pin::new(&mut self.0).poll_write(cx, buf) + } + + #[inline(always)] + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + bufs: &[IoSlice<'_>], + ) -> std::task::Poll> { + Pin::new(&mut self.0).poll_write_vectored(cx, bufs) + } + + #[inline(always)] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + + #[inline(always)] + fn poll_flush( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + Pin::new(&mut self.0).poll_flush(cx) + } + + #[inline(always)] + fn poll_shutdown( + mut self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let res = ready!(Pin::new(&mut self.0).poll_shutdown(cx)); + if let Err(e) = &res { + // Swallow NotConnected errors here + if e.kind() == std::io::ErrorKind::NotConnected { + return Poll::Ready(Ok(())); + } + } + Poll::Ready(res) + } +} + +impl TlsDriver for OpensslDriver { + type Stream = TlsStream; + type ClientParams = openssl::ssl::Ssl; + type ServerParams = openssl::ssl::SslContext; + + fn init_client( + params: &TlsParameters, + name: Option, + ) -> Result { + let TlsParameters { + server_cert_verify, + root_cert, + cert, + key, + crl, + min_protocol_version, + max_protocol_version, + alpn, + sni_override, + enable_keylog, + } = params; + + // let mut ssl = SslConnector::builder(SslMethod::tls_client())?; + let mut ssl = SslContextBuilder::new(SslMethod::tls_client())?; + + // Load root cert + if let TlsCert::Custom(root) = root_cert { + let root = openssl::x509::X509::from_der(root.as_ref())?; + ssl.cert_store_mut().add_cert(root)?; + ssl.set_verify(SslVerifyMode::PEER); + } else if *server_cert_verify == TlsServerCertVerify::Insecure { + ssl.set_verify(SslVerifyMode::NONE); + } + + // Load CRL + if !crl.is_empty() { + // The openssl crate doesn't yet have add_crl, so we need to use the raw FFI + use foreign_types::ForeignTypeRef; + let ptr = ssl.cert_store_mut().as_ptr(); + + extern "C" { + pub fn X509_STORE_add_crl( + store: *mut openssl_sys::X509_STORE, + x: *mut openssl_sys::X509_CRL, + ) -> openssl_sys::c_int; + } + + for crl in crl { + let crl = openssl::x509::X509Crl::from_der(crl.as_ref())?; + let crl_ptr = crl.as_ptr(); + let res = unsafe { X509_STORE_add_crl(ptr, crl_ptr) }; + if res != 1 { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Failed to add CRL to store", + ) + .into()); + } + } + + ssl.verify_param_mut() + .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?; + ssl.cert_store_mut() + .set_flags(X509VerifyFlags::CRL_CHECK | X509VerifyFlags::CRL_CHECK_ALL)?; + } + + // Load certificate chain and private key + if let (Some(cert), Some(key)) = (cert.as_ref(), key.as_ref()) { + let builder = openssl::x509::X509::from_der(cert.as_ref())?; + ssl.set_certificate(&builder)?; + let builder = openssl::pkey::PKey::private_key_from_der(&key.secret_der())?; + ssl.set_private_key(&builder)?; + } + + // Configure hostname verification + if *server_cert_verify == TlsServerCertVerify::VerifyFull { + ssl.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT); + } + + ssl.set_min_proto_version(min_protocol_version.map(|s| s.into()))?; + ssl.set_max_proto_version(max_protocol_version.map(|s| s.into()))?; + + // Configure key log filename + if *enable_keylog { + if let Ok(path) = std::env::var("SSLKEYLOGFILE") { + ssl.set_keylog_callback(move |_ssl, msg| { + let Ok(mut file) = std::fs::OpenOptions::new().append(true).open(&path) else { + return; + }; + let _ = std::io::Write::write_all(&mut file, msg.as_bytes()); + }); + } + } + + if *server_cert_verify == TlsServerCertVerify::VerifyFull { + if let Some(hostname) = sni_override { + ssl.verify_param_mut().set_host(hostname)?; + } else if let Some(ServerName::DnsName(hostname)) = &name { + ssl.verify_param_mut().set_host(hostname.as_ref())?; + } else if let Some(ServerName::IpAddress(ip)) = &name { + ssl.verify_param_mut().set_ip((*ip).into())?; + } + } + + let mut ssl = openssl::ssl::Ssl::new(&ssl.build())?; + ssl.set_connect_state(); + + // Set hostname if it's not an IP address + if let Some(hostname) = sni_override { + ssl.set_hostname(hostname)?; + } else if let Some(ServerName::DnsName(hostname)) = &name { + ssl.set_hostname(hostname.as_ref())?; + } + + if !alpn.is_empty() { + ssl.set_alpn_protos(&alpn.as_bytes())?; + } + + Ok(ssl) + } + + fn init_server(params: &TlsServerParameters) -> Result { + let TlsServerParameters { + client_cert_verify, + min_protocol_version, + max_protocol_version, + server_certificate, + // Handled elsewhere + alpn: _alpn, + } = params; + + let mut ssl = SslAcceptor::mozilla_intermediate_v5(SslMethod::tls_server())?; + let cert = openssl::x509::X509::from_der(&server_certificate.cert.as_ref())?; + let key = openssl::pkey::PKey::private_key_from_der(&server_certificate.key.secret_der())?; + ssl.set_certificate(&cert)?; + ssl.set_private_key(&key)?; + ssl.set_min_proto_version(min_protocol_version.map(|s| s.into()))?; + ssl.set_max_proto_version(max_protocol_version.map(|s| s.into()))?; + match client_cert_verify { + TlsClientCertVerify::Ignore => ssl.set_verify(SslVerifyMode::NONE), + TlsClientCertVerify::Optional(root) => { + ssl.set_verify(SslVerifyMode::PEER); + for root in root { + let root = openssl::x509::X509::from_der(root.as_ref())?; + ssl.cert_store_mut().add_cert(root)?; + } + } + TlsClientCertVerify::Validate(root) => { + ssl.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT); + for root in root { + let root = openssl::x509::X509::from_der(root.as_ref())?; + ssl.cert_store_mut().add_cert(root)?; + } + } + } + create_alpn_callback(&mut ssl); + + Ok(ssl.build().into_context()) + } + + async fn upgrade_client( + params: Self::ClientParams, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + let stream = stream + .downcast::() + .map_err(|_| crate::SslError::SslUnsupportedByClient)?; + let TokioStream::Tcp(stream) = stream else { + return Err(crate::SslError::SslUnsupportedByClient); + }; + + let mut stream = tokio_openssl::SslStream::new(params, stream)?; + let res = Pin::new(&mut stream).do_handshake().await; + if res.is_err() { + if stream.ssl().verify_result() != X509VerifyResult::OK { + return Err(SslError::OpenSslErrorVerify(stream.ssl().verify_result())); + } + } + + let alpn = stream + .ssl() + .selected_alpn_protocol() + .map(|p| Cow::Owned(p.to_vec())); + + res.map_err(SslError::OpenSslError)?; + Ok(( + TlsStream(stream), + TlsHandshake { + alpn, + sni: None, + cert: None, + }, + )) + } + + async fn upgrade_server( + params: TlsServerParameterProvider, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + let stream = stream + .downcast::>() + .map_err(|_| crate::SslError::SslUnsupportedByClient)?; + let (stream, buffer) = stream.into_inner(); + if !buffer.is_empty() { + // TODO: We should also be able to support rewinding + return Err(crate::SslError::SslUnsupportedByClient); + } + let TokioStream::Tcp(stream) = stream else { + return Err(crate::SslError::SslUnsupportedByClient); + }; + + let handshake = Arc::new(Mutex::new(HandshakeData::default())); + + let mut ssl = SslContextBuilder::new(SslMethod::tls_server())?; + create_alpn_callback(&mut ssl); + create_sni_callback(&mut ssl, params); + + let mut ssl = Ssl::new(&ssl.build())?; + ssl.set_accept_state(); + ssl.set_ex_data(get_ssl_ex_data_index(), handshake.clone()); + + let mut stream = tokio_openssl::SslStream::new(ssl, stream)?; + let res = Pin::new(&mut stream).do_handshake().await; + res.map_err(SslError::OpenSslError)?; + + let handshake = handshake.lock().unwrap().handshake.clone(); + + Ok((TlsStream(stream), handshake)) + } +} + +fn ssl_select_next_proto<'a, 'b>(server: &'a [u8], client: &'b [u8]) -> Option<&'b [u8]> { + let mut server_packet = server; + while !server_packet.is_empty() { + let server_proto_len = *server_packet.get(0)? as usize; + let server_proto = server_packet.get(1..1 + server_proto_len)?; + let mut client_packet = client; + while !client_packet.is_empty() { + let client_proto_len = *client_packet.get(0)? as usize; + let client_proto = client_packet.get(1..1 + client_proto_len)?; + if client_proto == server_proto { + return Some(client_proto); + } + client_packet = client_packet.get(1 + client_proto_len..)?; + } + server_packet = server_packet.get(1 + server_proto_len..)?; + } + None +} + +/// Create an ALPN callback for the [`SslContextBuilder`]. +fn create_alpn_callback(ssl: &mut SslContextBuilder) { + ssl.set_alpn_select_callback(|ssl_ref, alpn| { + let Some(mut handshake) = HandshakeData::from_ssl(ssl_ref) else { + return Err(AlpnError::ALERT_FATAL); + }; + + if let Some(server) = handshake.server_alpn.take() { + eprintln!("server: {:?} alpn: {:?}", server, alpn); + let Some(selected) = ssl_select_next_proto(&server, alpn) else { + return Err(AlpnError::NOACK); + }; + handshake.handshake.alpn = Some(Cow::Owned(selected.to_vec())); + + Ok(selected) + } else { + Err(AlpnError::NOACK) + } + }) +} + +/// Create an SNI callback for the [`SslContextBuilder`]. +fn create_sni_callback(ssl: &mut SslContextBuilder, params: TlsServerParameterProvider) { + ssl.set_servername_callback(move |ssl_ref, _alert| { + let Some(mut handshake) = HandshakeData::from_ssl(ssl_ref) else { + return Ok(()); + }; + + if let Some(servername) = ssl_ref.servername_raw(NameType::HOST_NAME) { + handshake.handshake.sni = + Some(Cow::Owned(String::from_utf8_lossy(servername).to_string())); + } + + let params = params.lookup(None); + if !params.alpn.is_empty() { + handshake.server_alpn = Some(params.alpn.as_bytes().to_vec()); + } + + drop(handshake); + + let Ok(ssl) = OpensslDriver::init_server(¶ms) else { + return Err(SniError::ALERT_FATAL); + }; + let Ok(_) = ssl_ref.set_ssl_context(&ssl) else { + return Err(SniError::ALERT_FATAL); + }; + Ok(()) + }); +} + +impl From for openssl::ssl::SslVersion { + fn from(val: SslVersion) -> Self { + match val { + SslVersion::Tls1 => openssl::ssl::SslVersion::TLS1, + SslVersion::Tls1_1 => openssl::ssl::SslVersion::TLS1_1, + SslVersion::Tls1_2 => openssl::ssl::SslVersion::TLS1_2, + SslVersion::Tls1_3 => openssl::ssl::SslVersion::TLS1_3, + } + } +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_ssl_select_next_proto() { + let server = b"\x02h2\x08http/1.1"; + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"http/1.1".as_slice())); + } + + #[test] + fn test_ssl_select_next_proto_empty() { + let server = b""; + let client = b""; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_invalid_length() { + let server = b"\x08h2"; // Claims 8 bytes but only has 2 + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_zero_length() { + let server = b"\x00h2"; // Zero length but has data + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_truncated() { + let server = b"\x02h2\x08http/1"; // Second protocol truncated + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_overflow() { + let server = b"\xFFh2"; // Length that would overflow buffer + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_no_match() { + let server = b"\x02h2"; + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, None); + } + + #[test] + fn test_ssl_select_next_proto_multiple_server() { + let server = b"\x02h2\x06spdy/2\x08http/1.1"; + let client = b"\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"http/1.1".as_slice())); + } + + #[test] + fn test_ssl_select_next_proto_multiple_client() { + let server = b"\x08http/1.1"; + let client = b"\x02h2\x06spdy/2\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"http/1.1".as_slice())); + } + + #[test] + fn test_ssl_select_next_proto_first_match() { + let server = b"\x02h2\x06spdy/2\x08http/1.1"; + let client = b"\x06spdy/2\x02h2\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"h2".as_slice())); + } + + #[test] + fn test_ssl_select_next_proto_first_match_2() { + let server = b"\x06spdy/2\x02h2\x08http/1.1"; + let client = b"\x02h2\x06spdy/2\x08http/1.1"; + let selected = ssl_select_next_proto(server, client); + assert_eq!(selected, Some(b"spdy/2".as_slice())); + } +} diff --git a/rust/gel-stream/src/client/rustls.rs b/rust/gel-stream/src/common/rustls.rs similarity index 53% rename from rust/gel-stream/src/client/rustls.rs rename to rust/gel-stream/src/common/rustls.rs index 456dc4818ec..8ec4368a317 100644 --- a/rust/gel-stream/src/client/rustls.rs +++ b/rust/gel-stream/src/common/rustls.rs @@ -1,109 +1,39 @@ +use futures::FutureExt; use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; use rustls::client::WebPkiServerVerifier; +use rustls::server::{Acceptor, ClientHello, WebPkiClientVerifier}; use rustls::{ - ClientConfig, ClientConnection, DigitallySignedStruct, RootCertStore, SignatureScheme, + ClientConfig, ClientConnection, DigitallySignedStruct, RootCertStore, ServerConfig, + SignatureScheme, }; use rustls_pki_types::{ CertificateDer, CertificateRevocationListDer, DnsName, ServerName, UnixTime, }; use rustls_platform_verifier::Verifier; +use rustls_tokio_stream::TlsStream; -use super::stream::{Stream, StreamWithUpgrade}; use super::tokio_stream::TokioStream; -use super::{TlsCert, TlsInit, TlsParameters, TlsServerCertVerify}; -use std::any::Any; +use crate::{ + RewindStream, SslError, Stream, TlsClientCertVerify, TlsDriver, TlsHandshake, + TlsServerParameterProvider, TlsServerParameters, +}; +use crate::{TlsCert, TlsParameters, TlsServerCertVerify}; +use std::borrow::Cow; use std::net::{IpAddr, Ipv4Addr}; use std::sync::Arc; -impl StreamWithUpgrade for (S, Option) { - type Base = S; - type Config = ClientConnection; - type Upgrade = rustls_tokio_stream::TlsStream; - - async fn secure_upgrade(self) -> Result - where - Self: Sized, - { - let Some(tls) = self.1 else { - return Err(super::SslError::SslUnsupportedByClient); - }; - - // Note that we only support Tokio TcpStream for rustls. - let stream = &mut Some(self.0) as &mut dyn Any; - let Some(stream) = stream.downcast_mut::>() else { - return Err(super::SslError::SslUnsupportedByClient); - }; - - let stream = stream.take().unwrap(); - let TokioStream::Tcp(stream) = stream else { - return Err(super::SslError::SslUnsupportedByClient); - }; - - let mut stream = rustls_tokio_stream::TlsStream::new_client_side(stream, tls, None); - let res = stream.handshake().await; - - // Potentially unwrap the error to get the underlying error. - if let Err(e) = res { - let kind = e.kind(); - if let Some(e2) = e.into_inner() { - match e2.downcast::<::rustls::Error>() { - Ok(e) => return Err(super::SslError::RustlsError(*e)), - Err(e) => return Err(std::io::Error::new(kind, e).into()), - } - } else { - return Err(std::io::Error::from(kind).into()); - } - } - - Ok(stream) - } -} +#[derive(Default)] +pub struct RustlsDriver; -fn make_verifier( - server_cert_verify: &TlsServerCertVerify, - root_cert: &TlsCert, - crls: Vec>, -) -> Result, super::SslError> { - if *server_cert_verify == TlsServerCertVerify::Insecure { - return Ok(Arc::new(NullVerifier)); - } +impl TlsDriver for RustlsDriver { + type Stream = TlsStream; + type ClientParams = ClientConnection; + type ServerParams = Arc; - if let TlsCert::Custom(root) = root_cert { - let mut roots = RootCertStore::empty(); - let (loaded, ignored) = roots.add_parsable_certificates([root.clone()]); - if loaded == 0 || ignored > 0 { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidInput, - "Invalid certificate", - ) - .into()); - } - - let verifier = WebPkiServerVerifier::builder(Arc::new(roots)) - .with_crls(crls) - .build()?; - if *server_cert_verify == TlsServerCertVerify::IgnoreHostname { - return Ok(Arc::new(IgnoreHostnameVerifier::new(verifier))); - } - return Ok(verifier); - } - - if *server_cert_verify == TlsServerCertVerify::IgnoreHostname { - return Ok(Arc::new(IgnoreHostnameVerifier::new(Arc::new( - Verifier::new(), - )))); - } - - Ok(Arc::new(Verifier::new())) -} - -impl TlsInit for ClientConnection { - type Tls = ClientConnection; - - fn init( - parameters: &TlsParameters, + fn init_client( + params: &TlsParameters, name: Option, - ) -> Result { + ) -> Result { let _ = ::rustls::crypto::ring::default_provider().install_default(); let TlsParameters { @@ -117,7 +47,7 @@ impl TlsInit for ClientConnection { alpn, enable_keylog, sni_override, - } = parameters; + } = params; let verifier = make_verifier(server_cert_verify, root_cert, crl.clone())?; @@ -140,12 +70,7 @@ impl TlsInit for ClientConnection { }; // Configure ALPN if provided - if let Some(alpn_protocols) = alpn { - config.alpn_protocols = alpn_protocols - .iter() - .map(|p| p.as_bytes().to_vec()) - .collect(); - } + config.alpn_protocols = alpn.as_vec_vec(); // Configure keylog if provided if *enable_keylog { @@ -163,6 +88,172 @@ impl TlsInit for ClientConnection { Ok(ClientConnection::new(Arc::new(config), name)?) } + + fn init_server(params: &TlsServerParameters) -> Result { + let builder = match ¶ms.client_cert_verify { + TlsClientCertVerify::Ignore => ServerConfig::builder().with_no_client_auth(), + TlsClientCertVerify::Optional(certs) => { + let mut roots = RootCertStore::empty(); + roots.add_parsable_certificates( + certs.iter().map(|c| CertificateDer::from_slice(c.as_ref())), + ); + ServerConfig::builder().with_client_cert_verifier( + WebPkiClientVerifier::builder(roots.into()) + .allow_unauthenticated() + .build()?, + ) + } + TlsClientCertVerify::Validate(certs) => { + let mut roots = RootCertStore::empty(); + roots.add_parsable_certificates( + certs.iter().map(|c| CertificateDer::from_slice(c.as_ref())), + ); + ServerConfig::builder() + .with_client_cert_verifier(WebPkiClientVerifier::builder(roots.into()).build()?) + } + }; + + let mut config = builder.with_single_cert( + vec![params.server_certificate.cert.clone()], + params.server_certificate.key.clone_key(), + )?; + + config.alpn_protocols = params.alpn.as_vec_vec(); + + Ok(Arc::new(config)) + } + + async fn upgrade_client( + params: Self::ClientParams, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + // Note that we only support Tokio TcpStream for rustls. + let stream = stream + .downcast::() + .map_err(|_| crate::SslError::SslUnsupportedByClient)?; + let TokioStream::Tcp(stream) = stream else { + return Err(crate::SslError::SslUnsupportedByClient); + }; + + let mut stream = TlsStream::new_client_side(stream, params, None); + + match stream.handshake().await { + Ok(handshake) => Ok(( + stream, + TlsHandshake { + alpn: handshake.alpn.map(|alpn| Cow::Owned(alpn.to_vec())), + sni: handshake.sni.map(|sni| Cow::Owned(sni.to_string())), + cert: None, + }, + )), + Err(e) => { + let kind = e.kind(); + if let Some(e2) = e.into_inner() { + match e2.downcast::<::rustls::Error>() { + Ok(e) => Err(crate::SslError::RustlsError(*e)), + Err(e) => Err(std::io::Error::new(kind, e).into()), + } + } else { + Err(std::io::Error::from(kind).into()) + } + } + } + } + + async fn upgrade_server( + params: TlsServerParameterProvider, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + let stream = stream + .downcast::>() + .map_err(|_| crate::SslError::SslUnsupportedByClient)?; + let (stream, buffer) = stream.into_inner(); + let TokioStream::Tcp(stream) = stream else { + return Err(crate::SslError::SslUnsupportedByClient); + }; + + let mut acceptor = Acceptor::default(); + acceptor.read_tls(&mut buffer.as_slice())?; + let server_config_provider = Arc::new(move |client_hello: ClientHello| { + let params = params.clone(); + let server_name = client_hello + .server_name() + .map(|name| ServerName::DnsName(DnsName::try_from(name.to_string()).unwrap())); + async move { + let params = params.lookup(server_name); + let config = RustlsDriver::init_server(¶ms) + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidInput, e))?; + Ok::<_, std::io::Error>(config) + } + .boxed() + }); + let mut stream = TlsStream::new_server_side_from_acceptor( + acceptor, + stream, + server_config_provider, + None, + ); + + match stream.handshake().await { + Ok(handshake) => Ok(( + stream, + TlsHandshake { + alpn: handshake.alpn.map(|alpn| Cow::Owned(alpn.to_vec())), + sni: handshake.sni.map(|sni| Cow::Owned(sni.to_string())), + cert: None, + }, + )), + Err(e) => { + let kind = e.kind(); + if let Some(e2) = e.into_inner() { + match e2.downcast::<::rustls::Error>() { + Ok(e) => Err(crate::SslError::RustlsError(*e)), + Err(e) => Err(std::io::Error::new(kind, e).into()), + } + } else { + Err(std::io::Error::from(kind).into()) + } + } + } + } +} + +fn make_verifier( + server_cert_verify: &TlsServerCertVerify, + root_cert: &TlsCert, + crls: Vec>, +) -> Result, crate::SslError> { + if *server_cert_verify == TlsServerCertVerify::Insecure { + return Ok(Arc::new(NullVerifier)); + } + + if let TlsCert::Custom(root) = root_cert { + let mut roots = RootCertStore::empty(); + let (loaded, ignored) = roots.add_parsable_certificates([root.clone()]); + if loaded == 0 || ignored > 0 { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Invalid certificate", + ) + .into()); + } + + let verifier = WebPkiServerVerifier::builder(Arc::new(roots)) + .with_crls(crls) + .build()?; + if *server_cert_verify == TlsServerCertVerify::IgnoreHostname { + return Ok(Arc::new(IgnoreHostnameVerifier::new(verifier))); + } + return Ok(verifier); + } + + if *server_cert_verify == TlsServerCertVerify::IgnoreHostname { + return Ok(Arc::new(IgnoreHostnameVerifier::new(Arc::new( + Verifier::new(), + )))); + } + + Ok(Arc::new(Verifier::new())) } #[derive(Debug)] diff --git a/rust/gel-stream/src/common/stream.rs b/rust/gel-stream/src/common/stream.rs new file mode 100644 index 00000000000..9b56a25e68a --- /dev/null +++ b/rust/gel-stream/src/common/stream.rs @@ -0,0 +1,343 @@ +#[cfg(feature = "tokio")] +use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; + +use std::future::Future; +#[cfg(feature = "tokio")] +use std::{ + any::Any, + io::IoSlice, + pin::Pin, + task::{Context, Poll}, +}; + +use crate::{Ssl, SslError, TlsDriver, TlsHandshake, TlsServerParameterProvider}; + +#[cfg(feature = "tokio")] +pub trait Stream: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static { + fn downcast(self) -> Result + where + Self: Sized + 'static, + { + // Note that we only support Tokio TcpStream for rustls. + let mut holder = Some(self); + let stream = &mut holder as &mut dyn Any; + let Some(stream) = stream.downcast_mut::>() else { + return Err(holder.take().unwrap()); + }; + let stream = stream.take().unwrap(); + Ok(stream) + } +} + +#[cfg(feature = "tokio")] +impl Stream for T where T: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin + Send + 'static {} + +#[cfg(not(feature = "tokio"))] +pub trait Stream: 'static {} +#[cfg(not(feature = "tokio"))] +impl Stream for UpgradableStream {} +#[cfg(not(feature = "tokio"))] +impl Stream for () {} + +pub trait StreamUpgrade: Stream { + fn secure_upgrade(&mut self) -> impl Future> + Send; + fn handshake(&self) -> Option<&TlsHandshake>; +} + +#[allow(private_bounds)] +#[derive(derive_more::Debug)] +pub struct UpgradableStream { + inner: UpgradableStreamInner, +} + +#[allow(private_bounds)] +impl UpgradableStream { + #[inline(always)] + pub(crate) fn new_client(base: S, config: Option) -> Self { + UpgradableStream { + inner: UpgradableStreamInner::BaseClient(base, config), + } + } + + #[inline(always)] + pub(crate) fn new_server(base: S, config: Option) -> Self { + UpgradableStream { + inner: UpgradableStreamInner::BaseServer(base, config), + } + } + + /// Consume the `UpgradableStream` and return the underlying stream as a [`Box`]. + pub fn into_boxed(self) -> Result, Self> { + match self.inner { + UpgradableStreamInner::BaseClient(base, _) => Ok(Box::new(base)), + UpgradableStreamInner::BaseServer(base, _) => Ok(Box::new(base)), + UpgradableStreamInner::Upgraded(upgraded, _) => Ok(Box::new(upgraded)), + UpgradableStreamInner::Upgrading => Err(self), + } + } +} + +impl StreamUpgrade for UpgradableStream { + async fn secure_upgrade(&mut self) -> Result<(), SslError> { + match std::mem::replace(&mut self.inner, UpgradableStreamInner::Upgrading) { + UpgradableStreamInner::BaseClient(base, config) => { + let Some(config) = config else { + return Err(SslError::SslUnsupportedByClient); + }; + let (upgraded, handshake) = D::upgrade_client(config, base).await?; + self.inner = UpgradableStreamInner::Upgraded(upgraded, handshake); + Ok(()) + } + UpgradableStreamInner::BaseServer(base, config) => { + let Some(config) = config else { + return Err(SslError::SslUnsupportedByClient); + }; + let (upgraded, handshake) = D::upgrade_server(config, base).await?; + self.inner = UpgradableStreamInner::Upgraded(upgraded, handshake); + Ok(()) + } + UpgradableStreamInner::Upgraded(..) => Err(SslError::SslAlreadyUpgraded), + UpgradableStreamInner::Upgrading => Err(SslError::SslAlreadyUpgraded), + } + } + + fn handshake(&self) -> Option<&TlsHandshake> { + match &self.inner { + UpgradableStreamInner::Upgraded(_, handshake) => Some(handshake), + _ => None, + } + } +} + +#[cfg(feature = "tokio")] +impl tokio::io::AsyncRead for UpgradableStream { + #[inline(always)] + fn poll_read( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &mut tokio::io::ReadBuf<'_>, + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => Pin::new(base).poll_read(cx, buf), + UpgradableStreamInner::BaseServer(base, _) => Pin::new(base).poll_read(cx, buf), + UpgradableStreamInner::Upgraded(upgraded, _) => Pin::new(upgraded).poll_read(cx, buf), + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot read while upgrading", + ))), + } + } +} + +#[cfg(feature = "tokio")] +impl tokio::io::AsyncWrite for UpgradableStream { + #[inline(always)] + fn poll_write( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + buf: &[u8], + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => Pin::new(base).poll_write(cx, buf), + UpgradableStreamInner::BaseServer(base, _) => Pin::new(base).poll_write(cx, buf), + UpgradableStreamInner::Upgraded(upgraded, _) => Pin::new(upgraded).poll_write(cx, buf), + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot write while upgrading", + ))), + } + } + + #[inline(always)] + fn poll_flush( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => Pin::new(base).poll_flush(cx), + UpgradableStreamInner::BaseServer(base, _) => Pin::new(base).poll_flush(cx), + UpgradableStreamInner::Upgraded(upgraded, _) => Pin::new(upgraded).poll_flush(cx), + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot flush while upgrading", + ))), + } + } + + #[inline(always)] + fn poll_shutdown( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => Pin::new(base).poll_shutdown(cx), + UpgradableStreamInner::BaseServer(base, _) => Pin::new(base).poll_shutdown(cx), + UpgradableStreamInner::Upgraded(upgraded, _) => Pin::new(upgraded).poll_shutdown(cx), + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot shutdown while upgrading", + ))), + } + } + + #[inline(always)] + fn is_write_vectored(&self) -> bool { + match &self.inner { + UpgradableStreamInner::BaseClient(base, _) => base.is_write_vectored(), + UpgradableStreamInner::BaseServer(base, _) => base.is_write_vectored(), + UpgradableStreamInner::Upgraded(upgraded, _) => upgraded.is_write_vectored(), + UpgradableStreamInner::Upgrading => false, + } + } + + #[inline(always)] + fn poll_write_vectored( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + bufs: &[std::io::IoSlice<'_>], + ) -> std::task::Poll> { + let inner = &mut self.get_mut().inner; + match inner { + UpgradableStreamInner::BaseClient(base, _) => { + Pin::new(base).poll_write_vectored(cx, bufs) + } + UpgradableStreamInner::BaseServer(base, _) => { + Pin::new(base).poll_write_vectored(cx, bufs) + } + UpgradableStreamInner::Upgraded(upgraded, _) => { + Pin::new(upgraded).poll_write_vectored(cx, bufs) + } + UpgradableStreamInner::Upgrading => std::task::Poll::Ready(Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Cannot write vectored while upgrading", + ))), + } + } +} + +#[derive(derive_more::Debug)] +enum UpgradableStreamInner { + #[debug("BaseClient(..)")] + BaseClient(S, Option), + #[debug("BaseServer(..)")] + BaseServer(S, Option), + #[debug("Upgraded(..)")] + Upgraded(D::Stream, TlsHandshake), + #[debug("Upgrading")] + Upgrading, +} + +pub trait Rewindable { + fn rewind(&mut self, bytes: &[u8]) -> std::io::Result<()>; +} + +pub struct RewindStream { + buffer: Vec, + inner: S, +} + +impl RewindStream { + pub fn new(inner: S) -> Self { + RewindStream { + buffer: Vec::new(), + inner, + } + } + + pub fn rewind(&mut self, data: &[u8]) { + self.buffer.extend_from_slice(data); + } + + pub fn into_inner(self) -> (S, Vec) { + (self.inner, self.buffer) + } +} + +#[cfg(feature = "tokio")] +impl AsyncRead for RewindStream { + #[inline(always)] + fn poll_read( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &mut ReadBuf<'_>, + ) -> Poll> { + if !self.buffer.is_empty() { + let to_read = std::cmp::min(buf.remaining(), self.buffer.len()); + let data = self.buffer.drain(..to_read).collect::>(); + buf.put_slice(&data); + Poll::Ready(Ok(())) + } else { + Pin::new(&mut self.inner).poll_read(cx, buf) + } + } +} + +#[cfg(feature = "tokio")] +impl AsyncWrite for RewindStream { + #[inline(always)] + fn poll_write( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + buf: &[u8], + ) -> Poll> { + Pin::new(&mut self.inner).poll_write(cx, buf) + } + + #[inline(always)] + fn poll_flush( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + Pin::new(&mut self.inner).poll_flush(cx) + } + + #[inline(always)] + fn poll_shutdown( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll> { + Pin::new(&mut self.inner).poll_shutdown(cx) + } + + #[inline(always)] + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + #[inline(always)] + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { + Pin::new(&mut self.inner).poll_write_vectored(cx, bufs) + } +} + +impl Rewindable for RewindStream { + fn rewind(&mut self, bytes: &[u8]) -> std::io::Result<()> { + self.rewind(bytes); + Ok(()) + } +} + +impl Rewindable for UpgradableStream +where + D::Stream: Rewindable, +{ + fn rewind(&mut self, bytes: &[u8]) -> std::io::Result<()> { + match &mut self.inner { + UpgradableStreamInner::BaseClient(stm, _) => stm.rewind(bytes), + UpgradableStreamInner::BaseServer(stm, _) => stm.rewind(bytes), + UpgradableStreamInner::Upgraded(stm, _) => stm.rewind(bytes), + UpgradableStreamInner::Upgrading => Err(std::io::Error::new( + std::io::ErrorKind::Unsupported, + "Cannot rewind a stream that is upgrading", + )), + } + } +} diff --git a/rust/gel-stream/src/client/target.rs b/rust/gel-stream/src/common/target.rs similarity index 97% rename from rust/gel-stream/src/client/target.rs rename to rust/gel-stream/src/common/target.rs index 233b03865c5..1eccbdb1cff 100644 --- a/rust/gel-stream/src/client/target.rs +++ b/rust/gel-stream/src/common/target.rs @@ -7,7 +7,7 @@ use std::{ use rustls_pki_types::ServerName; -use super::TlsParameters; +use crate::TlsParameters; /// A target name describes the TCP or Unix socket that a client will connect to. pub struct TargetName { @@ -249,6 +249,19 @@ pub enum ResolvedTarget { UnixSocketAddr(std::os::unix::net::SocketAddr), } +impl ResolvedTarget { + pub fn tcp(&self) -> Option { + match self { + ResolvedTarget::SocketAddr(addr) => Some(*addr), + _ => None, + } + } +} + +pub trait LocalAddress { + fn local_address(&self) -> std::io::Result; +} + trait TcpResolve { fn into(self) -> MaybeResolvedTarget; } diff --git a/rust/gel-stream/src/common/tls.rs b/rust/gel-stream/src/common/tls.rs new file mode 100644 index 00000000000..07c2ead1608 --- /dev/null +++ b/rust/gel-stream/src/common/tls.rs @@ -0,0 +1,259 @@ +use crate::{SslError, Stream}; +use rustls_pki_types::{CertificateDer, CertificateRevocationListDer, PrivateKeyDer, ServerName}; +use std::{borrow::Cow, future::Future, sync::Arc}; + +use super::BaseStream; + +// Note that we choose rustls when both openssl and rustls are enabled. + +#[cfg(all(feature = "openssl", not(feature = "rustls")))] +pub type Ssl = crate::common::openssl::OpensslDriver; +#[cfg(feature = "rustls")] +pub type Ssl = crate::common::rustls::RustlsDriver; +#[cfg(not(any(feature = "openssl", feature = "rustls")))] +pub type Ssl = NullTlsDriver; + +pub trait TlsDriver: Default + Send + Sync + Unpin + 'static { + type Stream: Stream + Send; + type ClientParams: Unpin + Send; + type ServerParams: Unpin + Send; + + #[allow(unused)] + fn init_client( + params: &TlsParameters, + name: Option, + ) -> Result; + #[allow(unused)] + fn init_server(params: &TlsServerParameters) -> Result; + + fn upgrade_client( + params: Self::ClientParams, + stream: S, + ) -> impl Future> + Send; + fn upgrade_server( + params: TlsServerParameterProvider, + stream: S, + ) -> impl Future> + Send; +} + +#[derive(Default)] +pub struct NullTlsDriver; + +#[allow(unused)] +impl TlsDriver for NullTlsDriver { + type Stream = BaseStream; + type ClientParams = (); + type ServerParams = (); + + fn init_client( + params: &TlsParameters, + name: Option, + ) -> Result { + Err(SslError::SslUnsupportedByClient) + } + + fn init_server(params: &TlsServerParameters) -> Result { + Err(SslError::SslUnsupportedByClient) + } + + async fn upgrade_client( + params: Self::ClientParams, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + Err(SslError::SslUnsupportedByClient) + } + + async fn upgrade_server( + params: TlsServerParameterProvider, + stream: S, + ) -> Result<(Self::Stream, TlsHandshake), SslError> { + Err(SslError::SslUnsupportedByClient) + } +} + +/// Verification modes for TLS that are a superset of both PostgreSQL and EdgeDB/Gel. +/// +/// Postgres offers six levels: `disable`, `allow`, `prefer`, `require`, `verify-ca` and `verify-full`. +/// +/// EdgeDB/Gel offers three levels: `insecure`, `no_host_verification' and 'strict'. +/// +/// This table maps the various levels: +/// +/// | Postgres | EdgeDB/Gel | `TlsServerCertVerify` enum | +/// | -------- | ----------- | ----------------- | +/// | require | insecure | `Insecure` | +/// | verify-ca | no_host_verification | `IgnoreHostname` | +/// | verify-full | strict | `VerifyFull` | +/// +/// Note that both EdgeDB/Gel and Postgres may alter certificate validation levels +/// when custom root certificates are provided. This must be done in the +/// `TlsParameters` struct by the caller. +#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] +pub enum TlsServerCertVerify { + /// Do not verify the server's certificate. Only confirm that the server is + /// using TLS. + Insecure, + /// Verify the server's certificate using the CA (ignore hostname). + IgnoreHostname, + /// Verify the server's certificate using the CA and hostname. + #[default] + VerifyFull, +} + +#[derive(Debug, Clone, Default, PartialEq, Eq)] +pub enum TlsCert { + /// Use the system's default certificate. + #[default] + System, + /// Use a custom root certificate only. + Custom(CertificateDer<'static>), +} + +#[derive(Default, Debug, PartialEq, Eq)] +pub struct TlsParameters { + pub server_cert_verify: TlsServerCertVerify, + pub cert: Option>, + pub key: Option>, + pub root_cert: TlsCert, + pub crl: Vec>, + pub min_protocol_version: Option, + pub max_protocol_version: Option, + pub enable_keylog: bool, + pub sni_override: Option>, + pub alpn: TlsAlpn, +} + +impl TlsParameters { + pub fn insecure() -> Self { + Self { + server_cert_verify: TlsServerCertVerify::Insecure, + ..Default::default() + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum SslVersion { + Tls1, + Tls1_1, + Tls1_2, + Tls1_3, +} + +#[derive(Default, Debug, PartialEq, Eq)] +pub enum TlsClientCertVerify { + /// Do not verify the client's certificate, just ignore it. + #[default] + Ignore, + /// If a client certificate is provided, validate it. + Optional(Vec>), + /// Validate that a client certificate exists and is valid. This configuration + /// may not be ideal, because it does not fail the client-side handshake. + Validate(Vec>), +} + +#[derive(derive_more::Debug, derive_more::Constructor)] +pub struct TlsKey { + #[debug("key(...)")] + pub(crate) key: PrivateKeyDer<'static>, + #[debug("cert(...)")] + pub(crate) cert: CertificateDer<'static>, +} + +#[derive(Debug, Clone)] +pub struct TlsServerParameterProvider { + inner: TlsServerParameterProviderInner, +} + +impl TlsServerParameterProvider { + pub fn new(params: TlsServerParameters) -> Self { + Self { + inner: TlsServerParameterProviderInner::Static(Arc::new(params)), + } + } + + pub fn with_lookup( + lookup: impl Fn(Option) -> Arc + Send + Sync + 'static, + ) -> Self { + Self { + inner: TlsServerParameterProviderInner::Lookup(Arc::new(lookup)), + } + } + + pub fn lookup(&self, name: Option) -> Arc { + match &self.inner { + TlsServerParameterProviderInner::Static(params) => params.clone(), + TlsServerParameterProviderInner::Lookup(lookup) => lookup(name), + } + } +} + +#[derive(derive_more::Debug, Clone)] +enum TlsServerParameterProviderInner { + Static(Arc), + #[debug("Lookup(...)")] + #[allow(clippy::type_complexity)] + Lookup(Arc) -> Arc + Send + Sync + 'static>), +} + +#[derive(Debug)] +pub struct TlsServerParameters { + pub client_cert_verify: TlsClientCertVerify, + pub min_protocol_version: Option, + pub max_protocol_version: Option, + pub server_certificate: TlsKey, + pub alpn: TlsAlpn, +} + +#[derive(Debug, Default, Eq, PartialEq)] +pub struct TlsAlpn { + /// The split form (ie: ["AB", "ABCD"]) + alpn_parts: Cow<'static, [Cow<'static, [u8]>]>, +} + +impl TlsAlpn { + pub fn new(alpn: &'static [&'static [u8]]) -> Self { + let alpn = alpn.iter().map(|s| Cow::Borrowed(*s)).collect::>(); + Self { + alpn_parts: Cow::Owned(alpn), + } + } + + pub fn new_str(alpn: &'static [&'static str]) -> Self { + let alpn = alpn + .iter() + .map(|s| Cow::Borrowed(s.as_bytes())) + .collect::>(); + Self { + alpn_parts: Cow::Owned(alpn), + } + } + + pub fn is_empty(&self) -> bool { + self.alpn_parts.is_empty() + } + + pub fn as_bytes(&self) -> Vec { + let mut bytes = Vec::with_capacity(self.alpn_parts.len() * 2); + for part in self.alpn_parts.iter() { + bytes.push(part.len() as u8); + bytes.extend_from_slice(part.as_ref()); + } + bytes + } + + pub fn as_vec_vec(&self) -> Vec> { + let mut vec = Vec::with_capacity(self.alpn_parts.len()); + for part in self.alpn_parts.iter() { + vec.push(part.to_vec()); + } + vec + } +} + +#[derive(Debug, Clone, Default)] +pub struct TlsHandshake { + pub alpn: Option>, + pub sni: Option>, + pub cert: Option>, +} diff --git a/rust/gel-stream/src/client/tokio_stream.rs b/rust/gel-stream/src/common/tokio_stream.rs similarity index 61% rename from rust/gel-stream/src/client/tokio_stream.rs rename to rust/gel-stream/src/common/tokio_stream.rs index 3b938e86d28..45b07310708 100644 --- a/rust/gel-stream/src/client/tokio_stream.rs +++ b/rust/gel-stream/src/common/tokio_stream.rs @@ -2,13 +2,13 @@ use std::net::{IpAddr, ToSocketAddrs}; use std::pin::Pin; -use std::task::{Context, Poll}; +use std::task::{ready, Context, Poll}; use tokio::io::{AsyncRead, AsyncWrite}; -use tokio::net::TcpStream; #[cfg(unix)] use tokio::net::UnixStream; +use tokio::net::{TcpListener, TcpStream, UnixListener}; -use super::target::ResolvedTarget; +use super::target::{LocalAddress, ResolvedTarget}; pub(crate) struct Resolver { #[cfg(feature = "hickory")] @@ -51,7 +51,8 @@ impl Resolver { } impl ResolvedTarget { - /// Connects to the socket address and returns a TokioStream + #[cfg(feature = "client")] + /// Connects to the socket address and returns a [`TokioStream`]. pub async fn connect(&self) -> std::io::Result { match self { ResolvedTarget::SocketAddr(addr) => { @@ -66,6 +67,76 @@ impl ResolvedTarget { } } } + + #[cfg(feature = "server")] + pub async fn listen( + &self, + ) -> std::io::Result< + impl futures::Stream> + LocalAddress, + > { + self.listen_raw().await + } + + /// Listens for incoming connections on the socket address and returns a + /// [`futures::Stream`] of [`TokioStream`]s and the incoming address. + #[cfg(feature = "server")] + pub(crate) async fn listen_raw(&self) -> std::io::Result { + match self { + ResolvedTarget::SocketAddr(addr) => { + let listener = TcpListener::bind(addr).await?; + Ok(TokioListenerStream::Tcp(listener)) + } + #[cfg(unix)] + ResolvedTarget::UnixSocketAddr(path) => { + let listener = std::os::unix::net::UnixListener::bind_addr(path)?; + listener.set_nonblocking(true)?; + let listener = tokio::net::UnixListener::from_std(listener)?; + Ok(TokioListenerStream::Unix(listener)) + } + } + } +} + +pub(crate) enum TokioListenerStream { + Tcp(TcpListener), + #[cfg(unix)] + Unix(UnixListener), +} + +impl LocalAddress for TokioListenerStream { + fn local_address(&self) -> std::io::Result { + match self { + TokioListenerStream::Tcp(listener) => { + listener.local_addr().map(ResolvedTarget::SocketAddr) + } + #[cfg(unix)] + TokioListenerStream::Unix(listener) => listener + .local_addr() + .map(|addr| ResolvedTarget::UnixSocketAddr(addr.into())), + } + } +} + +impl futures::Stream for TokioListenerStream { + type Item = std::io::Result<(TokioStream, ResolvedTarget)>; + + fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + match self.get_mut() { + TokioListenerStream::Tcp(listener) => { + let (stream, addr) = ready!(listener.poll_accept(cx))?; + let stream = TokioStream::Tcp(stream); + let target = ResolvedTarget::SocketAddr(addr); + Poll::Ready(Some(Ok((stream, target)))) + } + #[cfg(unix)] + TokioListenerStream::Unix(listener) => { + let (stream, addr) = ready!(listener.poll_accept(cx))?; + let stream = TokioStream::Unix(stream); + let target = ResolvedTarget::UnixSocketAddr(addr.into()); + Poll::Ready(Some(Ok((stream, target)))) + } + } + } } /// Represents a connected Tokio stream, either TCP or Unix diff --git a/rust/gel-stream/src/lib.rs b/rust/gel-stream/src/lib.rs index b9babe5bc1d..a8feb5678b8 100644 --- a/rust/gel-stream/src/lib.rs +++ b/rust/gel-stream/src/lib.rs @@ -1 +1,127 @@ -pub mod client; +// We don't want to warn about unused code when 1) either client or server is not +// enabled, or 2) no crypto backend is enabled. +#![cfg_attr( + not(all( + all(feature = "client", feature = "server"), + any(feature = "rustls", feature = "openssl") + )), + allow(unused) +)] + +#[cfg(feature = "client")] +mod client; +#[cfg(feature = "server")] +mod server; + +#[cfg(feature = "client")] +pub use client::Connector; + +#[cfg(feature = "server")] +pub use server::Acceptor; + +mod common; +#[cfg(feature = "openssl")] +pub use common::openssl::OpensslDriver; +#[cfg(feature = "rustls")] +pub use common::rustls::RustlsDriver; +pub use common::{stream::*, target::*, tls::*, BaseStream}; + +#[derive(Debug, thiserror::Error)] +pub enum ConnectionError { + /// I/O error encountered during connection operations. + #[error("I/O error: {0}")] + Io(#[from] std::io::Error), + + /// UTF-8 decoding error. + #[error("UTF8 error: {0}")] + Utf8Error(#[from] std::str::Utf8Error), + + /// SSL-related error. + #[error("SSL error: {0}")] + SslError(#[from] SslError), +} + +#[derive(Debug, thiserror::Error)] +pub enum SslError { + #[error("SSL is not supported by this client transport")] + SslUnsupportedByClient, + #[error("SSL is already upgraded or is in the process of upgrading")] + SslAlreadyUpgraded, + + #[cfg(feature = "openssl")] + #[error("OpenSSL error: {0}")] + OpenSslError(#[from] ::openssl::ssl::Error), + #[cfg(feature = "openssl")] + #[error("OpenSSL error: {0}")] + OpenSslErrorStack(#[from] ::openssl::error::ErrorStack), + #[cfg(feature = "openssl")] + #[error("OpenSSL certificate verification error: {0}")] + OpenSslErrorVerify(#[from] ::openssl::x509::X509VerifyResult), + + #[cfg(feature = "rustls")] + #[error("Rustls error: {0}")] + RustlsError(#[from] ::rustls::Error), + + #[cfg(feature = "rustls")] + #[error("Webpki error: {0}")] + WebpkiError(::webpki::Error), + + #[cfg(feature = "rustls")] + #[error("Verifier builder error: {0}")] + VerifierBuilderError(#[from] ::rustls::server::VerifierBuilderError), + + #[error("Invalid DNS name: {0}")] + InvalidDnsNameError(#[from] ::rustls_pki_types::InvalidDnsNameError), + + #[error("SSL I/O error: {0}")] + SslIoError(#[from] std::io::Error), +} + +impl SslError { + /// Returns a common error for any time of crypto backend. + pub fn common_error(&self) -> Option { + match self { + #[cfg(feature = "rustls")] + SslError::RustlsError(::rustls::Error::InvalidCertificate(cert_err)) => { + match cert_err { + ::rustls::CertificateError::NotValidForName => { + Some(CommonError::InvalidCertificateForName) + } + ::rustls::CertificateError::Revoked => Some(CommonError::CertificateRevoked), + ::rustls::CertificateError::Expired => Some(CommonError::CertificateExpired), + ::rustls::CertificateError::UnknownIssuer => Some(CommonError::InvalidIssuer), + _ => None, + } + } + #[cfg(feature = "openssl")] + SslError::OpenSslErrorVerify(e) => match e.as_raw() { + openssl_sys::X509_V_ERR_HOSTNAME_MISMATCH => { + Some(CommonError::InvalidCertificateForName) + } + openssl_sys::X509_V_ERR_IP_ADDRESS_MISMATCH => { + Some(CommonError::InvalidCertificateForName) + } + openssl_sys::X509_V_ERR_CERT_REVOKED => Some(CommonError::CertificateRevoked), + openssl_sys::X509_V_ERR_CERT_HAS_EXPIRED => Some(CommonError::CertificateExpired), + openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT + | openssl_sys::X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY => { + Some(CommonError::InvalidIssuer) + } + _ => None, + }, + _ => None, + } + } +} + +#[derive(Debug, thiserror::Error, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] +pub enum CommonError { + #[error("The certificate's subject name(s) do not match the name of the host")] + InvalidCertificateForName, + #[error("The certificate has been revoked")] + CertificateRevoked, + #[error("The certificate has expired")] + CertificateExpired, + #[error("The certificate was issued by an untrusted authority")] + InvalidIssuer, +} diff --git a/rust/gel-stream/src/server/acceptor.rs b/rust/gel-stream/src/server/acceptor.rs new file mode 100644 index 00000000000..df9c9307653 --- /dev/null +++ b/rust/gel-stream/src/server/acceptor.rs @@ -0,0 +1,178 @@ +use crate::{ + common::tokio_stream::TokioListenerStream, ConnectionError, LocalAddress, ResolvedTarget, + RewindStream, Ssl, SslError, StreamUpgrade, TlsDriver, TlsServerParameterProvider, + UpgradableStream, +}; +use futures::{FutureExt, StreamExt}; +use std::{ + future::Future, + pin::Pin, + task::{ready, Poll}, +}; +use std::{net::SocketAddr, path::Path}; + +use super::Connection; + +pub struct Acceptor { + resolved_target: ResolvedTarget, + tls_provider: Option, + should_upgrade: bool, +} + +impl Acceptor { + pub fn new_tcp(addr: SocketAddr) -> Self { + Self { + resolved_target: ResolvedTarget::SocketAddr(addr), + tls_provider: None, + should_upgrade: false, + } + } + + pub fn new_tcp_tls(addr: SocketAddr, provider: TlsServerParameterProvider) -> Self { + Self { + resolved_target: ResolvedTarget::SocketAddr(addr), + tls_provider: Some(provider), + should_upgrade: true, + } + } + + pub fn new_tcp_starttls(addr: SocketAddr, provider: TlsServerParameterProvider) -> Self { + Self { + resolved_target: ResolvedTarget::SocketAddr(addr), + tls_provider: Some(provider), + should_upgrade: false, + } + } + + #[cfg(unix)] + pub fn new_unix_path(path: impl AsRef) -> Result { + Ok(Self { + resolved_target: ResolvedTarget::from(std::os::unix::net::SocketAddr::from_pathname( + path, + )?), + tls_provider: None, + should_upgrade: false, + }) + } + + #[cfg(any(target_os = "linux", target_os = "android"))] + pub fn new_unix_domain(domain: impl AsRef<[u8]>) -> Result { + use std::os::linux::net::SocketAddrExt; + Ok(Self { + resolved_target: ResolvedTarget::from( + std::os::unix::net::SocketAddr::from_abstract_name(domain)?, + ), + tls_provider: None, + should_upgrade: false, + }) + } + + pub async fn bind( + self, + ) -> Result< + impl ::futures::Stream> + LocalAddress, + ConnectionError, + > { + let stream = self.resolved_target.listen_raw().await?; + Ok(AcceptedStream { + stream, + should_upgrade: self.should_upgrade, + upgrade_future: None, + tls_provider: self.tls_provider, + _phantom: None, + }) + } + + #[allow(private_bounds)] + pub async fn bind_explicit( + self, + ) -> Result< + impl ::futures::Stream, ConnectionError>> + LocalAddress, + ConnectionError, + > { + let stream = self.resolved_target.listen_raw().await?; + Ok(AcceptedStream { + stream, + should_upgrade: self.should_upgrade, + upgrade_future: None, + tls_provider: self.tls_provider, + _phantom: None, + }) + } + + pub async fn accept_one(self) -> Result { + let mut stream = self.resolved_target.listen().await?; + let (stream, _target) = stream.next().await.unwrap()?; + Ok(UpgradableStream::new_server( + RewindStream::new(stream), + None::, + )) + } +} + +struct AcceptedStream { + stream: TokioListenerStream, + should_upgrade: bool, + tls_provider: Option, + #[allow(clippy::type_complexity)] + upgrade_future: + Option, SslError>> + Send + 'static>>>, + // Avoid using PhantomData because it fails to implement certain auto-traits + _phantom: Option<&'static D>, +} + +impl LocalAddress for AcceptedStream { + fn local_address(&self) -> std::io::Result { + self.stream.local_address() + } +} + +impl futures::Stream for AcceptedStream { + type Item = Result, ConnectionError>; + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + if let Some(mut upgrade_future) = self.upgrade_future.take() { + match upgrade_future.poll_unpin(cx) { + Poll::Ready(Ok(conn)) => { + return Poll::Ready(Some(Ok(conn))); + } + Poll::Ready(Err(e)) => { + return Poll::Ready(Some(Err(e.into()))); + } + Poll::Pending => { + self.upgrade_future = Some(upgrade_future); + return Poll::Pending; + } + } + } + let r = ready!(self.stream.poll_next_unpin(cx)); + let Some(r) = r else { + return Poll::Ready(None); + }; + let (stream, _target) = r?; + let mut stream = + UpgradableStream::new_server(RewindStream::new(stream), self.tls_provider.clone()); + if self.should_upgrade { + let mut upgrade_future = Box::pin(async move { + stream.secure_upgrade().await?; + Ok::<_, SslError>(stream) + }); + match upgrade_future.poll_unpin(cx) { + Poll::Ready(Ok(stream)) => { + return Poll::Ready(Some(Ok(stream))); + } + Poll::Ready(Err(e)) => { + return Poll::Ready(Some(Err(e.into()))); + } + Poll::Pending => { + self.upgrade_future = Some(upgrade_future); + return Poll::Pending; + } + } + } + Poll::Ready(Some(Ok(stream))) + } +} diff --git a/rust/gel-stream/src/server/mod.rs b/rust/gel-stream/src/server/mod.rs new file mode 100644 index 00000000000..81d15f68943 --- /dev/null +++ b/rust/gel-stream/src/server/mod.rs @@ -0,0 +1,6 @@ +use crate::{RewindStream, Ssl, UpgradableStream}; + +mod acceptor; +pub use acceptor::Acceptor; + +type Connection = UpgradableStream, D>; diff --git a/rust/gel-stream/tests/socket.rs b/rust/gel-stream/tests/socket.rs new file mode 100644 index 00000000000..47f92e3de5d --- /dev/null +++ b/rust/gel-stream/tests/socket.rs @@ -0,0 +1,66 @@ +use futures::StreamExt; +use gel_stream::*; +use std::net::Ipv4Addr; +use std::net::SocketAddr; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; + +#[cfg(unix)] +#[tokio::test] +#[ntest::timeout(30_000)] +async fn test_target_unix() -> Result<(), ConnectionError> { + let tempdir = tempfile::tempdir().unwrap(); + let path = tempdir.path().join("gel-stream-test"); + + // Create a unix socket and connect to it + let mut acceptor = Acceptor::new_unix_path(&path)?.bind().await?; + let addr = acceptor.local_address(); + eprintln!("addr: {:?}", addr); + + let accept_task = tokio::spawn(async move { + let mut connection = acceptor.next().await.unwrap().unwrap(); + let mut buf = String::new(); + connection.read_to_string(&mut buf).await.unwrap(); + assert_eq!(buf, "Hello, world!"); + }); + + let connect_task = tokio::spawn(async { + let target = Target::new_unix_path(path)?; + let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) +} + +#[tokio::test] +#[ntest::timeout(30_000)] +async fn test_target_tcp() -> Result<(), ConnectionError> { + // Create a TCP listener on a random port + let mut acceptor = Acceptor::new_tcp(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0)) + .bind() + .await?; + let addr = acceptor.local_address()?; + + let accept_task = tokio::spawn(async move { + let mut connection = acceptor.next().await.unwrap().unwrap(); + let mut buf = String::new(); + connection.read_to_string(&mut buf).await.unwrap(); + assert_eq!(buf, "Hello, world!"); + }); + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved(addr); + let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) +} diff --git a/rust/gel-stream/tests/tls.rs b/rust/gel-stream/tests/tls.rs new file mode 100644 index 00000000000..b71b2a15386 --- /dev/null +++ b/rust/gel-stream/tests/tls.rs @@ -0,0 +1,451 @@ +use futures::StreamExt; +use gel_stream::*; +use std::borrow::Cow; +use std::net::Ipv4Addr; +use std::net::SocketAddr; +use tokio::io::{AsyncReadExt, AsyncWriteExt}; + +fn load_client_test_cert() -> rustls_pki_types::CertificateDer<'static> { + rustls_pemfile::certs(&mut include_str!("../../../tests/certs/client.cert.pem").as_bytes()) + .next() + .expect("no cert") + .expect("cert is bad") +} + +fn load_client_test_key() -> rustls_pki_types::PrivateKeyDer<'static> { + rustls_pemfile::private_key(&mut include_str!("../../../tests/certs/client.key.pem").as_bytes()) + .expect("no client key") + .expect("client key is bad") +} + +fn load_client_test_ca() -> rustls_pki_types::CertificateDer<'static> { + rustls_pemfile::certs(&mut include_str!("../../../tests/certs/client_ca.cert.pem").as_bytes()) + .next() + .expect("no ca cert") + .expect("ca cert is bad") +} + +fn load_test_cert() -> rustls_pki_types::CertificateDer<'static> { + rustls_pemfile::certs(&mut include_str!("../../../tests/certs/server.cert.pem").as_bytes()) + .next() + .expect("no cert") + .expect("cert is bad") +} + +fn load_test_ca() -> rustls_pki_types::CertificateDer<'static> { + rustls_pemfile::certs(&mut include_str!("../../../tests/certs/ca.cert.pem").as_bytes()) + .next() + .expect("no ca cert") + .expect("ca cert is bad") +} + +fn load_test_key() -> rustls_pki_types::PrivateKeyDer<'static> { + rustls_pemfile::private_key(&mut include_str!("../../../tests/certs/server.key.pem").as_bytes()) + .expect("no server key") + .expect("server key is bad") +} + +fn load_test_crls() -> Vec> { + rustls_pemfile::crls(&mut include_str!("../../../tests/certs/ca.crl.pem").as_bytes()) + .collect::, _>>() + .unwrap() +} + +fn tls_server_parameters( + alpn: TlsAlpn, + client_cert_verify: TlsClientCertVerify, +) -> TlsServerParameterProvider { + TlsServerParameterProvider::new(TlsServerParameters { + server_certificate: TlsKey::new(load_test_key(), load_test_cert()), + client_cert_verify, + min_protocol_version: None, + max_protocol_version: None, + alpn, + }) +} + +async fn spawn_tls_server( + expected_hostname: Option<&str>, + server_alpn: TlsAlpn, + expected_alpn: Option<&str>, + client_cert_verify: TlsClientCertVerify, +) -> Result< + ( + ResolvedTarget, + tokio::task::JoinHandle>, + ), + ConnectionError, +> { + let mut acceptor = Acceptor::new_tcp_tls( + SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0), + tls_server_parameters(server_alpn, client_cert_verify), + ) + .bind_explicit::() + .await?; + let addr = acceptor.local_address()?; + + let expected_alpn = expected_alpn.map(|alpn| alpn.as_bytes().to_vec()); + let expected_hostname = expected_hostname.map(|sni| sni.to_string()); + let accept_task = tokio::spawn(async move { + let mut connection = acceptor.next().await.unwrap()?; + let handshake = connection + .handshake() + .unwrap_or_else(|| panic!("handshake was not available on {connection:?}")); + assert_eq!( + handshake.alpn.as_ref().map(|b| b.as_ref().to_vec()), + expected_alpn + ); + assert_eq!(handshake.sni.as_deref(), expected_hostname.as_deref()); + let mut buf = String::new(); + connection.read_to_string(&mut buf).await.unwrap(); + assert_eq!(buf, "Hello, world!"); + connection.shutdown().await?; + Ok::<_, ConnectionError>(()) + }); + Ok((addr, accept_task)) +} + +macro_rules! tls_test ( + ( + $( + $(#[ $attr:meta ])* + async fn $name:ident() -> Result<(), ConnectionError> $body:block + )* + ) => { + mod rustls { + use super::*; + $( + $(#[ $attr ])* + async fn $name() -> Result<(), ConnectionError> { + async fn test_inner() -> Result<(), ConnectionError> { + $body + } + test_inner::().await + } + )* + } + + mod rustls_server { + use super::*; + $( + $(#[ $attr ])* + async fn $name() -> Result<(), ConnectionError> { + async fn test_inner() -> Result<(), ConnectionError> { + $body + } + test_inner::().await + } + )* + } + + mod openssl { + use super::*; + + $( + $(#[ $attr ])* + async fn $name() -> Result<(), ConnectionError> { + async fn test_inner() -> Result<(), ConnectionError> { + $body + } + test_inner::().await + } + )* + } + + mod openssl_server { + use super::*; + $( + $(#[ $attr ])* + async fn $name() -> Result<(), ConnectionError> { + async fn test_inner() -> Result<(), ConnectionError> { + $body + } + test_inner::().await + } + )* + } + + } +); + +tls_test! { + /// The certificate is not valid for 127.0.0.1, so the connection should fail. + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_verify_full_fails() -> Result<(), ConnectionError> { + let (addr, accept_task) = + spawn_tls_server::(None, TlsAlpn::default(), None, TlsClientCertVerify::Ignore).await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, // Raw IP + TlsParameters { + ..Default::default() + }, + ); + let stm = Connector::::new_explicit(target).unwrap().connect().await; + assert!( + matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::InvalidIssuer)), + "{stm:?}" + ); + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap_err(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + /// The certificate is not valid for 127.0.0.1, so the connection should fail. + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_verify_full_fails_name() -> Result<(), ConnectionError> { + let (addr, accept_task) = + spawn_tls_server::(None, TlsAlpn::default(), None, TlsClientCertVerify::Ignore).await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, // Raw IP + TlsParameters { + root_cert: TlsCert::Custom(load_test_ca()), + ..Default::default() + }, + ); + let stm = Connector::::new_explicit(target).unwrap().connect().await; + assert!( + matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::InvalidCertificateForName)), + "{stm:?}" + ); + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap_err(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + /// The certificate is valid for "localhost", so the connection should succeed. + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_verify_full_ok() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + Some("localhost"), + TlsAlpn::default(), + None, + TlsClientCertVerify::Ignore, + ) + .await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_tcp_tls( + ("localhost", addr.tcp().unwrap().port()), + TlsParameters { + root_cert: TlsCert::Custom(load_test_ca()), + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await?; + stm.write_all(b"Hello, world!").await?; + stm.shutdown().await?; + Ok::<_, ConnectionError>(()) + }); + + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_insecure() -> Result<(), ConnectionError> { + let (addr, accept_task) = + spawn_tls_server::(None, TlsAlpn::default(), None, TlsClientCertVerify::Ignore).await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, // Raw IP + TlsParameters { + server_cert_verify: TlsServerCertVerify::Insecure, + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await?; + stm.shutdown().await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_crl() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + Some("localhost"), + TlsAlpn::default(), + None, + TlsClientCertVerify::Ignore, + ) + .await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_tcp_tls( + ("localhost", addr.tcp().unwrap().port()), + TlsParameters { + root_cert: TlsCert::Custom(load_test_ca()), + crl: load_test_crls(), + ..Default::default() + }, + ); + let stm = Connector::::new_explicit(target).unwrap().connect().await; + assert!( + matches!(&stm, Err(ConnectionError::SslError(ssl)) if ssl.common_error() == Some(CommonError::CertificateRevoked)), + "{stm:?}" + ); + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap_err(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + /// Test that we can override the SNI. + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_sni_override() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + Some("www.google.com"), + TlsAlpn::default(), + None, + TlsClientCertVerify::Ignore, + ) + .await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, + TlsParameters { + server_cert_verify: TlsServerCertVerify::Insecure, + sni_override: Some(Cow::Borrowed("www.google.com")), + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await.unwrap(); + stm.shutdown().await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + /// Test that we can set the ALPN. + #[tokio::test] + async fn test_target_tcp_tls_alpn() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + None, + TlsAlpn::new_str(&["nope", "accepted"]), + Some("accepted"), + TlsClientCertVerify::Ignore, + ) + .await?; + + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, + TlsParameters { + server_cert_verify: TlsServerCertVerify::Insecure, + alpn: TlsAlpn::new_str(&["accepted", "fake"]), + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await.unwrap(); + stm.shutdown().await?; + Ok::<_, std::io::Error>(()) + }); + + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + + Ok(()) + } + + #[tokio::test] + #[ntest::timeout(30_000)] + async fn test_target_tcp_tls_client_verify_optional() -> Result<(), ConnectionError> { + let (addr, accept_task) = spawn_tls_server::( + None, + TlsAlpn::default(), + None, + TlsClientCertVerify::Optional(vec![load_client_test_ca()]), + ) + .await?; + let connect_task = tokio::spawn(async move { + let target = Target::new_resolved_tls( + addr, + TlsParameters { + server_cert_verify: TlsServerCertVerify::Insecure, + cert: Some(load_client_test_cert()), + key: Some(load_client_test_key()), + ..Default::default() + }, + ); + let mut stm = Connector::::new_explicit(target).unwrap().connect().await.unwrap(); + stm.write_all(b"Hello, world!").await.unwrap(); + stm.shutdown().await?; + Ok::<_, std::io::Error>(()) + }); + accept_task.await.unwrap().unwrap(); + connect_task.await.unwrap().unwrap(); + Ok(()) + } +} + +#[cfg(feature = "__manual_tests")] +#[tokio::test] +async fn test_live_server_manual_google_com() { + let target = Target::new_tcp_tls(("www.google.com", 443), TlsParameters::default()); + let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); + stm.write_all(b"GET / HTTP/1.0\r\n\r\n").await.unwrap(); + // HTTP/1. ..... + assert_eq!(stm.read_u8().await.unwrap(), b'H'); +} + +/// Normally connecting to Google's IP will send an invalid SNI and fail. +/// This test ensures that we can override the SNI to the correct hostname. +#[cfg(feature = "__manual_tests")] +#[tokio::test] +async fn test_live_server_google_com_override_sni() { + use std::net::ToSocketAddrs; + + let addr = "www.google.com:443" + .to_socket_addrs() + .unwrap() + .into_iter() + .next() + .unwrap(); + let target = Target::new_tcp_tls( + addr, + TlsParameters { + sni_override: Some(Cow::Borrowed("www.google.com")), + ..Default::default() + }, + ); + let mut stm = Connector::new(target).unwrap().connect().await.unwrap(); + stm.write_all(b"GET / HTTP/1.0\r\n\r\n").await.unwrap(); + // HTTP/1. ..... + assert_eq!(stm.read_u8().await.unwrap(), b'H'); +} diff --git a/rust/pgrust/Cargo.toml b/rust/pgrust/Cargo.toml index e23839d874e..e65b8413e27 100644 --- a/rust/pgrust/Cargo.toml +++ b/rust/pgrust/Cargo.toml @@ -18,7 +18,7 @@ pyo3.workspace = true tokio.workspace = true tracing.workspace = true db_proto.workspace = true -gel-stream.workspace = true +gel-stream = { workspace = true, features = ["client"] } futures = "0" thiserror = "1" @@ -41,6 +41,7 @@ features = ["full"] [dev-dependencies] tracing-subscriber.workspace = true captive_postgres.workspace = true +gel-stream = { workspace = true, features = ["rustls"] } scopeguard = "1" pretty_assertions = "1.2.0" diff --git a/rust/pgrust/examples/connect.rs b/rust/pgrust/examples/connect.rs index 1a6d05c6796..0b5e9fd881e 100644 --- a/rust/pgrust/examples/connect.rs +++ b/rust/pgrust/examples/connect.rs @@ -4,7 +4,7 @@ use captive_postgres::{ use clap::Parser; use clap_derive::Parser; use gel_auth::AuthType; -use gel_stream::client::{Connector, ResolvedTarget, Target}; +use gel_stream::{Connector, ResolvedTarget, Target}; use pgrust::{ connection::{ dsn::parse_postgres_dsn_env, Client, Credentials, ExecuteSink, Format, MaxRows, diff --git a/rust/pgrust/src/connection/conn.rs b/rust/pgrust/src/connection/conn.rs index 58c6443d175..0715d439642 100644 --- a/rust/pgrust/src/connection/conn.rs +++ b/rust/pgrust/src/connection/conn.rs @@ -14,7 +14,7 @@ use crate::{ }; use db_proto::StructBuffer; use futures::{future::Either, FutureExt}; -use gel_stream::client::{stream::Stream, Connector}; +use gel_stream::{Connector, Stream}; use std::{ cell::RefCell, future::ready, @@ -52,7 +52,7 @@ pub enum PGConnError { /// /// ``` /// # use pgrust::connection::*; -/// # use gel_stream::client::{Target, Connector}; +/// # use gel_stream::{Target, Connector}; /// # _ = async { /// # let credentials = Credentials::default(); /// # let connector = Connector::new(Target::new_tcp(("localhost", 1234))).unwrap(); diff --git a/rust/pgrust/src/connection/dsn/host.rs b/rust/pgrust/src/connection/dsn/host.rs index e08b28b8510..d290b4bfefe 100644 --- a/rust/pgrust/src/connection/dsn/host.rs +++ b/rust/pgrust/src/connection/dsn/host.rs @@ -1,5 +1,5 @@ use super::ParseError; -use gel_stream::client::{ResolvedTarget, TargetName}; +use gel_stream::{ResolvedTarget, TargetName}; use serde_derive::Serialize; use std::net::{IpAddr, Ipv6Addr}; diff --git a/rust/pgrust/src/connection/mod.rs b/rust/pgrust/src/connection/mod.rs index 8ceb3085dc8..28b4f366f91 100644 --- a/rust/pgrust/src/connection/mod.rs +++ b/rust/pgrust/src/connection/mod.rs @@ -13,7 +13,7 @@ pub use flow::{ CopyDataSink, DataSink, DoneHandling, ExecuteSink, FlowAccumulator, Format, MaxRows, Oid, Param, Pipeline, PipelineBuilder, Portal, QuerySink, Statement, }; -use gel_stream::client::ConnectionError; +use gel_stream::ConnectionError; pub use raw_conn::RawClient; macro_rules! __invalid_state { @@ -89,7 +89,6 @@ pub enum SslError { #[derive(Clone, Default, derive_more::Debug)] pub struct Credentials { pub username: String, - #[debug(skip)] pub password: String, pub database: String, pub server_settings: HashMap, diff --git a/rust/pgrust/src/connection/raw_conn.rs b/rust/pgrust/src/connection/raw_conn.rs index fece126c2b3..688f0dde67a 100644 --- a/rust/pgrust/src/connection/raw_conn.rs +++ b/rust/pgrust/src/connection/raw_conn.rs @@ -10,10 +10,7 @@ use crate::protocol::postgres::{FrontendBuilder, InitialBuilder}; use crate::protocol::{postgres::data::SSLResponse, postgres::meta}; use db_proto::StructBuffer; use gel_auth::AuthType; -use gel_stream::client::{ - stream::{Stream, StreamWithUpgrade, UpgradableStream}, - Connector, -}; +use gel_stream::{ConnectionError, Connector, Stream, StreamUpgrade}; use std::collections::HashMap; use std::pin::Pin; use tokio::io::AsyncWriteExt; @@ -74,16 +71,13 @@ impl ConnectionDriver { } } - async fn drive_bytes( + async fn drive_bytes( &mut self, state: &mut ConnectionState, drive: &[u8], message_buffer: &mut StructBuffer, - stream: &mut UpgradableStream, - ) -> Result<(), PGConnectionError> - where - (B, C): StreamWithUpgrade, - { + stream: &mut S, + ) -> Result<(), PGConnectionError> { message_buffer.push_fallible(drive, |msg| { state.drive(ConnectionDrive::Message(msg), self) })?; @@ -100,7 +94,10 @@ impl ConnectionDriver { } if self.upgrade { self.upgrade = false; - stream.secure_upgrade().await?; + stream + .secure_upgrade() + .await + .map_err(ConnectionError::from)?; state.drive(ConnectionDrive::SslReady, self)?; } else { break; @@ -109,15 +106,12 @@ impl ConnectionDriver { Ok(()) } - async fn drive( + async fn drive( &mut self, state: &mut ConnectionState, drive: ConnectionDrive<'_>, - stream: &mut UpgradableStream, - ) -> Result<(), PGConnectionError> - where - (B, C): StreamWithUpgrade, - { + stream: &mut S, + ) -> Result<(), PGConnectionError> { state.drive(drive, self)?; loop { if !self.send_buffer.is_empty() { @@ -132,7 +126,10 @@ impl ConnectionDriver { } if self.upgrade { self.upgrade = false; - stream.secure_upgrade().await?; + stream + .secure_upgrade() + .await + .map_err(ConnectionError::from)?; state.drive(ConnectionDrive::SslReady, self)?; } else { break; @@ -221,11 +218,11 @@ impl RawClient { } // This should not be possible -- we've fully upgraded the stream by now - let Ok(stream) = stream.into_choice() else { + let Ok(stream) = stream.into_boxed() else { return Err(invalid_state!("Connection was not ready")); }; - Ok(RawClient::new_boxed(stream.into_boxed(), update.params)) + Ok(RawClient::new_boxed(stream, update.params)) } /// Consume the `RawClient` and return the underlying stream and connection parameters. diff --git a/rust/pgrust/src/handshake/edgedb_server.rs b/rust/pgrust/src/handshake/edgedb_server.rs index 6aa2106f8b2..00a4a54fbbe 100644 --- a/rust/pgrust/src/handshake/edgedb_server.rs +++ b/rust/pgrust/src/handshake/edgedb_server.rs @@ -140,8 +140,10 @@ enum ServerStateImpl { Error, } +#[derive(derive_more::Debug, Default)] pub struct ServerState { state: ServerStateImpl, + #[debug(skip)] buffer: StructBuffer, } diff --git a/rust/pgrust/src/handshake/mod.rs b/rust/pgrust/src/handshake/mod.rs index a253e3bbde6..bc3689b5c20 100644 --- a/rust/pgrust/src/handshake/mod.rs +++ b/rust/pgrust/src/handshake/mod.rs @@ -139,7 +139,7 @@ mod tests { username: "user".to_string(), password: "password".to_string(), database: "database".to_string(), - ..Default::default() + server_settings: Default::default(), }, ConnectionSslRequirement::Disable, ); diff --git a/rust/pgrust/src/python.rs b/rust/pgrust/src/python.rs index 0e14393cf78..a31c515fbd4 100644 --- a/rust/pgrust/src/python.rs +++ b/rust/pgrust/src/python.rs @@ -14,7 +14,7 @@ use crate::{ protocol::postgres::{data::SSLResponse, meta, FrontendBuilder, InitialBuilder}, }; use db_proto::StructBuffer; -use gel_stream::client::ResolvedTarget; +use gel_stream::ResolvedTarget; use pyo3::{ buffer::PyBuffer, exceptions::{PyException, PyRuntimeError}, diff --git a/rust/pgrust/tests/query_real_postgres.rs b/rust/pgrust/tests/query_real_postgres.rs index 4f2ba64b39f..22fc622e198 100644 --- a/rust/pgrust/tests/query_real_postgres.rs +++ b/rust/pgrust/tests/query_real_postgres.rs @@ -6,7 +6,7 @@ use std::rc::Rc; // Constants use db_proto::match_message; use gel_auth::AuthType; -use gel_stream::client::{Connector, ResolvedTarget, Target}; +use gel_stream::{Connector, ResolvedTarget, Target}; use pgrust::connection::{ Client, Credentials, FlowAccumulator, MaxRows, Oid, Param, PipelineBuilder, Portal, Statement, }; diff --git a/rust/pgrust/tests/real_postgres.rs b/rust/pgrust/tests/real_postgres.rs index d0cb92fcf8a..301d97ec390 100644 --- a/rust/pgrust/tests/real_postgres.rs +++ b/rust/pgrust/tests/real_postgres.rs @@ -1,6 +1,6 @@ // Constants use gel_auth::AuthType; -use gel_stream::client::{Connector, ResolvedTarget, Target, TlsParameters}; +use gel_stream::{Connector, ResolvedTarget, Target, TlsParameters}; use pgrust::connection::{Credentials, PGConnectionError, RawClient}; use pgrust::errors::PgServerError; use pgrust::handshake::ConnectionSslRequirement; diff --git a/tests/certs/ca.cert.pem b/tests/certs/ca.cert.pem index 63e21bcf524..95b20225e32 100644 --- a/tests/certs/ca.cert.pem +++ b/tests/certs/ca.cert.pem @@ -1,40 +1,40 @@ -----BEGIN CERTIFICATE----- -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 -wuuleg3Qo92tkeoX9SqR +CQEWEGhlbGxvQGVkZ2VkYi5jb22CFERoZl6t5a0Aw+udK3fmakODwWozMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAEFPR/3ga+tJenOAlNwykYma +4rz1ryxizrww2TgFKmA7VdPK+NqyoTuK+OhikJ0r2GCk6jEQvru4e7pBxsUoBpTP +d6wv/xNkMnDgS/J9VGziQF3ZarbayyQdLlt+J/kmvxiF9/RUyB0x3f3hfx/yqrRD +b07/0qRgW0pIk/D5Hs+D3FnPpr3i0pg1iauLwnWptagobFEM27eHAuqOmmc8EMUP +hHmwhEI7vQ1NZ7X/+gdVx/CyIiDYBw88/x4aEH/6rVPZU3Ifg5GINGyMyndJ+WtV +21CSFz8SqG+K2pU3k9wjorJcSZr2ChLEi9gyHH4Rk9ADHYxiKg+qb11Mysyx4Qoo +pyfGeJq1qhb2ScJrdTuj2NctQhUVTQoeIWh36zdf6sxRLXcj8M6gQz5joed1/7Y7 +YgOXq3gmI4e9you/F4Vqhdl3ojhstkpW8fWQiXYvWIvOctgjGtZoLP4gZujgGs4h ++fdX5pMmOoSPrriUINo+0W55hhIFIDisUNkxC1PKkjdU4XjckFC9iJeT0VsKLPzK +HMN0LA7BxEjLnV0TG/vXaoaM+rlz11nMTwt7BNSWqhH+6lxwgOSG3Ft7u8svt7x/ +6b706AHItpYRegu+NWzVfrbntZsJSdGSYi8mZwvIjSrA8o/zFpWepINlWph14mxU +bmAtF79u44d/tAoBn/gH -----END CERTIFICATE----- diff --git a/tests/certs/ca.crl.pem b/tests/certs/ca.crl.pem index 5f3b1bac25f..8c956b333ab 100644 --- a/tests/certs/ca.crl.pem +++ b/tests/certs/ca.crl.pem @@ -3,22 +3,22 @@ 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 -----END X509 CRL----- diff --git a/tests/certs/ca.key.pem b/tests/certs/ca.key.pem index 718e4c4fdb4..f49f6fa219f 100644 --- a/tests/certs/ca.key.pem +++ b/tests/certs/ca.key.pem @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -9SXjVRx6nxQSlO4HYDaa2aw6W0+wdw== +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 +HEQwFKprD1VR7j6l2kChJIMHc5RJxQ== -----END PRIVATE KEY----- diff --git a/tests/certs/client.cert.pem b/tests/certs/client.cert.pem index 14510751712..ee18ce07ccf 100644 --- a/tests/certs/client.cert.pem +++ b/tests/certs/client.cert.pem @@ -1,33 +1,36 @@ -----BEGIN CERTIFICATE----- -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 +vR6+GZsfuWGM8iVlCZPSFrZCngjEZKg= -----END CERTIFICATE----- diff --git a/tests/certs/client.csr.pem b/tests/certs/client.csr.pem index ed38fc1246e..d0ccdd809d4 100644 --- a/tests/certs/client.csr.pem +++ b/tests/certs/client.csr.pem @@ -3,27 +3,27 @@ MIIE4TCCAskCAQAwgZsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlh MRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRQwEgYDVQQKDAtFZGdlREIgSW5jLjEV MBMGA1UECwwMRWRnZURCIHRlc3RzMREwDwYDVQQDDAhzc2xfdXNlcjEfMB0GCSqG SIb3DQEJARYQaGVsbG9AZWRnZWRiLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP -ADCCAgoCggIBAKI4Gq3AsHQ8sWyVk+bKgeYuoN0NdfXaALQNZiSZRYlzeiKadugm -3B5SVPU3ivIM+DzKxWIuZRq082xxflBGQIS3AARfjgUD4oSlq8kqnqZG8Gm6PgsA -pG64Dmr/jeU33U2KCtCHSS7ciCLMz3fBWsilaztdLFH0psDjFVGQTiWm0WDzgZNN -It7mXcvUoyb3/rFXgeE0mg35PqVhSlWyFrT4Vb7j1bK4T+yW4ulfx3TgzkGaRp4+ -NnoHWE1arDfT4XZxiav5t/S110W/UR1xMY0+wdCIu5Gl+JKUpazikEz+kJAC5OGJ -kW2nzMMYJ/MlnZWK84q+hM8QZshCHQdW5z87BFwe2382zOs5Zzj/w7XD2cI7pw+3 -Z3FAL79sx+quZZRJomaJTj/capBxK426oewcA4Ey2wmZa7zLVX8Xs0+vmWhm2/xC -/p+E5reLI/v0y2YIW0KmyBKU5X1Hew9b27jZgoao7dPIb36NNDIh9MhQ/pBU5PE1 -XGz679OnQJDZVNUNhZosZoBeuMTrp+g3n7Cuim0btsf3+SQBRlZftfBHJwTspc6H -GPmPKiLCOMSYzx+fZ1e4bw4X7wfkBf+C8uxt55mD1vtd5bvU41++97VtwkPt/9aA -ySd4cb7V6YJPA250+AvUUD5qkq54Si0+ZVJ4RdhBQdDma/skHuu+xS6tAgMBAAGg -ADANBgkqhkiG9w0BAQsFAAOCAgEAdXiLGvPIm4u2XF8OyCi/2wbwT3Hswg8Z7AG+ -F4z6L3B+mDZNVtk+NQr3eAr9Eg5HsjC81VxSwXQtwjnzinAgpoNqRr70qhKeCjXr -szVHdN40L5J2RA+PeB9qFsUBXymt7qr9Cqb6a3s4sHTy8wMaYOmmkNqfdak674Tl -C7+Z/E9saASlgDDrlLLvzvPgC/y5gIhNYK7LIHI8yOtgd96R5Gs9/hyJ9y05+B9i -rnwok1QBkpy2cGnYoX+4Hn2gRIu6wMWfv5mj/wfn/gGihe8Fi2/89u+XRSZaZivZ -9CQzoLu1bajof8lSDPjORrL/ceiz7nNtKlkBCGtsscGUvuFXSMg7ENIukzGhCFI9 -Yo2ZVNnEjzaaBngVSdufVWkUhS/AfxxWKUDq/tS1zzX76PlZ1Cc847x6s+8+28uu -f9IOxwxVMJqEwtvIpG0ECsBBr+tgYIBaaSyUIHRlagOfeZ23HgJjYxa9Zvuxs+gb -GVheIgz1oZRtYL/MUa9UwptQ666gzcBXLQf5oCKzp73WIPVdp99r3y8P0b2X63Xz -Dhtp5dMfSlitOM7a3/Ddqt/iiSsq2caV5hbSElQsorxypbDv+roL851TRzqfHYSA -dZIgI0aWgVfsXDtByf8R7lfZWgwISsIKAomsSXIFihERKkzxWG1swCIs8WcqLcAM -6wHuhd0= +ADCCAgoCggIBAMUzOWyNYcpd7fCMtrBXA2YI4Uop1A0xfZtAg1Gopcg46WziPtrV +RlVtqyCzUome87CIJ6ggqLblS6SnrpWnw6YsNv3Hc9Zt3OonF6SrMF/ygglxMzXF +6cuoSevQVyWlgQobWd9N0gHzQGj95iF7p3f4+CdCK7R6tThG6rPg/QUlTSOW+ZBO +BjJsbGUMIbNDXm2UBUDqEGqNX+A4WiG3TSlos7uBJnBmDLRRqsuC1MF4FRXnE/Xo +rKsc3CE3k9DVijHQXlkhmAux33I8GtSrQj8yUmDPRwuUMFNlT6lQRj55pObTIz3p +3XvJlG3GB8VMwlW5P/y5GnjDdHKNjWBKKhGvYKUtbtkP3KlRLlbOOTqclwO6oytI +e7voZqKH6bN14vCmlNkUd3kcQGkV2rswtlL/Dmx4c/ZemURHNI8tOMiXtky/aBFt +tAk8EEb4qLGRvY5RK1GA+M3oRuIdwSJOYEkq7D345HJ3xoznCC/JXdfCtULHB08b +36UtDeIdx7WeHM5/xqW3aLavxM3QpsRswfONXeqDeBmXF/JB5br7Ls3TQpPFsELh +BKLBeibuWGBPPVln8RnVZw6I17a9Y9WAXLAYJh1n+fwnMR0qxnmQlptoILeNriCR +syLOtSP+o+5v0S2kxfMys4s3sBMntQawgkFABHn0iymMPwm7p91O85t1AgMBAAGg +ADANBgkqhkiG9w0BAQsFAAOCAgEAXK7EjCpnqgDWCumXkE5fkymVgQ40gtj4OvMz +OVjW+HqNIU9+v12OqENxtPZJLxzU7hsGbUjNY6zuplFnaK86Z8GTMXbvLz2tXtN+ ++BIi6ZGzPrvFub5CLBpxzVBQdDCSDkR8t5D0LRl+N1ep+Ls3FyCOWRe5LF58tbCl +SLImwOFaOLRe3dALB8vvMKi/BP9zZUuxRgNIy4mdMUasr8ma9xkb19/FvOy9BMIJ +ei9g28+xgOJ14uI1zqrKIDpdLcgObYy1DpPatpzgs65JLnVxZH8H3r2DFd7m+XuI +mt0iZr7Cry7aYgdemOCf8jehq+dJkqvefQFUPbelbOZV7yLQS74CQXbLkhmTytP+ +zYqDIU6Gwo65rE59g53Aonqa+gOgGdu9cKfz54Sa4KqtsGZPtsASd4jgp8bcQ5sE +8Reg4fjWETyNVIDf2FHPEL4S3IbLRaRATcPzTvBYxP/CotqnoexXT2Vp6PSwYnVk +Lm1bd41oEhitlrzU7Zx/fOvJuL079Qy+2ixQiusEfRaYNICVHyaC7JieNk6P2G5Y +qyUx4beBOYm+Ux1R4kuyRGI7befJa1QyE0nxFQmJrHzOkrwJ722MMZSkhAyB5wKV +NKVMxMMSFpevo7wDRjlZve5V8R0l2lDc8TGrmRFDCSchvO0yLlnEg7TrdIRXAAuq +MDjdO8g= -----END CERTIFICATE REQUEST----- diff --git a/tests/certs/client.key.pem b/tests/certs/client.key.pem index aa63c1f5237..d6ad1d98b8f 100644 --- a/tests/certs/client.key.pem +++ b/tests/certs/client.key.pem @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -g1WA14/4g+NcaVuglAM0na4pouro +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 +TRkcU50kVlx/0XcGTR0F9Cp2fhO8NHo= -----END PRIVATE KEY----- diff --git a/tests/certs/client.key.protected.pem b/tests/certs/client.key.protected.pem index e2b882cc99b..4fffb1fd88a 100644 --- a/tests/certs/client.key.protected.pem +++ b/tests/certs/client.key.protected.pem @@ -1,54 +1,54 @@ -----BEGIN ENCRYPTED PRIVATE KEY----- -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 -----END ENCRYPTED PRIVATE KEY----- diff --git a/tests/certs/client_ca.cert.pem b/tests/certs/client_ca.cert.pem index becca16bea7..1278c0ec1b0 100644 --- a/tests/certs/client_ca.cert.pem +++ b/tests/certs/client_ca.cert.pem @@ -1,36 +1,36 @@ -----BEGIN CERTIFICATE----- -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 -z1r76p+mCg== +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAKybpkWhPpMncwyrbUmPWyjYh0v42XS+ ++Mr+G45OAzt6H+FCnOKLTaHV3dOAAztmYcc/XjBJ51Tv/bRqn8ou2xhCAX5eky2i +8xBq04dYLz1iatT2Gvla0JpxozNxKEQhGN/AaC6BsGomSf05sjgrTI/b5tEZxzv3 +iqdyewPq9bYPiEjU7r7lQBOGUfmItpUQq1NQXhBO6ezovFAZ52iPxfyIdatl9CWY +bZWc/VgEIc3ojjsfspeXvkbDawQlIkJgBFD+O5BPDltF5bZG0MLcSU1fnWpwFlf5 +Cqf+H7F7dk001zD90Uq1evBFmYbQMD2IIeDP05kK5aeWcRX9ibbEydUaRKh6L1Ag +JrfmBoneoMcjxbdiK43b8lsPnkEeuvCwu5VN0upHLGJW7Fy60assL0hCvSMbmKTJ +qIHQd+sINifXq2vAjVZdUJompHrnypJxIrxdl+sTSYP/veZwvxuLdTUXQceiofEc +aR/y7OcLOIgywQkbqkrO/Cx1fcoPopr++dAEWQ2VhoSPuoC9f54dxgeMXj1/Kmxy +u4z89Xz6HfWqNDYbAEwSaWFOOWewUVfnsJ7gcptE2Arn+NlllGQN10DKdwHKUiKG +YfBhd3tdMlMkkNtowUGHhny32eoEnQv3Xqrd4rqe8cE58bKacM+OhhPkfWA2UT9w +bYA2mUVcg+izAgMBAAGjUzBRMB0GA1UdDgQWBBQyJOoeR8Y5TkgQ9vmRjskM3yS1 +qTAfBgNVHSMEGDAWgBQyJOoeR8Y5TkgQ9vmRjskM3yS1qTAPBgNVHRMBAf8EBTAD +AQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAmq6ca42dFmuRrIzMTKQgAAD70QC1dgGAh +N8miJlbTfzsqXKtiMezZCQmeBJHVb3ljYtf3HkddqxQG8YGHOYTbxjvpoMhUbQe7 +/r2iBtYtMcempJPpflT3GqNPZcESMQKJP7Cq8uZjSbHAE3kgXxH6/89J9DP2V0mF +fOs3pnenvsEQPnPub/QZ4XGRtUJH1+0ALlBfvULiG8Sm3pMS0wvOeNB7GkXwUl1V +ZvEhCTJUX1lrgYVmw/wnypAffABIXl1PIeXP2GVxANPjFhFgoSKJI1iAvMoCeCAQ +JLuH7Vxk1nA9BaQavwvWJdDlfdtDMTrMegM9U2dSHeqw1Ai8lyxsINnCRtmLSRui +7DztPojiUanBJSPNJPzcAjJvFJRJ/xafHL3uhK31cMo15yUskxPPJvSfVzDvRGBX +GQjN7BIcFVx9CZYwjlVkXjGXCbUs+LAo5ecN6MmQ/BU4AKJ8GHcH2VBQ34W7H1TU +ZlnQxlzus+eMlhAjkoEKQn7SLjHdZT0SqYBPKXDymj2/VtvTqJgwcrf2E0pKBDh3 +TlmL+OuSLjwmhoQo2YASw0wb1NKJuALvYUfULl7en+WQPpfYvcHdShqWe8cid3T9 +BSksp7qKiKm67n4okeOqhUJu68yJ1ffdAnZCoy8DQmTouIWSAf2/5Z4En9rfT8+a +nuI9Lyjq7Q== -----END CERTIFICATE----- diff --git a/tests/certs/client_ca.cert.srl b/tests/certs/client_ca.cert.srl index 5e2fab31bcb..58dc4271789 100644 --- a/tests/certs/client_ca.cert.srl +++ b/tests/certs/client_ca.cert.srl @@ -1 +1 @@ -3DF7A3F0843FE5B0AB8A1A96226AEADAF28F3ABD +3DF7A3F0843FE5B0AB8A1A96226AEADAF28F3ABE diff --git a/tests/certs/client_ca.key.pem b/tests/certs/client_ca.key.pem index ad3a15a3d2f..864e7f15cfb 100644 --- a/tests/certs/client_ca.key.pem +++ b/tests/certs/client_ca.key.pem @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDremN0uCcC+1Us -JlNYSGDD/iy/4jFzvBTIXZ6JAVszSSCwE7NHuVbJPp72yCtOzNnyDEAoXC1fvDYP -Ah2NIKqYt2XKal6DQl/+B2yiepl9M/lYMX26MHL8N9k8RJ0Nn3joKFqlEi5Jri7n -3q9zsXYE6HgeWnaUQjyQRGYPVgFc2n5XLrUo3J/U+UNP+0q8cDOg8AU8kOqowwun -E0rQiQHdsPd3NUpebLViXBYZFfMtEnRU9tpAc6XG5Clv0Y+wzNIjO7DpKp7j0o+e -I3j9Z7hwkB/rMlMQbJ1Fgvw9x/puUb4FuhFKvlegw8RNtF/TUIvJa8iwGRk8Qc42 -w7/DjN3XI0CR9r2wZh0Eg1SodxbMObcqwZkFrw+wpGYBwMduiRDVaeKl8149aSuc -fGsQ+SfmYz0Hh4XCsn2s6UoILkJ4sSSjjOIk83/4sOR8eQB/Sv9LMIudYekhX3fy -V5757uXkRTxuPWDo9jwt/Kf1YyzzumoFAtaetxkvzU6fdXcTaYpLHBh+3/MVH/q5 -TVFw6r9YPfgKDOWA3Q6xrFOv6geUfX2p+Ze/o/fzbzEs1C7RSrWUiKhx2SmNPBoz -3rADw1a4FycPRIAYJzwXp9vt6PvjPadnc/ME/s3HkzOnYNI6inc9Ic0/HHgl/Mn9 -ScoF7dA1kIExKERlGjEPfbvNgl1ixwIDAQABAoICAAnDAO98Q4XAnzcdfvQDIBvP -5CavklGUGPUgyGsxPAjOvcT+3r5DmoDs5dB2MNwV6u0Oq/Q1tLMqIsA8MWHB2mtK -owohSboS8iwePlcn/PKZ89AU+9DQTwanVraZuOcGgY/M6HZntV/cPC6O5o1wbGOS -CDS97E+DcBj3n5bVf732gtP2EuWBlpCmJVph9lGvLGdou9bXF8Xs5q/uQU+Oy8iB -xxMmiZGLhnjFjNb3uCUvWtTmMjBc0EuuoWHKJApLcLoBhfkh3q9exxG3smgoOMGr -Koo+A6qDzitCXaw+p4zo5OyThOxTzV8pQ8Xdiza/4+OdjRbGcOuKENSSsyxAoTZE -b9C+TerZQZLJ/PH3zQqNBJyz2h0Cil/eO5KDnDcxiQ+yUZ7MxhFJy7Sz8Qux5nlx -JM93yYtgDUCmEU9RNdeNSjePkyy76CCnVldFKizEW6Hv3gxOvhZ0ZuFspVIDKGXq -jv7zgTbEH3DxBszjT/wY1yOvc5Viia94yF3f/Y/v8p+wCJEXuEPesh0mvXR93WnB -Qh5XeI9PX+rlEiAIjhP97SxBpa+kAN5Iecmd+qv/JfGpdfF85wYtWmkz+RgLfHw9 -+o6icVTKWUkYIySFK0PnN5iWabb1tpb4DlHiz0Jqj5C63fWoXm2/98fQ+nXRwrR7 -jgzc3hUcDoTpAzkyIMNlAoIBAQD633Ul8nqGTdLq5HizMcwaqdbJOKlIxQBter5Q -weRVs/SKwu6Tv54VMP3tuao5nZZpFM99d2JFP7Hwm2xs5AT2ogoy/Zs8gth4cJuq -/K8YHucs+xmeCmg2v5a/IQ2P3a5ZYgDIIh3w0arHwyhJNvLtOqgdnXu+tCff2eR/ -jRYpNnGcfvgAjHikrBXBZDk2yeBeX81/dTcGjs8+pP4Qml4dwQ1jWZDJgKkLfwU2 -BWlYAP2+PN9LIrvTPtBIyelKSwQsrPNowq0P8bUTCQ29e9VzlwZgnyq2JWUvJDIA -khX0R9yF6CmH2LH21DIj+5CNOXNf579zocSkBil6ZCjPQTV9AoIBAQDwSmME9wMB -rPwlpbI3KkWDn9ixXK7xpjETdrZcrvKcv28eekX3Fjz3sxXR0n5jfuDvUBkTjmaO -4ouUibqxAWjFIeuNfc0QYF97VsBz7EtVyBFkano8iboyUMFn5QZJKf/26uKRGvYN -I42jMgtT9ES5eB6iS+M2zEWWL21Mn/L2vvUnsWrUJ3BnFMw0KNd3eU/7v8lyAxV4 -KBITwZfbZRa2kUP7pxP7EVtRZLj4Q1IivE1Zdo4H3IipdQ2FESXd5cU9zv86nUfR -ObJOEW2DUxnCAfMMa6QwO4TVO0ue/gVqEpxS9fLbtZHbIYUIqgb8H+Iv27GZeLan -m+1kJftK+hyTAoIBABwRC+Ym7pY/9qzYyrghhhglkCYK9MVzZMzawpf+WTFNZLpx -fIeDFIiCZqZF80lm3AD9lwkOZiwhKCMnAEZebD+7eTCjNs7aRKWU05WZl203Z92c -ag1IVMhrPs47QG0r++l8EWJSjs72ZgjbSJKIVz07JrvJdqKrPRrKIcozWptZv/Qm -MFC/Zm/l4Lk2IUCD7VohlbgAwRs2tvDnPJVW79icVIcc6hnhDwh+OXMFv/dchQbX -gJPDWwgTKvI5xKPPKLRm1QSPYxU5kWyDwsnEJOk9qDT/GaQvItbXUdDGhzZBI+bH -Rn4wPBjFPKbR6iYim0nLf5vMKVfAaLuMoRQu03ECggEAKaApQR3tRmgKEhd/JPFM -s32IU0lEARaSH9YLx0iDPMYo4LW70w7mJt6+I+f7/w5mtu5AOdQMTipOlb+6OJmO -5b93h75IPNMFF1+y3SIM9uI+qQ+M91nAiKDWsEHLcfc1oTeVYh+yihojmia8MaH6 -GcsGO4U76i0+zMKQg5qdw0LXQzYH1JK0dRb0PQDqOocoZOsXYYnJOVRvtT5vKRF8 -+sl1Zm3OF0stb48sP82ht+S43YudFR2OCxT875VF4we/wHJQYn4Gh+cfzUhVmU9X -AfXGfdtTyQs2ep3X/sXweCybKf/zPz5X8wb+fb6+kQSQ8Ut0m6p+sdBgMl4mBxoG -wwKCAQAHTMyhsebi83tsOu5g41CPZTNYNrvz0ypXbV7pVrQ2T2BakVLWwemTt5gD -ldKX416oz1zRLiPSdPyClOfuL7bQjeU1zP3pupjMuzm89D1b5qT8aI/3anHtS+Rm -xlcnaiKld8IZEFXfi4+FIfwEWLlfZn+7J+rphTGZ43WLxvdeCGqdGef8Nt2hzxkF -9QoPwhEjyossII1yJw2JMx87S5ZzNzA4Iy8FkPXV9FBFLgrjO3f9Dx0MbGXDqhae -kx5WVRgas7KH4RFVLL+zjesQ2zVtxq+4YtsYX5oA/kD1XFIH3SRkExdTElpNTxo4 -JMzZVaMH/iiG4xZmm1vh3roPi8Sq +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 +grZhpKVB22PtQI9T68oHoj4yU7BC -----END PRIVATE KEY----- diff --git a/tests/certs/gen.sh b/tests/certs/gen.sh index ed53e24218a..1ee040f624c 100755 --- a/tests/certs/gen.sh +++ b/tests/certs/gen.sh @@ -35,7 +35,7 @@ openssl req -new -x509 -key client_ca.key.pem -out client_ca.cert.pem -days 7300 # Client cert openssl genrsa -out client.key.pem 4096 openssl req -new -key client.key.pem -out client.csr.pem -subj "/C=US/ST=California/L=San Francisco/O=EdgeDB Inc./OU=EdgeDB tests/CN=ssl_user/emailAddress=hello@edgedb.com" -batch -openssl x509 -req -in client.csr.pem -CA client_ca.cert.pem -CAkey client_ca.key.pem -CAcreateserial -out client.cert.pem -days 7300 +openssl x509 -req -in client.csr.pem -CA client_ca.cert.pem -CAkey client_ca.key.pem -CAcreateserial -out client.cert.pem -days 7300 -extensions v3_req -extfile ca.conf # Password protected client key openssl rsa -aes256 -in client.key.pem -out client.key.protected.pem -passout pass:secret1234 diff --git a/tests/certs/server.cert.pem b/tests/certs/server.cert.pem index 970908a810c..8f7361e4d50 100644 --- a/tests/certs/server.cert.pem +++ b/tests/certs/server.cert.pem @@ -1,36 +1,36 @@ -----BEGIN CERTIFICATE----- -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 -m+hGEYaP23LwDLBwv9//+jNASPYLfA== +c3QwHQYDVR0OBBYEFJfIRd55lBPNoJqNtVl+a7OOsIOvMB8GA1UdIwQYMBaAFBRx +NC1cmmAeggflm7LlZqIIZSTKMA0GCSqGSIb3DQEBCwUAA4ICAQBYe/i6zkxTwJXH +Zhv+0kAgdUIBiTKBImzwPwnwShbKbWNLloKtZ6aF+Spy1uO0w/NnCZ5S8M/E7HZr +ELnLJR+tU//sfmDb/y0UGNyJptj2z78R8k7yZCqA2MpA+t8nf9TT9cYu2wmCORt+ +jNZ0qYiRD4JichkVprkswF8gzZkhy8tM8TzO1HJu5TTZKQqcT4O1BCh9LkSgkhFD +OYqVqwdq/bo8tCnJzICl6ZdRObKUkQ3MrEyGde68suvG5mlfxylgknF9BUDvQKPA +eQISbIy+KuUSgD5q8f12qL6O1gPbnydYaFdS3aY8nTkfZCKUFcqBroyO57vK9rr3 +WdUZoT3eU011JrAXG7w8MBaoghTHor8mx3tjsNmnnJztngvm2nE2f34q261SA/uT +jfp1avecmzRFudUtT4NaAHw2aa6KqTZ4y/nHfoFozJxMtYVyuFGsIeToAAtZIpdb +zp8cDL7kW6MTIwFy7d8RAI+msDB5dUgT45iJUseAGklvnn/kibLzsbgfkeZXLxTg +l7oPm8ybtrM0RU/s3Pkknq5zoYp4PTQukcWWKO6rKBnu4UHDaF7ATtj9/7mQ/7rK +Muqt+iFhb3RMD7lj0ihZokvGZSe1AQxyS48llbLZoXOts20giTZGwVkvR125jF70 +bLtP4MYoBxHJxYGo4r0S6pYJ/nnTEA== -----END CERTIFICATE----- diff --git a/tests/certs/server.key.pem b/tests/certs/server.key.pem index 65bf666b930..c9a8a6abef2 100644 --- a/tests/certs/server.key.pem +++ b/tests/certs/server.key.pem @@ -1,52 +1,52 @@ -----BEGIN PRIVATE KEY----- -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 -VOSY1MQIxTgVpg1s9emO9LzO+FedN5k= +MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQC0se06E5EF/GwL +/y1CqNwPJK04qpDmt6kL9feZsegdh0KGR062RP7RPieJxYYCVSGSokNU5LJXo1t3 +XbS18xjnLVFfZXZNE1zbF1xRWQKJE7ZV5BpGO1ed1cAQGR6tsNsbUjQ3N+kLkph3 +dxLSho4Bqu9RQjTtrdGnu/lDlC3Tt2qmAl4MFFLmyUGPQiBOHWKDU+VG/i09cbZQ +VS7tFnyfL6F0SS3N+fOCa/gt7uEdNdVDRz81OoQ/xFAJFbj2kvCMgNfigyaUQc+C +JVXHgWvw+hLdgiGqIbnVB6nUpVOXIS9xXSY8i+ZURWdoz82HJJxuPUPoVsmlGqKT +Zy6DXIlLz0kPXCNpIAMatlBfWO3VV+Zc/ylCEjfN5uoGellr8WVlu793WuSZMpyy +50ULeGTV7/sNmQtdsYbl5wmv/mFG4EQm8De2gw9G09Ek7JdJbKLX3+lg2hC7AGec +QNLbnPhtvgMTp7dY0jy9xh7+k88Qha9EGAiF21ZzhqxhWrNk0u3CKJtD1QxtVDyH +q8FoeYpxLyDdW7h2YKykCXialZQlqHIk3wjQGlUTgNUtQn8z/el8a2pPWeU0+KsK +MDIizvFHMFbB5YZo/7vQ3k6rCq4tP5/UapTNeud6X6nlztGZL+Df+hONULJmL7Su +NIablyqACmBykFpqvH1kF0xtklENsQIDAQABAoICAA3YrJMMuMo6o5Tvwuoewm4u +o096Uow7eqq9+HFAnsbUfJaJlFCHTPd/ycvW5QP8vgvcf0hcFgZ9MB8fgR+IN1pP +sLKctcoGN9FaIurg5T7X0dsXFaRYG8iufn89TYqFyOR5EiNBF4yZeTF+YGTdhrg9 +/wS9DA1CipRN5TX2fuSAY53BBK/sRsYEmg9+Q7d4rPnfTex4wcK5mfzh6iyk0nvo +THj6upXUF4Lg/y2V5o40d9kl9oP/re6s/m0Tyw6qB+DcZq6m2if2Ow6ACei11C2t +HBD5TdcZqoHWin8PBC7KjjYjqzBskAPZJal0cw1uEsanzzJYpC8QsXCWMYxDZQnW +/JnOaEI8fbTalIjdprNNUWTH3bYuUjhdzlGj0XG8fgJmVWcI0YxvZK/7XkYZoO3T +0YsPlNfT92v1gUFy9LmdbzwVR+X3szQbKW00Mi4UfI9PGvVnNFWIWgQzZSn0unHL +x6bqFoL+7lRndJYhw7XEfgmkvWAC72VVW44v/gfhbPreInayrm6sjCU3iW2ck5oA +2yUQ5tkRIUAKRzrFFUeFlPifQYyl+XBqdZxmm4dBS8+wD5EidDWR+SSTrdQtHRQe +ZMnlLrQ2pselkJfWT0kN69Ht/+MlM8XFXC4pnRwzBPqzZe3SvaqSFXTV6iZVkr87 +brXjQHqpDR2Iz/mLeuohAoIBAQDvJUBhO/jFaNL07zMz2PVPvp02kw4XkAf9Ioj1 +cvMopPt5dJl/Ib3YzFSspgHt1fyQhXOMcyge+eUppfdvyeQD0NL5pq/snDUjTs8/ +rkHkEeqi0uEE3mIBSZJMyPj/M/0PIkP6aTS1YOD1wUnrmiKPAO5XxhxoDkOKvjua +n9G8Atn9p419V57JYgUOQKXMJ54dSgG57brBpCztiCjrv+ryCKJN3RDy4YBi/wIR ++60UIfUfp0LDtqXGOzUoFW+gF7BtmoI/bMS+JRt2tUhANQ0agLm09FQolQY9cvWt +m3jqSCT0G2F9EASk5z6dQQnM4Vm0Xa1nopCcGXxshj7Fw3SlAoIBAQDBbhc2VqKT +5vss3hdWWJ/NMR+n1dF+DN+0oKzRTv6mThUClTivliNh6a8S2N7uNspzKwfLJYtF +t7lttBypmX+AWFXfuvdQwckU2mbsqUu0eX0B1yleo/xjxDEH2X3KtR7oGd5fCSqq +gPSud7luTnD1+i4NYn0CWZuBIqz1/2UJAiMJ9C35pkK3kYZnVXl51ra0MHoqAN7l +xWxto7kdipbvRqHaxWRxDlEovnjdh2h9WcdT9L2Sv7yoddG6M1csvzj+BlpCdozX +Gc2Msn8WXqaOstbrxbrSH1ONrIMnd7C6/AulzBDgm6/0oG2vloGYEg4P+R6Shmj8 +AUm/fsxxlssdAoIBAAIGc7wfEOVDFP5EBE/9F168g4JRzn2+l4K6RySk+5AtjX+i +0CX2eDAc0t6/bSbBeCkVKDxZQU652Qn4QNcug4LQwuigU78SN5T79t9YL3CqAi2s +0YEEDRprsBR8YzduDkeRh7fYKj0a++y43VJkdMR3Qo11vQnYjRPgtoqBrfoEoCn4 +wEb+dfbIoLhVLdJDx6AB32/epoU7SbIdRBNzBZ9VGWLFa35TEI5GEJNsaTPRccz5 +0qPrqQ27tKCJRe+6I6FZ/J5i4mulzsy7jkgU6u59hpUUuJ27XVkp3xDAT07Um5OB +o9q2RwPKfYpBYb7dbbAMVwqYotbflGEq5d8w340CggEADIUlt3ywFUa0J1lQxWQD +I/L0C5cJclE/AaAMz5d/YCBZt8sU2jirnaDUljG3bE/blszIOlv5wc98jx9DY67t +087j8BFYBMAmVdU1KEhlAA+FCeN1aAzRP1vpmIp5W++RSpCyFhCv1E14iPpy5DLr +mOBSrscbNFW8fQVTkLCxR3396p0FhM1AMEWZH4Mm074UIWGp5qIby1+V/xrD1qer +0V0PCOwR7kdw9WQuypgDKWnwPvzucFs8yOKnapf8IodWFwsuOHMX9qxS47KCC16h +BUeKJcSsrQEeFWN/McTLia7ayiaFSSSKpRjlQKJLTR6ODnafhfhxPy6OKXj5nriV ++QKCAQBRgUoJr+ByP1fqmbz0M/0zvo5567bFPIhX1SQ+VTCnMkSFKDonrh2k0MSX +4pY8jQCcRlhQqXNrDoGrJ1brkmLSIVHbdzquI+2YemffgPiOs8n7cEkHvpoD6eMm +qlcDH/QvbVWMWeJ3rPMmbzh+9mrcOn86qPLLNzy6gU8J03rBi7tcO1aRvqx9vq44 +0WNNnTHMI53bNDZOt4J326N0sVVPpJFzx7GXTbhHI6yMVQ87touZ+GH1KQZu5Q8V +Xm54TyqZ76Pl7okuTq92yhdBuHCq0W+aUTW2GDMykp887m3PmWfub1/Dmj1BY0eY +OVaGdduWlABHp+A2Q9+iJdYrF5iN -----END PRIVATE KEY-----