diff --git a/.github/workflows/cargo.yml b/.github/workflows/cargo.yml index 20c20fbc..ffbe6acd 100644 --- a/.github/workflows/cargo.yml +++ b/.github/workflows/cargo.yml @@ -26,6 +26,19 @@ jobs: run: | cargo check --all-targets + check-powerset: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + - uses: swlynch99/cargo-sweep-action@v1 + - uses: taiki-e/install-action@cargo-hack + + - name: check powerset + run: | + cargo hack --feature-powerset check --locked + clippy: runs-on: ubuntu-latest steps: @@ -116,16 +129,16 @@ jobs: - name: build shell: bash run: | - cargo build --workspace --all-features --all-targets --locked ${{ env.FLAGS }} + cargo build --workspace --all-targets --locked ${{ env.FLAGS }} - name: test shell: bash run: | - cargo test --workspace --all-features --tests --lib --bins --examples --locked ${{ env.FLAGS }} + cargo test --workspace --tests --lib --bins --examples --locked ${{ env.FLAGS }} - name: doctests if: ${{ matrix.profile == 'debug' }} shell: bash run: | - cargo test --workspace --all-features --doc --locked -- --test-threads 16 + cargo test --workspace --doc --locked -- --test-threads 16 - name: generate bin artifact if: ${{ matrix.profile == 'release' && matrix.os == 'ubuntu-latest' }} diff --git a/Cargo.lock b/Cargo.lock index 0c6712c7..6a6cea7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,9 +40,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom", @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -68,9 +68,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstream" -version = "0.6.11" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb" dependencies = [ "anstyle", "anstyle-parse", @@ -82,9 +82,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arrayref" @@ -163,25 +163,25 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "awaken" @@ -240,9 +240,9 @@ dependencies = [ [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -271,7 +271,7 @@ version = "0.66.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "cexpr", "clang-sys", "lazy_static", @@ -282,7 +282,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -293,9 +293,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitvec" @@ -311,9 +311,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec", @@ -339,9 +339,9 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ae1aba472e42d3cf45ac6d0a6c8fc3ddf743871209e1b40229aed9fbdf48ece" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "boring-sys", - "foreign-types", + "foreign-types 0.5.0", "libc", "once_cell", ] @@ -360,9 +360,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.9.0" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "regex-automata", @@ -371,15 +371,15 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cast" @@ -389,9 +389,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" dependencies = [ "jobserver", "libc", @@ -420,9 +420,9 @@ checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" [[package]] name = "ciborium" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", @@ -431,15 +431,15 @@ dependencies = [ [[package]] name = "ciborium-io" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", @@ -458,18 +458,18 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.18" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstream", "anstyle", @@ -479,9 +479,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "clocksource" @@ -592,9 +592,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ "crossbeam-utils", ] @@ -633,6 +633,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "datatier" version = "0.1.0" @@ -655,9 +661,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "entrystore" @@ -690,9 +696,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "fnv" @@ -700,6 +706,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + [[package]] name = "foreign-types" version = "0.5.0" @@ -707,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" dependencies = [ "foreign-types-macros", - "foreign-types-shared", + "foreign-types-shared 0.3.1", ] [[package]] @@ -718,9 +733,15 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "foreign-types-shared" version = "0.3.1" @@ -805,7 +826,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -863,9 +884,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "h2" -version = "0.3.24" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -873,7 +894,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 2.2.6", "slab", "tokio", "tokio-util", @@ -882,9 +903,13 @@ dependencies = [ [[package]] name = "half" -version = "1.8.2" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" +dependencies = [ + "cfg-if", + "crunchy", +] [[package]] name = "hashbrown" @@ -900,9 +925,9 @@ checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "histogram" @@ -915,18 +940,18 @@ dependencies = [ [[package]] name = "histogram" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ee9487899388cf1a1155759c39e3c156c5d198b6da1734053954a6e40e6d4d" +checksum = "4b634390eb8a63662e127836d4e2f26d7ae930600d4e05ee0fd85a009eeb1175" dependencies = [ "thiserror", ] [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1004,9 +1029,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -1014,12 +1039,12 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", - "rustix", + "libc", "windows-sys 0.52.0", ] @@ -1043,24 +1068,24 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1093,38 +1118,38 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-targets 0.52.4", ] [[package]] name = "linkme" -version = "0.3.22" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b53ad6a33de58864705954edb5ad5d571a010f9e296865ed43dc72a5621b430" +checksum = "bb2cfee0de9bd869589fb9a015e155946d1be5ff415cb844c2caccc6cc4b5db9" dependencies = [ "linkme-impl", ] [[package]] name = "linkme-impl" -version = "0.3.22" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e542a18c94a9b6fcc7adb090fa3ba6b79ee220a16404f325672729f32a66ff" +checksum = "adf157a4dc5a29b7b464aa8fe7edeff30076e07e13646a1c3874f58477dc99f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -1145,9 +1170,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "logger" @@ -1166,15 +1191,15 @@ checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45fd3a57831bf88bc63f8cebc0cf956116276e97fef3966103e96416209f7c92" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" dependencies = [ "libc", ] @@ -1198,7 +1223,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3870ac33c736eb72b163e299d3942ddf8faf78600768ac13973d240593eedf" dependencies = [ - "histogram 0.9.0", + "histogram 0.9.1", "metriken-core", "metriken-derive 0.4.1", "once_cell", @@ -1260,9 +1285,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -1360,21 +1385,26 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -1410,12 +1440,60 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.5.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.2.1+3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fe476c29791a5ca0d1273c697e96085bbabbbea2ef7afd5617e78a4b40332d3" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1447,14 +1525,17 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pelikan-net" -version = "0.1.0" +version = "0.2.0" dependencies = [ "boring", "boring-sys", - "foreign-types-shared", + "foreign-types-shared 0.1.1", + "foreign-types-shared 0.3.1", "libc", "metriken 0.3.5", "mio", + "openssl", + "openssl-sys", ] [[package]] @@ -1518,7 +1599,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -1532,29 +1613,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -1594,9 +1675,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plotters" @@ -1650,9 +1731,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1677,7 +1758,7 @@ dependencies = [ "itertools 0.11.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -1848,9 +1929,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -1893,9 +1974,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -1905,9 +1986,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -1916,9 +1997,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "ring" @@ -1937,16 +2018,17 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", + "cfg-if", "getrandom", "libc", "spin 0.9.8", "untrusted 0.9.0", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1976,11 +2058,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustix" -version = "0.38.30" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -1994,7 +2076,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.7", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -2026,7 +2108,7 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] @@ -2038,9 +2120,9 @@ checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" @@ -2072,15 +2154,15 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", + "ring 0.17.8", "untrusted 0.9.0", ] [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -2091,9 +2173,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -2117,29 +2199,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -2243,18 +2325,18 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -2281,9 +2363,9 @@ version = "0.3.1" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "switchboard" @@ -2310,9 +2392,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687" dependencies = [ "proc-macro2", "quote", @@ -2333,35 +2415,34 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.9.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", "rustix", "windows-sys 0.52.0", ] [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -2380,12 +2461,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -2400,10 +2482,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -2431,9 +2514,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.35.1" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -2466,7 +2549,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -2481,9 +2564,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -2506,14 +2589,14 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.8" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.21.0", + "toml_edit 0.22.9", ] [[package]] @@ -2531,22 +2614,22 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.21.0" +version = "0.22.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.5", ] [[package]] @@ -2632,7 +2715,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -2690,6 +2773,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -2698,9 +2787,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -2723,9 +2812,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2733,24 +2822,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2758,28 +2847,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", @@ -2787,9 +2876,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.25.3" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "winapi" @@ -2837,7 +2926,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -2857,17 +2946,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -2878,9 +2967,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -2890,9 +2979,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -2902,9 +2991,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -2914,9 +3003,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -2926,9 +3015,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -2938,9 +3027,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -2950,15 +3039,24 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + +[[package]] +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] [[package]] name = "winnow" -version = "0.5.34" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8" dependencies = [ "memchr", ] @@ -2989,7 +3087,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.58", ] [[package]] @@ -3013,9 +3111,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 21f60211..867d5231 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,7 +51,6 @@ clap = "4.4.6" clocksource = "0.8.1" crossbeam-channel = "0.5.8" datatier = { path = "./src/storage/datatier", version = "0.1.0"} -foreign-types-shared = "0.3.1" httparse = "1.8.0" libc = "0.2.149" log = "0.4.20" @@ -60,8 +59,10 @@ metriken = "0.3.3" metrohash = "1.0.6" mio = "0.8.11" nom = "7.1.3" +openssl = "0.10.64" +openssl-sys = "0.9.102" parking_lot = "0.12.1" -pelikan-net = { path = "./src/net", version = "0.1.0" } +pelikan-net = { path = "./src/net", version = "0.2.0" } phf = "0.11.2" proc-macro2 = "1.0.69" quote = "1.0.33" diff --git a/src/common/Cargo.toml b/src/common/Cargo.toml index 52e6a560..6fdf6bb3 100644 --- a/src/common/Cargo.toml +++ b/src/common/Cargo.toml @@ -13,6 +13,6 @@ license = { workspace = true } boring = { workspace = true } clocksource = { workspace = true } metriken = { workspace = true } -pelikan-net = { workspace = true } +pelikan-net = { workspace = true, features = ["boringssl"] } ringlog = { workspace = true } serde = { workspace = true, features = ["derive"] } diff --git a/src/common/src/ssl.rs b/src/common/src/ssl.rs index e27ab749..acf79e65 100644 --- a/src/common/src/ssl.rs +++ b/src/common/src/ssl.rs @@ -22,7 +22,7 @@ pub trait TlsConfig { /// `TlsTcpAcceptor` wrapped in an option, where the `None` variant indicates /// that TLS should not be used. pub fn tls_acceptor(config: &dyn TlsConfig) -> Result, IoError> { - let mut builder = TlsTcpAcceptor::mozilla_intermediate_v5()?; + let mut builder = TlsTcpAcceptor::builder(); // we use xor here to check if we have an under-specified tls configuration if config.private_key().is_some() diff --git a/src/net/Cargo.toml b/src/net/Cargo.toml index d27d836e..cbaea76f 100644 --- a/src/net/Cargo.toml +++ b/src/net/Cargo.toml @@ -2,7 +2,7 @@ name = "pelikan-net" description = "Pelikan project's networking abstractions for non-blocking event loops" authors = ["Brian Martin "] -version = "0.1.0" +version = "0.2.0" edition = { workspace = true } homepage = { workspace = true } @@ -10,9 +10,17 @@ repository = { workspace = true } license = { workspace = true } [dependencies] -boring = { workspace = true } -boring-sys = { workspace = true } -foreign-types-shared = { workspace = true } +boring = { workspace = true, optional = true } +boring-sys = { workspace = true, optional = true } +foreign-types-shared_03 = { package = "foreign-types-shared", version = "0.3.1" } +foreign-types-shared_01 = { package = "foreign-types-shared", version = "0.1.1" } libc = { workspace = true } metriken = { workspace = true } mio = { workspace = true, features = ["os-poll", "net"] } +openssl = { workspace = true, optional = true } +openssl-sys = { workspace = true, optional = true } + +[features] +default = ["boringssl"] +boringssl = ["boring", "boring-sys"] +openssl = ["dep:openssl", "openssl-sys", "openssl/vendored"] diff --git a/src/net/src/connector.rs b/src/net/src/connector.rs index c49f1ee8..342078d1 100644 --- a/src/net/src/connector.rs +++ b/src/net/src/connector.rs @@ -10,6 +10,7 @@ pub struct Connector { enum ConnectorType { Tcp(TcpConnector), + #[cfg(any(feature = "boringssl", feature = "openssl"))] TlsTcp(TlsTcpConnector), } @@ -18,6 +19,7 @@ impl Connector { pub fn connect(&self, addr: A) -> Result { match &self.inner { ConnectorType::Tcp(connector) => Ok(Stream::from(connector.connect(addr)?)), + #[cfg(any(feature = "boringssl", feature = "openssl"))] ConnectorType::TlsTcp(connector) => Ok(Stream::from(connector.connect(addr)?)), } } @@ -31,6 +33,7 @@ impl From for Connector { } } +#[cfg(any(feature = "boringssl", feature = "openssl"))] impl From for Connector { fn from(other: TlsTcpConnector) -> Self { Self { diff --git a/src/net/src/lib.rs b/src/net/src/lib.rs index 18a6edc5..0c11a8be 100644 --- a/src/net/src/lib.rs +++ b/src/net/src/lib.rs @@ -6,12 +6,16 @@ mod connector; mod listener; mod stream; mod tcp; + +#[cfg(any(feature = "boringssl", feature = "openssl"))] mod tls_tcp; pub use connector::*; pub use listener::*; pub use stream::*; pub use tcp::*; + +#[cfg(any(feature = "boringssl", feature = "openssl"))] pub use tls_tcp::*; pub mod event { @@ -24,9 +28,7 @@ use core::fmt::Debug; use core::ops::Deref; use std::io::{Error, ErrorKind, Read, Write}; use std::net::{SocketAddr, ToSocketAddrs}; -use std::path::{Path, PathBuf}; -use foreign_types_shared::{ForeignType, ForeignTypeRef}; use metriken::*; type Result = std::io::Result; diff --git a/src/net/src/listener.rs b/src/net/src/listener.rs index e5e9f1f8..25601abb 100644 --- a/src/net/src/listener.rs +++ b/src/net/src/listener.rs @@ -10,6 +10,7 @@ pub struct Listener { enum ListenerType { Plain(TcpListener), + #[cfg(any(feature = "boringssl", feature = "openssl"))] Tls((TcpListener, TlsTcpAcceptor)), } @@ -21,6 +22,7 @@ impl From for Listener { } } +#[cfg(any(feature = "boringssl", feature = "openssl"))] impl From<(TcpListener, TlsTcpAcceptor)> for Listener { fn from(other: (TcpListener, TlsTcpAcceptor)) -> Self { Self { @@ -51,6 +53,7 @@ impl Listener { let (stream, _addr) = listener.accept()?; Ok(Stream::from(stream)) } + #[cfg(any(feature = "boringssl", feature = "openssl"))] ListenerType::Tls((listener, acceptor)) => { let (stream, _addr) = listener.accept()?; let stream = acceptor.accept(stream)?; @@ -62,6 +65,7 @@ impl Listener { pub fn local_addr(&self) -> Result { match &self.inner { ListenerType::Plain(listener) => listener.local_addr(), + #[cfg(any(feature = "boringssl", feature = "openssl"))] ListenerType::Tls((listener, _acceptor)) => listener.local_addr(), } } @@ -76,6 +80,7 @@ impl event::Source for Listener { ) -> Result<()> { match &mut self.inner { ListenerType::Plain(listener) => listener.register(registry, token, interests), + #[cfg(any(feature = "boringssl", feature = "openssl"))] ListenerType::Tls((listener, _acceptor)) => { listener.register(registry, token, interests) } @@ -90,6 +95,7 @@ impl event::Source for Listener { ) -> Result<()> { match &mut self.inner { ListenerType::Plain(listener) => listener.reregister(registry, token, interests), + #[cfg(any(feature = "boringssl", feature = "openssl"))] ListenerType::Tls((listener, _acceptor)) => { listener.reregister(registry, token, interests) } @@ -99,6 +105,7 @@ impl event::Source for Listener { fn deregister(&mut self, registry: &mio::Registry) -> Result<()> { match &mut self.inner { ListenerType::Plain(listener) => listener.deregister(registry), + #[cfg(any(feature = "boringssl", feature = "openssl"))] ListenerType::Tls((listener, _acceptor)) => listener.deregister(registry), } } diff --git a/src/net/src/stream.rs b/src/net/src/stream.rs index 249948c8..e6efcc7f 100644 --- a/src/net/src/stream.rs +++ b/src/net/src/stream.rs @@ -20,6 +20,8 @@ impl AsRawFd for Stream { fn as_raw_fd(&self) -> i32 { match &self.inner { StreamType::Tcp(s) => s.as_raw_fd(), + + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.as_raw_fd(), } } @@ -35,6 +37,7 @@ impl Stream { Interest::READABLE } } + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.interest(), } } @@ -42,6 +45,7 @@ impl Stream { pub fn is_established(&mut self) -> bool { match &mut self.inner { StreamType::Tcp(s) => s.is_established(), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => !s.is_handshaking(), } } @@ -49,6 +53,7 @@ impl Stream { pub fn is_handshaking(&self) -> bool { match &self.inner { StreamType::Tcp(_) => false, + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.is_handshaking(), } } @@ -56,6 +61,7 @@ impl Stream { pub fn do_handshake(&mut self) -> Result<()> { match &mut self.inner { StreamType::Tcp(_) => Ok(()), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.do_handshake(), } } @@ -63,6 +69,7 @@ impl Stream { pub fn set_nodelay(&mut self, nodelay: bool) -> Result<()> { match &mut self.inner { StreamType::Tcp(s) => s.set_nodelay(nodelay), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.set_nodelay(nodelay), } } @@ -70,6 +77,7 @@ impl Stream { pub fn shutdown(&mut self) -> Result { let result = match &mut self.inner { StreamType::Tcp(s) => s.shutdown(Shutdown::Both).map(|_| true), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.shutdown().map(|v| v == ShutdownResult::Received), }; @@ -92,6 +100,7 @@ impl Debug for Stream { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { match &self.inner { StreamType::Tcp(s) => write!(f, "{s:?}"), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => write!(f, "{s:?}"), } } @@ -105,6 +114,7 @@ impl From for Stream { } } +#[cfg(any(feature = "boringssl", feature = "openssl"))] impl From for Stream { fn from(other: TlsTcpStream) -> Self { Self { @@ -117,6 +127,7 @@ impl Read for Stream { fn read(&mut self, buf: &mut [u8]) -> Result { match &mut self.inner { StreamType::Tcp(s) => s.read(buf), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.read(buf), } } @@ -126,6 +137,7 @@ impl Write for Stream { fn write(&mut self, buf: &[u8]) -> Result { match &mut self.inner { StreamType::Tcp(s) => s.write(buf), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.write(buf), } } @@ -133,6 +145,7 @@ impl Write for Stream { fn flush(&mut self) -> Result<()> { match &mut self.inner { StreamType::Tcp(s) => s.flush(), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.flush(), } } @@ -142,6 +155,7 @@ impl event::Source for Stream { fn register(&mut self, registry: &Registry, token: Token, interest: Interest) -> Result<()> { match &mut self.inner { StreamType::Tcp(s) => s.register(registry, token, interest), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.register(registry, token, interest), } } @@ -154,6 +168,7 @@ impl event::Source for Stream { ) -> Result<()> { match &mut self.inner { StreamType::Tcp(s) => s.reregister(registry, token, interest), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.reregister(registry, token, interest), } } @@ -161,6 +176,7 @@ impl event::Source for Stream { fn deregister(&mut self, registry: &mio::Registry) -> Result<()> { match &mut self.inner { StreamType::Tcp(s) => s.deregister(registry), + #[cfg(any(feature = "boringssl", feature = "openssl"))] StreamType::TlsTcp(s) => s.deregister(registry), } } @@ -171,5 +187,6 @@ impl event::Source for Stream { /// efficient than using a trait for dynamic dispatch. enum StreamType { Tcp(TcpStream), + #[cfg(any(feature = "boringssl", feature = "openssl"))] TlsTcp(TlsTcpStream), } diff --git a/src/net/src/tcp.rs b/src/net/src/tcp.rs index 3f70ea73..873a424c 100644 --- a/src/net/src/tcp.rs +++ b/src/net/src/tcp.rs @@ -5,8 +5,6 @@ use crate::*; use std::os::unix::prelude::FromRawFd; -pub use std::net::Shutdown; - #[derive(PartialEq)] enum State { Connecting, diff --git a/src/net/src/tls_tcp.rs b/src/net/src/tls_tcp/boringssl.rs similarity index 72% rename from src/net/src/tls_tcp.rs rename to src/net/src/tls_tcp/boringssl.rs index 4980e962..2977272d 100644 --- a/src/net/src/tls_tcp.rs +++ b/src/net/src/tls_tcp/boringssl.rs @@ -2,11 +2,13 @@ // Licensed under the Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 -pub use boring::ssl::{ShutdownResult, SslVerifyMode}; +pub use boring::ssl::ShutdownResult; + use std::os::unix::prelude::AsRawFd; use boring::ssl::{ErrorCode, Ssl, SslFiletype, SslMethod, SslStream}; use boring::x509::X509; +use foreign_types_shared_03::{ForeignType, ForeignTypeRef}; use crate::*; @@ -38,14 +40,6 @@ impl TlsTcpStream { self.state == TlsState::Handshaking } - pub fn interest(&self) -> Interest { - if self.is_handshaking() { - Interest::READABLE.add(Interest::WRITABLE) - } else { - Interest::READABLE - } - } - /// Attempts to drive the TLS/SSL handshake to completion. If the return /// variant is `Ok` it indiates that the handshake is complete. An error /// result of `WouldBlock` indicates that the handshake may complete in the @@ -154,62 +148,14 @@ pub struct TlsTcpAcceptor { } impl TlsTcpAcceptor { - pub fn mozilla_intermediate_v5() -> Result { - let inner = boring::ssl::SslAcceptor::mozilla_intermediate_v5(SslMethod::tls_server()) - .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?; - - Ok(TlsTcpAcceptorBuilder { - inner, - ca_file: None, - certificate_file: None, - certificate_chain_file: None, - private_key_file: None, - }) - } + pub fn build(builder: TlsTcpAcceptorBuilder) -> Result { + let mut acceptor = + ::boring::ssl::SslAcceptor::mozilla_intermediate_v5(SslMethod::tls_client()) + .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?; - pub fn accept(&self, stream: TcpStream) -> Result { - let ssl = Ssl::new(&self.inner)?; - - let stream = unsafe { SslStream::from_raw_parts(ssl.into_ptr(), stream) }; - - let ret = unsafe { boring_sys::SSL_accept(stream.ssl().as_ptr()) }; - - if ret > 0 { - Ok(TlsTcpStream { - inner: stream, - state: TlsState::Negotiated, - }) - } else { - let code = unsafe { - ErrorCode::from_raw(boring_sys::SSL_get_error(stream.ssl().as_ptr(), ret)) - }; - match code { - ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Ok(TlsTcpStream { - inner: stream, - state: TlsState::Handshaking, - }), - _ => Err(Error::new(ErrorKind::Other, "handshake failed")), - } - } - } -} - -/// Provides a wrapped builder for producing a `TlsAcceptor`. This has some -/// minor differences from the `boring::ssl::SslAcceptorBuilder` to provide -/// improved ergonomics. -pub struct TlsTcpAcceptorBuilder { - inner: boring::ssl::SslAcceptorBuilder, - ca_file: Option, - certificate_file: Option, - certificate_chain_file: Option, - private_key_file: Option, -} - -impl TlsTcpAcceptorBuilder { - pub fn build(mut self) -> Result { // load the CA file, if provided - if let Some(f) = self.ca_file { - self.inner.set_ca_file(f.clone()).map_err(|e| { + if let Some(f) = builder.ca_file { + acceptor.set_ca_file(f.clone()).map_err(|e| { Error::new( ErrorKind::Other, format!("failed to load CA file: {}\n{}", f.display(), e), @@ -218,8 +164,8 @@ impl TlsTcpAcceptorBuilder { } // load the private key from file - if let Some(f) = self.private_key_file { - self.inner + if let Some(f) = builder.private_key_file { + acceptor .set_private_key_file(f.clone(), SslFiletype::PEM) .map_err(|e| { Error::new( @@ -232,13 +178,13 @@ impl TlsTcpAcceptorBuilder { } // load the certificate chain, certificate file, or both - match (self.certificate_chain_file, self.certificate_file) { + match (builder.certificate_chain_file, builder.certificate_file) { (Some(chain), Some(cert)) => { // assume we have the leaf in a standalone file, and the // intermediates + root in another file // first load the leaf - self.inner + acceptor .set_certificate_file(cert.clone(), SslFiletype::PEM) .map_err(|e| { Error::new( @@ -269,7 +215,7 @@ impl TlsTcpAcceptorBuilder { ) })?; for cert in cert_chain { - self.inner.add_extra_chain_cert(cert).map_err(|e| { + acceptor.add_extra_chain_cert(cert).map_err(|e| { Error::new( ErrorKind::Other, format!( @@ -286,7 +232,7 @@ impl TlsTcpAcceptorBuilder { // one file // load the entire chain - self.inner + acceptor .set_certificate_chain_file(chain.clone()) .map_err(|e| { Error::new( @@ -301,7 +247,7 @@ impl TlsTcpAcceptorBuilder { } (None, Some(cert)) => { // this will just load the leaf certificate from the file - self.inner + acceptor .set_certificate_file(cert.clone(), SslFiletype::PEM) .map_err(|e| { Error::new( @@ -318,96 +264,17 @@ impl TlsTcpAcceptorBuilder { } } - let inner = self.inner.build().into_context(); + let inner = acceptor.build().into_context(); Ok(TlsTcpAcceptor { inner }) } - pub fn verify(mut self, mode: SslVerifyMode) -> Self { - self.inner.set_verify(mode); - self - } - - /// Load trusted root certificates from a file. - /// - /// The file should contain a sequence of PEM-formatted CA certificates. - pub fn ca_file>(mut self, file: P) -> Self { - self.ca_file = Some(file.as_ref().to_path_buf()); - self - } - - /// Load a leaf certificate from a file. - /// - /// This loads only a single PEM-formatted certificate from the file which - /// will be used as the leaf certifcate. - /// - /// Use `set_certificate_chain_file` to provide a complete certificate - /// chain. Use this with the `set_certifcate_chain_file` if the leaf - /// certifcate and remainder of the certificate chain are split across two - /// files. - pub fn certificate_file>(mut self, file: P) -> Self { - self.certificate_file = Some(file.as_ref().to_path_buf()); - self - } - - /// Load a certificate chain from a file. - /// - /// The file should contain a sequence of PEM-formatted certificates. If - /// used without `set_certificate_file` the provided file must contain the - /// leaf certificate and the complete chain of certificates up to and - /// including the trusted root certificate. If used with - /// `set_certificate_file`, this file must not contain the leaf certifcate - /// and will be treated as the complete chain of certificates up to and - /// including the trusted root certificate. - pub fn certificate_chain_file>(mut self, file: P) -> Self { - self.certificate_chain_file = Some(file.as_ref().to_path_buf()); - self - } - - /// Loads the private key from a PEM-formatted file. - pub fn private_key_file>(mut self, file: P) -> Self { - self.private_key_file = Some(file.as_ref().to_path_buf()); - self - } -} - -/// Provides a wrapped connector for client-side TLS. This returns our wrapped -/// `TlsStream` type so that clients can store negotiated and handshaking -/// streams in a structure with a uniform type. -#[allow(dead_code)] -pub struct TlsTcpConnector { - inner: boring::ssl::SslContext, -} - -impl TlsTcpConnector { - pub fn builder() -> Result { - let inner = boring::ssl::SslConnector::builder(SslMethod::tls_client()) - .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?; - - Ok(TlsTcpConnectorBuilder { - inner, - ca_file: None, - certificate_file: None, - certificate_chain_file: None, - private_key_file: None, - }) - } - - pub fn connect(&self, addr: A) -> Result { - let addrs: Vec = addr.to_socket_addrs()?.collect(); - let mut s = Err(Error::new(ErrorKind::Other, "failed to resolve")); - for addr in addrs { - s = TcpStream::connect(addr); - if s.is_ok() { - break; - } - } - + pub fn accept(&self, stream: TcpStream) -> Result { let ssl = Ssl::new(&self.inner)?; - let stream = unsafe { SslStream::from_raw_parts(ssl.into_ptr(), s?) }; + let stream = unsafe { SslStream::from_raw_parts(ssl.into_ptr(), stream) }; - let ret = unsafe { boring_sys::SSL_connect(stream.ssl().as_ptr()) }; + let ret = unsafe { boring_sys::SSL_accept(stream.ssl().as_ptr()) }; if ret > 0 { Ok(TlsTcpStream { @@ -429,29 +296,30 @@ impl TlsTcpConnector { } } -/// Provides a wrapped builder for producing a `TlsConnector`. This has some -/// minor differences from the `boring::ssl::SslConnectorBuilder` to provide -/// improved ergonomics. -pub struct TlsTcpConnectorBuilder { - inner: boring::ssl::SslConnectorBuilder, - ca_file: Option, - certificate_file: Option, - certificate_chain_file: Option, - private_key_file: Option, +/// Provides a wrapped connector for client-side TLS. This returns our wrapped +/// `TlsStream` type so that clients can store negotiated and handshaking +/// streams in a structure with a uniform type. +#[allow(dead_code)] +pub struct TlsTcpConnector { + inner: boring::ssl::SslContext, } -impl TlsTcpConnectorBuilder { - pub fn build(mut self) -> Result { +impl TlsTcpConnector { + pub fn build(builder: TlsTcpConnectorBuilder) -> Result { + let mut connector = + ::boring::ssl::SslAcceptor::mozilla_intermediate_v5(SslMethod::tls_server()) + .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?; + // load the CA file, if provided - if let Some(f) = self.ca_file { - self.inner.set_ca_file(f).map_err(|e| { + if let Some(f) = builder.ca_file { + connector.set_ca_file(f).map_err(|e| { Error::new(ErrorKind::Other, format!("failed to load CA file: {e}")) })?; } // load the private key from file - if let Some(f) = self.private_key_file { - self.inner + if let Some(f) = builder.private_key_file { + connector .set_private_key_file(f, SslFiletype::PEM) .map_err(|e| { Error::new( @@ -464,13 +332,13 @@ impl TlsTcpConnectorBuilder { } // load the certificate chain, certificate file, or both - match (self.certificate_chain_file, self.certificate_file) { + match (builder.certificate_chain_file, builder.certificate_file) { (Some(chain), Some(cert)) => { // assume we have the leaf in a standalone file, and the // intermediates + root in another file // first load the leaf - self.inner + connector .set_certificate_file(cert, SslFiletype::PEM) .map_err(|e| { Error::new( @@ -493,7 +361,7 @@ impl TlsTcpConnectorBuilder { ) })?; for cert in chain { - self.inner.add_extra_chain_cert(cert).map_err(|e| { + connector.add_extra_chain_cert(cert).map_err(|e| { Error::new( ErrorKind::Other, format!("bad certificate in certificate chain file: {e}"), @@ -506,7 +374,7 @@ impl TlsTcpConnectorBuilder { // one file // load the entire chain - self.inner.set_certificate_chain_file(chain).map_err(|e| { + connector.set_certificate_chain_file(chain).map_err(|e| { Error::new( ErrorKind::Other, format!("failed to load certificate chain file: {e}"), @@ -515,7 +383,7 @@ impl TlsTcpConnectorBuilder { } (None, Some(cert)) => { // this will just load the leaf certificate from the file - self.inner + connector .set_certificate_file(cert, SslFiletype::PEM) .map_err(|e| { Error::new( @@ -532,56 +400,44 @@ impl TlsTcpConnectorBuilder { } } - let inner = self.inner.build().into_context(); + let inner = connector.build().into_context(); Ok(TlsTcpConnector { inner }) } - pub fn verify(mut self, mode: SslVerifyMode) -> Self { - self.inner.set_verify(mode); - self - } + pub fn connect(&self, addr: A) -> Result { + let addrs: Vec = addr.to_socket_addrs()?.collect(); + let mut s = Err(Error::new(ErrorKind::Other, "failed to resolve")); + for addr in addrs { + s = TcpStream::connect(addr); + if s.is_ok() { + break; + } + } - /// Load trusted root certificates from a file. - /// - /// The file should contain a sequence of PEM-formatted CA certificates. - pub fn ca_file>(mut self, file: P) -> Self { - self.ca_file = Some(file.as_ref().to_path_buf()); - self - } + let ssl = Ssl::new(&self.inner)?; - /// Load a leaf certificate from a file. - /// - /// This loads only a single PEM-formatted certificate from the file which - /// will be used as the leaf certifcate. - /// - /// Use `set_certificate_chain_file` to provide a complete certificate - /// chain. Use this with the `set_certifcate_chain_file` if the leaf - /// certifcate and remainder of the certificate chain are split across two - /// files. - pub fn certificate_file>(mut self, file: P) -> Self { - self.certificate_file = Some(file.as_ref().to_path_buf()); - self - } + let stream = unsafe { SslStream::from_raw_parts(ssl.into_ptr(), s?) }; - /// Load a certificate chain from a file. - /// - /// The file should contain a sequence of PEM-formatted certificates. If - /// used without `set_certificate_file` the provided file must contain the - /// leaf certificate and the complete chain of certificates up to and - /// including the trusted root certificate. If used with - /// `set_certificate_file`, this file must not contain the leaf certifcate - /// and will be treated as the complete chain of certificates up to and - /// including the trusted root certificate. - pub fn certificate_chain_file>(mut self, file: P) -> Self { - self.certificate_chain_file = Some(file.as_ref().to_path_buf()); - self - } + let ret = unsafe { boring_sys::SSL_connect(stream.ssl().as_ptr()) }; - /// Loads the private key from a PEM-formatted file. - pub fn private_key_file>(mut self, file: P) -> Self { - self.private_key_file = Some(file.as_ref().to_path_buf()); - self + if ret > 0 { + Ok(TlsTcpStream { + inner: stream, + state: TlsState::Negotiated, + }) + } else { + let code = unsafe { + ErrorCode::from_raw(boring_sys::SSL_get_error(stream.ssl().as_ptr(), ret)) + }; + match code { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Ok(TlsTcpStream { + inner: stream, + state: TlsState::Handshaking, + }), + _ => Err(Error::new(ErrorKind::Other, "handshake failed")), + } + } } } diff --git a/src/net/src/tls_tcp/mod.rs b/src/net/src/tls_tcp/mod.rs new file mode 100644 index 00000000..c64d2575 --- /dev/null +++ b/src/net/src/tls_tcp/mod.rs @@ -0,0 +1,405 @@ +use crate::*; +use std::io::Result; +use std::os::fd::AsRawFd; +use std::path::Path; +use std::path::PathBuf; + +#[cfg(feature = "boringssl")] +mod boringssl; + +#[cfg(feature = "openssl")] +mod openssl; + +pub enum Implementation { + #[cfg(feature = "boringssl")] + Boringssl, + #[cfg(feature = "openssl")] + Openssl, +} + +impl Default for Implementation { + fn default() -> Self { + #[cfg(all(not(feature = "boringssl"), feature = "openssl"))] + { + return Self::Openssl; + } + + #[cfg(feature = "boringssl")] + Self::Boringssl + } +} + +#[derive(PartialEq, Debug, Copy, Clone)] +pub enum ShutdownResult { + Sent, + Received, +} + +#[cfg(feature = "openssl")] +impl From<::openssl::ssl::ShutdownResult> for ShutdownResult { + fn from(other: ::openssl::ssl::ShutdownResult) -> Self { + match other { + ::openssl::ssl::ShutdownResult::Sent => Self::Sent, + ::openssl::ssl::ShutdownResult::Received => Self::Received, + } + } +} + +#[cfg(feature = "boringssl")] +impl From<::boring::ssl::ShutdownResult> for ShutdownResult { + fn from(other: ::boring::ssl::ShutdownResult) -> Self { + match other { + ::boring::ssl::ShutdownResult::Sent => Self::Sent, + ::boring::ssl::ShutdownResult::Received => Self::Received, + } + } +} + +#[derive(Debug)] +pub struct TlsTcpStream { + inner: TlsTcpStreamImpl, +} + +#[derive(Debug)] +enum TlsTcpStreamImpl { + #[cfg(feature = "boringssl")] + Boringssl(boringssl::TlsTcpStream), + #[cfg(feature = "openssl")] + Openssl(openssl::TlsTcpStream), +} + +impl AsRawFd for TlsTcpStream { + fn as_raw_fd(&self) -> i32 { + match &self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.as_raw_fd(), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.as_raw_fd(), + } + } +} + +impl TlsTcpStream { + pub fn set_nodelay(&mut self, nodelay: bool) -> Result<()> { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.set_nodelay(nodelay), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.set_nodelay(nodelay), + } + } + + pub fn is_handshaking(&self) -> bool { + match &self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.is_handshaking(), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.is_handshaking(), + } + } + + pub fn interest(&self) -> Interest { + if self.is_handshaking() { + Interest::READABLE.add(Interest::WRITABLE) + } else { + Interest::READABLE + } + } + + /// Attempts to drive the TLS/SSL handshake to completion. If the return + /// variant is `Ok` it indiates that the handshake is complete. An error + /// result of `WouldBlock` indicates that the handshake may complete in the + /// future. Other error types indiate a handshake failure with no possible + /// recovery and that the connection should be closed. + pub fn do_handshake(&mut self) -> Result<()> { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.do_handshake(), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.do_handshake(), + } + } + + pub fn shutdown(&mut self) -> Result { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.shutdown().map(|v| v.into()), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.shutdown().map(|v| v.into()), + } + } +} + +impl Read for TlsTcpStream { + fn read(&mut self, buf: &mut [u8]) -> Result { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.read(buf), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.read(buf), + } + } +} + +impl Write for TlsTcpStream { + fn write(&mut self, buf: &[u8]) -> Result { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.write(buf), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.write(buf), + } + } + + fn flush(&mut self) -> Result<()> { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.flush(), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.flush(), + } + } +} + +impl event::Source for TlsTcpStream { + fn register(&mut self, registry: &Registry, token: Token, interest: Interest) -> Result<()> { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.register(registry, token, interest), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.register(registry, token, interest), + } + } + + fn reregister( + &mut self, + registry: &mio::Registry, + token: mio::Token, + interest: mio::Interest, + ) -> Result<()> { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.reregister(registry, token, interest), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.reregister(registry, token, interest), + } + } + + fn deregister(&mut self, registry: &mio::Registry) -> Result<()> { + match &mut self.inner { + #[cfg(feature = "boringssl")] + TlsTcpStreamImpl::Boringssl(s) => s.deregister(registry), + #[cfg(feature = "openssl")] + TlsTcpStreamImpl::Openssl(s) => s.deregister(registry), + } + } +} + +pub struct TlsTcpAcceptor { + inner: TlsTcpAcceptorImpl, +} + +enum TlsTcpAcceptorImpl { + #[cfg(feature = "boringssl")] + Boringssl(boringssl::TlsTcpAcceptor), + #[cfg(feature = "openssl")] + Openssl(openssl::TlsTcpAcceptor), +} + +impl TlsTcpAcceptor { + pub fn builder() -> TlsTcpAcceptorBuilder { + TlsTcpAcceptorBuilder::default() + } + + pub fn accept(&self, stream: TcpStream) -> Result { + match &self.inner { + #[cfg(feature = "boringssl")] + TlsTcpAcceptorImpl::Boringssl(s) => s.accept(stream).map(|s| TlsTcpStream { + inner: TlsTcpStreamImpl::Boringssl(s), + }), + #[cfg(feature = "openssl")] + TlsTcpAcceptorImpl::Openssl(s) => s.accept(stream).map(|s| TlsTcpStream { + inner: TlsTcpStreamImpl::Openssl(s), + }), + } + } +} + +/// Provides a wrapped builder for producing a `TlsAcceptor`. This has some +/// minor differences from the `boring::ssl::SslAcceptorBuilder` to provide +/// improved ergonomics. +#[derive(Default)] +pub struct TlsTcpAcceptorBuilder { + implementation: Implementation, + ca_file: Option, + certificate_file: Option, + certificate_chain_file: Option, + private_key_file: Option, +} + +impl TlsTcpAcceptorBuilder { + pub fn build(self) -> Result { + match self.implementation { + #[cfg(feature = "boringssl")] + Implementation::Boringssl => Ok(TlsTcpAcceptor { + inner: TlsTcpAcceptorImpl::Boringssl(boringssl::TlsTcpAcceptor::build(self)?), + }), + #[cfg(feature = "openssl")] + Implementation::Openssl => Ok(TlsTcpAcceptor { + inner: TlsTcpAcceptorImpl::Openssl(openssl::TlsTcpAcceptor::build(self)?), + }), + } + } + + /// Allows selection of the TLS/SSL implementation if this crate is built + /// with multiple implementations enabled. + pub fn implementation(mut self, implementation: Implementation) -> Self { + self.implementation = implementation; + self + } + + /// Load trusted root certificates from a file. + /// + /// The file should contain a sequence of PEM-formatted CA certificates. + pub fn ca_file>(mut self, file: P) -> Self { + self.ca_file = Some(file.as_ref().to_path_buf()); + self + } + + /// Load a leaf certificate from a file. + /// + /// This loads only a single PEM-formatted certificate from the file which + /// will be used as the leaf certifcate. + /// + /// Use `set_certificate_chain_file` to provide a complete certificate + /// chain. Use this with the `set_certifcate_chain_file` if the leaf + /// certifcate and remainder of the certificate chain are split across two + /// files. + pub fn certificate_file>(mut self, file: P) -> Self { + self.certificate_file = Some(file.as_ref().to_path_buf()); + self + } + + /// Load a certificate chain from a file. + /// + /// The file should contain a sequence of PEM-formatted certificates. If + /// used without `set_certificate_file` the provided file must contain the + /// leaf certificate and the complete chain of certificates up to and + /// including the trusted root certificate. If used with + /// `set_certificate_file`, this file must not contain the leaf certifcate + /// and will be treated as the complete chain of certificates up to and + /// including the trusted root certificate. + pub fn certificate_chain_file>(mut self, file: P) -> Self { + self.certificate_chain_file = Some(file.as_ref().to_path_buf()); + self + } + + /// Loads the private key from a PEM-formatted file. + pub fn private_key_file>(mut self, file: P) -> Self { + self.private_key_file = Some(file.as_ref().to_path_buf()); + self + } +} + +pub struct TlsTcpConnector { + inner: TlsTcpConnectorImpl, +} + +enum TlsTcpConnectorImpl { + #[cfg(feature = "boringssl")] + Boringssl(boringssl::TlsTcpConnector), + #[cfg(feature = "openssl")] + Openssl(openssl::TlsTcpConnector), +} + +impl TlsTcpConnector { + pub fn builder() -> TlsTcpConnectorBuilder { + TlsTcpConnectorBuilder::default() + } + + pub fn connect(&self, addr: A) -> Result { + match &self.inner { + #[cfg(feature = "boringssl")] + TlsTcpConnectorImpl::Boringssl(s) => s.connect(addr).map(|s| TlsTcpStream { + inner: TlsTcpStreamImpl::Boringssl(s), + }), + #[cfg(feature = "openssl")] + TlsTcpConnectorImpl::Openssl(s) => s.connect(addr).map(|s| TlsTcpStream { + inner: TlsTcpStreamImpl::Openssl(s), + }), + } + } +} + +#[derive(Default)] +pub struct TlsTcpConnectorBuilder { + implementation: Implementation, + ca_file: Option, + certificate_file: Option, + certificate_chain_file: Option, + private_key_file: Option, +} + +impl TlsTcpConnectorBuilder { + pub fn build(self) -> Result { + match self.implementation { + #[cfg(feature = "boringssl")] + Implementation::Boringssl => Ok(TlsTcpConnector { + inner: TlsTcpConnectorImpl::Boringssl(boringssl::TlsTcpConnector::build(self)?), + }), + #[cfg(feature = "openssl")] + Implementation::Openssl => Ok(TlsTcpConnector { + inner: TlsTcpConnectorImpl::Openssl(openssl::TlsTcpConnector::build(self)?), + }), + } + } + + /// Allows selection of the TLS/SSL implementation if this crate is built + /// with multiple implementations enabled. + pub fn implementation(mut self, implementation: Implementation) -> Self { + self.implementation = implementation; + self + } + + /// Load trusted root certificates from a file. + /// + /// The file should contain a sequence of PEM-formatted CA certificates. + pub fn ca_file>(mut self, file: P) -> Self { + self.ca_file = Some(file.as_ref().to_path_buf()); + self + } + + /// Load a leaf certificate from a file. + /// + /// This loads only a single PEM-formatted certificate from the file which + /// will be used as the leaf certifcate. + /// + /// Use `set_certificate_chain_file` to provide a complete certificate + /// chain. Use this with the `set_certifcate_chain_file` if the leaf + /// certifcate and remainder of the certificate chain are split across two + /// files. + pub fn certificate_file>(mut self, file: P) -> Self { + self.certificate_file = Some(file.as_ref().to_path_buf()); + self + } + + /// Load a certificate chain from a file. + /// + /// The file should contain a sequence of PEM-formatted certificates. If + /// used without `set_certificate_file` the provided file must contain the + /// leaf certificate and the complete chain of certificates up to and + /// including the trusted root certificate. If used with + /// `set_certificate_file`, this file must not contain the leaf certifcate + /// and will be treated as the complete chain of certificates up to and + /// including the trusted root certificate. + pub fn certificate_chain_file>(mut self, file: P) -> Self { + self.certificate_chain_file = Some(file.as_ref().to_path_buf()); + self + } + + /// Loads the private key from a PEM-formatted file. + pub fn private_key_file>(mut self, file: P) -> Self { + self.private_key_file = Some(file.as_ref().to_path_buf()); + self + } +} diff --git a/src/net/src/tls_tcp/openssl.rs b/src/net/src/tls_tcp/openssl.rs new file mode 100644 index 00000000..c11b3f72 --- /dev/null +++ b/src/net/src/tls_tcp/openssl.rs @@ -0,0 +1,561 @@ +// Copyright 2022 Twitter, Inc. +// Licensed under the Apache License, Version 2.0 +// http://www.apache.org/licenses/LICENSE-2.0 + +pub use ::openssl::ssl::ShutdownResult; + +use std::os::unix::prelude::AsRawFd; + +use ::openssl::ssl::{ErrorCode, Ssl, SslFiletype, SslMethod, SslStream}; +use ::openssl::x509::X509; +use foreign_types_shared_01::ForeignTypeRef; + +use crate::*; + +#[derive(PartialEq)] +enum TlsState { + Handshaking, + Negotiated, +} + +/// Wraps a TLS/SSL stream so that negotiated and handshaking sessions have a +/// uniform type. +pub struct TlsTcpStream { + inner: SslStream, + state: TlsState, +} + +impl AsRawFd for TlsTcpStream { + fn as_raw_fd(&self) -> i32 { + self.inner.get_ref().as_raw_fd() + } +} + +impl TlsTcpStream { + pub fn set_nodelay(&mut self, nodelay: bool) -> Result<()> { + self.inner.get_mut().set_nodelay(nodelay) + } + + pub fn is_handshaking(&self) -> bool { + self.state == TlsState::Handshaking + } + + /// Attempts to drive the TLS/SSL handshake to completion. If the return + /// variant is `Ok` it indiates that the handshake is complete. An error + /// result of `WouldBlock` indicates that the handshake may complete in the + /// future. Other error types indiate a handshake failure with no possible + /// recovery and that the connection should be closed. + pub fn do_handshake(&mut self) -> Result<()> { + if self.is_handshaking() { + let ptr = self.inner.ssl().as_ptr(); + let ret = unsafe { openssl_sys::SSL_do_handshake(ptr) }; + if ret > 0 { + STREAM_HANDSHAKE.increment(); + self.state = TlsState::Negotiated; + Ok(()) + } else { + let code = unsafe { ErrorCode::from_raw(openssl_sys::SSL_get_error(ptr, ret)) }; + match code { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { + Err(Error::from(ErrorKind::WouldBlock)) + } + _ => { + STREAM_HANDSHAKE.increment(); + STREAM_HANDSHAKE_EX.increment(); + Err(Error::new(ErrorKind::Other, "handshake failed")) + } + } + } + } else { + Ok(()) + } + } + + pub fn shutdown(&mut self) -> Result { + self.inner + .shutdown() + .map_err(|e| Error::new(ErrorKind::Other, e.to_string())) + } +} + +impl Debug for TlsTcpStream { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { + write!(f, "{:?}", self.inner.get_ref()) + } +} + +impl Read for TlsTcpStream { + fn read(&mut self, buf: &mut [u8]) -> Result { + if self.is_handshaking() { + Err(Error::new( + ErrorKind::WouldBlock, + "read on handshaking session would block", + )) + } else { + self.inner.read(buf) + } + } +} + +impl Write for TlsTcpStream { + fn write(&mut self, buf: &[u8]) -> Result { + if self.is_handshaking() { + Err(Error::new( + ErrorKind::WouldBlock, + "write on handshaking session would block", + )) + } else { + self.inner.write(buf) + } + } + + fn flush(&mut self) -> Result<()> { + if self.is_handshaking() { + Err(Error::new( + ErrorKind::WouldBlock, + "flush on handshaking session would block", + )) + } else { + self.inner.flush() + } + } +} + +impl event::Source for TlsTcpStream { + fn register(&mut self, registry: &Registry, token: Token, interest: Interest) -> Result<()> { + self.inner.get_mut().register(registry, token, interest) + } + + fn reregister( + &mut self, + registry: &mio::Registry, + token: mio::Token, + interest: mio::Interest, + ) -> Result<()> { + self.inner.get_mut().reregister(registry, token, interest) + } + + fn deregister(&mut self, registry: &mio::Registry) -> Result<()> { + self.inner.get_mut().deregister(registry) + } +} + +/// Provides a wrapped acceptor for server-side TLS. This returns our wrapped +/// `TlsStream` type so that clients can store negotiated and handshaking +/// streams in a structure with a uniform type. +pub struct TlsTcpAcceptor { + inner: ::openssl::ssl::SslContext, +} + +impl TlsTcpAcceptor { + pub fn build(builder: TlsTcpAcceptorBuilder) -> Result { + let mut acceptor = + ::openssl::ssl::SslAcceptor::mozilla_intermediate_v5(SslMethod::tls_client()) + .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?; + + // load the CA file, if provided + if let Some(f) = builder.ca_file { + acceptor.set_ca_file(f.clone()).map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load CA file: {}\n{}", f.display(), e), + ) + })?; + } + + // load the private key from file + if let Some(f) = builder.private_key_file { + acceptor + .set_private_key_file(f.clone(), SslFiletype::PEM) + .map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load private key file: {}\n{}", f.display(), e), + ) + })?; + } else { + return Err(Error::new(ErrorKind::Other, "no private key file provided")); + } + + // load the certificate chain, certificate file, or both + match (builder.certificate_chain_file, builder.certificate_file) { + (Some(chain), Some(cert)) => { + // assume we have the leaf in a standalone file, and the + // intermediates + root in another file + + // first load the leaf + acceptor + .set_certificate_file(cert.clone(), SslFiletype::PEM) + .map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load certificate file: {}\n{}", cert.display(), e), + ) + })?; + + // append the rest of the chain + let pem = std::fs::read(chain.clone()).map_err(|e| { + Error::new( + ErrorKind::Other, + format!( + "failed to load certificate chain file: {}\n{}", + chain.display(), + e + ), + ) + })?; + let cert_chain = X509::stack_from_pem(&pem).map_err(|e| { + Error::new( + ErrorKind::Other, + format!( + "failed to load certificate chain file: {}\n{}", + chain.display(), + e + ), + ) + })?; + for cert in cert_chain { + acceptor.add_extra_chain_cert(cert).map_err(|e| { + Error::new( + ErrorKind::Other, + format!( + "bad certificate in certificate chain file: {}\n{}", + chain.display(), + e + ), + ) + })?; + } + } + (Some(chain), None) => { + // assume we have a complete chain: leaf + intermediates + root in + // one file + + // load the entire chain + acceptor + .set_certificate_chain_file(chain.clone()) + .map_err(|e| { + Error::new( + ErrorKind::Other, + format!( + "failed to load certificate chain file: {}\n{}", + chain.display(), + e + ), + ) + })?; + } + (None, Some(cert)) => { + // this will just load the leaf certificate from the file + acceptor + .set_certificate_file(cert.clone(), SslFiletype::PEM) + .map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load certificate file: {}\n{}", cert.display(), e), + ) + })?; + } + (None, None) => { + return Err(Error::new( + ErrorKind::Other, + "no certificate file or certificate chain file provided", + )); + } + } + + let inner = acceptor.build().into_context(); + + Ok(TlsTcpAcceptor { inner }) + } + + pub fn accept(&self, stream: TcpStream) -> Result { + let ssl = Ssl::new(&self.inner)?; + + let stream = SslStream::new(ssl, stream)?; + + let ret = unsafe { openssl_sys::SSL_accept(stream.ssl().as_ptr()) }; + + if ret > 0 { + Ok(TlsTcpStream { + inner: stream, + state: TlsState::Negotiated, + }) + } else { + let code = unsafe { + ErrorCode::from_raw(openssl_sys::SSL_get_error(stream.ssl().as_ptr(), ret)) + }; + match code { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Ok(TlsTcpStream { + inner: stream, + state: TlsState::Handshaking, + }), + _ => Err(Error::new(ErrorKind::Other, "handshake failed")), + } + } + } +} + +/// Provides a wrapped connector for client-side TLS. This returns our wrapped +/// `TlsStream` type so that clients can store negotiated and handshaking +/// streams in a structure with a uniform type. +#[allow(dead_code)] +pub struct TlsTcpConnector { + inner: ::openssl::ssl::SslContext, +} + +impl TlsTcpConnector { + pub fn build(builder: TlsTcpConnectorBuilder) -> Result { + let mut connector = ::openssl::ssl::SslConnector::builder(SslMethod::tls_client()) + .map_err(|e| Error::new(ErrorKind::Other, e.to_string()))?; + + // load the CA file, if provided + if let Some(f) = builder.ca_file { + connector.set_ca_file(f).map_err(|e| { + Error::new(ErrorKind::Other, format!("failed to load CA file: {e}")) + })?; + } + + // load the private key from file + if let Some(f) = builder.private_key_file { + connector + .set_private_key_file(f, SslFiletype::PEM) + .map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load private key file: {e}"), + ) + })?; + } else { + return Err(Error::new(ErrorKind::Other, "no private key file provided")); + } + + // load the certificate chain, certificate file, or both + match (builder.certificate_chain_file, builder.certificate_file) { + (Some(chain), Some(cert)) => { + // assume we have the leaf in a standalone file, and the + // intermediates + root in another file + + // first load the leaf + connector + .set_certificate_file(cert, SslFiletype::PEM) + .map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load certificate file: {e}"), + ) + })?; + + // append the rest of the chain + let pem = std::fs::read(chain).map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load certificate chain file: {e}"), + ) + })?; + let chain = X509::stack_from_pem(&pem).map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load certificate chain file: {e}"), + ) + })?; + for cert in chain { + connector.add_extra_chain_cert(cert).map_err(|e| { + Error::new( + ErrorKind::Other, + format!("bad certificate in certificate chain file: {e}"), + ) + })?; + } + } + (Some(chain), None) => { + // assume we have a complete chain: leaf + intermediates + root in + // one file + + // load the entire chain + connector.set_certificate_chain_file(chain).map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load certificate chain file: {e}"), + ) + })?; + } + (None, Some(cert)) => { + // this will just load the leaf certificate from the file + connector + .set_certificate_file(cert, SslFiletype::PEM) + .map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to load certificate file: {e}"), + ) + })?; + } + (None, None) => { + return Err(Error::new( + ErrorKind::Other, + "no certificate file or certificate chain file provided", + )); + } + } + + let inner = connector.build().into_context(); + + Ok(TlsTcpConnector { inner }) + } + + pub fn connect(&self, addr: A) -> Result { + let addrs: Vec = addr.to_socket_addrs()?.collect(); + let mut s = Err(Error::new(ErrorKind::Other, "failed to resolve")); + for addr in addrs { + s = TcpStream::connect(addr); + if s.is_ok() { + break; + } + } + + let ssl = Ssl::new(&self.inner)?; + + let stream = SslStream::new(ssl, s?)?; + + let ret = unsafe { openssl_sys::SSL_connect(stream.ssl().as_ptr()) }; + + if ret > 0 { + Ok(TlsTcpStream { + inner: stream, + state: TlsState::Negotiated, + }) + } else { + let code = unsafe { + ErrorCode::from_raw(openssl_sys::SSL_get_error(stream.ssl().as_ptr(), ret)) + }; + match code { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Ok(TlsTcpStream { + inner: stream, + state: TlsState::Handshaking, + }), + _ => Err(Error::new(ErrorKind::Other, "handshake failed")), + } + } + } +} + +// NOTE: these tests only work if there's a `test` folder within this crate that +// contains the necessary keys and certs. They are left here for reference and +// in the future we should automate creation of self-signed keys and certs for +// use for testing during local development and in CI. + +// #[cfg(test)] +// mod tests { +// use super::*; + +// fn gen_keys() -> Result<(), ()> { + +// } + +// fn create_connector() -> Connector { +// let tls_connector = TlsTcpConnector::builder() +// .expect("failed to create builder") +// .ca_file("test/root.crt") +// .certificate_chain_file("test/client.crt") +// .private_key_file("test/client.key") +// .build() +// .expect("failed to initialize tls connector"); + +// Connector::from(tls_connector) +// } + +// fn create_listener(addr: &'static str) -> Listener { +// let tcp_listener = TcpListener::bind(addr).expect("failed to bind"); +// let tls_acceptor = TlsTcpAcceptor::mozilla_intermediate_v5() +// .expect("failed to create builder") +// .ca_file("test/root.crt") +// .certificate_chain_file("test/server.crt") +// .private_key_file("test/server.key") +// .build() +// .expect("failed to initialize tls acceptor"); + +// Listener::from((tcp_listener, tls_acceptor)) +// } + +// #[test] +// fn listener() { +// let _ = create_listener("127.0.0.1:0"); +// } + +// #[test] +// fn connector() { +// let _ = create_connector(); +// } + +// #[test] +// fn ping_pong() { +// let connector = create_connector(); +// let listener = create_listener("127.0.0.1:0"); + +// let addr = listener.local_addr().expect("listener has no local addr"); + +// let mut client_stream = connector.connect(addr).expect("failed to connect"); +// std::thread::sleep(std::time::Duration::from_millis(100)); +// let mut server_stream = listener.accept().expect("failed to accept"); + +// let mut server_handshake_complete = false; +// let mut client_handshake_complete = false; + +// while !(server_handshake_complete && client_handshake_complete) { +// if !server_handshake_complete { +// std::thread::sleep(std::time::Duration::from_millis(100)); +// if server_stream.do_handshake().is_ok() { +// server_handshake_complete = true; +// } +// } + +// if !client_handshake_complete { +// std::thread::sleep(std::time::Duration::from_millis(100)); +// if client_stream.do_handshake().is_ok() { +// client_handshake_complete = true; +// } +// } +// } + +// std::thread::sleep(std::time::Duration::from_millis(100)); + +// client_stream +// .write_all(b"PING\r\n") +// .expect("failed to write"); +// client_stream.flush().expect("failed to flush"); + +// std::thread::sleep(std::time::Duration::from_millis(100)); + +// let mut buf = [0; 4096]; + +// match server_stream.read(&mut buf) { +// Ok(6) => { +// assert_eq!(&buf[0..6], b"PING\r\n"); +// server_stream +// .write_all(b"PONG\r\n") +// .expect("failed to write"); +// } +// Ok(n) => { +// panic!("read: {} bytes but expected 6", n); +// } +// Err(e) => { +// panic!("error reading: {}", e); +// } +// } + +// std::thread::sleep(std::time::Duration::from_millis(100)); + +// match client_stream.read(&mut buf) { +// Ok(6) => { +// assert_eq!(&buf[0..6], b"PONG\r\n"); +// } +// Ok(n) => { +// panic!("read: {} bytes but expected 6", n); +// } +// Err(e) => { +// panic!("error reading: {}", e); +// } +// } +// } +// }