diff options
Diffstat (limited to 'vendor/rustls')
117 files changed, 0 insertions, 49352 deletions
diff --git a/vendor/rustls/.cargo-checksum.json b/vendor/rustls/.cargo-checksum.json deleted file mode 100644 index 441dc8f0..00000000 --- a/vendor/rustls/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.lock":"16463c44989ca7b3256ddb327730574dd03fa25ba4c117e92c26884a00f23ec9","Cargo.toml":"46f1cf9ca064bd16baf3416b8efff9a0d8f6e88935495dbd21cddf4c798f142a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-ISC":"7cfafc877eccc46c0e346ccbaa5c51bb6b894d2b818e617d970211e232785ad4","LICENSE-MIT":"709e3175b4212f7b13aa93971c9f62ff8c69ec45ad8c6532a7e0c41d7a7d6f8c","README.md":"1f3cec2c07d17bf1c3860fa6a692953fd456315134a1abe79ae4cc0c8cc1ca35","benches/benchmarks.rs":"251ec5926d31af7087308224ac3bcf2a58b3fb1965083da1c75779957e30cedf","build.rs":"380b9a051325baa7d4957bd9a4f1a637c27a663610b1b502f9524530f6995f4d","examples/internal/test_ca.rs":"bcb952d082cc46e53e8ef0ac547cda0cd990e7d36f0e9512448aa5ef4dd5e056","src/bs_debug.rs":"4e4ff4ee2d1db612ba7367e88ee587d525a973167c87b28bb2b35555a9eda27b","src/builder.rs":"3cfebc1faeb5e2b7fbb8ede68aca1240c7ba69061f3381a1a4ded87f11bf5d6a","src/check.rs":"8e5b8a35aebe931c60afa009159a398cf81f300c21898d2002fec88b42d13ad7","src/client/builder.rs":"dedb310e92f9bf837f2500bb9bc8bb3f02975477682232bc91801fe891a2048f","src/client/client_conn.rs":"beb8e4d6720370ab6696f082aede044e62e47e69246b044f5d1101691149b4ef","src/client/common.rs":"c745f89b8fd2381118dda319ab69c71a410212d879d380fb8205aa74ece52b48","src/client/ech.rs":"622eeccb85ea350b01e597821bc92fee8939f87c30c028cf043133a663cb9d89","src/client/handy.rs":"7137eeea1cbd8df5a8620e5934a2c3a6889d992caf45c5b13f33072c46ddefb1","src/client/hs.rs":"0b48abf24f0fc6093fe17b628a3d3989f6f35018e322d63d0b90c2066319d2a9","src/client/test.rs":"ca72f595d0f2c9ee713bf68ad647bbfaf402bfa19d7a6e610e98f57464b34221","src/client/tls12.rs":"39b2fd1c88d5b764cfc7f183f6dda7dcf38cf7384a17adfa3e26a5a5ff2d325d","src/client/tls13.rs":"e5db6db56ca31dbe270a4bfe7cf7c99929d05babb3760484baef8c9e1acad35e","src/common_state.rs":"d60d2790e97aee52667e8b9f18d25f3b6066cbcc6bed2e6153d2932525b6d0d5","src/compress.rs":"b3d5d65cd16f8ae98d0398697a4d86fbfb9a5a0db8243b553ea1d763992b5544","src/conn.rs":"72fad622038e07436da895faf2eaadc5a9b5e4fd2a1ac4d68d73ef47959da37c","src/conn/kernel.rs":"ecdbb41cd6e4aa95c33a16584723befe6b310754452174cee9ab201917ffb87e","src/conn/unbuffered.rs":"843c2eaa532cdce077cb6f33972d9da5149de0558d4aab86dddb7f5c59aa9d92","src/crypto/aws_lc_rs/hpke.rs":"9786831e6b839d52b91b5ba1b1bfc77cb1c859489e19ccfa7f84940dfc5c706e","src/crypto/aws_lc_rs/mod.rs":"e566e21c3a8f7aac1eba68ca195f51dea16127f79eb37b9f883eec1d2df7d32f","src/crypto/aws_lc_rs/pq/hybrid.rs":"a1ac53e228fe7bb6851b3a73b1ba4aa64f09bdbc77a09053f59ae89c8ea152b8","src/crypto/aws_lc_rs/pq/mlkem.rs":"c6b18343b1fb337e95994fb5d3ea473785bd681d383a215e81a232d46f6d5ef5","src/crypto/aws_lc_rs/pq/mod.rs":"4848bbd5780a2061c0bd0837312061a8bef131a1db1af8c025eb0195dba8a866","src/crypto/aws_lc_rs/sign.rs":"972f4deb09c5b64091bc9e16bd8062e39aceffb94bad5cc77ab58af066e35543","src/crypto/aws_lc_rs/ticketer.rs":"a16431d3ac21b944e6b43a78f930e13bd82603483b85cfa823f43f2a86eb0e32","src/crypto/aws_lc_rs/tls12.rs":"9e3a9220b68ce2a340d2289d376107bf4b75bc73319d1562c2800c5c01476d28","src/crypto/aws_lc_rs/tls13.rs":"e9998aa39049aa886c34c7ffb0da3b8d74388ce823bd310d07e1cd83b3559857","src/crypto/cipher.rs":"e2551ee5086adecd749e1cedc794398299104323ec14027b66e6d17c127f5ece","src/crypto/hash.rs":"eaa21b2d8f11afb9f5e41794e3461bcc18c950c53153d1fc37dfd23e3bdc1094","src/crypto/hmac.rs":"82ac9b1da0295b0ab70adec4ce321fb87d7873f530652a8b86397655042d035b","src/crypto/hpke.rs":"b65ace9c09cc0f83888c000b369376d8b8ca8a49e016d1aa0a9691c7921fdfbc","src/crypto/mod.rs":"d375a0ddf9da06669436fde13d9593e1dd400043348d0709466220bde0b73b6b","src/crypto/ring/hash.rs":"d4b594369971c8e8dc275a85beea83b51f5134174a4b37f620e130a51266d6ea","src/crypto/ring/hmac.rs":"7df8a4c33176c4e53306c23285ed965c9e35e0aebcc6fd03f1cd68759122ae94","src/crypto/ring/kx.rs":"d385431f42e76b7aa8bd0749ea256da268239d762114b40a37bee8306b07229d","src/crypto/ring/mod.rs":"b43827457ae0248f1ec3888464d40875f80e60b2d785e38517c79dda819b7675","src/crypto/ring/quic.rs":"73ced30aa8e5cf01578ca71f5546075557123d1dd7a73deb9579e93153f35a9c","src/crypto/ring/sign.rs":"6bb88454d5751ce1262d68c670ba41a52f88cd152b75d0740743ef603a43f650","src/crypto/ring/ticketer.rs":"2ec1193097d3032fc31dda08277cfb0fcb8defc6667af09d4ff1bd16be95eba4","src/crypto/ring/tls12.rs":"a3a65ebd7cf6fe7157dd19500d35ac7a948970fc64f94909ec4cc22e889e3a44","src/crypto/ring/tls13.rs":"2d093ce74d9ad824ed15f0a18abf5d845fd701a5b8de2d7db088e706dd49ab62","src/crypto/signer.rs":"3d99f11b9472eb7b316312cf94157edeb5d21ac189ed114450219f5bd60123f9","src/crypto/tls12.rs":"b729e02f64415570ba68fdde0a17cfaa60062f4d694001658b0467672a4e626d","src/crypto/tls13.rs":"feec69f36dcc738ccf735bc69e12a767857d8b52ad9af139b2b8584990b651d3","src/enums.rs":"807d39e7720ab3be31b7064fa2a67593d7246598edf6fe012f80a363afca417c","src/error.rs":"d85c232735d313be3661d564c2858fe26ebe72b203a127c3a681ef44d3c95ffd","src/hash_hs.rs":"6a03da8c8aea2f44f162843bc803a0dfb683b4b99137e5e5f5a6dd7978b02849","src/key_log.rs":"6aeb8c45365e6d53c51246fe8773243096b8c6806274cdcc3ffd1bb82fe360e9","src/key_log_file.rs":"9e781ef5e267b56afa0e70f7aeced53e5060814c71d4175741f076d5aa55fa4d","src/lib.rs":"1e1e14d37121fc3b2f3ddce24ae51f7f911d67b93a0fc968fde0db025a941eb8","src/limited_cache.rs":"a53eb38036ab1db04fe7c561d804076690631dedb17040eaa006f1264cfed097","src/lock.rs":"a4d9befd9a53e7dfbd7fb5d30ca16bcdd54e61f3fc9b353992cd45928818d70e","src/manual/defaults.rs":"71e854184d355b71a96280d82f3e83224491300e861655916d76f44325bf626a","src/manual/features.rs":"a7fecd590287388215fa6bcc6403f425897f3d4ea4f44b72a5dee9bfa2ee8345","src/manual/fips.rs":"50881a17d61c65cd855c1295572cd9b6381cf60008555b841b5e3bfca93dc712","src/manual/howto.rs":"df03dcc9abd0e8c11c13573680d43c84fd92876e4b128fb8bd881a58e07a0ae2","src/manual/implvulns.rs":"b42abb13ce142e83da012f7fa47759091c43216628abd46563de9910748efe5b","src/manual/mod.rs":"45e5d510140d668553030695a45e6ad50da2274e097e3e8fa8900446944a7576","src/manual/tlsvulns.rs":"9d2dc1d4f8f5703b67eb159d698325788863795848a246e36bef779dbba252be","src/msgs/alert.rs":"cf85febb6f1bd2719dd4767f6dea61468e2cee211f507956e93cfe79a9139afc","src/msgs/base.rs":"b6bb842fcfdf2d800e0594cb63c574663e335d4725dc870ee5fb26256f9eba64","src/msgs/ccs.rs":"61117e8e8cc2fb7b030360f959b66d6392d34a601f4ae1dc7276bb444462a742","src/msgs/codec.rs":"fa53201ef4387a453c626c37138a6a2de2d2ff13d85c0ec34f8b13ee20daeeaf","src/msgs/deframer/buffers.rs":"48bb18eff4e5859ec56aba8910488a791457afabc79feba0b09375e11bcca459","src/msgs/deframer/handshake.rs":"e7309acb70aa406dbd6c2c35c17e9d8fe036e9d24e4d29b362b37aa59bae9944","src/msgs/deframer/mod.rs":"bab59c49aa59b4d44e49928ab3aa6b58a5d167412585017bdae88cd32ce23847","src/msgs/enums.rs":"2366725846e1daa22481cfe5351d68199f833e88eb8d12095c00bc78fc77eb18","src/msgs/ffdhe_groups.rs":"22a2abdede92e082300998e0b0d49cc915a995713db2cdd811b4ff3502c1c619","src/msgs/fragmenter.rs":"c324f9ac144999ec36673736d0ef026122be9d4f6eb1f2908c01461cebe1122d","src/msgs/handshake.rs":"08219f5e36f75163f2c64e3dbf1a4506ef0d1266a42791e33863609225f0c3c8","src/msgs/handshake_test.rs":"bb73da98b08bfeea59762441c56a5aa0d9a17f30468ef5f6f87d8feb6cc1ef28","src/msgs/macros.rs":"2d4efa38989d480f8d36015d4487beedf9ec5e16aeacd3f9980d9ec61720890c","src/msgs/message/inbound.rs":"85c75ca765f5f7ce70b2f1afbb4d7a1568c1098e7be5267a16a4cb20b50b7ed5","src/msgs/message/mod.rs":"f1bdfa1ee08e31e54c85dd1c47d090afee672bd50bb6074aaa9c51d08feae3bf","src/msgs/message/outbound.rs":"fb214090aff53ea7228519feeac4444fa4b0f389c9af6dc062bf6efbe6c8a8ff","src/msgs/message_test.rs":"b3889ee3db6b8a28241fc1795209e2202f942445d8ec8ed0b08424ad6ad56dd0","src/msgs/mod.rs":"39c54a233a8bd46497c27b3e2626d8aee173d4c41ec8670386bb8c1f19249d07","src/msgs/persist.rs":"33ae762fe42981379082622bd66b2133e224cbaef012535834a4f2eeeaef9a72","src/polyfill.rs":"a6c6dcb5c42aa481099e60b85fd16d84559daa68bbef215c5cb02f93d5c65bec","src/quic.rs":"7bc4e28e1173b223b3242e8915383be0ae5476d73ad623280cd96cd00181a258","src/rand.rs":"c0c55d130516c8415836187c9050ecb5269ed7b51f65d70b40305f05f9ba57fb","src/record_layer.rs":"299c725f5bb3e032ecb17e9d1b228a1fa6fc580714c1470d5ff93c54592dc97d","src/server/builder.rs":"53cc5765fd1646c675a239f442fc212e8081369e0dfb1795aaed972d3e02a4a7","src/server/common.rs":"aef13bfc295f17218aa9b157f69c6fdfb9802ee90263acd43e880465a707bb20","src/server/handy.rs":"85ce7ea135eb5582703cb41eb8a5ec7d1d6b9266a130935d291eb71c1327394d","src/server/hs.rs":"5cfe9298ddf83d22786870460dd22b803d450ae4f0cc13e1e83c67512a24838f","src/server/server_conn.rs":"6ae7036a0ffe9c9d4c579e4aea33fa2be7ebf8056b9ad0417f31a64996559be6","src/server/test.rs":"c51e092a1e0bb8721bc66dc2a6de33ba173603f1cb51dab6b422f24c6b0d8f1c","src/server/tls12.rs":"4db5408886f09341063bde2d143f3bc29c2e4456c942fd1d16309dd4bcd3371c","src/server/tls13.rs":"a399e36edbda2f10d2b1e000d30555a4d8e23a40969d3121895bcb2f2be9758c","src/stream.rs":"00e4d9671226311ee50840a00a9e70d0921838a8a780aca6b78e4e208822d5e4","src/suites.rs":"82f697a876e4dcd720d2317d2ffd807c2ff79c081a4de3f2acf3fdf850b18980","src/test_macros.rs":"e5f98aa388375cc195cef7bae2cdba8b33c795ce48e8ff228fbfef153a493c47","src/ticketer.rs":"b722e6be43f8920ca495e4a3cbd624a4e69d61e1ad7584cfae0d8bc06429290a","src/time_provider.rs":"cdc75369bb353ca1edfb1d700a6467e42779c1c0cba5d5bd7d9f67f392ea92b1","src/tls12/mod.rs":"159fb6a519534986e1d1fd2326d30ffa0422650d9fe636c3dac8a5bd113c7c8b","src/tls13/key_schedule.rs":"dfe3a46dc72f4b175c70f0e0504819697a4876eed1e68715348d3f30585185cf","src/tls13/mod.rs":"f22e73dd261d1cc94076a9d3e0147352d7aa4c86872566bb79c93a8ad9f1c1a7","src/vecbuf.rs":"e8941e43ff21527ca3e8f6c9a9dc8526fab2e9a2676acb29065f075f98b622d6","src/verify.rs":"ba9dbc12548b0a1d3813e5c51b54ce2073fe6a87aaca9f6368185fb452add659","src/verifybench.rs":"5e4bd4bc5e2b93e4ee2f7f15b552e10c1c2f4bde7e60d44f426a0fc97f7b5d71","src/versions.rs":"125d9981b8c02ed6dcbabfdd76721fef3537f41d424ac1fb79e088331061fb22","src/webpki/anchors.rs":"82011d21d85376f695044157dbb0659ac42bbf8dcbf671e6c19e6e6bc355c9b7","src/webpki/client_verifier.rs":"c6051e79858a70ce746fb55208751a429c691c1bb76bcaca238be310ae11d652","src/webpki/mod.rs":"96075da2044ee4d89ba5647d832bfad06a35a2aa628924e9ed3570d06bc56e2f","src/webpki/server_verifier.rs":"1678d02f7fa352b990915de691959e1d90309ba631b714992afd1e98600cb301","src/webpki/verify.rs":"fcbc90dc30793cbe7f15f363fda793d6e08a132a82d003c1f9e88019a6e1f2b4","src/x509.rs":"e036e80ceb688d1b7ff2ff82a63e99545678b262cf5af0c331fbebc714db4444"},"package":"2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"}
\ No newline at end of file diff --git a/vendor/rustls/Cargo.lock b/vendor/rustls/Cargo.lock deleted file mode 100644 index 29fb7bfa..00000000 --- a/vendor/rustls/Cargo.lock +++ /dev/null @@ -1,1131 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "anstream" -version = "0.6.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.59.0", -] - -[[package]] -name = "asn1-rs" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56624a96882bb8c26d61312ae18cb45868e5a9992ea73c58e45c3101e56a1e60" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "aws-lc-fips-sys" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e99d74bb793a19f542ae870a6edafbc5ecf0bc0ba01d4636b7f7e0aba9ee9bd3" -dependencies = [ - "bindgen", - "cc", - "cmake", - "dunce", - "fs_extra", - "regex", -] - -[[package]] -name = "aws-lc-rs" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fcc8f365936c834db5514fc45aee5b1202d677e6b40e48468aaaa8183ca8c7" -dependencies = [ - "aws-lc-fips-sys", - "aws-lc-sys", - "zeroize", -] - -[[package]] -name = "aws-lc-sys" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b1d86e7705efe1be1b569bab41d4fa1e14e220b60a160f78de2db687add079" -dependencies = [ - "bindgen", - "cc", - "cmake", - "dunce", - "fs_extra", -] - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bencher" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfdb4953a096c551ce9ace855a604d702e6e62d77fac690575ae347571717f5" - -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", - "which", -] - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "brotli" -version = "8.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "cc" -version = "1.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "der-parser" -version = "10.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint", - "num-traits", - "rusticata-macros", -] - -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "env_filter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - -[[package]] -name = "errno" -version = "0.3.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "fs_extra" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "hashbrown" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" -dependencies = [ - "foldhash", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jiff" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom 0.3.3", - "libc", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "libloading" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" -dependencies = [ - "cfg-if", - "windows-targets", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "macro_rules_attribute" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65049d7923698040cd0b1ddcced9b0eb14dd22c5f86ae59c3740eab64a676520" -dependencies = [ - "macro_rules_attribute-proc_macro", - "paste", -] - -[[package]] -name = "macro_rules_attribute-proc_macro" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670fdfda89751bc4a84ac13eaa63e205cf0fd22b4c9a5fbfa085b63c1f1d3a30" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "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.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "oid-registry" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" -dependencies = [ - "asn1-rs", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pem" -version = "3.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" -dependencies = [ - "base64", - "serde", -] - -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "prettyplease" -version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dee91521343f4c5c6a63edd65e54f31f5c92fe8978c40a4282f8372194c6a7d" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "rcgen" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "218a7fbb357f6da42c9fd3610b1a5128d087d460e5386eaa5040705c464611dc" -dependencies = [ - "aws-lc-rs", - "pem", - "rustls-pki-types", - "time", - "yasna", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rusticata-macros" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" -dependencies = [ - "nom", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls" -version = "0.23.29" -dependencies = [ - "aws-lc-rs", - "base64", - "bencher", - "brotli", - "brotli-decompressor", - "env_logger", - "hashbrown", - "hex", - "log", - "macro_rules_attribute", - "num-bigint", - "once_cell", - "rcgen", - "ring", - "rustls-pki-types", - "rustls-webpki", - "rustversion", - "serde", - "serde_json", - "subtle", - "time", - "webpki-roots", - "x509-parser", - "zeroize", - "zlib-rs", -] - -[[package]] -name = "rustls-pki-types" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" -dependencies = [ - "aws-lc-rs", - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "webpki-roots" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2853738d1cc4f2da3a225c18ec6c3721abb31961096e9dbf5ab35fa88b19cfdb" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "x509-parser" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569f339c0c402346d4a75a9e39cf8dad310e287eef1ff56d4c68e5067f53460" -dependencies = [ - "asn1-rs", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror", - "time", -] - -[[package]] -name = "yasna" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" -dependencies = [ - "time", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zlib-rs" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626bd9fa9734751fc50d6060752170984d7053f5a39061f524cda68023d4db8a" diff --git a/vendor/rustls/Cargo.toml b/vendor/rustls/Cargo.toml deleted file mode 100644 index a7504ff5..00000000 --- a/vendor/rustls/Cargo.toml +++ /dev/null @@ -1,233 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies. -# -# If you are reading this file be aware that the original Cargo.toml -# will likely look very different (and much more reasonable). -# See Cargo.toml.orig for the original contents. - -[package] -edition = "2021" -rust-version = "1.71" -name = "rustls" -version = "0.23.29" -build = "build.rs" -exclude = [ - "src/testdata", - "tests/**", -] -autolib = false -autobins = false -autoexamples = false -autotests = false -autobenches = false -description = "Rustls is a modern TLS library written in Rust." -homepage = "https://github.com/rustls/rustls" -readme = "README.md" -categories = [ - "network-programming", - "cryptography", -] -license = "Apache-2.0 OR ISC OR MIT" -repository = "https://github.com/rustls/rustls" - -[package.metadata.cargo-semver-checks.lints] -enum_no_repr_variant_discriminant_changed = "warn" - -[package.metadata.cargo_check_external_types] -allowed_external_types = [ - "rustls_pki_types", - "rustls_pki_types::*", -] - -[package.metadata.docs.rs] -features = [ - "read_buf", - "ring", -] -rustdoc-args = [ - "--cfg", - "docsrs", -] - -[features] -aws-lc-rs = ["aws_lc_rs"] -aws_lc_rs = [ - "dep:aws-lc-rs", - "webpki/aws-lc-rs", - "aws-lc-rs/aws-lc-sys", - "aws-lc-rs/prebuilt-nasm", -] -brotli = [ - "dep:brotli", - "dep:brotli-decompressor", - "std", -] -custom-provider = [] -default = [ - "aws_lc_rs", - "logging", - "prefer-post-quantum", - "std", - "tls12", -] -fips = [ - "aws_lc_rs", - "aws-lc-rs?/fips", - "webpki/aws-lc-rs-fips", -] -logging = ["log"] -prefer-post-quantum = ["aws_lc_rs"] -read_buf = [ - "rustversion", - "std", -] -ring = [ - "dep:ring", - "webpki/ring", -] -std = [ - "webpki/std", - "pki-types/std", - "once_cell/std", -] -tls12 = [] -zlib = ["dep:zlib-rs"] - -[lib] -name = "rustls" -path = "src/lib.rs" - -[[example]] -name = "test_ca" -path = "examples/internal/test_ca.rs" - -[[bench]] -name = "benchmarks" -path = "benches/benchmarks.rs" -harness = false -required-features = ["ring"] - -[dependencies.aws-lc-rs] -version = "1.12" -optional = true -default-features = false - -[dependencies.brotli] -version = "8" -features = ["std"] -optional = true -default-features = false - -[dependencies.brotli-decompressor] -version = "5.0.0" -optional = true - -[dependencies.hashbrown] -version = "0.15" -features = [ - "default-hasher", - "inline-more", -] -optional = true -default-features = false - -[dependencies.log] -version = "0.4.8" -optional = true - -[dependencies.once_cell] -version = "1.16" -features = [ - "alloc", - "race", -] -default-features = false - -[dependencies.pki-types] -version = "1.12" -features = ["alloc"] -package = "rustls-pki-types" - -[dependencies.ring] -version = "0.17" -optional = true - -[dependencies.subtle] -version = "2.5.0" -default-features = false - -[dependencies.webpki] -version = "0.103.4" -features = ["alloc"] -default-features = false -package = "rustls-webpki" - -[dependencies.zeroize] -version = "1.7" - -[dependencies.zlib-rs] -version = "0.5" -optional = true - -[dev-dependencies.base64] -version = "0.22" - -[dev-dependencies.bencher] -version = "0.1.5" - -[dev-dependencies.env_logger] -version = "0.11" - -[dev-dependencies.hex] -version = "0.4" - -[dev-dependencies.log] -version = "0.4.8" - -[dev-dependencies.macro_rules_attribute] -version = "0.2" - -[dev-dependencies.num-bigint] -version = "0.4.4" - -[dev-dependencies.rcgen] -version = "0.14" -features = [ - "pem", - "aws_lc_rs", -] -default-features = false - -[dev-dependencies.serde] -version = "1" -features = ["derive"] - -[dev-dependencies.serde_json] -version = "1" - -[dev-dependencies.time] -version = "0.3.6" -default-features = false - -[dev-dependencies.webpki-roots] -version = "1" - -[dev-dependencies.x509-parser] -version = "0.17" - -[build-dependencies.rustversion] -version = "1.0.6" -optional = true - -[lints.rust.unexpected_cfgs] -level = "warn" -priority = 0 -check-cfg = [ - "cfg(bench)", - "cfg(coverage_nightly)", - "cfg(read_buf)", -] diff --git a/vendor/rustls/LICENSE-APACHE b/vendor/rustls/LICENSE-APACHE deleted file mode 100644 index 16fe87b0..00000000 --- a/vendor/rustls/LICENSE-APACHE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright [yyyy] [name of copyright owner] - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/vendor/rustls/LICENSE-ISC b/vendor/rustls/LICENSE-ISC deleted file mode 100644 index 03acf1bd..00000000 --- a/vendor/rustls/LICENSE-ISC +++ /dev/null @@ -1,15 +0,0 @@ -ISC License (ISC) -Copyright (c) 2016, Joseph Birr-Pixton <jpixton@gmail.com> - -Permission to use, copy, modify, and/or distribute this software for -any purpose with or without fee is hereby granted, provided that the -above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL -WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE -AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL -DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR -PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. diff --git a/vendor/rustls/LICENSE-MIT b/vendor/rustls/LICENSE-MIT deleted file mode 100644 index ef480e6f..00000000 --- a/vendor/rustls/LICENSE-MIT +++ /dev/null @@ -1,25 +0,0 @@ -Copyright (c) 2016 Joseph Birr-Pixton <jpixton@gmail.com> - -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/vendor/rustls/README.md b/vendor/rustls/README.md deleted file mode 100644 index 5b8f0124..00000000 --- a/vendor/rustls/README.md +++ /dev/null @@ -1,222 +0,0 @@ -<p align="center"> - <img width="460" height="300" src="https://raw.githubusercontent.com/rustls/rustls/main/admin/rustls-logo-web.png"> -</p> - -<p align="center"> -Rustls is a modern TLS library written in Rust. -</p> - -# Status - -Rustls is used in production at many organizations and projects. We aim to maintain -reasonable API surface stability but the API may evolve as we make changes to accommodate -new features or performance improvements. - -We have a [roadmap](ROADMAP.md) for our future plans. We also have [benchmarks](BENCHMARKING.md) to -prevent performance regressions and to let you evaluate rustls on your target hardware. - -If you'd like to help out, please see [CONTRIBUTING.md](CONTRIBUTING.md). - -[](https://github.com/rustls/rustls/actions/workflows/build.yml?query=branch%3Amain) -[](https://codecov.io/gh/rustls/rustls/) -[](https://docs.rs/rustls/) -[](https://discord.gg/MCSB76RU96) -[](https://www.bestpractices.dev/projects/9034) - -## Changelog - -The detailed list of changes in each release can be found at -https://github.com/rustls/rustls/releases. - -# Documentation - -https://docs.rs/rustls/ - -# Approach - -Rustls is a TLS library that aims to provide a good level of cryptographic security, -requires no configuration to achieve that security, and provides no unsafe features or -obsolete cryptography by default. - -Rustls implements TLS1.2 and TLS1.3 for both clients and servers. See [the full -list of protocol features](https://docs.rs/rustls/latest/rustls/manual/_04_features/index.html). - -### Platform support - -While Rustls itself is platform independent, by default it uses [`aws-lc-rs`] for implementing -the cryptography in TLS. See [the aws-lc-rs FAQ][aws-lc-rs-platforms-faq] for more details of the -platform/architecture support constraints in aws-lc-rs. - -[`ring`] is also available via the `ring` crate feature: see -[the supported `ring` target platforms][ring-target-platforms]. - -By providing a custom instance of the [`crypto::CryptoProvider`] struct, you -can replace all cryptography dependencies of rustls. This is a route to being portable -to a wider set of architectures and environments, or compliance requirements. See the -[`crypto::CryptoProvider`] documentation for more details. - -Specifying `default-features = false` when depending on rustls will remove the implicit -dependency on aws-lc-rs. - -Rustls requires Rust 1.71 or later. It has an optional dependency on zlib-rs which requires 1.75 or later. - -[ring-target-platforms]: https://github.com/briansmith/ring/blob/2e8363b433fa3b3962c877d9ed2e9145612f3160/include/ring-core/target.h#L18-L64 -[`crypto::CryptoProvider`]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html -[`ring`]: https://crates.io/crates/ring -[aws-lc-rs-platforms-faq]: https://aws.github.io/aws-lc-rs/faq.html#can-i-run-aws-lc-rs-on-x-platform-or-architecture -[`aws-lc-rs`]: https://crates.io/crates/aws-lc-rs - -### Cryptography providers - -Since Rustls 0.22 it has been possible to choose the provider of the cryptographic primitives -that Rustls uses. This may be appealing if you have specific platform, compliance or feature -requirements that aren't met by the default provider, [`aws-lc-rs`]. - -Users that wish to customize the provider in use can do so when constructing `ClientConfig` -and `ServerConfig` instances using the `with_crypto_provider` method on the respective config -builder types. See the [`crypto::CryptoProvider`] documentation for more details. - -#### Built-in providers - -Rustls ships with two built-in providers controlled by associated crate features: - -* [`aws-lc-rs`] - enabled by default, available with the `aws_lc_rs` crate feature enabled. -* [`ring`] - available with the `ring` crate feature enabled. - -See the documentation for [`crypto::CryptoProvider`] for details on how providers are -selected. - -#### Third-party providers - -The community has also started developing third-party providers for Rustls: - -* [`boring-rustls-provider`] - a work-in-progress provider that uses [`boringssl`] for -cryptography. -* [`rustls-graviola`] - a provider that uses [`graviola`] for cryptography. -* [`rustls-mbedtls-provider`] - a provider that uses [`mbedtls`] for cryptography. -* [`rustls-openssl`] - a provider that uses [OpenSSL] for cryptography. -* [`rustls-rustcrypto`] - an experimental provider that uses the crypto primitives -from [`RustCrypto`] for cryptography. -* [`rustls-symcrypt`] - a provider that uses Microsoft's [SymCrypt] library. -* [`rustls-wolfcrypt-provider`] - a work-in-progress provider that uses [`wolfCrypt`] for cryptography. - -[`rustls-graviola`]: https://crates.io/crates/rustls-graviola -[`graviola`]: https://github.com/ctz/graviola -[`rustls-mbedtls-provider`]: https://github.com/fortanix/rustls-mbedtls-provider -[`mbedtls`]: https://github.com/Mbed-TLS/mbedtls -[`rustls-openssl`]: https://github.com/tofay/rustls-openssl -[OpenSSL]: https://openssl-library.org/ -[`rustls-symcrypt`]: https://github.com/microsoft/rustls-symcrypt -[SymCrypt]: https://github.com/microsoft/SymCrypt -[`boring-rustls-provider`]: https://github.com/janrueth/boring-rustls-provider -[`boringssl`]: https://github.com/google/boringssl -[`rustls-rustcrypto`]: https://github.com/RustCrypto/rustls-rustcrypto -[`RustCrypto`]: https://github.com/RustCrypto -[`rustls-wolfcrypt-provider`]: https://github.com/wolfSSL/rustls-wolfcrypt-provider -[`wolfCrypt`]: https://www.wolfssl.com/products/wolfcrypt - -#### Custom provider - -We also provide a simple example of writing your own provider in the [custom provider example]. -This example implements a minimal provider using parts of the [`RustCrypto`] ecosystem. - -See the [Making a custom CryptoProvider] section of the documentation for more information -on this topic. - -[custom provider example]: https://github.com/rustls/rustls/tree/main/provider-example/ -[`RustCrypto`]: https://github.com/RustCrypto -[Making a custom CryptoProvider]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html#making-a-custom-cryptoprovider - -# Example code - -Our [examples] directory contains demos that show how to handle I/O using the -[`stream::Stream`] helper, as well as more complex asynchronous I/O using [`mio`]. -If you're already using Tokio for an async runtime you may prefer to use -[`tokio-rustls`] instead of interacting with rustls directly. - -The [`mio`] based examples are the most complete, and discussed below. Users -new to Rustls may prefer to look at the simple client/server examples before -diving in to the more complex MIO examples. - -[examples]: examples/ -[`stream::Stream`]: https://docs.rs/rustls/latest/rustls/struct.Stream.html -[`mio`]: https://docs.rs/mio/latest/mio/ -[`tokio-rustls`]: https://docs.rs/tokio-rustls/latest/tokio_rustls/ - -## Client example program - -The MIO client example program is named `tlsclient-mio`. - -Some sample runs: - -``` -$ cargo run --bin tlsclient-mio -- --http mozilla-modern.badssl.com -HTTP/1.1 200 OK -Server: nginx/1.6.2 (Ubuntu) -Date: Wed, 01 Jun 2016 18:44:00 GMT -Content-Type: text/html -Content-Length: 644 -(...) -``` - -or - -``` -$ cargo run --bin tlsclient-mio -- --http expired.badssl.com -TLS error: InvalidCertificate(Expired) -Connection closed -``` - -Run `cargo run --bin tlsclient-mio -- --help` for more options. - -## Server example program - -The MIO server example program is named `tlsserver-mio`. - -Here's a sample run; we start a TLS echo server, then connect to it with -`openssl` and `tlsclient-mio`: - -``` -$ cargo run --bin tlsserver-mio -- --certs test-ca/rsa-2048/end.fullchain --key test-ca/rsa-2048/end.key -p 8443 echo & -$ echo hello world | openssl s_client -ign_eof -quiet -connect localhost:8443 -depth=2 CN = ponytown RSA CA -verify error:num=19:self signed certificate in certificate chain -hello world -^C -$ echo hello world | cargo run --bin tlsclient-mio -- --cafile test-ca/rsa-2048/ca.cert --port 8443 localhost -hello world -^C -``` - -Run `cargo run --bin tlsserver-mio -- --help` for more options. - -# License - -Rustls is distributed under the following three licenses: - -- Apache License version 2.0. -- MIT license. -- ISC license. - -These are included as LICENSE-APACHE, LICENSE-MIT and LICENSE-ISC -respectively. You may use this software under the terms of any -of these licenses, at your option. - -# Project Membership - -- Joe Birr-Pixton ([@ctz], Project Founder - full-time funded by [Prossimo]) -- Dirkjan Ochtman ([@djc], Co-maintainer) -- Daniel McCarney ([@cpu], Co-maintainer) -- Josh Aas ([@bdaehlie], Project Management) - -[@ctz]: https://github.com/ctz -[@djc]: https://github.com/djc -[@cpu]: https://github.com/cpu -[@bdaehlie]: https://github.com/bdaehlie -[Prossimo]: https://www.memorysafety.org/initiative/rustls/ - -# Code of conduct - -This project adopts the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct). -Please email rustls-mod@googlegroups.com to report any instance of misconduct, or if you -have any comments or questions on the Code of Conduct. diff --git a/vendor/rustls/benches/benchmarks.rs b/vendor/rustls/benches/benchmarks.rs deleted file mode 100644 index 5aebc995..00000000 --- a/vendor/rustls/benches/benchmarks.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![cfg(feature = "ring")] -#![allow(clippy::disallowed_types)] - -use std::io; -use std::sync::Arc; - -use bencher::{Bencher, benchmark_group, benchmark_main}; -use rustls::ServerConnection; -use rustls::crypto::ring as provider; -use rustls_test::{FailsReads, KeyType, make_server_config}; - -fn bench_ewouldblock(c: &mut Bencher) { - let server_config = make_server_config(KeyType::Rsa2048, &provider::default_provider()); - let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); - let mut read_ewouldblock = FailsReads::new(io::ErrorKind::WouldBlock); - c.iter(|| server.read_tls(&mut read_ewouldblock)); -} - -benchmark_group!(benches, bench_ewouldblock); -benchmark_main!(benches); diff --git a/vendor/rustls/build.rs b/vendor/rustls/build.rs deleted file mode 100644 index 8c0bd2aa..00000000 --- a/vendor/rustls/build.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! This build script allows us to enable the `read_buf` language feature only -//! for Rust Nightly. -//! -//! See the comment in lib.rs to understand why we need this. - -#[cfg_attr(feature = "read_buf", rustversion::not(nightly))] -fn main() {} - -#[cfg(feature = "read_buf")] -#[rustversion::nightly] -fn main() { - println!("cargo:rustc-cfg=read_buf"); -} diff --git a/vendor/rustls/examples/internal/test_ca.rs b/vendor/rustls/examples/internal/test_ca.rs deleted file mode 100644 index 1df38484..00000000 --- a/vendor/rustls/examples/internal/test_ca.rs +++ /dev/null @@ -1,352 +0,0 @@ -use std::collections::HashMap; -use std::env; -use std::fs::{self, File}; -use std::io::Write; -use std::net::IpAddr; -use std::path::PathBuf; -use std::str::FromStr; -use std::sync::atomic::{AtomicU64, Ordering}; -use std::time::Duration; - -use rcgen::string::Ia5String; -use rcgen::{ - BasicConstraints, Certificate, CertificateParams, CertificateRevocationListParams, - DistinguishedName, DnType, ExtendedKeyUsagePurpose, IsCa, Issuer, KeyIdMethod, KeyPair, - KeyUsagePurpose, PKCS_ECDSA_P256_SHA256, PKCS_ECDSA_P384_SHA384, PKCS_ECDSA_P521_SHA512, - PKCS_ED25519, PKCS_RSA_SHA256, PKCS_RSA_SHA384, PKCS_RSA_SHA512, RevocationReason, - RevokedCertParams, RsaKeySize, SanType, SerialNumber, SignatureAlgorithm, -}; -use time::OffsetDateTime; - -fn main() -> Result<(), Box<dyn std::error::Error>> { - let mut certified_keys = HashMap::< - (Role, &'static SignatureAlgorithm), - (Issuer<'static, KeyPair>, Certificate), - >::with_capacity(ROLES.len() * SIG_ALGS.len()); - - for role in ROLES { - for alg in SIG_ALGS { - // Generate a key pair and serialize it to a PEM encoded file. - let key_pair = alg.key_pair(); - let mut key_pair_file = File::create(role.key_file_path(alg))?; - key_pair_file.write_all(key_pair.serialize_pem().as_bytes())?; - - // Issue a certificate for the key pair. For trust anchors, this will be self-signed. - // Otherwise we dig out the issuer and issuer_key for the issuer, which should have - // been produced in earlier iterations based on the careful ordering of roles. - let (params, cert) = match role { - Role::TrustAnchor => { - let params = role.params(alg); - let cert = params.self_signed(&key_pair)?; - (params, cert) - } - Role::Intermediate => { - let issuer = certified_keys - .get(&(Role::TrustAnchor, alg.inner)) - .unwrap(); - let params = role.params(alg); - let cert = params.signed_by(&key_pair, &issuer.0)?; - (params, cert) - } - Role::EndEntity | Role::Client => { - let issuer = certified_keys - .get(&(Role::Intermediate, alg.inner)) - .unwrap(); - let params = role.params(alg); - let cert = params.signed_by(&key_pair, &issuer.0)?; - (params, cert) - } - }; - - // Serialize the issued certificate to a PEM encoded file. - let mut cert_file = File::create(role.cert_pem_file_path(alg))?; - cert_file.write_all(cert.pem().as_bytes())?; - // And to a DER encoded file. - let mut cert_file = File::create(role.cert_der_file_path(alg))?; - cert_file.write_all(cert.der())?; - - // If we're not a trust anchor, generate a CRL for the certificate we just issued. - if role != Role::TrustAnchor { - // The CRL will be signed by the issuer of the certificate being revoked. For - // intermediates this will be the trust anchor, and for client/EE certs this will - // be the intermediate. - let issuer = match role { - Role::Intermediate => certified_keys - .get(&(Role::TrustAnchor, alg.inner)) - .unwrap(), - Role::EndEntity | Role::Client => certified_keys - .get(&(Role::Intermediate, alg.inner)) - .unwrap(), - _ => panic!("unexpected role for CRL generation: {role:?}"), - }; - - let revoked_crl = - crl_for_serial(params.serial_number.clone().unwrap()).signed_by(&issuer.0)?; - let mut revoked_crl_file = File::create( - alg.output_directory() - .join(format!("{}.revoked.crl.pem", role.label())), - )?; - revoked_crl_file.write_all(revoked_crl.pem().unwrap().as_bytes())?; - - let expired_crl = expired_crl().signed_by(&issuer.0)?; - let mut expired_crl_file = File::create( - alg.output_directory() - .join(format!("{}.expired.crl.pem", role.label())), - )?; - expired_crl_file.write_all(expired_crl.pem().unwrap().as_bytes())?; - } - - // When we're issuing end entity or client certs we have a bit of extra work to do - // now that we have full chains in hand. - if matches!(role, Role::EndEntity | Role::Client) { - let root = &certified_keys - .get(&(Role::TrustAnchor, alg.inner)) - .unwrap() - .1; - let intermediate = &certified_keys - .get(&(Role::Intermediate, alg.inner)) - .unwrap() - .1; - - // Write the PEM chain and full chain files for the end entity and client certs. - // Chain files include the intermediate and root certs, while full chain files include - // the end entity or client cert as well. - for f in [ - ("chain", &[intermediate, root][..]), - ("fullchain", &[&cert, intermediate, root][..]), - ] { - let mut chain_file = File::create(alg.output_directory().join(format!( - "{}.{}", - role.label(), - f.0 - )))?; - for cert in f.1 { - chain_file.write_all(cert.pem().as_bytes())?; - } - } - - // Write the PEM public key for the end entity and client. - let mut raw_public_key_file = File::create( - alg.output_directory() - .join(format!("{}.spki.pem", role.label())), - )?; - raw_public_key_file.write_all(key_pair.public_key_pem().as_bytes())?; - } - - certified_keys.insert((role, alg.inner), (Issuer::new(params, key_pair), cert)); - } - } - - Ok(()) -} - -fn crl_for_serial(serial_number: SerialNumber) -> CertificateRevocationListParams { - let now = OffsetDateTime::now_utc(); - CertificateRevocationListParams { - this_update: now, - next_update: now + Duration::from_secs(60 * 60 * 24 * 365 * 100), // 100 years - crl_number: SerialNumber::from(1234), - issuing_distribution_point: None, - revoked_certs: vec![RevokedCertParams { - serial_number, - revocation_time: now, - reason_code: Some(RevocationReason::KeyCompromise), - invalidity_date: None, - }], - key_identifier_method: KeyIdMethod::Sha256, - } -} - -fn expired_crl() -> CertificateRevocationListParams { - let now = OffsetDateTime::now_utc(); - CertificateRevocationListParams { - this_update: now - Duration::from_secs(60), - next_update: now, - crl_number: SerialNumber::from(1234), - issuing_distribution_point: None, - revoked_certs: vec![], - key_identifier_method: KeyIdMethod::Sha256, - } -} - -// Note: these are ordered such that the data dependencies for issuance are satisfied. -const ROLES: [Role; 4] = [ - Role::TrustAnchor, - Role::Intermediate, - Role::EndEntity, - Role::Client, -]; - -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -enum Role { - Client, - EndEntity, - Intermediate, - TrustAnchor, -} - -impl Role { - fn params(&self, alg: &'static SigAlgContext) -> CertificateParams { - let mut params = CertificateParams::default(); - params.distinguished_name = self.common_name(alg); - params.use_authority_key_identifier_extension = true; - let serial = SERIAL_NUMBER.fetch_add(1, Ordering::SeqCst); - params.serial_number = Some(SerialNumber::from_slice(&serial.to_be_bytes()[..])); - - match self { - Self::TrustAnchor | Self::Intermediate => { - params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - params.key_usages = ISSUER_KEY_USAGES.to_vec(); - params.extended_key_usages = ISSUER_EXTENDED_KEY_USAGES.to_vec(); - } - Self::EndEntity | Self::Client => { - params.is_ca = IsCa::NoCa; - params.key_usages = EE_KEY_USAGES.to_vec(); - params.subject_alt_names = vec![ - SanType::DnsName(Ia5String::try_from("testserver.com".to_string()).unwrap()), - SanType::DnsName( - Ia5String::try_from("second.testserver.com".to_string()).unwrap(), - ), - SanType::DnsName(Ia5String::try_from("localhost".to_string()).unwrap()), - SanType::IpAddress(IpAddr::from_str("198.51.100.1").unwrap()), - SanType::IpAddress(IpAddr::from_str("2001:db8::1").unwrap()), - ]; - } - } - - // Client certificates additionally get the client auth EKU. - if *self == Self::Client { - params.extended_key_usages = vec![ExtendedKeyUsagePurpose::ClientAuth]; - } - - params - } - - fn common_name(&self, alg: &'static SigAlgContext) -> DistinguishedName { - let mut distinguished_name = DistinguishedName::new(); - distinguished_name.push( - DnType::CommonName, - match self { - Self::Client => "ponytown client".to_owned(), - Self::EndEntity => "testserver.com".to_owned(), - Self::Intermediate => { - format!("ponytown {} level 2 intermediate", alg.issuer_cn) - } - Self::TrustAnchor => format!("ponytown {} CA", alg.issuer_cn), - }, - ); - distinguished_name - } - - fn key_file_path(&self, alg: &'static SigAlgContext) -> PathBuf { - alg.output_directory() - .join(format!("{}.key", self.label())) - } - - fn cert_pem_file_path(&self, alg: &'static SigAlgContext) -> PathBuf { - alg.output_directory() - .join(format!("{}.cert", self.label())) - } - - fn cert_der_file_path(&self, alg: &'static SigAlgContext) -> PathBuf { - alg.output_directory() - .join(format!("{}.der", self.label())) - } - - fn label(&self) -> &'static str { - match self { - Self::Client => "client", - Self::EndEntity => "end", - Self::Intermediate => "inter", - Self::TrustAnchor => "ca", - } - } -} - -// Note: for convenience we use the RSA sigalg digest algorithm to inform the RSA modulus -// size, mapping SHA256 to RSA 2048, SHA384 to RSA 3072, and SHA512 to RSA 4096. -static SIG_ALGS: &[SigAlgContext] = &[ - SigAlgContext { - inner: &PKCS_RSA_SHA256, - issuer_cn: "RSA 2048", - }, - SigAlgContext { - inner: &PKCS_RSA_SHA384, - issuer_cn: "RSA 3072", - }, - SigAlgContext { - inner: &PKCS_RSA_SHA512, - issuer_cn: "RSA 4096", - }, - SigAlgContext { - inner: &PKCS_ECDSA_P256_SHA256, - issuer_cn: "ECDSA p256", - }, - SigAlgContext { - inner: &PKCS_ECDSA_P384_SHA384, - issuer_cn: "ECDSA p384", - }, - SigAlgContext { - inner: &PKCS_ECDSA_P521_SHA512, - issuer_cn: "ECDSA p521", - }, - SigAlgContext { - inner: &PKCS_ED25519, - issuer_cn: "EdDSA", - }, -]; - -struct SigAlgContext { - pub(crate) inner: &'static SignatureAlgorithm, - pub(crate) issuer_cn: &'static str, -} - -impl SigAlgContext { - fn output_directory(&self) -> PathBuf { - let output_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) - .join("../") - .join("test-ca") - .join( - self.issuer_cn - .to_lowercase() - .replace(' ', "-"), - ); - fs::create_dir_all(&output_dir).unwrap(); - output_dir - } - - fn key_pair(&self) -> KeyPair { - if *self.inner == PKCS_RSA_SHA256 { - KeyPair::generate_rsa_for(&PKCS_RSA_SHA256, RsaKeySize::_2048) - } else if *self.inner == PKCS_RSA_SHA384 { - KeyPair::generate_rsa_for(&PKCS_RSA_SHA384, RsaKeySize::_3072) - } else if *self.inner == PKCS_RSA_SHA512 { - KeyPair::generate_rsa_for(&PKCS_RSA_SHA512, RsaKeySize::_4096) - } else { - KeyPair::generate_for(self.inner) - } - .unwrap() - } -} - -const ISSUER_KEY_USAGES: &[KeyUsagePurpose; 7] = &[ - KeyUsagePurpose::CrlSign, - KeyUsagePurpose::KeyCertSign, - KeyUsagePurpose::DigitalSignature, - KeyUsagePurpose::ContentCommitment, - KeyUsagePurpose::KeyEncipherment, - KeyUsagePurpose::DataEncipherment, - KeyUsagePurpose::KeyAgreement, -]; - -const ISSUER_EXTENDED_KEY_USAGES: &[ExtendedKeyUsagePurpose; 2] = &[ - ExtendedKeyUsagePurpose::ServerAuth, - ExtendedKeyUsagePurpose::ClientAuth, -]; - -const EE_KEY_USAGES: &[KeyUsagePurpose; 2] = &[ - KeyUsagePurpose::DigitalSignature, - KeyUsagePurpose::ContentCommitment, -]; - -static SERIAL_NUMBER: AtomicU64 = AtomicU64::new(1); diff --git a/vendor/rustls/src/bs_debug.rs b/vendor/rustls/src/bs_debug.rs deleted file mode 100644 index eac4149f..00000000 --- a/vendor/rustls/src/bs_debug.rs +++ /dev/null @@ -1,80 +0,0 @@ -use core::fmt; - -/// Alternative implementation of `fmt::Debug` for byte slice. -/// -/// Standard `Debug` implementation for `[u8]` is comma separated -/// list of numbers. Since large amount of byte strings are in fact -/// ASCII strings or contain a lot of ASCII strings (e. g. HTTP), -/// it is convenient to print strings as ASCII when possible. -/// -/// This struct wraps `&[u8]` just to override `fmt::Debug`. -/// -/// `BsDebug` is not a part of public API of bytes crate. -pub(crate) struct BsDebug<'a>(pub(crate) &'a [u8]); - -impl fmt::Debug for BsDebug<'_> { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(fmt, "b\"")?; - for &c in self.0 { - // https://doc.rust-lang.org/reference.html#byte-escapes - if c == b'\n' { - write!(fmt, "\\n")?; - } else if c == b'\r' { - write!(fmt, "\\r")?; - } else if c == b'\t' { - write!(fmt, "\\t")?; - } else if c == b'\\' || c == b'"' { - write!(fmt, "\\{}", c as char)?; - } else if c == b'\0' { - write!(fmt, "\\0")?; - // ASCII printable - } else if (0x20..0x7f).contains(&c) { - write!(fmt, "{}", c as char)?; - } else { - write!(fmt, "\\x{c:02x}")?; - } - } - write!(fmt, "\"")?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use std::format; - use std::prelude::v1::*; - - use super::BsDebug; - - #[test] - fn debug() { - let vec: Vec<_> = (0..0x100).map(|b| b as u8).collect(); - - let expected = "b\"\ - \\0\\x01\\x02\\x03\\x04\\x05\\x06\\x07\ - \\x08\\t\\n\\x0b\\x0c\\r\\x0e\\x0f\ - \\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\ - \\x18\\x19\\x1a\\x1b\\x1c\\x1d\\x1e\\x1f\ - \x20!\\\"#$%&'()*+,-./0123456789:;<=>?\ - @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_\ - `abcdefghijklmnopqrstuvwxyz{|}~\\x7f\ - \\x80\\x81\\x82\\x83\\x84\\x85\\x86\\x87\ - \\x88\\x89\\x8a\\x8b\\x8c\\x8d\\x8e\\x8f\ - \\x90\\x91\\x92\\x93\\x94\\x95\\x96\\x97\ - \\x98\\x99\\x9a\\x9b\\x9c\\x9d\\x9e\\x9f\ - \\xa0\\xa1\\xa2\\xa3\\xa4\\xa5\\xa6\\xa7\ - \\xa8\\xa9\\xaa\\xab\\xac\\xad\\xae\\xaf\ - \\xb0\\xb1\\xb2\\xb3\\xb4\\xb5\\xb6\\xb7\ - \\xb8\\xb9\\xba\\xbb\\xbc\\xbd\\xbe\\xbf\ - \\xc0\\xc1\\xc2\\xc3\\xc4\\xc5\\xc6\\xc7\ - \\xc8\\xc9\\xca\\xcb\\xcc\\xcd\\xce\\xcf\ - \\xd0\\xd1\\xd2\\xd3\\xd4\\xd5\\xd6\\xd7\ - \\xd8\\xd9\\xda\\xdb\\xdc\\xdd\\xde\\xdf\ - \\xe0\\xe1\\xe2\\xe3\\xe4\\xe5\\xe6\\xe7\ - \\xe8\\xe9\\xea\\xeb\\xec\\xed\\xee\\xef\ - \\xf0\\xf1\\xf2\\xf3\\xf4\\xf5\\xf6\\xf7\ - \\xf8\\xf9\\xfa\\xfb\\xfc\\xfd\\xfe\\xff\""; - - assert_eq!(expected, format!("{:?}", BsDebug(&vec))); - } -} diff --git a/vendor/rustls/src/builder.rs b/vendor/rustls/src/builder.rs deleted file mode 100644 index f8ff6140..00000000 --- a/vendor/rustls/src/builder.rs +++ /dev/null @@ -1,290 +0,0 @@ -use alloc::format; -use alloc::vec::Vec; -use core::fmt; -use core::marker::PhantomData; - -use crate::client::EchMode; -use crate::crypto::CryptoProvider; -use crate::error::Error; -use crate::msgs::handshake::ALL_KEY_EXCHANGE_ALGORITHMS; -use crate::sync::Arc; -use crate::time_provider::TimeProvider; -use crate::versions; -#[cfg(doc)] -use crate::{ClientConfig, ServerConfig}; - -/// A [builder] for [`ServerConfig`] or [`ClientConfig`] values. -/// -/// To get one of these, call [`ServerConfig::builder()`] or [`ClientConfig::builder()`]. -/// -/// To build a config, you must make at least two decisions (in order): -/// -/// - How should this client or server verify certificates provided by its peer? -/// - What certificates should this client or server present to its peer? -/// -/// For settings besides these, see the fields of [`ServerConfig`] and [`ClientConfig`]. -/// -/// The usual choice for protocol primitives is to call -/// [`ClientConfig::builder`]/[`ServerConfig::builder`] -/// which will use rustls' default cryptographic provider and safe defaults for ciphersuites and -/// supported protocol versions. -/// -/// ``` -/// # #[cfg(feature = "aws_lc_rs")] { -/// # rustls::crypto::aws_lc_rs::default_provider().install_default(); -/// use rustls::{ClientConfig, ServerConfig}; -/// ClientConfig::builder() -/// // ... -/// # ; -/// -/// ServerConfig::builder() -/// // ... -/// # ; -/// # } -/// ``` -/// -/// You may also override the choice of protocol versions: -/// -/// ```no_run -/// # #[cfg(feature = "aws_lc_rs")] { -/// # rustls::crypto::aws_lc_rs::default_provider().install_default(); -/// # use rustls::ServerConfig; -/// ServerConfig::builder_with_protocol_versions(&[&rustls::version::TLS13]) -/// // ... -/// # ; -/// # } -/// ``` -/// -/// Overriding the default cryptographic provider introduces a `Result` that must be unwrapped, -/// because the config builder checks for consistency of the choices made. For instance, it's an error to -/// configure only TLS 1.2 cipher suites while specifying that TLS 1.3 should be the only supported protocol -/// version. -/// -/// If you configure a smaller set of protocol primitives than the default, you may get a smaller binary, -/// since the code for the unused ones can be optimized away at link time. -/// -/// After choosing protocol primitives, you must choose (a) how to verify certificates and (b) what certificates -/// (if any) to send to the peer. The methods to do this are specific to whether you're building a ClientConfig -/// or a ServerConfig, as tracked by the [`ConfigSide`] type parameter on the various impls of ConfigBuilder. -/// -/// # ClientConfig certificate configuration -/// -/// For a client, _certificate verification_ must be configured either by calling one of: -/// - [`ConfigBuilder::with_root_certificates`] or -/// - [`ConfigBuilder::dangerous()`] and [`DangerousClientConfigBuilder::with_custom_certificate_verifier`] -/// -/// Next, _certificate sending_ (also known as "client authentication", "mutual TLS", or "mTLS") must be configured -/// or disabled using one of: -/// - [`ConfigBuilder::with_no_client_auth`] - to not send client authentication (most common) -/// - [`ConfigBuilder::with_client_auth_cert`] - to always send a specific certificate -/// - [`ConfigBuilder::with_client_cert_resolver`] - to send a certificate chosen dynamically -/// -/// For example: -/// -/// ``` -/// # #[cfg(feature = "aws_lc_rs")] { -/// # rustls::crypto::aws_lc_rs::default_provider().install_default(); -/// # use rustls::ClientConfig; -/// # let root_certs = rustls::RootCertStore::empty(); -/// ClientConfig::builder() -/// .with_root_certificates(root_certs) -/// .with_no_client_auth(); -/// # } -/// ``` -/// -/// # ServerConfig certificate configuration -/// -/// For a server, _certificate verification_ must be configured by calling one of: -/// - [`ConfigBuilder::with_no_client_auth`] - to not require client authentication (most common) -/// - [`ConfigBuilder::with_client_cert_verifier`] - to use a custom verifier -/// -/// Next, _certificate sending_ must be configured by calling one of: -/// - [`ConfigBuilder::with_single_cert`] - to send a specific certificate -/// - [`ConfigBuilder::with_single_cert_with_ocsp`] - to send a specific certificate, plus stapled OCSP -/// - [`ConfigBuilder::with_cert_resolver`] - to send a certificate chosen dynamically -/// -/// For example: -/// -/// ```no_run -/// # #[cfg(feature = "aws_lc_rs")] { -/// # rustls::crypto::aws_lc_rs::default_provider().install_default(); -/// # use rustls::ServerConfig; -/// # let certs = vec![]; -/// # let private_key = pki_types::PrivateKeyDer::from( -/// # pki_types::PrivatePkcs8KeyDer::from(vec![]) -/// # ); -/// ServerConfig::builder() -/// .with_no_client_auth() -/// .with_single_cert(certs, private_key) -/// .expect("bad certificate/key"); -/// # } -/// ``` -/// -/// # Types -/// -/// ConfigBuilder uses the [typestate] pattern to ensure at compile time that each required -/// configuration item is provided exactly once. This is tracked in the `State` type parameter, -/// which can have these values: -/// -/// - [`WantsVersions`] -/// - [`WantsVerifier`] -/// - [`WantsClientCert`] -/// - [`WantsServerCert`] -/// -/// The other type parameter is `Side`, which is either `ServerConfig` or `ClientConfig` -/// depending on whether the ConfigBuilder was built with [`ServerConfig::builder()`] or -/// [`ClientConfig::builder()`]. -/// -/// You won't need to write out either of these type parameters explicitly. If you write a -/// correct chain of configuration calls they will be used automatically. If you write an -/// incorrect chain of configuration calls you will get an error message from the compiler -/// mentioning some of these types. -/// -/// Additionally, ServerConfig and ClientConfig carry a private field containing a -/// [`CryptoProvider`], from [`ClientConfig::builder_with_provider()`] or -/// [`ServerConfig::builder_with_provider()`]. This determines which cryptographic backend -/// is used. The default is [the process-default provider](`CryptoProvider::get_default`). -/// -/// [builder]: https://rust-unofficial.github.io/patterns/patterns/creational/builder.html -/// [typestate]: http://cliffle.com/blog/rust-typestate/ -/// [`ServerConfig`]: crate::ServerConfig -/// [`ServerConfig::builder`]: crate::ServerConfig::builder -/// [`ClientConfig`]: crate::ClientConfig -/// [`ClientConfig::builder()`]: crate::ClientConfig::builder() -/// [`ServerConfig::builder()`]: crate::ServerConfig::builder() -/// [`ClientConfig::builder_with_provider()`]: crate::ClientConfig::builder_with_provider() -/// [`ServerConfig::builder_with_provider()`]: crate::ServerConfig::builder_with_provider() -/// [`ConfigBuilder<ClientConfig, WantsVerifier>`]: struct.ConfigBuilder.html#impl-3 -/// [`ConfigBuilder<ServerConfig, WantsVerifier>`]: struct.ConfigBuilder.html#impl-6 -/// [`WantsClientCert`]: crate::client::WantsClientCert -/// [`WantsServerCert`]: crate::server::WantsServerCert -/// [`CryptoProvider::get_default`]: crate::crypto::CryptoProvider::get_default -/// [`DangerousClientConfigBuilder::with_custom_certificate_verifier`]: crate::client::danger::DangerousClientConfigBuilder::with_custom_certificate_verifier -#[derive(Clone)] -pub struct ConfigBuilder<Side: ConfigSide, State> { - pub(crate) state: State, - pub(crate) provider: Arc<CryptoProvider>, - pub(crate) time_provider: Arc<dyn TimeProvider>, - pub(crate) side: PhantomData<Side>, -} - -impl<Side: ConfigSide, State> ConfigBuilder<Side, State> { - /// Return the crypto provider used to construct this builder. - pub fn crypto_provider(&self) -> &Arc<CryptoProvider> { - &self.provider - } -} - -impl<Side: ConfigSide, State: fmt::Debug> fmt::Debug for ConfigBuilder<Side, State> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let side_name = core::any::type_name::<Side>(); - let (ty, _) = side_name - .split_once('<') - .unwrap_or((side_name, "")); - let (_, name) = ty.rsplit_once("::").unwrap_or(("", ty)); - - f.debug_struct(&format!("ConfigBuilder<{name}, _>",)) - .field("state", &self.state) - .finish() - } -} - -/// Config builder state where the caller must supply TLS protocol versions. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsVersions {} - -impl<S: ConfigSide> ConfigBuilder<S, WantsVersions> { - /// Accept the default protocol versions: both TLS1.2 and TLS1.3 are enabled. - pub fn with_safe_default_protocol_versions( - self, - ) -> Result<ConfigBuilder<S, WantsVerifier>, Error> { - self.with_protocol_versions(versions::DEFAULT_VERSIONS) - } - - /// Use a specific set of protocol versions. - pub fn with_protocol_versions( - self, - versions: &[&'static versions::SupportedProtocolVersion], - ) -> Result<ConfigBuilder<S, WantsVerifier>, Error> { - let mut any_usable_suite = false; - for suite in &self.provider.cipher_suites { - if versions.contains(&suite.version()) { - any_usable_suite = true; - break; - } - } - - if !any_usable_suite { - return Err(Error::General("no usable cipher suites configured".into())); - } - - if self.provider.kx_groups.is_empty() { - return Err(Error::General("no kx groups configured".into())); - } - - // verifying cipher suites have matching kx groups - let mut supported_kx_algos = Vec::with_capacity(ALL_KEY_EXCHANGE_ALGORITHMS.len()); - for group in self.provider.kx_groups.iter() { - let kx = group.name().key_exchange_algorithm(); - if !supported_kx_algos.contains(&kx) { - supported_kx_algos.push(kx); - } - // Small optimization. We don't need to go over other key exchange groups - // if we already cover all supported key exchange algorithms - if supported_kx_algos.len() == ALL_KEY_EXCHANGE_ALGORITHMS.len() { - break; - } - } - - for cs in self.provider.cipher_suites.iter() { - let cs_kx = cs.key_exchange_algorithms(); - if cs_kx - .iter() - .any(|kx| supported_kx_algos.contains(kx)) - { - continue; - } - let suite_name = cs.common().suite; - return Err(Error::General(alloc::format!( - "Ciphersuite {suite_name:?} requires {cs_kx:?} key exchange, but no {cs_kx:?}-compatible \ - key exchange groups were present in `CryptoProvider`'s `kx_groups` field", - ))); - } - - Ok(ConfigBuilder { - state: WantsVerifier { - versions: versions::EnabledVersions::new(versions), - client_ech_mode: None, - }, - provider: self.provider, - time_provider: self.time_provider, - side: self.side, - }) - } -} - -/// Config builder state where the caller must supply a verifier. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsVerifier { - pub(crate) versions: versions::EnabledVersions, - pub(crate) client_ech_mode: Option<EchMode>, -} - -/// Helper trait to abstract [`ConfigBuilder`] over building a [`ClientConfig`] or [`ServerConfig`]. -/// -/// [`ClientConfig`]: crate::ClientConfig -/// [`ServerConfig`]: crate::ServerConfig -pub trait ConfigSide: sealed::Sealed {} - -impl ConfigSide for crate::ClientConfig {} -impl ConfigSide for crate::ServerConfig {} - -mod sealed { - pub trait Sealed {} - impl Sealed for crate::ClientConfig {} - impl Sealed for crate::ServerConfig {} -} diff --git a/vendor/rustls/src/check.rs b/vendor/rustls/src/check.rs deleted file mode 100644 index 9875bc8b..00000000 --- a/vendor/rustls/src/check.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::enums::{ContentType, HandshakeType}; -use crate::error::Error; -use crate::log::warn; -use crate::msgs::message::MessagePayload; - -/// For a Message $m, and a HandshakePayload enum member $payload_type, -/// return Ok(payload) if $m is both a handshake message and one that -/// has the given $payload_type. If not, return Err(rustls::Error) quoting -/// $handshake_type as the expected handshake type. -macro_rules! require_handshake_msg( - ( $m:expr, $handshake_type:path, $payload_type:path ) => ( - match &$m.payload { - MessagePayload::Handshake { parsed: $crate::msgs::handshake::HandshakeMessagePayload( - $payload_type(hm), - ), .. } => Ok(hm), - payload => Err($crate::check::inappropriate_handshake_message( - payload, - &[$crate::ContentType::Handshake], - &[$handshake_type])) - } - ) -); - -/// Like require_handshake_msg, but moves the payload out of $m. -macro_rules! require_handshake_msg_move( - ( $m:expr, $handshake_type:path, $payload_type:path ) => ( - match $m.payload { - MessagePayload::Handshake { parsed: $crate::msgs::handshake::HandshakeMessagePayload( - $payload_type(hm), - ), .. } => Ok(hm), - payload => - Err($crate::check::inappropriate_handshake_message( - &payload, - &[$crate::ContentType::Handshake], - &[$handshake_type])) - } - ) -); - -pub(crate) fn inappropriate_message( - payload: &MessagePayload<'_>, - content_types: &[ContentType], -) -> Error { - warn!( - "Received a {:?} message while expecting {content_types:?}", - payload.content_type(), - ); - Error::InappropriateMessage { - expect_types: content_types.to_vec(), - got_type: payload.content_type(), - } -} - -pub(crate) fn inappropriate_handshake_message( - payload: &MessagePayload<'_>, - content_types: &[ContentType], - handshake_types: &[HandshakeType], -) -> Error { - match payload { - MessagePayload::Handshake { parsed, .. } => { - let got_type = parsed.0.handshake_type(); - warn!("Received a {got_type:?} handshake message while expecting {handshake_types:?}",); - Error::InappropriateHandshakeMessage { - expect_types: handshake_types.to_vec(), - got_type, - } - } - payload => inappropriate_message(payload, content_types), - } -} diff --git a/vendor/rustls/src/client/builder.rs b/vendor/rustls/src/client/builder.rs deleted file mode 100644 index b301e750..00000000 --- a/vendor/rustls/src/client/builder.rs +++ /dev/null @@ -1,186 +0,0 @@ -use alloc::vec::Vec; -use core::marker::PhantomData; - -use pki_types::{CertificateDer, PrivateKeyDer}; - -use super::client_conn::Resumption; -use crate::builder::{ConfigBuilder, WantsVerifier}; -use crate::client::{ClientConfig, EchMode, ResolvesClientCert, handy}; -use crate::error::Error; -use crate::key_log::NoKeyLog; -use crate::sign::{CertifiedKey, SingleCertAndKey}; -use crate::sync::Arc; -use crate::versions::TLS13; -use crate::webpki::{self, WebPkiServerVerifier}; -use crate::{WantsVersions, compress, verify, versions}; - -impl ConfigBuilder<ClientConfig, WantsVersions> { - /// Enable Encrypted Client Hello (ECH) in the given mode. - /// - /// This implicitly selects TLS 1.3 as the only supported protocol version to meet the - /// requirement to support ECH. - /// - /// The `ClientConfig` that will be produced by this builder will be specific to the provided - /// [`crate::client::EchConfig`] and may not be appropriate for all connections made by the program. - /// In this case the configuration should only be shared by connections intended for domains - /// that offer the provided [`crate::client::EchConfig`] in their DNS zone. - pub fn with_ech( - self, - mode: EchMode, - ) -> Result<ConfigBuilder<ClientConfig, WantsVerifier>, Error> { - let mut res = self.with_protocol_versions(&[&TLS13][..])?; - res.state.client_ech_mode = Some(mode); - Ok(res) - } -} - -impl ConfigBuilder<ClientConfig, WantsVerifier> { - /// Choose how to verify server certificates. - /// - /// Using this function does not configure revocation. If you wish to - /// configure revocation, instead use: - /// - /// ```diff - /// - .with_root_certificates(root_store) - /// + .with_webpki_verifier( - /// + WebPkiServerVerifier::builder_with_provider(root_store, crypto_provider) - /// + .with_crls(...) - /// + .build()? - /// + ) - /// ``` - pub fn with_root_certificates( - self, - root_store: impl Into<Arc<webpki::RootCertStore>>, - ) -> ConfigBuilder<ClientConfig, WantsClientCert> { - let algorithms = self - .provider - .signature_verification_algorithms; - self.with_webpki_verifier( - WebPkiServerVerifier::new_without_revocation(root_store, algorithms).into(), - ) - } - - /// Choose how to verify server certificates using a webpki verifier. - /// - /// See [`webpki::WebPkiServerVerifier::builder`] and - /// [`webpki::WebPkiServerVerifier::builder_with_provider`] for more information. - pub fn with_webpki_verifier( - self, - verifier: Arc<WebPkiServerVerifier>, - ) -> ConfigBuilder<ClientConfig, WantsClientCert> { - ConfigBuilder { - state: WantsClientCert { - versions: self.state.versions, - verifier, - client_ech_mode: self.state.client_ech_mode, - }, - provider: self.provider, - time_provider: self.time_provider, - side: PhantomData, - } - } - - /// Access configuration options whose use is dangerous and requires - /// extra care. - pub fn dangerous(self) -> danger::DangerousClientConfigBuilder { - danger::DangerousClientConfigBuilder { cfg: self } - } -} - -/// Container for unsafe APIs -pub(super) mod danger { - use core::marker::PhantomData; - - use crate::client::WantsClientCert; - use crate::sync::Arc; - use crate::{ClientConfig, ConfigBuilder, WantsVerifier, verify}; - - /// Accessor for dangerous configuration options. - #[derive(Debug)] - pub struct DangerousClientConfigBuilder { - /// The underlying ClientConfigBuilder - pub cfg: ConfigBuilder<ClientConfig, WantsVerifier>, - } - - impl DangerousClientConfigBuilder { - /// Set a custom certificate verifier. - pub fn with_custom_certificate_verifier( - self, - verifier: Arc<dyn verify::ServerCertVerifier>, - ) -> ConfigBuilder<ClientConfig, WantsClientCert> { - ConfigBuilder { - state: WantsClientCert { - versions: self.cfg.state.versions, - verifier, - client_ech_mode: self.cfg.state.client_ech_mode, - }, - provider: self.cfg.provider, - time_provider: self.cfg.time_provider, - side: PhantomData, - } - } - } -} - -/// A config builder state where the caller needs to supply whether and how to provide a client -/// certificate. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone)] -pub struct WantsClientCert { - versions: versions::EnabledVersions, - verifier: Arc<dyn verify::ServerCertVerifier>, - client_ech_mode: Option<EchMode>, -} - -impl ConfigBuilder<ClientConfig, WantsClientCert> { - /// Sets a single certificate chain and matching private key for use - /// in client authentication. - /// - /// `cert_chain` is a vector of DER-encoded certificates. - /// `key_der` is a DER-encoded private key as PKCS#1, PKCS#8, or SEC1. The - /// `aws-lc-rs` and `ring` [`CryptoProvider`][crate::CryptoProvider]s support - /// all three encodings, but other `CryptoProviders` may not. - /// - /// This function fails if `key_der` is invalid. - pub fn with_client_auth_cert( - self, - cert_chain: Vec<CertificateDer<'static>>, - key_der: PrivateKeyDer<'static>, - ) -> Result<ClientConfig, Error> { - let certified_key = CertifiedKey::from_der(cert_chain, key_der, &self.provider)?; - Ok(self.with_client_cert_resolver(Arc::new(SingleCertAndKey::from(certified_key)))) - } - - /// Do not support client auth. - pub fn with_no_client_auth(self) -> ClientConfig { - self.with_client_cert_resolver(Arc::new(handy::FailResolveClientCert {})) - } - - /// Sets a custom [`ResolvesClientCert`]. - pub fn with_client_cert_resolver( - self, - client_auth_cert_resolver: Arc<dyn ResolvesClientCert>, - ) -> ClientConfig { - ClientConfig { - provider: self.provider, - alpn_protocols: Vec::new(), - resumption: Resumption::default(), - max_fragment_size: None, - client_auth_cert_resolver, - versions: self.state.versions, - enable_sni: true, - verifier: self.state.verifier, - key_log: Arc::new(NoKeyLog {}), - enable_secret_extraction: false, - enable_early_data: false, - #[cfg(feature = "tls12")] - require_ems: cfg!(feature = "fips"), - time_provider: self.time_provider, - cert_compressors: compress::default_cert_compressors().to_vec(), - cert_compression_cache: Arc::new(compress::CompressionCache::default()), - cert_decompressors: compress::default_cert_decompressors().to_vec(), - ech_mode: self.state.client_ech_mode, - } - } -} diff --git a/vendor/rustls/src/client/client_conn.rs b/vendor/rustls/src/client/client_conn.rs deleted file mode 100644 index d214c2a1..00000000 --- a/vendor/rustls/src/client/client_conn.rs +++ /dev/null @@ -1,1062 +0,0 @@ -use alloc::vec::Vec; -use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; -use core::{fmt, mem}; - -use pki_types::{ServerName, UnixTime}; - -use super::handy::NoClientSessionStorage; -use super::hs::{self, ClientHelloInput}; -#[cfg(feature = "std")] -use crate::WantsVerifier; -use crate::builder::ConfigBuilder; -use crate::client::{EchMode, EchStatus}; -use crate::common_state::{CommonState, Protocol, Side}; -use crate::conn::{ConnectionCore, UnbufferedConnectionCommon}; -use crate::crypto::{CryptoProvider, SupportedKxGroup}; -use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; -use crate::error::Error; -use crate::kernel::KernelConnection; -use crate::log::trace; -use crate::msgs::enums::NamedGroup; -use crate::msgs::handshake::ClientExtensionsInput; -use crate::msgs::persist; -use crate::suites::{ExtractedSecrets, SupportedCipherSuite}; -use crate::sync::Arc; -#[cfg(feature = "std")] -use crate::time_provider::DefaultTimeProvider; -use crate::time_provider::TimeProvider; -use crate::unbuffered::{EncryptError, TransmitTlsData}; -#[cfg(doc)] -use crate::{DistinguishedName, crypto}; -use crate::{KeyLog, WantsVersions, compress, sign, verify, versions}; - -/// A trait for the ability to store client session data, so that sessions -/// can be resumed in future connections. -/// -/// Generally all data in this interface should be treated as -/// **highly sensitive**, containing enough key material to break all security -/// of the corresponding session. -/// -/// `set_`, `insert_`, `remove_` and `take_` operations are mutating; this isn't -/// expressed in the type system to allow implementations freedom in -/// how to achieve interior mutability. `Mutex` is a common choice. -pub trait ClientSessionStore: fmt::Debug + Send + Sync { - /// Remember what `NamedGroup` the given server chose. - fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup); - - /// This should return the value most recently passed to `set_kx_hint` - /// for the given `server_name`. - /// - /// If `None` is returned, the caller chooses the first configured group, - /// and an extra round trip might happen if that choice is unsatisfactory - /// to the server. - fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup>; - - /// Remember a TLS1.2 session. - /// - /// At most one of these can be remembered at a time, per `server_name`. - fn set_tls12_session( - &self, - server_name: ServerName<'static>, - value: persist::Tls12ClientSessionValue, - ); - - /// Get the most recently saved TLS1.2 session for `server_name` provided to `set_tls12_session`. - fn tls12_session( - &self, - server_name: &ServerName<'_>, - ) -> Option<persist::Tls12ClientSessionValue>; - - /// Remove and forget any saved TLS1.2 session for `server_name`. - fn remove_tls12_session(&self, server_name: &ServerName<'static>); - - /// Remember a TLS1.3 ticket that might be retrieved later from `take_tls13_ticket`, allowing - /// resumption of this session. - /// - /// This can be called multiple times for a given session, allowing multiple independent tickets - /// to be valid at once. The number of times this is called is controlled by the server, so - /// implementations of this trait should apply a reasonable bound of how many items are stored - /// simultaneously. - fn insert_tls13_ticket( - &self, - server_name: ServerName<'static>, - value: persist::Tls13ClientSessionValue, - ); - - /// Return a TLS1.3 ticket previously provided to `add_tls13_ticket`. - /// - /// Implementations of this trait must return each value provided to `add_tls13_ticket` _at most once_. - fn take_tls13_ticket( - &self, - server_name: &ServerName<'static>, - ) -> Option<persist::Tls13ClientSessionValue>; -} - -/// A trait for the ability to choose a certificate chain and -/// private key for the purposes of client authentication. -pub trait ResolvesClientCert: fmt::Debug + Send + Sync { - /// Resolve a client certificate chain/private key to use as the client's - /// identity. - /// - /// `root_hint_subjects` is an optional list of certificate authority - /// subject distinguished names that the client can use to help - /// decide on a client certificate the server is likely to accept. If - /// the list is empty, the client should send whatever certificate it - /// has. The hints are expected to be DER-encoded X.500 distinguished names, - /// per [RFC 5280 A.1]. See [`DistinguishedName`] for more information - /// on decoding with external crates like `x509-parser`. - /// - /// `sigschemes` is the list of the [`SignatureScheme`]s the server - /// supports. - /// - /// Return `None` to continue the handshake without any client - /// authentication. The server may reject the handshake later - /// if it requires authentication. - /// - /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1 - fn resolve( - &self, - root_hint_subjects: &[&[u8]], - sigschemes: &[SignatureScheme], - ) -> Option<Arc<sign::CertifiedKey>>; - - /// Return true if the client only supports raw public keys. - /// - /// See [RFC 7250](https://www.rfc-editor.org/rfc/rfc7250). - fn only_raw_public_keys(&self) -> bool { - false - } - - /// Return true if any certificates at all are available. - fn has_certs(&self) -> bool; -} - -/// Common configuration for (typically) all connections made by a program. -/// -/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots -/// from the operating system to add to the [`RootCertStore`] passed to `with_root_certificates()` -/// (the rustls-native-certs crate is often used for this) may take on the order of a few hundred -/// milliseconds. -/// -/// These must be created via the [`ClientConfig::builder()`] or [`ClientConfig::builder_with_provider()`] -/// function. -/// -/// Note that using [`ConfigBuilder<ClientConfig, WantsVersions>::with_ech()`] will produce a common -/// configuration specific to the provided [`crate::client::EchConfig`] that may not be appropriate -/// for all connections made by the program. In this case the configuration should only be shared -/// by connections intended for domains that offer the provided [`crate::client::EchConfig`] in -/// their DNS zone. -/// -/// # Defaults -/// -/// * [`ClientConfig::max_fragment_size`]: the default is `None` (meaning 16kB). -/// * [`ClientConfig::resumption`]: supports resumption with up to 256 server names, using session -/// ids or tickets, with a max of eight tickets per server. -/// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. -/// * [`ClientConfig::key_log`]: key material is not logged. -/// * [`ClientConfig::cert_decompressors`]: depends on the crate features, see [`compress::default_cert_decompressors()`]. -/// * [`ClientConfig::cert_compressors`]: depends on the crate features, see [`compress::default_cert_compressors()`]. -/// * [`ClientConfig::cert_compression_cache`]: caches the most recently used 4 compressions -/// -/// [`RootCertStore`]: crate::RootCertStore -#[derive(Clone, Debug)] -pub struct ClientConfig { - /// Which ALPN protocols we include in our client hello. - /// If empty, no ALPN extension is sent. - pub alpn_protocols: Vec<Vec<u8>>, - - /// How and when the client can resume a previous session. - /// - /// # Sharing `resumption` between `ClientConfig`s - /// In a program using many `ClientConfig`s it may improve resumption rates - /// (which has a significant impact on connection performance) if those - /// configs share a single `Resumption`. - /// - /// However, resumption is only allowed between two `ClientConfig`s if their - /// `client_auth_cert_resolver` (ie, potential client authentication credentials) - /// and `verifier` (ie, server certificate verification settings) are - /// the same (according to `Arc::ptr_eq`). - /// - /// To illustrate, imagine two `ClientConfig`s `A` and `B`. `A` fully validates - /// the server certificate, `B` does not. If `A` and `B` shared a resumption store, - /// it would be possible for a session originated by `B` to be inserted into the - /// store, and then resumed by `A`. This would give a false impression to the user - /// of `A` that the server certificate is fully validated. - pub resumption: Resumption, - - /// The maximum size of plaintext input to be emitted in a single TLS record. - /// A value of None is equivalent to the [TLS maximum] of 16 kB. - /// - /// rustls enforces an arbitrary minimum of 32 bytes for this field. - /// Out of range values are reported as errors from [ClientConnection::new]. - /// - /// Setting this value to a little less than the TCP MSS may improve latency - /// for stream-y workloads. - /// - /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1 - /// [ClientConnection::new]: crate::client::ClientConnection::new - pub max_fragment_size: Option<usize>, - - /// How to decide what client auth certificate/keys to use. - pub client_auth_cert_resolver: Arc<dyn ResolvesClientCert>, - - /// Whether to send the Server Name Indication (SNI) extension - /// during the client handshake. - /// - /// The default is true. - pub enable_sni: bool, - - /// How to output key material for debugging. The default - /// does nothing. - pub key_log: Arc<dyn KeyLog>, - - /// Allows traffic secrets to be extracted after the handshake, - /// e.g. for kTLS setup. - pub enable_secret_extraction: bool, - - /// Whether to send data on the first flight ("early data") in - /// TLS 1.3 handshakes. - /// - /// The default is false. - pub enable_early_data: bool, - - /// If set to `true`, requires the server to support the extended - /// master secret extraction method defined in [RFC 7627]. - /// - /// The default is `true` if the `fips` crate feature is enabled, - /// `false` otherwise. - /// - /// It must be set to `true` to meet FIPS requirement mentioned in section - /// **D.Q Transition of the TLS 1.2 KDF to Support the Extended Master - /// Secret** from [FIPS 140-3 IG.pdf]. - /// - /// [RFC 7627]: https://datatracker.ietf.org/doc/html/rfc7627 - /// [FIPS 140-3 IG.pdf]: https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf - #[cfg(feature = "tls12")] - pub require_ems: bool, - - /// Provides the current system time - pub time_provider: Arc<dyn TimeProvider>, - - /// Source of randomness and other crypto. - pub(super) provider: Arc<CryptoProvider>, - - /// Supported versions, in no particular order. The default - /// is all supported versions. - pub(super) versions: versions::EnabledVersions, - - /// How to verify the server certificate chain. - pub(super) verifier: Arc<dyn verify::ServerCertVerifier>, - - /// How to decompress the server's certificate chain. - /// - /// If this is non-empty, the [RFC8779] certificate compression - /// extension is offered, and any compressed certificates are - /// transparently decompressed during the handshake. - /// - /// This only applies to TLS1.3 connections. It is ignored for - /// TLS1.2 connections. - /// - /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/ - pub cert_decompressors: Vec<&'static dyn compress::CertDecompressor>, - - /// How to compress the client's certificate chain. - /// - /// If a server supports this extension, and advertises support - /// for one of the compression algorithms included here, the - /// client certificate will be compressed according to [RFC8779]. - /// - /// This only applies to TLS1.3 connections. It is ignored for - /// TLS1.2 connections. - /// - /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/ - pub cert_compressors: Vec<&'static dyn compress::CertCompressor>, - - /// Caching for compressed certificates. - /// - /// This is optional: [`compress::CompressionCache::Disabled`] gives - /// a cache that does no caching. - pub cert_compression_cache: Arc<compress::CompressionCache>, - - /// How to offer Encrypted Client Hello (ECH). The default is to not offer ECH. - pub(super) ech_mode: Option<EchMode>, -} - -impl ClientConfig { - /// Create a builder for a client configuration with - /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider] - /// and safe protocol version defaults. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - #[cfg(feature = "std")] - pub fn builder() -> ConfigBuilder<Self, WantsVerifier> { - Self::builder_with_protocol_versions(versions::DEFAULT_VERSIONS) - } - - /// Create a builder for a client configuration with - /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider] - /// and the provided protocol versions. - /// - /// Panics if - /// - the supported versions are not compatible with the provider (eg. - /// the combination of ciphersuites supported by the provider and supported - /// versions lead to zero cipher suites being usable), - /// - if a `CryptoProvider` cannot be resolved using a combination of - /// the crate features and process default. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - #[cfg(feature = "std")] - pub fn builder_with_protocol_versions( - versions: &[&'static versions::SupportedProtocolVersion], - ) -> ConfigBuilder<Self, WantsVerifier> { - // Safety assumptions: - // 1. that the provider has been installed (explicitly or implicitly) - // 2. that the process-level default provider is usable with the supplied protocol versions. - Self::builder_with_provider( - CryptoProvider::get_default_or_install_from_crate_features().clone(), - ) - .with_protocol_versions(versions) - .unwrap() - } - - /// Create a builder for a client configuration with a specific [`CryptoProvider`]. - /// - /// This will use the provider's configured ciphersuites. You must additionally choose - /// which protocol versions to enable, using `with_protocol_versions` or - /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol - /// version is not supported by the provider's ciphersuites. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - #[cfg(feature = "std")] - pub fn builder_with_provider( - provider: Arc<CryptoProvider>, - ) -> ConfigBuilder<Self, WantsVersions> { - ConfigBuilder { - state: WantsVersions {}, - provider, - time_provider: Arc::new(DefaultTimeProvider), - side: PhantomData, - } - } - /// Create a builder for a client configuration with no default implementation details. - /// - /// This API must be used by `no_std` users. - /// - /// You must provide a specific [`TimeProvider`]. - /// - /// You must provide a specific [`CryptoProvider`]. - /// - /// This will use the provider's configured ciphersuites. You must additionally choose - /// which protocol versions to enable, using `with_protocol_versions` or - /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol - /// version is not supported by the provider's ciphersuites. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - pub fn builder_with_details( - provider: Arc<CryptoProvider>, - time_provider: Arc<dyn TimeProvider>, - ) -> ConfigBuilder<Self, WantsVersions> { - ConfigBuilder { - state: WantsVersions {}, - provider, - time_provider, - side: PhantomData, - } - } - - /// Return true if connections made with this `ClientConfig` will - /// operate in FIPS mode. - /// - /// This is different from [`CryptoProvider::fips()`]: [`CryptoProvider::fips()`] - /// is concerned only with cryptography, whereas this _also_ covers TLS-level - /// configuration that NIST recommends, as well as ECH HPKE suites if applicable. - pub fn fips(&self) -> bool { - let mut is_fips = self.provider.fips(); - - #[cfg(feature = "tls12")] - { - is_fips = is_fips && self.require_ems - } - - if let Some(ech_mode) = &self.ech_mode { - is_fips = is_fips && ech_mode.fips(); - } - - is_fips - } - - /// Return the crypto provider used to construct this client configuration. - pub fn crypto_provider(&self) -> &Arc<CryptoProvider> { - &self.provider - } - - /// Access configuration options whose use is dangerous and requires - /// extra care. - pub fn dangerous(&mut self) -> danger::DangerousClientConfig<'_> { - danger::DangerousClientConfig { cfg: self } - } - - pub(super) fn needs_key_share(&self) -> bool { - self.supports_version(ProtocolVersion::TLSv1_3) - } - - /// We support a given TLS version if it's quoted in the configured - /// versions *and* at least one ciphersuite for this version is - /// also configured. - pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool { - self.versions.contains(v) - && self - .provider - .cipher_suites - .iter() - .any(|cs| cs.version().version == v) - } - - #[cfg(feature = "std")] - pub(crate) fn supports_protocol(&self, proto: Protocol) -> bool { - self.provider - .cipher_suites - .iter() - .any(|cs| cs.usable_for_protocol(proto)) - } - - pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option<SupportedCipherSuite> { - self.provider - .cipher_suites - .iter() - .copied() - .find(|&scs| scs.suite() == suite) - } - - pub(super) fn find_kx_group( - &self, - group: NamedGroup, - version: ProtocolVersion, - ) -> Option<&'static dyn SupportedKxGroup> { - self.provider - .kx_groups - .iter() - .copied() - .find(|skxg| skxg.usable_for_version(version) && skxg.name() == group) - } - - pub(super) fn current_time(&self) -> Result<UnixTime, Error> { - self.time_provider - .current_time() - .ok_or(Error::FailedToGetCurrentTime) - } -} - -/// Configuration for how/when a client is allowed to resume a previous session. -#[derive(Clone, Debug)] -pub struct Resumption { - /// How we store session data or tickets. The default is to use an in-memory - /// [super::handy::ClientSessionMemoryCache]. - pub(super) store: Arc<dyn ClientSessionStore>, - - /// What mechanism is used for resuming a TLS 1.2 session. - pub(super) tls12_resumption: Tls12Resumption, -} - -impl Resumption { - /// Create a new `Resumption` that stores data for the given number of sessions in memory. - /// - /// This is the default `Resumption` choice, and enables resuming a TLS 1.2 session with - /// a session id or RFC 5077 ticket. - #[cfg(feature = "std")] - pub fn in_memory_sessions(num: usize) -> Self { - Self { - store: Arc::new(super::handy::ClientSessionMemoryCache::new(num)), - tls12_resumption: Tls12Resumption::SessionIdOrTickets, - } - } - - /// Use a custom [`ClientSessionStore`] implementation to store sessions. - /// - /// By default, enables resuming a TLS 1.2 session with a session id or RFC 5077 ticket. - pub fn store(store: Arc<dyn ClientSessionStore>) -> Self { - Self { - store, - tls12_resumption: Tls12Resumption::SessionIdOrTickets, - } - } - - /// Disable all use of session resumption. - pub fn disabled() -> Self { - Self { - store: Arc::new(NoClientSessionStorage), - tls12_resumption: Tls12Resumption::Disabled, - } - } - - /// Configure whether TLS 1.2 sessions may be resumed, and by what mechanism. - /// - /// This is meaningless if you've disabled resumption entirely, which is the case in `no-std` - /// contexts. - pub fn tls12_resumption(mut self, tls12: Tls12Resumption) -> Self { - self.tls12_resumption = tls12; - self - } -} - -impl Default for Resumption { - /// Create an in-memory session store resumption with up to 256 server names, allowing - /// a TLS 1.2 session to resume with a session id or RFC 5077 ticket. - fn default() -> Self { - #[cfg(feature = "std")] - let ret = Self::in_memory_sessions(256); - - #[cfg(not(feature = "std"))] - let ret = Self::disabled(); - - ret - } -} - -/// What mechanisms to support for resuming a TLS 1.2 session. -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum Tls12Resumption { - /// Disable 1.2 resumption. - Disabled, - /// Support 1.2 resumption using session ids only. - SessionIdOnly, - /// Support 1.2 resumption using session ids or RFC 5077 tickets. - /// - /// See[^1] for why you might like to disable RFC 5077 by instead choosing the `SessionIdOnly` - /// option. Note that TLS 1.3 tickets do not have those issues. - /// - /// [^1]: <https://words.filippo.io/we-need-to-talk-about-session-tickets/> - SessionIdOrTickets, -} - -/// Container for unsafe APIs -pub(super) mod danger { - use super::ClientConfig; - use super::verify::ServerCertVerifier; - use crate::sync::Arc; - - /// Accessor for dangerous configuration options. - #[derive(Debug)] - pub struct DangerousClientConfig<'a> { - /// The underlying ClientConfig - pub cfg: &'a mut ClientConfig, - } - - impl DangerousClientConfig<'_> { - /// Overrides the default `ServerCertVerifier` with something else. - pub fn set_certificate_verifier(&mut self, verifier: Arc<dyn ServerCertVerifier>) { - self.cfg.verifier = verifier; - } - } -} - -#[derive(Debug, PartialEq)] -enum EarlyDataState { - Disabled, - Ready, - Accepted, - AcceptedFinished, - Rejected, -} - -#[derive(Debug)] -pub(super) struct EarlyData { - state: EarlyDataState, - left: usize, -} - -impl EarlyData { - fn new() -> Self { - Self { - left: 0, - state: EarlyDataState::Disabled, - } - } - - pub(super) fn is_enabled(&self) -> bool { - matches!(self.state, EarlyDataState::Ready | EarlyDataState::Accepted) - } - - #[cfg(feature = "std")] - fn is_accepted(&self) -> bool { - matches!( - self.state, - EarlyDataState::Accepted | EarlyDataState::AcceptedFinished - ) - } - - pub(super) fn enable(&mut self, max_data: usize) { - assert_eq!(self.state, EarlyDataState::Disabled); - self.state = EarlyDataState::Ready; - self.left = max_data; - } - - pub(super) fn rejected(&mut self) { - trace!("EarlyData rejected"); - self.state = EarlyDataState::Rejected; - } - - pub(super) fn accepted(&mut self) { - trace!("EarlyData accepted"); - assert_eq!(self.state, EarlyDataState::Ready); - self.state = EarlyDataState::Accepted; - } - - pub(super) fn finished(&mut self) { - trace!("EarlyData finished"); - self.state = match self.state { - EarlyDataState::Accepted => EarlyDataState::AcceptedFinished, - _ => panic!("bad EarlyData state"), - } - } - - fn check_write_opt(&mut self, sz: usize) -> Option<usize> { - match self.state { - EarlyDataState::Disabled => unreachable!(), - EarlyDataState::Ready | EarlyDataState::Accepted => { - let take = if self.left < sz { - mem::replace(&mut self.left, 0) - } else { - self.left -= sz; - sz - }; - - Some(take) - } - EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => None, - } - } -} - -#[cfg(feature = "std")] -mod connection { - use alloc::vec::Vec; - use core::fmt; - use core::ops::{Deref, DerefMut}; - use std::io; - - use pki_types::ServerName; - - use super::{ClientConnectionData, ClientExtensionsInput}; - use crate::ClientConfig; - use crate::client::EchStatus; - use crate::common_state::Protocol; - use crate::conn::{ConnectionCommon, ConnectionCore}; - use crate::error::Error; - use crate::suites::ExtractedSecrets; - use crate::sync::Arc; - - /// Stub that implements io::Write and dispatches to `write_early_data`. - pub struct WriteEarlyData<'a> { - sess: &'a mut ClientConnection, - } - - impl<'a> WriteEarlyData<'a> { - fn new(sess: &'a mut ClientConnection) -> Self { - WriteEarlyData { sess } - } - - /// How many bytes you may send. Writes will become short - /// once this reaches zero. - pub fn bytes_left(&self) -> usize { - self.sess - .inner - .core - .data - .early_data - .bytes_left() - } - } - - impl io::Write for WriteEarlyData<'_> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.sess.write_early_data(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - } - - impl super::EarlyData { - fn check_write(&mut self, sz: usize) -> io::Result<usize> { - self.check_write_opt(sz) - .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidInput)) - } - - fn bytes_left(&self) -> usize { - self.left - } - } - - /// This represents a single TLS client connection. - pub struct ClientConnection { - inner: ConnectionCommon<ClientConnectionData>, - } - - impl fmt::Debug for ClientConnection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ClientConnection") - .finish() - } - } - - impl ClientConnection { - /// Make a new ClientConnection. `config` controls how - /// we behave in the TLS protocol, `name` is the - /// name of the server we want to talk to. - pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> { - Self::new_with_alpn(config.clone(), name, config.alpn_protocols.clone()) - } - - /// Make a new ClientConnection with custom ALPN protocols. - pub fn new_with_alpn( - config: Arc<ClientConfig>, - name: ServerName<'static>, - alpn_protocols: Vec<Vec<u8>>, - ) -> Result<Self, Error> { - Ok(Self { - inner: ConnectionCommon::from(ConnectionCore::for_client( - config, - name, - ClientExtensionsInput::from_alpn(alpn_protocols), - Protocol::Tcp, - )?), - }) - } - /// Returns an `io::Write` implementer you can write bytes to - /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server. - /// - /// This returns None in many circumstances when the capability to - /// send early data is not available, including but not limited to: - /// - /// - The server hasn't been talked to previously. - /// - The server does not support resumption. - /// - The server does not support early data. - /// - The resumption data for the server has expired. - /// - /// The server specifies a maximum amount of early data. You can - /// learn this limit through the returned object, and writes through - /// it will process only this many bytes. - /// - /// The server can choose not to accept any sent early data -- - /// in this case the data is lost but the connection continues. You - /// can tell this happened using `is_early_data_accepted`. - pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> { - if self - .inner - .core - .data - .early_data - .is_enabled() - { - Some(WriteEarlyData::new(self)) - } else { - None - } - } - - /// Returns True if the server signalled it will process early data. - /// - /// If you sent early data and this returns false at the end of the - /// handshake then the server will not process the data. This - /// is not an error, but you may wish to resend the data. - pub fn is_early_data_accepted(&self) -> bool { - self.inner.core.is_early_data_accepted() - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - /// Should be used with care as it exposes secret key material. - pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { - self.inner.dangerous_extract_secrets() - } - - /// Return the connection's Encrypted Client Hello (ECH) status. - pub fn ech_status(&self) -> EchStatus { - self.inner.core.data.ech_status - } - - /// Returns the number of TLS1.3 tickets that have been received. - pub fn tls13_tickets_received(&self) -> u32 { - self.inner.tls13_tickets_received - } - - /// Return true if the connection was made with a `ClientConfig` that is FIPS compatible. - /// - /// This is different from [`crate::crypto::CryptoProvider::fips()`]: - /// it is concerned only with cryptography, whereas this _also_ covers TLS-level - /// configuration that NIST recommends, as well as ECH HPKE suites if applicable. - pub fn fips(&self) -> bool { - self.inner.core.common_state.fips - } - - fn write_early_data(&mut self, data: &[u8]) -> io::Result<usize> { - self.inner - .core - .data - .early_data - .check_write(data.len()) - .map(|sz| { - self.inner - .send_early_plaintext(&data[..sz]) - }) - } - } - - impl Deref for ClientConnection { - type Target = ConnectionCommon<ClientConnectionData>; - - fn deref(&self) -> &Self::Target { - &self.inner - } - } - - impl DerefMut for ClientConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } - } - - #[doc(hidden)] - impl<'a> TryFrom<&'a mut crate::Connection> for &'a mut ClientConnection { - type Error = (); - - fn try_from(value: &'a mut crate::Connection) -> Result<Self, Self::Error> { - use crate::Connection::*; - match value { - Client(conn) => Ok(conn), - Server(_) => Err(()), - } - } - } - - impl From<ClientConnection> for crate::Connection { - fn from(conn: ClientConnection) -> Self { - Self::Client(conn) - } - } -} -#[cfg(feature = "std")] -pub use connection::{ClientConnection, WriteEarlyData}; - -impl ConnectionCore<ClientConnectionData> { - pub(crate) fn for_client( - config: Arc<ClientConfig>, - name: ServerName<'static>, - extra_exts: ClientExtensionsInput<'static>, - proto: Protocol, - ) -> Result<Self, Error> { - let mut common_state = CommonState::new(Side::Client); - common_state.set_max_fragment_size(config.max_fragment_size)?; - common_state.protocol = proto; - common_state.enable_secret_extraction = config.enable_secret_extraction; - common_state.fips = config.fips(); - let mut data = ClientConnectionData::new(); - - let mut cx = hs::ClientContext { - common: &mut common_state, - data: &mut data, - // `start_handshake` won't produce plaintext - sendable_plaintext: None, - }; - - let input = ClientHelloInput::new(name, &extra_exts, &mut cx, config)?; - let state = input.start_handshake(extra_exts, &mut cx)?; - Ok(Self::new(state, data, common_state)) - } - - #[cfg(feature = "std")] - pub(crate) fn is_early_data_accepted(&self) -> bool { - self.data.early_data.is_accepted() - } -} - -/// Unbuffered version of `ClientConnection` -/// -/// See the [`crate::unbuffered`] module docs for more details -pub struct UnbufferedClientConnection { - inner: UnbufferedConnectionCommon<ClientConnectionData>, -} - -impl UnbufferedClientConnection { - /// Make a new ClientConnection. `config` controls how we behave in the TLS protocol, `name` is - /// the name of the server we want to talk to. - pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> { - Self::new_with_extensions( - config.clone(), - name, - ClientExtensionsInput::from_alpn(config.alpn_protocols.clone()), - ) - } - - /// Make a new UnbufferedClientConnection with custom ALPN protocols. - pub fn new_with_alpn( - config: Arc<ClientConfig>, - name: ServerName<'static>, - alpn_protocols: Vec<Vec<u8>>, - ) -> Result<Self, Error> { - Self::new_with_extensions( - config, - name, - ClientExtensionsInput::from_alpn(alpn_protocols), - ) - } - - fn new_with_extensions( - config: Arc<ClientConfig>, - name: ServerName<'static>, - extensions: ClientExtensionsInput<'static>, - ) -> Result<Self, Error> { - Ok(Self { - inner: UnbufferedConnectionCommon::from(ConnectionCore::for_client( - config, - name, - extensions, - Protocol::Tcp, - )?), - }) - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - /// Should be used with care as it exposes secret key material. - #[deprecated = "dangerous_extract_secrets() does not support session tickets or \ - key updates, use dangerous_into_kernel_connection() instead"] - pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { - self.inner.dangerous_extract_secrets() - } - - /// Extract secrets and a [`KernelConnection`] object. - /// - /// This allows you use rustls to manage keys and then manage encryption and - /// decryption yourself (e.g. for kTLS). - /// - /// Should be used with care as it exposes secret key material. - /// - /// See the [`crate::kernel`] documentations for details on prerequisites - /// for calling this method. - pub fn dangerous_into_kernel_connection( - self, - ) -> Result<(ExtractedSecrets, KernelConnection<ClientConnectionData>), Error> { - self.inner - .core - .dangerous_into_kernel_connection() - } - - /// Returns the number of TLS1.3 tickets that have been received. - pub fn tls13_tickets_received(&self) -> u32 { - self.inner.tls13_tickets_received - } -} - -impl Deref for UnbufferedClientConnection { - type Target = UnbufferedConnectionCommon<ClientConnectionData>; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for UnbufferedClientConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl TransmitTlsData<'_, ClientConnectionData> { - /// returns an adapter that allows encrypting early (RTT-0) data before transmitting the - /// already encoded TLS data - /// - /// IF allowed by the protocol - pub fn may_encrypt_early_data(&mut self) -> Option<MayEncryptEarlyData<'_>> { - if self - .conn - .core - .data - .early_data - .is_enabled() - { - Some(MayEncryptEarlyData { conn: self.conn }) - } else { - None - } - } -} - -/// Allows encrypting early (RTT-0) data -pub struct MayEncryptEarlyData<'c> { - conn: &'c mut UnbufferedConnectionCommon<ClientConnectionData>, -} - -impl MayEncryptEarlyData<'_> { - /// Encrypts `application_data` into the `outgoing_tls` buffer - /// - /// returns the number of bytes that were written into `outgoing_tls`, or an error if - /// the provided buffer was too small. In the error case, `outgoing_tls` is not modified - pub fn encrypt( - &mut self, - early_data: &[u8], - outgoing_tls: &mut [u8], - ) -> Result<usize, EarlyDataError> { - let Some(allowed) = self - .conn - .core - .data - .early_data - .check_write_opt(early_data.len()) - else { - return Err(EarlyDataError::ExceededAllowedEarlyData); - }; - - self.conn - .core - .common_state - .write_plaintext(early_data[..allowed].into(), outgoing_tls) - .map_err(|e| e.into()) - } -} - -/// Errors that may arise when encrypting early (RTT-0) data -#[derive(Debug)] -pub enum EarlyDataError { - /// Cannot encrypt more early data due to imposed limits - ExceededAllowedEarlyData, - /// Encryption error - Encrypt(EncryptError), -} - -impl From<EncryptError> for EarlyDataError { - fn from(v: EncryptError) -> Self { - Self::Encrypt(v) - } -} - -impl fmt::Display for EarlyDataError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::ExceededAllowedEarlyData => f.write_str("cannot send any more early data"), - Self::Encrypt(e) => fmt::Display::fmt(e, f), - } - } -} - -#[cfg(feature = "std")] -impl std::error::Error for EarlyDataError {} - -/// State associated with a client connection. -#[derive(Debug)] -pub struct ClientConnectionData { - pub(super) early_data: EarlyData, - pub(super) ech_status: EchStatus, -} - -impl ClientConnectionData { - fn new() -> Self { - Self { - early_data: EarlyData::new(), - ech_status: EchStatus::NotOffered, - } - } -} - -impl crate::conn::SideData for ClientConnectionData {} diff --git a/vendor/rustls/src/client/common.rs b/vendor/rustls/src/client/common.rs deleted file mode 100644 index 9afa0c34..00000000 --- a/vendor/rustls/src/client/common.rs +++ /dev/null @@ -1,119 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; - -use super::ResolvesClientCert; -use crate::log::{debug, trace}; -use crate::msgs::enums::ExtensionType; -use crate::msgs::handshake::{CertificateChain, DistinguishedName, ProtocolName, ServerExtensions}; -use crate::sync::Arc; -use crate::{SignatureScheme, compress, sign}; - -#[derive(Debug)] -pub(super) struct ServerCertDetails<'a> { - pub(super) cert_chain: CertificateChain<'a>, - pub(super) ocsp_response: Vec<u8>, -} - -impl<'a> ServerCertDetails<'a> { - pub(super) fn new(cert_chain: CertificateChain<'a>, ocsp_response: Vec<u8>) -> Self { - Self { - cert_chain, - ocsp_response, - } - } - - pub(super) fn into_owned(self) -> ServerCertDetails<'static> { - let Self { - cert_chain, - ocsp_response, - } = self; - ServerCertDetails { - cert_chain: cert_chain.into_owned(), - ocsp_response, - } - } -} - -pub(super) struct ClientHelloDetails { - pub(super) alpn_protocols: Vec<ProtocolName>, - pub(super) sent_extensions: Vec<ExtensionType>, - pub(super) extension_order_seed: u16, - pub(super) offered_cert_compression: bool, -} - -impl ClientHelloDetails { - pub(super) fn new(alpn_protocols: Vec<ProtocolName>, extension_order_seed: u16) -> Self { - Self { - alpn_protocols, - sent_extensions: Vec::new(), - extension_order_seed, - offered_cert_compression: false, - } - } - - pub(super) fn server_sent_unsolicited_extensions( - &self, - received_exts: &ServerExtensions<'_>, - allowed_unsolicited: &[ExtensionType], - ) -> bool { - let mut extensions = received_exts.collect_used(); - extensions.extend( - received_exts - .unknown_extensions - .iter() - .map(|ext| ExtensionType::from(*ext)), - ); - for ext_type in extensions { - if !self.sent_extensions.contains(&ext_type) && !allowed_unsolicited.contains(&ext_type) - { - trace!("Unsolicited extension {ext_type:?}"); - return true; - } - } - - false - } -} - -pub(super) enum ClientAuthDetails { - /// Send an empty `Certificate` and no `CertificateVerify`. - Empty { auth_context_tls13: Option<Vec<u8>> }, - /// Send a non-empty `Certificate` and a `CertificateVerify`. - Verify { - certkey: Arc<sign::CertifiedKey>, - signer: Box<dyn sign::Signer>, - auth_context_tls13: Option<Vec<u8>>, - compressor: Option<&'static dyn compress::CertCompressor>, - }, -} - -impl ClientAuthDetails { - pub(super) fn resolve( - resolver: &dyn ResolvesClientCert, - canames: Option<&[DistinguishedName]>, - sigschemes: &[SignatureScheme], - auth_context_tls13: Option<Vec<u8>>, - compressor: Option<&'static dyn compress::CertCompressor>, - ) -> Self { - let acceptable_issuers = canames - .unwrap_or_default() - .iter() - .map(|p| p.as_ref()) - .collect::<Vec<&[u8]>>(); - - if let Some(certkey) = resolver.resolve(&acceptable_issuers, sigschemes) { - if let Some(signer) = certkey.key.choose_scheme(sigschemes) { - debug!("Attempting client auth"); - return Self::Verify { - certkey, - signer, - auth_context_tls13, - compressor, - }; - } - } - - debug!("Client auth requested but no cert/sigscheme available"); - Self::Empty { auth_context_tls13 } - } -} diff --git a/vendor/rustls/src/client/ech.rs b/vendor/rustls/src/client/ech.rs deleted file mode 100644 index 616ebbfc..00000000 --- a/vendor/rustls/src/client/ech.rs +++ /dev/null @@ -1,899 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; - -use pki_types::{DnsName, EchConfigListBytes, ServerName}; -use subtle::ConstantTimeEq; - -use crate::CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV; -use crate::client::tls13; -use crate::crypto::SecureRandom; -use crate::crypto::hash::Hash; -use crate::crypto::hpke::{EncapsulatedSecret, Hpke, HpkePublicKey, HpkeSealer, HpkeSuite}; -use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; -use crate::log::{debug, trace, warn}; -use crate::msgs::base::{Payload, PayloadU16}; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::{ExtensionType, HpkeKem}; -use crate::msgs::handshake::{ - ClientExtensions, ClientHelloPayload, EchConfigContents, EchConfigPayload, Encoding, - EncryptedClientHello, EncryptedClientHelloOuter, HandshakeMessagePayload, HandshakePayload, - HelloRetryRequest, HpkeKeyConfig, HpkeSymmetricCipherSuite, PresharedKeyBinder, - PresharedKeyOffer, Random, ServerHelloPayload, ServerNamePayload, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::msgs::persist::Retrieved; -use crate::tls13::key_schedule::{ - KeyScheduleEarly, KeyScheduleHandshakeStart, server_ech_hrr_confirmation_secret, -}; -use crate::{ - AlertDescription, ClientConfig, CommonState, EncryptedClientHelloError, Error, - PeerIncompatible, PeerMisbehaved, ProtocolVersion, Tls13CipherSuite, -}; - -/// Controls how Encrypted Client Hello (ECH) is used in a client handshake. -#[derive(Clone, Debug)] -pub enum EchMode { - /// ECH is enabled and the ClientHello will be encrypted based on the provided - /// configuration. - Enable(EchConfig), - - /// No ECH configuration is available but the client should act as though it were. - /// - /// This is an anti-ossification measure, sometimes referred to as "GREASE"[^0]. - /// [^0]: <https://www.rfc-editor.org/rfc/rfc8701> - Grease(EchGreaseConfig), -} - -impl EchMode { - /// Returns true if the ECH mode will use a FIPS approved HPKE suite. - pub fn fips(&self) -> bool { - match self { - Self::Enable(ech_config) => ech_config.suite.fips(), - Self::Grease(grease_config) => grease_config.suite.fips(), - } - } -} - -impl From<EchConfig> for EchMode { - fn from(config: EchConfig) -> Self { - Self::Enable(config) - } -} - -impl From<EchGreaseConfig> for EchMode { - fn from(config: EchGreaseConfig) -> Self { - Self::Grease(config) - } -} - -/// Configuration for performing encrypted client hello. -/// -/// Note: differs from the protocol-encoded EchConfig (`EchConfigMsg`). -#[derive(Clone, Debug)] -pub struct EchConfig { - /// The selected EchConfig. - pub(crate) config: EchConfigPayload, - - /// An HPKE instance corresponding to a suite from the `config` we have selected as - /// a compatible choice. - pub(crate) suite: &'static dyn Hpke, -} - -impl EchConfig { - /// Construct an EchConfig by selecting a ECH config from the provided bytes that is compatible - /// with one of the given HPKE suites. - /// - /// The config list bytes should be sourced from a DNS-over-HTTPS lookup resolving the `HTTPS` - /// resource record for the host name of the server you wish to connect via ECH, - /// and extracting the ECH configuration from the `ech` parameter. The extracted bytes should - /// be base64 decoded to yield the `EchConfigListBytes` you provide to rustls. - /// - /// One of the provided ECH configurations must be compatible with the HPKE provider's supported - /// suites or an error will be returned. - /// - /// See the [`ech-client.rs`] example for a complete example of fetching ECH configs from DNS. - /// - /// [`ech-client.rs`]: https://github.com/rustls/rustls/blob/main/examples/src/bin/ech-client.rs - pub fn new( - ech_config_list: EchConfigListBytes<'_>, - hpke_suites: &[&'static dyn Hpke], - ) -> Result<Self, Error> { - let ech_configs = Vec::<EchConfigPayload>::read(&mut Reader::init(&ech_config_list)) - .map_err(|_| { - Error::InvalidEncryptedClientHello(EncryptedClientHelloError::InvalidConfigList) - })?; - - // Note: we name the index var _i because if the log feature is disabled - // it is unused. - #[cfg_attr(not(feature = "logging"), allow(clippy::unused_enumerate_index))] - for (_i, config) in ech_configs.iter().enumerate() { - let contents = match config { - EchConfigPayload::V18(contents) => contents, - EchConfigPayload::Unknown { - version: _version, .. - } => { - warn!( - "ECH config {} has unsupported version {:?}", - _i + 1, - _version - ); - continue; // Unsupported version. - } - }; - - if contents.has_unknown_mandatory_extension() || contents.has_duplicate_extension() { - warn!("ECH config has duplicate, or unknown mandatory extensions: {contents:?}",); - continue; // Unsupported, or malformed extensions. - } - - let key_config = &contents.key_config; - for cipher_suite in &key_config.symmetric_cipher_suites { - if cipher_suite.aead_id.tag_len().is_none() { - continue; // Unsupported EXPORT_ONLY AEAD cipher suite. - } - - let suite = HpkeSuite { - kem: key_config.kem_id, - sym: *cipher_suite, - }; - if let Some(hpke) = hpke_suites - .iter() - .find(|hpke| hpke.suite() == suite) - { - debug!( - "selected ECH config ID {:?} suite {:?} public_name {:?}", - key_config.config_id, suite, contents.public_name - ); - return Ok(Self { - config: config.clone(), - suite: *hpke, - }); - } - } - } - - Err(EncryptedClientHelloError::NoCompatibleConfig.into()) - } - - pub(super) fn state( - &self, - server_name: ServerName<'static>, - config: &ClientConfig, - ) -> Result<EchState, Error> { - EchState::new( - self, - server_name.clone(), - config - .client_auth_cert_resolver - .has_certs(), - config.provider.secure_random, - config.enable_sni, - ) - } - - /// Compute the HPKE `SetupBaseS` `info` parameter for this ECH configuration. - /// - /// See <https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#section-6.1>. - pub(crate) fn hpke_info(&self) -> Vec<u8> { - let mut info = Vec::with_capacity(128); - // "tls ech" || 0x00 || ECHConfig - info.extend_from_slice(b"tls ech\0"); - self.config.encode(&mut info); - info - } -} - -/// Configuration for GREASE Encrypted Client Hello. -#[derive(Clone, Debug)] -pub struct EchGreaseConfig { - pub(crate) suite: &'static dyn Hpke, - pub(crate) placeholder_key: HpkePublicKey, -} - -impl EchGreaseConfig { - /// Construct a GREASE ECH configuration. - /// - /// This configuration is used when the client wishes to offer ECH to prevent ossification, - /// but doesn't have a real ECH configuration to use for the remote server. In this case - /// a placeholder or "GREASE"[^0] extension is used. - /// - /// Returns an error if the HPKE provider does not support the given suite. - /// - /// [^0]: <https://www.rfc-editor.org/rfc/rfc8701> - pub fn new(suite: &'static dyn Hpke, placeholder_key: HpkePublicKey) -> Self { - Self { - suite, - placeholder_key, - } - } - - /// Build a GREASE ECH extension based on the placeholder configuration. - /// - /// See <https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#name-grease-ech> for - /// more information. - pub(crate) fn grease_ext( - &self, - secure_random: &'static dyn SecureRandom, - inner_name: ServerName<'static>, - outer_hello: &ClientHelloPayload, - ) -> Result<EncryptedClientHello, Error> { - trace!("Preparing GREASE ECH extension"); - - // Pick a random config id. - let mut config_id: [u8; 1] = [0; 1]; - secure_random.fill(&mut config_id[..])?; - - let suite = self.suite.suite(); - - // Construct a dummy ECH state - we don't have a real ECH config from a server since - // this is for GREASE. - let mut grease_state = EchState::new( - &EchConfig { - config: EchConfigPayload::V18(EchConfigContents { - key_config: HpkeKeyConfig { - config_id: config_id[0], - kem_id: HpkeKem::DHKEM_P256_HKDF_SHA256, - public_key: PayloadU16::new(self.placeholder_key.0.clone()), - symmetric_cipher_suites: vec![suite.sym], - }, - maximum_name_length: 0, - public_name: DnsName::try_from("filler").unwrap(), - extensions: Vec::default(), - }), - suite: self.suite, - }, - inner_name, - false, - secure_random, - false, // Does not matter if we enable/disable SNI here. Inner hello is not used. - )?; - - // Construct an inner hello using the outer hello - this allows us to know the size of - // dummy payload we should use for the GREASE extension. - let encoded_inner_hello = grease_state.encode_inner_hello(outer_hello, None, &None); - - // Generate a payload of random data equivalent in length to a real inner hello. - let payload_len = encoded_inner_hello.len() - + suite - .sym - .aead_id - .tag_len() - // Safety: we have confirmed the AEAD is supported when building the config. All - // supported AEADs have a tag length. - .unwrap(); - let mut payload = vec![0; payload_len]; - secure_random.fill(&mut payload)?; - - // Return the GREASE extension. - Ok(EncryptedClientHello::Outer(EncryptedClientHelloOuter { - cipher_suite: suite.sym, - config_id: config_id[0], - enc: PayloadU16::new(grease_state.enc.0), - payload: PayloadU16::new(payload), - })) - } -} - -/// An enum representing ECH offer status. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub enum EchStatus { - /// ECH was not offered - it is a normal TLS handshake. - NotOffered, - /// GREASE ECH was sent. This is not considered offering ECH. - Grease, - /// ECH was offered but we do not yet know whether the offer was accepted or rejected. - Offered, - /// ECH was offered and the server accepted. - Accepted, - /// ECH was offered and the server rejected. - Rejected, -} - -/// Contextual data for a TLS client handshake that has offered encrypted client hello (ECH). -pub(crate) struct EchState { - // The public DNS name from the ECH configuration we've chosen - this is included as the SNI - // value for the "outer" client hello. It can only be a DnsName, not an IP address. - pub(crate) outer_name: DnsName<'static>, - // If we're resuming in the inner hello, this is the early key schedule to use for encrypting - // early data if the ECH offer is accepted. - pub(crate) early_data_key_schedule: Option<KeyScheduleEarly>, - // A random value we use for the inner hello. - pub(crate) inner_hello_random: Random, - // A transcript buffer maintained for the inner hello. Once ECH is confirmed we switch to - // using this transcript for the handshake. - pub(crate) inner_hello_transcript: HandshakeHashBuffer, - // A source of secure random data. - secure_random: &'static dyn SecureRandom, - // An HPKE sealer context that can be used for encrypting ECH data. - sender: Box<dyn HpkeSealer>, - // The ID of the ECH configuration we've chosen - this is included in the outer ECH extension. - config_id: u8, - // The private server name we'll use for the inner protected hello. - inner_name: ServerName<'static>, - // The advertised maximum name length from the ECH configuration we've chosen - this is used - // for padding calculations. - maximum_name_length: u8, - // A supported symmetric cipher suite from the ECH configuration we've chosen - this is - // included in the outer ECH extension. - cipher_suite: HpkeSymmetricCipherSuite, - // A secret encapsulated to the public key of the remote server. This is included in the - // outer ECH extension for non-retry outer hello messages. - enc: EncapsulatedSecret, - // Whether the inner client hello should contain a server name indication (SNI) extension. - enable_sni: bool, - // The extensions sent in the inner hello. - sent_extensions: Vec<ExtensionType>, -} - -impl EchState { - pub(crate) fn new( - config: &EchConfig, - inner_name: ServerName<'static>, - client_auth_enabled: bool, - secure_random: &'static dyn SecureRandom, - enable_sni: bool, - ) -> Result<Self, Error> { - let EchConfigPayload::V18(config_contents) = &config.config else { - // the public EchConfig::new() constructor ensures we only have supported - // configurations. - unreachable!("ECH config version mismatch"); - }; - let key_config = &config_contents.key_config; - - // Encapsulate a secret for the server's public key, and set up a sender context - // we can use to seal messages. - let (enc, sender) = config.suite.setup_sealer( - &config.hpke_info(), - &HpkePublicKey(key_config.public_key.0.clone()), - )?; - - // Start a new transcript buffer for the inner hello. - let mut inner_hello_transcript = HandshakeHashBuffer::new(); - if client_auth_enabled { - inner_hello_transcript.set_client_auth_enabled(); - } - - Ok(Self { - secure_random, - sender, - config_id: key_config.config_id, - inner_name, - outer_name: config_contents.public_name.clone(), - maximum_name_length: config_contents.maximum_name_length, - cipher_suite: config.suite.suite().sym, - enc, - inner_hello_random: Random::new(secure_random)?, - inner_hello_transcript, - early_data_key_schedule: None, - enable_sni, - sent_extensions: Vec::new(), - }) - } - - /// Construct a ClientHelloPayload offering ECH. - /// - /// An outer hello, with a protected inner hello for the `inner_name` will be returned, and the - /// ECH context will be updated to reflect the inner hello that was offered. - /// - /// If `retry_req` is `Some`, then the outer hello will be constructed for a hello retry request. - /// - /// If `resuming` is `Some`, then the inner hello will be constructed for a resumption handshake. - pub(crate) fn ech_hello( - &mut self, - mut outer_hello: ClientHelloPayload, - retry_req: Option<&HelloRetryRequest>, - resuming: &Option<Retrieved<&persist::Tls13ClientSessionValue>>, - ) -> Result<ClientHelloPayload, Error> { - trace!( - "Preparing ECH offer {}", - if retry_req.is_some() { "for retry" } else { "" } - ); - - // Construct the encoded inner hello and update the transcript. - let encoded_inner_hello = self.encode_inner_hello(&outer_hello, retry_req, resuming); - - // Complete the ClientHelloOuterAAD with an ech extension, the payload should be a placeholder - // of size L, all zeroes. L == length of encrypting encoded client hello inner w/ the selected - // HPKE AEAD. (sum of plaintext + tag length, typically). - let payload_len = encoded_inner_hello.len() - + self - .cipher_suite - .aead_id - .tag_len() - // Safety: we've already verified this AEAD is supported when loading the config - // that was used to create the ECH context. All supported AEADs have a tag length. - .unwrap(); - - // Outer hello's created in response to a hello retry request omit the enc value. - let enc = match retry_req.is_some() { - true => Vec::default(), - false => self.enc.0.clone(), - }; - - fn outer_hello_ext(ctx: &EchState, enc: Vec<u8>, payload: Vec<u8>) -> EncryptedClientHello { - EncryptedClientHello::Outer(EncryptedClientHelloOuter { - cipher_suite: ctx.cipher_suite, - config_id: ctx.config_id, - enc: PayloadU16::new(enc), - payload: PayloadU16::new(payload), - }) - } - - // The outer handshake is not permitted to resume a session. If we're resuming in the - // inner handshake we remove the PSK extension from the outer hello, replacing it - // with a GREASE PSK to implement the "ClientHello Malleability Mitigation" mentioned - // in 10.12.3. - if let Some(psk_offer) = outer_hello.preshared_key_offer.as_mut() { - self.grease_psk(psk_offer)?; - } - - // To compute the encoded AAD we add a placeholder extension with an empty payload. - outer_hello.encrypted_client_hello = - Some(outer_hello_ext(self, enc.clone(), vec![0; payload_len])); - - // Next we compute the proper extension payload. - let payload = self - .sender - .seal(&outer_hello.get_encoding(), &encoded_inner_hello)?; - - // And then we replace the placeholder extension with the real one. - outer_hello.encrypted_client_hello = Some(outer_hello_ext(self, enc, payload)); - - Ok(outer_hello) - } - - /// Confirm whether an ECH offer was accepted based on examining the server hello. - pub(crate) fn confirm_acceptance( - self, - ks: &mut KeyScheduleHandshakeStart, - server_hello: &ServerHelloPayload, - server_hello_encoded: &Payload<'_>, - hash: &'static dyn Hash, - ) -> Result<Option<EchAccepted>, Error> { - // Start the inner transcript hash now that we know the hash algorithm to use. - let inner_transcript = self - .inner_hello_transcript - .start_hash(hash); - - // Fork the transcript that we've started with the inner hello to use for a confirmation step. - // We need to preserve the original inner_transcript to use if this confirmation succeeds. - let mut confirmation_transcript = inner_transcript.clone(); - - // Add the server hello confirmation - this is computed by altering the received - // encoding rather than reencoding it. - confirmation_transcript - .add_message(&Self::server_hello_conf(server_hello, server_hello_encoded)); - - // Derive a confirmation secret from the inner hello random and the confirmation transcript. - let derived = ks.server_ech_confirmation_secret( - self.inner_hello_random.0.as_ref(), - confirmation_transcript.current_hash(), - ); - - // Check that first 8 digits of the derived secret match the last 8 digits of the original - // server random. This match signals that the server accepted the ECH offer. - // Indexing safety: Random is [0; 32] by construction. - - match ConstantTimeEq::ct_eq(derived.as_ref(), server_hello.random.0[24..].as_ref()).into() { - true => { - trace!("ECH accepted by server"); - Ok(Some(EchAccepted { - transcript: inner_transcript, - random: self.inner_hello_random, - sent_extensions: self.sent_extensions, - })) - } - false => { - trace!("ECH rejected by server"); - Ok(None) - } - } - } - - pub(crate) fn confirm_hrr_acceptance( - &self, - hrr: &HelloRetryRequest, - cs: &Tls13CipherSuite, - common: &mut CommonState, - ) -> Result<bool, Error> { - // The client checks for the "encrypted_client_hello" extension. - let ech_conf = match &hrr.encrypted_client_hello { - // If none is found, the server has implicitly rejected ECH. - None => return Ok(false), - // Otherwise, if it has a length other than 8, the client aborts the - // handshake with a "decode_error" alert. - Some(ech_conf) if ech_conf.bytes().len() != 8 => { - return Err({ - common.send_fatal_alert( - AlertDescription::DecodeError, - PeerMisbehaved::IllegalHelloRetryRequestWithInvalidEch, - ) - }); - } - Some(ech_conf) => ech_conf, - }; - - // Otherwise the client computes hrr_accept_confirmation as described in Section - // 7.2.1 - let confirmation_transcript = self.inner_hello_transcript.clone(); - let mut confirmation_transcript = - confirmation_transcript.start_hash(cs.common.hash_provider); - confirmation_transcript.rollup_for_hrr(); - confirmation_transcript.add_message(&Self::hello_retry_request_conf(hrr)); - - let derived = server_ech_hrr_confirmation_secret( - cs.hkdf_provider, - &self.inner_hello_random.0, - confirmation_transcript.current_hash(), - ); - - match ConstantTimeEq::ct_eq(derived.as_ref(), ech_conf.bytes()).into() { - true => { - trace!("ECH accepted by server in hello retry request"); - Ok(true) - } - false => { - trace!("ECH rejected by server in hello retry request"); - Ok(false) - } - } - } - - /// Update the ECH context inner hello transcript based on a received hello retry request message. - /// - /// This will start the in-progress transcript using the given `hash`, convert it into an HRR - /// buffer, and then add the hello retry message `m`. - pub(crate) fn transcript_hrr_update(&mut self, hash: &'static dyn Hash, m: &Message<'_>) { - trace!("Updating ECH inner transcript for HRR"); - - let inner_transcript = self - .inner_hello_transcript - .clone() - .start_hash(hash); - - let mut inner_transcript_buffer = inner_transcript.into_hrr_buffer(); - inner_transcript_buffer.add_message(m); - self.inner_hello_transcript = inner_transcript_buffer; - } - - // 5.1 "Encoding the ClientHelloInner" - fn encode_inner_hello( - &mut self, - outer_hello: &ClientHelloPayload, - retryreq: Option<&HelloRetryRequest>, - resuming: &Option<Retrieved<&persist::Tls13ClientSessionValue>>, - ) -> Vec<u8> { - // Start building an inner hello using the outer_hello as a template. - let mut inner_hello = ClientHelloPayload { - // Some information is copied over as-is. - client_version: outer_hello.client_version, - session_id: outer_hello.session_id, - compression_methods: outer_hello.compression_methods.clone(), - - // We will build up the included extensions ourselves. - extensions: Box::new(ClientExtensions::default()), - - // Set the inner hello random to the one we generated when creating the ECH state. - // We hold on to the inner_hello_random in the ECH state to use later for confirming - // whether ECH was accepted or not. - random: self.inner_hello_random, - - // We remove the empty renegotiation info SCSV from the outer hello's ciphersuite. - // Similar to the TLS 1.2 specific extensions we will filter out, this is seen as a - // TLS 1.2 only feature by bogo. - cipher_suites: outer_hello - .cipher_suites - .iter() - .filter(|cs| **cs != TLS_EMPTY_RENEGOTIATION_INFO_SCSV) - .cloned() - .collect(), - }; - - inner_hello.order_seed = outer_hello.order_seed; - - // The inner hello will always have an inner variant of the ECH extension added. - // See Section 6.1 rule 4. - inner_hello.encrypted_client_hello = Some(EncryptedClientHello::Inner); - - let inner_sni = match &self.inner_name { - // The inner hello only gets a SNI value if enable_sni is true and the inner name - // is a domain name (not an IP address). - ServerName::DnsName(dns_name) if self.enable_sni => Some(dns_name), - _ => None, - }; - - // Now we consider each of the outer hello's extensions - we can either: - // 1. Omit the extension if it isn't appropriate (e.g. is a TLS 1.2 extension). - // 2. Add the extension to the inner hello as-is. - // 3. Compress the extension, by collecting it into a list of to-be-compressed - // extensions we'll handle separately. - let outer_extensions = outer_hello.used_extensions_in_encoding_order(); - let mut compressed_exts = Vec::with_capacity(outer_extensions.len()); - for ext in outer_extensions { - // Some outer hello extensions are only useful in the context where a TLS 1.3 - // connection allows TLS 1.2. This isn't the case for ECH so we skip adding them - // to the inner hello. - if matches!( - ext, - ExtensionType::ExtendedMasterSecret - | ExtensionType::SessionTicket - | ExtensionType::ECPointFormats - ) { - continue; - } - - if ext == ExtensionType::ServerName { - // We may want to replace the outer hello SNI with our own inner hello specific SNI. - if let Some(sni_value) = inner_sni { - inner_hello.server_name = Some(ServerNamePayload::from(sni_value)); - } - // We don't want to add, or compress, the SNI from the outer hello. - continue; - } - - // Compressed extensions need to be put aside to include in one contiguous block. - // Uncompressed extensions get added directly to the inner hello. - if ext.ech_compress() { - compressed_exts.push(ext); - } - - inner_hello.clone_one(outer_hello, ext); - } - - // We've added all the uncompressed extensions. Now we need to add the contiguous - // block of to-be-compressed extensions. - inner_hello.contiguous_extensions = compressed_exts.clone(); - - // Note which extensions we're sending in the inner hello. This may differ from - // the outer hello (e.g. the inner hello may omit SNI while the outer hello will - // always have the ECH cover name in SNI). - self.sent_extensions = inner_hello.collect_used(); - - // If we're resuming, we need to update the PSK binder in the inner hello. - if let Some(resuming) = resuming.as_ref() { - let mut chp = HandshakeMessagePayload(HandshakePayload::ClientHello(inner_hello)); - - // Retain the early key schedule we get from processing the binder. - self.early_data_key_schedule = Some(tls13::fill_in_psk_binder( - resuming, - &self.inner_hello_transcript, - &mut chp, - )); - - // fill_in_psk_binder works on an owned HandshakeMessagePayload, so we need to - // extract our inner hello back out of it to retain ownership. - inner_hello = match chp.0 { - HandshakePayload::ClientHello(chp) => chp, - // Safety: we construct the HMP above and know its type unconditionally. - _ => unreachable!(), - }; - } - - trace!("ECH Inner Hello: {inner_hello:#?}"); - - // Encode the inner hello according to the rules required for ECH. This differs - // from the standard encoding in several ways. Notably this is where we will - // replace the block of contiguous to-be-compressed extensions with a marker. - let mut encoded_hello = inner_hello.ech_inner_encoding(compressed_exts); - - // Calculate padding - // max_name_len = L - let max_name_len = self.maximum_name_length; - let max_name_len = if max_name_len > 0 { max_name_len } else { 255 }; - - let padding_len = match &self.inner_name { - ServerName::DnsName(name) => { - // name.len() = D - // max(0, L - D) - core::cmp::max( - 0, - max_name_len.saturating_sub(name.as_ref().len() as u8) as usize, - ) - } - _ => { - // L + 9 - // "This is the length of a "server_name" extension with an L-byte name." - // We widen to usize here to avoid overflowing u8 + u8. - max_name_len as usize + 9 - } - }; - - // Let L be the length of the EncodedClientHelloInner with all the padding computed so far - // Let N = 31 - ((L - 1) % 32) and add N bytes of padding. - let padding_len = 31 - ((encoded_hello.len() + padding_len - 1) % 32); - encoded_hello.extend(vec![0; padding_len]); - - // Construct the inner hello message that will be used for the transcript. - let inner_hello_msg = Message { - version: match retryreq { - // <https://datatracker.ietf.org/doc/html/rfc8446#section-5.1>: - // "This value MUST be set to 0x0303 for all records generated - // by a TLS 1.3 implementation ..." - Some(_) => ProtocolVersion::TLSv1_2, - // "... other than an initial ClientHello (i.e., one not - // generated after a HelloRetryRequest), where it MAY also be - // 0x0301 for compatibility purposes" - // - // (retryreq == None means we're in the "initial ClientHello" case) - None => ProtocolVersion::TLSv1_0, - }, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ClientHello(inner_hello), - )), - }; - - // Update the inner transcript buffer with the inner hello message. - self.inner_hello_transcript - .add_message(&inner_hello_msg); - - encoded_hello - } - - // See https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#name-grease-psk - fn grease_psk(&self, psk_offer: &mut PresharedKeyOffer) -> Result<(), Error> { - for ident in psk_offer.identities.iter_mut() { - // "For each PSK identity advertised in the ClientHelloInner, the - // client generates a random PSK identity with the same length." - self.secure_random - .fill(&mut ident.identity.0)?; - // "It also generates a random, 32-bit, unsigned integer to use as - // the obfuscated_ticket_age." - let mut ticket_age = [0_u8; 4]; - self.secure_random - .fill(&mut ticket_age)?; - ident.obfuscated_ticket_age = u32::from_be_bytes(ticket_age); - } - - // "Likewise, for each inner PSK binder, the client generates a random string - // of the same length." - psk_offer.binders = psk_offer - .binders - .iter() - .map(|old_binder| { - // We can't access the wrapped binder PresharedKeyBinder's PayloadU8 mutably, - // so we construct new PresharedKeyBinder's from scratch with the same length. - let mut new_binder = vec![0; old_binder.as_ref().len()]; - self.secure_random - .fill(&mut new_binder)?; - Ok::<PresharedKeyBinder, Error>(PresharedKeyBinder::from(new_binder)) - }) - .collect::<Result<_, _>>()?; - Ok(()) - } - - fn server_hello_conf( - server_hello: &ServerHelloPayload, - server_hello_encoded: &Payload<'_>, - ) -> Message<'static> { - // The confirmation is computed over the server hello, which has had - // its `random` field altered to zero the final 8 bytes. - // - // nb. we don't require that we can round-trip a `ServerHelloPayload`, to - // allow for efficiency in its in-memory representation. That means - // we operate here on the received encoding, as the confirmation needs - // to be computed on that. - let mut encoded = server_hello_encoded.clone().into_vec(); - encoded[SERVER_HELLO_ECH_CONFIRMATION_SPAN].fill(0x00); - - Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::Handshake { - encoded: Payload::Owned(encoded), - parsed: HandshakeMessagePayload(HandshakePayload::ServerHello( - server_hello.clone(), - )), - }, - } - } - - fn hello_retry_request_conf(retry_req: &HelloRetryRequest) -> Message<'_> { - Self::ech_conf_message(HandshakeMessagePayload( - HandshakePayload::HelloRetryRequest(retry_req.clone()), - )) - } - - fn ech_conf_message(hmp: HandshakeMessagePayload<'_>) -> Message<'_> { - let mut hmp_encoded = Vec::new(); - hmp.payload_encode(&mut hmp_encoded, Encoding::EchConfirmation); - Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::Handshake { - encoded: Payload::new(hmp_encoded), - parsed: hmp, - }, - } - } -} - -/// The last eight bytes of the ServerHello's random, taken from a Handshake message containing it. -/// -/// This has: -/// - a HandshakeType (1 byte), -/// - an exterior length (3 bytes), -/// - the legacy_version (2 bytes), and -/// - the balance of the random field (24 bytes). -const SERVER_HELLO_ECH_CONFIRMATION_SPAN: core::ops::Range<usize> = - (1 + 3 + 2 + 24)..(1 + 3 + 2 + 32); - -/// Returned from EchState::check_acceptance when the server has accepted the ECH offer. -/// -/// Holds the state required to continue the handshake with the inner hello from the ECH offer. -pub(crate) struct EchAccepted { - pub(crate) transcript: HandshakeHash, - pub(crate) random: Random, - pub(crate) sent_extensions: Vec<ExtensionType>, -} - -pub(crate) fn fatal_alert_required( - retry_configs: Option<Vec<EchConfigPayload>>, - common: &mut CommonState, -) -> Error { - common.send_fatal_alert( - AlertDescription::EncryptedClientHelloRequired, - PeerIncompatible::ServerRejectedEncryptedClientHello(retry_configs), - ) -} - -#[cfg(test)] -mod tests { - use crate::enums::CipherSuite; - use crate::msgs::handshake::{Random, ServerExtensions, SessionId}; - - use super::*; - - #[test] - fn server_hello_conf_alters_server_hello_random() { - let server_hello = ServerHelloPayload { - legacy_version: ProtocolVersion::TLSv1_2, - random: Random([0xffu8; 32]), - session_id: SessionId::empty(), - cipher_suite: CipherSuite::TLS13_AES_256_GCM_SHA384, - compression_method: crate::msgs::enums::Compression::Null, - extensions: Box::new(ServerExtensions::default()), - }; - let message = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ServerHello(server_hello.clone()), - )), - }; - let Message { - payload: - MessagePayload::Handshake { - encoded: server_hello_encoded_before, - .. - }, - .. - } = &message - else { - unreachable!("ServerHello is a handshake message"); - }; - - let message = EchState::server_hello_conf(&server_hello, server_hello_encoded_before); - - let Message { - payload: - MessagePayload::Handshake { - encoded: server_hello_encoded_after, - .. - }, - .. - } = &message - else { - unreachable!("ServerHello is a handshake message"); - }; - - assert_eq!( - std::format!("{server_hello_encoded_before:x?}"), - "020000280303ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001302000000", - "beforehand eight bytes at end of Random should be 0xff here ^^^^^^^^^^^^^^^^ " - ); - assert_eq!( - std::format!("{server_hello_encoded_after:x?}"), - "020000280303ffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000001302000000", - " afterwards those bytes are zeroed ^^^^^^^^^^^^^^^^ " - ); - } -} diff --git a/vendor/rustls/src/client/handy.rs b/vendor/rustls/src/client/handy.rs deleted file mode 100644 index 3ad3073b..00000000 --- a/vendor/rustls/src/client/handy.rs +++ /dev/null @@ -1,390 +0,0 @@ -use pki_types::ServerName; - -use crate::enums::SignatureScheme; -use crate::msgs::persist; -use crate::sync::Arc; -use crate::{NamedGroup, client, sign}; - -/// An implementer of `ClientSessionStore` which does nothing. -#[derive(Debug)] -pub(super) struct NoClientSessionStorage; - -impl client::ClientSessionStore for NoClientSessionStorage { - fn set_kx_hint(&self, _: ServerName<'static>, _: NamedGroup) {} - - fn kx_hint(&self, _: &ServerName<'_>) -> Option<NamedGroup> { - None - } - - fn set_tls12_session(&self, _: ServerName<'static>, _: persist::Tls12ClientSessionValue) {} - - fn tls12_session(&self, _: &ServerName<'_>) -> Option<persist::Tls12ClientSessionValue> { - None - } - - fn remove_tls12_session(&self, _: &ServerName<'_>) {} - - fn insert_tls13_ticket(&self, _: ServerName<'static>, _: persist::Tls13ClientSessionValue) {} - - fn take_tls13_ticket(&self, _: &ServerName<'_>) -> Option<persist::Tls13ClientSessionValue> { - None - } -} - -#[cfg(any(feature = "std", feature = "hashbrown"))] -mod cache { - use alloc::collections::VecDeque; - use core::fmt; - - use pki_types::ServerName; - - use crate::lock::Mutex; - use crate::msgs::persist; - use crate::{NamedGroup, limited_cache}; - - const MAX_TLS13_TICKETS_PER_SERVER: usize = 8; - - struct ServerData { - kx_hint: Option<NamedGroup>, - - // Zero or one TLS1.2 sessions. - #[cfg(feature = "tls12")] - tls12: Option<persist::Tls12ClientSessionValue>, - - // Up to MAX_TLS13_TICKETS_PER_SERVER TLS1.3 tickets, oldest first. - tls13: VecDeque<persist::Tls13ClientSessionValue>, - } - - impl Default for ServerData { - fn default() -> Self { - Self { - kx_hint: None, - #[cfg(feature = "tls12")] - tls12: None, - tls13: VecDeque::with_capacity(MAX_TLS13_TICKETS_PER_SERVER), - } - } - } - - /// An implementer of `ClientSessionStore` that stores everything - /// in memory. - /// - /// It enforces a limit on the number of entries to bound memory usage. - pub struct ClientSessionMemoryCache { - servers: Mutex<limited_cache::LimitedCache<ServerName<'static>, ServerData>>, - } - - impl ClientSessionMemoryCache { - /// Make a new ClientSessionMemoryCache. `size` is the - /// maximum number of stored sessions. - #[cfg(feature = "std")] - pub fn new(size: usize) -> Self { - let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1) - / MAX_TLS13_TICKETS_PER_SERVER; - Self { - servers: Mutex::new(limited_cache::LimitedCache::new(max_servers)), - } - } - - /// Make a new ClientSessionMemoryCache. `size` is the - /// maximum number of stored sessions. - #[cfg(not(feature = "std"))] - pub fn new<M: crate::lock::MakeMutex>(size: usize) -> Self { - let max_servers = size.saturating_add(MAX_TLS13_TICKETS_PER_SERVER - 1) - / MAX_TLS13_TICKETS_PER_SERVER; - Self { - servers: Mutex::new::<M>(limited_cache::LimitedCache::new(max_servers)), - } - } - } - - impl super::client::ClientSessionStore for ClientSessionMemoryCache { - fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup) { - self.servers - .lock() - .unwrap() - .get_or_insert_default_and_edit(server_name, |data| data.kx_hint = Some(group)); - } - - fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup> { - self.servers - .lock() - .unwrap() - .get(server_name) - .and_then(|sd| sd.kx_hint) - } - - fn set_tls12_session( - &self, - _server_name: ServerName<'static>, - _value: persist::Tls12ClientSessionValue, - ) { - #[cfg(feature = "tls12")] - self.servers - .lock() - .unwrap() - .get_or_insert_default_and_edit(_server_name.clone(), |data| { - data.tls12 = Some(_value) - }); - } - - fn tls12_session( - &self, - _server_name: &ServerName<'_>, - ) -> Option<persist::Tls12ClientSessionValue> { - #[cfg(not(feature = "tls12"))] - return None; - - #[cfg(feature = "tls12")] - self.servers - .lock() - .unwrap() - .get(_server_name) - .and_then(|sd| sd.tls12.as_ref().cloned()) - } - - fn remove_tls12_session(&self, _server_name: &ServerName<'static>) { - #[cfg(feature = "tls12")] - self.servers - .lock() - .unwrap() - .get_mut(_server_name) - .and_then(|data| data.tls12.take()); - } - - fn insert_tls13_ticket( - &self, - server_name: ServerName<'static>, - value: persist::Tls13ClientSessionValue, - ) { - self.servers - .lock() - .unwrap() - .get_or_insert_default_and_edit(server_name.clone(), |data| { - if data.tls13.len() == data.tls13.capacity() { - data.tls13.pop_front(); - } - data.tls13.push_back(value); - }); - } - - fn take_tls13_ticket( - &self, - server_name: &ServerName<'static>, - ) -> Option<persist::Tls13ClientSessionValue> { - self.servers - .lock() - .unwrap() - .get_mut(server_name) - .and_then(|data| data.tls13.pop_back()) - } - } - - impl fmt::Debug for ClientSessionMemoryCache { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Note: we omit self.servers as it may contain sensitive data. - f.debug_struct("ClientSessionMemoryCache") - .finish() - } - } -} - -#[cfg(any(feature = "std", feature = "hashbrown"))] -pub use cache::ClientSessionMemoryCache; - -#[derive(Debug)] -pub(super) struct FailResolveClientCert {} - -impl client::ResolvesClientCert for FailResolveClientCert { - fn resolve( - &self, - _root_hint_subjects: &[&[u8]], - _sigschemes: &[SignatureScheme], - ) -> Option<Arc<sign::CertifiedKey>> { - None - } - - fn has_certs(&self) -> bool { - false - } -} - -/// An exemplar `ResolvesClientCert` implementation that always resolves to a single -/// [RFC 7250] raw public key. -/// -/// [RFC 7250]: https://tools.ietf.org/html/rfc7250 -#[derive(Clone, Debug)] -pub struct AlwaysResolvesClientRawPublicKeys(Arc<sign::CertifiedKey>); -impl AlwaysResolvesClientRawPublicKeys { - /// Create a new `AlwaysResolvesClientRawPublicKeys` instance. - pub fn new(certified_key: Arc<sign::CertifiedKey>) -> Self { - Self(certified_key) - } -} - -impl client::ResolvesClientCert for AlwaysResolvesClientRawPublicKeys { - fn resolve( - &self, - _root_hint_subjects: &[&[u8]], - _sigschemes: &[SignatureScheme], - ) -> Option<Arc<sign::CertifiedKey>> { - Some(self.0.clone()) - } - - fn only_raw_public_keys(&self) -> bool { - true - } - - /// Returns true if the resolver is ready to present an identity. - /// - /// Even though the function is called `has_certs`, it returns true - /// although only an RPK (Raw Public Key) is available, not an actual certificate. - fn has_certs(&self) -> bool { - true - } -} - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use std::prelude::v1::*; - - use pki_types::{ServerName, UnixTime}; - - use super::NoClientSessionStorage; - use super::provider::cipher_suite; - use crate::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; - use crate::client::{ClientSessionStore, ResolvesClientCert}; - use crate::msgs::base::PayloadU16; - use crate::msgs::enums::NamedGroup; - use crate::msgs::handshake::CertificateChain; - #[cfg(feature = "tls12")] - use crate::msgs::handshake::SessionId; - use crate::msgs::persist::Tls13ClientSessionValue; - use crate::pki_types::CertificateDer; - use crate::suites::SupportedCipherSuite; - use crate::sync::Arc; - use crate::{DigitallySignedStruct, Error, SignatureScheme, sign}; - - #[test] - fn test_noclientsessionstorage_does_nothing() { - let c = NoClientSessionStorage {}; - let name = ServerName::try_from("example.com").unwrap(); - let now = UnixTime::now(); - let server_cert_verifier: Arc<dyn ServerCertVerifier> = Arc::new(DummyServerCertVerifier); - let resolves_client_cert: Arc<dyn ResolvesClientCert> = Arc::new(DummyResolvesClientCert); - - c.set_kx_hint(name.clone(), NamedGroup::X25519); - assert_eq!(None, c.kx_hint(&name)); - - #[cfg(feature = "tls12")] - { - use crate::msgs::persist::Tls12ClientSessionValue; - let SupportedCipherSuite::Tls12(tls12_suite) = - cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - else { - unreachable!() - }; - - c.set_tls12_session( - name.clone(), - Tls12ClientSessionValue::new( - tls12_suite, - SessionId::empty(), - Arc::new(PayloadU16::empty()), - &[], - CertificateChain::default(), - &server_cert_verifier, - &resolves_client_cert, - now, - 0, - true, - ), - ); - assert!(c.tls12_session(&name).is_none()); - c.remove_tls12_session(&name); - } - - let SupportedCipherSuite::Tls13(tls13_suite) = cipher_suite::TLS13_AES_256_GCM_SHA384 - else { - unreachable!(); - }; - c.insert_tls13_ticket( - name.clone(), - Tls13ClientSessionValue::new( - tls13_suite, - Arc::new(PayloadU16::empty()), - &[], - CertificateChain::default(), - &server_cert_verifier, - &resolves_client_cert, - now, - 0, - 0, - 0, - ), - ); - assert!(c.take_tls13_ticket(&name).is_none()); - } - - #[derive(Debug)] - struct DummyServerCertVerifier; - - impl ServerCertVerifier for DummyServerCertVerifier { - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp_response: &[u8], - _now: UnixTime, - ) -> Result<ServerCertVerified, Error> { - unreachable!() - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - unreachable!() - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - unreachable!() - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn supported_verify_schemes(&self) -> Vec<SignatureScheme> { - unreachable!() - } - } - - #[derive(Debug)] - struct DummyResolvesClientCert; - - impl ResolvesClientCert for DummyResolvesClientCert { - #[cfg_attr(coverage_nightly, coverage(off))] - fn resolve( - &self, - _root_hint_subjects: &[&[u8]], - _sigschemes: &[SignatureScheme], - ) -> Option<Arc<sign::CertifiedKey>> { - unreachable!() - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn has_certs(&self) -> bool { - unreachable!() - } - } -} diff --git a/vendor/rustls/src/client/hs.rs b/vendor/rustls/src/client/hs.rs deleted file mode 100644 index 4669f33d..00000000 --- a/vendor/rustls/src/client/hs.rs +++ /dev/null @@ -1,1178 +0,0 @@ -use alloc::borrow::ToOwned; -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; -use core::ops::Deref; - -use pki_types::ServerName; - -#[cfg(feature = "tls12")] -use super::tls12; -use super::{ResolvesClientCert, Tls12Resumption}; -use crate::SupportedCipherSuite; -#[cfg(feature = "logging")] -use crate::bs_debug; -use crate::check::inappropriate_handshake_message; -use crate::client::client_conn::ClientConnectionData; -use crate::client::common::ClientHelloDetails; -use crate::client::ech::EchState; -use crate::client::{ClientConfig, EchMode, EchStatus, tls13}; -use crate::common_state::{CommonState, HandshakeKind, KxState, State}; -use crate::conn::ConnectionRandoms; -use crate::crypto::{ActiveKeyExchange, KeyExchangeAlgorithm}; -use crate::enums::{ - AlertDescription, CertificateType, CipherSuite, ContentType, HandshakeType, ProtocolVersion, -}; -use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; -use crate::hash_hs::HandshakeHashBuffer; -use crate::log::{debug, trace}; -use crate::msgs::base::Payload; -use crate::msgs::enums::{Compression, ExtensionType}; -use crate::msgs::handshake::{ - CertificateStatusRequest, ClientExtensions, ClientExtensionsInput, ClientHelloPayload, - ClientSessionTicket, EncryptedClientHello, HandshakeMessagePayload, HandshakePayload, - HelloRetryRequest, KeyShareEntry, ProtocolName, PskKeyExchangeModes, Random, ServerNamePayload, - SessionId, SupportedEcPointFormats, SupportedProtocolVersions, TransportParameters, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::sync::Arc; -use crate::tls13::key_schedule::KeyScheduleEarly; -use crate::verify::ServerCertVerifier; - -pub(super) type NextState<'a> = Box<dyn State<ClientConnectionData> + 'a>; -pub(super) type NextStateOrError<'a> = Result<NextState<'a>, Error>; -pub(super) type ClientContext<'a> = crate::common_state::Context<'a, ClientConnectionData>; - -struct ExpectServerHello { - input: ClientHelloInput, - transcript_buffer: HandshakeHashBuffer, - // The key schedule for sending early data. - // - // If the server accepts the PSK used for early data then - // this is used to compute the rest of the key schedule. - // Otherwise, it is thrown away. - // - // If this is `None` then we do not support early data. - early_data_key_schedule: Option<KeyScheduleEarly>, - offered_key_share: Option<Box<dyn ActiveKeyExchange>>, - suite: Option<SupportedCipherSuite>, - ech_state: Option<EchState>, -} - -struct ExpectServerHelloOrHelloRetryRequest { - next: ExpectServerHello, - extra_exts: ClientExtensionsInput<'static>, -} - -pub(super) struct ClientHelloInput { - pub(super) config: Arc<ClientConfig>, - pub(super) resuming: Option<persist::Retrieved<ClientSessionValue>>, - pub(super) random: Random, - pub(super) sent_tls13_fake_ccs: bool, - pub(super) hello: ClientHelloDetails, - pub(super) session_id: SessionId, - pub(super) server_name: ServerName<'static>, - pub(super) prev_ech_ext: Option<EncryptedClientHello>, -} - -impl ClientHelloInput { - pub(super) fn new( - server_name: ServerName<'static>, - extra_exts: &ClientExtensionsInput<'_>, - cx: &mut ClientContext<'_>, - config: Arc<ClientConfig>, - ) -> Result<Self, Error> { - let mut resuming = ClientSessionValue::retrieve(&server_name, &config, cx); - let session_id = match &mut resuming { - Some(_resuming) => { - debug!("Resuming session"); - match &mut _resuming.value { - #[cfg(feature = "tls12")] - ClientSessionValue::Tls12(inner) => { - // If we have a ticket, we use the sessionid as a signal that - // we're doing an abbreviated handshake. See section 3.4 in - // RFC5077. - if !inner.ticket().0.is_empty() { - inner.session_id = SessionId::random(config.provider.secure_random)?; - } - Some(inner.session_id) - } - _ => None, - } - } - _ => { - debug!("Not resuming any session"); - None - } - }; - - // https://tools.ietf.org/html/rfc8446#appendix-D.4 - // https://tools.ietf.org/html/draft-ietf-quic-tls-34#section-8.4 - let session_id = match session_id { - Some(session_id) => session_id, - None if cx.common.is_quic() => SessionId::empty(), - None if !config.supports_version(ProtocolVersion::TLSv1_3) => SessionId::empty(), - None => SessionId::random(config.provider.secure_random)?, - }; - - let hello = ClientHelloDetails::new( - extra_exts - .protocols - .clone() - .unwrap_or_default(), - crate::rand::random_u16(config.provider.secure_random)?, - ); - - Ok(Self { - resuming, - random: Random::new(config.provider.secure_random)?, - sent_tls13_fake_ccs: false, - hello, - session_id, - server_name, - prev_ech_ext: None, - config, - }) - } - - pub(super) fn start_handshake( - self, - extra_exts: ClientExtensionsInput<'static>, - cx: &mut ClientContext<'_>, - ) -> NextStateOrError<'static> { - let mut transcript_buffer = HandshakeHashBuffer::new(); - if self - .config - .client_auth_cert_resolver - .has_certs() - { - transcript_buffer.set_client_auth_enabled(); - } - - let key_share = if self.config.needs_key_share() { - Some(tls13::initial_key_share( - &self.config, - &self.server_name, - &mut cx.common.kx_state, - )?) - } else { - None - }; - - let ech_state = match self.config.ech_mode.as_ref() { - Some(EchMode::Enable(ech_config)) => { - Some(ech_config.state(self.server_name.clone(), &self.config)?) - } - _ => None, - }; - - emit_client_hello_for_retry( - transcript_buffer, - None, - key_share, - extra_exts, - None, - self, - cx, - ech_state, - ) - } -} - -/// Emits the initial ClientHello or a ClientHello in response to -/// a HelloRetryRequest. -/// -/// `retryreq` and `suite` are `None` if this is the initial -/// ClientHello. -fn emit_client_hello_for_retry( - mut transcript_buffer: HandshakeHashBuffer, - retryreq: Option<&HelloRetryRequest>, - key_share: Option<Box<dyn ActiveKeyExchange>>, - extra_exts: ClientExtensionsInput<'static>, - suite: Option<SupportedCipherSuite>, - mut input: ClientHelloInput, - cx: &mut ClientContext<'_>, - mut ech_state: Option<EchState>, -) -> NextStateOrError<'static> { - let config = &input.config; - // Defense in depth: the ECH state should be None if ECH is disabled based on config - // builder semantics. - let forbids_tls12 = cx.common.is_quic() || ech_state.is_some(); - - let supported_versions = SupportedProtocolVersions { - tls12: config.supports_version(ProtocolVersion::TLSv1_2) && !forbids_tls12, - tls13: config.supports_version(ProtocolVersion::TLSv1_3), - }; - - // should be unreachable thanks to config builder - assert!(supported_versions.any(|_| true)); - - let mut exts = Box::new(ClientExtensions { - // offer groups which are usable for any offered version - named_groups: Some( - config - .provider - .kx_groups - .iter() - .filter(|skxg| supported_versions.any(|v| skxg.usable_for_version(v))) - .map(|skxg| skxg.name()) - .collect(), - ), - supported_versions: Some(supported_versions), - signature_schemes: Some( - config - .verifier - .supported_verify_schemes(), - ), - extended_master_secret_request: Some(()), - certificate_status_request: Some(CertificateStatusRequest::build_ocsp()), - protocols: extra_exts.protocols.clone(), - ..Default::default() - }); - - match extra_exts.transport_parameters.clone() { - Some(TransportParameters::Quic(v)) => exts.transport_parameters = Some(v), - Some(TransportParameters::QuicDraft(v)) => exts.transport_parameters_draft = Some(v), - None => {} - }; - - if supported_versions.tls13 { - if let Some(cas_extension) = config.verifier.root_hint_subjects() { - exts.certificate_authority_names = Some(cas_extension.to_owned()); - } - } - - // Send the ECPointFormat extension only if we are proposing ECDHE - if config - .provider - .kx_groups - .iter() - .any(|skxg| skxg.name().key_exchange_algorithm() == KeyExchangeAlgorithm::ECDHE) - { - exts.ec_point_formats = Some(SupportedEcPointFormats::default()); - } - - exts.server_name = match (ech_state.as_ref(), config.enable_sni) { - // If we have ECH state we have a "cover name" to send in the outer hello - // as the SNI domain name. This happens unconditionally so we ignore the - // `enable_sni` value. That will be used later to decide what to do for - // the protected inner hello's SNI. - (Some(ech_state), _) => Some(ServerNamePayload::from(&ech_state.outer_name)), - - // If we have no ECH state, and SNI is enabled, try to use the input server_name - // for the SNI domain name. - (None, true) => match &input.server_name { - ServerName::DnsName(dns_name) => Some(ServerNamePayload::from(dns_name)), - _ => None, - }, - - // If we have no ECH state, and SNI is not enabled, there's nothing to do. - (None, false) => None, - }; - - if let Some(key_share) = &key_share { - debug_assert!(supported_versions.tls13); - let mut shares = vec![KeyShareEntry::new(key_share.group(), key_share.pub_key())]; - - if !retryreq - .map(|rr| rr.key_share.is_some()) - .unwrap_or_default() - { - // Only for the initial client hello, or a HRR that does not specify a kx group, - // see if we can send a second KeyShare for "free". We only do this if the same - // algorithm is also supported separately by our provider for this version - // (`find_kx_group` looks that up). - if let Some((component_group, component_share)) = - key_share - .hybrid_component() - .filter(|(group, _)| { - config - .find_kx_group(*group, ProtocolVersion::TLSv1_3) - .is_some() - }) - { - shares.push(KeyShareEntry::new(component_group, component_share)); - } - } - - exts.key_shares = Some(shares); - } - - if let Some(cookie) = retryreq.and_then(|hrr| hrr.cookie.as_ref()) { - exts.cookie = Some(cookie.clone()); - } - - if supported_versions.tls13 { - // We could support PSK_KE here too. Such connections don't - // have forward secrecy, and are similar to TLS1.2 resumption. - exts.preshared_key_modes = Some(PskKeyExchangeModes { - psk: false, - psk_dhe: true, - }); - } - - input.hello.offered_cert_compression = - if supported_versions.tls13 && !config.cert_decompressors.is_empty() { - exts.certificate_compression_algorithms = Some( - config - .cert_decompressors - .iter() - .map(|dec| dec.algorithm()) - .collect(), - ); - true - } else { - false - }; - - if config - .client_auth_cert_resolver - .only_raw_public_keys() - { - exts.client_certificate_types = Some(vec![CertificateType::RawPublicKey]); - } - - if config - .verifier - .requires_raw_public_keys() - { - exts.server_certificate_types = Some(vec![CertificateType::RawPublicKey]); - } - - // If this is a second client hello we're constructing in response to an HRR, and - // we've rejected ECH or sent GREASE ECH, then we need to carry forward the - // exact same ECH extension we used in the first hello. - if matches!(cx.data.ech_status, EchStatus::Rejected | EchStatus::Grease) & retryreq.is_some() { - if let Some(prev_ech_ext) = input.prev_ech_ext.take() { - exts.encrypted_client_hello = Some(prev_ech_ext); - } - } - - // Do we have a SessionID or ticket cached for this host? - let tls13_session = prepare_resumption(&input.resuming, &mut exts, suite, cx, config); - - // Extensions MAY be randomized - // but they also need to keep the same order as the previous ClientHello - exts.order_seed = input.hello.extension_order_seed; - - let mut cipher_suites: Vec<_> = config - .provider - .cipher_suites - .iter() - .filter_map(|cs| match cs.usable_for_protocol(cx.common.protocol) { - true => Some(cs.suite()), - false => None, - }) - .collect(); - - if supported_versions.tls12 { - // We don't do renegotiation at all, in fact. - cipher_suites.push(CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); - } - - let mut chp_payload = ClientHelloPayload { - client_version: ProtocolVersion::TLSv1_2, - random: input.random, - session_id: input.session_id, - cipher_suites, - compression_methods: vec![Compression::Null], - extensions: exts, - }; - - let ech_grease_ext = config - .ech_mode - .as_ref() - .and_then(|mode| match mode { - EchMode::Grease(cfg) => Some(cfg.grease_ext( - config.provider.secure_random, - input.server_name.clone(), - &chp_payload, - )), - _ => None, - }); - - match (cx.data.ech_status, &mut ech_state) { - // If we haven't offered ECH, or have offered ECH but got a non-rejecting HRR, then - // we need to replace the client hello payload with an ECH client hello payload. - (EchStatus::NotOffered | EchStatus::Offered, Some(ech_state)) => { - // Replace the client hello payload with an ECH client hello payload. - chp_payload = ech_state.ech_hello(chp_payload, retryreq, &tls13_session)?; - cx.data.ech_status = EchStatus::Offered; - // Store the ECH extension in case we need to carry it forward in a subsequent hello. - input.prev_ech_ext = chp_payload - .encrypted_client_hello - .clone(); - } - // If we haven't offered ECH, and have no ECH state, then consider whether to use GREASE - // ECH. - (EchStatus::NotOffered, None) => { - if let Some(grease_ext) = ech_grease_ext { - // Add the GREASE ECH extension. - let grease_ext = grease_ext?; - chp_payload.encrypted_client_hello = Some(grease_ext.clone()); - cx.data.ech_status = EchStatus::Grease; - // Store the GREASE ECH extension in case we need to carry it forward in a - // subsequent hello. - input.prev_ech_ext = Some(grease_ext); - } - } - _ => {} - } - - // Note what extensions we sent. - input.hello.sent_extensions = chp_payload.collect_used(); - - let mut chp = HandshakeMessagePayload(HandshakePayload::ClientHello(chp_payload)); - - let tls13_early_data_key_schedule = match (ech_state.as_mut(), tls13_session) { - // If we're performing ECH and resuming, then the PSK binder will have been dealt with - // separately, and we need to take the early_data_key_schedule computed for the inner hello. - (Some(ech_state), Some(tls13_session)) => ech_state - .early_data_key_schedule - .take() - .map(|schedule| (tls13_session.suite(), schedule)), - - // When we're not doing ECH and resuming, then the PSK binder need to be filled in as - // normal. - (_, Some(tls13_session)) => Some(( - tls13_session.suite(), - tls13::fill_in_psk_binder(&tls13_session, &transcript_buffer, &mut chp), - )), - - // No early key schedule in other cases. - _ => None, - }; - - let ch = Message { - version: match retryreq { - // <https://datatracker.ietf.org/doc/html/rfc8446#section-5.1>: - // "This value MUST be set to 0x0303 for all records generated - // by a TLS 1.3 implementation ..." - Some(_) => ProtocolVersion::TLSv1_2, - // "... other than an initial ClientHello (i.e., one not - // generated after a HelloRetryRequest), where it MAY also be - // 0x0301 for compatibility purposes" - // - // (retryreq == None means we're in the "initial ClientHello" case) - None => ProtocolVersion::TLSv1_0, - }, - payload: MessagePayload::handshake(chp), - }; - - if retryreq.is_some() { - // send dummy CCS to fool middleboxes prior - // to second client hello - tls13::emit_fake_ccs(&mut input.sent_tls13_fake_ccs, cx.common); - } - - trace!("Sending ClientHello {ch:#?}"); - - transcript_buffer.add_message(&ch); - cx.common.send_msg(ch, false); - - // Calculate the hash of ClientHello and use it to derive EarlyTrafficSecret - let early_data_key_schedule = - tls13_early_data_key_schedule.map(|(resuming_suite, schedule)| { - if !cx.data.early_data.is_enabled() { - return schedule; - } - - let (transcript_buffer, random) = match &ech_state { - // When using ECH the early data key schedule is derived based on the inner - // hello transcript and random. - Some(ech_state) => ( - &ech_state.inner_hello_transcript, - &ech_state.inner_hello_random.0, - ), - None => (&transcript_buffer, &input.random.0), - }; - - tls13::derive_early_traffic_secret( - &*config.key_log, - cx, - resuming_suite.common.hash_provider, - &schedule, - &mut input.sent_tls13_fake_ccs, - transcript_buffer, - random, - ); - schedule - }); - - let next = ExpectServerHello { - input, - transcript_buffer, - early_data_key_schedule, - offered_key_share: key_share, - suite, - ech_state, - }; - - Ok(if supported_versions.tls13 && retryreq.is_none() { - Box::new(ExpectServerHelloOrHelloRetryRequest { - next, - extra_exts: extra_exts.into_owned(), - }) - } else { - Box::new(next) - }) -} - -/// Prepares `exts` and `cx` with TLS 1.2 or TLS 1.3 session -/// resumption. -/// -/// - `suite` is `None` if this is the initial ClientHello, or -/// `Some` if we're retrying in response to -/// a HelloRetryRequest. -/// -/// This function will push onto `exts` to -/// -/// (a) request a new ticket if we don't have one, -/// (b) send our TLS 1.2 ticket after retrieving an 1.2 session, -/// (c) send a request for 1.3 early data if allowed and -/// (d) send a 1.3 preshared key if we have one. -/// -/// It returns the TLS 1.3 PSKs, if any, for further processing. -fn prepare_resumption<'a>( - resuming: &'a Option<persist::Retrieved<ClientSessionValue>>, - exts: &mut ClientExtensions<'_>, - suite: Option<SupportedCipherSuite>, - cx: &mut ClientContext<'_>, - config: &ClientConfig, -) -> Option<persist::Retrieved<&'a persist::Tls13ClientSessionValue>> { - // Check whether we're resuming with a non-empty ticket. - let resuming = match resuming { - Some(resuming) if !resuming.ticket().is_empty() => resuming, - _ => { - if config.supports_version(ProtocolVersion::TLSv1_2) - && config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets - { - // If we don't have a ticket, request one. - exts.session_ticket = Some(ClientSessionTicket::Request); - } - return None; - } - }; - - let Some(tls13) = resuming.map(|csv| csv.tls13()) else { - // TLS 1.2; send the ticket if we have support this protocol version - if config.supports_version(ProtocolVersion::TLSv1_2) - && config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets - { - exts.session_ticket = Some(ClientSessionTicket::Offer(Payload::new(resuming.ticket()))); - } - return None; // TLS 1.2, so nothing to return here - }; - - if !config.supports_version(ProtocolVersion::TLSv1_3) { - return None; - } - - // If the server selected TLS 1.2, we can't resume. - let suite = match suite { - Some(SupportedCipherSuite::Tls13(suite)) => Some(suite), - #[cfg(feature = "tls12")] - Some(SupportedCipherSuite::Tls12(_)) => return None, - None => None, - }; - - // If the selected cipher suite can't select from the session's, we can't resume. - if let Some(suite) = suite { - suite.can_resume_from(tls13.suite())?; - } - - tls13::prepare_resumption(config, cx, &tls13, exts, suite.is_some()); - Some(tls13) -} - -pub(super) fn process_alpn_protocol( - common: &mut CommonState, - offered_protocols: &[ProtocolName], - selected: Option<&ProtocolName>, -) -> Result<(), Error> { - common.alpn_protocol = selected.map(ToOwned::to_owned); - - if let Some(alpn_protocol) = &common.alpn_protocol { - if !offered_protocols.contains(alpn_protocol) { - return Err(common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::SelectedUnofferedApplicationProtocol, - )); - } - } - - // RFC 9001 says: "While ALPN only specifies that servers use this alert, QUIC clients MUST - // use error 0x0178 to terminate a connection when ALPN negotiation fails." We judge that - // the user intended to use ALPN (rather than some out-of-band protocol negotiation - // mechanism) if and only if any ALPN protocols were configured. This defends against badly-behaved - // servers which accept a connection that requires an application-layer protocol they do not - // understand. - if common.is_quic() && common.alpn_protocol.is_none() && !offered_protocols.is_empty() { - return Err(common.send_fatal_alert( - AlertDescription::NoApplicationProtocol, - Error::NoApplicationProtocol, - )); - } - - debug!( - "ALPN protocol is {:?}", - common - .alpn_protocol - .as_ref() - .map(|v| bs_debug::BsDebug(v.as_ref())) - ); - Ok(()) -} - -pub(super) fn process_server_cert_type_extension( - common: &mut CommonState, - config: &ClientConfig, - server_cert_extension: Option<&CertificateType>, -) -> Result<Option<(ExtensionType, CertificateType)>, Error> { - process_cert_type_extension( - common, - config - .verifier - .requires_raw_public_keys(), - server_cert_extension.copied(), - ExtensionType::ServerCertificateType, - ) -} - -pub(super) fn process_client_cert_type_extension( - common: &mut CommonState, - config: &ClientConfig, - client_cert_extension: Option<&CertificateType>, -) -> Result<Option<(ExtensionType, CertificateType)>, Error> { - process_cert_type_extension( - common, - config - .client_auth_cert_resolver - .only_raw_public_keys(), - client_cert_extension.copied(), - ExtensionType::ClientCertificateType, - ) -} - -impl State<ClientConnectionData> for ExpectServerHello { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> NextStateOrError<'m> - where - Self: 'm, - { - let server_hello = - require_handshake_msg!(m, HandshakeType::ServerHello, HandshakePayload::ServerHello)?; - trace!("We got ServerHello {server_hello:#?}"); - - use crate::ProtocolVersion::{TLSv1_2, TLSv1_3}; - let config = &self.input.config; - let tls13_supported = config.supports_version(TLSv1_3); - - let server_version = if server_hello.legacy_version == TLSv1_2 { - server_hello - .selected_version - .unwrap_or(server_hello.legacy_version) - } else { - server_hello.legacy_version - }; - - let version = match server_version { - TLSv1_3 if tls13_supported => TLSv1_3, - TLSv1_2 if config.supports_version(TLSv1_2) => { - if cx.data.early_data.is_enabled() && cx.common.early_traffic { - // The client must fail with a dedicated error code if the server - // responds with TLS 1.2 when offering 0-RTT. - return Err(PeerMisbehaved::OfferedEarlyDataWithOldProtocolVersion.into()); - } - - if server_hello.selected_version.is_some() { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::SelectedTls12UsingTls13VersionExtension, - ) - }); - } - - TLSv1_2 - } - _ => { - let reason = match server_version { - TLSv1_2 | TLSv1_3 => PeerIncompatible::ServerTlsVersionIsDisabledByOurConfig, - _ => PeerIncompatible::ServerDoesNotSupportTls12Or13, - }; - return Err(cx - .common - .send_fatal_alert(AlertDescription::ProtocolVersion, reason)); - } - }; - - if server_hello.compression_method != Compression::Null { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::SelectedUnofferedCompression, - ) - }); - } - - let allowed_unsolicited = [ExtensionType::RenegotiationInfo]; - if self - .input - .hello - .server_sent_unsolicited_extensions(server_hello, &allowed_unsolicited) - { - return Err(cx.common.send_fatal_alert( - AlertDescription::UnsupportedExtension, - PeerMisbehaved::UnsolicitedServerHelloExtension, - )); - } - - cx.common.negotiated_version = Some(version); - - // Extract ALPN protocol - if !cx.common.is_tls13() { - process_alpn_protocol( - cx.common, - &self.input.hello.alpn_protocols, - server_hello - .selected_protocol - .as_ref() - .map(|s| s.as_ref()), - )?; - } - - // If ECPointFormats extension is supplied by the server, it must contain - // Uncompressed. But it's allowed to be omitted. - if let Some(point_fmts) = &server_hello.ec_point_formats { - if !point_fmts.uncompressed { - return Err(cx.common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerMisbehaved::ServerHelloMustOfferUncompressedEcPoints, - )); - } - } - - let suite = config - .find_cipher_suite(server_hello.cipher_suite) - .ok_or_else(|| { - cx.common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerMisbehaved::SelectedUnofferedCipherSuite, - ) - })?; - - if version != suite.version().version { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::SelectedUnusableCipherSuiteForVersion, - ) - }); - } - - match self.suite { - Some(prev_suite) if prev_suite != suite => { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::SelectedDifferentCipherSuiteAfterRetry, - ) - }); - } - _ => { - debug!("Using ciphersuite {suite:?}"); - self.suite = Some(suite); - cx.common.suite = Some(suite); - } - } - - // Start our handshake hash, and input the server-hello. - let mut transcript = self - .transcript_buffer - .start_hash(suite.hash_provider()); - transcript.add_message(&m); - - let randoms = ConnectionRandoms::new(self.input.random, server_hello.random); - // For TLS1.3, start message encryption using - // handshake_traffic_secret. - match suite { - SupportedCipherSuite::Tls13(suite) => { - tls13::handle_server_hello( - cx, - server_hello, - randoms, - suite, - transcript, - self.early_data_key_schedule, - // We always send a key share when TLS 1.3 is enabled. - self.offered_key_share.unwrap(), - &m, - self.ech_state, - self.input, - ) - } - #[cfg(feature = "tls12")] - SupportedCipherSuite::Tls12(suite) => tls12::CompleteServerHelloHandling { - randoms, - transcript, - input: self.input, - } - .handle_server_hello(cx, suite, server_hello, tls13_supported), - } - } - - fn into_owned(self: Box<Self>) -> NextState<'static> { - self - } -} - -impl ExpectServerHelloOrHelloRetryRequest { - fn into_expect_server_hello(self) -> NextState<'static> { - Box::new(self.next) - } - - fn handle_hello_retry_request( - mut self, - cx: &mut ClientContext<'_>, - m: Message<'_>, - ) -> NextStateOrError<'static> { - let hrr = require_handshake_msg!( - m, - HandshakeType::HelloRetryRequest, - HandshakePayload::HelloRetryRequest - )?; - trace!("Got HRR {hrr:?}"); - - cx.common.check_aligned_handshake()?; - - // We always send a key share when TLS 1.3 is enabled. - let offered_key_share = self.next.offered_key_share.unwrap(); - - // A retry request is illegal if it contains no cookie and asks for - // retry of a group we already sent. - let config = &self.next.input.config; - - if let (None, Some(req_group)) = (&hrr.cookie, hrr.key_share) { - let offered_hybrid = offered_key_share - .hybrid_component() - .and_then(|(group_name, _)| { - config.find_kx_group(group_name, ProtocolVersion::TLSv1_3) - }) - .map(|skxg| skxg.name()); - - if req_group == offered_key_share.group() || Some(req_group) == offered_hybrid { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::IllegalHelloRetryRequestWithOfferedGroup, - ) - }); - } - } - - // Or has an empty cookie. - if let Some(cookie) = &hrr.cookie { - if cookie.0.is_empty() { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::IllegalHelloRetryRequestWithEmptyCookie, - ) - }); - } - } - - // Or asks us to change nothing. - if hrr.cookie.is_none() && hrr.key_share.is_none() { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::IllegalHelloRetryRequestWithNoChanges, - ) - }); - } - - // Or does not echo the session_id from our ClientHello: - // - // > the HelloRetryRequest has the same format as a ServerHello message, - // > and the legacy_version, legacy_session_id_echo, cipher_suite, and - // > legacy_compression_method fields have the same meaning - // <https://www.rfc-editor.org/rfc/rfc8446#section-4.1.4> - // - // and - // - // > A client which receives a legacy_session_id_echo field that does not - // > match what it sent in the ClientHello MUST abort the handshake with an - // > "illegal_parameter" alert. - // <https://www.rfc-editor.org/rfc/rfc8446#section-4.1.3> - if hrr.session_id != self.next.input.session_id { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::IllegalHelloRetryRequestWithWrongSessionId, - ) - }); - } - - // Or asks us to talk a protocol we didn't offer, or doesn't support HRR at all. - match hrr.supported_versions { - Some(ProtocolVersion::TLSv1_3) => { - cx.common.negotiated_version = Some(ProtocolVersion::TLSv1_3); - } - _ => { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::IllegalHelloRetryRequestWithUnsupportedVersion, - ) - }); - } - } - - // Or asks us to use a ciphersuite we didn't offer. - let Some(cs) = config.find_cipher_suite(hrr.cipher_suite) else { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::IllegalHelloRetryRequestWithUnofferedCipherSuite, - ) - }); - }; - - // Or offers ECH related extensions when we didn't offer ECH. - if cx.data.ech_status == EchStatus::NotOffered && hrr.encrypted_client_hello.is_some() { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::UnsupportedExtension, - PeerMisbehaved::IllegalHelloRetryRequestWithInvalidEch, - ) - }); - } - - // HRR selects the ciphersuite. - cx.common.suite = Some(cs); - cx.common.handshake_kind = Some(HandshakeKind::FullWithHelloRetryRequest); - - // If we offered ECH, we need to confirm that the server accepted it. - match (self.next.ech_state.as_ref(), cs.tls13()) { - (Some(ech_state), Some(tls13_cs)) => { - if !ech_state.confirm_hrr_acceptance(hrr, tls13_cs, cx.common)? { - // If the server did not confirm, then note the new ECH status but - // continue the handshake. We will abort with an ECH required error - // at the end. - cx.data.ech_status = EchStatus::Rejected; - } - } - (Some(_), None) => { - unreachable!("ECH state should only be set when TLS 1.3 was negotiated") - } - _ => {} - }; - - // This is the draft19 change where the transcript became a tree - let transcript = self - .next - .transcript_buffer - .start_hash(cs.hash_provider()); - let mut transcript_buffer = transcript.into_hrr_buffer(); - transcript_buffer.add_message(&m); - - // If we offered ECH and the server accepted, we also need to update the separate - // ECH transcript with the hello retry request message. - if let Some(ech_state) = self.next.ech_state.as_mut() { - ech_state.transcript_hrr_update(cs.hash_provider(), &m); - } - - // Early data is not allowed after HelloRetryrequest - if cx.data.early_data.is_enabled() { - cx.data.early_data.rejected(); - } - - let key_share = match hrr.key_share { - Some(group) if group != offered_key_share.group() => { - let Some(skxg) = config.find_kx_group(group, ProtocolVersion::TLSv1_3) else { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::IllegalHelloRetryRequestWithUnofferedNamedGroup, - )); - }; - - cx.common.kx_state = KxState::Start(skxg); - skxg.start()? - } - _ => offered_key_share, - }; - - emit_client_hello_for_retry( - transcript_buffer, - Some(hrr), - Some(key_share), - self.extra_exts, - Some(cs), - self.next.input, - cx, - self.next.ech_state, - ) - } -} - -impl State<ClientConnectionData> for ExpectServerHelloOrHelloRetryRequest { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::ServerHello(..)), - .. - } => self - .into_expect_server_hello() - .handle(cx, m), - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::HelloRetryRequest(..)), - .. - } => self.handle_hello_retry_request(cx, m), - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[HandshakeType::ServerHello, HandshakeType::HelloRetryRequest], - )), - } - } - - fn into_owned(self: Box<Self>) -> NextState<'static> { - self - } -} - -fn process_cert_type_extension( - common: &mut CommonState, - client_expects: bool, - server_negotiated: Option<CertificateType>, - extension_type: ExtensionType, -) -> Result<Option<(ExtensionType, CertificateType)>, Error> { - match (client_expects, server_negotiated) { - (true, Some(CertificateType::RawPublicKey)) => { - Ok(Some((extension_type, CertificateType::RawPublicKey))) - } - (true, _) => Err(common.send_fatal_alert( - AlertDescription::HandshakeFailure, - Error::PeerIncompatible(PeerIncompatible::IncorrectCertificateTypeExtension), - )), - (_, Some(CertificateType::RawPublicKey)) => { - unreachable!("Caught by `PeerMisbehaved::UnsolicitedEncryptedExtension`") - } - (_, _) => Ok(None), - } -} - -pub(super) enum ClientSessionValue { - Tls13(persist::Tls13ClientSessionValue), - #[cfg(feature = "tls12")] - Tls12(persist::Tls12ClientSessionValue), -} - -impl ClientSessionValue { - fn retrieve( - server_name: &ServerName<'static>, - config: &ClientConfig, - cx: &mut ClientContext<'_>, - ) -> Option<persist::Retrieved<Self>> { - let found = config - .resumption - .store - .take_tls13_ticket(server_name) - .map(ClientSessionValue::Tls13) - .or_else(|| { - #[cfg(feature = "tls12")] - { - config - .resumption - .store - .tls12_session(server_name) - .map(ClientSessionValue::Tls12) - } - - #[cfg(not(feature = "tls12"))] - None - }) - .and_then(|resuming| { - resuming.compatible_config(&config.verifier, &config.client_auth_cert_resolver) - }) - .and_then(|resuming| { - let now = config - .current_time() - .map_err(|_err| debug!("Could not get current time: {_err}")) - .ok()?; - - let retrieved = persist::Retrieved::new(resuming, now); - match retrieved.has_expired() { - false => Some(retrieved), - true => None, - } - }) - .or_else(|| { - debug!("No cached session for {server_name:?}"); - None - }); - - if let Some(resuming) = &found { - if cx.common.is_quic() { - cx.common.quic.params = resuming - .tls13() - .map(|v| v.quic_params()); - } - } - - found - } - - fn common(&self) -> &persist::ClientSessionCommon { - match self { - Self::Tls13(inner) => &inner.common, - #[cfg(feature = "tls12")] - Self::Tls12(inner) => &inner.common, - } - } - - fn tls13(&self) -> Option<&persist::Tls13ClientSessionValue> { - match self { - Self::Tls13(v) => Some(v), - #[cfg(feature = "tls12")] - Self::Tls12(_) => None, - } - } - - fn compatible_config( - self, - server_cert_verifier: &Arc<dyn ServerCertVerifier>, - client_creds: &Arc<dyn ResolvesClientCert>, - ) -> Option<Self> { - match &self { - Self::Tls13(v) => v - .compatible_config(server_cert_verifier, client_creds) - .then_some(self), - #[cfg(feature = "tls12")] - Self::Tls12(v) => v - .compatible_config(server_cert_verifier, client_creds) - .then_some(self), - } - } -} - -impl Deref for ClientSessionValue { - type Target = persist::ClientSessionCommon; - - fn deref(&self) -> &Self::Target { - self.common() - } -} diff --git a/vendor/rustls/src/client/test.rs b/vendor/rustls/src/client/test.rs deleted file mode 100644 index f4ea9580..00000000 --- a/vendor/rustls/src/client/test.rs +++ /dev/null @@ -1,712 +0,0 @@ -#![cfg(any(feature = "ring", feature = "aws_lc_rs"))] -use core::sync::atomic::{AtomicBool, Ordering}; -use std::prelude::v1::*; -use std::vec; - -use pki_types::{CertificateDer, ServerName}; - -use crate::client::{ClientConfig, ClientConnection, Resumption, Tls12Resumption}; -use crate::crypto::CryptoProvider; -use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; -use crate::msgs::base::PayloadU16; -use crate::msgs::codec::Reader; -use crate::msgs::enums::{Compression, NamedGroup}; -use crate::msgs::handshake::{ - ClientHelloPayload, HandshakeMessagePayload, HandshakePayload, HelloRetryRequest, Random, - ServerHelloPayload, SessionId, -}; -use crate::msgs::message::{Message, MessagePayload, OutboundOpaqueMessage}; -use crate::sync::Arc; -use crate::{Error, PeerIncompatible, PeerMisbehaved, RootCertStore}; - -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use std::sync::OnceLock; - - use super::super::*; - use crate::client::AlwaysResolvesClientRawPublicKeys; - use crate::crypto::cipher::MessageEncrypter; - use crate::crypto::tls13::OkmBlock; - use crate::enums::CertificateType; - use crate::msgs::base::PayloadU8; - use crate::msgs::enums::ECCurveType; - use crate::msgs::handshake::{ - CertificateChain, EcParameters, HelloRetryRequestExtensions, KeyShareEntry, - ServerEcdhParams, ServerExtensions, ServerKeyExchange, ServerKeyExchangeParams, - ServerKeyExchangePayload, - }; - use crate::msgs::message::PlainMessage; - use crate::pki_types::pem::PemObject; - use crate::pki_types::{PrivateKeyDer, UnixTime}; - use crate::sign::CertifiedKey; - use crate::tls13::key_schedule::{derive_traffic_iv, derive_traffic_key}; - use crate::verify::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; - use crate::{DigitallySignedStruct, DistinguishedName, KeyLog, version}; - - /// Tests that session_ticket(35) extension - /// is not sent if the client does not support TLS 1.2. - #[test] - fn test_no_session_ticket_request_on_tls_1_3() { - let mut config = - ClientConfig::builder_with_provider(super::provider::default_provider().into()) - .with_protocol_versions(&[&version::TLS13]) - .unwrap() - .with_root_certificates(roots()) - .with_no_client_auth(); - config.resumption = Resumption::in_memory_sessions(128) - .tls12_resumption(Tls12Resumption::SessionIdOrTickets); - let ch = client_hello_sent_for_config(config).unwrap(); - assert!(ch.extensions.session_ticket.is_none()); - } - - #[test] - fn test_no_renegotiation_scsv_on_tls_1_3() { - let ch = client_hello_sent_for_config( - ClientConfig::builder_with_provider(super::provider::default_provider().into()) - .with_protocol_versions(&[&version::TLS13]) - .unwrap() - .with_root_certificates(roots()) - .with_no_client_auth(), - ) - .unwrap(); - assert!( - !ch.cipher_suites - .contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV) - ); - } - - #[test] - fn test_client_does_not_offer_sha1() { - for version in crate::ALL_VERSIONS { - let config = - ClientConfig::builder_with_provider(super::provider::default_provider().into()) - .with_protocol_versions(&[version]) - .unwrap() - .with_root_certificates(roots()) - .with_no_client_auth(); - let ch = client_hello_sent_for_config(config).unwrap(); - assert!( - !ch.extensions - .signature_schemes - .as_ref() - .unwrap() - .contains(&SignatureScheme::RSA_PKCS1_SHA1), - "sha1 unexpectedly offered" - ); - } - } - - #[test] - fn test_client_rejects_hrr_with_varied_session_id() { - let config = - ClientConfig::builder_with_provider(super::provider::default_provider().into()) - .with_safe_default_protocol_versions() - .unwrap() - .with_root_certificates(roots()) - .with_no_client_auth(); - let mut conn = - ClientConnection::new(config.into(), ServerName::try_from("localhost").unwrap()) - .unwrap(); - let mut sent = Vec::new(); - conn.write_tls(&mut sent).unwrap(); - - // server replies with HRR, but does not echo `session_id` as required. - let hrr = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::HelloRetryRequest(HelloRetryRequest { - cipher_suite: CipherSuite::TLS13_AES_128_GCM_SHA256, - legacy_version: ProtocolVersion::TLSv1_2, - session_id: SessionId::empty(), - extensions: HelloRetryRequestExtensions { - cookie: Some(PayloadU16::new(vec![1, 2, 3, 4])), - ..HelloRetryRequestExtensions::default() - }, - }), - )), - }; - - conn.read_tls(&mut hrr.into_wire_bytes().as_slice()) - .unwrap(); - assert_eq!( - conn.process_new_packets().unwrap_err(), - PeerMisbehaved::IllegalHelloRetryRequestWithWrongSessionId.into() - ); - } - - #[cfg(feature = "tls12")] - #[test] - fn test_client_rejects_no_extended_master_secret_extension_when_require_ems_or_fips() { - let mut config = - ClientConfig::builder_with_provider(super::provider::default_provider().into()) - .with_safe_default_protocol_versions() - .unwrap() - .with_root_certificates(roots()) - .with_no_client_auth(); - if config.provider.fips() { - assert!(config.require_ems); - } else { - config.require_ems = true; - } - - let config = Arc::new(config); - let mut conn = - ClientConnection::new(config.clone(), ServerName::try_from("localhost").unwrap()) - .unwrap(); - let mut sent = Vec::new(); - conn.write_tls(&mut sent).unwrap(); - - let sh = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ServerHello(ServerHelloPayload { - random: Random::new(config.provider.secure_random).unwrap(), - compression_method: Compression::Null, - cipher_suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - legacy_version: ProtocolVersion::TLSv1_2, - session_id: SessionId::empty(), - extensions: Box::new(ServerExtensions::default()), - }), - )), - }; - conn.read_tls(&mut sh.into_wire_bytes().as_slice()) - .unwrap(); - - assert_eq!( - conn.process_new_packets(), - Err(PeerIncompatible::ExtendedMasterSecretExtensionRequired.into()) - ); - } - - #[test] - fn cas_extension_in_client_hello_if_server_verifier_requests_it() { - let cas_sending_server_verifier = - ServerVerifierWithAuthorityNames(vec![DistinguishedName::from(b"hello".to_vec())]); - - for (protocol_version, cas_extension_expected) in - [(&version::TLS12, false), (&version::TLS13, true)] - { - let client_hello = client_hello_sent_for_config( - ClientConfig::builder_with_provider(super::provider::default_provider().into()) - .with_protocol_versions(&[protocol_version]) - .unwrap() - .dangerous() - .with_custom_certificate_verifier(Arc::new(cas_sending_server_verifier.clone())) - .with_no_client_auth(), - ) - .unwrap(); - assert_eq!( - client_hello - .extensions - .certificate_authority_names - .is_some(), - cas_extension_expected - ); - } - } - - /// Regression test for <https://github.com/seanmonstar/reqwest/issues/2191> - #[cfg(feature = "tls12")] - #[test] - fn test_client_with_custom_verifier_can_accept_ecdsa_sha1_signatures() { - let verifier = Arc::new(ExpectSha1EcdsaVerifier::default()); - let config = ClientConfig::builder_with_provider(x25519_provider().into()) - .with_safe_default_protocol_versions() - .unwrap() - .dangerous() - .with_custom_certificate_verifier(verifier.clone()) - .with_no_client_auth(); - - let mut conn = - ClientConnection::new(config.into(), ServerName::try_from("localhost").unwrap()) - .unwrap(); - let mut sent = Vec::new(); - conn.write_tls(&mut sent).unwrap(); - - let sh = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ServerHello(ServerHelloPayload { - random: Random([0u8; 32]), - compression_method: Compression::Null, - cipher_suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - legacy_version: ProtocolVersion::TLSv1_2, - session_id: SessionId::empty(), - extensions: Box::new(ServerExtensions { - extended_master_secret_ack: Some(()), - ..ServerExtensions::default() - }), - }), - )), - }; - conn.read_tls(&mut sh.into_wire_bytes().as_slice()) - .unwrap(); - conn.process_new_packets().unwrap(); - - let cert = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::Certificate(CertificateChain(vec![CertificateDer::from( - &b"does not matter"[..], - )])), - )), - }; - conn.read_tls(&mut cert.into_wire_bytes().as_slice()) - .unwrap(); - conn.process_new_packets().unwrap(); - - let server_kx = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ServerKeyExchange(ServerKeyExchangePayload::Known( - ServerKeyExchange { - dss: DigitallySignedStruct::new( - SignatureScheme::ECDSA_SHA1_Legacy, - b"also does not matter".to_vec(), - ), - params: ServerKeyExchangeParams::Ecdh(ServerEcdhParams { - curve_params: EcParameters { - curve_type: ECCurveType::NamedCurve, - named_group: NamedGroup::X25519, - }, - public: PayloadU8::new(vec![0xab; 32]), - }), - }, - )), - )), - }; - conn.read_tls(&mut server_kx.into_wire_bytes().as_slice()) - .unwrap(); - conn.process_new_packets().unwrap(); - - let server_done = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ServerHelloDone, - )), - }; - conn.read_tls(&mut server_done.into_wire_bytes().as_slice()) - .unwrap(); - conn.process_new_packets().unwrap(); - - assert!( - verifier - .seen_sha1_signature - .load(Ordering::SeqCst) - ); - } - - #[derive(Debug, Default)] - struct ExpectSha1EcdsaVerifier { - seen_sha1_signature: AtomicBool, - } - - impl ServerCertVerifier for ExpectSha1EcdsaVerifier { - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp_response: &[u8], - _now: UnixTime, - ) -> Result<ServerCertVerified, Error> { - Ok(ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - assert_eq!(dss.scheme, SignatureScheme::ECDSA_SHA1_Legacy); - self.seen_sha1_signature - .store(true, Ordering::SeqCst); - Ok(HandshakeSignatureValid::assertion()) - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - todo!() - } - - fn supported_verify_schemes(&self) -> Vec<SignatureScheme> { - vec![SignatureScheme::ECDSA_SHA1_Legacy] - } - } - - #[test] - fn test_client_requiring_rpk_rejects_server_that_only_offers_x509_id_by_omission() { - assert_eq!( - client_requiring_rpk_receives_server_ee(ServerExtensions::default()), - Err(PeerIncompatible::IncorrectCertificateTypeExtension.into()) - ); - } - - #[test] - fn test_client_requiring_rpk_rejects_server_that_only_offers_x509_id() { - assert_eq!( - client_requiring_rpk_receives_server_ee(ServerExtensions { - server_certificate_type: Some(CertificateType::X509), - ..ServerExtensions::default() - }), - Err(PeerIncompatible::IncorrectCertificateTypeExtension.into()) - ); - } - - #[test] - fn test_client_requiring_rpk_rejects_server_that_only_demands_x509_by_omission() { - assert_eq!( - client_requiring_rpk_receives_server_ee(ServerExtensions { - server_certificate_type: Some(CertificateType::RawPublicKey), - ..ServerExtensions::default() - }), - Err(PeerIncompatible::IncorrectCertificateTypeExtension.into()) - ); - } - - #[test] - fn test_client_requiring_rpk_rejects_server_that_only_demands_x509() { - assert_eq!( - client_requiring_rpk_receives_server_ee(ServerExtensions { - client_certificate_type: Some(CertificateType::X509), - server_certificate_type: Some(CertificateType::RawPublicKey), - ..ServerExtensions::default() - }), - Err(PeerIncompatible::IncorrectCertificateTypeExtension.into()) - ); - } - - #[test] - fn test_client_requiring_rpk_accepts_rpk_server() { - assert_eq!( - client_requiring_rpk_receives_server_ee(ServerExtensions { - client_certificate_type: Some(CertificateType::RawPublicKey), - server_certificate_type: Some(CertificateType::RawPublicKey), - ..ServerExtensions::default() - }), - Ok(()) - ); - } - - fn client_requiring_rpk_receives_server_ee( - encrypted_extensions: ServerExtensions<'_>, - ) -> Result<(), Error> { - let fake_server_crypto = Arc::new(FakeServerCrypto::new()); - let mut conn = ClientConnection::new( - client_config_for_rpk(fake_server_crypto.clone()).into(), - ServerName::try_from("localhost").unwrap(), - ) - .unwrap(); - let mut sent = Vec::new(); - conn.write_tls(&mut sent).unwrap(); - - let sh = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ServerHello(ServerHelloPayload { - random: Random([0; 32]), - compression_method: Compression::Null, - cipher_suite: CipherSuite::TLS13_AES_128_GCM_SHA256, - legacy_version: ProtocolVersion::TLSv1_3, - session_id: SessionId::empty(), - extensions: Box::new(ServerExtensions { - key_share: Some(KeyShareEntry { - group: NamedGroup::X25519, - payload: PayloadU16::new(vec![0xaa; 32]), - }), - ..ServerExtensions::default() - }), - }), - )), - }; - conn.read_tls(&mut sh.into_wire_bytes().as_slice()) - .unwrap(); - conn.process_new_packets().unwrap(); - - let ee = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::EncryptedExtensions(Box::new(encrypted_extensions)), - )), - }; - - let mut encrypter = fake_server_crypto.server_handshake_encrypter(); - let enc_ee = encrypter - .encrypt(PlainMessage::from(ee).borrow_outbound(), 0) - .unwrap(); - conn.read_tls(&mut enc_ee.encode().as_slice()) - .unwrap(); - conn.process_new_packets().map(|_| ()) - } - - fn client_config_for_rpk(key_log: Arc<dyn KeyLog>) -> ClientConfig { - let mut config = ClientConfig::builder_with_provider(x25519_provider().into()) - .with_protocol_versions(&[&version::TLS13]) - .unwrap() - .dangerous() - .with_custom_certificate_verifier(Arc::new(ServerVerifierRequiringRpk)) - .with_client_cert_resolver(Arc::new(AlwaysResolvesClientRawPublicKeys::new(Arc::new( - client_certified_key(), - )))); - config.key_log = key_log; - config - } - - fn client_certified_key() -> CertifiedKey { - let key = super::provider::default_provider() - .key_provider - .load_private_key(client_key()) - .unwrap(); - let public_key_as_cert = vec![CertificateDer::from( - key.public_key() - .unwrap() - .as_ref() - .to_vec(), - )]; - CertifiedKey::new(public_key_as_cert, key) - } - - fn client_key() -> PrivateKeyDer<'static> { - PrivateKeyDer::from_pem_reader( - &mut include_bytes!("../../../test-ca/rsa-2048/client.key").as_slice(), - ) - .unwrap() - } - - fn x25519_provider() -> CryptoProvider { - // ensures X25519 is offered irrespective of cfg(feature = "fips"), which eases - // creation of fake server messages. - CryptoProvider { - kx_groups: vec![super::provider::kx_group::X25519], - ..super::provider::default_provider() - } - } - - #[derive(Clone, Debug)] - struct ServerVerifierWithAuthorityNames(Vec<DistinguishedName>); - - impl ServerCertVerifier for ServerVerifierWithAuthorityNames { - fn root_hint_subjects(&self) -> Option<&[DistinguishedName]> { - Some(self.0.as_slice()) - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp_response: &[u8], - _now: UnixTime, - ) -> Result<ServerCertVerified, Error> { - unreachable!() - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - unreachable!() - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - unreachable!() - } - - fn supported_verify_schemes(&self) -> Vec<SignatureScheme> { - vec![SignatureScheme::RSA_PKCS1_SHA1] - } - } - - #[derive(Debug)] - struct ServerVerifierRequiringRpk; - - impl ServerCertVerifier for ServerVerifierRequiringRpk { - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_server_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _server_name: &ServerName<'_>, - _ocsp_response: &[u8], - _now: UnixTime, - ) -> Result<ServerCertVerified, Error> { - todo!() - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - todo!() - } - - #[cfg_attr(coverage_nightly, coverage(off))] - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - todo!() - } - - fn supported_verify_schemes(&self) -> Vec<SignatureScheme> { - vec![SignatureScheme::RSA_PKCS1_SHA1] - } - - fn requires_raw_public_keys(&self) -> bool { - true - } - } - - #[derive(Debug)] - struct FakeServerCrypto { - server_handshake_secret: OnceLock<Vec<u8>>, - } - - impl FakeServerCrypto { - fn new() -> Self { - Self { - server_handshake_secret: OnceLock::new(), - } - } - - fn server_handshake_encrypter(&self) -> Box<dyn MessageEncrypter> { - let cipher_suite = super::provider::cipher_suite::TLS13_AES_128_GCM_SHA256 - .tls13() - .unwrap(); - - let secret = self - .server_handshake_secret - .get() - .unwrap(); - - let expander = cipher_suite - .hkdf_provider - .expander_for_okm(&OkmBlock::new(secret)); - - // Derive Encrypter - let key = derive_traffic_key(expander.as_ref(), cipher_suite.aead_alg); - let iv = derive_traffic_iv(expander.as_ref()); - cipher_suite.aead_alg.encrypter(key, iv) - } - } - - impl KeyLog for FakeServerCrypto { - fn will_log(&self, _label: &str) -> bool { - true - } - - fn log(&self, label: &str, _client_random: &[u8], secret: &[u8]) { - if label == "SERVER_HANDSHAKE_TRAFFIC_SECRET" { - self.server_handshake_secret - .set(secret.to_vec()) - .unwrap(); - } - } - } -} - -// invalid with fips, as we can't offer X25519 separately -#[cfg(all( - feature = "aws-lc-rs", - feature = "prefer-post-quantum", - not(feature = "fips") -))] -#[test] -fn hybrid_kx_component_share_offered_if_supported_separately() { - let ch = client_hello_sent_for_config( - ClientConfig::builder_with_provider(crate::crypto::aws_lc_rs::default_provider().into()) - .with_safe_default_protocol_versions() - .unwrap() - .with_root_certificates(roots()) - .with_no_client_auth(), - ) - .unwrap(); - - let key_shares = ch - .extensions - .key_shares - .as_ref() - .unwrap(); - assert_eq!(key_shares.len(), 2); - assert_eq!(key_shares[0].group, NamedGroup::X25519MLKEM768); - assert_eq!(key_shares[1].group, NamedGroup::X25519); -} - -#[cfg(feature = "aws-lc-rs")] -#[test] -fn hybrid_kx_component_share_not_offered_unless_supported_separately() { - use crate::crypto::aws_lc_rs; - let provider = CryptoProvider { - kx_groups: vec![aws_lc_rs::kx_group::X25519MLKEM768], - ..aws_lc_rs::default_provider() - }; - let ch = client_hello_sent_for_config( - ClientConfig::builder_with_provider(provider.into()) - .with_safe_default_protocol_versions() - .unwrap() - .with_root_certificates(roots()) - .with_no_client_auth(), - ) - .unwrap(); - - let key_shares = ch - .extensions - .key_shares - .as_ref() - .unwrap(); - assert_eq!(key_shares.len(), 1); - assert_eq!(key_shares[0].group, NamedGroup::X25519MLKEM768); -} - -fn client_hello_sent_for_config(config: ClientConfig) -> Result<ClientHelloPayload, Error> { - let mut conn = - ClientConnection::new(config.into(), ServerName::try_from("localhost").unwrap())?; - let mut bytes = Vec::new(); - conn.write_tls(&mut bytes).unwrap(); - - let message = OutboundOpaqueMessage::read(&mut Reader::init(&bytes)) - .unwrap() - .into_plain_message(); - - match Message::try_from(message).unwrap() { - Message { - payload: - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::ClientHello(ch)), - .. - }, - .. - } => Ok(ch), - other => panic!("unexpected message {other:?}"), - } -} - -fn roots() -> RootCertStore { - let mut r = RootCertStore::empty(); - r.add(CertificateDer::from_slice(include_bytes!( - "../../../test-ca/rsa-2048/ca.der" - ))) - .unwrap(); - r -} diff --git a/vendor/rustls/src/client/tls12.rs b/vendor/rustls/src/client/tls12.rs deleted file mode 100644 index 0fc5acee..00000000 --- a/vendor/rustls/src/client/tls12.rs +++ /dev/null @@ -1,1372 +0,0 @@ -use alloc::borrow::ToOwned; -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; - -use pki_types::ServerName; -pub(super) use server_hello::CompleteServerHelloHandling; -use subtle::ConstantTimeEq; - -use super::client_conn::ClientConnectionData; -use super::hs::ClientContext; -use crate::ConnectionTrafficSecrets; -use crate::check::{inappropriate_handshake_message, inappropriate_message}; -use crate::client::common::{ClientAuthDetails, ServerCertDetails}; -use crate::client::{ClientConfig, hs}; -use crate::common_state::{CommonState, HandshakeKind, KxState, Side, State}; -use crate::conn::ConnectionRandoms; -use crate::conn::kernel::{Direction, KernelContext, KernelState}; -use crate::crypto::KeyExchangeAlgorithm; -use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion}; -use crate::error::{Error, InvalidMessage, PeerIncompatible, PeerMisbehaved}; -use crate::hash_hs::HandshakeHash; -use crate::log::{debug, trace, warn}; -use crate::msgs::base::{Payload, PayloadU8, PayloadU16}; -use crate::msgs::ccs::ChangeCipherSpecPayload; -use crate::msgs::handshake::{ - CertificateChain, ClientDhParams, ClientEcdhParams, ClientKeyExchangeParams, - HandshakeMessagePayload, HandshakePayload, NewSessionTicketPayload, - NewSessionTicketPayloadTls13, ServerKeyExchangeParams, SessionId, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::sign::Signer; -use crate::suites::{PartiallyExtractedSecrets, SupportedCipherSuite}; -use crate::sync::Arc; -use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite}; -use crate::verify::{self, DigitallySignedStruct}; - -mod server_hello { - use super::*; - use crate::client::hs::{ClientHelloInput, ClientSessionValue}; - use crate::msgs::handshake::ServerHelloPayload; - - pub(in crate::client) struct CompleteServerHelloHandling { - pub(in crate::client) randoms: ConnectionRandoms, - pub(in crate::client) transcript: HandshakeHash, - pub(in crate::client) input: ClientHelloInput, - } - - impl CompleteServerHelloHandling { - pub(in crate::client) fn handle_server_hello( - mut self, - cx: &mut ClientContext<'_>, - suite: &'static Tls12CipherSuite, - server_hello: &ServerHelloPayload, - tls13_supported: bool, - ) -> hs::NextStateOrError<'static> { - self.randoms - .server - .clone_from_slice(&server_hello.random.0[..]); - - // Look for TLS1.3 downgrade signal in server random - // both the server random and TLS12_DOWNGRADE_SENTINEL are - // public values and don't require constant time comparison - let has_downgrade_marker = self.randoms.server[24..] == tls12::DOWNGRADE_SENTINEL; - if tls13_supported && has_downgrade_marker { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::AttemptedDowngradeToTls12WhenTls13IsSupported, - ) - }); - } - - // If we didn't have an input session to resume, and we sent a session ID, - // that implies we sent a TLS 1.3 legacy_session_id for compatibility purposes. - // In this instance since we're now continuing a TLS 1.2 handshake the server - // should not have echoed it back: it's a randomly generated session ID it couldn't - // have known. - if self.input.resuming.is_none() - && !self.input.session_id.is_empty() - && self.input.session_id == server_hello.session_id - { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::ServerEchoedCompatibilitySessionId, - ) - }); - } - - let ClientHelloInput { - config, - server_name, - .. - } = self.input; - - let resuming_session = self - .input - .resuming - .and_then(|resuming| match resuming.value { - ClientSessionValue::Tls12(inner) => Some(inner), - ClientSessionValue::Tls13(_) => None, - }); - - // Doing EMS? - let using_ems = server_hello - .extended_master_secret_ack - .is_some(); - if config.require_ems && !using_ems { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerIncompatible::ExtendedMasterSecretExtensionRequired, - ) - }); - } - - // Might the server send a ticket? - let must_issue_new_ticket = if server_hello - .session_ticket_ack - .is_some() - { - debug!("Server supports tickets"); - true - } else { - false - }; - - // Might the server send a CertificateStatus between Certificate and - // ServerKeyExchange? - let may_send_cert_status = server_hello - .certificate_status_request_ack - .is_some(); - if may_send_cert_status { - debug!("Server may staple OCSP response"); - } - - // See if we're successfully resuming. - if let Some(resuming) = resuming_session { - if resuming.session_id == server_hello.session_id { - debug!("Server agreed to resume"); - - // Is the server telling lies about the ciphersuite? - if resuming.suite() != suite { - return Err(PeerMisbehaved::ResumptionOfferedWithVariedCipherSuite.into()); - } - - // And about EMS support? - if resuming.extended_ms() != using_ems { - return Err(PeerMisbehaved::ResumptionOfferedWithVariedEms.into()); - } - - let secrets = - ConnectionSecrets::new_resume(self.randoms, suite, resuming.secret()); - config.key_log.log( - "CLIENT_RANDOM", - &secrets.randoms.client, - &secrets.master_secret, - ); - cx.common - .start_encryption_tls12(&secrets, Side::Client); - - // Since we're resuming, we verified the certificate and - // proof of possession in the prior session. - cx.common.peer_certificates = Some( - resuming - .server_cert_chain() - .clone() - .into_owned(), - ); - cx.common.handshake_kind = Some(HandshakeKind::Resumed); - let cert_verified = verify::ServerCertVerified::assertion(); - let sig_verified = verify::HandshakeSignatureValid::assertion(); - - return if must_issue_new_ticket { - Ok(Box::new(ExpectNewTicket { - config, - secrets, - resuming_session: Some(resuming), - session_id: server_hello.session_id, - server_name, - using_ems, - transcript: self.transcript, - resuming: true, - cert_verified, - sig_verified, - })) - } else { - Ok(Box::new(ExpectCcs { - config, - secrets, - resuming_session: Some(resuming), - session_id: server_hello.session_id, - server_name, - using_ems, - transcript: self.transcript, - ticket: None, - resuming: true, - cert_verified, - sig_verified, - })) - }; - } - } - - cx.common.handshake_kind = Some(HandshakeKind::Full); - Ok(Box::new(ExpectCertificate { - config, - resuming_session: None, - session_id: server_hello.session_id, - server_name, - randoms: self.randoms, - using_ems, - transcript: self.transcript, - suite, - may_send_cert_status, - must_issue_new_ticket, - })) - } - } -} - -struct ExpectCertificate { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - pub(super) suite: &'static Tls12CipherSuite, - may_send_cert_status: bool, - must_issue_new_ticket: bool, -} - -impl State<ClientConnectionData> for ExpectCertificate { - fn handle<'m>( - mut self: Box<Self>, - _cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - self.transcript.add_message(&m); - let server_cert_chain = require_handshake_msg_move!( - m, - HandshakeType::Certificate, - HandshakePayload::Certificate - )?; - - if self.may_send_cert_status { - Ok(Box::new(ExpectCertificateStatusOrServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert_chain, - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } else { - let server_cert = ServerCertDetails::new(server_cert_chain, vec![]); - - Ok(Box::new(ExpectServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert, - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCertificateStatusOrServerKx<'m> { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert_chain: CertificateChain<'m>, - must_issue_new_ticket: bool, -} - -impl State<ClientConnectionData> for ExpectCertificateStatusOrServerKx<'_> { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::ServerKeyExchange(..)), - .. - } => Box::new(ExpectServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: ServerCertDetails::new(self.server_cert_chain, vec![]), - must_issue_new_ticket: self.must_issue_new_ticket, - }) - .handle(cx, m), - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CertificateStatus(..)), - .. - } => Box::new(ExpectCertificateStatus { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert_chain: self.server_cert_chain, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - .handle(cx, m), - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[ - HandshakeType::ServerKeyExchange, - HandshakeType::CertificateStatus, - ], - )), - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectCertificateStatusOrServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert_chain: self.server_cert_chain.into_owned(), - must_issue_new_ticket: self.must_issue_new_ticket, - }) - } -} - -struct ExpectCertificateStatus<'a> { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert_chain: CertificateChain<'a>, - must_issue_new_ticket: bool, -} - -impl State<ClientConnectionData> for ExpectCertificateStatus<'_> { - fn handle<'m>( - mut self: Box<Self>, - _cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - self.transcript.add_message(&m); - let server_cert_ocsp_response = require_handshake_msg_move!( - m, - HandshakeType::CertificateStatus, - HandshakePayload::CertificateStatus - )? - .into_inner(); - - trace!( - "Server stapled OCSP response is {:?}", - &server_cert_ocsp_response - ); - - let server_cert = ServerCertDetails::new(self.server_cert_chain, server_cert_ocsp_response); - - Ok(Box::new(ExpectServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert, - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectCertificateStatus { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert_chain: self.server_cert_chain.into_owned(), - must_issue_new_ticket: self.must_issue_new_ticket, - }) - } -} - -struct ExpectServerKx<'a> { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert: ServerCertDetails<'a>, - must_issue_new_ticket: bool, -} - -impl State<ClientConnectionData> for ExpectServerKx<'_> { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let opaque_kx = require_handshake_msg!( - m, - HandshakeType::ServerKeyExchange, - HandshakePayload::ServerKeyExchange - )?; - self.transcript.add_message(&m); - - let kx = opaque_kx - .unwrap_given_kxa(self.suite.kx) - .ok_or_else(|| { - cx.common.send_fatal_alert( - AlertDescription::DecodeError, - InvalidMessage::MissingKeyExchange, - ) - })?; - - // Save the signature and signed parameters for later verification. - let mut kx_params = Vec::new(); - kx.params.encode(&mut kx_params); - let server_kx = ServerKxDetails::new(kx_params, kx.dss); - - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - { - match &kx.params { - ServerKeyExchangeParams::Ecdh(ecdhe) => { - debug!("ECDHE curve is {:?}", ecdhe.curve_params) - } - ServerKeyExchangeParams::Dh(dhe) => { - debug!("DHE params are p = {:?}, g = {:?}", dhe.dh_p, dhe.dh_g) - } - } - } - - Ok(Box::new(ExpectServerDoneOrCertReq { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert, - server_kx, - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectServerKx { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert.into_owned(), - must_issue_new_ticket: self.must_issue_new_ticket, - }) - } -} - -fn emit_certificate( - transcript: &mut HandshakeHash, - cert_chain: CertificateChain<'static>, - common: &mut CommonState, -) { - let cert = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload(HandshakePayload::Certificate( - cert_chain, - ))), - }; - - transcript.add_message(&cert); - common.send_msg(cert, false); -} - -fn emit_client_kx( - transcript: &mut HandshakeHash, - kxa: KeyExchangeAlgorithm, - common: &mut CommonState, - pub_key: &[u8], -) { - let mut buf = Vec::new(); - match kxa { - KeyExchangeAlgorithm::ECDHE => ClientKeyExchangeParams::Ecdh(ClientEcdhParams { - public: PayloadU8::new(pub_key.to_vec()), - }), - KeyExchangeAlgorithm::DHE => ClientKeyExchangeParams::Dh(ClientDhParams { - public: PayloadU16::new(pub_key.to_vec()), - }), - } - .encode(&mut buf); - let pubkey = Payload::new(buf); - - let ckx = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ClientKeyExchange(pubkey), - )), - }; - - transcript.add_message(&ckx); - common.send_msg(ckx, false); -} - -fn emit_certverify( - transcript: &mut HandshakeHash, - signer: &dyn Signer, - common: &mut CommonState, -) -> Result<(), Error> { - let message = transcript - .take_handshake_buf() - .ok_or_else(|| Error::General("Expected transcript".to_owned()))?; - - let scheme = signer.scheme(); - let sig = signer.sign(&message)?; - let body = DigitallySignedStruct::new(scheme, sig); - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::CertificateVerify(body), - )), - }; - - transcript.add_message(&m); - common.send_msg(m, false); - Ok(()) -} - -fn emit_ccs(common: &mut CommonState) { - let ccs = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), - }; - - common.send_msg(ccs, false); -} - -fn emit_finished( - secrets: &ConnectionSecrets, - transcript: &mut HandshakeHash, - common: &mut CommonState, -) { - let vh = transcript.current_hash(); - let verify_data = secrets.client_verify_data(&vh); - let verify_data_payload = Payload::new(verify_data); - - let f = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload(HandshakePayload::Finished( - verify_data_payload, - ))), - }; - - transcript.add_message(&f); - common.send_msg(f, true); -} - -struct ServerKxDetails { - kx_params: Vec<u8>, - kx_sig: DigitallySignedStruct, -} - -impl ServerKxDetails { - fn new(params: Vec<u8>, sig: DigitallySignedStruct) -> Self { - Self { - kx_params: params, - kx_sig: sig, - } - } -} - -// --- Either a CertificateRequest, or a ServerHelloDone. --- -// Existence of the CertificateRequest tells us the server is asking for -// client auth. Otherwise we go straight to ServerHelloDone. -struct ExpectServerDoneOrCertReq<'a> { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert: ServerCertDetails<'a>, - server_kx: ServerKxDetails, - must_issue_new_ticket: bool, -} - -impl State<ClientConnectionData> for ExpectServerDoneOrCertReq<'_> { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - if matches!( - m.payload, - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CertificateRequest(_)), - .. - } - ) { - Box::new(ExpectCertificateRequest { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert, - server_kx: self.server_kx, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - .handle(cx, m) - } else { - self.transcript.abandon_client_auth(); - - Box::new(ExpectServerDone { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert, - server_kx: self.server_kx, - client_auth: None, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - .handle(cx, m) - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectServerDoneOrCertReq { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert.into_owned(), - server_kx: self.server_kx, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - } -} - -struct ExpectCertificateRequest<'a> { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert: ServerCertDetails<'a>, - server_kx: ServerKxDetails, - must_issue_new_ticket: bool, -} - -impl State<ClientConnectionData> for ExpectCertificateRequest<'_> { - fn handle<'m>( - mut self: Box<Self>, - _cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let certreq = require_handshake_msg!( - m, - HandshakeType::CertificateRequest, - HandshakePayload::CertificateRequest - )?; - self.transcript.add_message(&m); - debug!("Got CertificateRequest {certreq:?}"); - - // The RFC jovially describes the design here as 'somewhat complicated' - // and 'somewhat underspecified'. So thanks for that. - // - // We ignore certreq.certtypes as a result, since the information it contains - // is entirely duplicated in certreq.sigschemes. - - const NO_CONTEXT: Option<Vec<u8>> = None; // TLS 1.2 doesn't use a context. - let no_compression = None; // or compression - let client_auth = ClientAuthDetails::resolve( - self.config - .client_auth_cert_resolver - .as_ref(), - Some(&certreq.canames), - &certreq.sigschemes, - NO_CONTEXT, - no_compression, - ); - - Ok(Box::new(ExpectServerDone { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert, - server_kx: self.server_kx, - client_auth: Some(client_auth), - must_issue_new_ticket: self.must_issue_new_ticket, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectCertificateRequest { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert.into_owned(), - server_kx: self.server_kx, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - } -} - -struct ExpectServerDone<'a> { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - using_ems: bool, - transcript: HandshakeHash, - suite: &'static Tls12CipherSuite, - server_cert: ServerCertDetails<'a>, - server_kx: ServerKxDetails, - client_auth: Option<ClientAuthDetails>, - must_issue_new_ticket: bool, -} - -impl State<ClientConnectionData> for ExpectServerDone<'_> { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::ServerHelloDone), - .. - } => {} - payload => { - return Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[HandshakeType::ServerHelloDone], - )); - } - } - - let mut st = *self; - st.transcript.add_message(&m); - - cx.common.check_aligned_handshake()?; - - trace!("Server cert is {:?}", st.server_cert.cert_chain); - debug!("Server DNS name is {:?}", st.server_name); - - let suite = st.suite; - - // 1. Verify the cert chain. - // 2. Verify that the top certificate signed their kx. - // 3. If doing client auth, send our Certificate. - // 4. Complete the key exchange: - // a) generate our kx pair - // b) emit a ClientKeyExchange containing it - // c) if doing client auth, emit a CertificateVerify - // d) derive the shared keys - // e) emit a CCS - // f) use the derived keys to start encryption - // 5. emit a Finished, our first encrypted message under the new keys. - - // 1. - let (end_entity, intermediates) = st - .server_cert - .cert_chain - .split_first() - .ok_or(Error::NoCertificatesPresented)?; - - let now = st.config.current_time()?; - - let cert_verified = st - .config - .verifier - .verify_server_cert( - end_entity, - intermediates, - &st.server_name, - &st.server_cert.ocsp_response, - now, - ) - .map_err(|err| { - cx.common - .send_cert_verify_error_alert(err) - })?; - - // 2. - // Build up the contents of the signed message. - // It's ClientHello.random || ServerHello.random || ServerKeyExchange.params - let sig_verified = { - let mut message = Vec::new(); - message.extend_from_slice(&st.randoms.client); - message.extend_from_slice(&st.randoms.server); - message.extend_from_slice(&st.server_kx.kx_params); - - // Check the signature is compatible with the ciphersuite. - let sig = &st.server_kx.kx_sig; - if !SupportedCipherSuite::from(suite) - .usable_for_signature_algorithm(sig.scheme.algorithm()) - { - warn!( - "peer signed kx with wrong algorithm (got {:?} expect {:?})", - sig.scheme.algorithm(), - suite.sign - ); - return Err(PeerMisbehaved::SignedKxWithWrongAlgorithm.into()); - } - - st.config - .verifier - .verify_tls12_signature(&message, end_entity, sig) - .map_err(|err| { - cx.common - .send_cert_verify_error_alert(err) - })? - }; - cx.common.peer_certificates = Some(st.server_cert.cert_chain.into_owned()); - - // 3. - if let Some(client_auth) = &st.client_auth { - let certs = match client_auth { - ClientAuthDetails::Empty { .. } => CertificateChain::default(), - ClientAuthDetails::Verify { certkey, .. } => CertificateChain(certkey.cert.clone()), - }; - emit_certificate(&mut st.transcript, certs, cx.common); - } - - // 4a. - let kx_params = tls12::decode_kx_params::<ServerKeyExchangeParams>( - st.suite.kx, - cx.common, - &st.server_kx.kx_params, - )?; - let maybe_skxg = match &kx_params { - ServerKeyExchangeParams::Ecdh(ecdh) => st - .config - .find_kx_group(ecdh.curve_params.named_group, ProtocolVersion::TLSv1_2), - ServerKeyExchangeParams::Dh(dh) => { - let ffdhe_group = dh.as_ffdhe_group(); - - st.config - .provider - .kx_groups - .iter() - .find(|kxg| kxg.ffdhe_group() == Some(ffdhe_group)) - .copied() - } - }; - let Some(skxg) = maybe_skxg else { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::SelectedUnofferedKxGroup, - )); - }; - cx.common.kx_state = KxState::Start(skxg); - let kx = skxg.start()?; - - // 4b. - let mut transcript = st.transcript; - emit_client_kx(&mut transcript, st.suite.kx, cx.common, kx.pub_key()); - // Note: EMS handshake hash only runs up to ClientKeyExchange. - let ems_seed = st - .using_ems - .then(|| transcript.current_hash()); - - // 4c. - if let Some(ClientAuthDetails::Verify { signer, .. }) = &st.client_auth { - emit_certverify(&mut transcript, signer.as_ref(), cx.common)?; - } - - // 4d. Derive secrets. - // An alert at this point will be sent in plaintext. That must happen - // prior to the CCS, or else the peer will try to decrypt it. - let secrets = ConnectionSecrets::from_key_exchange( - kx, - kx_params.pub_key(), - ems_seed, - st.randoms, - suite, - ) - .map_err(|err| { - cx.common - .send_fatal_alert(AlertDescription::IllegalParameter, err) - })?; - cx.common.kx_state.complete(); - - // 4e. CCS. We are definitely going to switch on encryption. - emit_ccs(cx.common); - - // 4f. Now commit secrets. - st.config.key_log.log( - "CLIENT_RANDOM", - &secrets.randoms.client, - &secrets.master_secret, - ); - cx.common - .start_encryption_tls12(&secrets, Side::Client); - cx.common - .record_layer - .start_encrypting(); - - // 5. - emit_finished(&secrets, &mut transcript, cx.common); - - if st.must_issue_new_ticket { - Ok(Box::new(ExpectNewTicket { - config: st.config, - secrets, - resuming_session: st.resuming_session, - session_id: st.session_id, - server_name: st.server_name, - using_ems: st.using_ems, - transcript, - resuming: false, - cert_verified, - sig_verified, - })) - } else { - Ok(Box::new(ExpectCcs { - config: st.config, - secrets, - resuming_session: st.resuming_session, - session_id: st.session_id, - server_name: st.server_name, - using_ems: st.using_ems, - transcript, - ticket: None, - resuming: false, - cert_verified, - sig_verified, - })) - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectServerDone { - config: self.config, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - randoms: self.randoms, - using_ems: self.using_ems, - transcript: self.transcript, - suite: self.suite, - server_cert: self.server_cert.into_owned(), - server_kx: self.server_kx, - client_auth: self.client_auth, - must_issue_new_ticket: self.must_issue_new_ticket, - }) - } -} - -struct ExpectNewTicket { - config: Arc<ClientConfig>, - secrets: ConnectionSecrets, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - using_ems: bool, - transcript: HandshakeHash, - resuming: bool, - cert_verified: verify::ServerCertVerified, - sig_verified: verify::HandshakeSignatureValid, -} - -impl State<ClientConnectionData> for ExpectNewTicket { - fn handle<'m>( - mut self: Box<Self>, - _cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - self.transcript.add_message(&m); - - let nst = require_handshake_msg_move!( - m, - HandshakeType::NewSessionTicket, - HandshakePayload::NewSessionTicket - )?; - - Ok(Box::new(ExpectCcs { - config: self.config, - secrets: self.secrets, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - using_ems: self.using_ems, - transcript: self.transcript, - ticket: Some(nst), - resuming: self.resuming, - cert_verified: self.cert_verified, - sig_verified: self.sig_verified, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// -- Waiting for their CCS -- -struct ExpectCcs { - config: Arc<ClientConfig>, - secrets: ConnectionSecrets, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - using_ems: bool, - transcript: HandshakeHash, - ticket: Option<NewSessionTicketPayload>, - resuming: bool, - cert_verified: verify::ServerCertVerified, - sig_verified: verify::HandshakeSignatureValid, -} - -impl State<ClientConnectionData> for ExpectCcs { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::ChangeCipherSpec(..) => {} - payload => { - return Err(inappropriate_message( - &payload, - &[ContentType::ChangeCipherSpec], - )); - } - } - // CCS should not be received interleaved with fragmented handshake-level - // message. - cx.common.check_aligned_handshake()?; - - // Note: msgs layer validates trivial contents of CCS. - cx.common - .record_layer - .start_decrypting(); - - Ok(Box::new(ExpectFinished { - config: self.config, - secrets: self.secrets, - resuming_session: self.resuming_session, - session_id: self.session_id, - server_name: self.server_name, - using_ems: self.using_ems, - transcript: self.transcript, - ticket: self.ticket, - resuming: self.resuming, - cert_verified: self.cert_verified, - sig_verified: self.sig_verified, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectFinished { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls12ClientSessionValue>, - session_id: SessionId, - server_name: ServerName<'static>, - using_ems: bool, - transcript: HandshakeHash, - ticket: Option<NewSessionTicketPayload>, - secrets: ConnectionSecrets, - resuming: bool, - cert_verified: verify::ServerCertVerified, - sig_verified: verify::HandshakeSignatureValid, -} - -impl ExpectFinished { - // -- Waiting for their finished -- - fn save_session(&mut self, cx: &ClientContext<'_>) { - // Save a ticket. If we got a new ticket, save that. Otherwise, save the - // original ticket again. - let (mut ticket, lifetime) = match self.ticket.take() { - Some(nst) => (nst.ticket, nst.lifetime_hint), - None => (Arc::new(PayloadU16::empty()), 0), - }; - - if ticket.0.is_empty() { - if let Some(resuming_session) = &mut self.resuming_session { - ticket = resuming_session.ticket(); - } - } - - if self.session_id.is_empty() && ticket.0.is_empty() { - debug!("Session not saved: server didn't allocate id or ticket"); - return; - } - - let Ok(now) = self.config.current_time() else { - debug!("Could not get current time"); - return; - }; - - let session_value = persist::Tls12ClientSessionValue::new( - self.secrets.suite(), - self.session_id, - ticket, - self.secrets.master_secret(), - cx.common - .peer_certificates - .clone() - .unwrap_or_default(), - &self.config.verifier, - &self.config.client_auth_cert_resolver, - now, - lifetime, - self.using_ems, - ); - - self.config - .resumption - .store - .set_tls12_session(self.server_name.clone(), session_value); - } -} - -impl State<ClientConnectionData> for ExpectFinished { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let mut st = *self; - let finished = - require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; - - cx.common.check_aligned_handshake()?; - - // Work out what verify_data we expect. - let vh = st.transcript.current_hash(); - let expect_verify_data = st.secrets.server_verify_data(&vh); - - // Constant-time verification of this is relatively unimportant: they only - // get one chance. But it can't hurt. - let _fin_verified = - match ConstantTimeEq::ct_eq(&expect_verify_data[..], finished.bytes()).into() { - true => verify::FinishedMessageVerified::assertion(), - false => { - return Err(cx - .common - .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError)); - } - }; - - // Hash this message too. - st.transcript.add_message(&m); - - st.save_session(cx); - - if st.resuming { - emit_ccs(cx.common); - cx.common - .record_layer - .start_encrypting(); - emit_finished(&st.secrets, &mut st.transcript, cx.common); - } - - cx.common - .start_traffic(&mut cx.sendable_plaintext); - Ok(Box::new(ExpectTraffic { - secrets: st.secrets, - _cert_verified: st.cert_verified, - _sig_verified: st.sig_verified, - _fin_verified, - })) - } - - // we could not decrypt the encrypted handshake message with session resumption - // this might mean that the ticket was invalid for some reason, so we remove it - // from the store to restart a session from scratch - fn handle_decrypt_error(&self) { - if self.resuming { - self.config - .resumption - .store - .remove_tls12_session(&self.server_name); - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// -- Traffic transit state -- -struct ExpectTraffic { - secrets: ConnectionSecrets, - _cert_verified: verify::ServerCertVerified, - _sig_verified: verify::HandshakeSignatureValid, - _fin_verified: verify::FinishedMessageVerified, -} - -impl State<ClientConnectionData> for ExpectTraffic { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::ApplicationData(payload) => cx - .common - .take_received_plaintext(payload), - payload => { - return Err(inappropriate_message( - &payload, - &[ContentType::ApplicationData], - )); - } - } - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.secrets - .export_keying_material(output, label, context); - Ok(()) - } - - fn extract_secrets(&self) -> Result<PartiallyExtractedSecrets, Error> { - self.secrets - .extract_secrets(Side::Client) - } - - fn into_external_state(self: Box<Self>) -> Result<Box<dyn KernelState + 'static>, Error> { - Ok(self) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -impl KernelState for ExpectTraffic { - fn update_secrets(&mut self, _: Direction) -> Result<ConnectionTrafficSecrets, Error> { - Err(Error::General( - "TLS 1.2 connections do not support traffic secret updates".into(), - )) - } - - fn handle_new_session_ticket( - &mut self, - _cx: &mut KernelContext<'_>, - _message: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error> { - Err(Error::General( - "TLS 1.2 session tickets may not be sent once the handshake has completed".into(), - )) - } -} diff --git a/vendor/rustls/src/client/tls13.rs b/vendor/rustls/src/client/tls13.rs deleted file mode 100644 index fe8495cc..00000000 --- a/vendor/rustls/src/client/tls13.rs +++ /dev/null @@ -1,1700 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; - -use pki_types::ServerName; -use subtle::ConstantTimeEq; - -use super::client_conn::ClientConnectionData; -use super::hs::{ClientContext, ClientHelloInput, ClientSessionValue}; -use crate::check::inappropriate_handshake_message; -use crate::client::common::{ClientAuthDetails, ClientHelloDetails, ServerCertDetails}; -use crate::client::ech::{self, EchState, EchStatus}; -use crate::client::{ClientConfig, ClientSessionStore, hs}; -use crate::common_state::{ - CommonState, HandshakeFlightTls13, HandshakeKind, KxState, Protocol, Side, State, -}; -use crate::conn::ConnectionRandoms; -use crate::conn::kernel::{Direction, KernelContext, KernelState}; -use crate::crypto::hash::Hash; -use crate::crypto::{ActiveKeyExchange, SharedSecret}; -use crate::enums::{ - AlertDescription, ContentType, HandshakeType, ProtocolVersion, SignatureScheme, -}; -use crate::error::{Error, InvalidMessage, PeerIncompatible, PeerMisbehaved}; -use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; -use crate::log::{debug, trace, warn}; -use crate::msgs::base::{Payload, PayloadU8}; -use crate::msgs::ccs::ChangeCipherSpecPayload; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::{ExtensionType, KeyUpdateRequest}; -use crate::msgs::handshake::{ - CERTIFICATE_MAX_SIZE_LIMIT, CertificatePayloadTls13, ClientExtensions, EchConfigPayload, - HandshakeMessagePayload, HandshakePayload, KeyShareEntry, NewSessionTicketPayloadTls13, - PresharedKeyBinder, PresharedKeyIdentity, PresharedKeyOffer, ServerExtensions, - ServerHelloPayload, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist::{self, Retrieved}; -use crate::sign::{CertifiedKey, Signer}; -use crate::suites::PartiallyExtractedSecrets; -use crate::sync::Arc; -use crate::tls13::key_schedule::{ - KeyScheduleEarly, KeyScheduleHandshake, KeySchedulePreHandshake, KeyScheduleResumption, - KeyScheduleTraffic, -}; -use crate::tls13::{ - Tls13CipherSuite, construct_client_verify_message, construct_server_verify_message, -}; -use crate::verify::{self, DigitallySignedStruct}; -use crate::{ConnectionTrafficSecrets, KeyLog, compress, crypto}; - -// Extensions we expect in plaintext in the ServerHello. -static ALLOWED_PLAINTEXT_EXTS: &[ExtensionType] = &[ - ExtensionType::KeyShare, - ExtensionType::PreSharedKey, - ExtensionType::SupportedVersions, -]; - -// Only the intersection of things we offer, and those disallowed -// in TLS1.3 -static DISALLOWED_TLS13_EXTS: &[ExtensionType] = &[ - ExtensionType::ECPointFormats, - ExtensionType::SessionTicket, - ExtensionType::RenegotiationInfo, - ExtensionType::ExtendedMasterSecret, -]; - -/// `early_data_key_schedule` is `Some` if we sent the -/// "early_data" extension to the server. -pub(super) fn handle_server_hello( - cx: &mut ClientContext<'_>, - server_hello: &ServerHelloPayload, - mut randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - mut transcript: HandshakeHash, - early_data_key_schedule: Option<KeyScheduleEarly>, - our_key_share: Box<dyn ActiveKeyExchange>, - server_hello_msg: &Message<'_>, - ech_state: Option<EchState>, - input: ClientHelloInput, -) -> hs::NextStateOrError<'static> { - validate_server_hello(cx.common, server_hello)?; - - let their_key_share = server_hello - .key_share - .as_ref() - .ok_or_else(|| { - cx.common.send_fatal_alert( - AlertDescription::MissingExtension, - PeerMisbehaved::MissingKeyShare, - ) - })?; - - let ClientHelloInput { - config, - resuming, - mut sent_tls13_fake_ccs, - mut hello, - server_name, - .. - } = input; - - let mut resuming_session = match resuming { - Some(Retrieved { - value: ClientSessionValue::Tls13(value), - .. - }) => Some(value), - _ => None, - }; - - let our_key_share = KeyExchangeChoice::new(&config, cx, our_key_share, their_key_share) - .map_err(|_| { - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::WrongGroupForKeyShare, - ) - })?; - - let key_schedule_pre_handshake = match (server_hello.preshared_key, early_data_key_schedule) { - (Some(selected_psk), Some(early_key_schedule)) => { - match &resuming_session { - Some(resuming) => { - let Some(resuming_suite) = suite.can_resume_from(resuming.suite()) else { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::ResumptionOfferedWithIncompatibleCipherSuite, - ) - }); - }; - - // If the server varies the suite here, we will have encrypted early data with - // the wrong suite. - if cx.data.early_data.is_enabled() && resuming_suite != suite { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::EarlyDataOfferedWithVariedCipherSuite, - ) - }); - } - - if selected_psk != 0 { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::SelectedInvalidPsk, - ) - }); - } - - debug!("Resuming using PSK"); - // The key schedule has been initialized and set in fill_in_psk_binder() - } - _ => { - return Err(PeerMisbehaved::SelectedUnofferedPsk.into()); - } - } - KeySchedulePreHandshake::from(early_key_schedule) - } - _ => { - debug!("Not resuming"); - // Discard the early data key schedule. - cx.data.early_data.rejected(); - cx.common.early_traffic = false; - resuming_session.take(); - KeySchedulePreHandshake::new(suite) - } - }; - - cx.common.kx_state.complete(); - let shared_secret = our_key_share - .complete(&their_key_share.payload.0) - .map_err(|err| { - cx.common - .send_fatal_alert(AlertDescription::IllegalParameter, err) - })?; - - let mut key_schedule = key_schedule_pre_handshake.into_handshake(shared_secret); - - // If we have ECH state, check that the server accepted our offer. - if let Some(ech_state) = ech_state { - let Message { - payload: - MessagePayload::Handshake { - encoded: server_hello_encoded, - .. - }, - .. - } = &server_hello_msg - else { - unreachable!("ServerHello is a handshake message"); - }; - cx.data.ech_status = match ech_state.confirm_acceptance( - &mut key_schedule, - server_hello, - server_hello_encoded, - suite.common.hash_provider, - )? { - // The server accepted our ECH offer, so complete the inner transcript with the - // server hello message, and switch the relevant state to the copies for the - // inner client hello. - Some(mut accepted) => { - accepted - .transcript - .add_message(server_hello_msg); - transcript = accepted.transcript; - randoms.client = accepted.random.0; - hello.sent_extensions = accepted.sent_extensions; - EchStatus::Accepted - } - // The server rejected our ECH offer. - None => EchStatus::Rejected, - }; - } - - // Remember what KX group the server liked for next time. - config - .resumption - .store - .set_kx_hint(server_name.clone(), their_key_share.group); - - // If we change keying when a subsequent handshake message is being joined, - // the two halves will have different record layer protections. Disallow this. - cx.common.check_aligned_handshake()?; - - let hash_at_client_recvd_server_hello = transcript.current_hash(); - let key_schedule = key_schedule.derive_client_handshake_secrets( - cx.data.early_data.is_enabled(), - hash_at_client_recvd_server_hello, - suite, - &*config.key_log, - &randoms.client, - cx.common, - ); - - emit_fake_ccs(&mut sent_tls13_fake_ccs, cx.common); - - Ok(Box::new(ExpectEncryptedExtensions { - config, - resuming_session, - server_name, - randoms, - suite, - transcript, - key_schedule, - hello, - })) -} - -enum KeyExchangeChoice { - Whole(Box<dyn ActiveKeyExchange>), - Component(Box<dyn ActiveKeyExchange>), -} - -impl KeyExchangeChoice { - /// Decide between `our_key_share` or `our_key_share.hybrid_component()` - /// based on the selection of the server expressed in `their_key_share`. - fn new( - config: &Arc<ClientConfig>, - cx: &mut ClientContext<'_>, - our_key_share: Box<dyn ActiveKeyExchange>, - their_key_share: &KeyShareEntry, - ) -> Result<Self, ()> { - if our_key_share.group() == their_key_share.group { - return Ok(Self::Whole(our_key_share)); - } - - let (component_group, _) = our_key_share - .hybrid_component() - .ok_or(())?; - - if component_group != their_key_share.group { - return Err(()); - } - - // correct the record for the benefit of accuracy of - // `negotiated_key_exchange_group()` - let actual_skxg = config - .find_kx_group(component_group, ProtocolVersion::TLSv1_3) - .ok_or(())?; - cx.common.kx_state = KxState::Start(actual_skxg); - - Ok(Self::Component(our_key_share)) - } - - fn complete(self, peer_pub_key: &[u8]) -> Result<SharedSecret, Error> { - match self { - Self::Whole(akx) => akx.complete(peer_pub_key), - Self::Component(akx) => akx.complete_hybrid_component(peer_pub_key), - } - } -} - -fn validate_server_hello( - common: &mut CommonState, - server_hello: &ServerHelloPayload, -) -> Result<(), Error> { - if !server_hello.only_contains(ALLOWED_PLAINTEXT_EXTS) { - return Err(common.send_fatal_alert( - AlertDescription::UnsupportedExtension, - PeerMisbehaved::UnexpectedCleartextExtension, - )); - } - - Ok(()) -} - -pub(super) fn initial_key_share( - config: &ClientConfig, - server_name: &ServerName<'_>, - kx_state: &mut KxState, -) -> Result<Box<dyn ActiveKeyExchange>, Error> { - let group = config - .resumption - .store - .kx_hint(server_name) - .and_then(|group_name| config.find_kx_group(group_name, ProtocolVersion::TLSv1_3)) - .unwrap_or_else(|| { - config - .provider - .kx_groups - .iter() - .copied() - .next() - .expect("No kx groups configured") - }); - - *kx_state = KxState::Start(group); - group.start() -} - -/// This implements the horrifying TLS1.3 hack where PSK binders have a -/// data dependency on the message they are contained within. -pub(super) fn fill_in_psk_binder( - resuming: &persist::Tls13ClientSessionValue, - transcript: &HandshakeHashBuffer, - hmp: &mut HandshakeMessagePayload<'_>, -) -> KeyScheduleEarly { - // We need to know the hash function of the suite we're trying to resume into. - let suite = resuming.suite(); - let suite_hash = suite.common.hash_provider; - - // The binder is calculated over the clienthello, but doesn't include itself or its - // length, or the length of its container. - let binder_plaintext = hmp.encoding_for_binder_signing(); - let handshake_hash = transcript.hash_given(suite_hash, &binder_plaintext); - - // Run a fake key_schedule to simulate what the server will do if it chooses - // to resume. - let key_schedule = KeyScheduleEarly::new(suite, resuming.secret()); - let real_binder = key_schedule.resumption_psk_binder_key_and_sign_verify_data(&handshake_hash); - - if let HandshakePayload::ClientHello(ch) = &mut hmp.0 { - if let Some(PresharedKeyOffer { - binders, - identities, - }) = &mut ch.preshared_key_offer - { - // the caller of this function must have set up the desired identity, and a - // matching (dummy) binder; or else the binder we compute here will be incorrect. - // See `prepare_resumption()`. - debug_assert_eq!(identities.len(), 1); - debug_assert_eq!(binders.len(), 1); - debug_assert_eq!(binders[0].as_ref().len(), real_binder.as_ref().len()); - binders[0] = PresharedKeyBinder::from(real_binder.as_ref().to_vec()); - } - }; - - key_schedule -} - -pub(super) fn prepare_resumption( - config: &ClientConfig, - cx: &mut ClientContext<'_>, - resuming_session: &Retrieved<&persist::Tls13ClientSessionValue>, - exts: &mut ClientExtensions<'_>, - doing_retry: bool, -) { - let resuming_suite = resuming_session.suite(); - cx.common.suite = Some(resuming_suite.into()); - // The EarlyData extension MUST be supplied together with the - // PreSharedKey extension. - let max_early_data_size = resuming_session.max_early_data_size(); - if config.enable_early_data && max_early_data_size > 0 && !doing_retry { - cx.data - .early_data - .enable(max_early_data_size as usize); - exts.early_data_request = Some(()); - } - - // Finally, and only for TLS1.3 with a ticket resumption, include a binder - // for our ticket. This must go last. - // - // Include an empty binder. It gets filled in below because it depends on - // the message it's contained in (!!!). - let obfuscated_ticket_age = resuming_session.obfuscated_ticket_age(); - - let binder_len = resuming_suite - .common - .hash_provider - .output_len(); - let binder = vec![0u8; binder_len]; - - let psk_identity = - PresharedKeyIdentity::new(resuming_session.ticket().to_vec(), obfuscated_ticket_age); - let psk_offer = PresharedKeyOffer::new(psk_identity, binder); - exts.preshared_key_offer = Some(psk_offer); -} - -pub(super) fn derive_early_traffic_secret( - key_log: &dyn KeyLog, - cx: &mut ClientContext<'_>, - hash_alg: &'static dyn Hash, - early_key_schedule: &KeyScheduleEarly, - sent_tls13_fake_ccs: &mut bool, - transcript_buffer: &HandshakeHashBuffer, - client_random: &[u8; 32], -) { - // For middlebox compatibility - emit_fake_ccs(sent_tls13_fake_ccs, cx.common); - - let client_hello_hash = transcript_buffer.hash_given(hash_alg, &[]); - early_key_schedule.client_early_traffic_secret( - &client_hello_hash, - key_log, - client_random, - cx.common, - ); - - // Now the client can send encrypted early data - cx.common.early_traffic = true; - trace!("Starting early data traffic"); -} - -pub(super) fn emit_fake_ccs(sent_tls13_fake_ccs: &mut bool, common: &mut CommonState) { - if common.is_quic() { - return; - } - - if core::mem::replace(sent_tls13_fake_ccs, true) { - return; - } - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), - }; - common.send_msg(m, false); -} - -fn validate_encrypted_extensions( - common: &mut CommonState, - hello: &ClientHelloDetails, - exts: &ServerExtensions<'_>, -) -> Result<(), Error> { - if hello.server_sent_unsolicited_extensions(exts, &[]) { - return Err(common.send_fatal_alert( - AlertDescription::UnsupportedExtension, - PeerMisbehaved::UnsolicitedEncryptedExtension, - )); - } - - if exts.contains_any(ALLOWED_PLAINTEXT_EXTS) || exts.contains_any(DISALLOWED_TLS13_EXTS) { - return Err(common.send_fatal_alert( - AlertDescription::UnsupportedExtension, - PeerMisbehaved::DisallowedEncryptedExtension, - )); - } - - Ok(()) -} - -struct ExpectEncryptedExtensions { - config: Arc<ClientConfig>, - resuming_session: Option<persist::Tls13ClientSessionValue>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - hello: ClientHelloDetails, -} - -impl State<ClientConnectionData> for ExpectEncryptedExtensions { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let exts = require_handshake_msg!( - m, - HandshakeType::EncryptedExtensions, - HandshakePayload::EncryptedExtensions - )?; - debug!("TLS1.3 encrypted extensions: {exts:?}"); - self.transcript.add_message(&m); - - validate_encrypted_extensions(cx.common, &self.hello, exts)?; - hs::process_alpn_protocol( - cx.common, - &self.hello.alpn_protocols, - exts.selected_protocol - .as_ref() - .map(|protocol| protocol.as_ref()), - )?; - hs::process_client_cert_type_extension( - cx.common, - &self.config, - exts.client_certificate_type.as_ref(), - )?; - hs::process_server_cert_type_extension( - cx.common, - &self.config, - exts.server_certificate_type.as_ref(), - )?; - - let ech_retry_configs = match (cx.data.ech_status, &exts.encrypted_client_hello_ack) { - // If we didn't offer ECH, or ECH was accepted, but the server sent an ECH encrypted - // extension with retry configs, we must error. - (EchStatus::NotOffered | EchStatus::Accepted, Some(_)) => { - return Err(cx.common.send_fatal_alert( - AlertDescription::UnsupportedExtension, - PeerMisbehaved::UnsolicitedEchExtension, - )); - } - // If we offered ECH, and it was rejected, store the retry configs (if any) from - // the server's ECH extension. We will return them in an error produced at the end - // of the handshake. - (EchStatus::Rejected, ext) => ext - .as_ref() - .map(|ext| ext.retry_configs.to_vec()), - _ => None, - }; - - // QUIC transport parameters - if cx.common.is_quic() { - match exts - .transport_parameters - .as_ref() - .or(exts.transport_parameters_draft.as_ref()) - { - Some(params) => cx.common.quic.params = Some(params.clone().into_vec()), - None => { - return Err(cx - .common - .missing_extension(PeerMisbehaved::MissingQuicTransportParameters)); - } - } - } - - match self.resuming_session { - Some(resuming_session) => { - let was_early_traffic = cx.common.early_traffic; - if was_early_traffic { - match exts.early_data_ack { - Some(()) => cx.data.early_data.accepted(), - None => { - cx.data.early_data.rejected(); - cx.common.early_traffic = false; - } - } - } - - if was_early_traffic && !cx.common.early_traffic { - // If no early traffic, set the encryption key for handshakes - self.key_schedule - .set_handshake_encrypter(cx.common); - } - - cx.common.peer_certificates = Some( - resuming_session - .server_cert_chain() - .clone(), - ); - cx.common.handshake_kind = Some(HandshakeKind::Resumed); - - // We *don't* reverify the certificate chain here: resumption is a - // continuation of the previous session in terms of security policy. - let cert_verified = verify::ServerCertVerified::assertion(); - let sig_verified = verify::HandshakeSignatureValid::assertion(); - Ok(Box::new(ExpectFinished { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: None, - cert_verified, - sig_verified, - ech_retry_configs, - })) - } - _ => { - if exts.early_data_ack.is_some() { - return Err(PeerMisbehaved::EarlyDataExtensionWithoutResumption.into()); - } - cx.common - .handshake_kind - .get_or_insert(HandshakeKind::Full); - - Ok(if self.hello.offered_cert_compression { - Box::new(ExpectCertificateOrCompressedCertificateOrCertReq { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - ech_retry_configs, - }) - } else { - Box::new(ExpectCertificateOrCertReq { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - ech_retry_configs, - }) - }) - } - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCertificateOrCompressedCertificateOrCertReq { - config: Arc<ClientConfig>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - ech_retry_configs: Option<Vec<EchConfigPayload>>, -} - -impl State<ClientConnectionData> for ExpectCertificateOrCompressedCertificateOrCertReq { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CertificateTls13(..)), - .. - } => Box::new(ExpectCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: None, - message_already_in_transcript: false, - ech_retry_configs: self.ech_retry_configs, - }) - .handle(cx, m), - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CompressedCertificate(..)), - .. - } => Box::new(ExpectCompressedCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: None, - ech_retry_configs: self.ech_retry_configs, - }) - .handle(cx, m), - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CertificateRequestTls13(..)), - .. - } => Box::new(ExpectCertificateRequest { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - offered_cert_compression: true, - ech_retry_configs: self.ech_retry_configs, - }) - .handle(cx, m), - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[ - HandshakeType::Certificate, - HandshakeType::CertificateRequest, - HandshakeType::CompressedCertificate, - ], - )), - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCertificateOrCompressedCertificate { - config: Arc<ClientConfig>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - client_auth: Option<ClientAuthDetails>, - ech_retry_configs: Option<Vec<EchConfigPayload>>, -} - -impl State<ClientConnectionData> for ExpectCertificateOrCompressedCertificate { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CertificateTls13(..)), - .. - } => Box::new(ExpectCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: self.client_auth, - message_already_in_transcript: false, - ech_retry_configs: self.ech_retry_configs, - }) - .handle(cx, m), - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CompressedCertificate(..)), - .. - } => Box::new(ExpectCompressedCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: self.client_auth, - ech_retry_configs: self.ech_retry_configs, - }) - .handle(cx, m), - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[ - HandshakeType::Certificate, - HandshakeType::CompressedCertificate, - ], - )), - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCertificateOrCertReq { - config: Arc<ClientConfig>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - ech_retry_configs: Option<Vec<EchConfigPayload>>, -} - -impl State<ClientConnectionData> for ExpectCertificateOrCertReq { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CertificateTls13(..)), - .. - } => Box::new(ExpectCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: None, - message_already_in_transcript: false, - ech_retry_configs: self.ech_retry_configs, - }) - .handle(cx, m), - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CertificateRequestTls13(..)), - .. - } => Box::new(ExpectCertificateRequest { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - offered_cert_compression: false, - ech_retry_configs: self.ech_retry_configs, - }) - .handle(cx, m), - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[ - HandshakeType::Certificate, - HandshakeType::CertificateRequest, - ], - )), - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// TLS1.3 version of CertificateRequest handling. We then move to expecting the server -// Certificate. Unfortunately the CertificateRequest type changed in an annoying way -// in TLS1.3. -struct ExpectCertificateRequest { - config: Arc<ClientConfig>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - offered_cert_compression: bool, - ech_retry_configs: Option<Vec<EchConfigPayload>>, -} - -impl State<ClientConnectionData> for ExpectCertificateRequest { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let certreq = &require_handshake_msg!( - m, - HandshakeType::CertificateRequest, - HandshakePayload::CertificateRequestTls13 - )?; - self.transcript.add_message(&m); - debug!("Got CertificateRequest {certreq:?}"); - - // Fortunately the problems here in TLS1.2 and prior are corrected in - // TLS1.3. - - // Must be empty during handshake. - if !certreq.context.0.is_empty() { - warn!("Server sent non-empty certreq context"); - return Err(cx.common.send_fatal_alert( - AlertDescription::DecodeError, - InvalidMessage::InvalidCertRequest, - )); - } - - let compat_sigschemes = certreq - .extensions - .signature_algorithms - .as_deref() - .unwrap_or_default() - .iter() - .cloned() - .filter(SignatureScheme::supported_in_tls13) - .collect::<Vec<SignatureScheme>>(); - - if compat_sigschemes.is_empty() { - return Err(cx.common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerIncompatible::NoCertificateRequestSignatureSchemesInCommon, - )); - } - - let compat_compressor = certreq - .extensions - .certificate_compression_algorithms - .as_deref() - .and_then(|offered| { - self.config - .cert_compressors - .iter() - .find(|compressor| offered.contains(&compressor.algorithm())) - }) - .cloned(); - - let client_auth = ClientAuthDetails::resolve( - self.config - .client_auth_cert_resolver - .as_ref(), - certreq - .extensions - .authority_names - .as_deref(), - &compat_sigschemes, - Some(certreq.context.0.clone()), - compat_compressor, - ); - - Ok(if self.offered_cert_compression { - Box::new(ExpectCertificateOrCompressedCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: Some(client_auth), - ech_retry_configs: self.ech_retry_configs, - }) - } else { - Box::new(ExpectCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: Some(client_auth), - message_already_in_transcript: false, - ech_retry_configs: self.ech_retry_configs, - }) - }) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCompressedCertificate { - config: Arc<ClientConfig>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - client_auth: Option<ClientAuthDetails>, - ech_retry_configs: Option<Vec<EchConfigPayload>>, -} - -impl State<ClientConnectionData> for ExpectCompressedCertificate { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - self.transcript.add_message(&m); - let compressed_cert = require_handshake_msg_move!( - m, - HandshakeType::CompressedCertificate, - HandshakePayload::CompressedCertificate - )?; - - let selected_decompressor = self - .config - .cert_decompressors - .iter() - .find(|item| item.algorithm() == compressed_cert.alg); - - let Some(decompressor) = selected_decompressor else { - return Err(cx.common.send_fatal_alert( - AlertDescription::BadCertificate, - PeerMisbehaved::SelectedUnofferedCertCompression, - )); - }; - - if compressed_cert.uncompressed_len as usize > CERTIFICATE_MAX_SIZE_LIMIT { - return Err(cx.common.send_fatal_alert( - AlertDescription::BadCertificate, - InvalidMessage::MessageTooLarge, - )); - } - - let mut decompress_buffer = vec![0u8; compressed_cert.uncompressed_len as usize]; - if let Err(compress::DecompressionFailed) = - decompressor.decompress(compressed_cert.compressed.0.bytes(), &mut decompress_buffer) - { - return Err(cx.common.send_fatal_alert( - AlertDescription::BadCertificate, - PeerMisbehaved::InvalidCertCompression, - )); - } - - let cert_payload = - match CertificatePayloadTls13::read(&mut Reader::init(&decompress_buffer)) { - Ok(cm) => cm, - Err(err) => { - return Err(cx - .common - .send_fatal_alert(AlertDescription::BadCertificate, err)); - } - }; - trace!( - "Server certificate decompressed using {:?} ({} bytes -> {})", - compressed_cert.alg, - compressed_cert - .compressed - .0 - .bytes() - .len(), - compressed_cert.uncompressed_len, - ); - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::CertificateTls13(cert_payload.into_owned()), - )), - }; - - Box::new(ExpectCertificate { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: self.client_auth, - message_already_in_transcript: true, - ech_retry_configs: self.ech_retry_configs, - }) - .handle(cx, m) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCertificate { - config: Arc<ClientConfig>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - client_auth: Option<ClientAuthDetails>, - message_already_in_transcript: bool, - ech_retry_configs: Option<Vec<EchConfigPayload>>, -} - -impl State<ClientConnectionData> for ExpectCertificate { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - if !self.message_already_in_transcript { - self.transcript.add_message(&m); - } - let cert_chain = require_handshake_msg_move!( - m, - HandshakeType::Certificate, - HandshakePayload::CertificateTls13 - )?; - - // This is only non-empty for client auth. - if !cert_chain.context.0.is_empty() { - return Err(cx.common.send_fatal_alert( - AlertDescription::DecodeError, - InvalidMessage::InvalidCertRequest, - )); - } - - let end_entity_ocsp = cert_chain.end_entity_ocsp().to_vec(); - let server_cert = ServerCertDetails::new( - cert_chain - .into_certificate_chain() - .into_owned(), - end_entity_ocsp, - ); - - Ok(Box::new(ExpectCertificateVerify { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - server_cert, - client_auth: self.client_auth, - ech_retry_configs: self.ech_retry_configs, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// --- TLS1.3 CertificateVerify --- -struct ExpectCertificateVerify<'a> { - config: Arc<ClientConfig>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - server_cert: ServerCertDetails<'a>, - client_auth: Option<ClientAuthDetails>, - ech_retry_configs: Option<Vec<EchConfigPayload>>, -} - -impl State<ClientConnectionData> for ExpectCertificateVerify<'_> { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let cert_verify = require_handshake_msg!( - m, - HandshakeType::CertificateVerify, - HandshakePayload::CertificateVerify - )?; - - trace!("Server cert is {:?}", self.server_cert.cert_chain); - - // 1. Verify the certificate chain. - let (end_entity, intermediates) = self - .server_cert - .cert_chain - .split_first() - .ok_or(Error::NoCertificatesPresented)?; - - let now = self.config.current_time()?; - - let cert_verified = self - .config - .verifier - .verify_server_cert( - end_entity, - intermediates, - &self.server_name, - &self.server_cert.ocsp_response, - now, - ) - .map_err(|err| { - cx.common - .send_cert_verify_error_alert(err) - })?; - - // 2. Verify their signature on the handshake. - let handshake_hash = self.transcript.current_hash(); - let sig_verified = self - .config - .verifier - .verify_tls13_signature( - construct_server_verify_message(&handshake_hash).as_ref(), - end_entity, - cert_verify, - ) - .map_err(|err| { - cx.common - .send_cert_verify_error_alert(err) - })?; - - cx.common.peer_certificates = Some(self.server_cert.cert_chain.into_owned()); - self.transcript.add_message(&m); - - Ok(Box::new(ExpectFinished { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_auth: self.client_auth, - cert_verified, - sig_verified, - ech_retry_configs: self.ech_retry_configs, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectCertificateVerify { - config: self.config, - server_name: self.server_name, - randoms: self.randoms, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - server_cert: self.server_cert.into_owned(), - client_auth: self.client_auth, - ech_retry_configs: self.ech_retry_configs, - }) - } -} - -fn emit_compressed_certificate_tls13( - flight: &mut HandshakeFlightTls13<'_>, - certkey: &CertifiedKey, - auth_context: Option<Vec<u8>>, - compressor: &dyn compress::CertCompressor, - config: &ClientConfig, -) { - let mut cert_payload = CertificatePayloadTls13::new(certkey.cert.iter(), None); - cert_payload.context = PayloadU8::new(auth_context.clone().unwrap_or_default()); - - let Ok(compressed) = config - .cert_compression_cache - .compression_for(compressor, &cert_payload) - else { - return emit_certificate_tls13(flight, Some(certkey), auth_context); - }; - - flight.add(HandshakeMessagePayload( - HandshakePayload::CompressedCertificate(compressed.compressed_cert_payload()), - )); -} - -fn emit_certificate_tls13( - flight: &mut HandshakeFlightTls13<'_>, - certkey: Option<&CertifiedKey>, - auth_context: Option<Vec<u8>>, -) { - let certs = certkey - .map(|ck| ck.cert.as_ref()) - .unwrap_or(&[][..]); - let mut cert_payload = CertificatePayloadTls13::new(certs.iter(), None); - cert_payload.context = PayloadU8::new(auth_context.unwrap_or_default()); - - flight.add(HandshakeMessagePayload(HandshakePayload::CertificateTls13( - cert_payload, - ))); -} - -fn emit_certverify_tls13( - flight: &mut HandshakeFlightTls13<'_>, - signer: &dyn Signer, -) -> Result<(), Error> { - let message = construct_client_verify_message(&flight.transcript.current_hash()); - - let scheme = signer.scheme(); - let sig = signer.sign(message.as_ref())?; - let dss = DigitallySignedStruct::new(scheme, sig); - - flight.add(HandshakeMessagePayload( - HandshakePayload::CertificateVerify(dss), - )); - Ok(()) -} - -fn emit_finished_tls13(flight: &mut HandshakeFlightTls13<'_>, verify_data: &crypto::hmac::Tag) { - let verify_data_payload = Payload::new(verify_data.as_ref()); - - flight.add(HandshakeMessagePayload(HandshakePayload::Finished( - verify_data_payload, - ))); -} - -fn emit_end_of_early_data_tls13(transcript: &mut HandshakeHash, common: &mut CommonState) { - if common.is_quic() { - return; - } - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::EndOfEarlyData, - )), - }; - - transcript.add_message(&m); - common.send_msg(m, true); -} - -struct ExpectFinished { - config: Arc<ClientConfig>, - server_name: ServerName<'static>, - randoms: ConnectionRandoms, - suite: &'static Tls13CipherSuite, - transcript: HandshakeHash, - key_schedule: KeyScheduleHandshake, - client_auth: Option<ClientAuthDetails>, - cert_verified: verify::ServerCertVerified, - sig_verified: verify::HandshakeSignatureValid, - ech_retry_configs: Option<Vec<EchConfigPayload>>, -} - -impl State<ClientConnectionData> for ExpectFinished { - fn handle<'m>( - self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let mut st = *self; - let finished = - require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; - - let handshake_hash = st.transcript.current_hash(); - let expect_verify_data = st - .key_schedule - .sign_server_finish(&handshake_hash); - - let fin = match ConstantTimeEq::ct_eq(expect_verify_data.as_ref(), finished.bytes()).into() - { - true => verify::FinishedMessageVerified::assertion(), - false => { - return Err(cx - .common - .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError)); - } - }; - - st.transcript.add_message(&m); - - let hash_after_handshake = st.transcript.current_hash(); - /* The EndOfEarlyData message to server is still encrypted with early data keys, - * but appears in the transcript after the server Finished. */ - if cx.common.early_traffic { - emit_end_of_early_data_tls13(&mut st.transcript, cx.common); - cx.common.early_traffic = false; - cx.data.early_data.finished(); - st.key_schedule - .set_handshake_encrypter(cx.common); - } - - let mut flight = HandshakeFlightTls13::new(&mut st.transcript); - - /* Send our authentication/finished messages. These are still encrypted - * with our handshake keys. */ - if let Some(client_auth) = st.client_auth { - match client_auth { - ClientAuthDetails::Empty { - auth_context_tls13: auth_context, - } => { - emit_certificate_tls13(&mut flight, None, auth_context); - } - ClientAuthDetails::Verify { - auth_context_tls13: auth_context, - .. - } if cx.data.ech_status == EchStatus::Rejected => { - // If ECH was offered, and rejected, we MUST respond with - // an empty certificate message. - emit_certificate_tls13(&mut flight, None, auth_context); - } - ClientAuthDetails::Verify { - certkey, - signer, - auth_context_tls13: auth_context, - compressor, - } => { - if let Some(compressor) = compressor { - emit_compressed_certificate_tls13( - &mut flight, - &certkey, - auth_context, - compressor, - &st.config, - ); - } else { - emit_certificate_tls13(&mut flight, Some(&certkey), auth_context); - } - emit_certverify_tls13(&mut flight, signer.as_ref())?; - } - } - } - - let (key_schedule_pre_finished, verify_data) = st - .key_schedule - .into_pre_finished_client_traffic( - hash_after_handshake, - flight.transcript.current_hash(), - &*st.config.key_log, - &st.randoms.client, - ); - - emit_finished_tls13(&mut flight, &verify_data); - flight.finish(cx.common); - - /* We're now sure this server supports TLS1.3. But if we run out of TLS1.3 tickets - * when connecting to it again, we definitely don't want to attempt a TLS1.2 resumption. */ - st.config - .resumption - .store - .remove_tls12_session(&st.server_name); - - /* Now move to our application traffic keys. */ - cx.common.check_aligned_handshake()?; - let (key_schedule, resumption) = - key_schedule_pre_finished.into_traffic(cx.common, st.transcript.current_hash()); - cx.common - .start_traffic(&mut cx.sendable_plaintext); - - // Now that we've reached the end of the normal handshake we must enforce ECH acceptance by - // sending an alert and returning an error (potentially with retry configs) if the server - // did not accept our ECH offer. - if cx.data.ech_status == EchStatus::Rejected { - return Err(ech::fatal_alert_required(st.ech_retry_configs, cx.common)); - } - - let st = ExpectTraffic { - config: st.config.clone(), - session_storage: st.config.resumption.store.clone(), - server_name: st.server_name, - suite: st.suite, - key_schedule, - resumption, - _cert_verified: st.cert_verified, - _sig_verified: st.sig_verified, - _fin_verified: fin, - }; - - Ok(match cx.common.is_quic() { - true => Box::new(ExpectQuicTraffic(st)), - false => Box::new(st), - }) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// -- Traffic transit state (TLS1.3) -- -// In this state we can be sent tickets, key updates, -// and application data. -struct ExpectTraffic { - config: Arc<ClientConfig>, - session_storage: Arc<dyn ClientSessionStore>, - server_name: ServerName<'static>, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTraffic, - resumption: KeyScheduleResumption, - _cert_verified: verify::ServerCertVerified, - _sig_verified: verify::HandshakeSignatureValid, - _fin_verified: verify::FinishedMessageVerified, -} - -impl ExpectTraffic { - fn handle_new_ticket_impl( - &mut self, - cx: &mut KernelContext<'_>, - nst: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error> { - let secret = self - .resumption - .derive_ticket_psk(&nst.nonce.0); - - let now = self.config.current_time()?; - - #[allow(unused_mut)] - let mut value = persist::Tls13ClientSessionValue::new( - self.suite, - nst.ticket.clone(), - secret.as_ref(), - cx.peer_certificates - .cloned() - .unwrap_or_default(), - &self.config.verifier, - &self.config.client_auth_cert_resolver, - now, - nst.lifetime, - nst.age_add, - nst.extensions - .max_early_data_size - .unwrap_or_default(), - ); - - if cx.is_quic() { - if let Some(sz) = nst.extensions.max_early_data_size { - if sz != 0 && sz != 0xffff_ffff { - return Err(PeerMisbehaved::InvalidMaxEarlyDataSize.into()); - } - } - - if let Some(quic_params) = &cx.quic.params { - value.set_quic_params(quic_params); - } - } - - self.session_storage - .insert_tls13_ticket(self.server_name.clone(), value); - Ok(()) - } - - fn handle_new_ticket_tls13( - &mut self, - cx: &mut ClientContext<'_>, - nst: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error> { - let mut kcx = KernelContext { - peer_certificates: cx.common.peer_certificates.as_ref(), - protocol: cx.common.protocol, - quic: &cx.common.quic, - }; - cx.common.tls13_tickets_received = cx - .common - .tls13_tickets_received - .saturating_add(1); - self.handle_new_ticket_impl(&mut kcx, nst) - } - - fn handle_key_update( - &mut self, - common: &mut CommonState, - key_update_request: &KeyUpdateRequest, - ) -> Result<(), Error> { - if let Protocol::Quic = common.protocol { - return Err(common.send_fatal_alert( - AlertDescription::UnexpectedMessage, - PeerMisbehaved::KeyUpdateReceivedInQuicConnection, - )); - } - - // Mustn't be interleaved with other handshake messages. - common.check_aligned_handshake()?; - - if common.should_update_key(key_update_request)? { - self.key_schedule - .update_encrypter_and_notify(common); - } - - // Update our read-side keys. - self.key_schedule - .update_decrypter(common); - Ok(()) - } -} - -impl State<ClientConnectionData> for ExpectTraffic { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::ApplicationData(payload) => cx - .common - .take_received_plaintext(payload), - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::NewSessionTicketTls13(new_ticket)), - .. - } => self.handle_new_ticket_tls13(cx, &new_ticket)?, - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::KeyUpdate(key_update)), - .. - } => self.handle_key_update(cx.common, &key_update)?, - payload => { - return Err(inappropriate_handshake_message( - &payload, - &[ContentType::ApplicationData, ContentType::Handshake], - &[HandshakeType::NewSessionTicket, HandshakeType::KeyUpdate], - )); - } - } - - Ok(self) - } - - fn send_key_update_request(&mut self, common: &mut CommonState) -> Result<(), Error> { - self.key_schedule - .request_key_update_and_update_encrypter(common) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.key_schedule - .export_keying_material(output, label, context) - } - - fn extract_secrets(&self) -> Result<PartiallyExtractedSecrets, Error> { - self.key_schedule - .extract_secrets(Side::Client) - } - - fn into_external_state(self: Box<Self>) -> Result<Box<dyn KernelState + 'static>, Error> { - Ok(self) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -impl KernelState for ExpectTraffic { - fn update_secrets(&mut self, dir: Direction) -> Result<ConnectionTrafficSecrets, Error> { - self.key_schedule - .refresh_traffic_secret(match dir { - Direction::Transmit => Side::Client, - Direction::Receive => Side::Server, - }) - } - - fn handle_new_session_ticket( - &mut self, - cx: &mut KernelContext<'_>, - message: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error> { - self.handle_new_ticket_impl(cx, message) - } -} - -struct ExpectQuicTraffic(ExpectTraffic); - -impl State<ClientConnectionData> for ExpectQuicTraffic { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ClientContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let nst = require_handshake_msg!( - m, - HandshakeType::NewSessionTicket, - HandshakePayload::NewSessionTicketTls13 - )?; - self.0 - .handle_new_ticket_tls13(cx, nst)?; - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.0 - .export_keying_material(output, label, context) - } - - fn into_external_state(self: Box<Self>) -> Result<Box<dyn KernelState + 'static>, Error> { - Ok(self) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -impl KernelState for ExpectQuicTraffic { - fn update_secrets(&mut self, _: Direction) -> Result<ConnectionTrafficSecrets, Error> { - Err(Error::General( - "KeyUpdate is not supported for QUIC connections".into(), - )) - } - - fn handle_new_session_ticket( - &mut self, - cx: &mut KernelContext<'_>, - nst: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error> { - self.0.handle_new_ticket_impl(cx, nst) - } -} diff --git a/vendor/rustls/src/common_state.rs b/vendor/rustls/src/common_state.rs deleted file mode 100644 index 4d47cf15..00000000 --- a/vendor/rustls/src/common_state.rs +++ /dev/null @@ -1,1049 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; - -use pki_types::CertificateDer; - -use crate::conn::kernel::KernelState; -use crate::crypto::SupportedKxGroup; -use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion}; -use crate::error::{Error, InvalidMessage, PeerMisbehaved}; -use crate::hash_hs::HandshakeHash; -use crate::log::{debug, error, warn}; -use crate::msgs::alert::AlertMessagePayload; -use crate::msgs::base::Payload; -use crate::msgs::codec::Codec; -use crate::msgs::enums::{AlertLevel, KeyUpdateRequest}; -use crate::msgs::fragmenter::MessageFragmenter; -use crate::msgs::handshake::{CertificateChain, HandshakeMessagePayload, ProtocolName}; -use crate::msgs::message::{ - Message, MessagePayload, OutboundChunks, OutboundOpaqueMessage, OutboundPlainMessage, - PlainMessage, -}; -use crate::record_layer::PreEncryptAction; -use crate::suites::{PartiallyExtractedSecrets, SupportedCipherSuite}; -#[cfg(feature = "tls12")] -use crate::tls12::ConnectionSecrets; -use crate::unbuffered::{EncryptError, InsufficientSizeError}; -use crate::vecbuf::ChunkVecBuffer; -use crate::{quic, record_layer}; - -/// Connection state common to both client and server connections. -pub struct CommonState { - pub(crate) negotiated_version: Option<ProtocolVersion>, - pub(crate) handshake_kind: Option<HandshakeKind>, - pub(crate) side: Side, - pub(crate) record_layer: record_layer::RecordLayer, - pub(crate) suite: Option<SupportedCipherSuite>, - pub(crate) kx_state: KxState, - pub(crate) alpn_protocol: Option<ProtocolName>, - pub(crate) aligned_handshake: bool, - pub(crate) may_send_application_data: bool, - pub(crate) may_receive_application_data: bool, - pub(crate) early_traffic: bool, - sent_fatal_alert: bool, - /// If we signaled end of stream. - pub(crate) has_sent_close_notify: bool, - /// If the peer has signaled end of stream. - pub(crate) has_received_close_notify: bool, - #[cfg(feature = "std")] - pub(crate) has_seen_eof: bool, - pub(crate) peer_certificates: Option<CertificateChain<'static>>, - message_fragmenter: MessageFragmenter, - pub(crate) received_plaintext: ChunkVecBuffer, - pub(crate) sendable_tls: ChunkVecBuffer, - queued_key_update_message: Option<Vec<u8>>, - - /// Protocol whose key schedule should be used. Unused for TLS < 1.3. - pub(crate) protocol: Protocol, - pub(crate) quic: quic::Quic, - pub(crate) enable_secret_extraction: bool, - temper_counters: TemperCounters, - pub(crate) refresh_traffic_keys_pending: bool, - pub(crate) fips: bool, - pub(crate) tls13_tickets_received: u32, -} - -impl CommonState { - pub(crate) fn new(side: Side) -> Self { - Self { - negotiated_version: None, - handshake_kind: None, - side, - record_layer: record_layer::RecordLayer::new(), - suite: None, - kx_state: KxState::default(), - alpn_protocol: None, - aligned_handshake: true, - may_send_application_data: false, - may_receive_application_data: false, - early_traffic: false, - sent_fatal_alert: false, - has_sent_close_notify: false, - has_received_close_notify: false, - #[cfg(feature = "std")] - has_seen_eof: false, - peer_certificates: None, - message_fragmenter: MessageFragmenter::default(), - received_plaintext: ChunkVecBuffer::new(Some(DEFAULT_RECEIVED_PLAINTEXT_LIMIT)), - sendable_tls: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)), - queued_key_update_message: None, - protocol: Protocol::Tcp, - quic: quic::Quic::default(), - enable_secret_extraction: false, - temper_counters: TemperCounters::default(), - refresh_traffic_keys_pending: false, - fips: false, - tls13_tickets_received: 0, - } - } - - /// Returns true if the caller should call [`Connection::write_tls`] as soon as possible. - /// - /// [`Connection::write_tls`]: crate::Connection::write_tls - pub fn wants_write(&self) -> bool { - !self.sendable_tls.is_empty() - } - - /// Returns true if the connection is currently performing the TLS handshake. - /// - /// During this time plaintext written to the connection is buffered in memory. After - /// [`Connection::process_new_packets()`] has been called, this might start to return `false` - /// while the final handshake packets still need to be extracted from the connection's buffers. - /// - /// [`Connection::process_new_packets()`]: crate::Connection::process_new_packets - pub fn is_handshaking(&self) -> bool { - !(self.may_send_application_data && self.may_receive_application_data) - } - - /// Retrieves the certificate chain or the raw public key used by the peer to authenticate. - /// - /// The order of the certificate chain is as it appears in the TLS - /// protocol: the first certificate relates to the peer, the - /// second certifies the first, the third certifies the second, and - /// so on. - /// - /// When using raw public keys, the first and only element is the raw public key. - /// - /// This is made available for both full and resumed handshakes. - /// - /// For clients, this is the certificate chain or the raw public key of the server. - /// - /// For servers, this is the certificate chain or the raw public key of the client, - /// if client authentication was completed. - /// - /// The return value is None until this value is available. - /// - /// Note: the return type of the 'certificate', when using raw public keys is `CertificateDer<'static>` - /// even though this should technically be a `SubjectPublicKeyInfoDer<'static>`. - /// This choice simplifies the API and ensures backwards compatibility. - pub fn peer_certificates(&self) -> Option<&[CertificateDer<'static>]> { - self.peer_certificates.as_deref() - } - - /// Retrieves the protocol agreed with the peer via ALPN. - /// - /// A return value of `None` after handshake completion - /// means no protocol was agreed (because no protocols - /// were offered or accepted by the peer). - pub fn alpn_protocol(&self) -> Option<&[u8]> { - self.get_alpn_protocol() - } - - /// Retrieves the ciphersuite agreed with the peer. - /// - /// This returns None until the ciphersuite is agreed. - pub fn negotiated_cipher_suite(&self) -> Option<SupportedCipherSuite> { - self.suite - } - - /// Retrieves the key exchange group agreed with the peer. - /// - /// This function may return `None` depending on the state of the connection, - /// the type of handshake, and the protocol version. - /// - /// If [`CommonState::is_handshaking()`] is true this function will return `None`. - /// Similarly, if the [`CommonState::handshake_kind()`] is [`HandshakeKind::Resumed`] - /// and the [`CommonState::protocol_version()`] is TLS 1.2, then no key exchange will have - /// occurred and this function will return `None`. - pub fn negotiated_key_exchange_group(&self) -> Option<&'static dyn SupportedKxGroup> { - match self.kx_state { - KxState::Complete(group) => Some(group), - _ => None, - } - } - - /// Retrieves the protocol version agreed with the peer. - /// - /// This returns `None` until the version is agreed. - pub fn protocol_version(&self) -> Option<ProtocolVersion> { - self.negotiated_version - } - - /// Which kind of handshake was performed. - /// - /// This tells you whether the handshake was a resumption or not. - /// - /// This will return `None` before it is known which sort of - /// handshake occurred. - pub fn handshake_kind(&self) -> Option<HandshakeKind> { - self.handshake_kind - } - - pub(crate) fn is_tls13(&self) -> bool { - matches!(self.negotiated_version, Some(ProtocolVersion::TLSv1_3)) - } - - pub(crate) fn process_main_protocol<Data>( - &mut self, - msg: Message<'_>, - mut state: Box<dyn State<Data>>, - data: &mut Data, - sendable_plaintext: Option<&mut ChunkVecBuffer>, - ) -> Result<Box<dyn State<Data>>, Error> { - // For TLS1.2, outside of the handshake, send rejection alerts for - // renegotiation requests. These can occur any time. - if self.may_receive_application_data && !self.is_tls13() { - let reject_ty = match self.side { - Side::Client => HandshakeType::HelloRequest, - Side::Server => HandshakeType::ClientHello, - }; - if msg.is_handshake_type(reject_ty) { - self.temper_counters - .received_renegotiation_request()?; - self.send_warning_alert(AlertDescription::NoRenegotiation); - return Ok(state); - } - } - - let mut cx = Context { - common: self, - data, - sendable_plaintext, - }; - match state.handle(&mut cx, msg) { - Ok(next) => { - state = next.into_owned(); - Ok(state) - } - Err(e @ Error::InappropriateMessage { .. }) - | Err(e @ Error::InappropriateHandshakeMessage { .. }) => { - Err(self.send_fatal_alert(AlertDescription::UnexpectedMessage, e)) - } - Err(e) => Err(e), - } - } - - pub(crate) fn write_plaintext( - &mut self, - payload: OutboundChunks<'_>, - outgoing_tls: &mut [u8], - ) -> Result<usize, EncryptError> { - if payload.is_empty() { - return Ok(0); - } - - let fragments = self - .message_fragmenter - .fragment_payload( - ContentType::ApplicationData, - ProtocolVersion::TLSv1_2, - payload.clone(), - ); - - for f in 0..fragments.len() { - match self - .record_layer - .pre_encrypt_action(f as u64) - { - PreEncryptAction::Nothing => {} - PreEncryptAction::RefreshOrClose => match self.negotiated_version { - Some(ProtocolVersion::TLSv1_3) => { - // driven by caller, as we don't have the `State` here - self.refresh_traffic_keys_pending = true; - } - _ => { - error!( - "traffic keys exhausted, closing connection to prevent security failure" - ); - self.send_close_notify(); - return Err(EncryptError::EncryptExhausted); - } - }, - PreEncryptAction::Refuse => { - return Err(EncryptError::EncryptExhausted); - } - } - } - - self.perhaps_write_key_update(); - - self.check_required_size(outgoing_tls, fragments)?; - - let fragments = self - .message_fragmenter - .fragment_payload( - ContentType::ApplicationData, - ProtocolVersion::TLSv1_2, - payload, - ); - - Ok(self.write_fragments(outgoing_tls, fragments)) - } - - // Changing the keys must not span any fragmented handshake - // messages. Otherwise the defragmented messages will have - // been protected with two different record layer protections, - // which is illegal. Not mentioned in RFC. - pub(crate) fn check_aligned_handshake(&mut self) -> Result<(), Error> { - if !self.aligned_handshake { - Err(self.send_fatal_alert( - AlertDescription::UnexpectedMessage, - PeerMisbehaved::KeyEpochWithPendingFragment, - )) - } else { - Ok(()) - } - } - - /// Fragment `m`, encrypt the fragments, and then queue - /// the encrypted fragments for sending. - pub(crate) fn send_msg_encrypt(&mut self, m: PlainMessage) { - let iter = self - .message_fragmenter - .fragment_message(&m); - for m in iter { - self.send_single_fragment(m); - } - } - - /// Like send_msg_encrypt, but operate on an appdata directly. - fn send_appdata_encrypt(&mut self, payload: OutboundChunks<'_>, limit: Limit) -> usize { - // Here, the limit on sendable_tls applies to encrypted data, - // but we're respecting it for plaintext data -- so we'll - // be out by whatever the cipher+record overhead is. That's a - // constant and predictable amount, so it's not a terrible issue. - let len = match limit { - #[cfg(feature = "std")] - Limit::Yes => self - .sendable_tls - .apply_limit(payload.len()), - Limit::No => payload.len(), - }; - - let iter = self - .message_fragmenter - .fragment_payload( - ContentType::ApplicationData, - ProtocolVersion::TLSv1_2, - payload.split_at(len).0, - ); - for m in iter { - self.send_single_fragment(m); - } - - len - } - - fn send_single_fragment(&mut self, m: OutboundPlainMessage<'_>) { - if m.typ == ContentType::Alert { - // Alerts are always sendable -- never quashed by a PreEncryptAction. - let em = self.record_layer.encrypt_outgoing(m); - self.queue_tls_message(em); - return; - } - - match self - .record_layer - .next_pre_encrypt_action() - { - PreEncryptAction::Nothing => {} - - // Close connection once we start to run out of - // sequence space. - PreEncryptAction::RefreshOrClose => { - match self.negotiated_version { - Some(ProtocolVersion::TLSv1_3) => { - // driven by caller, as we don't have the `State` here - self.refresh_traffic_keys_pending = true; - } - _ => { - error!( - "traffic keys exhausted, closing connection to prevent security failure" - ); - self.send_close_notify(); - return; - } - } - } - - // Refuse to wrap counter at all costs. This - // is basically untestable unfortunately. - PreEncryptAction::Refuse => { - return; - } - }; - - let em = self.record_layer.encrypt_outgoing(m); - self.queue_tls_message(em); - } - - fn send_plain_non_buffering(&mut self, payload: OutboundChunks<'_>, limit: Limit) -> usize { - debug_assert!(self.may_send_application_data); - debug_assert!(self.record_layer.is_encrypting()); - - if payload.is_empty() { - // Don't send empty fragments. - return 0; - } - - self.send_appdata_encrypt(payload, limit) - } - - /// Mark the connection as ready to send application data. - /// - /// Also flush `sendable_plaintext` if it is `Some`. - pub(crate) fn start_outgoing_traffic( - &mut self, - sendable_plaintext: &mut Option<&mut ChunkVecBuffer>, - ) { - self.may_send_application_data = true; - if let Some(sendable_plaintext) = sendable_plaintext { - self.flush_plaintext(sendable_plaintext); - } - } - - /// Mark the connection as ready to send and receive application data. - /// - /// Also flush `sendable_plaintext` if it is `Some`. - pub(crate) fn start_traffic(&mut self, sendable_plaintext: &mut Option<&mut ChunkVecBuffer>) { - self.may_receive_application_data = true; - self.start_outgoing_traffic(sendable_plaintext); - } - - /// Send any buffered plaintext. Plaintext is buffered if - /// written during handshake. - fn flush_plaintext(&mut self, sendable_plaintext: &mut ChunkVecBuffer) { - if !self.may_send_application_data { - return; - } - - while let Some(buf) = sendable_plaintext.pop() { - self.send_plain_non_buffering(buf.as_slice().into(), Limit::No); - } - } - - // Put m into sendable_tls for writing. - fn queue_tls_message(&mut self, m: OutboundOpaqueMessage) { - self.perhaps_write_key_update(); - self.sendable_tls.append(m.encode()); - } - - pub(crate) fn perhaps_write_key_update(&mut self) { - if let Some(message) = self.queued_key_update_message.take() { - self.sendable_tls.append(message); - } - } - - /// Send a raw TLS message, fragmenting it if needed. - pub(crate) fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) { - { - if let Protocol::Quic = self.protocol { - if let MessagePayload::Alert(alert) = m.payload { - self.quic.alert = Some(alert.description); - } else { - debug_assert!( - matches!( - m.payload, - MessagePayload::Handshake { .. } | MessagePayload::HandshakeFlight(_) - ), - "QUIC uses TLS for the cryptographic handshake only" - ); - let mut bytes = Vec::new(); - m.payload.encode(&mut bytes); - self.quic - .hs_queue - .push_back((must_encrypt, bytes)); - } - return; - } - } - if !must_encrypt { - let msg = &m.into(); - let iter = self - .message_fragmenter - .fragment_message(msg); - for m in iter { - self.queue_tls_message(m.to_unencrypted_opaque()); - } - } else { - self.send_msg_encrypt(m.into()); - } - } - - pub(crate) fn take_received_plaintext(&mut self, bytes: Payload<'_>) { - self.received_plaintext - .append(bytes.into_vec()); - } - - #[cfg(feature = "tls12")] - pub(crate) fn start_encryption_tls12(&mut self, secrets: &ConnectionSecrets, side: Side) { - let (dec, enc) = secrets.make_cipher_pair(side); - self.record_layer - .prepare_message_encrypter( - enc, - secrets - .suite() - .common - .confidentiality_limit, - ); - self.record_layer - .prepare_message_decrypter(dec); - } - - pub(crate) fn missing_extension(&mut self, why: PeerMisbehaved) -> Error { - self.send_fatal_alert(AlertDescription::MissingExtension, why) - } - - fn send_warning_alert(&mut self, desc: AlertDescription) { - warn!("Sending warning alert {desc:?}"); - self.send_warning_alert_no_log(desc); - } - - pub(crate) fn process_alert(&mut self, alert: &AlertMessagePayload) -> Result<(), Error> { - // Reject unknown AlertLevels. - if let AlertLevel::Unknown(_) = alert.level { - return Err(self.send_fatal_alert( - AlertDescription::IllegalParameter, - Error::AlertReceived(alert.description), - )); - } - - // If we get a CloseNotify, make a note to declare EOF to our - // caller. But do not treat unauthenticated alerts like this. - if self.may_receive_application_data && alert.description == AlertDescription::CloseNotify { - self.has_received_close_notify = true; - return Ok(()); - } - - // Warnings are nonfatal for TLS1.2, but outlawed in TLS1.3 - // (except, for no good reason, user_cancelled). - let err = Error::AlertReceived(alert.description); - if alert.level == AlertLevel::Warning { - self.temper_counters - .received_warning_alert()?; - if self.is_tls13() && alert.description != AlertDescription::UserCanceled { - return Err(self.send_fatal_alert(AlertDescription::DecodeError, err)); - } - - // Some implementations send pointless `user_canceled` alerts, don't log them - // in release mode (https://bugs.openjdk.org/browse/JDK-8323517). - if alert.description != AlertDescription::UserCanceled || cfg!(debug_assertions) { - warn!("TLS alert warning received: {alert:?}"); - } - - return Ok(()); - } - - Err(err) - } - - pub(crate) fn send_cert_verify_error_alert(&mut self, err: Error) -> Error { - self.send_fatal_alert( - match &err { - Error::InvalidCertificate(e) => e.clone().into(), - Error::PeerMisbehaved(_) => AlertDescription::IllegalParameter, - _ => AlertDescription::HandshakeFailure, - }, - err, - ) - } - - pub(crate) fn send_fatal_alert( - &mut self, - desc: AlertDescription, - err: impl Into<Error>, - ) -> Error { - debug_assert!(!self.sent_fatal_alert); - let m = Message::build_alert(AlertLevel::Fatal, desc); - self.send_msg(m, self.record_layer.is_encrypting()); - self.sent_fatal_alert = true; - err.into() - } - - /// Queues a `close_notify` warning alert to be sent in the next - /// [`Connection::write_tls`] call. This informs the peer that the - /// connection is being closed. - /// - /// Does nothing if any `close_notify` or fatal alert was already sent. - /// - /// [`Connection::write_tls`]: crate::Connection::write_tls - pub fn send_close_notify(&mut self) { - if self.sent_fatal_alert { - return; - } - debug!("Sending warning alert {:?}", AlertDescription::CloseNotify); - self.sent_fatal_alert = true; - self.has_sent_close_notify = true; - self.send_warning_alert_no_log(AlertDescription::CloseNotify); - } - - pub(crate) fn eager_send_close_notify( - &mut self, - outgoing_tls: &mut [u8], - ) -> Result<usize, EncryptError> { - self.send_close_notify(); - self.check_required_size(outgoing_tls, [].into_iter())?; - Ok(self.write_fragments(outgoing_tls, [].into_iter())) - } - - fn send_warning_alert_no_log(&mut self, desc: AlertDescription) { - let m = Message::build_alert(AlertLevel::Warning, desc); - self.send_msg(m, self.record_layer.is_encrypting()); - } - - fn check_required_size<'a>( - &self, - outgoing_tls: &mut [u8], - fragments: impl Iterator<Item = OutboundPlainMessage<'a>>, - ) -> Result<(), EncryptError> { - let mut required_size = self.sendable_tls.len(); - - for m in fragments { - required_size += m.encoded_len(&self.record_layer); - } - - if required_size > outgoing_tls.len() { - return Err(EncryptError::InsufficientSize(InsufficientSizeError { - required_size, - })); - } - - Ok(()) - } - - fn write_fragments<'a>( - &mut self, - outgoing_tls: &mut [u8], - fragments: impl Iterator<Item = OutboundPlainMessage<'a>>, - ) -> usize { - let mut written = 0; - - // Any pre-existing encrypted messages in `sendable_tls` must - // be output before encrypting any of the `fragments`. - while let Some(message) = self.sendable_tls.pop() { - let len = message.len(); - outgoing_tls[written..written + len].copy_from_slice(&message); - written += len; - } - - for m in fragments { - let em = self - .record_layer - .encrypt_outgoing(m) - .encode(); - - let len = em.len(); - outgoing_tls[written..written + len].copy_from_slice(&em); - written += len; - } - - written - } - - pub(crate) fn set_max_fragment_size(&mut self, new: Option<usize>) -> Result<(), Error> { - self.message_fragmenter - .set_max_fragment_size(new) - } - - pub(crate) fn get_alpn_protocol(&self) -> Option<&[u8]> { - self.alpn_protocol - .as_ref() - .map(AsRef::as_ref) - } - - /// Returns true if the caller should call [`Connection::read_tls`] as soon - /// as possible. - /// - /// If there is pending plaintext data to read with [`Connection::reader`], - /// this returns false. If your application respects this mechanism, - /// only one full TLS message will be buffered by rustls. - /// - /// [`Connection::reader`]: crate::Connection::reader - /// [`Connection::read_tls`]: crate::Connection::read_tls - pub fn wants_read(&self) -> bool { - // We want to read more data all the time, except when we have unprocessed plaintext. - // This provides back-pressure to the TCP buffers. We also don't want to read more after - // the peer has sent us a close notification. - // - // In the handshake case we don't have readable plaintext before the handshake has - // completed, but also don't want to read if we still have sendable tls. - self.received_plaintext.is_empty() - && !self.has_received_close_notify - && (self.may_send_application_data || self.sendable_tls.is_empty()) - } - - pub(crate) fn current_io_state(&self) -> IoState { - IoState { - tls_bytes_to_write: self.sendable_tls.len(), - plaintext_bytes_to_read: self.received_plaintext.len(), - peer_has_closed: self.has_received_close_notify, - } - } - - pub(crate) fn is_quic(&self) -> bool { - self.protocol == Protocol::Quic - } - - pub(crate) fn should_update_key( - &mut self, - key_update_request: &KeyUpdateRequest, - ) -> Result<bool, Error> { - self.temper_counters - .received_key_update_request()?; - - match key_update_request { - KeyUpdateRequest::UpdateNotRequested => Ok(false), - KeyUpdateRequest::UpdateRequested => Ok(self.queued_key_update_message.is_none()), - _ => Err(self.send_fatal_alert( - AlertDescription::IllegalParameter, - InvalidMessage::InvalidKeyUpdate, - )), - } - } - - pub(crate) fn enqueue_key_update_notification(&mut self) { - let message = PlainMessage::from(Message::build_key_update_notify()); - self.queued_key_update_message = Some( - self.record_layer - .encrypt_outgoing(message.borrow_outbound()) - .encode(), - ); - } - - pub(crate) fn received_tls13_change_cipher_spec(&mut self) -> Result<(), Error> { - self.temper_counters - .received_tls13_change_cipher_spec() - } -} - -#[cfg(feature = "std")] -impl CommonState { - /// Send plaintext application data, fragmenting and - /// encrypting it as it goes out. - /// - /// If internal buffers are too small, this function will not accept - /// all the data. - pub(crate) fn buffer_plaintext( - &mut self, - payload: OutboundChunks<'_>, - sendable_plaintext: &mut ChunkVecBuffer, - ) -> usize { - self.perhaps_write_key_update(); - self.send_plain(payload, Limit::Yes, sendable_plaintext) - } - - pub(crate) fn send_early_plaintext(&mut self, data: &[u8]) -> usize { - debug_assert!(self.early_traffic); - debug_assert!(self.record_layer.is_encrypting()); - - if data.is_empty() { - // Don't send empty fragments. - return 0; - } - - self.send_appdata_encrypt(data.into(), Limit::Yes) - } - - /// Encrypt and send some plaintext `data`. `limit` controls - /// whether the per-connection buffer limits apply. - /// - /// Returns the number of bytes written from `data`: this might - /// be less than `data.len()` if buffer limits were exceeded. - fn send_plain( - &mut self, - payload: OutboundChunks<'_>, - limit: Limit, - sendable_plaintext: &mut ChunkVecBuffer, - ) -> usize { - if !self.may_send_application_data { - // If we haven't completed handshaking, buffer - // plaintext to send once we do. - let len = match limit { - Limit::Yes => sendable_plaintext.append_limited_copy(payload), - Limit::No => sendable_plaintext.append(payload.to_vec()), - }; - return len; - } - - self.send_plain_non_buffering(payload, limit) - } -} - -/// Describes which sort of handshake happened. -#[derive(Debug, PartialEq, Clone, Copy)] -pub enum HandshakeKind { - /// A full handshake. - /// - /// This is the typical TLS connection initiation process when resumption is - /// not yet unavailable, and the initial `ClientHello` was accepted by the server. - Full, - - /// A full TLS1.3 handshake, with an extra round-trip for a `HelloRetryRequest`. - /// - /// The server can respond with a `HelloRetryRequest` if the initial `ClientHello` - /// is unacceptable for several reasons, the most likely if no supported key - /// shares were offered by the client. - FullWithHelloRetryRequest, - - /// A resumed handshake. - /// - /// Resumed handshakes involve fewer round trips and less cryptography than - /// full ones, but can only happen when the peers have previously done a full - /// handshake together, and then remember data about it. - Resumed, -} - -/// Values of this structure are returned from [`Connection::process_new_packets`] -/// and tell the caller the current I/O state of the TLS connection. -/// -/// [`Connection::process_new_packets`]: crate::Connection::process_new_packets -#[derive(Debug, Eq, PartialEq)] -pub struct IoState { - tls_bytes_to_write: usize, - plaintext_bytes_to_read: usize, - peer_has_closed: bool, -} - -impl IoState { - /// How many bytes could be written by [`Connection::write_tls`] if called - /// right now. A non-zero value implies [`CommonState::wants_write`]. - /// - /// [`Connection::write_tls`]: crate::Connection::write_tls - pub fn tls_bytes_to_write(&self) -> usize { - self.tls_bytes_to_write - } - - /// How many plaintext bytes could be obtained via [`std::io::Read`] - /// without further I/O. - pub fn plaintext_bytes_to_read(&self) -> usize { - self.plaintext_bytes_to_read - } - - /// True if the peer has sent us a close_notify alert. This is - /// the TLS mechanism to securely half-close a TLS connection, - /// and signifies that the peer will not send any further data - /// on this connection. - /// - /// This is also signalled via returning `Ok(0)` from - /// [`std::io::Read`], after all the received bytes have been - /// retrieved. - pub fn peer_has_closed(&self) -> bool { - self.peer_has_closed - } -} - -pub(crate) trait State<Data>: Send + Sync { - fn handle<'m>( - self: Box<Self>, - cx: &mut Context<'_, Data>, - message: Message<'m>, - ) -> Result<Box<dyn State<Data> + 'm>, Error> - where - Self: 'm; - - fn export_keying_material( - &self, - _output: &mut [u8], - _label: &[u8], - _context: Option<&[u8]>, - ) -> Result<(), Error> { - Err(Error::HandshakeNotComplete) - } - - fn extract_secrets(&self) -> Result<PartiallyExtractedSecrets, Error> { - Err(Error::HandshakeNotComplete) - } - - fn send_key_update_request(&mut self, _common: &mut CommonState) -> Result<(), Error> { - Err(Error::HandshakeNotComplete) - } - - fn handle_decrypt_error(&self) {} - - fn into_external_state(self: Box<Self>) -> Result<Box<dyn KernelState + 'static>, Error> { - Err(Error::HandshakeNotComplete) - } - - fn into_owned(self: Box<Self>) -> Box<dyn State<Data> + 'static>; -} - -pub(crate) struct Context<'a, Data> { - pub(crate) common: &'a mut CommonState, - pub(crate) data: &'a mut Data, - /// Buffered plaintext. This is `Some` if any plaintext was written during handshake and `None` - /// otherwise. - pub(crate) sendable_plaintext: Option<&'a mut ChunkVecBuffer>, -} - -/// Side of the connection. -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum Side { - /// A client initiates the connection. - Client, - /// A server waits for a client to connect. - Server, -} - -impl Side { - pub(crate) fn peer(&self) -> Self { - match self { - Self::Client => Self::Server, - Self::Server => Self::Client, - } - } -} - -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub(crate) enum Protocol { - Tcp, - Quic, -} - -enum Limit { - #[cfg(feature = "std")] - Yes, - No, -} - -/// Tracking technically-allowed protocol actions -/// that we limit to avoid denial-of-service vectors. -struct TemperCounters { - allowed_warning_alerts: u8, - allowed_renegotiation_requests: u8, - allowed_key_update_requests: u8, - allowed_middlebox_ccs: u8, -} - -impl TemperCounters { - fn received_warning_alert(&mut self) -> Result<(), Error> { - match self.allowed_warning_alerts { - 0 => Err(PeerMisbehaved::TooManyWarningAlertsReceived.into()), - _ => { - self.allowed_warning_alerts -= 1; - Ok(()) - } - } - } - - fn received_renegotiation_request(&mut self) -> Result<(), Error> { - match self.allowed_renegotiation_requests { - 0 => Err(PeerMisbehaved::TooManyRenegotiationRequests.into()), - _ => { - self.allowed_renegotiation_requests -= 1; - Ok(()) - } - } - } - - fn received_key_update_request(&mut self) -> Result<(), Error> { - match self.allowed_key_update_requests { - 0 => Err(PeerMisbehaved::TooManyKeyUpdateRequests.into()), - _ => { - self.allowed_key_update_requests -= 1; - Ok(()) - } - } - } - - fn received_tls13_change_cipher_spec(&mut self) -> Result<(), Error> { - match self.allowed_middlebox_ccs { - 0 => Err(PeerMisbehaved::IllegalMiddleboxChangeCipherSpec.into()), - _ => { - self.allowed_middlebox_ccs -= 1; - Ok(()) - } - } - } -} - -impl Default for TemperCounters { - fn default() -> Self { - Self { - // cf. BoringSSL `kMaxWarningAlerts` - // <https://github.com/google/boringssl/blob/dec5989b793c56ad4dd32173bd2d8595ca78b398/ssl/tls_record.cc#L137-L139> - allowed_warning_alerts: 4, - - // we rebuff renegotiation requests with a `NoRenegotiation` warning alerts. - // a second request after this is fatal. - allowed_renegotiation_requests: 1, - - // cf. BoringSSL `kMaxKeyUpdates` - // <https://github.com/google/boringssl/blob/dec5989b793c56ad4dd32173bd2d8595ca78b398/ssl/tls13_both.cc#L35-L38> - allowed_key_update_requests: 32, - - // At most two CCS are allowed: one after each ClientHello (recall a second - // ClientHello happens after a HelloRetryRequest). - // - // note BoringSSL allows up to 32. - allowed_middlebox_ccs: 2, - } - } -} - -#[derive(Debug, Default)] -pub(crate) enum KxState { - #[default] - None, - Start(&'static dyn SupportedKxGroup), - Complete(&'static dyn SupportedKxGroup), -} - -impl KxState { - pub(crate) fn complete(&mut self) { - debug_assert!(matches!(self, Self::Start(_))); - if let Self::Start(group) = self { - *self = Self::Complete(*group); - } - } -} - -pub(crate) struct HandshakeFlight<'a, const TLS13: bool> { - pub(crate) transcript: &'a mut HandshakeHash, - body: Vec<u8>, -} - -impl<'a, const TLS13: bool> HandshakeFlight<'a, TLS13> { - pub(crate) fn new(transcript: &'a mut HandshakeHash) -> Self { - Self { - transcript, - body: Vec::new(), - } - } - - pub(crate) fn add(&mut self, hs: HandshakeMessagePayload<'_>) { - let start_len = self.body.len(); - hs.encode(&mut self.body); - self.transcript - .add(&self.body[start_len..]); - } - - pub(crate) fn finish(self, common: &mut CommonState) { - common.send_msg( - Message { - version: match TLS13 { - true => ProtocolVersion::TLSv1_3, - false => ProtocolVersion::TLSv1_2, - }, - payload: MessagePayload::HandshakeFlight(Payload::new(self.body)), - }, - TLS13, - ); - } -} - -#[cfg(feature = "tls12")] -pub(crate) type HandshakeFlightTls12<'a> = HandshakeFlight<'a, false>; -pub(crate) type HandshakeFlightTls13<'a> = HandshakeFlight<'a, true>; - -const DEFAULT_RECEIVED_PLAINTEXT_LIMIT: usize = 16 * 1024; -pub(crate) const DEFAULT_BUFFER_LIMIT: usize = 64 * 1024; diff --git a/vendor/rustls/src/compress.rs b/vendor/rustls/src/compress.rs deleted file mode 100644 index d34cbaff..00000000 --- a/vendor/rustls/src/compress.rs +++ /dev/null @@ -1,677 +0,0 @@ -//! Certificate compression and decompression support -//! -//! This crate supports compression and decompression everywhere -//! certificates are used, in accordance with [RFC8879][rfc8879]. -//! -//! Note that this is only supported for TLS1.3 connections. -//! -//! # Getting started -//! -//! Build this crate with the `brotli` and/or `zlib` crate features. This -//! adds dependencies on these crates. They are used by default if enabled. -//! -//! We especially recommend `brotli` as it has the widest deployment so far. -//! -//! # Custom compression/decompression implementations -//! -//! 1. Implement the [`CertCompressor`] and/or [`CertDecompressor`] traits -//! 2. Provide those to: -//! - [`ClientConfig::cert_compressors`][cc_cc] or [`ServerConfig::cert_compressors`][sc_cc]. -//! - [`ClientConfig::cert_decompressors`][cc_cd] or [`ServerConfig::cert_decompressors`][sc_cd]. -//! -//! These are used in these circumstances: -//! -//! | Peer | Client authentication | Server authentication | -//! | ---- | --------------------- | --------------------- | -//! | *Client* | [`ClientConfig::cert_compressors`][cc_cc] | [`ClientConfig::cert_decompressors`][cc_cd] | -//! | *Server* | [`ServerConfig::cert_decompressors`][sc_cd] | [`ServerConfig::cert_compressors`][sc_cc] | -//! -//! [rfc8879]: https://datatracker.ietf.org/doc/html/rfc8879 -//! [cc_cc]: crate::ClientConfig::cert_compressors -//! [sc_cc]: crate::ServerConfig::cert_compressors -//! [cc_cd]: crate::ClientConfig::cert_decompressors -//! [sc_cd]: crate::ServerConfig::cert_decompressors - -#[cfg(feature = "std")] -use alloc::collections::VecDeque; -use alloc::vec::Vec; -use core::fmt::Debug; -#[cfg(feature = "std")] -use std::sync::Mutex; - -use crate::enums::CertificateCompressionAlgorithm; -use crate::msgs::base::{Payload, PayloadU24}; -use crate::msgs::codec::Codec; -use crate::msgs::handshake::{CertificatePayloadTls13, CompressedCertificatePayload}; -use crate::sync::Arc; - -/// Returns the supported `CertDecompressor` implementations enabled -/// by crate features. -pub fn default_cert_decompressors() -> &'static [&'static dyn CertDecompressor] { - &[ - #[cfg(feature = "brotli")] - BROTLI_DECOMPRESSOR, - #[cfg(feature = "zlib")] - ZLIB_DECOMPRESSOR, - ] -} - -/// An available certificate decompression algorithm. -pub trait CertDecompressor: Debug + Send + Sync { - /// Decompress `input`, writing the result to `output`. - /// - /// `output` is sized to match the declared length of the decompressed data. - /// - /// `Err(DecompressionFailed)` should be returned if decompression produces more, or fewer - /// bytes than fit in `output`, or if the `input` is in any way malformed. - fn decompress(&self, input: &[u8], output: &mut [u8]) -> Result<(), DecompressionFailed>; - - /// Which algorithm this decompressor handles. - fn algorithm(&self) -> CertificateCompressionAlgorithm; -} - -/// Returns the supported `CertCompressor` implementations enabled -/// by crate features. -pub fn default_cert_compressors() -> &'static [&'static dyn CertCompressor] { - &[ - #[cfg(feature = "brotli")] - BROTLI_COMPRESSOR, - #[cfg(feature = "zlib")] - ZLIB_COMPRESSOR, - ] -} - -/// An available certificate compression algorithm. -pub trait CertCompressor: Debug + Send + Sync { - /// Compress `input`, returning the result. - /// - /// `input` is consumed by this function so (if the underlying implementation - /// supports it) the compression can be performed in-place. - /// - /// `level` is a hint as to how much effort to expend on the compression. - /// - /// `Err(CompressionFailed)` may be returned for any reason. - fn compress( - &self, - input: Vec<u8>, - level: CompressionLevel, - ) -> Result<Vec<u8>, CompressionFailed>; - - /// Which algorithm this compressor handles. - fn algorithm(&self) -> CertificateCompressionAlgorithm; -} - -/// A hint for how many resources to dedicate to a compression. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub enum CompressionLevel { - /// This compression is happening interactively during a handshake. - /// - /// Implementations may wish to choose a conservative compression level. - Interactive, - - /// The compression may be amortized over many connections. - /// - /// Implementations may wish to choose an aggressive compression level. - Amortized, -} - -/// A content-less error for when `CertDecompressor::decompress` fails. -#[derive(Debug)] -pub struct DecompressionFailed; - -/// A content-less error for when `CertCompressor::compress` fails. -#[derive(Debug)] -pub struct CompressionFailed; - -#[cfg(feature = "zlib")] -mod feat_zlib_rs { - use zlib_rs::c_api::Z_BEST_COMPRESSION; - use zlib_rs::{ReturnCode, deflate, inflate}; - - use super::*; - - /// A certificate decompressor for the Zlib algorithm using the `zlib-rs` crate. - pub const ZLIB_DECOMPRESSOR: &dyn CertDecompressor = &ZlibRsDecompressor; - - #[derive(Debug)] - struct ZlibRsDecompressor; - - impl CertDecompressor for ZlibRsDecompressor { - fn decompress(&self, input: &[u8], output: &mut [u8]) -> Result<(), DecompressionFailed> { - let output_len = output.len(); - match inflate::uncompress_slice(output, input, inflate::InflateConfig::default()) { - (output_filled, ReturnCode::Ok) if output_filled.len() == output_len => Ok(()), - (_, _) => Err(DecompressionFailed), - } - } - - fn algorithm(&self) -> CertificateCompressionAlgorithm { - CertificateCompressionAlgorithm::Zlib - } - } - - /// A certificate compressor for the Zlib algorithm using the `zlib-rs` crate. - pub const ZLIB_COMPRESSOR: &dyn CertCompressor = &ZlibRsCompressor; - - #[derive(Debug)] - struct ZlibRsCompressor; - - impl CertCompressor for ZlibRsCompressor { - fn compress( - &self, - input: Vec<u8>, - level: CompressionLevel, - ) -> Result<Vec<u8>, CompressionFailed> { - let mut output = alloc::vec![0u8; deflate::compress_bound(input.len())]; - let config = match level { - CompressionLevel::Interactive => deflate::DeflateConfig::default(), - CompressionLevel::Amortized => deflate::DeflateConfig::new(Z_BEST_COMPRESSION), - }; - let (output_filled, rc) = deflate::compress_slice(&mut output, &input, config); - if rc != ReturnCode::Ok { - return Err(CompressionFailed); - } - - let used = output_filled.len(); - output.truncate(used); - Ok(output) - } - - fn algorithm(&self) -> CertificateCompressionAlgorithm { - CertificateCompressionAlgorithm::Zlib - } - } -} - -#[cfg(feature = "zlib")] -pub use feat_zlib_rs::{ZLIB_COMPRESSOR, ZLIB_DECOMPRESSOR}; - -#[cfg(feature = "brotli")] -mod feat_brotli { - use std::io::{Cursor, Write}; - - use super::*; - - /// A certificate decompressor for the brotli algorithm using the `brotli` crate. - pub const BROTLI_DECOMPRESSOR: &dyn CertDecompressor = &BrotliDecompressor; - - #[derive(Debug)] - struct BrotliDecompressor; - - impl CertDecompressor for BrotliDecompressor { - fn decompress(&self, input: &[u8], output: &mut [u8]) -> Result<(), DecompressionFailed> { - let mut in_cursor = Cursor::new(input); - let mut out_cursor = Cursor::new(output); - - brotli::BrotliDecompress(&mut in_cursor, &mut out_cursor) - .map_err(|_| DecompressionFailed)?; - - if out_cursor.position() as usize != out_cursor.into_inner().len() { - return Err(DecompressionFailed); - } - - Ok(()) - } - - fn algorithm(&self) -> CertificateCompressionAlgorithm { - CertificateCompressionAlgorithm::Brotli - } - } - - /// A certificate compressor for the brotli algorithm using the `brotli` crate. - pub const BROTLI_COMPRESSOR: &dyn CertCompressor = &BrotliCompressor; - - #[derive(Debug)] - struct BrotliCompressor; - - impl CertCompressor for BrotliCompressor { - fn compress( - &self, - input: Vec<u8>, - level: CompressionLevel, - ) -> Result<Vec<u8>, CompressionFailed> { - let quality = match level { - CompressionLevel::Interactive => QUALITY_FAST, - CompressionLevel::Amortized => QUALITY_SLOW, - }; - let output = Cursor::new(Vec::with_capacity(input.len() / 2)); - let mut compressor = brotli::CompressorWriter::new(output, BUFFER_SIZE, quality, LGWIN); - compressor - .write_all(&input) - .map_err(|_| CompressionFailed)?; - Ok(compressor.into_inner().into_inner()) - } - - fn algorithm(&self) -> CertificateCompressionAlgorithm { - CertificateCompressionAlgorithm::Brotli - } - } - - /// Brotli buffer size. - /// - /// Chosen based on brotli `examples/compress.rs`. - const BUFFER_SIZE: usize = 4096; - - /// This is the default lgwin parameter, see `BrotliEncoderInitParams()` - const LGWIN: u32 = 22; - - /// Compression quality we use for interactive compressions. - /// See <https://blog.cloudflare.com/results-experimenting-brotli> for data. - const QUALITY_FAST: u32 = 4; - - /// Compression quality we use for offline compressions (the maximum). - const QUALITY_SLOW: u32 = 11; -} - -#[cfg(feature = "brotli")] -pub use feat_brotli::{BROTLI_COMPRESSOR, BROTLI_DECOMPRESSOR}; - -/// An LRU cache for compressions. -/// -/// The prospect of being able to reuse a given compression for many connections -/// means we can afford to spend more time on that compression (by passing -/// `CompressionLevel::Amortized` to the compressor). -#[derive(Debug)] -pub enum CompressionCache { - /// No caching happens, and compression happens each time using - /// `CompressionLevel::Interactive`. - Disabled, - - /// Compressions are stored in an LRU cache. - #[cfg(feature = "std")] - Enabled(CompressionCacheInner), -} - -/// Innards of an enabled CompressionCache. -/// -/// You cannot make one of these directly. Use [`CompressionCache::new`]. -#[cfg(feature = "std")] -#[derive(Debug)] -pub struct CompressionCacheInner { - /// Maximum size of underlying storage. - size: usize, - - /// LRU-order entries. - /// - /// First is least-used, last is most-used. - entries: Mutex<VecDeque<Arc<CompressionCacheEntry>>>, -} - -impl CompressionCache { - /// Make a `CompressionCache` that stores up to `size` compressed - /// certificate messages. - #[cfg(feature = "std")] - pub fn new(size: usize) -> Self { - if size == 0 { - return Self::Disabled; - } - - Self::Enabled(CompressionCacheInner { - size, - entries: Mutex::new(VecDeque::with_capacity(size)), - }) - } - - /// Return a `CompressionCacheEntry`, which is an owning - /// wrapper for a `CompressedCertificatePayload`. - /// - /// `compressor` is the compression function we have negotiated. - /// `original` is the uncompressed certificate message. - pub(crate) fn compression_for( - &self, - compressor: &dyn CertCompressor, - original: &CertificatePayloadTls13<'_>, - ) -> Result<Arc<CompressionCacheEntry>, CompressionFailed> { - match self { - Self::Disabled => Self::uncached_compression(compressor, original), - - #[cfg(feature = "std")] - Self::Enabled(_) => self.compression_for_impl(compressor, original), - } - } - - #[cfg(feature = "std")] - fn compression_for_impl( - &self, - compressor: &dyn CertCompressor, - original: &CertificatePayloadTls13<'_>, - ) -> Result<Arc<CompressionCacheEntry>, CompressionFailed> { - let (max_size, entries) = match self { - Self::Enabled(CompressionCacheInner { size, entries }) => (*size, entries), - _ => unreachable!(), - }; - - // context is a per-connection quantity, and included in the compressed data. - // it is not suitable for inclusion in the cache. - if !original.context.0.is_empty() { - return Self::uncached_compression(compressor, original); - } - - // cache probe: - let encoding = original.get_encoding(); - let algorithm = compressor.algorithm(); - - let mut cache = entries - .lock() - .map_err(|_| CompressionFailed)?; - for (i, item) in cache.iter().enumerate() { - if item.algorithm == algorithm && item.original == encoding { - // this item is now MRU - let item = cache.remove(i).unwrap(); - cache.push_back(item.clone()); - return Ok(item); - } - } - drop(cache); - - // do compression: - let uncompressed_len = encoding.len() as u32; - let compressed = compressor.compress(encoding.clone(), CompressionLevel::Amortized)?; - let new_entry = Arc::new(CompressionCacheEntry { - algorithm, - original: encoding, - compressed: CompressedCertificatePayload { - alg: algorithm, - uncompressed_len, - compressed: PayloadU24(Payload::new(compressed)), - }, - }); - - // insert into cache - let mut cache = entries - .lock() - .map_err(|_| CompressionFailed)?; - if cache.len() == max_size { - cache.pop_front(); - } - cache.push_back(new_entry.clone()); - Ok(new_entry) - } - - /// Compress `original` using `compressor` at `Interactive` level. - fn uncached_compression( - compressor: &dyn CertCompressor, - original: &CertificatePayloadTls13<'_>, - ) -> Result<Arc<CompressionCacheEntry>, CompressionFailed> { - let algorithm = compressor.algorithm(); - let encoding = original.get_encoding(); - let uncompressed_len = encoding.len() as u32; - let compressed = compressor.compress(encoding, CompressionLevel::Interactive)?; - - // this `CompressionCacheEntry` in fact never makes it into the cache, so - // `original` is left empty - Ok(Arc::new(CompressionCacheEntry { - algorithm, - original: Vec::new(), - compressed: CompressedCertificatePayload { - alg: algorithm, - uncompressed_len, - compressed: PayloadU24(Payload::new(compressed)), - }, - })) - } -} - -impl Default for CompressionCache { - fn default() -> Self { - #[cfg(feature = "std")] - { - // 4 entries allows 2 certificate chains times 2 compression algorithms - Self::new(4) - } - - #[cfg(not(feature = "std"))] - { - Self::Disabled - } - } -} - -#[cfg_attr(not(feature = "std"), allow(dead_code))] -#[derive(Debug)] -pub(crate) struct CompressionCacheEntry { - // cache key is algorithm + original: - algorithm: CertificateCompressionAlgorithm, - original: Vec<u8>, - - // cache value is compression result: - compressed: CompressedCertificatePayload<'static>, -} - -impl CompressionCacheEntry { - pub(crate) fn compressed_cert_payload(&self) -> CompressedCertificatePayload<'_> { - self.compressed.as_borrowed() - } -} - -#[cfg(all(test, any(feature = "brotli", feature = "zlib")))] -mod tests { - use std::{println, vec}; - - use super::*; - - #[test] - #[cfg(feature = "zlib")] - fn test_zlib() { - test_compressor(ZLIB_COMPRESSOR, ZLIB_DECOMPRESSOR); - } - - #[test] - #[cfg(feature = "brotli")] - fn test_brotli() { - test_compressor(BROTLI_COMPRESSOR, BROTLI_DECOMPRESSOR); - } - - fn test_compressor(comp: &dyn CertCompressor, decomp: &dyn CertDecompressor) { - assert_eq!(comp.algorithm(), decomp.algorithm()); - for sz in [16, 64, 512, 2048, 8192, 16384] { - test_trivial_pairwise(comp, decomp, sz); - } - test_decompress_wrong_len(comp, decomp); - test_decompress_garbage(decomp); - } - - fn test_trivial_pairwise( - comp: &dyn CertCompressor, - decomp: &dyn CertDecompressor, - plain_len: usize, - ) { - let original = vec![0u8; plain_len]; - - for level in [CompressionLevel::Interactive, CompressionLevel::Amortized] { - let compressed = comp - .compress(original.clone(), level) - .unwrap(); - println!( - "{:?} compressed trivial {} -> {} using {:?} level", - comp.algorithm(), - original.len(), - compressed.len(), - level - ); - let mut recovered = vec![0xffu8; plain_len]; - decomp - .decompress(&compressed, &mut recovered) - .unwrap(); - assert_eq!(original, recovered); - } - } - - fn test_decompress_wrong_len(comp: &dyn CertCompressor, decomp: &dyn CertDecompressor) { - let original = vec![0u8; 2048]; - let compressed = comp - .compress(original.clone(), CompressionLevel::Interactive) - .unwrap(); - println!("{compressed:?}"); - - // too big - let mut recovered = vec![0xffu8; original.len() + 1]; - decomp - .decompress(&compressed, &mut recovered) - .unwrap_err(); - - // too small - let mut recovered = vec![0xffu8; original.len() - 1]; - decomp - .decompress(&compressed, &mut recovered) - .unwrap_err(); - } - - fn test_decompress_garbage(decomp: &dyn CertDecompressor) { - let junk = [0u8; 1024]; - let mut recovered = vec![0u8; 512]; - decomp - .decompress(&junk, &mut recovered) - .unwrap_err(); - } - - #[test] - #[cfg(all(feature = "brotli", feature = "zlib"))] - fn test_cache_evicts_lru() { - use core::sync::atomic::{AtomicBool, Ordering}; - - use pki_types::CertificateDer; - - let cache = CompressionCache::default(); - - let cert = CertificateDer::from(vec![1]); - - let cert1 = CertificatePayloadTls13::new([&cert].into_iter(), Some(b"1")); - let cert2 = CertificatePayloadTls13::new([&cert].into_iter(), Some(b"2")); - let cert3 = CertificatePayloadTls13::new([&cert].into_iter(), Some(b"3")); - let cert4 = CertificatePayloadTls13::new([&cert].into_iter(), Some(b"4")); - - // insert zlib (1), (2), (3), (4) - - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), true), - &cert1, - ) - .unwrap(); - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), true), - &cert2, - ) - .unwrap(); - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), true), - &cert3, - ) - .unwrap(); - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), true), - &cert4, - ) - .unwrap(); - - // -- now full - - // insert brotli (1) evicts zlib (1) - cache - .compression_for( - &RequireCompress(BROTLI_COMPRESSOR, AtomicBool::default(), true), - &cert4, - ) - .unwrap(); - - // now zlib (2), (3), (4) and brotli (4) exist - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), false), - &cert2, - ) - .unwrap(); - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), false), - &cert3, - ) - .unwrap(); - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), false), - &cert4, - ) - .unwrap(); - cache - .compression_for( - &RequireCompress(BROTLI_COMPRESSOR, AtomicBool::default(), false), - &cert4, - ) - .unwrap(); - - // insert zlib (1) requires re-compression & evicts zlib (2) - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), true), - &cert1, - ) - .unwrap(); - - // now zlib (1), (3), (4) and brotli (4) exist - // query zlib (4), (3), (1) to demonstrate LRU tracks usage rather than insertion - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), false), - &cert4, - ) - .unwrap(); - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), false), - &cert3, - ) - .unwrap(); - cache - .compression_for( - &RequireCompress(ZLIB_COMPRESSOR, AtomicBool::default(), false), - &cert1, - ) - .unwrap(); - - // now brotli (4), zlib (4), (3), (1) - // insert brotli (1) evicting brotli (4) - cache - .compression_for( - &RequireCompress(BROTLI_COMPRESSOR, AtomicBool::default(), true), - &cert1, - ) - .unwrap(); - - // verify brotli (4) disappeared - cache - .compression_for( - &RequireCompress(BROTLI_COMPRESSOR, AtomicBool::default(), true), - &cert4, - ) - .unwrap(); - - #[derive(Debug)] - struct RequireCompress(&'static dyn CertCompressor, AtomicBool, bool); - - impl CertCompressor for RequireCompress { - fn compress( - &self, - input: Vec<u8>, - level: CompressionLevel, - ) -> Result<Vec<u8>, CompressionFailed> { - self.1.store(true, Ordering::SeqCst); - self.0.compress(input, level) - } - - fn algorithm(&self) -> CertificateCompressionAlgorithm { - self.0.algorithm() - } - } - - impl Drop for RequireCompress { - fn drop(&mut self) { - assert_eq!(self.1.load(Ordering::SeqCst), self.2); - } - } - } -} diff --git a/vendor/rustls/src/conn.rs b/vendor/rustls/src/conn.rs deleted file mode 100644 index 1a95079f..00000000 --- a/vendor/rustls/src/conn.rs +++ /dev/null @@ -1,1280 +0,0 @@ -use alloc::boxed::Box; -use core::fmt::Debug; -use core::mem; -use core::ops::{Deref, DerefMut, Range}; -#[cfg(feature = "std")] -use std::io; - -use kernel::KernelConnection; - -use crate::common_state::{CommonState, Context, DEFAULT_BUFFER_LIMIT, IoState, State}; -use crate::enums::{AlertDescription, ContentType, ProtocolVersion}; -use crate::error::{Error, PeerMisbehaved}; -use crate::log::trace; -use crate::msgs::deframer::DeframerIter; -use crate::msgs::deframer::buffers::{BufferProgress, DeframerVecBuffer, Delocator, Locator}; -use crate::msgs::deframer::handshake::HandshakeDeframer; -use crate::msgs::handshake::Random; -use crate::msgs::message::{InboundPlainMessage, Message, MessagePayload}; -use crate::record_layer::Decrypted; -use crate::suites::ExtractedSecrets; -use crate::vecbuf::ChunkVecBuffer; - -// pub so that it can be re-exported from the crate root -pub mod kernel; -pub(crate) mod unbuffered; - -#[cfg(feature = "std")] -mod connection { - use alloc::vec::Vec; - use core::fmt::Debug; - use core::ops::{Deref, DerefMut}; - use std::io::{self, BufRead, Read}; - - use crate::ConnectionCommon; - use crate::common_state::{CommonState, IoState}; - use crate::error::Error; - use crate::msgs::message::OutboundChunks; - use crate::suites::ExtractedSecrets; - use crate::vecbuf::ChunkVecBuffer; - - /// A client or server connection. - #[derive(Debug)] - pub enum Connection { - /// A client connection - Client(crate::client::ClientConnection), - /// A server connection - Server(crate::server::ServerConnection), - } - - impl Connection { - /// Read TLS content from `rd`. - /// - /// See [`ConnectionCommon::read_tls()`] for more information. - pub fn read_tls(&mut self, rd: &mut dyn Read) -> Result<usize, io::Error> { - match self { - Self::Client(conn) => conn.read_tls(rd), - Self::Server(conn) => conn.read_tls(rd), - } - } - - /// Writes TLS messages to `wr`. - /// - /// See [`ConnectionCommon::write_tls()`] for more information. - pub fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error> { - self.sendable_tls.write_to(wr) - } - - /// Returns an object that allows reading plaintext. - pub fn reader(&mut self) -> Reader<'_> { - match self { - Self::Client(conn) => conn.reader(), - Self::Server(conn) => conn.reader(), - } - } - - /// Returns an object that allows writing plaintext. - pub fn writer(&mut self) -> Writer<'_> { - match self { - Self::Client(conn) => Writer::new(&mut **conn), - Self::Server(conn) => Writer::new(&mut **conn), - } - } - - /// Processes any new packets read by a previous call to [`Connection::read_tls`]. - /// - /// See [`ConnectionCommon::process_new_packets()`] for more information. - pub fn process_new_packets(&mut self) -> Result<IoState, Error> { - match self { - Self::Client(conn) => conn.process_new_packets(), - Self::Server(conn) => conn.process_new_packets(), - } - } - - /// Derives key material from the agreed connection secrets. - /// - /// See [`ConnectionCommon::export_keying_material()`] for more information. - pub fn export_keying_material<T: AsMut<[u8]>>( - &self, - output: T, - label: &[u8], - context: Option<&[u8]>, - ) -> Result<T, Error> { - match self { - Self::Client(conn) => conn.export_keying_material(output, label, context), - Self::Server(conn) => conn.export_keying_material(output, label, context), - } - } - - /// This function uses `io` to complete any outstanding IO for this connection. - /// - /// See [`ConnectionCommon::complete_io()`] for more information. - pub fn complete_io<T>(&mut self, io: &mut T) -> Result<(usize, usize), io::Error> - where - Self: Sized, - T: Read + io::Write, - { - match self { - Self::Client(conn) => conn.complete_io(io), - Self::Server(conn) => conn.complete_io(io), - } - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - /// Should be used with care as it exposes secret key material. - pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { - match self { - Self::Client(client) => client.dangerous_extract_secrets(), - Self::Server(server) => server.dangerous_extract_secrets(), - } - } - - /// Sets a limit on the internal buffers - /// - /// See [`ConnectionCommon::set_buffer_limit()`] for more information. - pub fn set_buffer_limit(&mut self, limit: Option<usize>) { - match self { - Self::Client(client) => client.set_buffer_limit(limit), - Self::Server(server) => server.set_buffer_limit(limit), - } - } - - /// Sends a TLS1.3 `key_update` message to refresh a connection's keys - /// - /// See [`ConnectionCommon::refresh_traffic_keys()`] for more information. - pub fn refresh_traffic_keys(&mut self) -> Result<(), Error> { - match self { - Self::Client(client) => client.refresh_traffic_keys(), - Self::Server(server) => server.refresh_traffic_keys(), - } - } - } - - impl Deref for Connection { - type Target = CommonState; - - fn deref(&self) -> &Self::Target { - match self { - Self::Client(conn) => &conn.core.common_state, - Self::Server(conn) => &conn.core.common_state, - } - } - } - - impl DerefMut for Connection { - fn deref_mut(&mut self) -> &mut Self::Target { - match self { - Self::Client(conn) => &mut conn.core.common_state, - Self::Server(conn) => &mut conn.core.common_state, - } - } - } - - /// A structure that implements [`std::io::Read`] for reading plaintext. - pub struct Reader<'a> { - pub(super) received_plaintext: &'a mut ChunkVecBuffer, - pub(super) has_received_close_notify: bool, - pub(super) has_seen_eof: bool, - } - - impl<'a> Reader<'a> { - /// Check the connection's state if no bytes are available for reading. - fn check_no_bytes_state(&self) -> io::Result<()> { - match (self.has_received_close_notify, self.has_seen_eof) { - // cleanly closed; don't care about TCP EOF: express this as Ok(0) - (true, _) => Ok(()), - // unclean closure - (false, true) => Err(io::Error::new( - io::ErrorKind::UnexpectedEof, - UNEXPECTED_EOF_MESSAGE, - )), - // connection still going, but needs more data: signal `WouldBlock` so that - // the caller knows this - (false, false) => Err(io::ErrorKind::WouldBlock.into()), - } - } - - /// Obtain a chunk of plaintext data received from the peer over this TLS connection. - /// - /// This method consumes `self` so that it can return a slice whose lifetime is bounded by - /// the [`ConnectionCommon`] that created this `Reader`. - pub fn into_first_chunk(self) -> io::Result<&'a [u8]> { - match self.received_plaintext.chunk() { - Some(chunk) => Ok(chunk), - None => { - self.check_no_bytes_state()?; - Ok(&[]) - } - } - } - } - - impl Read for Reader<'_> { - /// Obtain plaintext data received from the peer over this TLS connection. - /// - /// If the peer closes the TLS session cleanly, this returns `Ok(0)` once all - /// the pending data has been read. No further data can be received on that - /// connection, so the underlying TCP connection should be half-closed too. - /// - /// If the peer closes the TLS session uncleanly (a TCP EOF without sending a - /// `close_notify` alert) this function returns a `std::io::Error` of type - /// `ErrorKind::UnexpectedEof` once any pending data has been read. - /// - /// Note that support for `close_notify` varies in peer TLS libraries: many do not - /// support it and uncleanly close the TCP connection (this might be - /// vulnerable to truncation attacks depending on the application protocol). - /// This means applications using rustls must both handle EOF - /// from this function, *and* unexpected EOF of the underlying TCP connection. - /// - /// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`. - /// - /// You may learn the number of bytes available at any time by inspecting - /// the return of [`Connection::process_new_packets`]. - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - let len = self.received_plaintext.read(buf)?; - if len > 0 || buf.is_empty() { - return Ok(len); - } - - self.check_no_bytes_state() - .map(|()| len) - } - - /// Obtain plaintext data received from the peer over this TLS connection. - /// - /// If the peer closes the TLS session, this returns `Ok(())` without filling - /// any more of the buffer once all the pending data has been read. No further - /// data can be received on that connection, so the underlying TCP connection - /// should be half-closed too. - /// - /// If the peer closes the TLS session uncleanly (a TCP EOF without sending a - /// `close_notify` alert) this function returns a `std::io::Error` of type - /// `ErrorKind::UnexpectedEof` once any pending data has been read. - /// - /// Note that support for `close_notify` varies in peer TLS libraries: many do not - /// support it and uncleanly close the TCP connection (this might be - /// vulnerable to truncation attacks depending on the application protocol). - /// This means applications using rustls must both handle EOF - /// from this function, *and* unexpected EOF of the underlying TCP connection. - /// - /// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`. - /// - /// You may learn the number of bytes available at any time by inspecting - /// the return of [`Connection::process_new_packets`]. - #[cfg(read_buf)] - fn read_buf(&mut self, mut cursor: core::io::BorrowedCursor<'_>) -> io::Result<()> { - let before = cursor.written(); - self.received_plaintext - .read_buf(cursor.reborrow())?; - let len = cursor.written() - before; - if len > 0 || cursor.capacity() == 0 { - return Ok(()); - } - - self.check_no_bytes_state() - } - } - - impl BufRead for Reader<'_> { - /// Obtain a chunk of plaintext data received from the peer over this TLS connection. - /// This reads the same data as [`Reader::read()`], but returns a reference instead of - /// copying the data. - /// - /// The caller should call [`Reader::consume()`] afterward to advance the buffer. - /// - /// See [`Reader::into_first_chunk()`] for a version of this function that returns a - /// buffer with a longer lifetime. - fn fill_buf(&mut self) -> io::Result<&[u8]> { - Reader { - // reborrow - received_plaintext: self.received_plaintext, - ..*self - } - .into_first_chunk() - } - - fn consume(&mut self, amt: usize) { - self.received_plaintext - .consume_first_chunk(amt) - } - } - - const UNEXPECTED_EOF_MESSAGE: &str = "peer closed connection without sending TLS close_notify: \ -https://docs.rs/rustls/latest/rustls/manual/_03_howto/index.html#unexpected-eof"; - - /// A structure that implements [`std::io::Write`] for writing plaintext. - pub struct Writer<'a> { - sink: &'a mut dyn PlaintextSink, - } - - impl<'a> Writer<'a> { - /// Create a new Writer. - /// - /// This is not an external interface. Get one of these objects - /// from [`Connection::writer`]. - pub(crate) fn new(sink: &'a mut dyn PlaintextSink) -> Self { - Writer { sink } - } - } - - impl io::Write for Writer<'_> { - /// Send the plaintext `buf` to the peer, encrypting - /// and authenticating it. Once this function succeeds - /// you should call [`Connection::write_tls`] which will output the - /// corresponding TLS records. - /// - /// This function buffers plaintext sent before the - /// TLS handshake completes, and sends it as soon - /// as it can. See [`ConnectionCommon::set_buffer_limit`] to control - /// the size of this buffer. - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.sink.write(buf) - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { - self.sink.write_vectored(bufs) - } - - fn flush(&mut self) -> io::Result<()> { - self.sink.flush() - } - } - - /// Internal trait implemented by the [`ServerConnection`]/[`ClientConnection`] - /// allowing them to be the subject of a [`Writer`]. - /// - /// [`ServerConnection`]: crate::ServerConnection - /// [`ClientConnection`]: crate::ClientConnection - pub(crate) trait PlaintextSink { - fn write(&mut self, buf: &[u8]) -> io::Result<usize>; - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>; - fn flush(&mut self) -> io::Result<()>; - } - - impl<T> PlaintextSink for ConnectionCommon<T> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let len = self - .core - .common_state - .buffer_plaintext(buf.into(), &mut self.sendable_plaintext); - self.core.maybe_refresh_traffic_keys(); - Ok(len) - } - - fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { - let payload_owner: Vec<&[u8]>; - let payload = match bufs.len() { - 0 => return Ok(0), - 1 => OutboundChunks::Single(bufs[0].deref()), - _ => { - payload_owner = bufs - .iter() - .map(|io_slice| io_slice.deref()) - .collect(); - - OutboundChunks::new(&payload_owner) - } - }; - let len = self - .core - .common_state - .buffer_plaintext(payload, &mut self.sendable_plaintext); - self.core.maybe_refresh_traffic_keys(); - Ok(len) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - } -} - -#[cfg(feature = "std")] -pub use connection::{Connection, Reader, Writer}; - -#[derive(Debug)] -pub(crate) struct ConnectionRandoms { - pub(crate) client: [u8; 32], - pub(crate) server: [u8; 32], -} - -impl ConnectionRandoms { - pub(crate) fn new(client: Random, server: Random) -> Self { - Self { - client: client.0, - server: server.0, - } - } -} - -/// Interface shared by client and server connections. -pub struct ConnectionCommon<Data> { - pub(crate) core: ConnectionCore<Data>, - deframer_buffer: DeframerVecBuffer, - sendable_plaintext: ChunkVecBuffer, -} - -impl<Data> ConnectionCommon<Data> { - /// Processes any new packets read by a previous call to - /// [`Connection::read_tls`]. - /// - /// Errors from this function relate to TLS protocol errors, and - /// are fatal to the connection. Future calls after an error will do - /// no new work and will return the same error. After an error is - /// received from [`process_new_packets`], you should not call [`read_tls`] - /// any more (it will fill up buffers to no purpose). However, you - /// may call the other methods on the connection, including `write`, - /// `send_close_notify`, and `write_tls`. Most likely you will want to - /// call `write_tls` to send any alerts queued by the error and then - /// close the underlying connection. - /// - /// Success from this function comes with some sundry state data - /// about the connection. - /// - /// [`read_tls`]: Connection::read_tls - /// [`process_new_packets`]: Connection::process_new_packets - #[inline] - pub fn process_new_packets(&mut self) -> Result<IoState, Error> { - self.core - .process_new_packets(&mut self.deframer_buffer, &mut self.sendable_plaintext) - } - - /// Derives key material from the agreed connection secrets. - /// - /// This function fills in `output` with `output.len()` bytes of key - /// material derived from the master session secret using `label` - /// and `context` for diversification. Ownership of the buffer is taken - /// by the function and returned via the Ok result to ensure no key - /// material leaks if the function fails. - /// - /// See RFC5705 for more details on what this does and is for. - /// - /// For TLS1.3 connections, this function does not use the - /// "early" exporter at any point. - /// - /// This function fails if called prior to the handshake completing; - /// check with [`CommonState::is_handshaking`] first. - /// - /// This function fails if `output.len()` is zero. - #[inline] - pub fn export_keying_material<T: AsMut<[u8]>>( - &self, - output: T, - label: &[u8], - context: Option<&[u8]>, - ) -> Result<T, Error> { - self.core - .export_keying_material(output, label, context) - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - /// Should be used with care as it exposes secret key material. - pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { - self.core.dangerous_extract_secrets() - } - - /// Sets a limit on the internal buffers used to buffer - /// unsent plaintext (prior to completing the TLS handshake) - /// and unsent TLS records. This limit acts only on application - /// data written through [`Connection::writer`]. - /// - /// By default the limit is 64KB. The limit can be set - /// at any time, even if the current buffer use is higher. - /// - /// [`None`] means no limit applies, and will mean that written - /// data is buffered without bound -- it is up to the application - /// to appropriately schedule its plaintext and TLS writes to bound - /// memory usage. - /// - /// For illustration: `Some(1)` means a limit of one byte applies: - /// [`Connection::writer`] will accept only one byte, encrypt it and - /// add a TLS header. Once this is sent via [`Connection::write_tls`], - /// another byte may be sent. - /// - /// # Internal write-direction buffering - /// rustls has two buffers whose size are bounded by this setting: - /// - /// ## Buffering of unsent plaintext data prior to handshake completion - /// - /// Calls to [`Connection::writer`] before or during the handshake - /// are buffered (up to the limit specified here). Once the - /// handshake completes this data is encrypted and the resulting - /// TLS records are added to the outgoing buffer. - /// - /// ## Buffering of outgoing TLS records - /// - /// This buffer is used to store TLS records that rustls needs to - /// send to the peer. It is used in these two circumstances: - /// - /// - by [`Connection::process_new_packets`] when a handshake or alert - /// TLS record needs to be sent. - /// - by [`Connection::writer`] post-handshake: the plaintext is - /// encrypted and the resulting TLS record is buffered. - /// - /// This buffer is emptied by [`Connection::write_tls`]. - /// - /// [`Connection::writer`]: crate::Connection::writer - /// [`Connection::write_tls`]: crate::Connection::write_tls - /// [`Connection::process_new_packets`]: crate::Connection::process_new_packets - pub fn set_buffer_limit(&mut self, limit: Option<usize>) { - self.sendable_plaintext.set_limit(limit); - self.sendable_tls.set_limit(limit); - } - - /// Sends a TLS1.3 `key_update` message to refresh a connection's keys. - /// - /// This call refreshes our encryption keys. Once the peer receives the message, - /// it refreshes _its_ encryption and decryption keys and sends a response. - /// Once we receive that response, we refresh our decryption keys to match. - /// At the end of this process, keys in both directions have been refreshed. - /// - /// Note that this process does not happen synchronously: this call just - /// arranges that the `key_update` message will be included in the next - /// `write_tls` output. - /// - /// This fails with `Error::HandshakeNotComplete` if called before the initial - /// handshake is complete, or if a version prior to TLS1.3 is negotiated. - /// - /// # Usage advice - /// Note that other implementations (including rustls) may enforce limits on - /// the number of `key_update` messages allowed on a given connection to prevent - /// denial of service. Therefore, this should be called sparingly. - /// - /// rustls implicitly and automatically refreshes traffic keys when needed - /// according to the selected cipher suite's cryptographic constraints. There - /// is therefore no need to call this manually to avoid cryptographic keys - /// "wearing out". - /// - /// The main reason to call this manually is to roll keys when it is known - /// a connection will be idle for a long period. - pub fn refresh_traffic_keys(&mut self) -> Result<(), Error> { - self.core.refresh_traffic_keys() - } -} - -#[cfg(feature = "std")] -impl<Data> ConnectionCommon<Data> { - /// Returns an object that allows reading plaintext. - pub fn reader(&mut self) -> Reader<'_> { - let common = &mut self.core.common_state; - Reader { - received_plaintext: &mut common.received_plaintext, - // Are we done? i.e., have we processed all received messages, and received a - // close_notify to indicate that no new messages will arrive? - has_received_close_notify: common.has_received_close_notify, - has_seen_eof: common.has_seen_eof, - } - } - - /// Returns an object that allows writing plaintext. - pub fn writer(&mut self) -> Writer<'_> { - Writer::new(self) - } - - /// This function uses `io` to complete any outstanding IO for - /// this connection. - /// - /// This is a convenience function which solely uses other parts - /// of the public API. - /// - /// What this means depends on the connection state: - /// - /// - If the connection [`is_handshaking`], then IO is performed until - /// the handshake is complete. - /// - Otherwise, if [`wants_write`] is true, [`write_tls`] is invoked - /// until it is all written. - /// - Otherwise, if [`wants_read`] is true, [`read_tls`] is invoked - /// once. - /// - /// The return value is the number of bytes read from and written - /// to `io`, respectively. - /// - /// This function will block if `io` blocks. - /// - /// Errors from TLS record handling (i.e., from [`process_new_packets`]) - /// are wrapped in an `io::ErrorKind::InvalidData`-kind error. - /// - /// [`is_handshaking`]: CommonState::is_handshaking - /// [`wants_read`]: CommonState::wants_read - /// [`wants_write`]: CommonState::wants_write - /// [`write_tls`]: ConnectionCommon::write_tls - /// [`read_tls`]: ConnectionCommon::read_tls - /// [`process_new_packets`]: ConnectionCommon::process_new_packets - pub fn complete_io<T>(&mut self, io: &mut T) -> Result<(usize, usize), io::Error> - where - Self: Sized, - T: io::Read + io::Write, - { - let mut eof = false; - let mut wrlen = 0; - let mut rdlen = 0; - - loop { - let until_handshaked = self.is_handshaking(); - - if !self.wants_write() && !self.wants_read() { - // We will make no further progress. - return Ok((rdlen, wrlen)); - } - - while self.wants_write() { - match self.write_tls(io)? { - 0 => { - io.flush()?; - return Ok((rdlen, wrlen)); // EOF. - } - n => wrlen += n, - } - } - io.flush()?; - - if !until_handshaked && wrlen > 0 { - return Ok((rdlen, wrlen)); - } - - while !eof && self.wants_read() { - let read_size = match self.read_tls(io) { - Ok(0) => { - eof = true; - Some(0) - } - Ok(n) => { - rdlen += n; - Some(n) - } - Err(err) if err.kind() == io::ErrorKind::Interrupted => None, // nothing to do - Err(err) => return Err(err), - }; - if read_size.is_some() { - break; - } - } - - match self.process_new_packets() { - Ok(_) => {} - Err(e) => { - // In case we have an alert to send describing this error, - // try a last-gasp write -- but don't predate the primary - // error. - let _ignored = self.write_tls(io); - let _ignored = io.flush(); - - return Err(io::Error::new(io::ErrorKind::InvalidData, e)); - } - }; - - // if we're doing IO until handshaked, and we believe we've finished handshaking, - // but process_new_packets() has queued TLS data to send, loop around again to write - // the queued messages. - if until_handshaked && !self.is_handshaking() && self.wants_write() { - continue; - } - - match (eof, until_handshaked, self.is_handshaking()) { - (_, true, false) => return Ok((rdlen, wrlen)), - (_, false, _) => return Ok((rdlen, wrlen)), - (true, true, true) => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)), - (..) => {} - } - } - } - - /// Extract the first handshake message. - /// - /// This is a shortcut to the `process_new_packets()` -> `process_msg()` -> - /// `process_handshake_messages()` path, specialized for the first handshake message. - pub(crate) fn first_handshake_message(&mut self) -> Result<Option<Message<'static>>, Error> { - let mut buffer_progress = self.core.hs_deframer.progress(); - - let res = self - .core - .deframe( - None, - self.deframer_buffer.filled_mut(), - &mut buffer_progress, - ) - .map(|opt| opt.map(|pm| Message::try_from(pm).map(|m| m.into_owned()))); - - match res? { - Some(Ok(msg)) => { - self.deframer_buffer - .discard(buffer_progress.take_discard()); - Ok(Some(msg)) - } - Some(Err(err)) => Err(self.send_fatal_alert(AlertDescription::DecodeError, err)), - None => Ok(None), - } - } - - pub(crate) fn replace_state(&mut self, new: Box<dyn State<Data>>) { - self.core.state = Ok(new); - } - - /// Read TLS content from `rd` into the internal buffer. - /// - /// Due to the internal buffering, `rd` can supply TLS messages in arbitrary-sized chunks (like - /// a socket or pipe might). - /// - /// You should call [`process_new_packets()`] each time a call to this function succeeds in order - /// to empty the incoming TLS data buffer. - /// - /// This function returns `Ok(0)` when the underlying `rd` does so. This typically happens when - /// a socket is cleanly closed, or a file is at EOF. Errors may result from the IO done through - /// `rd`; additionally, errors of `ErrorKind::Other` are emitted to signal backpressure: - /// - /// * In order to empty the incoming TLS data buffer, you should call [`process_new_packets()`] - /// each time a call to this function succeeds. - /// * In order to empty the incoming plaintext data buffer, you should empty it through - /// the [`reader()`] after the call to [`process_new_packets()`]. - /// - /// This function also returns `Ok(0)` once a `close_notify` alert has been successfully - /// received. No additional data is ever read in this state. - /// - /// [`process_new_packets()`]: ConnectionCommon::process_new_packets - /// [`reader()`]: ConnectionCommon::reader - pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result<usize, io::Error> { - if self.received_plaintext.is_full() { - return Err(io::Error::new( - io::ErrorKind::Other, - "received plaintext buffer full", - )); - } - - if self.has_received_close_notify { - return Ok(0); - } - - let res = self - .deframer_buffer - .read(rd, self.core.hs_deframer.is_active()); - if let Ok(0) = res { - self.has_seen_eof = true; - } - res - } - - /// Writes TLS messages to `wr`. - /// - /// On success, this function returns `Ok(n)` where `n` is a number of bytes written to `wr` - /// (after encoding and encryption). - /// - /// After this function returns, the connection buffer may not yet be fully flushed. The - /// [`CommonState::wants_write`] function can be used to check if the output buffer is empty. - pub fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error> { - self.sendable_tls.write_to(wr) - } -} - -impl<'a, Data> From<&'a mut ConnectionCommon<Data>> for Context<'a, Data> { - fn from(conn: &'a mut ConnectionCommon<Data>) -> Self { - Self { - common: &mut conn.core.common_state, - data: &mut conn.core.data, - sendable_plaintext: Some(&mut conn.sendable_plaintext), - } - } -} - -impl<T> Deref for ConnectionCommon<T> { - type Target = CommonState; - - fn deref(&self) -> &Self::Target { - &self.core.common_state - } -} - -impl<T> DerefMut for ConnectionCommon<T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.core.common_state - } -} - -impl<Data> From<ConnectionCore<Data>> for ConnectionCommon<Data> { - fn from(core: ConnectionCore<Data>) -> Self { - Self { - core, - deframer_buffer: DeframerVecBuffer::default(), - sendable_plaintext: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)), - } - } -} - -/// Interface shared by unbuffered client and server connections. -pub struct UnbufferedConnectionCommon<Data> { - pub(crate) core: ConnectionCore<Data>, - wants_write: bool, - emitted_peer_closed_state: bool, -} - -impl<Data> From<ConnectionCore<Data>> for UnbufferedConnectionCommon<Data> { - fn from(core: ConnectionCore<Data>) -> Self { - Self { - core, - wants_write: false, - emitted_peer_closed_state: false, - } - } -} - -impl<Data> UnbufferedConnectionCommon<Data> { - /// Extract secrets, so they can be used when configuring kTLS, for example. - /// Should be used with care as it exposes secret key material. - pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { - self.core.dangerous_extract_secrets() - } -} - -impl<T> Deref for UnbufferedConnectionCommon<T> { - type Target = CommonState; - - fn deref(&self) -> &Self::Target { - &self.core.common_state - } -} - -pub(crate) struct ConnectionCore<Data> { - pub(crate) state: Result<Box<dyn State<Data>>, Error>, - pub(crate) data: Data, - pub(crate) common_state: CommonState, - pub(crate) hs_deframer: HandshakeDeframer, - - /// We limit consecutive empty fragments to avoid a route for the peer to send - /// us significant but fruitless traffic. - seen_consecutive_empty_fragments: u8, -} - -impl<Data> ConnectionCore<Data> { - pub(crate) fn new(state: Box<dyn State<Data>>, data: Data, common_state: CommonState) -> Self { - Self { - state: Ok(state), - data, - common_state, - hs_deframer: HandshakeDeframer::default(), - seen_consecutive_empty_fragments: 0, - } - } - - pub(crate) fn process_new_packets( - &mut self, - deframer_buffer: &mut DeframerVecBuffer, - sendable_plaintext: &mut ChunkVecBuffer, - ) -> Result<IoState, Error> { - let mut state = match mem::replace(&mut self.state, Err(Error::HandshakeNotComplete)) { - Ok(state) => state, - Err(e) => { - self.state = Err(e.clone()); - return Err(e); - } - }; - - let mut buffer_progress = self.hs_deframer.progress(); - - loop { - let res = self.deframe( - Some(&*state), - deframer_buffer.filled_mut(), - &mut buffer_progress, - ); - - let opt_msg = match res { - Ok(opt_msg) => opt_msg, - Err(e) => { - self.state = Err(e.clone()); - deframer_buffer.discard(buffer_progress.take_discard()); - return Err(e); - } - }; - - let Some(msg) = opt_msg else { - break; - }; - - match self.process_msg(msg, state, Some(sendable_plaintext)) { - Ok(new) => state = new, - Err(e) => { - self.state = Err(e.clone()); - deframer_buffer.discard(buffer_progress.take_discard()); - return Err(e); - } - } - - if self - .common_state - .has_received_close_notify - { - // "Any data received after a closure alert has been received MUST be ignored." - // -- <https://datatracker.ietf.org/doc/html/rfc8446#section-6.1> - // This is data that has already been accepted in `read_tls`. - buffer_progress.add_discard(deframer_buffer.filled().len()); - break; - } - - deframer_buffer.discard(buffer_progress.take_discard()); - } - - deframer_buffer.discard(buffer_progress.take_discard()); - self.state = Ok(state); - Ok(self.common_state.current_io_state()) - } - - /// Pull a message out of the deframer and send any messages that need to be sent as a result. - fn deframe<'b>( - &mut self, - state: Option<&dyn State<Data>>, - buffer: &'b mut [u8], - buffer_progress: &mut BufferProgress, - ) -> Result<Option<InboundPlainMessage<'b>>, Error> { - // before processing any more of `buffer`, return any extant messages from `hs_deframer` - if self.hs_deframer.has_message_ready() { - Ok(self.take_handshake_message(buffer, buffer_progress)) - } else { - self.process_more_input(state, buffer, buffer_progress) - } - } - - fn take_handshake_message<'b>( - &mut self, - buffer: &'b mut [u8], - buffer_progress: &mut BufferProgress, - ) -> Option<InboundPlainMessage<'b>> { - self.hs_deframer - .iter(buffer) - .next() - .map(|(message, discard)| { - buffer_progress.add_discard(discard); - message - }) - } - - fn process_more_input<'b>( - &mut self, - state: Option<&dyn State<Data>>, - buffer: &'b mut [u8], - buffer_progress: &mut BufferProgress, - ) -> Result<Option<InboundPlainMessage<'b>>, Error> { - let version_is_tls13 = matches!( - self.common_state.negotiated_version, - Some(ProtocolVersion::TLSv1_3) - ); - - let locator = Locator::new(buffer); - - loop { - let mut iter = DeframerIter::new(&mut buffer[buffer_progress.processed()..]); - - let (message, processed) = loop { - let message = match iter.next().transpose() { - Ok(Some(message)) => message, - Ok(None) => return Ok(None), - Err(err) => return Err(self.handle_deframe_error(err, state)), - }; - - let allowed_plaintext = match message.typ { - // CCS messages are always plaintext. - ContentType::ChangeCipherSpec => true, - // Alerts are allowed to be plaintext if-and-only-if: - // * The negotiated protocol version is TLS 1.3. - In TLS 1.2 it is unambiguous when - // keying changes based on the CCS message. Only TLS 1.3 requires these heuristics. - // * We have not yet decrypted any messages from the peer - if we have we don't - // expect any plaintext. - // * The payload size is indicative of a plaintext alert message. - ContentType::Alert - if version_is_tls13 - && !self - .common_state - .record_layer - .has_decrypted() - && message.payload.len() <= 2 => - { - true - } - // In other circumstances, we expect all messages to be encrypted. - _ => false, - }; - - if allowed_plaintext && !self.hs_deframer.is_active() { - break (message.into_plain_message(), iter.bytes_consumed()); - } - - let message = match self - .common_state - .record_layer - .decrypt_incoming(message) - { - // failed decryption during trial decryption is not allowed to be - // interleaved with partial handshake data. - Ok(None) if !self.hs_deframer.is_aligned() => { - return Err( - PeerMisbehaved::RejectedEarlyDataInterleavedWithHandshakeMessage.into(), - ); - } - - // failed decryption during trial decryption. - Ok(None) => continue, - - Ok(Some(message)) => message, - - Err(err) => return Err(self.handle_deframe_error(err, state)), - }; - - let Decrypted { - want_close_before_decrypt, - plaintext, - } = message; - - if want_close_before_decrypt { - self.common_state.send_close_notify(); - } - - break (plaintext, iter.bytes_consumed()); - }; - - if !self.hs_deframer.is_aligned() && message.typ != ContentType::Handshake { - // "Handshake messages MUST NOT be interleaved with other record - // types. That is, if a handshake message is split over two or more - // records, there MUST NOT be any other records between them." - // https://www.rfc-editor.org/rfc/rfc8446#section-5.1 - return Err(PeerMisbehaved::MessageInterleavedWithHandshakeMessage.into()); - } - - match message.payload.len() { - 0 => { - if self.seen_consecutive_empty_fragments - == ALLOWED_CONSECUTIVE_EMPTY_FRAGMENTS_MAX - { - return Err(PeerMisbehaved::TooManyEmptyFragments.into()); - } - self.seen_consecutive_empty_fragments += 1; - } - _ => { - self.seen_consecutive_empty_fragments = 0; - } - }; - - buffer_progress.add_processed(processed); - - // do an end-run around the borrow checker, converting `message` (containing - // a borrowed slice) to an unborrowed one (containing a `Range` into the - // same buffer). the reborrow happens inside the branch that returns the - // message. - // - // is fixed by -Zpolonius - // https://github.com/rust-lang/rfcs/blob/master/text/2094-nll.md#problem-case-3-conditional-control-flow-across-functions - let unborrowed = InboundUnborrowedMessage::unborrow(&locator, message); - - if unborrowed.typ != ContentType::Handshake { - let message = unborrowed.reborrow(&Delocator::new(buffer)); - buffer_progress.add_discard(processed); - return Ok(Some(message)); - } - - let message = unborrowed.reborrow(&Delocator::new(buffer)); - self.hs_deframer - .input_message(message, &locator, buffer_progress.processed()); - self.hs_deframer.coalesce(buffer)?; - - self.common_state.aligned_handshake = self.hs_deframer.is_aligned(); - - if self.hs_deframer.has_message_ready() { - // trial decryption finishes with the first handshake message after it started. - self.common_state - .record_layer - .finish_trial_decryption(); - - return Ok(self.take_handshake_message(buffer, buffer_progress)); - } - } - } - - fn handle_deframe_error(&mut self, error: Error, state: Option<&dyn State<Data>>) -> Error { - match error { - error @ Error::InvalidMessage(_) => { - if self.common_state.is_quic() { - self.common_state.quic.alert = Some(AlertDescription::DecodeError); - error - } else { - self.common_state - .send_fatal_alert(AlertDescription::DecodeError, error) - } - } - Error::PeerSentOversizedRecord => self - .common_state - .send_fatal_alert(AlertDescription::RecordOverflow, error), - Error::DecryptError => { - if let Some(state) = state { - state.handle_decrypt_error(); - } - self.common_state - .send_fatal_alert(AlertDescription::BadRecordMac, error) - } - - error => error, - } - } - - fn process_msg( - &mut self, - msg: InboundPlainMessage<'_>, - state: Box<dyn State<Data>>, - sendable_plaintext: Option<&mut ChunkVecBuffer>, - ) -> Result<Box<dyn State<Data>>, Error> { - // Drop CCS messages during handshake in TLS1.3 - if msg.typ == ContentType::ChangeCipherSpec - && !self - .common_state - .may_receive_application_data - && self.common_state.is_tls13() - { - if !msg.is_valid_ccs() { - // "An implementation which receives any other change_cipher_spec value or - // which receives a protected change_cipher_spec record MUST abort the - // handshake with an "unexpected_message" alert." - return Err(self.common_state.send_fatal_alert( - AlertDescription::UnexpectedMessage, - PeerMisbehaved::IllegalMiddleboxChangeCipherSpec, - )); - } - - self.common_state - .received_tls13_change_cipher_spec()?; - trace!("Dropping CCS"); - return Ok(state); - } - - // Now we can fully parse the message payload. - let msg = match Message::try_from(msg) { - Ok(msg) => msg, - Err(err) => { - return Err(self - .common_state - .send_fatal_alert(AlertDescription::from(err), err)); - } - }; - - // For alerts, we have separate logic. - if let MessagePayload::Alert(alert) = &msg.payload { - self.common_state.process_alert(alert)?; - return Ok(state); - } - - self.common_state - .process_main_protocol(msg, state, &mut self.data, sendable_plaintext) - } - - pub(crate) fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { - Ok(self - .dangerous_into_kernel_connection()? - .0) - } - - pub(crate) fn dangerous_into_kernel_connection( - self, - ) -> Result<(ExtractedSecrets, KernelConnection<Data>), Error> { - if !self - .common_state - .enable_secret_extraction - { - return Err(Error::General("Secret extraction is disabled".into())); - } - - if self.common_state.is_handshaking() { - return Err(Error::HandshakeNotComplete); - } - - if !self - .common_state - .sendable_tls - .is_empty() - { - return Err(Error::General( - "cannot convert into an KernelConnection while there are still buffered TLS records to send" - .into() - )); - } - - let state = self.state?; - - let record_layer = &self.common_state.record_layer; - let secrets = state.extract_secrets()?; - let secrets = ExtractedSecrets { - tx: (record_layer.write_seq(), secrets.tx), - rx: (record_layer.read_seq(), secrets.rx), - }; - - let state = state.into_external_state()?; - let external = KernelConnection::new(state, self.common_state)?; - - Ok((secrets, external)) - } - - pub(crate) fn export_keying_material<T: AsMut<[u8]>>( - &self, - mut output: T, - label: &[u8], - context: Option<&[u8]>, - ) -> Result<T, Error> { - if output.as_mut().is_empty() { - return Err(Error::General( - "export_keying_material with zero-length output".into(), - )); - } - - match self.state.as_ref() { - Ok(st) => st - .export_keying_material(output.as_mut(), label, context) - .map(|_| output), - Err(e) => Err(e.clone()), - } - } - - /// Trigger a `refresh_traffic_keys` if required by `CommonState`. - fn maybe_refresh_traffic_keys(&mut self) { - if mem::take( - &mut self - .common_state - .refresh_traffic_keys_pending, - ) { - let _ = self.refresh_traffic_keys(); - } - } - - fn refresh_traffic_keys(&mut self) -> Result<(), Error> { - match &mut self.state { - Ok(st) => st.send_key_update_request(&mut self.common_state), - Err(e) => Err(e.clone()), - } - } -} - -/// Data specific to the peer's side (client or server). -pub trait SideData: Debug {} - -/// An InboundPlainMessage which does not borrow its payload, but -/// references a range that can later be borrowed. -struct InboundUnborrowedMessage { - typ: ContentType, - version: ProtocolVersion, - bounds: Range<usize>, -} - -impl InboundUnborrowedMessage { - fn unborrow(locator: &Locator, msg: InboundPlainMessage<'_>) -> Self { - Self { - typ: msg.typ, - version: msg.version, - bounds: locator.locate(msg.payload), - } - } - - fn reborrow<'b>(self, delocator: &Delocator<'b>) -> InboundPlainMessage<'b> { - InboundPlainMessage { - typ: self.typ, - version: self.version, - payload: delocator.slice_from_range(&self.bounds), - } - } -} - -/// cf. BoringSSL's `kMaxEmptyRecords` -/// <https://github.com/google/boringssl/blob/dec5989b793c56ad4dd32173bd2d8595ca78b398/ssl/tls_record.cc#L124-L128> -const ALLOWED_CONSECUTIVE_EMPTY_FRAGMENTS_MAX: u8 = 32; diff --git a/vendor/rustls/src/conn/kernel.rs b/vendor/rustls/src/conn/kernel.rs deleted file mode 100644 index b90fad39..00000000 --- a/vendor/rustls/src/conn/kernel.rs +++ /dev/null @@ -1,268 +0,0 @@ -//! Kernel connection API. -//! -//! This module gives you the bare minimum you need to implement a TLS connection -//! that does its own encryption and decryption while still using rustls to manage -//! connection secrets and session tickets. It is intended for use cases like kTLS -//! where you want to use rustls to establish the connection but want to use -//! something else to do the encryption/decryption after that. -//! -//! There are only two things that [`KernelConnection`] is able to do: -//! 1. Compute new traffic secrets when a key update occurs. -//! 2. Save received session tickets sent by a server peer. -//! -//! That's it. Everything else you will need to implement yourself. -//! -//! # Entry Point -//! The entry points into this API are -//! [`UnbufferedClientConnection::dangerous_into_kernel_connection`][client-into] -//! and -//! [`UnbufferedServerConnection::dangerous_into_kernel_connection`][server-into]. -//! -//! In order to actually create an [`KernelConnection`] all of the following -//! must be true: -//! - the connection must have completed its handshake, -//! - the connection must have no buffered TLS data waiting to be sent, and, -//! - the config used to create the connection must have `enable_extract_secrets` -//! set to true. -//! -//! This sounds fairly complicated to achieve at first glance. However, if you -//! drive an unbuffered connection through the handshake until it returns -//! [`WriteTraffic`] then it will end up in an appropriate state to convert -//! into an external connection. -//! -//! [client-into]: crate::client::UnbufferedClientConnection::dangerous_into_kernel_connection -//! [server-into]: crate::server::UnbufferedServerConnection::dangerous_into_kernel_connection -//! [`WriteTraffic`]: crate::unbuffered::ConnectionState::WriteTraffic -//! -//! # Cipher Suite Confidentiality Limits -//! Some cipher suites (notably AES-GCM) have vulnerabilities where they are no -//! longer secure once a certain number of messages have been sent. Normally, -//! rustls tracks how many messages have been written or read and will -//! automatically either refresh keys or emit an error when approaching the -//! confidentiality limit of the cipher suite. -//! -//! [`KernelConnection`] has no way to track this. It is the responsibility -//! of the user of the API to track approximately how many messages have been -//! sent and either refresh the traffic keys or abort the connection before the -//! confidentiality limit is reached. -//! -//! You can find the current confidentiality limit by looking at -//! [`CipherSuiteCommon::confidentiality_limit`] for the cipher suite selected -//! by the connection. -//! -//! [`CipherSuiteCommon::confidentiality_limit`]: crate::CipherSuiteCommon::confidentiality_limit -//! [`KernelConnection`]: crate::kernel::KernelConnection - -use alloc::boxed::Box; -use core::marker::PhantomData; - -use crate::client::ClientConnectionData; -use crate::common_state::Protocol; -use crate::msgs::codec::Codec; -use crate::msgs::handshake::{CertificateChain, NewSessionTicketPayloadTls13}; -use crate::quic::Quic; -use crate::{CommonState, ConnectionTrafficSecrets, Error, ProtocolVersion, SupportedCipherSuite}; - -/// A kernel connection. -/// -/// This does not directly wrap a kernel connection, rather it gives you the -/// minimal interfaces you need to implement a well-behaved TLS connection on -/// top of kTLS. -/// -/// See the [`crate::kernel`] module docs for more details. -pub struct KernelConnection<Data> { - state: Box<dyn KernelState>, - - peer_certificates: Option<CertificateChain<'static>>, - quic: Quic, - - negotiated_version: ProtocolVersion, - protocol: Protocol, - suite: SupportedCipherSuite, - - _data: PhantomData<Data>, -} - -impl<Data> KernelConnection<Data> { - pub(crate) fn new(state: Box<dyn KernelState>, common: CommonState) -> Result<Self, Error> { - Ok(Self { - state, - - peer_certificates: common.peer_certificates, - quic: common.quic, - negotiated_version: common - .negotiated_version - .ok_or(Error::HandshakeNotComplete)?, - protocol: common.protocol, - suite: common - .suite - .ok_or(Error::HandshakeNotComplete)?, - - _data: PhantomData, - }) - } - - /// Retrieves the ciphersuite agreed with the peer. - pub fn negotiated_cipher_suite(&self) -> SupportedCipherSuite { - self.suite - } - - /// Retrieves the protocol version agreed with the peer. - pub fn protocol_version(&self) -> ProtocolVersion { - self.negotiated_version - } - - /// Update the traffic secret used for encrypting messages sent to the peer. - /// - /// Returns the new traffic secret and initial sequence number to use. - /// - /// In order to use the new secret you should send a TLS 1.3 key update to - /// the peer and then use the new traffic secrets to encrypt any future - /// messages. - /// - /// Note that it is only possible to update the traffic secrets on a TLS 1.3 - /// connection. Attempting to do so on a non-TLS 1.3 connection will result - /// in an error. - pub fn update_tx_secret(&mut self) -> Result<(u64, ConnectionTrafficSecrets), Error> { - // The sequence number always starts at 0 after a key update. - self.state - .update_secrets(Direction::Transmit) - .map(|secret| (0, secret)) - } - - /// Update the traffic secret used for decrypting messages received from the - /// peer. - /// - /// Returns the new traffic secret and initial sequence number to use. - /// - /// You should call this method once you receive a TLS 1.3 key update message - /// from the peer. - /// - /// Note that it is only possible to update the traffic secrets on a TLS 1.3 - /// connection. Attempting to do so on a non-TLS 1.3 connection will result - /// in an error. - pub fn update_rx_secret(&mut self) -> Result<(u64, ConnectionTrafficSecrets), Error> { - // The sequence number always starts at 0 after a key update. - self.state - .update_secrets(Direction::Receive) - .map(|secret| (0, secret)) - } -} - -impl KernelConnection<ClientConnectionData> { - /// Handle a `new_session_ticket` message from the peer. - /// - /// This will register the session ticket within with rustls so that it can - /// be used to establish future TLS connections. - /// - /// # Getting the right payload - /// - /// This method expects to be passed the inner payload of the handshake - /// message. This means that you will need to parse the header of the - /// handshake message in order to determine the correct payload to pass in. - /// The message format is described in [RFC 8446 section 4][0]. `payload` - /// should not include the `msg_type` or `length` fields. - /// - /// Code to parse out the payload should look something like this - /// ```no_run - /// use rustls::{ContentType, HandshakeType}; - /// use rustls::kernel::KernelConnection; - /// use rustls::client::ClientConnectionData; - /// - /// # fn doctest(conn: &mut KernelConnection<ClientConnectionData>, typ: ContentType, message: &[u8]) -> Result<(), rustls::Error> { - /// let conn: &mut KernelConnection<ClientConnectionData> = // ... - /// # conn; - /// let typ: ContentType = // ... - /// # typ; - /// let mut message: &[u8] = // ... - /// # message; - /// - /// // Processing for other messages not included in this example - /// assert_eq!(typ, ContentType::Handshake); - /// - /// // There may be multiple handshake payloads within a single handshake message. - /// while !message.is_empty() { - /// let (typ, len, rest) = match message { - /// &[typ, a, b, c, ref rest @ ..] => ( - /// HandshakeType::from(typ), - /// u32::from_be_bytes([0, a, b, c]) as usize, - /// rest - /// ), - /// _ => panic!("error handling not included in this example") - /// }; - /// - /// // Processing for other messages not included in this example. - /// assert_eq!(typ, HandshakeType::NewSessionTicket); - /// assert!(rest.len() >= len, "invalid handshake message"); - /// - /// let (payload, rest) = rest.split_at(len); - /// message = rest; - /// - /// conn.handle_new_session_ticket(payload)?; - /// } - /// # Ok(()) - /// # } - /// ``` - /// - /// # Errors - /// This method will return an error if: - /// - This connection is not a TLS 1.3 connection (in TLS 1.2 session tickets - /// are sent as part of the handshake). - /// - The provided payload is not a valid `new_session_ticket` payload or has - /// extra unparsed trailing data. - /// - An error occurs while the connection updates the session ticket store. - /// - /// [0]: https://datatracker.ietf.org/doc/html/rfc8446#section-4 - pub fn handle_new_session_ticket(&mut self, payload: &[u8]) -> Result<(), Error> { - // We want to return a more specific error here first if this is called - // on a non-TLS 1.3 connection since a parsing error isn't the real issue - // here. - if self.protocol_version() != ProtocolVersion::TLSv1_3 { - return Err(Error::General( - "TLS 1.2 session tickets may not be sent once the handshake has completed".into(), - )); - } - - let nst = NewSessionTicketPayloadTls13::read_bytes(payload)?; - let mut cx = KernelContext { - peer_certificates: self.peer_certificates.as_ref(), - protocol: self.protocol, - quic: &self.quic, - }; - self.state - .handle_new_session_ticket(&mut cx, &nst) - } -} - -pub(crate) trait KernelState: Send + Sync { - /// Update the traffic secret for the specified direction on the connection. - fn update_secrets(&mut self, dir: Direction) -> Result<ConnectionTrafficSecrets, Error>; - - /// Handle a new session ticket. - /// - /// This will only ever be called for client connections, as [`KernelConnection`] - /// only exposes the relevant API for client connections. - fn handle_new_session_ticket( - &mut self, - cx: &mut KernelContext<'_>, - message: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error>; -} - -pub(crate) struct KernelContext<'a> { - pub(crate) peer_certificates: Option<&'a CertificateChain<'static>>, - pub(crate) protocol: Protocol, - pub(crate) quic: &'a Quic, -} - -impl KernelContext<'_> { - pub(crate) fn is_quic(&self) -> bool { - self.protocol == Protocol::Quic - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub(crate) enum Direction { - Transmit, - Receive, -} diff --git a/vendor/rustls/src/conn/unbuffered.rs b/vendor/rustls/src/conn/unbuffered.rs deleted file mode 100644 index 84fe3f09..00000000 --- a/vendor/rustls/src/conn/unbuffered.rs +++ /dev/null @@ -1,613 +0,0 @@ -//! Unbuffered connection API - -use alloc::vec::Vec; -use core::num::NonZeroUsize; -use core::{fmt, mem}; -#[cfg(feature = "std")] -use std::error::Error as StdError; - -use super::UnbufferedConnectionCommon; -use crate::Error; -use crate::client::ClientConnectionData; -use crate::msgs::deframer::buffers::DeframerSliceBuffer; -use crate::server::ServerConnectionData; - -impl UnbufferedConnectionCommon<ClientConnectionData> { - /// Processes the TLS records in `incoming_tls` buffer until a new [`UnbufferedStatus`] is - /// reached. - pub fn process_tls_records<'c, 'i>( - &'c mut self, - incoming_tls: &'i mut [u8], - ) -> UnbufferedStatus<'c, 'i, ClientConnectionData> { - self.process_tls_records_common(incoming_tls, |_| false, |_, _| unreachable!()) - } -} - -impl UnbufferedConnectionCommon<ServerConnectionData> { - /// Processes the TLS records in `incoming_tls` buffer until a new [`UnbufferedStatus`] is - /// reached. - pub fn process_tls_records<'c, 'i>( - &'c mut self, - incoming_tls: &'i mut [u8], - ) -> UnbufferedStatus<'c, 'i, ServerConnectionData> { - self.process_tls_records_common( - incoming_tls, - |conn| conn.peek_early_data().is_some(), - |conn, incoming_tls| ReadEarlyData::new(conn, incoming_tls).into(), - ) - } -} - -impl<Data> UnbufferedConnectionCommon<Data> { - fn process_tls_records_common<'c, 'i>( - &'c mut self, - incoming_tls: &'i mut [u8], - mut early_data_available: impl FnMut(&mut Self) -> bool, - early_data_state: impl FnOnce(&'c mut Self, &'i mut [u8]) -> ConnectionState<'c, 'i, Data>, - ) -> UnbufferedStatus<'c, 'i, Data> { - let mut buffer = DeframerSliceBuffer::new(incoming_tls); - let mut buffer_progress = self.core.hs_deframer.progress(); - - let (discard, state) = loop { - if early_data_available(self) { - break ( - buffer.pending_discard(), - early_data_state(self, incoming_tls), - ); - } - - if !self - .core - .common_state - .received_plaintext - .is_empty() - { - break ( - buffer.pending_discard(), - ReadTraffic::new(self, incoming_tls).into(), - ); - } - - if let Some(chunk) = self - .core - .common_state - .sendable_tls - .pop() - { - break ( - buffer.pending_discard(), - EncodeTlsData::new(self, chunk).into(), - ); - } - - let deframer_output = - match self - .core - .deframe(None, buffer.filled_mut(), &mut buffer_progress) - { - Err(err) => { - buffer.queue_discard(buffer_progress.take_discard()); - return UnbufferedStatus { - discard: buffer.pending_discard(), - state: Err(err), - }; - } - Ok(r) => r, - }; - - if let Some(msg) = deframer_output { - let mut state = - match mem::replace(&mut self.core.state, Err(Error::HandshakeNotComplete)) { - Ok(state) => state, - Err(e) => { - buffer.queue_discard(buffer_progress.take_discard()); - self.core.state = Err(e.clone()); - return UnbufferedStatus { - discard: buffer.pending_discard(), - state: Err(e), - }; - } - }; - - match self.core.process_msg(msg, state, None) { - Ok(new) => state = new, - - Err(e) => { - buffer.queue_discard(buffer_progress.take_discard()); - self.core.state = Err(e.clone()); - return UnbufferedStatus { - discard: buffer.pending_discard(), - state: Err(e), - }; - } - } - - buffer.queue_discard(buffer_progress.take_discard()); - - self.core.state = Ok(state); - } else if self.wants_write { - break ( - buffer.pending_discard(), - TransmitTlsData { conn: self }.into(), - ); - } else if self - .core - .common_state - .has_received_close_notify - && !self.emitted_peer_closed_state - { - self.emitted_peer_closed_state = true; - break (buffer.pending_discard(), ConnectionState::PeerClosed); - } else if self - .core - .common_state - .has_received_close_notify - && self - .core - .common_state - .has_sent_close_notify - { - break (buffer.pending_discard(), ConnectionState::Closed); - } else if self - .core - .common_state - .may_send_application_data - { - break ( - buffer.pending_discard(), - ConnectionState::WriteTraffic(WriteTraffic { conn: self }), - ); - } else { - break (buffer.pending_discard(), ConnectionState::BlockedHandshake); - } - }; - - UnbufferedStatus { - discard, - state: Ok(state), - } - } -} - -/// The current status of the `UnbufferedConnection*` -#[must_use] -#[derive(Debug)] -pub struct UnbufferedStatus<'c, 'i, Data> { - /// Number of bytes to discard - /// - /// After the `state` field of this object has been handled, `discard` bytes must be - /// removed from the *front* of the `incoming_tls` buffer that was passed to - /// the [`UnbufferedConnectionCommon::process_tls_records`] call that returned this object. - /// - /// This discard operation MUST happen *before* - /// [`UnbufferedConnectionCommon::process_tls_records`] is called again. - pub discard: usize, - - /// The current state of the handshake process - /// - /// This value MUST be handled prior to calling - /// [`UnbufferedConnectionCommon::process_tls_records`] again. See the documentation on the - /// variants of [`ConnectionState`] for more details. - pub state: Result<ConnectionState<'c, 'i, Data>, Error>, -} - -/// The state of the [`UnbufferedConnectionCommon`] object -#[non_exhaustive] // for forwards compatibility; to support caller-side certificate verification -pub enum ConnectionState<'c, 'i, Data> { - /// One, or more, application data records are available - /// - /// See [`ReadTraffic`] for more details on how to use the enclosed object to access - /// the received data. - ReadTraffic(ReadTraffic<'c, 'i, Data>), - - /// Connection has been cleanly closed by the peer. - /// - /// This state is encountered at most once by each connection -- it is - /// "edge" triggered, rather than "level" triggered. - /// - /// It delimits the data received from the peer, meaning you can be sure you - /// have received all the data the peer sent. - /// - /// No further application data will be received from the peer, so no further - /// `ReadTraffic` states will be produced. - /// - /// However, it is possible to _send_ further application data via `WriteTraffic` - /// states, or close the connection cleanly by calling - /// [`WriteTraffic::queue_close_notify()`]. - PeerClosed, - - /// Connection has been cleanly closed by both us and the peer. - /// - /// This is a terminal state. No other states will be produced for this - /// connection. - Closed, - - /// One, or more, early (RTT-0) data records are available - ReadEarlyData(ReadEarlyData<'c, 'i, Data>), - - /// A Handshake record is ready for encoding - /// - /// Call [`EncodeTlsData::encode`] on the enclosed object, providing an `outgoing_tls` - /// buffer to store the encoding - EncodeTlsData(EncodeTlsData<'c, Data>), - - /// Previously encoded handshake records need to be transmitted - /// - /// Transmit the contents of the `outgoing_tls` buffer that was passed to previous - /// [`EncodeTlsData::encode`] calls to the peer. - /// - /// After transmitting the contents, call [`TransmitTlsData::done`] on the enclosed object. - /// The transmitted contents MUST not be sent to the peer more than once so they SHOULD be - /// discarded at this point. - /// - /// At some stages of the handshake process, it's possible to send application-data alongside - /// handshake records. Call [`TransmitTlsData::may_encrypt_app_data`] on the enclosed - /// object to probe if that's allowed. - TransmitTlsData(TransmitTlsData<'c, Data>), - - /// More TLS data is needed to continue with the handshake - /// - /// Request more data from the peer and append the contents to the `incoming_tls` buffer that - /// was passed to [`UnbufferedConnectionCommon::process_tls_records`]. - BlockedHandshake, - - /// The handshake process has been completed. - /// - /// [`WriteTraffic::encrypt`] can be called on the enclosed object to encrypt application - /// data into an `outgoing_tls` buffer. Similarly, [`WriteTraffic::queue_close_notify`] can - /// be used to encrypt a close_notify alert message into a buffer to signal the peer that the - /// connection is being closed. Data written into `outgoing_buffer` by either method MAY be - /// transmitted to the peer during this state. - /// - /// Once this state has been reached, data MAY be requested from the peer and appended to an - /// `incoming_tls` buffer that will be passed to a future - /// [`UnbufferedConnectionCommon::process_tls_records`] invocation. When enough data has been - /// appended to `incoming_tls`, [`UnbufferedConnectionCommon::process_tls_records`] will yield - /// the [`ConnectionState::ReadTraffic`] state. - WriteTraffic(WriteTraffic<'c, Data>), -} - -impl<'c, 'i, Data> From<ReadTraffic<'c, 'i, Data>> for ConnectionState<'c, 'i, Data> { - fn from(v: ReadTraffic<'c, 'i, Data>) -> Self { - Self::ReadTraffic(v) - } -} - -impl<'c, 'i, Data> From<ReadEarlyData<'c, 'i, Data>> for ConnectionState<'c, 'i, Data> { - fn from(v: ReadEarlyData<'c, 'i, Data>) -> Self { - Self::ReadEarlyData(v) - } -} - -impl<'c, Data> From<EncodeTlsData<'c, Data>> for ConnectionState<'c, '_, Data> { - fn from(v: EncodeTlsData<'c, Data>) -> Self { - Self::EncodeTlsData(v) - } -} - -impl<'c, Data> From<TransmitTlsData<'c, Data>> for ConnectionState<'c, '_, Data> { - fn from(v: TransmitTlsData<'c, Data>) -> Self { - Self::TransmitTlsData(v) - } -} - -impl<Data> fmt::Debug for ConnectionState<'_, '_, Data> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::ReadTraffic(..) => f.debug_tuple("ReadTraffic").finish(), - - Self::PeerClosed => write!(f, "PeerClosed"), - - Self::Closed => write!(f, "Closed"), - - Self::ReadEarlyData(..) => f.debug_tuple("ReadEarlyData").finish(), - - Self::EncodeTlsData(..) => f.debug_tuple("EncodeTlsData").finish(), - - Self::TransmitTlsData(..) => f - .debug_tuple("TransmitTlsData") - .finish(), - - Self::BlockedHandshake => f - .debug_tuple("BlockedHandshake") - .finish(), - - Self::WriteTraffic(..) => f.debug_tuple("WriteTraffic").finish(), - } - } -} - -/// Application data is available -pub struct ReadTraffic<'c, 'i, Data> { - conn: &'c mut UnbufferedConnectionCommon<Data>, - // for forwards compatibility; to support in-place decryption in the future - _incoming_tls: &'i mut [u8], - - // owner of the latest chunk obtained in `next_record`, as borrowed by - // `AppDataRecord` - chunk: Option<Vec<u8>>, -} - -impl<'c, 'i, Data> ReadTraffic<'c, 'i, Data> { - fn new(conn: &'c mut UnbufferedConnectionCommon<Data>, _incoming_tls: &'i mut [u8]) -> Self { - Self { - conn, - _incoming_tls, - chunk: None, - } - } - - /// Decrypts and returns the next available app-data record - // TODO deprecate in favor of `Iterator` implementation, which requires in-place decryption - pub fn next_record(&mut self) -> Option<Result<AppDataRecord<'_>, Error>> { - self.chunk = self - .conn - .core - .common_state - .received_plaintext - .pop(); - self.chunk.as_ref().map(|chunk| { - Ok(AppDataRecord { - discard: 0, - payload: chunk, - }) - }) - } - - /// Returns the payload size of the next app-data record *without* decrypting it - /// - /// Returns `None` if there are no more app-data records - pub fn peek_len(&self) -> Option<NonZeroUsize> { - self.conn - .core - .common_state - .received_plaintext - .peek() - .and_then(|ch| NonZeroUsize::new(ch.len())) - } -} - -/// Early application-data is available. -pub struct ReadEarlyData<'c, 'i, Data> { - conn: &'c mut UnbufferedConnectionCommon<Data>, - - // for forwards compatibility; to support in-place decryption in the future - _incoming_tls: &'i mut [u8], - - // owner of the latest chunk obtained in `next_record`, as borrowed by - // `AppDataRecord` - chunk: Option<Vec<u8>>, -} - -impl<'c, 'i> ReadEarlyData<'c, 'i, ServerConnectionData> { - fn new( - conn: &'c mut UnbufferedConnectionCommon<ServerConnectionData>, - _incoming_tls: &'i mut [u8], - ) -> Self { - Self { - conn, - _incoming_tls, - chunk: None, - } - } - - /// decrypts and returns the next available app-data record - // TODO deprecate in favor of `Iterator` implementation, which requires in-place decryption - pub fn next_record(&mut self) -> Option<Result<AppDataRecord<'_>, Error>> { - self.chunk = self.conn.pop_early_data(); - self.chunk.as_ref().map(|chunk| { - Ok(AppDataRecord { - discard: 0, - payload: chunk, - }) - }) - } - - /// returns the payload size of the next app-data record *without* decrypting it - /// - /// returns `None` if there are no more app-data records - pub fn peek_len(&self) -> Option<NonZeroUsize> { - self.conn - .peek_early_data() - .and_then(|ch| NonZeroUsize::new(ch.len())) - } -} - -/// A decrypted application-data record -pub struct AppDataRecord<'i> { - /// Number of additional bytes to discard - /// - /// This number MUST be added to the value of [`UnbufferedStatus.discard`] *prior* to the - /// discard operation. See [`UnbufferedStatus.discard`] for more details - pub discard: usize, - - /// The payload of the app-data record - pub payload: &'i [u8], -} - -/// Allows encrypting app-data -pub struct WriteTraffic<'c, Data> { - conn: &'c mut UnbufferedConnectionCommon<Data>, -} - -impl<Data> WriteTraffic<'_, Data> { - /// Encrypts `application_data` into the `outgoing_tls` buffer - /// - /// Returns the number of bytes that were written into `outgoing_tls`, or an error if - /// the provided buffer is too small. In the error case, `outgoing_tls` is not modified - pub fn encrypt( - &mut self, - application_data: &[u8], - outgoing_tls: &mut [u8], - ) -> Result<usize, EncryptError> { - self.conn - .core - .maybe_refresh_traffic_keys(); - self.conn - .core - .common_state - .write_plaintext(application_data.into(), outgoing_tls) - } - - /// Encrypts a close_notify warning alert in `outgoing_tls` - /// - /// Returns the number of bytes that were written into `outgoing_tls`, or an error if - /// the provided buffer is too small. In the error case, `outgoing_tls` is not modified - pub fn queue_close_notify(&mut self, outgoing_tls: &mut [u8]) -> Result<usize, EncryptError> { - self.conn - .core - .common_state - .eager_send_close_notify(outgoing_tls) - } - - /// Arranges for a TLS1.3 `key_update` to be sent. - /// - /// This consumes the `WriteTraffic` state: to actually send the message, - /// call [`UnbufferedConnectionCommon::process_tls_records`] again which will - /// return a `ConnectionState::EncodeTlsData` that emits the `key_update` - /// message. - /// - /// See [`ConnectionCommon::refresh_traffic_keys()`] for full documentation, - /// including why you might call this and in what circumstances it will fail. - /// - /// [`ConnectionCommon::refresh_traffic_keys()`]: crate::ConnectionCommon::refresh_traffic_keys - pub fn refresh_traffic_keys(self) -> Result<(), Error> { - self.conn.core.refresh_traffic_keys() - } -} - -/// A handshake record must be encoded -pub struct EncodeTlsData<'c, Data> { - conn: &'c mut UnbufferedConnectionCommon<Data>, - chunk: Option<Vec<u8>>, -} - -impl<'c, Data> EncodeTlsData<'c, Data> { - fn new(conn: &'c mut UnbufferedConnectionCommon<Data>, chunk: Vec<u8>) -> Self { - Self { - conn, - chunk: Some(chunk), - } - } - - /// Encodes a handshake record into the `outgoing_tls` buffer - /// - /// Returns the number of bytes that were written into `outgoing_tls`, or an error if - /// the provided buffer is too small. In the error case, `outgoing_tls` is not modified - pub fn encode(&mut self, outgoing_tls: &mut [u8]) -> Result<usize, EncodeError> { - let Some(chunk) = self.chunk.take() else { - return Err(EncodeError::AlreadyEncoded); - }; - - let required_size = chunk.len(); - - if required_size > outgoing_tls.len() { - self.chunk = Some(chunk); - Err(InsufficientSizeError { required_size }.into()) - } else { - let written = chunk.len(); - outgoing_tls[..written].copy_from_slice(&chunk); - - self.conn.wants_write = true; - - Ok(written) - } - } -} - -/// Previously encoded TLS data must be transmitted -pub struct TransmitTlsData<'c, Data> { - pub(crate) conn: &'c mut UnbufferedConnectionCommon<Data>, -} - -impl<Data> TransmitTlsData<'_, Data> { - /// Signals that the previously encoded TLS data has been transmitted - pub fn done(self) { - self.conn.wants_write = false; - } - - /// Returns an adapter that allows encrypting application data - /// - /// If allowed at this stage of the handshake process - pub fn may_encrypt_app_data(&mut self) -> Option<WriteTraffic<'_, Data>> { - if self - .conn - .core - .common_state - .may_send_application_data - { - Some(WriteTraffic { conn: self.conn }) - } else { - None - } - } -} - -/// Errors that may arise when encoding a handshake record -#[derive(Debug)] -pub enum EncodeError { - /// Provided buffer was too small - InsufficientSize(InsufficientSizeError), - - /// The handshake record has already been encoded; do not call `encode` again - AlreadyEncoded, -} - -impl From<InsufficientSizeError> for EncodeError { - fn from(v: InsufficientSizeError) -> Self { - Self::InsufficientSize(v) - } -} - -impl fmt::Display for EncodeError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InsufficientSize(InsufficientSizeError { required_size }) => write!( - f, - "cannot encode due to insufficient size, {required_size} bytes are required" - ), - Self::AlreadyEncoded => "cannot encode, data has already been encoded".fmt(f), - } - } -} - -#[cfg(feature = "std")] -impl StdError for EncodeError {} - -/// Errors that may arise when encrypting application data -#[derive(Debug)] -pub enum EncryptError { - /// Provided buffer was too small - InsufficientSize(InsufficientSizeError), - - /// Encrypter has been exhausted - EncryptExhausted, -} - -impl From<InsufficientSizeError> for EncryptError { - fn from(v: InsufficientSizeError) -> Self { - Self::InsufficientSize(v) - } -} - -impl fmt::Display for EncryptError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InsufficientSize(InsufficientSizeError { required_size }) => write!( - f, - "cannot encrypt due to insufficient size, {required_size} bytes are required" - ), - Self::EncryptExhausted => f.write_str("encrypter has been exhausted"), - } - } -} - -#[cfg(feature = "std")] -impl StdError for EncryptError {} - -/// Provided buffer was too small -#[derive(Clone, Copy, Debug)] -pub struct InsufficientSizeError { - /// buffer must be at least this size - pub required_size: usize, -} diff --git a/vendor/rustls/src/crypto/aws_lc_rs/hpke.rs b/vendor/rustls/src/crypto/aws_lc_rs/hpke.rs deleted file mode 100644 index de0e5d63..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/hpke.rs +++ /dev/null @@ -1,1191 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt::{self, Debug, Formatter}; - -use aws_lc_rs::aead::{ - self, Aad, BoundKey, NONCE_LEN, Nonce, NonceSequence, OpeningKey, SealingKey, UnboundKey, -}; -use aws_lc_rs::agreement; -use aws_lc_rs::cipher::{AES_128_KEY_LEN, AES_256_KEY_LEN}; -use aws_lc_rs::digest::{SHA256_OUTPUT_LEN, SHA384_OUTPUT_LEN, SHA512_OUTPUT_LEN}; -use aws_lc_rs::encoding::{AsBigEndian, Curve25519SeedBin, EcPrivateKeyBin}; -use zeroize::Zeroize; - -use crate::crypto::aws_lc_rs::hmac::{HMAC_SHA256, HMAC_SHA384, HMAC_SHA512}; -use crate::crypto::aws_lc_rs::unspecified_err; -use crate::crypto::hpke::{ - EncapsulatedSecret, Hpke, HpkeOpener, HpkePrivateKey, HpkePublicKey, HpkeSealer, HpkeSuite, -}; -use crate::crypto::tls13::{HkdfExpander, HkdfPrkExtract, HkdfUsingHmac, expand}; -use crate::msgs::enums::{HpkeAead, HpkeKdf, HpkeKem}; -use crate::msgs::handshake::HpkeSymmetricCipherSuite; -#[cfg(feature = "std")] -use crate::sync::Arc; -use crate::{Error, OtherError}; - -/// Default [RFC 9180] Hybrid Public Key Encryption (HPKE) suites supported by aws-lc-rs cryptography. -pub static ALL_SUPPORTED_SUITES: &[&dyn Hpke] = &[ - DH_KEM_P256_HKDF_SHA256_AES_128, - DH_KEM_P256_HKDF_SHA256_AES_256, - #[cfg(not(feature = "fips"))] - DH_KEM_P256_HKDF_SHA256_CHACHA20_POLY1305, - DH_KEM_P384_HKDF_SHA384_AES_128, - DH_KEM_P384_HKDF_SHA384_AES_256, - #[cfg(not(feature = "fips"))] - DH_KEM_P384_HKDF_SHA384_CHACHA20_POLY1305, - DH_KEM_P521_HKDF_SHA512_AES_128, - DH_KEM_P521_HKDF_SHA512_AES_256, - #[cfg(not(feature = "fips"))] - DH_KEM_P521_HKDF_SHA512_CHACHA20_POLY1305, - #[cfg(not(feature = "fips"))] - DH_KEM_X25519_HKDF_SHA256_AES_128, - #[cfg(not(feature = "fips"))] - DH_KEM_X25519_HKDF_SHA256_AES_256, - #[cfg(not(feature = "fips"))] - DH_KEM_X25519_HKDF_SHA256_CHACHA20_POLY1305, -]; - -/// HPKE suite using ECDH P-256 for agreement, HKDF SHA-256 for key derivation, and AEAD AES-128-GCM -/// for symmetric encryption. -pub static DH_KEM_P256_HKDF_SHA256_AES_128: &HpkeAwsLcRs<AES_128_KEY_LEN, SHA256_OUTPUT_LEN> = - &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P256_HKDF_SHA256, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA256, - aead_id: HpkeAead::AES_128_GCM, - }, - }, - dh_kem: DH_KEM_P256_HKDF_SHA256, - hkdf: RING_HKDF_HMAC_SHA256, - aead: &aead::AES_128_GCM, - }; - -/// HPKE suite using ECDH P-256 for agreement, HKDF SHA-256 for key derivation and AEAD AES-256-GCM -/// for symmetric encryption. -pub static DH_KEM_P256_HKDF_SHA256_AES_256: &HpkeAwsLcRs<AES_256_KEY_LEN, SHA256_OUTPUT_LEN> = - &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P256_HKDF_SHA256, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA256, - aead_id: HpkeAead::AES_256_GCM, - }, - }, - dh_kem: DH_KEM_P256_HKDF_SHA256, - hkdf: RING_HKDF_HMAC_SHA256, - aead: &aead::AES_256_GCM, - }; - -/// HPKE suite using ECDH P-256 for agreement, HKDF SHA-256 for key derivation, and AEAD -/// CHACHA20-POLY-1305 for symmetric encryption. -pub static DH_KEM_P256_HKDF_SHA256_CHACHA20_POLY1305: &HpkeAwsLcRs< - CHACHA_KEY_LEN, - SHA256_OUTPUT_LEN, -> = &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P256_HKDF_SHA256, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA256, - aead_id: HpkeAead::CHACHA20_POLY_1305, - }, - }, - dh_kem: DH_KEM_P256_HKDF_SHA256, - hkdf: RING_HKDF_HMAC_SHA256, - aead: &aead::CHACHA20_POLY1305, -}; - -/// HPKE suite using ECDH P-384 for agreement, HKDF SHA-384 for key derivation, and AEAD AES-128-GCM -/// for symmetric encryption. -pub static DH_KEM_P384_HKDF_SHA384_AES_128: &HpkeAwsLcRs<AES_128_KEY_LEN, SHA384_OUTPUT_LEN> = - &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P384_HKDF_SHA384, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA384, - aead_id: HpkeAead::AES_128_GCM, - }, - }, - dh_kem: DH_KEM_P384_HKDF_SHA384, - hkdf: RING_HKDF_HMAC_SHA384, - aead: &aead::AES_128_GCM, - }; - -/// HPKE suite using ECDH P-384 for agreement, HKDF SHA-384 for key derivation, and AEAD AES-256-GCM -/// for symmetric encryption. -pub static DH_KEM_P384_HKDF_SHA384_AES_256: &HpkeAwsLcRs<AES_256_KEY_LEN, SHA384_OUTPUT_LEN> = - &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P384_HKDF_SHA384, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA384, - aead_id: HpkeAead::AES_256_GCM, - }, - }, - dh_kem: DH_KEM_P384_HKDF_SHA384, - hkdf: RING_HKDF_HMAC_SHA384, - aead: &aead::AES_256_GCM, - }; - -/// HPKE suite using ECDH P-384 for agreement, HKDF SHA-384 for key derivation, and AEAD -/// CHACHA20-POLY-1305 for symmetric encryption. -pub static DH_KEM_P384_HKDF_SHA384_CHACHA20_POLY1305: &HpkeAwsLcRs< - CHACHA_KEY_LEN, - SHA384_OUTPUT_LEN, -> = &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P384_HKDF_SHA384, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA384, - aead_id: HpkeAead::CHACHA20_POLY_1305, - }, - }, - dh_kem: DH_KEM_P384_HKDF_SHA384, - hkdf: RING_HKDF_HMAC_SHA384, - aead: &aead::CHACHA20_POLY1305, -}; - -/// HPKE suite using ECDH P-521 for agreement, HKDF SHA-512 for key derivation, and AEAD AES-128-GCM -/// for symmetric encryption. -pub static DH_KEM_P521_HKDF_SHA512_AES_128: &HpkeAwsLcRs<AES_128_KEY_LEN, SHA512_OUTPUT_LEN> = - &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P521_HKDF_SHA512, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA512, - aead_id: HpkeAead::AES_128_GCM, - }, - }, - dh_kem: DH_KEM_P521_HKDF_SHA512, - hkdf: RING_HKDF_HMAC_SHA512, - aead: &aead::AES_128_GCM, - }; - -/// HPKE suite using ECDH P-521 for agreement, HKDF SHA-512 for key derivation, and AEAD AES-256-GCM -/// for symmetric encryption. -pub static DH_KEM_P521_HKDF_SHA512_AES_256: &HpkeAwsLcRs<AES_256_KEY_LEN, SHA512_OUTPUT_LEN> = - &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P521_HKDF_SHA512, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA512, - aead_id: HpkeAead::AES_256_GCM, - }, - }, - dh_kem: DH_KEM_P521_HKDF_SHA512, - hkdf: RING_HKDF_HMAC_SHA512, - aead: &aead::AES_256_GCM, - }; - -/// HPKE suite using ECDH P-521 for agreement, HKDF SHA-512 for key derivation, and AEAD -/// CHACHA20-POLY-1305 for symmetric encryption. -pub static DH_KEM_P521_HKDF_SHA512_CHACHA20_POLY1305: &HpkeAwsLcRs< - CHACHA_KEY_LEN, - SHA512_OUTPUT_LEN, -> = &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_P521_HKDF_SHA512, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA512, - aead_id: HpkeAead::CHACHA20_POLY_1305, - }, - }, - dh_kem: DH_KEM_P521_HKDF_SHA512, - hkdf: RING_HKDF_HMAC_SHA512, - aead: &aead::CHACHA20_POLY1305, -}; - -/// HPKE suite using ECDH X25519 for agreement, HKDF SHA-256 for key derivation, and AEAD AES-128-GCM -/// for symmetric encryption. -pub static DH_KEM_X25519_HKDF_SHA256_AES_128: &HpkeAwsLcRs<AES_128_KEY_LEN, SHA256_OUTPUT_LEN> = - &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_X25519_HKDF_SHA256, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA256, - aead_id: HpkeAead::AES_128_GCM, - }, - }, - dh_kem: DH_KEM_X25519_HKDF_SHA256, - hkdf: RING_HKDF_HMAC_SHA256, - aead: &aead::AES_128_GCM, - }; - -/// HPKE suite using ECDH X25519 for agreement, HKDF SHA-256 for key derivation, and AEAD AES-256-GCM -/// for symmetric encryption. -pub static DH_KEM_X25519_HKDF_SHA256_AES_256: &HpkeAwsLcRs<AES_256_KEY_LEN, SHA256_OUTPUT_LEN> = - &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_X25519_HKDF_SHA256, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA256, - aead_id: HpkeAead::AES_256_GCM, - }, - }, - dh_kem: DH_KEM_X25519_HKDF_SHA256, - hkdf: RING_HKDF_HMAC_SHA256, - aead: &aead::AES_256_GCM, - }; - -/// HPKE suite using ECDH X25519 for agreement, HKDF SHA-256 for key derivation, and AEAD -/// CHACHA20-POLY-1305 for symmetric encryption. -pub static DH_KEM_X25519_HKDF_SHA256_CHACHA20_POLY1305: &HpkeAwsLcRs< - CHACHA_KEY_LEN, - SHA256_OUTPUT_LEN, -> = &HpkeAwsLcRs { - suite: HpkeSuite { - kem: HpkeKem::DHKEM_X25519_HKDF_SHA256, - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA256, - aead_id: HpkeAead::CHACHA20_POLY_1305, - }, - }, - dh_kem: DH_KEM_X25519_HKDF_SHA256, - hkdf: RING_HKDF_HMAC_SHA256, - aead: &aead::CHACHA20_POLY1305, -}; - -/// `HpkeAwsLcRs` holds the concrete instantiations of the algorithms specified by the [HpkeSuite]. -pub struct HpkeAwsLcRs<const KEY_SIZE: usize, const KDF_SIZE: usize> { - suite: HpkeSuite, - dh_kem: &'static DhKem<KDF_SIZE>, - hkdf: &'static dyn HkdfPrkExtract, - aead: &'static aead::Algorithm, -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> HpkeAwsLcRs<KEY_SIZE, KDF_SIZE> { - /// See [RFC 9180 §5.1 "Creating the Encryption Context"][0]. - /// - /// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1 - fn key_schedule( - &self, - shared_secret: KemSharedSecret<KDF_SIZE>, - info: &[u8], - ) -> Result<KeySchedule<KEY_SIZE>, Error> { - // Note: we use an empty IKM for the `psk_id_hash` and `secret` labelled extractions because - // there is no PSK ID in base mode HPKE. - - let suite_id = LabeledSuiteId::Hpke(self.suite); - let psk_id_hash = labeled_extract_for_prk(self.hkdf, suite_id, None, Label::PskIdHash, &[]); - let info_hash = labeled_extract_for_prk(self.hkdf, suite_id, None, Label::InfoHash, info); - let key_schedule_context = [ - &[0][..], // base mode (0x00) - &psk_id_hash, - &info_hash, - ] - .concat(); - - let key = AeadKey(self.key_schedule_labeled_expand::<KEY_SIZE>( - &shared_secret, - &key_schedule_context, - Label::Key, - )); - - let base_nonce = self.key_schedule_labeled_expand::<NONCE_LEN>( - &shared_secret, - &key_schedule_context, - Label::BaseNonce, - ); - - Ok(KeySchedule { - aead: self.aead, - key, - base_nonce, - seq_num: 0, - }) - } - - fn key_schedule_labeled_expand<const L: usize>( - &self, - shared_secret: &KemSharedSecret<KDF_SIZE>, - key_schedule_context: &[u8], - label: Label, - ) -> [u8; L] { - let suite_id = LabeledSuiteId::Hpke(self.suite); - labeled_expand::<L>( - suite_id, - labeled_extract_for_expand( - self.hkdf, - suite_id, - Some(&shared_secret.0), - Label::Secret, - &[], - ), - label, - key_schedule_context, - ) - } -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Hpke for HpkeAwsLcRs<KEY_SIZE, KDF_SIZE> { - fn seal( - &self, - info: &[u8], - aad: &[u8], - plaintext: &[u8], - pub_key: &HpkePublicKey, - ) -> Result<(EncapsulatedSecret, Vec<u8>), Error> { - let (encap, mut sealer) = self.setup_sealer(info, pub_key)?; - Ok((encap, sealer.seal(aad, plaintext)?)) - } - - fn setup_sealer( - &self, - info: &[u8], - pub_key: &HpkePublicKey, - ) -> Result<(EncapsulatedSecret, Box<dyn HpkeSealer + 'static>), Error> { - let (encap, sealer) = Sealer::new(self, info, pub_key)?; - Ok((encap, Box::new(sealer))) - } - - fn open( - &self, - enc: &EncapsulatedSecret, - info: &[u8], - aad: &[u8], - ciphertext: &[u8], - secret_key: &HpkePrivateKey, - ) -> Result<Vec<u8>, Error> { - self.setup_opener(enc, info, secret_key)? - .open(aad, ciphertext) - } - - fn setup_opener( - &self, - enc: &EncapsulatedSecret, - info: &[u8], - secret_key: &HpkePrivateKey, - ) -> Result<Box<dyn HpkeOpener + 'static>, Error> { - Ok(Box::new(Opener::new(self, enc, info, secret_key)?)) - } - - fn fips(&self) -> bool { - matches!( - // We make a FIPS determination based on the suite's DH KEM and AEAD choice. - // We don't need to examine the KDF choice because all supported KDFs are FIPS - // compatible. - (self.suite.kem, self.suite.sym.aead_id), - ( - // Only the NIST "P-curve" DH KEMs are FIPS compatible. - HpkeKem::DHKEM_P256_HKDF_SHA256 - | HpkeKem::DHKEM_P384_HKDF_SHA384 - | HpkeKem::DHKEM_P521_HKDF_SHA512, - // Only the AES AEADs are FIPS compatible. - HpkeAead::AES_128_GCM | HpkeAead::AES_256_GCM, - ) - ) - } - - fn generate_key_pair(&self) -> Result<(HpkePublicKey, HpkePrivateKey), Error> { - (self.dh_kem.key_generator)() - } - - fn suite(&self) -> HpkeSuite { - self.suite - } -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Debug for HpkeAwsLcRs<KEY_SIZE, KDF_SIZE> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - self.suite.fmt(f) - } -} - -/// Adapts a [KeySchedule] and [AeadKey] for the role of a [HpkeSealer]. -struct Sealer<const KEY_SIZE: usize, const KDF_SIZE: usize> { - key_schedule: KeySchedule<KEY_SIZE>, -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Sealer<KEY_SIZE, KDF_SIZE> { - /// See [RFC 9180 §5.1.1 "Encryption to a Public Key"][0]. - /// - /// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1.1 - fn new( - suite: &HpkeAwsLcRs<KEY_SIZE, KDF_SIZE>, - info: &[u8], - pub_key: &HpkePublicKey, - ) -> Result<(EncapsulatedSecret, Self), Error> { - // def SetupBaseS(pkR, info): - // shared_secret, enc = Encap(pkR) - // return enc, KeyScheduleS(mode_base, shared_secret, info, - // default_psk, default_psk_id) - - let (shared_secret, enc) = suite.dh_kem.encap(pub_key)?; - let key_schedule = suite.key_schedule(shared_secret, info)?; - Ok((enc, Self { key_schedule })) - } - - /// A **test only** constructor that uses a pre-specified ephemeral agreement private key - /// instead of one that is randomly generated. - #[cfg(test)] - fn test_only_new( - suite: &HpkeAwsLcRs<KEY_SIZE, KDF_SIZE>, - info: &[u8], - pub_key: &HpkePublicKey, - sk_e: &[u8], - ) -> Result<(EncapsulatedSecret, Self), Error> { - let (shared_secret, enc) = suite - .dh_kem - .test_only_encap(pub_key, sk_e)?; - let key_schedule = suite.key_schedule(shared_secret, info)?; - Ok((enc, Self { key_schedule })) - } -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> HpkeSealer for Sealer<KEY_SIZE, KDF_SIZE> { - fn seal(&mut self, aad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, Error> { - // def ContextS.Seal(aad, pt): - // ct = Seal(self.key, self.ComputeNonce(self.seq), aad, pt) - // self.IncrementSeq() - // return ct - - let key = UnboundKey::new(self.key_schedule.aead, &self.key_schedule.key.0) - .map_err(unspecified_err)?; - let mut sealing_key = SealingKey::new(key, &mut self.key_schedule); - - let mut in_out_buffer = Vec::from(plaintext); - sealing_key - .seal_in_place_append_tag(Aad::from(aad), &mut in_out_buffer) - .map_err(unspecified_err)?; - - Ok(in_out_buffer) - } -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Debug for Sealer<KEY_SIZE, KDF_SIZE> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Sealer").finish() - } -} - -/// Adapts a [KeySchedule] and [AeadKey] for the role of a [HpkeOpener]. -struct Opener<const KEY_SIZE: usize, const KDF_SIZE: usize> { - key_schedule: KeySchedule<KEY_SIZE>, -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Opener<KEY_SIZE, KDF_SIZE> { - /// See [RFC 9180 §5.1.1 "Encryption to a Public Key"][0]. - /// - /// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-5.1.1 - fn new( - suite: &HpkeAwsLcRs<KEY_SIZE, KDF_SIZE>, - enc: &EncapsulatedSecret, - info: &[u8], - secret_key: &HpkePrivateKey, - ) -> Result<Self, Error> { - // def SetupBaseR(enc, skR, info): - // shared_secret = Decap(enc, skR) - // return KeyScheduleR(mode_base, shared_secret, info, - // default_psk, default_psk_id) - Ok(Self { - key_schedule: suite.key_schedule(suite.dh_kem.decap(enc, secret_key)?, info)?, - }) - } -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> HpkeOpener for Opener<KEY_SIZE, KDF_SIZE> { - fn open(&mut self, aad: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, Error> { - // def ContextR.Open(aad, ct): - // pt = Open(self.key, self.ComputeNonce(self.seq), aad, ct) - // if pt == OpenError: - // raise OpenError - // self.IncrementSeq() - // return pt - - let key = UnboundKey::new(self.key_schedule.aead, &self.key_schedule.key.0) - .map_err(unspecified_err)?; - let mut opening_key = OpeningKey::new(key, &mut self.key_schedule); - - let mut in_out_buffer = Vec::from(ciphertext); - let plaintext = opening_key - .open_in_place(Aad::from(aad), &mut in_out_buffer) - .map_err(unspecified_err)?; - - Ok(plaintext.to_vec()) - } -} - -impl<const KEY_SIZE: usize, const KDF_SIZE: usize> Debug for Opener<KEY_SIZE, KDF_SIZE> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Opener").finish() - } -} - -/// A Diffie-Hellman (DH) based Key Encapsulation Mechanism (KEM). -/// -/// See [RFC 9180 §4.1 "DH-Based KEM (DHKEM)"][0]. -/// -/// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-4.1 -struct DhKem<const KDF_SIZE: usize> { - id: HpkeKem, - agreement_algorithm: &'static agreement::Algorithm, - key_generator: - &'static (dyn Fn() -> Result<(HpkePublicKey, HpkePrivateKey), Error> + Send + Sync), - hkdf: &'static dyn HkdfPrkExtract, -} - -impl<const KDF_SIZE: usize> DhKem<KDF_SIZE> { - /// See [RFC 9180 §4.1 "DH-Based KEM (DHKEM)"][0]. - /// - /// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-4.1 - fn encap( - &self, - recipient: &HpkePublicKey, - ) -> Result<(KemSharedSecret<KDF_SIZE>, EncapsulatedSecret), Error> { - // def Encap(pkR): - // skE, pkE = GenerateKeyPair() - - let sk_e = - agreement::PrivateKey::generate(self.agreement_algorithm).map_err(unspecified_err)?; - self.encap_impl(recipient, sk_e) - } - - /// A test-only encap operation that uses a fixed `test_only_ske` instead of generating - /// one randomly. - #[cfg(test)] - fn test_only_encap( - &self, - recipient: &HpkePublicKey, - test_only_ske: &[u8], - ) -> Result<(KemSharedSecret<KDF_SIZE>, EncapsulatedSecret), Error> { - // For test contexts only, we accept a static sk_e as an argument. - let sk_e = agreement::PrivateKey::from_private_key(self.agreement_algorithm, test_only_ske) - .map_err(key_rejected_err)?; - self.encap_impl(recipient, sk_e) - } - - fn encap_impl( - &self, - recipient: &HpkePublicKey, - sk_e: agreement::PrivateKey, - ) -> Result<(KemSharedSecret<KDF_SIZE>, EncapsulatedSecret), Error> { - // def Encap(pkR): - // skE, pkE = GenerateKeyPair() - // dh = DH(skE, pkR) - // enc = SerializePublicKey(pkE) - // - // pkRm = SerializePublicKey(pkR) - // kem_context = concat(enc, pkRm) - // - // shared_secret = ExtractAndExpand(dh, kem_context) - // return shared_secret, enc - - let enc = sk_e - .compute_public_key() - .map_err(unspecified_err)?; - let pk_r = agreement::UnparsedPublicKey::new(self.agreement_algorithm, &recipient.0); - let kem_context = [enc.as_ref(), pk_r.bytes()].concat(); - - let shared_secret = agreement::agree(&sk_e, &pk_r, aws_lc_rs::error::Unspecified, |dh| { - Ok(self.extract_and_expand(dh, &kem_context)) - }) - .map_err(unspecified_err)?; - - Ok(( - KemSharedSecret(shared_secret), - EncapsulatedSecret(enc.as_ref().into()), - )) - } - - /// See [RFC 9180 §4.1 "DH-Based KEM (DHKEM)"][0]. - /// - /// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-4.1 - fn decap( - &self, - enc: &EncapsulatedSecret, - recipient: &HpkePrivateKey, - ) -> Result<KemSharedSecret<KDF_SIZE>, Error> { - // def Decap(enc, skR): - // pkE = DeserializePublicKey(enc) - // dh = DH(skR, pkE) - // - // pkRm = SerializePublicKey(pk(skR)) - // kem_context = concat(enc, pkRm) - // - // shared_secret = ExtractAndExpand(dh, kem_context) - // return shared_secret - - let pk_e = agreement::UnparsedPublicKey::new(self.agreement_algorithm, &enc.0); - let sk_r = agreement::PrivateKey::from_private_key( - self.agreement_algorithm, - recipient.secret_bytes(), - ) - .map_err(key_rejected_err)?; - let pk_rm = sk_r - .compute_public_key() - .map_err(unspecified_err)?; - let kem_context = [&enc.0, pk_rm.as_ref()].concat(); - - let shared_secret = agreement::agree(&sk_r, &pk_e, aws_lc_rs::error::Unspecified, |dh| { - Ok(self.extract_and_expand(dh, &kem_context)) - }) - .map_err(unspecified_err)?; - - Ok(KemSharedSecret(shared_secret)) - } - - /// See [RFC 9180 §4.1 "DH-Based KEM (DHKEM)"][0]. - /// - /// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-4.1 - fn extract_and_expand(&self, dh: &[u8], kem_context: &[u8]) -> [u8; KDF_SIZE] { - // def ExtractAndExpand(dh, kem_context): - // eae_prk = LabeledExtract("", "eae_prk", dh) - // shared_secret = LabeledExpand(eae_prk, "shared_secret", - // kem_context, Nsecret) - // return shared_secret - - let suite_id = LabeledSuiteId::Kem(self.id); - labeled_expand( - suite_id, - labeled_extract_for_expand(self.hkdf, suite_id, None, Label::EaePrk, dh), - Label::SharedSecret, - kem_context, - ) - } -} - -static DH_KEM_P256_HKDF_SHA256: &DhKem<SHA256_OUTPUT_LEN> = &DhKem { - id: HpkeKem::DHKEM_P256_HKDF_SHA256, - agreement_algorithm: &agreement::ECDH_P256, - key_generator: &|| generate_p_curve_key_pair(&agreement::ECDH_P256), - hkdf: RING_HKDF_HMAC_SHA256, -}; - -static DH_KEM_P384_HKDF_SHA384: &DhKem<SHA384_OUTPUT_LEN> = &DhKem { - id: HpkeKem::DHKEM_P384_HKDF_SHA384, - agreement_algorithm: &agreement::ECDH_P384, - key_generator: &|| generate_p_curve_key_pair(&agreement::ECDH_P384), - hkdf: RING_HKDF_HMAC_SHA384, -}; - -static DH_KEM_P521_HKDF_SHA512: &DhKem<SHA512_OUTPUT_LEN> = &DhKem { - id: HpkeKem::DHKEM_P521_HKDF_SHA512, - agreement_algorithm: &agreement::ECDH_P521, - key_generator: &|| generate_p_curve_key_pair(&agreement::ECDH_P521), - hkdf: RING_HKDF_HMAC_SHA512, -}; - -static DH_KEM_X25519_HKDF_SHA256: &DhKem<SHA256_OUTPUT_LEN> = &DhKem { - id: HpkeKem::DHKEM_X25519_HKDF_SHA256, - agreement_algorithm: &agreement::X25519, - key_generator: &generate_x25519_key_pair, - hkdf: RING_HKDF_HMAC_SHA256, -}; - -/// Generate a NIST P-256, P-384 or P-512 key pair expressed as a raw big-endian fixed-length -/// integer. -/// -/// We must disambiguate the [`AsBigEndian`] trait in-use and this function uses -/// [`AsBigEndian<EcPrivateKeyBin>`], which does not support [`agreement::X25519`]. -/// For generating X25519 keys see [`generate_x25519_key_pair`]. -fn generate_p_curve_key_pair( - alg: &'static agreement::Algorithm, -) -> Result<(HpkePublicKey, HpkePrivateKey), Error> { - // We only initialize DH KEM instances that use this function as a key generator - // for non-X25519 algorithms. Debug assert this just in case since `AsBigEndian<EcPrivateKeyBin>` - // will panic for this algorithm. - debug_assert_ne!(alg, &agreement::X25519); - let (public_key, private_key) = generate_key_pair(alg)?; - let raw_private_key: EcPrivateKeyBin<'_> = private_key - .as_be_bytes() - .map_err(unspecified_err)?; - Ok(( - public_key, - HpkePrivateKey::from(raw_private_key.as_ref().to_vec()), - )) -} - -/// Generate a X25519 key pair expressed as a raw big-endian fixed-length -/// integer. -/// -/// We must disambiguate the [`AsBigEndian`] trait in-use and this function uses -/// [`AsBigEndian<Curve25519SeedBin>`], which only supports [`agreement::X25519`]. -/// For generating P-256, P-384 and P-512 keys see [`generate_p_curve_key_pair`]. -fn generate_x25519_key_pair() -> Result<(HpkePublicKey, HpkePrivateKey), Error> { - let (public_key, private_key) = generate_key_pair(&agreement::X25519)?; - let raw_private_key: Curve25519SeedBin<'_> = private_key - .as_be_bytes() - .map_err(unspecified_err)?; - Ok(( - public_key, - HpkePrivateKey::from(raw_private_key.as_ref().to_vec()), - )) -} - -fn generate_key_pair( - alg: &'static agreement::Algorithm, -) -> Result<(HpkePublicKey, agreement::PrivateKey), Error> { - let private_key = agreement::PrivateKey::generate(alg).map_err(unspecified_err)?; - let public_key = HpkePublicKey( - private_key - .compute_public_key() - .map_err(unspecified_err)? - .as_ref() - .to_vec(), - ); - Ok((public_key, private_key)) -} - -/// KeySchedule holds the derived AEAD key, base nonce, and seq number -/// common to both a [Sealer] and [Opener]. -struct KeySchedule<const KEY_SIZE: usize> { - aead: &'static aead::Algorithm, - key: AeadKey<KEY_SIZE>, - base_nonce: [u8; NONCE_LEN], - seq_num: u32, -} - -impl<const KEY_SIZE: usize> KeySchedule<KEY_SIZE> { - /// See [RFC 9180 §5.2 "Encryption and Decryption"][0]. - /// - /// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-5.2 - fn compute_nonce(&self) -> [u8; NONCE_LEN] { - // def Context<ROLE>.ComputeNonce(seq): - // seq_bytes = I2OSP(seq, Nn) - // return xor(self.base_nonce, seq_bytes) - - // Each new N-byte nonce is conceptually two parts: - // * N-4 bytes of the base nonce (0s in `nonce` to XOR in as-is). - // * 4 bytes derived from the sequence number XOR the base nonce. - let mut nonce = [0; NONCE_LEN]; - let seq_bytes = self.seq_num.to_be_bytes(); - nonce[NONCE_LEN - seq_bytes.len()..].copy_from_slice(&seq_bytes); - - for (n, &b) in nonce.iter_mut().zip(&self.base_nonce) { - *n ^= b; - } - - nonce - } - - /// See [RFC 9180 §5.2 "Encryption and Decryption"][0]. - /// - /// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-5.2 - fn increment_seq_num(&mut self) -> Result<(), aws_lc_rs::error::Unspecified> { - // def Context<ROLE>.IncrementSeq(): - // if self.seq >= (1 << (8*Nn)) - 1: - // raise MessageLimitReachedError - // self.seq += 1 - - // Determine the maximum sequence number using the AEAD nonce's length in bits. - // Do this as an u128 to prevent overflowing. - let max_seq_num = (1u128 << (NONCE_LEN * 8)) - 1; - - // Promote the u32 sequence number to an u128 and compare against the maximum allowed - // sequence number. - if u128::from(self.seq_num) >= max_seq_num { - return Err(aws_lc_rs::error::Unspecified); - } - - self.seq_num += 1; - Ok(()) - } -} - -impl<const KEY_SIZE: usize> NonceSequence for &mut KeySchedule<KEY_SIZE> { - fn advance(&mut self) -> Result<Nonce, aws_lc_rs::error::Unspecified> { - let nonce = self.compute_nonce(); - self.increment_seq_num()?; - Nonce::try_assume_unique_for_key(&nonce) - } -} - -/// See [RFC 9180 §4 "Cryptographic Dependencies"][0]. -/// -/// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-4 -fn labeled_extract_for_expand( - hkdf: &'static dyn HkdfPrkExtract, - suite_id: LabeledSuiteId, - salt: Option<&[u8]>, - label: Label, - ikm: &[u8], -) -> Box<dyn HkdfExpander> { - // def LabeledExtract(salt, label, ikm): - // labeled_ikm = concat("HPKE-v1", suite_id, label, ikm) - // return Extract(salt, labeled_ikm) - - let labeled_ikm = [&b"HPKE-v1"[..], &suite_id.encoded(), label.as_ref(), ikm].concat(); - hkdf.extract_from_secret(salt, &labeled_ikm) -} - -/// See [RFC 9180 §4 "Cryptographic Dependencies"][0]. -/// -/// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-4 -fn labeled_extract_for_prk( - hkdf: &'static dyn HkdfPrkExtract, - suite_id: LabeledSuiteId, - salt: Option<&[u8]>, - label: Label, - ikm: &[u8], -) -> Vec<u8> { - // def LabeledExtract(salt, label, ikm): - // labeled_ikm = concat("HPKE-v1", suite_id, label, ikm) - // return Extract(salt, labeled_ikm) - - let labeled_ikm = [&b"HPKE-v1"[..], &suite_id.encoded(), label.as_ref(), ikm].concat(); - hkdf.extract_prk_from_secret(salt, &labeled_ikm) -} - -/// See [RFC 9180 §4 "Cryptographic Dependencies"][0]. -/// -/// [0]: https://www.rfc-editor.org/rfc/rfc9180.html#section-4 -fn labeled_expand<const L: usize>( - suite_id: LabeledSuiteId, - expander: Box<dyn HkdfExpander>, - label: Label, - kem_context: &[u8], -) -> [u8; L] { - // def LabeledExpand(prk, label, info, L): - // labeled_info = concat(I2OSP(L, 2), "HPKE-v1", suite_id, - // label, info) - // return Expand(prk, labeled_info, L) - - let output_len = u16::to_be_bytes(L as u16); - let info = &[ - &output_len[..], - b"HPKE-v1", - &suite_id.encoded(), - label.as_ref(), - kem_context, - ]; - - expand(&*expander, info) -} - -/// Label describes the possible labels for use with [labeled_extract_for_expand] and [labeled_expand]. -#[derive(Debug)] -enum Label { - PskIdHash, - InfoHash, - Secret, - Key, - BaseNonce, - EaePrk, - SharedSecret, -} - -impl AsRef<[u8]> for Label { - fn as_ref(&self) -> &[u8] { - match self { - Self::PskIdHash => b"psk_id_hash", - Self::InfoHash => b"info_hash", - Self::Secret => b"secret", - Self::Key => b"key", - Self::BaseNonce => b"base_nonce", - Self::EaePrk => b"eae_prk", - Self::SharedSecret => b"shared_secret", - } - } -} - -/// LabeledSuiteId describes the possible suite ID values for use with [labeled_extract_for_expand] and -/// [labeled_expand]. -#[derive(Debug, Copy, Clone)] -enum LabeledSuiteId { - Hpke(HpkeSuite), - Kem(HpkeKem), -} - -impl LabeledSuiteId { - /// The suite ID encoding depends on the context of use. In the general HPKE context, - /// we use a "HPKE" prefix and encode the entire ciphersuite. In the KEM context we use a - /// "KEM" prefix and only encode the KEM ID. - /// - /// See the bottom of [RFC 9180 §4](https://www.rfc-editor.org/rfc/rfc9180.html#section-4) - /// for more information. - fn encoded(&self) -> Vec<u8> { - match self { - Self::Hpke(suite) => [ - &b"HPKE"[..], - &u16::from(suite.kem).to_be_bytes(), - &u16::from(suite.sym.kdf_id).to_be_bytes(), - &u16::from(suite.sym.aead_id).to_be_bytes(), - ] - .concat(), - Self::Kem(kem) => [&b"KEM"[..], &u16::from(*kem).to_be_bytes()].concat(), - } - } -} - -/// A newtype wrapper for an unbound AEAD key. -struct AeadKey<const KEY_LEN: usize>([u8; KEY_LEN]); - -impl<const KEY_LEN: usize> Drop for AeadKey<KEY_LEN> { - fn drop(&mut self) { - self.0.zeroize() - } -} - -/// A newtype wrapper for a DH KEM shared secret. -struct KemSharedSecret<const KDF_LEN: usize>([u8; KDF_LEN]); - -impl<const KDF_LEN: usize> Drop for KemSharedSecret<KDF_LEN> { - fn drop(&mut self) { - self.0.zeroize(); - } -} - -fn key_rejected_err(_e: aws_lc_rs::error::KeyRejected) -> Error { - #[cfg(feature = "std")] - { - Error::Other(OtherError(Arc::new(_e))) - } - #[cfg(not(feature = "std"))] - { - Error::Other(OtherError()) - } -} - -// The `cipher::chacha::KEY_LEN` const is not exported, so we copy it here: -// https://github.com/aws/aws-lc-rs/blob/0186ef7bb1a4d7e140bae8074a9871f49afedf1b/aws-lc-rs/src/cipher/chacha.rs#L13 -const CHACHA_KEY_LEN: usize = 32; - -static RING_HKDF_HMAC_SHA256: &HkdfUsingHmac<'static> = &HkdfUsingHmac(&HMAC_SHA256); -static RING_HKDF_HMAC_SHA384: &HkdfUsingHmac<'static> = &HkdfUsingHmac(&HMAC_SHA384); -static RING_HKDF_HMAC_SHA512: &HkdfUsingHmac<'static> = &HkdfUsingHmac(&HMAC_SHA512); - -#[cfg(test)] -mod tests { - use alloc::{format, vec}; - - use super::*; - - #[test] - fn smoke_test() { - for suite in ALL_SUPPORTED_SUITES { - _ = format!("{suite:?}"); // HpkeAwsLcRs suites should be Debug. - - // We should be able to generate a random keypair. - let (pk, sk) = suite.generate_key_pair().unwrap(); - - // Info value corresponds to the first RFC 9180 base mode test vector. - let info = &[ - 0x4f, 0x64, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x47, 0x72, 0x65, 0x63, 0x69, - 0x61, 0x6e, 0x20, 0x55, 0x72, 0x6e, - ][..]; - - // We should be able to set up a sealer. - let (enc, mut sealer) = suite.setup_sealer(info, &pk).unwrap(); - - _ = format!("{sealer:?}"); // Sealer should be Debug. - - // Setting up a sealer with an invalid public key should fail. - let bad_setup_res = suite.setup_sealer(info, &HpkePublicKey(vec![])); - assert!(matches!(bad_setup_res.unwrap_err(), Error::Other(_))); - - // We should be able to seal some plaintext. - let aad = &[0xC0, 0xFF, 0xEE]; - let pt = &[0xF0, 0x0D]; - let ct = sealer.seal(aad, pt).unwrap(); - - // We should be able to set up an opener. - let mut opener = suite - .setup_opener(&enc, info, &sk) - .unwrap(); - _ = format!("{opener:?}"); // Opener should be Debug. - - // Setting up an opener with an invalid private key should fail. - let bad_key_res = suite.setup_opener(&enc, info, &HpkePrivateKey::from(vec![])); - assert!(matches!(bad_key_res.unwrap_err(), Error::Other(_))); - - // Opening the plaintext should work with the correct opener and aad. - let pt_prime = opener.open(aad, &ct).unwrap(); - assert_eq!(pt_prime, pt); - - // Opening the plaintext with the correct opener and wrong aad should fail. - let open_res = opener.open(&[0x0], &ct); - assert!(matches!(open_res.unwrap_err(), Error::Other(_))); - - // Opening the plaintext with the wrong opener should fail. - let mut sk_rm_prime = sk.secret_bytes().to_vec(); - sk_rm_prime[10] ^= 0xFF; // Corrupt a byte of the private key. - let mut opener_two = suite - .setup_opener(&enc, info, &HpkePrivateKey::from(sk_rm_prime)) - .unwrap(); - let open_res = opener_two.open(aad, &ct); - assert!(matches!(open_res.unwrap_err(), Error::Other(_))); - } - } - - #[cfg(not(feature = "fips"))] // Ensure all supported suites are available to test. - #[test] - fn test_fips() { - let testcases: &[(&dyn Hpke, bool)] = &[ - // FIPS compatible. - (DH_KEM_P256_HKDF_SHA256_AES_128, true), - (DH_KEM_P256_HKDF_SHA256_AES_256, true), - (DH_KEM_P384_HKDF_SHA384_AES_128, true), - (DH_KEM_P384_HKDF_SHA384_AES_256, true), - (DH_KEM_P521_HKDF_SHA512_AES_128, true), - (DH_KEM_P521_HKDF_SHA512_AES_256, true), - // AEAD is not FIPS compatible. - (DH_KEM_P256_HKDF_SHA256_CHACHA20_POLY1305, false), - (DH_KEM_P384_HKDF_SHA384_CHACHA20_POLY1305, false), - (DH_KEM_P521_HKDF_SHA512_CHACHA20_POLY1305, false), - // KEM is not FIPS compatible. - (DH_KEM_X25519_HKDF_SHA256_AES_128, false), - (DH_KEM_X25519_HKDF_SHA256_AES_256, false), - (DH_KEM_X25519_HKDF_SHA256_CHACHA20_POLY1305, false), - ]; - for (suite, expected) in testcases { - assert_eq!(suite.fips(), *expected); - } - } -} - -#[cfg(test)] -mod rfc_tests { - use alloc::string::String; - use std::fs::File; - use std::println; - - use serde::Deserialize; - - use super::*; - - /// Confirm open/seal operations work using the test vectors from [RFC 9180 Appendix A]. - /// - /// [RFC 9180 Appendix A]: https://www.rfc-editor.org/rfc/rfc9180#TestVectors - #[test] - fn check_test_vectors() { - for (idx, vec) in test_vectors().into_iter().enumerate() { - let Some(hpke) = vec.applicable() else { - println!("skipping inapplicable vector {idx}"); - continue; - }; - - println!("testing vector {idx}"); - let pk_r = HpkePublicKey(hex::decode(vec.pk_rm).unwrap()); - let sk_r = HpkePrivateKey::from(hex::decode(vec.sk_rm).unwrap()); - let sk_em = hex::decode(vec.sk_em).unwrap(); - let info = hex::decode(vec.info).unwrap(); - let expected_enc = hex::decode(vec.enc).unwrap(); - - let (enc, mut sealer) = hpke - .setup_test_sealer(&info, &pk_r, &sk_em) - .unwrap(); - assert_eq!(enc.0, expected_enc); - - let mut opener = hpke - .setup_opener(&enc, &info, &sk_r) - .unwrap(); - - for test_encryption in vec.encryptions { - let aad = hex::decode(test_encryption.aad).unwrap(); - let pt = hex::decode(test_encryption.pt).unwrap(); - let expected_ct = hex::decode(test_encryption.ct).unwrap(); - - let ciphertext = sealer.seal(&aad, &pt).unwrap(); - assert_eq!(ciphertext, expected_ct); - - let plaintext = opener.open(&aad, &ciphertext).unwrap(); - assert_eq!(plaintext, pt); - } - } - } - - trait TestHpke: Hpke { - fn setup_test_sealer( - &self, - info: &[u8], - pub_key: &HpkePublicKey, - sk_em: &[u8], - ) -> Result<(EncapsulatedSecret, Box<dyn HpkeSealer + 'static>), Error>; - } - - impl<const KEY_SIZE: usize, const KDF_SIZE: usize> TestHpke for HpkeAwsLcRs<KEY_SIZE, KDF_SIZE> { - fn setup_test_sealer( - &self, - info: &[u8], - pub_key: &HpkePublicKey, - sk_em: &[u8], - ) -> Result<(EncapsulatedSecret, Box<dyn HpkeSealer + 'static>), Error> { - let (encap, sealer) = Sealer::test_only_new(self, info, pub_key, sk_em)?; - Ok((encap, Box::new(sealer))) - } - } - - static TEST_SUITES: &[&dyn TestHpke] = &[ - DH_KEM_P256_HKDF_SHA256_AES_128, - DH_KEM_P256_HKDF_SHA256_AES_256, - #[cfg(not(feature = "fips"))] - DH_KEM_P256_HKDF_SHA256_CHACHA20_POLY1305, - DH_KEM_P384_HKDF_SHA384_AES_128, - DH_KEM_P384_HKDF_SHA384_AES_256, - #[cfg(not(feature = "fips"))] - DH_KEM_P384_HKDF_SHA384_CHACHA20_POLY1305, - DH_KEM_P521_HKDF_SHA512_AES_128, - DH_KEM_P521_HKDF_SHA512_AES_256, - #[cfg(not(feature = "fips"))] - DH_KEM_P521_HKDF_SHA512_CHACHA20_POLY1305, - #[cfg(not(feature = "fips"))] - DH_KEM_X25519_HKDF_SHA256_AES_128, - #[cfg(not(feature = "fips"))] - DH_KEM_X25519_HKDF_SHA256_AES_256, - #[cfg(not(feature = "fips"))] - DH_KEM_X25519_HKDF_SHA256_CHACHA20_POLY1305, - ]; - - #[derive(Deserialize, Debug)] - struct TestVector { - mode: u8, - kem_id: u16, - kdf_id: u16, - aead_id: u16, - info: String, - #[serde(rename(deserialize = "pkRm"))] - pk_rm: String, - #[serde(rename(deserialize = "skRm"))] - sk_rm: String, - #[serde(rename(deserialize = "skEm"))] - sk_em: String, - enc: String, - encryptions: Vec<TestEncryption>, - } - - #[derive(Deserialize, Debug)] - struct TestEncryption { - aad: String, - pt: String, - ct: String, - } - - impl TestVector { - fn suite(&self) -> HpkeSuite { - HpkeSuite { - kem: HpkeKem::from(self.kem_id), - sym: HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::from(self.kdf_id), - aead_id: HpkeAead::from(self.aead_id), - }, - } - } - - fn applicable(&self) -> Option<&'static dyn TestHpke> { - // Only base mode test vectors for supported suites are applicable. - if self.mode != 0 { - return None; - } - - Self::lookup_suite(self.suite(), TEST_SUITES) - } - - fn lookup_suite( - suite: HpkeSuite, - supported: &[&'static dyn TestHpke], - ) -> Option<&'static dyn TestHpke> { - supported - .iter() - .find(|s| s.suite() == suite) - .copied() - } - } - - fn test_vectors() -> Vec<TestVector> { - serde_json::from_reader( - &mut File::open("../rustls-provider-test/tests/rfc-9180-test-vectors.json") - .expect("failed to open test vectors data file"), - ) - .expect("failed to deserialize test vectors") - } -} diff --git a/vendor/rustls/src/crypto/aws_lc_rs/mod.rs b/vendor/rustls/src/crypto/aws_lc_rs/mod.rs deleted file mode 100644 index 1a7d2263..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/mod.rs +++ /dev/null @@ -1,318 +0,0 @@ -use alloc::vec::Vec; - -// aws-lc-rs has a -- roughly -- ring-compatible API, so we just reuse all that -// glue here. The shared files should always use `super::ring_like` to access a -// ring-compatible crate, and `super::ring_shim` to bridge the gaps where they are -// small. -pub(crate) use aws_lc_rs as ring_like; -use pki_types::PrivateKeyDer; -use webpki::aws_lc_rs as webpki_algs; - -use crate::crypto::{CryptoProvider, KeyProvider, SecureRandom, SupportedKxGroup}; -use crate::enums::SignatureScheme; -use crate::rand::GetRandomFailed; -use crate::sign::SigningKey; -use crate::suites::SupportedCipherSuite; -use crate::sync::Arc; -use crate::webpki::WebPkiSupportedAlgorithms; -use crate::{Error, OtherError}; - -/// Hybrid public key encryption (HPKE). -pub mod hpke; -/// Post-quantum secure algorithms. -pub(crate) mod pq; -/// Using software keys for authentication. -pub mod sign; - -#[path = "../ring/hash.rs"] -pub(crate) mod hash; -#[path = "../ring/hmac.rs"] -pub(crate) mod hmac; -#[path = "../ring/kx.rs"] -pub(crate) mod kx; -#[path = "../ring/quic.rs"] -pub(crate) mod quic; -#[cfg(feature = "std")] -pub(crate) mod ticketer; -#[cfg(feature = "tls12")] -pub(crate) mod tls12; -pub(crate) mod tls13; - -/// A `CryptoProvider` backed by aws-lc-rs. -pub fn default_provider() -> CryptoProvider { - CryptoProvider { - cipher_suites: DEFAULT_CIPHER_SUITES.to_vec(), - kx_groups: default_kx_groups(), - signature_verification_algorithms: SUPPORTED_SIG_ALGS, - secure_random: &AwsLcRs, - key_provider: &AwsLcRs, - } -} - -fn default_kx_groups() -> Vec<&'static dyn SupportedKxGroup> { - #[cfg(feature = "fips")] - { - DEFAULT_KX_GROUPS - .iter() - .filter(|cs| cs.fips()) - .copied() - .collect() - } - #[cfg(not(feature = "fips"))] - { - DEFAULT_KX_GROUPS.to_vec() - } -} - -#[derive(Debug)] -struct AwsLcRs; - -impl SecureRandom for AwsLcRs { - fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed> { - use ring_like::rand::SecureRandom; - - ring_like::rand::SystemRandom::new() - .fill(buf) - .map_err(|_| GetRandomFailed) - } - - fn fips(&self) -> bool { - fips() - } -} - -impl KeyProvider for AwsLcRs { - fn load_private_key( - &self, - key_der: PrivateKeyDer<'static>, - ) -> Result<Arc<dyn SigningKey>, Error> { - sign::any_supported_type(&key_der) - } - - fn fips(&self) -> bool { - fips() - } -} - -/// The cipher suite configuration that an application should use by default. -/// -/// This will be [`ALL_CIPHER_SUITES`] sans any supported cipher suites that -/// shouldn't be enabled by most applications. -pub static DEFAULT_CIPHER_SUITES: &[SupportedCipherSuite] = &[ - // TLS1.3 suites - tls13::TLS13_AES_256_GCM_SHA384, - tls13::TLS13_AES_128_GCM_SHA256, - #[cfg(not(feature = "fips"))] - tls13::TLS13_CHACHA20_POLY1305_SHA256, - // TLS1.2 suites - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - #[cfg(all(feature = "tls12", not(feature = "fips")))] - tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - #[cfg(all(feature = "tls12", not(feature = "fips")))] - tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, -]; - -/// A list of all the cipher suites supported by the rustls aws-lc-rs provider. -pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[ - // TLS1.3 suites - tls13::TLS13_AES_256_GCM_SHA384, - tls13::TLS13_AES_128_GCM_SHA256, - tls13::TLS13_CHACHA20_POLY1305_SHA256, - // TLS1.2 suites - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, -]; - -/// All defined cipher suites supported by aws-lc-rs appear in this module. -pub mod cipher_suite { - #[cfg(feature = "tls12")] - pub use super::tls12::{ - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - }; - pub use super::tls13::{ - TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256, - }; -} - -/// A `WebPkiSupportedAlgorithms` value that reflects webpki's capabilities when -/// compiled against aws-lc-rs. -static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { - all: &[ - webpki_algs::ECDSA_P256_SHA256, - webpki_algs::ECDSA_P256_SHA384, - webpki_algs::ECDSA_P384_SHA256, - webpki_algs::ECDSA_P384_SHA384, - webpki_algs::ECDSA_P521_SHA256, - webpki_algs::ECDSA_P521_SHA384, - webpki_algs::ECDSA_P521_SHA512, - webpki_algs::ED25519, - webpki_algs::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, - webpki_algs::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, - webpki_algs::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, - webpki_algs::RSA_PKCS1_2048_8192_SHA256, - webpki_algs::RSA_PKCS1_2048_8192_SHA384, - webpki_algs::RSA_PKCS1_2048_8192_SHA512, - webpki_algs::RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS, - webpki_algs::RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS, - webpki_algs::RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS, - ], - mapping: &[ - // Note: for TLS1.2 the curve is not fixed by SignatureScheme. For TLS1.3 it is. - ( - SignatureScheme::ECDSA_NISTP384_SHA384, - &[ - webpki_algs::ECDSA_P384_SHA384, - webpki_algs::ECDSA_P256_SHA384, - webpki_algs::ECDSA_P521_SHA384, - ], - ), - ( - SignatureScheme::ECDSA_NISTP256_SHA256, - &[ - webpki_algs::ECDSA_P256_SHA256, - webpki_algs::ECDSA_P384_SHA256, - webpki_algs::ECDSA_P521_SHA256, - ], - ), - ( - SignatureScheme::ECDSA_NISTP521_SHA512, - &[webpki_algs::ECDSA_P521_SHA512], - ), - (SignatureScheme::ED25519, &[webpki_algs::ED25519]), - ( - SignatureScheme::RSA_PSS_SHA512, - &[webpki_algs::RSA_PSS_2048_8192_SHA512_LEGACY_KEY], - ), - ( - SignatureScheme::RSA_PSS_SHA384, - &[webpki_algs::RSA_PSS_2048_8192_SHA384_LEGACY_KEY], - ), - ( - SignatureScheme::RSA_PSS_SHA256, - &[webpki_algs::RSA_PSS_2048_8192_SHA256_LEGACY_KEY], - ), - ( - SignatureScheme::RSA_PKCS1_SHA512, - &[webpki_algs::RSA_PKCS1_2048_8192_SHA512], - ), - ( - SignatureScheme::RSA_PKCS1_SHA384, - &[webpki_algs::RSA_PKCS1_2048_8192_SHA384], - ), - ( - SignatureScheme::RSA_PKCS1_SHA256, - &[webpki_algs::RSA_PKCS1_2048_8192_SHA256], - ), - ], -}; - -/// All defined key exchange groups supported by aws-lc-rs appear in this module. -/// -/// [`ALL_KX_GROUPS`] is provided as an array of all of these values. -/// [`DEFAULT_KX_GROUPS`] is provided as an array of this provider's defaults. -pub mod kx_group { - pub use super::kx::{SECP256R1, SECP384R1, X25519}; - pub use super::pq::{MLKEM768, SECP256R1MLKEM768, X25519MLKEM768}; -} - -/// A list of the default key exchange groups supported by this provider. -/// -/// This does not contain MLKEM768; by default MLKEM768 is only offered -/// in hybrid with X25519. -pub static DEFAULT_KX_GROUPS: &[&dyn SupportedKxGroup] = &[ - #[cfg(feature = "prefer-post-quantum")] - kx_group::X25519MLKEM768, - kx_group::X25519, - kx_group::SECP256R1, - kx_group::SECP384R1, - #[cfg(not(feature = "prefer-post-quantum"))] - kx_group::X25519MLKEM768, -]; - -/// A list of all the key exchange groups supported by this provider. -pub static ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = &[ - #[cfg(feature = "prefer-post-quantum")] - kx_group::X25519MLKEM768, - #[cfg(feature = "prefer-post-quantum")] - kx_group::SECP256R1MLKEM768, - kx_group::X25519, - kx_group::SECP256R1, - kx_group::SECP384R1, - #[cfg(not(feature = "prefer-post-quantum"))] - kx_group::X25519MLKEM768, - #[cfg(not(feature = "prefer-post-quantum"))] - kx_group::SECP256R1MLKEM768, - kx_group::MLKEM768, -]; - -#[cfg(feature = "std")] -pub use ticketer::Ticketer; - -/// Compatibility shims between ring 0.16.x and 0.17.x API -mod ring_shim { - use super::ring_like; - use crate::crypto::SharedSecret; - - pub(super) fn agree_ephemeral( - priv_key: ring_like::agreement::EphemeralPrivateKey, - peer_key: &ring_like::agreement::UnparsedPublicKey<&[u8]>, - ) -> Result<SharedSecret, ()> { - ring_like::agreement::agree_ephemeral(priv_key, peer_key, (), |secret| { - Ok(SharedSecret::from(secret)) - }) - } -} - -/// Are we in FIPS mode? -pub(super) fn fips() -> bool { - aws_lc_rs::try_fips_mode().is_ok() -} - -pub(super) fn unspecified_err(_e: aws_lc_rs::error::Unspecified) -> Error { - #[cfg(feature = "std")] - { - Error::Other(OtherError(Arc::new(_e))) - } - #[cfg(not(feature = "std"))] - { - Error::Other(OtherError()) - } -} - -#[cfg(test)] -mod tests { - #[cfg(feature = "fips")] - #[test] - fn default_suites_are_fips() { - assert!( - super::DEFAULT_CIPHER_SUITES - .iter() - .all(|scs| scs.fips()) - ); - } - - #[cfg(not(feature = "fips"))] - #[test] - fn default_suites() { - assert_eq!(super::DEFAULT_CIPHER_SUITES, super::ALL_CIPHER_SUITES); - } -} diff --git a/vendor/rustls/src/crypto/aws_lc_rs/pq/hybrid.rs b/vendor/rustls/src/crypto/aws_lc_rs/pq/hybrid.rs deleted file mode 100644 index 8e30d782..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/pq/hybrid.rs +++ /dev/null @@ -1,205 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; - -use super::INVALID_KEY_SHARE; -use crate::crypto::{ActiveKeyExchange, CompletedKeyExchange, SharedSecret, SupportedKxGroup}; -use crate::ffdhe_groups::FfdheGroup; -use crate::{Error, NamedGroup, ProtocolVersion}; - -/// A generalization of hybrid key exchange. -#[derive(Debug)] -pub(crate) struct Hybrid { - pub(crate) classical: &'static dyn SupportedKxGroup, - pub(crate) post_quantum: &'static dyn SupportedKxGroup, - pub(crate) name: NamedGroup, - pub(crate) layout: Layout, -} - -impl SupportedKxGroup for Hybrid { - fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> { - let classical = self.classical.start()?; - let post_quantum = self.post_quantum.start()?; - - let combined_pub_key = self - .layout - .concat(post_quantum.pub_key(), classical.pub_key()); - - Ok(Box::new(ActiveHybrid { - classical, - post_quantum, - name: self.name, - layout: self.layout, - combined_pub_key, - })) - } - - fn start_and_complete(&self, client_share: &[u8]) -> Result<CompletedKeyExchange, Error> { - let (post_quantum_share, classical_share) = self - .layout - .split_received_client_share(client_share) - .ok_or(INVALID_KEY_SHARE)?; - - let cl = self - .classical - .start_and_complete(classical_share)?; - let pq = self - .post_quantum - .start_and_complete(post_quantum_share)?; - - let combined_pub_key = self - .layout - .concat(&pq.pub_key, &cl.pub_key); - let secret = self - .layout - .concat(pq.secret.secret_bytes(), cl.secret.secret_bytes()); - - Ok(CompletedKeyExchange { - group: self.name, - pub_key: combined_pub_key, - secret: SharedSecret::from(secret), - }) - } - - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - None - } - - fn name(&self) -> NamedGroup { - self.name - } - - fn fips(&self) -> bool { - // Behold! The Night Mare: SP800-56C rev 2: - // - // "In addition to the currently approved techniques for the generation of the - // shared secret Z as specified in SP 800-56A and SP 800-56B, this Recommendation - // permits the use of a "hybrid" shared secret of the form Z′ = Z || T, a - // concatenation consisting of a "standard" shared secret Z that was generated - // during the execution of a key-establishment scheme (as currently specified in - // [SP 800-56A] or [SP 800-56B])" - // - // NIST plan to adjust this and allow both orders: see - // <https://csrc.nist.gov/pubs/sp/800/227/ipd> (Jan 2025) lines 1070-1080. - // - // But, for now, we follow the SP800-56C logic: the element appearing first is the - // one that controls approval. - match self.layout.post_quantum_first { - true => self.post_quantum.fips(), - false => self.classical.fips(), - } - } - - fn usable_for_version(&self, version: ProtocolVersion) -> bool { - version == ProtocolVersion::TLSv1_3 - } -} - -struct ActiveHybrid { - classical: Box<dyn ActiveKeyExchange>, - post_quantum: Box<dyn ActiveKeyExchange>, - name: NamedGroup, - layout: Layout, - combined_pub_key: Vec<u8>, -} - -impl ActiveKeyExchange for ActiveHybrid { - fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error> { - let (post_quantum_share, classical_share) = self - .layout - .split_received_server_share(peer_pub_key) - .ok_or(INVALID_KEY_SHARE)?; - - let cl = self - .classical - .complete(classical_share)?; - let pq = self - .post_quantum - .complete(post_quantum_share)?; - - let secret = self - .layout - .concat(pq.secret_bytes(), cl.secret_bytes()); - Ok(SharedSecret::from(secret)) - } - - /// Allow the classical computation to be offered and selected separately. - fn hybrid_component(&self) -> Option<(NamedGroup, &[u8])> { - Some((self.classical.group(), self.classical.pub_key())) - } - - fn complete_hybrid_component( - self: Box<Self>, - peer_pub_key: &[u8], - ) -> Result<SharedSecret, Error> { - self.classical.complete(peer_pub_key) - } - - fn pub_key(&self) -> &[u8] { - &self.combined_pub_key - } - - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - None - } - - fn group(&self) -> NamedGroup { - self.name - } -} - -#[derive(Clone, Copy, Debug)] -pub(crate) struct Layout { - /// Length of classical key share. - pub(crate) classical_share_len: usize, - - /// Length of post-quantum key share sent by client - pub(crate) post_quantum_client_share_len: usize, - - /// Length of post-quantum key share sent by server - pub(crate) post_quantum_server_share_len: usize, - - /// Whether the post-quantum element comes first in shares and secrets. - /// - /// For dismal and unprincipled reasons, SECP256R1MLKEM768 has the - /// classical element first, while X25519MLKEM768 has it second. - pub(crate) post_quantum_first: bool, -} - -impl Layout { - fn split_received_client_share<'a>(&self, share: &'a [u8]) -> Option<(&'a [u8], &'a [u8])> { - self.split(share, self.post_quantum_client_share_len) - } - - fn split_received_server_share<'a>(&self, share: &'a [u8]) -> Option<(&'a [u8], &'a [u8])> { - self.split(share, self.post_quantum_server_share_len) - } - - /// Return the PQ and classical component of a key share. - fn split<'a>( - &self, - share: &'a [u8], - post_quantum_share_len: usize, - ) -> Option<(&'a [u8], &'a [u8])> { - if share.len() != self.classical_share_len + post_quantum_share_len { - return None; - } - - Some(match self.post_quantum_first { - true => { - let (first_share, second_share) = share.split_at(post_quantum_share_len); - (first_share, second_share) - } - false => { - let (first_share, second_share) = share.split_at(self.classical_share_len); - (second_share, first_share) - } - }) - } - - fn concat(&self, post_quantum: &[u8], classical: &[u8]) -> Vec<u8> { - match self.post_quantum_first { - true => [post_quantum, classical].concat(), - false => [classical, post_quantum].concat(), - } - } -} diff --git a/vendor/rustls/src/crypto/aws_lc_rs/pq/mlkem.rs b/vendor/rustls/src/crypto/aws_lc_rs/pq/mlkem.rs deleted file mode 100644 index fa2be078..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/pq/mlkem.rs +++ /dev/null @@ -1,103 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; - -use aws_lc_rs::kem; - -use super::INVALID_KEY_SHARE; -use crate::crypto::{ActiveKeyExchange, CompletedKeyExchange, SharedSecret, SupportedKxGroup}; -use crate::ffdhe_groups::FfdheGroup; -use crate::{Error, NamedGroup, ProtocolVersion}; - -#[derive(Debug)] -pub(crate) struct MlKem768; - -impl SupportedKxGroup for MlKem768 { - fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> { - let decaps_key = kem::DecapsulationKey::generate(&kem::ML_KEM_768) - .map_err(|_| Error::General("key generation failed".into()))?; - - let pub_key_bytes = decaps_key - .encapsulation_key() - .and_then(|encaps_key| encaps_key.key_bytes()) - .map_err(|_| Error::General("encaps failed".into()))?; - - Ok(Box::new(Active { - decaps_key: Box::new(decaps_key), - encaps_key_bytes: Vec::from(pub_key_bytes.as_ref()), - })) - } - - fn start_and_complete(&self, client_share: &[u8]) -> Result<CompletedKeyExchange, Error> { - let encaps_key = kem::EncapsulationKey::new(&kem::ML_KEM_768, client_share) - .map_err(|_| INVALID_KEY_SHARE)?; - - let (ciphertext, shared_secret) = encaps_key - .encapsulate() - .map_err(|_| INVALID_KEY_SHARE)?; - - Ok(CompletedKeyExchange { - group: self.name(), - pub_key: Vec::from(ciphertext.as_ref()), - secret: SharedSecret::from(shared_secret.as_ref()), - }) - } - - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - None - } - - fn name(&self) -> NamedGroup { - NamedGroup::MLKEM768 - } - - fn fips(&self) -> bool { - // AUDITORS: - // At the time of writing, the ML-KEM implementation in AWS-LC-FIPS module 3.0 - // is FIPS-pending. Some regulatory regimes (eg, FedRAMP rev 5 SC-13) allow - // use of implementations in this state, as if they are already approved. - // - // We follow this liberal interpretation, and say MlKem768 is FIPS-compliant - // if the underlying library is in FIPS mode. - // - // TODO: adjust the `fips()` function return type to allow more policies to - // be expressed, perhaps following something like - // <https://github.com/golang/go/issues/70200#issuecomment-2490017956> -- - // see <https://github.com/rustls/rustls/issues/2309> - super::super::fips() - } - - fn usable_for_version(&self, version: ProtocolVersion) -> bool { - version == ProtocolVersion::TLSv1_3 - } -} - -struct Active { - decaps_key: Box<kem::DecapsulationKey<kem::AlgorithmId>>, - encaps_key_bytes: Vec<u8>, -} - -impl ActiveKeyExchange for Active { - // The received 'peer_pub_key' is actually the ML-KEM ciphertext, - // which when decapsulated with our `decaps_key` produces the shared - // secret. - fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error> { - let shared_secret = self - .decaps_key - .decapsulate(peer_pub_key.into()) - .map_err(|_| INVALID_KEY_SHARE)?; - - Ok(SharedSecret::from(shared_secret.as_ref())) - } - - fn pub_key(&self) -> &[u8] { - &self.encaps_key_bytes - } - - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - None - } - - fn group(&self) -> NamedGroup { - NamedGroup::MLKEM768 - } -} diff --git a/vendor/rustls/src/crypto/aws_lc_rs/pq/mod.rs b/vendor/rustls/src/crypto/aws_lc_rs/pq/mod.rs deleted file mode 100644 index a2252da5..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/pq/mod.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::crypto::SupportedKxGroup; -use crate::crypto::aws_lc_rs::kx_group; -use crate::{Error, NamedGroup, PeerMisbehaved}; - -mod hybrid; -mod mlkem; - -/// This is the [X25519MLKEM768] key exchange. -/// -/// [X25519MLKEM768]: <https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/> -pub static X25519MLKEM768: &dyn SupportedKxGroup = &hybrid::Hybrid { - classical: kx_group::X25519, - post_quantum: MLKEM768, - name: NamedGroup::X25519MLKEM768, - layout: hybrid::Layout { - classical_share_len: X25519_LEN, - post_quantum_client_share_len: MLKEM768_ENCAP_LEN, - post_quantum_server_share_len: MLKEM768_CIPHERTEXT_LEN, - post_quantum_first: true, - }, -}; - -/// This is the [SECP256R1MLKEM768] key exchange. -/// -/// [SECP256R1MLKEM768]: <https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/> -pub static SECP256R1MLKEM768: &dyn SupportedKxGroup = &hybrid::Hybrid { - classical: kx_group::SECP256R1, - post_quantum: MLKEM768, - name: NamedGroup::secp256r1MLKEM768, - layout: hybrid::Layout { - classical_share_len: SECP256R1_LEN, - post_quantum_client_share_len: MLKEM768_ENCAP_LEN, - post_quantum_server_share_len: MLKEM768_CIPHERTEXT_LEN, - post_quantum_first: false, - }, -}; - -/// This is the [MLKEM] key exchange. -/// -/// [MLKEM]: https://datatracker.ietf.org/doc/draft-connolly-tls-mlkem-key-agreement -pub static MLKEM768: &dyn SupportedKxGroup = &mlkem::MlKem768; - -const INVALID_KEY_SHARE: Error = Error::PeerMisbehaved(PeerMisbehaved::InvalidKeyShare); - -const X25519_LEN: usize = 32; -const SECP256R1_LEN: usize = 65; -const MLKEM768_CIPHERTEXT_LEN: usize = 1088; -const MLKEM768_ENCAP_LEN: usize = 1184; diff --git a/vendor/rustls/src/crypto/aws_lc_rs/sign.rs b/vendor/rustls/src/crypto/aws_lc_rs/sign.rs deleted file mode 100644 index 0c874abf..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/sign.rs +++ /dev/null @@ -1,876 +0,0 @@ -#![allow(clippy::duplicate_mod)] - -use alloc::boxed::Box; -use alloc::string::ToString; -use alloc::vec::Vec; -use alloc::{format, vec}; -use core::fmt::{self, Debug, Formatter}; - -use pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer, SubjectPublicKeyInfoDer, alg_id}; - -use super::ring_like::rand::SystemRandom; -use super::ring_like::signature::{self, EcdsaKeyPair, Ed25519KeyPair, KeyPair, RsaKeyPair}; -use crate::crypto::signer::{Signer, SigningKey, public_key_to_spki}; -use crate::enums::{SignatureAlgorithm, SignatureScheme}; -use crate::error::Error; -use crate::sync::Arc; - -/// Parse `der` as any supported key encoding/type, returning -/// the first which works. -pub fn any_supported_type(der: &PrivateKeyDer<'_>) -> Result<Arc<dyn SigningKey>, Error> { - if let Ok(rsa) = RsaSigningKey::new(der) { - return Ok(Arc::new(rsa)); - } - - if let Ok(ecdsa) = any_ecdsa_type(der) { - return Ok(ecdsa); - } - - if let PrivateKeyDer::Pkcs8(pkcs8) = der { - if let Ok(eddsa) = any_eddsa_type(pkcs8) { - return Ok(eddsa); - } - } - - Err(Error::General( - "failed to parse private key as RSA, ECDSA, or EdDSA".into(), - )) -} - -/// Parse `der` as any ECDSA key type, returning the first which works. -/// -/// Both SEC1 (PEM section starting with 'BEGIN EC PRIVATE KEY') and PKCS8 -/// (PEM section starting with 'BEGIN PRIVATE KEY') encodings are supported. -pub fn any_ecdsa_type(der: &PrivateKeyDer<'_>) -> Result<Arc<dyn SigningKey>, Error> { - if let Ok(ecdsa_p256) = EcdsaSigningKey::new( - der, - SignatureScheme::ECDSA_NISTP256_SHA256, - &signature::ECDSA_P256_SHA256_ASN1_SIGNING, - ) { - return Ok(Arc::new(ecdsa_p256)); - } - - if let Ok(ecdsa_p384) = EcdsaSigningKey::new( - der, - SignatureScheme::ECDSA_NISTP384_SHA384, - &signature::ECDSA_P384_SHA384_ASN1_SIGNING, - ) { - return Ok(Arc::new(ecdsa_p384)); - } - - if let Ok(ecdsa_p521) = EcdsaSigningKey::new( - der, - SignatureScheme::ECDSA_NISTP521_SHA512, - &signature::ECDSA_P521_SHA512_ASN1_SIGNING, - ) { - return Ok(Arc::new(ecdsa_p521)); - } - - Err(Error::General( - "failed to parse ECDSA private key as PKCS#8 or SEC1".into(), - )) -} - -/// Parse `der` as any EdDSA key type, returning the first which works. -/// -/// Note that, at the time of writing, Ed25519 does not have wide support -/// in browsers. It is also not supported by the WebPKI, because the -/// CA/Browser Forum Baseline Requirements do not support it for publicly -/// trusted certificates. -pub fn any_eddsa_type(der: &PrivatePkcs8KeyDer<'_>) -> Result<Arc<dyn SigningKey>, Error> { - // TODO: Add support for Ed448 - Ok(Arc::new(Ed25519SigningKey::new( - der, - SignatureScheme::ED25519, - )?)) -} - -/// A `SigningKey` for RSA-PKCS1 or RSA-PSS. -/// -/// This is used by the test suite, so it must be `pub`, but it isn't part of -/// the public, stable, API. -#[doc(hidden)] -pub struct RsaSigningKey { - key: Arc<RsaKeyPair>, -} - -static ALL_RSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA256, -]; - -impl RsaSigningKey { - /// Make a new `RsaSigningKey` from a DER encoding, in either - /// PKCS#1 or PKCS#8 format. - pub fn new(der: &PrivateKeyDer<'_>) -> Result<Self, Error> { - let key_pair = match der { - PrivateKeyDer::Pkcs1(pkcs1) => RsaKeyPair::from_der(pkcs1.secret_pkcs1_der()), - PrivateKeyDer::Pkcs8(pkcs8) => RsaKeyPair::from_pkcs8(pkcs8.secret_pkcs8_der()), - _ => { - return Err(Error::General( - "failed to parse RSA private key as either PKCS#1 or PKCS#8".into(), - )); - } - } - .map_err(|key_rejected| { - Error::General(format!("failed to parse RSA private key: {key_rejected}")) - })?; - - Ok(Self { - key: Arc::new(key_pair), - }) - } -} - -impl SigningKey for RsaSigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> { - ALL_RSA_SCHEMES - .iter() - .find(|scheme| offered.contains(scheme)) - .map(|scheme| RsaSigner::new(self.key.clone(), *scheme)) - } - - fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> { - Some(public_key_to_spki( - &alg_id::RSA_ENCRYPTION, - self.key.public_key(), - )) - } - - fn algorithm(&self) -> SignatureAlgorithm { - SignatureAlgorithm::RSA - } -} - -impl Debug for RsaSigningKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("RsaSigningKey") - .field("algorithm", &self.algorithm()) - .finish() - } -} - -struct RsaSigner { - key: Arc<RsaKeyPair>, - scheme: SignatureScheme, - encoding: &'static dyn signature::RsaEncoding, -} - -impl RsaSigner { - fn new(key: Arc<RsaKeyPair>, scheme: SignatureScheme) -> Box<dyn Signer> { - let encoding: &dyn signature::RsaEncoding = match scheme { - SignatureScheme::RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_SHA256, - SignatureScheme::RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PSS_SHA256 => &signature::RSA_PSS_SHA256, - SignatureScheme::RSA_PSS_SHA384 => &signature::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA512 => &signature::RSA_PSS_SHA512, - _ => unreachable!(), - }; - - Box::new(Self { - key, - scheme, - encoding, - }) - } -} - -impl Signer for RsaSigner { - fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> { - let mut sig = vec![0; self.key.public_modulus_len()]; - - let rng = SystemRandom::new(); - self.key - .sign(self.encoding, &rng, message, &mut sig) - .map(|_| sig) - .map_err(|_| Error::General("signing failed".to_string())) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -impl Debug for RsaSigner { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("RsaSigner") - .field("scheme", &self.scheme) - .finish() - } -} - -/// A SigningKey that uses exactly one TLS-level SignatureScheme -/// and one ring-level signature::SigningAlgorithm. -/// -/// Compare this to RsaSigningKey, which for a particular key is -/// willing to sign with several algorithms. This is quite poor -/// cryptography practice, but is necessary because a given RSA key -/// is expected to work in TLS1.2 (PKCS#1 signatures) and TLS1.3 -/// (PSS signatures) -- nobody is willing to obtain certificates for -/// different protocol versions. -/// -/// Currently this is only implemented for ECDSA keys. -struct EcdsaSigningKey { - key: Arc<EcdsaKeyPair>, - scheme: SignatureScheme, -} - -impl EcdsaSigningKey { - /// Make a new `ECDSASigningKey` from a DER encoding in PKCS#8 or SEC1 - /// format, expecting a key usable with precisely the given signature - /// scheme. - fn new( - der: &PrivateKeyDer<'_>, - scheme: SignatureScheme, - sigalg: &'static signature::EcdsaSigningAlgorithm, - ) -> Result<Self, ()> { - let key_pair = match der { - PrivateKeyDer::Sec1(sec1) => { - EcdsaKeyPair::from_private_key_der(sigalg, sec1.secret_sec1_der()) - .map_err(|_| ())? - } - PrivateKeyDer::Pkcs8(pkcs8) => { - EcdsaKeyPair::from_pkcs8(sigalg, pkcs8.secret_pkcs8_der()).map_err(|_| ())? - } - _ => return Err(()), - }; - - Ok(Self { - key: Arc::new(key_pair), - scheme, - }) - } -} - -impl SigningKey for EcdsaSigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> { - if offered.contains(&self.scheme) { - Some(Box::new(EcdsaSigner { - key: self.key.clone(), - scheme: self.scheme, - })) - } else { - None - } - } - - fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> { - let id = match self.scheme { - SignatureScheme::ECDSA_NISTP256_SHA256 => alg_id::ECDSA_P256, - SignatureScheme::ECDSA_NISTP384_SHA384 => alg_id::ECDSA_P384, - SignatureScheme::ECDSA_NISTP521_SHA512 => alg_id::ECDSA_P521, - _ => unreachable!(), - }; - - Some(public_key_to_spki(&id, self.key.public_key())) - } - - fn algorithm(&self) -> SignatureAlgorithm { - self.scheme.algorithm() - } -} - -impl Debug for EcdsaSigningKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("EcdsaSigningKey") - .field("algorithm", &self.algorithm()) - .finish() - } -} - -struct EcdsaSigner { - key: Arc<EcdsaKeyPair>, - scheme: SignatureScheme, -} - -impl Signer for EcdsaSigner { - fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> { - let rng = SystemRandom::new(); - self.key - .sign(&rng, message) - .map_err(|_| Error::General("signing failed".into())) - .map(|sig| sig.as_ref().into()) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -impl Debug for EcdsaSigner { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("EcdsaSigner") - .field("scheme", &self.scheme) - .finish() - } -} - -/// A SigningKey that uses exactly one TLS-level SignatureScheme -/// and one ring-level signature::SigningAlgorithm. -/// -/// Compare this to RsaSigningKey, which for a particular key is -/// willing to sign with several algorithms. This is quite poor -/// cryptography practice, but is necessary because a given RSA key -/// is expected to work in TLS1.2 (PKCS#1 signatures) and TLS1.3 -/// (PSS signatures) -- nobody is willing to obtain certificates for -/// different protocol versions. -/// -/// Currently this is only implemented for Ed25519 keys. -struct Ed25519SigningKey { - key: Arc<Ed25519KeyPair>, - scheme: SignatureScheme, -} - -impl Ed25519SigningKey { - /// Make a new `Ed25519SigningKey` from a DER encoding in PKCS#8 format, - /// expecting a key usable with precisely the given signature scheme. - fn new(der: &PrivatePkcs8KeyDer<'_>, scheme: SignatureScheme) -> Result<Self, Error> { - match Ed25519KeyPair::from_pkcs8_maybe_unchecked(der.secret_pkcs8_der()) { - Ok(key_pair) => Ok(Self { - key: Arc::new(key_pair), - scheme, - }), - Err(e) => Err(Error::General(format!( - "failed to parse Ed25519 private key: {e}" - ))), - } - } -} - -impl SigningKey for Ed25519SigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> { - if offered.contains(&self.scheme) { - Some(Box::new(Ed25519Signer { - key: self.key.clone(), - scheme: self.scheme, - })) - } else { - None - } - } - - fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> { - Some(public_key_to_spki(&alg_id::ED25519, self.key.public_key())) - } - - fn algorithm(&self) -> SignatureAlgorithm { - self.scheme.algorithm() - } -} - -impl Debug for Ed25519SigningKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Ed25519SigningKey") - .field("algorithm", &self.algorithm()) - .finish() - } -} - -struct Ed25519Signer { - key: Arc<Ed25519KeyPair>, - scheme: SignatureScheme, -} - -impl Signer for Ed25519Signer { - fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> { - Ok(self.key.sign(message).as_ref().into()) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -impl Debug for Ed25519Signer { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Ed25519Signer") - .field("scheme", &self.scheme) - .finish() - } -} - -#[cfg(test)] -mod tests { - use alloc::format; - - use pki_types::{PrivatePkcs1KeyDer, PrivateSec1KeyDer}; - - use super::*; - - #[test] - fn can_load_ecdsa_nistp256_pkcs8() { - let key = - PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/nistp256key.pkcs8.der")[..]); - assert!(any_eddsa_type(&key).is_err()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_load_ecdsa_nistp256_sec1() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp256key.der")[..], - )); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_sign_ecdsa_nistp256() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp256key.der")[..], - )); - - let k = any_supported_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "EcdsaSigningKey { algorithm: ECDSA }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::ECDSA); - - assert!( - k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384]) - .is_none() - ); - let s = k - .choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .unwrap(); - assert_eq!( - format!("{s:?}"), - "EcdsaSigner { scheme: ECDSA_NISTP256_SHA256 }" - ); - assert_eq!(s.scheme(), SignatureScheme::ECDSA_NISTP256_SHA256); - // nb. signature is variable length and asn.1-encoded - assert!( - s.sign(b"hello") - .unwrap() - .starts_with(&[0x30]) - ); - } - - #[test] - fn can_load_ecdsa_nistp384_pkcs8() { - let key = - PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/nistp384key.pkcs8.der")[..]); - assert!(any_eddsa_type(&key).is_err()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_load_ecdsa_nistp384_sec1() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp384key.der")[..], - )); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_sign_ecdsa_nistp384() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp384key.der")[..], - )); - - let k = any_supported_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "EcdsaSigningKey { algorithm: ECDSA }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::ECDSA); - - assert!( - k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .is_none() - ); - let s = k - .choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384]) - .unwrap(); - assert_eq!( - format!("{s:?}"), - "EcdsaSigner { scheme: ECDSA_NISTP384_SHA384 }" - ); - assert_eq!(s.scheme(), SignatureScheme::ECDSA_NISTP384_SHA384); - // nb. signature is variable length and asn.1-encoded - assert!( - s.sign(b"hello") - .unwrap() - .starts_with(&[0x30]) - ); - } - - #[test] - fn can_load_ecdsa_nistp521_pkcs8() { - let key = - PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/nistp521key.pkcs8.der")[..]); - assert!(any_eddsa_type(&key).is_err()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_load_ecdsa_nistp521_sec1() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp521key.der")[..], - )); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_sign_ecdsa_nistp521() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp521key.der")[..], - )); - - let k = any_supported_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "EcdsaSigningKey { algorithm: ECDSA }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::ECDSA); - - assert!( - k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384]) - .is_none() - ); - let s = k - .choose_scheme(&[SignatureScheme::ECDSA_NISTP521_SHA512]) - .unwrap(); - assert_eq!( - format!("{s:?}"), - "EcdsaSigner { scheme: ECDSA_NISTP521_SHA512 }" - ); - assert_eq!(s.scheme(), SignatureScheme::ECDSA_NISTP521_SHA512); - // nb. signature is variable length and asn.1-encoded - assert!( - s.sign(b"hello") - .unwrap() - .starts_with(&[0x30]) - ); - } - - #[test] - fn can_load_eddsa_pkcs8() { - let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]); - assert!(any_eddsa_type(&key).is_ok()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_err()); - } - - #[test] - fn can_sign_eddsa() { - let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]); - - let k = any_eddsa_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "Ed25519SigningKey { algorithm: ED25519 }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::ED25519); - - assert!( - k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .is_none() - ); - let s = k - .choose_scheme(&[SignatureScheme::ED25519]) - .unwrap(); - assert_eq!(format!("{s:?}"), "Ed25519Signer { scheme: ED25519 }"); - assert_eq!(s.scheme(), SignatureScheme::ED25519); - assert_eq!(s.sign(b"hello").unwrap().len(), 64); - } - - #[test] - fn can_load_rsa2048_pkcs8() { - let key = - PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..]); - assert!(any_eddsa_type(&key).is_err()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_err()); - } - - #[test] - fn can_load_rsa2048_pkcs1() { - let key = PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs1.der")[..], - )); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_err()); - } - - #[test] - fn can_sign_rsa2048() { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..], - )); - - let k = any_supported_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "RsaSigningKey { algorithm: RSA }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::RSA); - - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ED25519]) - .is_none() - ); - - let s = k - .choose_scheme(&[SignatureScheme::RSA_PSS_SHA256]) - .unwrap(); - assert_eq!(format!("{s:?}"), "RsaSigner { scheme: RSA_PSS_SHA256 }"); - assert_eq!(s.scheme(), SignatureScheme::RSA_PSS_SHA256); - assert_eq!(s.sign(b"hello").unwrap().len(), 256); - - for scheme in &[ - SignatureScheme::RSA_PKCS1_SHA256, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA512, - ] { - k.choose_scheme(&[*scheme]).unwrap(); - } - } - - #[test] - fn cannot_load_invalid_pkcs8_encoding() { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(&b"invalid"[..])); - assert_eq!( - any_supported_type(&key).err(), - Some(Error::General( - "failed to parse private key as RSA, ECDSA, or EdDSA".into() - )) - ); - assert_eq!( - any_ecdsa_type(&key).err(), - Some(Error::General( - "failed to parse ECDSA private key as PKCS#8 or SEC1".into() - )) - ); - assert_eq!( - RsaSigningKey::new(&key).err(), - Some(Error::General( - "failed to parse RSA private key: InvalidEncoding".into() - )) - ); - } -} - -#[cfg(bench)] -mod benchmarks { - use super::{PrivateKeyDer, PrivatePkcs8KeyDer, SignatureScheme}; - - #[bench] - fn bench_rsa2048_pkcs1_sha256(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_rsa2048_pss_sha256(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::RSA_PSS_SHA256]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_eddsa(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/eddsakey.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::ED25519]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_ecdsa_p256_sha256(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp256key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_ecdsa_p384_sha384(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp384key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_ecdsa_p521_sha512(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp521key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::ECDSA_NISTP521_SHA512]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_load_and_validate_rsa2048(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_supported_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_rsa4096(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa4096key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_supported_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_p256(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp256key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_ecdsa_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_p384(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp384key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_ecdsa_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_p521(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp521key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_ecdsa_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_eddsa(b: &mut test::Bencher) { - let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]); - - b.iter(|| { - test::black_box(super::any_eddsa_type(&key).unwrap()); - }); - } - - const SAMPLE_TLS13_MESSAGE: &[u8] = &[ - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x54, 0x4c, 0x53, 0x20, 0x31, 0x2e, 0x33, 0x2c, 0x20, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x00, 0x04, 0xca, 0xc4, 0x48, 0x0e, 0x70, 0xf2, - 0x1b, 0xa9, 0x1c, 0x16, 0xca, 0x90, 0x48, 0xbe, 0x28, 0x2f, 0xc7, 0xf8, 0x9b, 0x87, 0x72, - 0x93, 0xda, 0x4d, 0x2f, 0x80, 0x80, 0x60, 0x1a, 0xd3, 0x08, 0xe2, 0xb7, 0x86, 0x14, 0x1b, - 0x54, 0xda, 0x9a, 0xc9, 0x6d, 0xe9, 0x66, 0xb4, 0x9f, 0xe2, 0x2c, - ]; -} diff --git a/vendor/rustls/src/crypto/aws_lc_rs/ticketer.rs b/vendor/rustls/src/crypto/aws_lc_rs/ticketer.rs deleted file mode 100644 index 44c7c21b..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/ticketer.rs +++ /dev/null @@ -1,397 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt; -use core::fmt::{Debug, Formatter}; -use core::sync::atomic::{AtomicUsize, Ordering}; - -use aws_lc_rs::cipher::{ - AES_256, AES_256_KEY_LEN, AES_CBC_IV_LEN, DecryptionContext, PaddedBlockDecryptingKey, - PaddedBlockEncryptingKey, UnboundCipherKey, -}; -use aws_lc_rs::{hmac, iv}; - -use super::ring_like::rand::{SecureRandom, SystemRandom}; -use super::unspecified_err; -use crate::error::Error; -#[cfg(debug_assertions)] -use crate::log::debug; -use crate::polyfill::try_split_at; -use crate::rand::GetRandomFailed; -use crate::server::ProducesTickets; -use crate::sync::Arc; - -/// A concrete, safe ticket creation mechanism. -pub struct Ticketer {} - -impl Ticketer { - /// Make the recommended `Ticketer`. This produces tickets - /// with a 12 hour life and randomly generated keys. - /// - /// The `Ticketer` uses the [RFC 5077 §4] "Recommended Ticket Construction", - /// using AES 256 for encryption and HMAC-SHA256 for ciphertext authentication. - /// - /// [RFC 5077 §4]: https://www.rfc-editor.org/rfc/rfc5077#section-4 - #[cfg(feature = "std")] - pub fn new() -> Result<Arc<dyn ProducesTickets>, Error> { - Ok(Arc::new(crate::ticketer::TicketRotator::new( - 6 * 60 * 60, - make_ticket_generator, - )?)) - } -} - -fn make_ticket_generator() -> Result<Box<dyn ProducesTickets>, GetRandomFailed> { - // NOTE(XXX): Unconditionally mapping errors to `GetRandomFailed` here is slightly - // misleading in some cases (e.g. failure to construct a padded block cipher encrypting key). - // However, we can't change the return type expected from a `TicketSwitcher` `generator` - // without breaking semver. - // Tracking in https://github.com/rustls/rustls/issues/2074 - Ok(Box::new( - Rfc5077Ticketer::new().map_err(|_| GetRandomFailed)?, - )) -} - -/// An RFC 5077 "Recommended Ticket Construction" implementation of a [`Ticketer`]. -struct Rfc5077Ticketer { - aes_encrypt_key: PaddedBlockEncryptingKey, - aes_decrypt_key: PaddedBlockDecryptingKey, - hmac_key: hmac::Key, - key_name: [u8; 16], - lifetime: u32, - maximum_ciphertext_len: AtomicUsize, -} - -impl Rfc5077Ticketer { - fn new() -> Result<Self, Error> { - let rand = SystemRandom::new(); - - // Generate a random AES 256 key to use for AES CBC encryption. - let mut aes_key = [0u8; AES_256_KEY_LEN]; - rand.fill(&mut aes_key) - .map_err(|_| GetRandomFailed)?; - - // Convert the raw AES 256 key bytes into encrypting and decrypting keys using CBC mode and - // PKCS#7 padding. We don't want to store just the raw key bytes as constructing the - // cipher keys has some setup overhead. We can't store just the `UnboundCipherKey` since - // constructing the padded encrypt/decrypt specific types consume the `UnboundCipherKey`. - let aes_encrypt_key = - UnboundCipherKey::new(&AES_256, &aes_key[..]).map_err(unspecified_err)?; - let aes_encrypt_key = - PaddedBlockEncryptingKey::cbc_pkcs7(aes_encrypt_key).map_err(unspecified_err)?; - - // Convert the raw AES 256 key bytes into a decrypting key using CBC PKCS#7 padding. - let aes_decrypt_key = - UnboundCipherKey::new(&AES_256, &aes_key[..]).map_err(unspecified_err)?; - let aes_decrypt_key = - PaddedBlockDecryptingKey::cbc_pkcs7(aes_decrypt_key).map_err(unspecified_err)?; - - // Generate a random HMAC SHA256 key to use for HMAC authentication. - let hmac_key = hmac::Key::generate(hmac::HMAC_SHA256, &rand).map_err(unspecified_err)?; - - // Generate a random key name. - let mut key_name = [0u8; 16]; - rand.fill(&mut key_name) - .map_err(|_| GetRandomFailed)?; - - Ok(Self { - aes_encrypt_key, - aes_decrypt_key, - hmac_key, - key_name, - lifetime: 60 * 60 * 12, - maximum_ciphertext_len: AtomicUsize::new(0), - }) - } -} - -impl ProducesTickets for Rfc5077Ticketer { - fn enabled(&self) -> bool { - true - } - - fn lifetime(&self) -> u32 { - self.lifetime - } - - /// Encrypt `message` and return the ciphertext. - fn encrypt(&self, message: &[u8]) -> Option<Vec<u8>> { - // Encrypt the ticket state - the cipher module handles generating a random IV of - // appropriate size, returning it in the `DecryptionContext`. - let mut encrypted_state = Vec::from(message); - let dec_ctx = self - .aes_encrypt_key - .encrypt(&mut encrypted_state) - .ok()?; - let iv: &[u8] = (&dec_ctx).try_into().ok()?; - - // Produce the MAC tag over the relevant context & encrypted state. - // Quoting RFC 5077: - // "The Message Authentication Code (MAC) is calculated using HMAC-SHA-256 over - // key_name (16 octets) and IV (16 octets), followed by the length of - // the encrypted_state field (2 octets) and its contents (variable - // length)." - let mut hmac_data = - Vec::with_capacity(self.key_name.len() + iv.len() + 2 + encrypted_state.len()); - hmac_data.extend(&self.key_name); - hmac_data.extend(iv); - hmac_data.extend( - u16::try_from(encrypted_state.len()) - .ok()? - .to_be_bytes(), - ); - hmac_data.extend(&encrypted_state); - let tag = hmac::sign(&self.hmac_key, &hmac_data); - let tag = tag.as_ref(); - - // Combine the context, the encrypted state, and the tag to produce the final ciphertext. - // Ciphertext structure is: - // key_name: [u8; 16] - // iv: [u8; 16] - // encrypted_state: [u8, _] - // mac tag: [u8; 32] - let mut ciphertext = - Vec::with_capacity(self.key_name.len() + iv.len() + encrypted_state.len() + tag.len()); - ciphertext.extend(self.key_name); - ciphertext.extend(iv); - ciphertext.extend(encrypted_state); - ciphertext.extend(tag); - - self.maximum_ciphertext_len - .fetch_max(ciphertext.len(), Ordering::SeqCst); - - Some(ciphertext) - } - - fn decrypt(&self, ciphertext: &[u8]) -> Option<Vec<u8>> { - if ciphertext.len() - > self - .maximum_ciphertext_len - .load(Ordering::SeqCst) - { - #[cfg(debug_assertions)] - debug!("rejected over-length ticket"); - return None; - } - - // Split off the key name from the remaining ciphertext. - let (alleged_key_name, ciphertext) = try_split_at(ciphertext, self.key_name.len())?; - - // Split off the IV from the remaining ciphertext. - let (iv, ciphertext) = try_split_at(ciphertext, AES_CBC_IV_LEN)?; - - // And finally, split the encrypted state from the tag. - let tag_len = self - .hmac_key - .algorithm() - .digest_algorithm() - .output_len(); - let (enc_state, mac) = try_split_at(ciphertext, ciphertext.len() - tag_len)?; - - // Reconstitute the HMAC data to verify the tag. - let mut hmac_data = - Vec::with_capacity(alleged_key_name.len() + iv.len() + 2 + enc_state.len()); - hmac_data.extend(alleged_key_name); - hmac_data.extend(iv); - hmac_data.extend( - u16::try_from(enc_state.len()) - .ok()? - .to_be_bytes(), - ); - hmac_data.extend(enc_state); - hmac::verify(&self.hmac_key, &hmac_data, mac).ok()?; - - // Convert the raw IV back into an appropriate decryption context. - let iv = iv::FixedLength::try_from(iv).ok()?; - let dec_context = DecryptionContext::Iv128(iv); - - // And finally, decrypt the encrypted state. - let mut out = Vec::from(enc_state); - let plaintext = self - .aes_decrypt_key - .decrypt(&mut out, dec_context) - .ok()?; - - Some(plaintext.into()) - } -} - -impl Debug for Rfc5077Ticketer { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - // Note: we deliberately omit keys from the debug output. - f.debug_struct("Rfc5077Ticketer") - .field("lifetime", &self.lifetime) - .finish() - } -} - -#[cfg(test)] -mod tests { - use core::time::Duration; - - use pki_types::UnixTime; - - use super::*; - - #[test] - fn basic_pairwise_test() { - let t = Ticketer::new().unwrap(); - assert!(t.enabled()); - let cipher = t.encrypt(b"hello world").unwrap(); - let plain = t.decrypt(&cipher).unwrap(); - assert_eq!(plain, b"hello world"); - } - - #[test] - fn refuses_decrypt_before_encrypt() { - let t = Ticketer::new().unwrap(); - assert_eq!(t.decrypt(b"hello"), None); - } - - #[test] - fn refuses_decrypt_larger_than_largest_encryption() { - let t = Ticketer::new().unwrap(); - let mut cipher = t.encrypt(b"hello world").unwrap(); - assert_eq!(t.decrypt(&cipher), Some(b"hello world".to_vec())); - - // obviously this would never work anyway, but this - // and `cannot_decrypt_before_encrypt` exercise the - // first branch in `decrypt()` - cipher.push(0); - assert_eq!(t.decrypt(&cipher), None); - } - - #[test] - fn ticketrotator_switching_test() { - let t = Arc::new(crate::ticketer::TicketRotator::new(1, make_ticket_generator).unwrap()); - let now = UnixTime::now(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - { - // Trigger new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 10, - ))); - } - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - { - // Trigger new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 20, - ))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_none()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); - } - - #[test] - fn ticketrotator_remains_usable_over_temporary_ticketer_creation_failure() { - let mut t = crate::ticketer::TicketRotator::new(1, make_ticket_generator).unwrap(); - let now = UnixTime::now(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - t.generator = fail_generator; - { - // Failed new ticketer; this means we still need to - // rotate. - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 10, - ))); - } - - // check post-failure encryption/decryption still works - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - - // do the rotation for real - t.generator = make_ticket_generator; - { - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 20, - ))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_some()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); - } - - #[test] - fn ticketswitcher_switching_test() { - #[expect(deprecated)] - let t = Arc::new(crate::ticketer::TicketSwitcher::new(1, make_ticket_generator).unwrap()); - let now = UnixTime::now(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - { - // Trigger new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 10, - ))); - } - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - { - // Trigger new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 20, - ))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_none()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); - } - - #[test] - fn ticketswitcher_recover_test() { - #[expect(deprecated)] - let mut t = crate::ticketer::TicketSwitcher::new(1, make_ticket_generator).unwrap(); - let now = UnixTime::now(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - t.generator = fail_generator; - { - // Failed new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 10, - ))); - } - t.generator = make_ticket_generator; - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - { - // recover - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 20, - ))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_none()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); - } - - #[test] - fn rfc5077ticketer_is_debug_and_producestickets() { - use alloc::format; - - use super::*; - - let t = make_ticket_generator().unwrap(); - - assert_eq!(format!("{t:?}"), "Rfc5077Ticketer { lifetime: 43200 }"); - assert!(t.enabled()); - assert_eq!(t.lifetime(), 43200); - } - - fn fail_generator() -> Result<Box<dyn ProducesTickets>, GetRandomFailed> { - Err(GetRandomFailed) - } -} diff --git a/vendor/rustls/src/crypto/aws_lc_rs/tls12.rs b/vendor/rustls/src/crypto/aws_lc_rs/tls12.rs deleted file mode 100644 index 3845af58..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/tls12.rs +++ /dev/null @@ -1,465 +0,0 @@ -use alloc::boxed::Box; - -use aws_lc_rs::{aead, tls_prf}; - -use crate::crypto::cipher::{ - AeadKey, InboundOpaqueMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter, - NONCE_LEN, Nonce, Tls12AeadAlgorithm, UnsupportedOperationError, make_tls12_aad, -}; -use crate::crypto::tls12::Prf; -use crate::crypto::{ActiveKeyExchange, KeyExchangeAlgorithm}; -use crate::enums::{CipherSuite, SignatureScheme}; -use crate::error::Error; -use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; -use crate::msgs::message::{ - InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, -}; -use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; -use crate::tls12::Tls12CipherSuite; -use crate::version::TLS12; - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256. -pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: u64::MAX, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - aead_alg: &ChaCha20Poly1305, - prf_provider: &Tls12Prf(&tls_prf::P_SHA256), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 -pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: u64::MAX, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - aead_alg: &ChaCha20Poly1305, - prf_provider: &Tls12Prf(&tls_prf::P_SHA256), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 -pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: 1 << 24, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - aead_alg: &AES128_GCM, - prf_provider: &Tls12Prf(&tls_prf::P_SHA256), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 -pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - hash_provider: &super::hash::SHA384, - confidentiality_limit: 1 << 24, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - aead_alg: &AES256_GCM, - prf_provider: &Tls12Prf(&tls_prf::P_SHA384), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 -pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: 1 << 24, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - aead_alg: &AES128_GCM, - prf_provider: &Tls12Prf(&tls_prf::P_SHA256), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 -pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - hash_provider: &super::hash::SHA384, - confidentiality_limit: 1 << 24, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - aead_alg: &AES256_GCM, - prf_provider: &Tls12Prf(&tls_prf::P_SHA384), - }); - -static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::ED25519, - SignatureScheme::ECDSA_NISTP521_SHA512, - SignatureScheme::ECDSA_NISTP384_SHA384, - SignatureScheme::ECDSA_NISTP256_SHA256, -]; - -static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA256, -]; - -pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM); -pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM); - -pub(crate) struct GcmAlgorithm(&'static aead::Algorithm); - -impl Tls12AeadAlgorithm for GcmAlgorithm { - fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> { - // safety: see `encrypter()`. - let dec_key = - aead::TlsRecordOpeningKey::new(self.0, aead::TlsProtocolId::TLS12, dec_key.as_ref()) - .unwrap(); - - let mut ret = GcmMessageDecrypter { - dec_key, - dec_salt: [0u8; 4], - }; - - debug_assert_eq!(dec_iv.len(), 4); - ret.dec_salt.copy_from_slice(dec_iv); - Box::new(ret) - } - - fn encrypter( - &self, - enc_key: AeadKey, - write_iv: &[u8], - explicit: &[u8], - ) -> Box<dyn MessageEncrypter> { - // safety: `TlsRecordSealingKey::new` fails if - // - `enc_key`'s length is wrong for `algorithm`. But the length is defined by - // `algorithm.key_len()` in `key_block_shape()`, below. - // - `algorithm` is not supported: but `AES_128_GCM` and `AES_256_GCM` is. - // thus, this `unwrap()` is unreachable. - // - // `TlsProtocolId::TLS13` is deliberate: we reuse the nonce construction from - // RFC7905 and TLS13: a random starting point, XOR'd with the sequence number. This means - // `TlsProtocolId::TLS12` (which wants to see a plain sequence number) is unsuitable. - // - // The most important property is that nonce is unique per key, which is satisfied by - // this construction, even if the nonce is not monotonically increasing. - let enc_key = - aead::TlsRecordSealingKey::new(self.0, aead::TlsProtocolId::TLS13, enc_key.as_ref()) - .unwrap(); - let iv = gcm_iv(write_iv, explicit); - Box::new(GcmMessageEncrypter { enc_key, iv }) - } - - fn key_block_shape(&self) -> KeyBlockShape { - KeyBlockShape { - enc_key_len: self.0.key_len(), - fixed_iv_len: 4, - explicit_nonce_len: 8, - } - } - - fn extract_keys( - &self, - key: AeadKey, - write_iv: &[u8], - explicit: &[u8], - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - let iv = gcm_iv(write_iv, explicit); - Ok(match self.0.key_len() { - 16 => ConnectionTrafficSecrets::Aes128Gcm { key, iv }, - 32 => ConnectionTrafficSecrets::Aes256Gcm { key, iv }, - _ => unreachable!(), - }) - } - - fn fips(&self) -> bool { - super::fips() - } -} - -pub(crate) struct ChaCha20Poly1305; - -impl Tls12AeadAlgorithm for ChaCha20Poly1305 { - fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> { - let dec_key = aead::LessSafeKey::new( - aead::UnboundKey::new(&aead::CHACHA20_POLY1305, dec_key.as_ref()).unwrap(), - ); - Box::new(ChaCha20Poly1305MessageDecrypter { - dec_key, - dec_offset: Iv::copy(iv), - }) - } - - fn encrypter(&self, enc_key: AeadKey, enc_iv: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> { - let enc_key = aead::LessSafeKey::new( - aead::UnboundKey::new(&aead::CHACHA20_POLY1305, enc_key.as_ref()).unwrap(), - ); - Box::new(ChaCha20Poly1305MessageEncrypter { - enc_key, - enc_offset: Iv::copy(enc_iv), - }) - } - - fn key_block_shape(&self) -> KeyBlockShape { - KeyBlockShape { - enc_key_len: 32, - fixed_iv_len: 12, - explicit_nonce_len: 0, - } - } - - fn extract_keys( - &self, - key: AeadKey, - iv: &[u8], - _explicit: &[u8], - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - // This should always be true because KeyBlockShape and the Iv nonce len are in agreement. - debug_assert_eq!(aead::NONCE_LEN, iv.len()); - Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { - key, - iv: Iv::new(iv[..].try_into().unwrap()), - }) - } - - fn fips(&self) -> bool { - false // not FIPS approved - } -} - -/// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only. -struct GcmMessageEncrypter { - enc_key: aead::TlsRecordSealingKey, - iv: Iv, -} - -/// A `MessageDecrypter` for AES-GCM AEAD ciphersuites. TLS1.2 only. -struct GcmMessageDecrypter { - dec_key: aead::TlsRecordOpeningKey, - dec_salt: [u8; 4], -} - -const GCM_EXPLICIT_NONCE_LEN: usize = 8; -const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16; - -impl MessageDecrypter for GcmMessageDecrypter { - fn decrypt<'a>( - &mut self, - mut msg: InboundOpaqueMessage<'a>, - seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - let payload = &msg.payload; - if payload.len() < GCM_OVERHEAD { - return Err(Error::DecryptError); - } - - let nonce = { - let mut nonce = [0u8; 12]; - nonce[..4].copy_from_slice(&self.dec_salt); - nonce[4..].copy_from_slice(&payload[..8]); - aead::Nonce::assume_unique_for_key(nonce) - }; - - let aad = aead::Aad::from(make_tls12_aad( - seq, - msg.typ, - msg.version, - payload.len() - GCM_OVERHEAD, - )); - - let payload = &mut msg.payload; - let plain_len = self - .dec_key - .open_in_place(nonce, aad, &mut payload[GCM_EXPLICIT_NONCE_LEN..]) - .map_err(|_| Error::DecryptError)? - .len(); - - if plain_len > MAX_FRAGMENT_LEN { - return Err(Error::PeerSentOversizedRecord); - } - - Ok( - msg.into_plain_message_range( - GCM_EXPLICIT_NONCE_LEN..GCM_EXPLICIT_NONCE_LEN + plain_len, - ), - ) - } -} - -impl MessageEncrypter for GcmMessageEncrypter { - fn encrypt( - &mut self, - msg: OutboundPlainMessage<'_>, - seq: u64, - ) -> Result<OutboundOpaqueMessage, Error> { - let total_len = self.encrypted_payload_len(msg.payload.len()); - let mut payload = PrefixedPayload::with_capacity(total_len); - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); - let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len())); - payload.extend_from_slice(&nonce.as_ref()[4..]); - payload.extend_from_chunks(&msg.payload); - - self.enc_key - .seal_in_place_separate_tag(nonce, aad, &mut payload.as_mut()[GCM_EXPLICIT_NONCE_LEN..]) - .map(|tag| payload.extend_from_slice(tag.as_ref())) - .map_err(|_| Error::EncryptError)?; - - Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload)) - } - - fn encrypted_payload_len(&self, payload_len: usize) -> usize { - payload_len + GCM_EXPLICIT_NONCE_LEN + self.enc_key.algorithm().tag_len() - } -} - -/// The RFC7905/RFC7539 ChaCha20Poly1305 construction. -/// This implementation does the AAD construction required in TLS1.2. -/// TLS1.3 uses `TLS13MessageEncrypter`. -struct ChaCha20Poly1305MessageEncrypter { - enc_key: aead::LessSafeKey, - enc_offset: Iv, -} - -/// The RFC7905/RFC7539 ChaCha20Poly1305 construction. -/// This implementation does the AAD construction required in TLS1.2. -/// TLS1.3 uses `TLS13MessageDecrypter`. -struct ChaCha20Poly1305MessageDecrypter { - dec_key: aead::LessSafeKey, - dec_offset: Iv, -} - -const CHACHAPOLY1305_OVERHEAD: usize = 16; - -impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter { - fn decrypt<'a>( - &mut self, - mut msg: InboundOpaqueMessage<'a>, - seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - let payload = &msg.payload; - - if payload.len() < CHACHAPOLY1305_OVERHEAD { - return Err(Error::DecryptError); - } - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.dec_offset, seq).0); - let aad = aead::Aad::from(make_tls12_aad( - seq, - msg.typ, - msg.version, - payload.len() - CHACHAPOLY1305_OVERHEAD, - )); - - let payload = &mut msg.payload; - let plain_len = self - .dec_key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)? - .len(); - - if plain_len > MAX_FRAGMENT_LEN { - return Err(Error::PeerSentOversizedRecord); - } - - payload.truncate(plain_len); - Ok(msg.into_plain_message()) - } -} - -impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter { - fn encrypt( - &mut self, - msg: OutboundPlainMessage<'_>, - seq: u64, - ) -> Result<OutboundOpaqueMessage, Error> { - let total_len = self.encrypted_payload_len(msg.payload.len()); - let mut payload = PrefixedPayload::with_capacity(total_len); - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0); - let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len())); - payload.extend_from_chunks(&msg.payload); - - self.enc_key - .seal_in_place_append_tag(nonce, aad, &mut payload) - .map_err(|_| Error::EncryptError)?; - - Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload)) - } - - fn encrypted_payload_len(&self, payload_len: usize) -> usize { - payload_len + self.enc_key.algorithm().tag_len() - } -} - -fn gcm_iv(write_iv: &[u8], explicit: &[u8]) -> Iv { - debug_assert_eq!(write_iv.len(), 4); - debug_assert_eq!(explicit.len(), 8); - - // The GCM nonce is constructed from a 32-bit 'salt' derived - // from the master-secret, and a 64-bit explicit part, - // with no specified construction. Thanks for that. - // - // We use the same construction as TLS1.3/ChaCha20Poly1305: - // a starting point extracted from the key block, xored with - // the sequence number. - let mut iv = [0; NONCE_LEN]; - iv[..4].copy_from_slice(write_iv); - iv[4..].copy_from_slice(explicit); - - Iv::new(iv) -} - -struct Tls12Prf(&'static tls_prf::Algorithm); - -impl Prf for Tls12Prf { - fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]) { - // safety: - // - [1] is safe because our caller guarantees `secret` is non-empty; this is - // the only documented error case. - // - [2] is safe in practice because the only failure from `derive()` is due - // to zero `output.len()`; this is outlawed at higher levels - let derived = tls_prf::Secret::new(self.0, secret) - .unwrap() // [1] - .derive(label, seed, output.len()) - .unwrap(); // [2] - output.copy_from_slice(derived.as_ref()); - } - - fn for_key_exchange( - &self, - output: &mut [u8; 48], - kx: Box<dyn ActiveKeyExchange>, - peer_pub_key: &[u8], - label: &[u8], - seed: &[u8], - ) -> Result<(), Error> { - self.for_secret( - output, - kx.complete_for_tls_version(peer_pub_key, &TLS12)? - .secret_bytes(), - label, - seed, - ); - Ok(()) - } - - fn fips(&self) -> bool { - super::fips() - } -} diff --git a/vendor/rustls/src/crypto/aws_lc_rs/tls13.rs b/vendor/rustls/src/crypto/aws_lc_rs/tls13.rs deleted file mode 100644 index dbc9d912..00000000 --- a/vendor/rustls/src/crypto/aws_lc_rs/tls13.rs +++ /dev/null @@ -1,425 +0,0 @@ -use alloc::boxed::Box; - -use aws_lc_rs::hkdf::KeyType; -use aws_lc_rs::{aead, hkdf, hmac}; - -use crate::crypto; -use crate::crypto::cipher::{ - AeadKey, InboundOpaqueMessage, Iv, MessageDecrypter, MessageEncrypter, Nonce, - Tls13AeadAlgorithm, UnsupportedOperationError, make_tls13_aad, -}; -use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock, OutputLengthError}; -use crate::enums::{CipherSuite, ContentType, ProtocolVersion}; -use crate::error::Error; -use crate::msgs::message::{ - InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, -}; -use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; -use crate::tls13::Tls13CipherSuite; - -/// The TLS1.3 ciphersuite TLS_CHACHA20_POLY1305_SHA256 -pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls13(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); - -pub(crate) static TLS13_CHACHA20_POLY1305_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, - hash_provider: &super::hash::SHA256, - // ref: <https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.2.1> - confidentiality_limit: u64::MAX, - }, - hkdf_provider: &AwsLcHkdf(hkdf::HKDF_SHA256, hmac::HMAC_SHA256), - aead_alg: &Chacha20Poly1305Aead(AeadAlgorithm(&aead::CHACHA20_POLY1305)), - quic: Some(&super::quic::KeyBuilder { - packet_alg: &aead::CHACHA20_POLY1305, - header_alg: &aead::quic::CHACHA20, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6> - confidentiality_limit: u64::MAX, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6> - integrity_limit: 1 << 36, - }), -}; - -/// The TLS1.3 ciphersuite TLS_AES_256_GCM_SHA384 -pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls13(&Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_AES_256_GCM_SHA384, - hash_provider: &super::hash::SHA384, - confidentiality_limit: 1 << 24, - }, - hkdf_provider: &AwsLcHkdf(hkdf::HKDF_SHA384, hmac::HMAC_SHA384), - aead_alg: &Aes256GcmAead(AeadAlgorithm(&aead::AES_256_GCM)), - quic: Some(&super::quic::KeyBuilder { - packet_alg: &aead::AES_256_GCM, - header_alg: &aead::quic::AES_256, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1> - confidentiality_limit: 1 << 23, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2> - integrity_limit: 1 << 52, - }), - }); - -/// The TLS1.3 ciphersuite TLS_AES_128_GCM_SHA256 -pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls13(TLS13_AES_128_GCM_SHA256_INTERNAL); - -pub(crate) static TLS13_AES_128_GCM_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_AES_128_GCM_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: 1 << 24, - }, - hkdf_provider: &AwsLcHkdf(hkdf::HKDF_SHA256, hmac::HMAC_SHA256), - aead_alg: &Aes128GcmAead(AeadAlgorithm(&aead::AES_128_GCM)), - quic: Some(&super::quic::KeyBuilder { - packet_alg: &aead::AES_128_GCM, - header_alg: &aead::quic::AES_128, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1> - confidentiality_limit: 1 << 23, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2> - integrity_limit: 1 << 52, - }), -}; - -struct Chacha20Poly1305Aead(AeadAlgorithm); - -impl Tls13AeadAlgorithm for Chacha20Poly1305Aead { - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { - // safety: the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. - Box::new(AeadMessageEncrypter { - enc_key: aead::LessSafeKey::new(aead::UnboundKey::new(self.0.0, key.as_ref()).unwrap()), - iv, - }) - } - - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { - // safety: the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. - Box::new(AeadMessageDecrypter { - dec_key: aead::LessSafeKey::new(aead::UnboundKey::new(self.0.0, key.as_ref()).unwrap()), - iv, - }) - } - - fn key_len(&self) -> usize { - self.0.key_len() - } - - fn extract_keys( - &self, - key: AeadKey, - iv: Iv, - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }) - } - - fn fips(&self) -> bool { - false // not FIPS approved - } -} - -struct Aes256GcmAead(AeadAlgorithm); - -impl Tls13AeadAlgorithm for Aes256GcmAead { - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { - self.0.encrypter(key, iv) - } - - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { - self.0.decrypter(key, iv) - } - - fn key_len(&self) -> usize { - self.0.key_len() - } - - fn extract_keys( - &self, - key: AeadKey, - iv: Iv, - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - Ok(ConnectionTrafficSecrets::Aes256Gcm { key, iv }) - } - - fn fips(&self) -> bool { - super::fips() - } -} - -struct Aes128GcmAead(AeadAlgorithm); - -impl Tls13AeadAlgorithm for Aes128GcmAead { - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { - self.0.encrypter(key, iv) - } - - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { - self.0.decrypter(key, iv) - } - - fn key_len(&self) -> usize { - self.0.key_len() - } - - fn extract_keys( - &self, - key: AeadKey, - iv: Iv, - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - Ok(ConnectionTrafficSecrets::Aes128Gcm { key, iv }) - } - - fn fips(&self) -> bool { - super::fips() - } -} - -// common encrypter/decrypter/key_len items for above Tls13AeadAlgorithm impls -struct AeadAlgorithm(&'static aead::Algorithm); - -impl AeadAlgorithm { - // using aead::TlsRecordSealingKey - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { - // safety: - // - the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. - // - this function should only be used for `Algorithm::AES_128_GCM` or `Algorithm::AES_256_GCM` - Box::new(GcmMessageEncrypter { - enc_key: aead::TlsRecordSealingKey::new( - self.0, - aead::TlsProtocolId::TLS13, - key.as_ref(), - ) - .unwrap(), - iv, - }) - } - - // using aead::TlsRecordOpeningKey - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { - // safety: - // - the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. - // - this function should only be used for `Algorithm::AES_128_GCM` or `Algorithm::AES_256_GCM` - Box::new(GcmMessageDecrypter { - dec_key: aead::TlsRecordOpeningKey::new( - self.0, - aead::TlsProtocolId::TLS13, - key.as_ref(), - ) - .unwrap(), - iv, - }) - } - - fn key_len(&self) -> usize { - self.0.key_len() - } -} - -struct AeadMessageEncrypter { - enc_key: aead::LessSafeKey, - iv: Iv, -} - -struct AeadMessageDecrypter { - dec_key: aead::LessSafeKey, - iv: Iv, -} - -impl MessageEncrypter for AeadMessageEncrypter { - fn encrypt( - &mut self, - msg: OutboundPlainMessage<'_>, - seq: u64, - ) -> Result<OutboundOpaqueMessage, Error> { - let total_len = self.encrypted_payload_len(msg.payload.len()); - let mut payload = PrefixedPayload::with_capacity(total_len); - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); - let aad = aead::Aad::from(make_tls13_aad(total_len)); - payload.extend_from_chunks(&msg.payload); - payload.extend_from_slice(&msg.typ.to_array()); - - self.enc_key - .seal_in_place_append_tag(nonce, aad, &mut payload) - .map_err(|_| Error::EncryptError)?; - - Ok(OutboundOpaqueMessage::new( - ContentType::ApplicationData, - // Note: all TLS 1.3 application data records use TLSv1_2 (0x0303) as the legacy record - // protocol version, see https://www.rfc-editor.org/rfc/rfc8446#section-5.1 - ProtocolVersion::TLSv1_2, - payload, - )) - } - - fn encrypted_payload_len(&self, payload_len: usize) -> usize { - payload_len + 1 + self.enc_key.algorithm().tag_len() - } -} - -impl MessageDecrypter for AeadMessageDecrypter { - fn decrypt<'a>( - &mut self, - mut msg: InboundOpaqueMessage<'a>, - seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - let payload = &mut msg.payload; - if payload.len() < self.dec_key.algorithm().tag_len() { - return Err(Error::DecryptError); - } - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); - let aad = aead::Aad::from(make_tls13_aad(payload.len())); - let plain_len = self - .dec_key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)? - .len(); - - payload.truncate(plain_len); - msg.into_tls13_unpadded_message() - } -} - -struct GcmMessageEncrypter { - enc_key: aead::TlsRecordSealingKey, - iv: Iv, -} - -impl MessageEncrypter for GcmMessageEncrypter { - fn encrypt( - &mut self, - msg: OutboundPlainMessage<'_>, - seq: u64, - ) -> Result<OutboundOpaqueMessage, Error> { - let total_len = self.encrypted_payload_len(msg.payload.len()); - let mut payload = PrefixedPayload::with_capacity(total_len); - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); - let aad = aead::Aad::from(make_tls13_aad(total_len)); - payload.extend_from_chunks(&msg.payload); - payload.extend_from_slice(&msg.typ.to_array()); - - self.enc_key - .seal_in_place_append_tag(nonce, aad, &mut payload) - .map_err(|_| Error::EncryptError)?; - - Ok(OutboundOpaqueMessage::new( - ContentType::ApplicationData, - ProtocolVersion::TLSv1_2, - payload, - )) - } - - fn encrypted_payload_len(&self, payload_len: usize) -> usize { - payload_len + 1 + self.enc_key.algorithm().tag_len() - } -} - -struct GcmMessageDecrypter { - dec_key: aead::TlsRecordOpeningKey, - iv: Iv, -} - -impl MessageDecrypter for GcmMessageDecrypter { - fn decrypt<'a>( - &mut self, - mut msg: InboundOpaqueMessage<'a>, - seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - let payload = &mut msg.payload; - if payload.len() < self.dec_key.algorithm().tag_len() { - return Err(Error::DecryptError); - } - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); - let aad = aead::Aad::from(make_tls13_aad(payload.len())); - let plain_len = self - .dec_key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)? - .len(); - - payload.truncate(plain_len); - msg.into_tls13_unpadded_message() - } -} - -struct AwsLcHkdf(hkdf::Algorithm, hmac::Algorithm); - -impl Hkdf for AwsLcHkdf { - fn extract_from_zero_ikm(&self, salt: Option<&[u8]>) -> Box<dyn HkdfExpander> { - let zeroes = [0u8; OkmBlock::MAX_LEN]; - let salt = match salt { - Some(salt) => salt, - None => &zeroes[..self.0.len()], - }; - Box::new(AwsLcHkdfExpander { - alg: self.0, - prk: hkdf::Salt::new(self.0, salt).extract(&zeroes[..self.0.len()]), - }) - } - - fn extract_from_secret(&self, salt: Option<&[u8]>, secret: &[u8]) -> Box<dyn HkdfExpander> { - let zeroes = [0u8; OkmBlock::MAX_LEN]; - let salt = match salt { - Some(salt) => salt, - None => &zeroes[..self.0.len()], - }; - Box::new(AwsLcHkdfExpander { - alg: self.0, - prk: hkdf::Salt::new(self.0, salt).extract(secret), - }) - } - - fn expander_for_okm(&self, okm: &OkmBlock) -> Box<dyn HkdfExpander> { - Box::new(AwsLcHkdfExpander { - alg: self.0, - prk: hkdf::Prk::new_less_safe(self.0, okm.as_ref()), - }) - } - - fn hmac_sign(&self, key: &OkmBlock, message: &[u8]) -> crypto::hmac::Tag { - crypto::hmac::Tag::new(hmac::sign(&hmac::Key::new(self.1, key.as_ref()), message).as_ref()) - } - - fn fips(&self) -> bool { - super::fips() - } -} - -struct AwsLcHkdfExpander { - alg: hkdf::Algorithm, - prk: hkdf::Prk, -} - -impl HkdfExpander for AwsLcHkdfExpander { - fn expand_slice(&self, info: &[&[u8]], output: &mut [u8]) -> Result<(), OutputLengthError> { - self.prk - .expand(info, Len(output.len())) - .and_then(|okm| okm.fill(output)) - .map_err(|_| OutputLengthError) - } - - fn expand_block(&self, info: &[&[u8]]) -> OkmBlock { - let mut buf = [0u8; OkmBlock::MAX_LEN]; - let output = &mut buf[..self.hash_len()]; - self.prk - .expand(info, Len(output.len())) - .and_then(|okm| okm.fill(output)) - .unwrap(); - OkmBlock::new(output) - } - - fn hash_len(&self) -> usize { - self.alg.len() - } -} - -struct Len(usize); - -impl KeyType for Len { - fn len(&self) -> usize { - self.0 - } -} diff --git a/vendor/rustls/src/crypto/cipher.rs b/vendor/rustls/src/crypto/cipher.rs deleted file mode 100644 index 64901a57..00000000 --- a/vendor/rustls/src/crypto/cipher.rs +++ /dev/null @@ -1,350 +0,0 @@ -use alloc::boxed::Box; -use alloc::string::ToString; -use core::fmt; - -use zeroize::Zeroize; - -use crate::enums::{ContentType, ProtocolVersion}; -use crate::error::Error; -use crate::msgs::codec; -pub use crate::msgs::message::{ - BorrowedPayload, InboundOpaqueMessage, InboundPlainMessage, OutboundChunks, - OutboundOpaqueMessage, OutboundPlainMessage, PlainMessage, PrefixedPayload, -}; -use crate::suites::ConnectionTrafficSecrets; - -/// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.3 cipher suite. -pub trait Tls13AeadAlgorithm: Send + Sync { - /// Build a `MessageEncrypter` for the given key/iv. - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter>; - - /// Build a `MessageDecrypter` for the given key/iv. - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter>; - - /// The length of key in bytes required by `encrypter()` and `decrypter()`. - fn key_len(&self) -> usize; - - /// Convert the key material from `key`/`iv`, into a `ConnectionTrafficSecrets` item. - /// - /// May return [`UnsupportedOperationError`] if the AEAD algorithm is not a supported - /// variant of `ConnectionTrafficSecrets`. - fn extract_keys( - &self, - key: AeadKey, - iv: Iv, - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } -} - -/// Factory trait for building `MessageEncrypter` and `MessageDecrypter` for a TLS1.2 cipher suite. -pub trait Tls12AeadAlgorithm: Send + Sync + 'static { - /// Build a `MessageEncrypter` for the given key/iv and extra key block (which can be used for - /// improving explicit nonce size security, if needed). - /// - /// The length of `key` is set by [`KeyBlockShape::enc_key_len`]. - /// - /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`]. - /// - /// The length of `extra` is set by [`KeyBlockShape::explicit_nonce_len`]. - fn encrypter(&self, key: AeadKey, iv: &[u8], extra: &[u8]) -> Box<dyn MessageEncrypter>; - - /// Build a `MessageDecrypter` for the given key/iv. - /// - /// The length of `key` is set by [`KeyBlockShape::enc_key_len`]. - /// - /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`]. - fn decrypter(&self, key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter>; - - /// Return a `KeyBlockShape` that defines how large the `key_block` is and how it - /// is split up prior to calling `encrypter()`, `decrypter()` and/or `extract_keys()`. - fn key_block_shape(&self) -> KeyBlockShape; - - /// Convert the key material from `key`/`iv`, into a `ConnectionTrafficSecrets` item. - /// - /// The length of `key` is set by [`KeyBlockShape::enc_key_len`]. - /// - /// The length of `iv` is set by [`KeyBlockShape::fixed_iv_len`]. - /// - /// The length of `extra` is set by [`KeyBlockShape::explicit_nonce_len`]. - /// - /// May return [`UnsupportedOperationError`] if the AEAD algorithm is not a supported - /// variant of `ConnectionTrafficSecrets`. - fn extract_keys( - &self, - key: AeadKey, - iv: &[u8], - explicit: &[u8], - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError>; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } -} - -/// An error indicating that the AEAD algorithm does not support the requested operation. -#[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub struct UnsupportedOperationError; - -impl From<UnsupportedOperationError> for Error { - fn from(value: UnsupportedOperationError) -> Self { - Self::General(value.to_string()) - } -} - -impl fmt::Display for UnsupportedOperationError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "operation not supported") - } -} - -#[cfg(feature = "std")] -impl std::error::Error for UnsupportedOperationError {} - -/// How a TLS1.2 `key_block` is partitioned. -/// -/// Note: ciphersuites with non-zero `mac_key_length` are not currently supported. -pub struct KeyBlockShape { - /// How long keys are. - /// - /// `enc_key_length` terminology is from the standard ([RFC5246 A.6]). - /// - /// [RFC5246 A.6]: <https://www.rfc-editor.org/rfc/rfc5246#appendix-A.6> - pub enc_key_len: usize, - - /// How long the fixed part of the 'IV' is. - /// - /// `fixed_iv_length` terminology is from the standard ([RFC5246 A.6]). - /// - /// This isn't usually an IV, but we continue the - /// terminology misuse to match the standard. - /// - /// [RFC5246 A.6]: <https://www.rfc-editor.org/rfc/rfc5246#appendix-A.6> - pub fixed_iv_len: usize, - - /// This is a non-standard extension which extends the - /// key block to provide an initial explicit nonce offset, - /// in a deterministic and safe way. GCM needs this, - /// chacha20poly1305 works this way by design. - pub explicit_nonce_len: usize, -} - -/// Objects with this trait can decrypt TLS messages. -pub trait MessageDecrypter: Send + Sync { - /// Decrypt the given TLS message `msg`, using the sequence number - /// `seq` which can be used to derive a unique [`Nonce`]. - fn decrypt<'a>( - &mut self, - msg: InboundOpaqueMessage<'a>, - seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error>; -} - -/// Objects with this trait can encrypt TLS messages. -pub trait MessageEncrypter: Send + Sync { - /// Encrypt the given TLS message `msg`, using the sequence number - /// `seq` which can be used to derive a unique [`Nonce`]. - fn encrypt( - &mut self, - msg: OutboundPlainMessage<'_>, - seq: u64, - ) -> Result<OutboundOpaqueMessage, Error>; - - /// Return the length of the ciphertext that results from encrypting plaintext of - /// length `payload_len` - fn encrypted_payload_len(&self, payload_len: usize) -> usize; -} - -impl dyn MessageEncrypter { - pub(crate) fn invalid() -> Box<dyn MessageEncrypter> { - Box::new(InvalidMessageEncrypter {}) - } -} - -impl dyn MessageDecrypter { - pub(crate) fn invalid() -> Box<dyn MessageDecrypter> { - Box::new(InvalidMessageDecrypter {}) - } -} - -/// A write or read IV. -#[derive(Default)] -pub struct Iv([u8; NONCE_LEN]); - -impl Iv { - /// Create a new `Iv` from a byte array, of precisely `NONCE_LEN` bytes. - #[cfg(feature = "tls12")] - pub fn new(value: [u8; NONCE_LEN]) -> Self { - Self(value) - } - - /// Create a new `Iv` from a byte slice, of precisely `NONCE_LEN` bytes. - #[cfg(feature = "tls12")] - pub fn copy(value: &[u8]) -> Self { - debug_assert_eq!(value.len(), NONCE_LEN); - let mut iv = Self::new(Default::default()); - iv.0.copy_from_slice(value); - iv - } -} - -impl From<[u8; NONCE_LEN]> for Iv { - fn from(bytes: [u8; NONCE_LEN]) -> Self { - Self(bytes) - } -} - -impl AsRef<[u8]> for Iv { - fn as_ref(&self) -> &[u8] { - self.0.as_ref() - } -} - -/// A nonce. This is unique for all messages on a connection. -pub struct Nonce(pub [u8; NONCE_LEN]); - -impl Nonce { - /// Combine an `Iv` and sequence number to produce a unique nonce. - /// - /// This is `iv ^ seq` where `seq` is encoded as a 96-bit big-endian integer. - #[inline] - pub fn new(iv: &Iv, seq: u64) -> Self { - let mut nonce = Self([0u8; NONCE_LEN]); - codec::put_u64(seq, &mut nonce.0[4..]); - - nonce - .0 - .iter_mut() - .zip(iv.0.iter()) - .for_each(|(nonce, iv)| { - *nonce ^= *iv; - }); - - nonce - } -} - -/// Size of TLS nonces (incorrectly termed "IV" in standard) for all supported ciphersuites -/// (AES-GCM, Chacha20Poly1305) -pub const NONCE_LEN: usize = 12; - -/// Returns a TLS1.3 `additional_data` encoding. -/// -/// See RFC8446 s5.2 for the `additional_data` definition. -#[inline] -pub fn make_tls13_aad(payload_len: usize) -> [u8; 5] { - let version = ProtocolVersion::TLSv1_2.to_array(); - [ - ContentType::ApplicationData.into(), - // Note: this is `legacy_record_version`, i.e. TLS1.2 even for TLS1.3. - version[0], - version[1], - (payload_len >> 8) as u8, - (payload_len & 0xff) as u8, - ] -} - -/// Returns a TLS1.2 `additional_data` encoding. -/// -/// See RFC5246 s6.2.3.3 for the `additional_data` definition. -#[inline] -pub fn make_tls12_aad( - seq: u64, - typ: ContentType, - vers: ProtocolVersion, - len: usize, -) -> [u8; TLS12_AAD_SIZE] { - let mut out = [0; TLS12_AAD_SIZE]; - codec::put_u64(seq, &mut out[0..]); - out[8] = typ.into(); - codec::put_u16(vers.into(), &mut out[9..]); - codec::put_u16(len as u16, &mut out[11..]); - out -} - -const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2; - -/// A key for an AEAD algorithm. -/// -/// This is a value type for a byte string up to `AeadKey::MAX_LEN` bytes in length. -pub struct AeadKey { - buf: [u8; Self::MAX_LEN], - used: usize, -} - -impl AeadKey { - #[cfg(feature = "tls12")] - pub(crate) fn new(buf: &[u8]) -> Self { - debug_assert!(buf.len() <= Self::MAX_LEN); - let mut key = Self::from([0u8; Self::MAX_LEN]); - key.buf[..buf.len()].copy_from_slice(buf); - key.used = buf.len(); - key - } - - pub(crate) fn with_length(self, len: usize) -> Self { - assert!(len <= self.used); - Self { - buf: self.buf, - used: len, - } - } - - /// Largest possible AEAD key in the ciphersuites we support. - pub(crate) const MAX_LEN: usize = 32; -} - -impl Drop for AeadKey { - fn drop(&mut self) { - self.buf.zeroize(); - } -} - -impl AsRef<[u8]> for AeadKey { - fn as_ref(&self) -> &[u8] { - &self.buf[..self.used] - } -} - -impl From<[u8; Self::MAX_LEN]> for AeadKey { - fn from(bytes: [u8; Self::MAX_LEN]) -> Self { - Self { - buf: bytes, - used: Self::MAX_LEN, - } - } -} - -/// A `MessageEncrypter` which doesn't work. -struct InvalidMessageEncrypter {} - -impl MessageEncrypter for InvalidMessageEncrypter { - fn encrypt( - &mut self, - _m: OutboundPlainMessage<'_>, - _seq: u64, - ) -> Result<OutboundOpaqueMessage, Error> { - Err(Error::EncryptError) - } - - fn encrypted_payload_len(&self, payload_len: usize) -> usize { - payload_len - } -} - -/// A `MessageDecrypter` which doesn't work. -struct InvalidMessageDecrypter {} - -impl MessageDecrypter for InvalidMessageDecrypter { - fn decrypt<'a>( - &mut self, - _m: InboundOpaqueMessage<'a>, - _seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - Err(Error::DecryptError) - } -} diff --git a/vendor/rustls/src/crypto/hash.rs b/vendor/rustls/src/crypto/hash.rs deleted file mode 100644 index 214dad4e..00000000 --- a/vendor/rustls/src/crypto/hash.rs +++ /dev/null @@ -1,81 +0,0 @@ -use alloc::boxed::Box; - -pub use crate::msgs::enums::HashAlgorithm; - -/// Describes a single cryptographic hash function. -/// -/// This interface can do both one-shot and incremental hashing, using -/// [`Hash::hash()`] and [`Hash::start()`] respectively. -pub trait Hash: Send + Sync { - /// Start an incremental hash computation. - fn start(&self) -> Box<dyn Context>; - - /// Return the output of this hash function with input `data`. - fn hash(&self, data: &[u8]) -> Output; - - /// The length in bytes of this hash function's output. - fn output_len(&self) -> usize; - - /// Which hash function this is, eg, `HashAlgorithm::SHA256`. - fn algorithm(&self) -> HashAlgorithm; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } -} - -/// A hash output, stored as a value. -pub struct Output { - buf: [u8; Self::MAX_LEN], - used: usize, -} - -impl Output { - /// Build a `hash::Output` from a slice of no more than `Output::MAX_LEN` bytes. - pub fn new(bytes: &[u8]) -> Self { - let mut output = Self { - buf: [0u8; Self::MAX_LEN], - used: bytes.len(), - }; - debug_assert!(bytes.len() <= Self::MAX_LEN); - output.buf[..bytes.len()].copy_from_slice(bytes); - output - } - - /// Maximum supported hash output size: supports up to SHA512. - pub const MAX_LEN: usize = 64; -} - -impl AsRef<[u8]> for Output { - fn as_ref(&self) -> &[u8] { - &self.buf[..self.used] - } -} - -/// How to incrementally compute a hash. -pub trait Context: Send + Sync { - /// Finish the computation, returning the resulting output. - /// - /// The computation remains valid, and more data can be added later with - /// [`Context::update()`]. - /// - /// Compare with [`Context::finish()`] which consumes the computation - /// and prevents any further data being added. This can be more efficient - /// because it avoids a hash context copy to apply Merkle-Damgård padding - /// (if required). - fn fork_finish(&self) -> Output; - - /// Fork the computation, producing another context that has the - /// same prefix as this one. - fn fork(&self) -> Box<dyn Context>; - - /// Terminate and finish the computation, returning the resulting output. - /// - /// Further data cannot be added after this, because the context is consumed. - /// Compare [`Context::fork_finish()`]. - fn finish(self: Box<Self>) -> Output; - - /// Add `data` to computation. - fn update(&mut self, data: &[u8]); -} diff --git a/vendor/rustls/src/crypto/hmac.rs b/vendor/rustls/src/crypto/hmac.rs deleted file mode 100644 index 6960b7e6..00000000 --- a/vendor/rustls/src/crypto/hmac.rs +++ /dev/null @@ -1,73 +0,0 @@ -use alloc::boxed::Box; - -use zeroize::Zeroize; - -/// A concrete HMAC implementation, for a single cryptographic hash function. -/// -/// You should have one object that implements this trait for HMAC-SHA256, another -/// for HMAC-SHA384, etc. -pub trait Hmac: Send + Sync { - /// Prepare to use `key` as a HMAC key. - fn with_key(&self, key: &[u8]) -> Box<dyn Key>; - - /// Give the length of the underlying hash function. In RFC2104 terminology this is `L`. - fn hash_output_len(&self) -> usize; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } -} - -/// A HMAC tag, stored as a value. -#[derive(Clone)] -pub struct Tag { - buf: [u8; Self::MAX_LEN], - used: usize, -} - -impl Tag { - /// Build a tag by copying a byte slice. - /// - /// The slice can be up to [`Tag::MAX_LEN`] bytes in length. - pub fn new(bytes: &[u8]) -> Self { - let mut tag = Self { - buf: [0u8; Self::MAX_LEN], - used: bytes.len(), - }; - tag.buf[..bytes.len()].copy_from_slice(bytes); - tag - } - - /// Maximum supported HMAC tag size: supports up to SHA512. - pub const MAX_LEN: usize = 64; -} - -impl Drop for Tag { - fn drop(&mut self) { - self.buf.zeroize(); - } -} - -impl AsRef<[u8]> for Tag { - fn as_ref(&self) -> &[u8] { - &self.buf[..self.used] - } -} - -/// A HMAC key that is ready for use. -/// -/// The algorithm used is implicit in the `Hmac` object that produced the key. -pub trait Key: Send + Sync { - /// Calculates a tag over `data` -- a slice of byte slices. - fn sign(&self, data: &[&[u8]]) -> Tag { - self.sign_concat(&[], data, &[]) - } - - /// Calculates a tag over the concatenation of `first`, the items in `middle`, and `last`. - fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> Tag; - - /// Returns the length of the tag returned by a computation using - /// this key. - fn tag_len(&self) -> usize; -} diff --git a/vendor/rustls/src/crypto/hpke.rs b/vendor/rustls/src/crypto/hpke.rs deleted file mode 100644 index 62074150..00000000 --- a/vendor/rustls/src/crypto/hpke.rs +++ /dev/null @@ -1,145 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt::Debug; - -use zeroize::Zeroize; - -use crate::Error; -use crate::msgs::enums::HpkeKem; -use crate::msgs::handshake::HpkeSymmetricCipherSuite; - -/// An HPKE suite, specifying a key encapsulation mechanism and a symmetric cipher suite. -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct HpkeSuite { - /// The choice of HPKE key encapsulation mechanism. - pub kem: HpkeKem, - - /// The choice of HPKE symmetric cipher suite. - /// - /// This combines a choice of authenticated encryption with additional data (AEAD) algorithm - /// and a key derivation function (KDF). - pub sym: HpkeSymmetricCipherSuite, -} - -/// An HPKE instance that can be used for base-mode single-shot encryption and decryption. -pub trait Hpke: Debug + Send + Sync { - /// Seal the provided `plaintext` to the recipient public key `pub_key` with application supplied - /// `info`, and additional data `aad`. - /// - /// Returns ciphertext that can be used with [Self::open] by the recipient to recover plaintext - /// using the same `info` and `aad` and the private key corresponding to `pub_key`. RFC 9180 - /// refers to `pub_key` as `pkR`. - fn seal( - &self, - info: &[u8], - aad: &[u8], - plaintext: &[u8], - pub_key: &HpkePublicKey, - ) -> Result<(EncapsulatedSecret, Vec<u8>), Error>; - - /// Set up a sealer context for the receiver public key `pub_key` with application supplied `info`. - /// - /// Returns both an encapsulated ciphertext and a sealer context that can be used to seal - /// messages to the recipient. RFC 9180 refers to `pub_key` as `pkR`. - fn setup_sealer( - &self, - info: &[u8], - pub_key: &HpkePublicKey, - ) -> Result<(EncapsulatedSecret, Box<dyn HpkeSealer + 'static>), Error>; - - /// Open the provided `ciphertext` using the encapsulated secret `enc`, with application - /// supplied `info`, and additional data `aad`. - /// - /// Returns plaintext if the `info` and `aad` match those used with [Self::seal], and - /// decryption with `secret_key` succeeds. RFC 9180 refers to `secret_key` as `skR`. - fn open( - &self, - enc: &EncapsulatedSecret, - info: &[u8], - aad: &[u8], - ciphertext: &[u8], - secret_key: &HpkePrivateKey, - ) -> Result<Vec<u8>, Error>; - - /// Set up an opener context for the secret key `secret_key` with application supplied `info`. - /// - /// Returns an opener context that can be used to open sealed messages encrypted to the - /// public key corresponding to `secret_key`. RFC 9180 refers to `secret_key` as `skR`. - fn setup_opener( - &self, - enc: &EncapsulatedSecret, - info: &[u8], - secret_key: &HpkePrivateKey, - ) -> Result<Box<dyn HpkeOpener + 'static>, Error>; - - /// Generate a new public key and private key pair compatible with this HPKE instance. - /// - /// Key pairs should be encoded as raw big endian fixed length integers sized based - /// on the suite's DH KEM algorithm. - fn generate_key_pair(&self) -> Result<(HpkePublicKey, HpkePrivateKey), Error>; - - /// Return whether the HPKE instance is FIPS compatible. - fn fips(&self) -> bool { - false - } - - /// Return the [HpkeSuite] that this HPKE instance supports. - fn suite(&self) -> HpkeSuite; -} - -/// An HPKE sealer context. -/// -/// This is a stateful object that can be used to seal messages for receipt by -/// a receiver. -pub trait HpkeSealer: Debug + Send + Sync + 'static { - /// Seal the provided `plaintext` with additional data `aad`, returning - /// ciphertext. - fn seal(&mut self, aad: &[u8], plaintext: &[u8]) -> Result<Vec<u8>, Error>; -} - -/// An HPKE opener context. -/// -/// This is a stateful object that can be used to open sealed messages sealed -/// by a sender. -pub trait HpkeOpener: Debug + Send + Sync + 'static { - /// Open the provided `ciphertext` with additional data `aad`, returning plaintext. - fn open(&mut self, aad: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>, Error>; -} - -/// An HPKE public key. -#[derive(Clone, Debug)] -pub struct HpkePublicKey(pub Vec<u8>); - -/// An HPKE private key. -pub struct HpkePrivateKey(Vec<u8>); - -impl HpkePrivateKey { - /// Return the private key bytes. - pub fn secret_bytes(&self) -> &[u8] { - self.0.as_slice() - } -} - -impl From<Vec<u8>> for HpkePrivateKey { - fn from(bytes: Vec<u8>) -> Self { - Self(bytes) - } -} - -impl Drop for HpkePrivateKey { - fn drop(&mut self) { - self.0.zeroize(); - } -} - -/// An HPKE key pair, made of a matching public and private key. -pub struct HpkeKeyPair { - /// A HPKE public key. - pub public_key: HpkePublicKey, - /// A HPKE private key. - pub private_key: HpkePrivateKey, -} - -/// An encapsulated secret returned from setting up a sender or receiver context. -#[derive(Debug)] -pub struct EncapsulatedSecret(pub Vec<u8>); diff --git a/vendor/rustls/src/crypto/mod.rs b/vendor/rustls/src/crypto/mod.rs deleted file mode 100644 index 3ce026b9..00000000 --- a/vendor/rustls/src/crypto/mod.rs +++ /dev/null @@ -1,756 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt::Debug; - -use pki_types::PrivateKeyDer; -use zeroize::Zeroize; - -#[cfg(all(doc, feature = "tls12"))] -use crate::Tls12CipherSuite; -use crate::msgs::ffdhe_groups::FfdheGroup; -use crate::sign::SigningKey; -use crate::sync::Arc; -pub use crate::webpki::{ - WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature, - verify_tls13_signature_with_raw_key, -}; -#[cfg(doc)] -use crate::{ - ClientConfig, ConfigBuilder, ServerConfig, SupportedCipherSuite, Tls13CipherSuite, client, - crypto, server, sign, -}; -use crate::{Error, NamedGroup, ProtocolVersion, SupportedProtocolVersion, suites}; - -/// *ring* based CryptoProvider. -#[cfg(feature = "ring")] -pub mod ring; - -/// aws-lc-rs-based CryptoProvider. -#[cfg(feature = "aws_lc_rs")] -pub mod aws_lc_rs; - -/// TLS message encryption/decryption interfaces. -pub mod cipher; - -/// Hashing interfaces. -pub mod hash; - -/// HMAC interfaces. -pub mod hmac; - -#[cfg(feature = "tls12")] -/// Cryptography specific to TLS1.2. -pub mod tls12; - -/// Cryptography specific to TLS1.3. -pub mod tls13; - -/// Hybrid public key encryption (RFC 9180). -pub mod hpke; - -// Message signing interfaces. Re-exported under rustls::sign. Kept crate-internal here to -// avoid having two import paths to the same types. -pub(crate) mod signer; - -pub use crate::msgs::handshake::KeyExchangeAlgorithm; -pub use crate::rand::GetRandomFailed; -pub use crate::suites::CipherSuiteCommon; - -/// Controls core cryptography used by rustls. -/// -/// This crate comes with two built-in options, provided as -/// `CryptoProvider` structures: -/// -/// - [`crypto::aws_lc_rs::default_provider`]: (behind the `aws_lc_rs` crate feature, -/// which is enabled by default). This provider uses the [aws-lc-rs](https://github.com/aws/aws-lc-rs) -/// crate. The `fips` crate feature makes this option use FIPS140-3-approved cryptography. -/// - [`crypto::ring::default_provider`]: (behind the `ring` crate feature, which -/// is optional). This provider uses the [*ring*](https://github.com/briansmith/ring) -/// crate. -/// -/// This structure provides defaults. Everything in it can be overridden at -/// runtime by replacing field values as needed. -/// -/// # Using the per-process default `CryptoProvider` -/// -/// There is the concept of an implicit default provider, configured at run-time once in -/// a given process. -/// -/// It is used for functions like [`ClientConfig::builder()`] and [`ServerConfig::builder()`]. -/// -/// The intention is that an application can specify the [`CryptoProvider`] they wish to use -/// once, and have that apply to the variety of places where their application does TLS -/// (which may be wrapped inside other libraries). -/// They should do this by calling [`CryptoProvider::install_default()`] early on. -/// -/// To achieve this goal: -/// -/// - _libraries_ should use [`ClientConfig::builder()`]/[`ServerConfig::builder()`] -/// or otherwise rely on the [`CryptoProvider::get_default()`] provider. -/// - _applications_ should call [`CryptoProvider::install_default()`] early -/// in their `fn main()`. If _applications_ uses a custom provider based on the one built-in, -/// they can activate the `custom-provider` feature to ensure its usage. -/// -/// # Using a specific `CryptoProvider` -/// -/// Supply the provider when constructing your [`ClientConfig`] or [`ServerConfig`]: -/// -/// - [`ClientConfig::builder_with_provider()`] -/// - [`ServerConfig::builder_with_provider()`] -/// -/// When creating and configuring a webpki-backed client or server certificate verifier, a choice of -/// provider is also needed to start the configuration process: -/// -/// - [`client::WebPkiServerVerifier::builder_with_provider()`] -/// - [`server::WebPkiClientVerifier::builder_with_provider()`] -/// -/// If you install a custom provider and want to avoid any accidental use of a built-in provider, the feature -/// `custom-provider` can be activated to ensure your custom provider is used everywhere -/// and not a built-in one. This will disable any implicit use of a built-in provider. -/// -/// # Making a custom `CryptoProvider` -/// -/// Your goal will be to populate an instance of this `CryptoProvider` struct. -/// -/// ## Which elements are required? -/// -/// There is no requirement that the individual elements ([`SupportedCipherSuite`], [`SupportedKxGroup`], -/// [`SigningKey`], etc.) come from the same crate. It is allowed and expected that uninteresting -/// elements would be delegated back to one of the default providers (statically) or a parent -/// provider (dynamically). -/// -/// For example, if we want to make a provider that just overrides key loading in the config builder -/// API (with [`ConfigBuilder::with_single_cert`], etc.), it might look like this: -/// -/// ``` -/// # #[cfg(feature = "aws_lc_rs")] { -/// # use std::sync::Arc; -/// # mod fictious_hsm_api { pub fn load_private_key(key_der: pki_types::PrivateKeyDer<'static>) -> ! { unreachable!(); } } -/// use rustls::crypto::aws_lc_rs; -/// -/// pub fn provider() -> rustls::crypto::CryptoProvider { -/// rustls::crypto::CryptoProvider{ -/// key_provider: &HsmKeyLoader, -/// ..aws_lc_rs::default_provider() -/// } -/// } -/// -/// #[derive(Debug)] -/// struct HsmKeyLoader; -/// -/// impl rustls::crypto::KeyProvider for HsmKeyLoader { -/// fn load_private_key(&self, key_der: pki_types::PrivateKeyDer<'static>) -> Result<Arc<dyn rustls::sign::SigningKey>, rustls::Error> { -/// fictious_hsm_api::load_private_key(key_der) -/// } -/// } -/// # } -/// ``` -/// -/// ## References to the individual elements -/// -/// The elements are documented separately: -/// -/// - **Random** - see [`crypto::SecureRandom::fill()`]. -/// - **Cipher suites** - see [`SupportedCipherSuite`], [`Tls12CipherSuite`], and -/// [`Tls13CipherSuite`]. -/// - **Key exchange groups** - see [`crypto::SupportedKxGroup`]. -/// - **Signature verification algorithms** - see [`crypto::WebPkiSupportedAlgorithms`]. -/// - **Authentication key loading** - see [`crypto::KeyProvider::load_private_key()`] and -/// [`sign::SigningKey`]. -/// -/// # Example code -/// -/// See custom [`provider-example/`] for a full client and server example that uses -/// cryptography from the [`RustCrypto`] and [`dalek-cryptography`] projects. -/// -/// ```shell -/// $ cargo run --example client | head -3 -/// Current ciphersuite: TLS13_CHACHA20_POLY1305_SHA256 -/// HTTP/1.1 200 OK -/// Content-Type: text/html; charset=utf-8 -/// Content-Length: 19899 -/// ``` -/// -/// [`provider-example/`]: https://github.com/rustls/rustls/tree/main/provider-example/ -/// [`RustCrypto`]: https://github.com/RustCrypto -/// [`dalek-cryptography`]: https://github.com/dalek-cryptography -/// -/// # FIPS-approved cryptography -/// The `fips` crate feature enables use of the `aws-lc-rs` crate in FIPS mode. -/// -/// You can verify the configuration at runtime by checking -/// [`ServerConfig::fips()`]/[`ClientConfig::fips()`] return `true`. -#[derive(Debug, Clone)] -pub struct CryptoProvider { - /// List of supported ciphersuites, in preference order -- the first element - /// is the highest priority. - /// - /// The `SupportedCipherSuite` type carries both configuration and implementation. - /// - /// A valid `CryptoProvider` must ensure that all cipher suites are accompanied by at least - /// one matching key exchange group in [`CryptoProvider::kx_groups`]. - pub cipher_suites: Vec<suites::SupportedCipherSuite>, - - /// List of supported key exchange groups, in preference order -- the - /// first element is the highest priority. - /// - /// The first element in this list is the _default key share algorithm_, - /// and in TLS1.3 a key share for it is sent in the client hello. - /// - /// The `SupportedKxGroup` type carries both configuration and implementation. - pub kx_groups: Vec<&'static dyn SupportedKxGroup>, - - /// List of signature verification algorithms for use with webpki. - /// - /// These are used for both certificate chain verification and handshake signature verification. - /// - /// This is called by [`ConfigBuilder::with_root_certificates()`], - /// [`server::WebPkiClientVerifier::builder_with_provider()`] and - /// [`client::WebPkiServerVerifier::builder_with_provider()`]. - pub signature_verification_algorithms: WebPkiSupportedAlgorithms, - - /// Source of cryptographically secure random numbers. - pub secure_random: &'static dyn SecureRandom, - - /// Provider for loading private [`SigningKey`]s from [`PrivateKeyDer`]. - pub key_provider: &'static dyn KeyProvider, -} - -impl CryptoProvider { - /// Sets this `CryptoProvider` as the default for this process. - /// - /// This can be called successfully at most once in any process execution. - /// - /// Call this early in your process to configure which provider is used for - /// the provider. The configuration should happen before any use of - /// [`ClientConfig::builder()`] or [`ServerConfig::builder()`]. - pub fn install_default(self) -> Result<(), Arc<Self>> { - static_default::install_default(self) - } - - /// Returns the default `CryptoProvider` for this process. - /// - /// This will be `None` if no default has been set yet. - pub fn get_default() -> Option<&'static Arc<Self>> { - static_default::get_default() - } - - /// An internal function that: - /// - /// - gets the pre-installed default, or - /// - installs one `from_crate_features()`, or else - /// - panics about the need to call [`CryptoProvider::install_default()`] - pub(crate) fn get_default_or_install_from_crate_features() -> &'static Arc<Self> { - if let Some(provider) = Self::get_default() { - return provider; - } - - let provider = Self::from_crate_features() - .expect("no process-level CryptoProvider available -- call CryptoProvider::install_default() before this point"); - // Ignore the error resulting from us losing a race, and accept the outcome. - let _ = provider.install_default(); - Self::get_default().unwrap() - } - - /// Returns a provider named unambiguously by rustls crate features. - /// - /// This function returns `None` if the crate features are ambiguous (ie, specify two - /// providers), or specify no providers, or the feature `custom-provider` is activated. - /// In all cases the application should explicitly specify the provider to use - /// with [`CryptoProvider::install_default`]. - fn from_crate_features() -> Option<Self> { - #[cfg(all( - feature = "ring", - not(feature = "aws_lc_rs"), - not(feature = "custom-provider") - ))] - { - return Some(ring::default_provider()); - } - - #[cfg(all( - feature = "aws_lc_rs", - not(feature = "ring"), - not(feature = "custom-provider") - ))] - { - return Some(aws_lc_rs::default_provider()); - } - - #[allow(unreachable_code)] - None - } - - /// Returns `true` if this `CryptoProvider` is operating in FIPS mode. - /// - /// This covers only the cryptographic parts of FIPS approval. There are - /// also TLS protocol-level recommendations made by NIST. You should - /// prefer to call [`ClientConfig::fips()`] or [`ServerConfig::fips()`] - /// which take these into account. - pub fn fips(&self) -> bool { - let Self { - cipher_suites, - kx_groups, - signature_verification_algorithms, - secure_random, - key_provider, - } = self; - cipher_suites.iter().all(|cs| cs.fips()) - && kx_groups.iter().all(|kx| kx.fips()) - && signature_verification_algorithms.fips() - && secure_random.fips() - && key_provider.fips() - } -} - -/// A source of cryptographically secure randomness. -pub trait SecureRandom: Send + Sync + Debug { - /// Fill the given buffer with random bytes. - /// - /// The bytes must be sourced from a cryptographically secure random number - /// generator seeded with good quality, secret entropy. - /// - /// This is used for all randomness required by rustls, but not necessarily - /// randomness required by the underlying cryptography library. For example: - /// [`SupportedKxGroup::start()`] requires random material to generate - /// an ephemeral key exchange key, but this is not included in the interface with - /// rustls: it is assumed that the cryptography library provides for this itself. - fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed>; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } -} - -/// A mechanism for loading private [`SigningKey`]s from [`PrivateKeyDer`]. -/// -/// This trait is intended to be used with private key material that is sourced from DER, -/// such as a private-key that may be present on-disk. It is not intended to be used with -/// keys held in hardware security modules (HSMs) or physical tokens. For these use-cases -/// see the Rustls manual section on [customizing private key usage]. -/// -/// [customizing private key usage]: <https://docs.rs/rustls/latest/rustls/manual/_03_howto/index.html#customising-private-key-usage> -pub trait KeyProvider: Send + Sync + Debug { - /// Decode and validate a private signing key from `key_der`. - /// - /// This is used by [`ConfigBuilder::with_client_auth_cert()`], [`ConfigBuilder::with_single_cert()`], - /// and [`ConfigBuilder::with_single_cert_with_ocsp()`]. The key types and formats supported by this - /// function directly defines the key types and formats supported in those APIs. - /// - /// Return an error if the key type encoding is not supported, or if the key fails validation. - fn load_private_key( - &self, - key_der: PrivateKeyDer<'static>, - ) -> Result<Arc<dyn SigningKey>, Error>; - - /// Return `true` if this is backed by a FIPS-approved implementation. - /// - /// If this returns `true`, that must be the case for all possible key types - /// supported by [`KeyProvider::load_private_key()`]. - fn fips(&self) -> bool { - false - } -} - -/// A supported key exchange group. -/// -/// This type carries both configuration and implementation. Specifically, -/// it has a TLS-level name expressed using the [`NamedGroup`] enum, and -/// a function which produces a [`ActiveKeyExchange`]. -/// -/// Compare with [`NamedGroup`], which carries solely a protocol identifier. -pub trait SupportedKxGroup: Send + Sync + Debug { - /// Start a key exchange. - /// - /// This will prepare an ephemeral secret key in the supported group, and a corresponding - /// public key. The key exchange can be completed by calling [ActiveKeyExchange#complete] - /// or discarded. - /// - /// # Errors - /// - /// This can fail if the random source fails during ephemeral key generation. - fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error>; - - /// Start and complete a key exchange, in one operation. - /// - /// The default implementation for this calls `start()` and then calls - /// `complete()` on the result. This is suitable for Diffie-Hellman-like - /// key exchange algorithms, where there is not a data dependency between - /// our key share (named "pub_key" in this API) and the peer's (`peer_pub_key`). - /// - /// If there is such a data dependency (like key encapsulation mechanisms), this - /// function should be implemented. - fn start_and_complete(&self, peer_pub_key: &[u8]) -> Result<CompletedKeyExchange, Error> { - let kx = self.start()?; - - Ok(CompletedKeyExchange { - group: kx.group(), - pub_key: kx.pub_key().to_vec(), - secret: kx.complete(peer_pub_key)?, - }) - } - - /// FFDHE group the `SupportedKxGroup` operates in. - /// - /// Return `None` if this group is not a FFDHE one. - /// - /// The default implementation calls `FfdheGroup::from_named_group`: this function - /// is extremely linker-unfriendly so it is recommended all key exchange implementers - /// provide this function. - /// - /// `rustls::ffdhe_groups` contains suitable values to return from this, - /// for example [`rustls::ffdhe_groups::FFDHE2048`][crate::ffdhe_groups::FFDHE2048]. - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - #[allow(deprecated)] - FfdheGroup::from_named_group(self.name()) - } - - /// Named group the SupportedKxGroup operates in. - /// - /// If the `NamedGroup` enum does not have a name for the algorithm you are implementing, - /// you can use [`NamedGroup::Unknown`]. - fn name(&self) -> NamedGroup; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } - - /// Return `true` if this should be offered/selected with the given version. - /// - /// The default implementation returns true for all versions. - fn usable_for_version(&self, _version: ProtocolVersion) -> bool { - true - } -} - -/// An in-progress key exchange originating from a [`SupportedKxGroup`]. -pub trait ActiveKeyExchange: Send + Sync { - /// Completes the key exchange, given the peer's public key. - /// - /// This method must return an error if `peer_pub_key` is invalid: either - /// mis-encoded, or an invalid public key (such as, but not limited to, being - /// in a small order subgroup). - /// - /// If the key exchange algorithm is FFDHE, the result must be left-padded with zeros, - /// as required by [RFC 8446](https://www.rfc-editor.org/rfc/rfc8446#section-7.4.1) - /// (see [`complete_for_tls_version()`](Self::complete_for_tls_version) for more details). - /// - /// The shared secret is returned as a [`SharedSecret`] which can be constructed - /// from a `&[u8]`. - /// - /// This consumes and so terminates the [`ActiveKeyExchange`]. - fn complete(self: Box<Self>, peer_pub_key: &[u8]) -> Result<SharedSecret, Error>; - - /// Completes the key exchange for the given TLS version, given the peer's public key. - /// - /// Note that finite-field Diffie–Hellman key exchange has different requirements for the derived - /// shared secret in TLS 1.2 and TLS 1.3 (ECDHE key exchange is the same in TLS 1.2 and TLS 1.3): - /// - /// In TLS 1.2, the calculated secret is required to be stripped of leading zeros - /// [(RFC 5246)](https://www.rfc-editor.org/rfc/rfc5246#section-8.1.2). - /// - /// In TLS 1.3, the calculated secret is required to be padded with leading zeros to be the same - /// byte-length as the group modulus [(RFC 8446)](https://www.rfc-editor.org/rfc/rfc8446#section-7.4.1). - /// - /// The default implementation of this method delegates to [`complete()`](Self::complete) assuming it is - /// implemented for TLS 1.3 (i.e., for FFDHE KX, removes padding as needed). Implementers of this trait - /// are encouraged to just implement [`complete()`](Self::complete) assuming TLS 1.3, and let the default - /// implementation of this method handle TLS 1.2-specific requirements. - /// - /// This method must return an error if `peer_pub_key` is invalid: either - /// mis-encoded, or an invalid public key (such as, but not limited to, being - /// in a small order subgroup). - /// - /// The shared secret is returned as a [`SharedSecret`] which can be constructed - /// from a `&[u8]`. - /// - /// This consumes and so terminates the [`ActiveKeyExchange`]. - fn complete_for_tls_version( - self: Box<Self>, - peer_pub_key: &[u8], - tls_version: &SupportedProtocolVersion, - ) -> Result<SharedSecret, Error> { - if tls_version.version != ProtocolVersion::TLSv1_2 { - return self.complete(peer_pub_key); - } - - let group = self.group(); - let mut complete_res = self.complete(peer_pub_key)?; - if group.key_exchange_algorithm() == KeyExchangeAlgorithm::DHE { - complete_res.strip_leading_zeros(); - } - Ok(complete_res) - } - - /// For hybrid key exchanges, returns the [`NamedGroup`] and key share - /// for the classical half of this key exchange. - /// - /// There is no requirement for a hybrid scheme (or any other!) to implement - /// `hybrid_component()`. It only enables an optimization; described below. - /// - /// "Hybrid" means a key exchange algorithm which is constructed from two - /// (or more) independent component algorithms. Usually one is post-quantum-secure, - /// and the other is "classical". See - /// <https://datatracker.ietf.org/doc/draft-ietf-tls-hybrid-design/11/> - /// - /// # Background - /// Rustls always sends a presumptive key share in its `ClientHello`, using - /// (absent any other information) the first item in [`CryptoProvider::kx_groups`]. - /// If the server accepts the client's selection, it can complete the handshake - /// using that key share. If not, the server sends a `HelloRetryRequest` instructing - /// the client to send a different key share instead. - /// - /// This request costs an extra round trip, and wastes the key exchange computation - /// (in [`SupportedKxGroup::start()`]) the client already did. We would - /// like to avoid those wastes if possible. - /// - /// It is early days for post-quantum-secure hybrid key exchange deployment. - /// This means (commonly) continuing to offer both the hybrid and classical - /// key exchanges, so the handshake can be completed without a `HelloRetryRequest` - /// for servers that support the offered hybrid or classical schemes. - /// - /// Implementing `hybrid_component()` enables two optimizations: - /// - /// 1. Sending both the hybrid and classical key shares in the `ClientHello`. - /// - /// 2. Performing the classical key exchange setup only once. This is important - /// because the classical key exchange setup is relatively expensive. - /// This optimization is permitted and described in - /// <https://www.ietf.org/archive/id/draft-ietf-tls-hybrid-design-11.html#section-3.2> - /// - /// Both of these only happen if the classical algorithm appears separately in - /// the client's [`CryptoProvider::kx_groups`], and if the hybrid algorithm appears - /// first in that list. - /// - /// # How it works - /// This function is only called by rustls for clients. It is called when - /// constructing the initial `ClientHello`. rustls follows these steps: - /// - /// 1. If the return value is `None`, nothing further happens. - /// 2. If the given [`NamedGroup`] does not appear in - /// [`CryptoProvider::kx_groups`], nothing further happens. - /// 3. The given key share is added to the `ClientHello`, after the hybrid entry. - /// - /// Then, one of three things may happen when the server replies to the `ClientHello`: - /// - /// 1. The server sends a `HelloRetryRequest`. Everything is thrown away and - /// we start again. - /// 2. The server agrees to our hybrid key exchange: rustls calls - /// [`ActiveKeyExchange::complete()`] consuming `self`. - /// 3. The server agrees to our classical key exchange: rustls calls - /// [`ActiveKeyExchange::complete_hybrid_component()`] which - /// discards the hybrid key data, and completes just the classical key exchange. - fn hybrid_component(&self) -> Option<(NamedGroup, &[u8])> { - None - } - - /// Completes the classical component of the key exchange, given the peer's public key. - /// - /// This is only called if `hybrid_component` returns `Some(_)`. - /// - /// This method must return an error if `peer_pub_key` is invalid: either - /// mis-encoded, or an invalid public key (such as, but not limited to, being - /// in a small order subgroup). - /// - /// The shared secret is returned as a [`SharedSecret`] which can be constructed - /// from a `&[u8]`. - /// - /// See the documentation on [`Self::hybrid_component()`] for explanation. - fn complete_hybrid_component( - self: Box<Self>, - _peer_pub_key: &[u8], - ) -> Result<SharedSecret, Error> { - unreachable!("only called if `hybrid_component()` implemented") - } - - /// Return the public key being used. - /// - /// For ECDHE, the encoding required is defined in - /// [RFC8446 section 4.2.8.2](https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.2). - /// - /// For FFDHE, the encoding required is defined in - /// [RFC8446 section 4.2.8.1](https://www.rfc-editor.org/rfc/rfc8446#section-4.2.8.1). - fn pub_key(&self) -> &[u8]; - - /// FFDHE group the `ActiveKeyExchange` is operating in. - /// - /// Return `None` if this group is not a FFDHE one. - /// - /// The default implementation calls `FfdheGroup::from_named_group`: this function - /// is extremely linker-unfriendly so it is recommended all key exchange implementers - /// provide this function. - /// - /// `rustls::ffdhe_groups` contains suitable values to return from this, - /// for example [`rustls::ffdhe_groups::FFDHE2048`][crate::ffdhe_groups::FFDHE2048]. - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - #[allow(deprecated)] - FfdheGroup::from_named_group(self.group()) - } - - /// Return the group being used. - fn group(&self) -> NamedGroup; -} - -/// The result from [`SupportedKxGroup::start_and_complete()`]. -pub struct CompletedKeyExchange { - /// Which group was used. - pub group: NamedGroup, - - /// Our key share (sometimes a public key). - pub pub_key: Vec<u8>, - - /// The computed shared secret. - pub secret: SharedSecret, -} - -/// The result from [`ActiveKeyExchange::complete`] or [`ActiveKeyExchange::complete_hybrid_component`]. -pub struct SharedSecret { - buf: Vec<u8>, - offset: usize, -} - -impl SharedSecret { - /// Returns the shared secret as a slice of bytes. - pub fn secret_bytes(&self) -> &[u8] { - &self.buf[self.offset..] - } - - /// Removes leading zeros from `secret_bytes()` by adjusting the `offset`. - /// - /// This function does not re-allocate. - fn strip_leading_zeros(&mut self) { - let start = self - .secret_bytes() - .iter() - .enumerate() - .find(|(_i, x)| **x != 0) - .map(|(i, _x)| i) - .unwrap_or(self.secret_bytes().len()); - self.offset += start; - } -} - -impl Drop for SharedSecret { - fn drop(&mut self) { - self.buf.zeroize(); - } -} - -impl From<&[u8]> for SharedSecret { - fn from(source: &[u8]) -> Self { - Self { - buf: source.to_vec(), - offset: 0, - } - } -} - -impl From<Vec<u8>> for SharedSecret { - fn from(buf: Vec<u8>) -> Self { - Self { buf, offset: 0 } - } -} - -/// This function returns a [`CryptoProvider`] that uses -/// FIPS140-3-approved cryptography. -/// -/// Using this function expresses in your code that you require -/// FIPS-approved cryptography, and will not compile if you make -/// a mistake with cargo features. -/// -/// See our [FIPS documentation](crate::manual::_06_fips) for -/// more detail. -/// -/// Install this as the process-default provider, like: -/// -/// ```rust -/// # #[cfg(feature = "fips")] { -/// rustls::crypto::default_fips_provider().install_default() -/// .expect("default provider already set elsewhere"); -/// # } -/// ``` -/// -/// You can also use this explicitly, like: -/// -/// ```rust -/// # #[cfg(feature = "fips")] { -/// # let root_store = rustls::RootCertStore::empty(); -/// let config = rustls::ClientConfig::builder_with_provider( -/// rustls::crypto::default_fips_provider().into() -/// ) -/// .with_safe_default_protocol_versions() -/// .unwrap() -/// .with_root_certificates(root_store) -/// .with_no_client_auth(); -/// # } -/// ``` -#[cfg(all(feature = "aws_lc_rs", any(feature = "fips", docsrs)))] -#[cfg_attr(docsrs, doc(cfg(feature = "fips")))] -pub fn default_fips_provider() -> CryptoProvider { - aws_lc_rs::default_provider() -} - -mod static_default { - #[cfg(not(feature = "std"))] - use alloc::boxed::Box; - #[cfg(feature = "std")] - use std::sync::OnceLock; - - #[cfg(not(feature = "std"))] - use once_cell::race::OnceBox; - - use super::CryptoProvider; - use crate::sync::Arc; - - #[cfg(feature = "std")] - pub(crate) fn install_default( - default_provider: CryptoProvider, - ) -> Result<(), Arc<CryptoProvider>> { - PROCESS_DEFAULT_PROVIDER.set(Arc::new(default_provider)) - } - - #[cfg(not(feature = "std"))] - pub(crate) fn install_default( - default_provider: CryptoProvider, - ) -> Result<(), Arc<CryptoProvider>> { - PROCESS_DEFAULT_PROVIDER - .set(Box::new(Arc::new(default_provider))) - .map_err(|e| *e) - } - - pub(crate) fn get_default() -> Option<&'static Arc<CryptoProvider>> { - PROCESS_DEFAULT_PROVIDER.get() - } - - #[cfg(feature = "std")] - static PROCESS_DEFAULT_PROVIDER: OnceLock<Arc<CryptoProvider>> = OnceLock::new(); - #[cfg(not(feature = "std"))] - static PROCESS_DEFAULT_PROVIDER: OnceBox<Arc<CryptoProvider>> = OnceBox::new(); -} - -#[cfg(test)] -mod tests { - use std::vec; - - use super::SharedSecret; - - #[test] - fn test_shared_secret_strip_leading_zeros() { - let test_cases = [ - (vec![0, 1], vec![1]), - (vec![1], vec![1]), - (vec![1, 0, 2], vec![1, 0, 2]), - (vec![0, 0, 1, 2], vec![1, 2]), - (vec![0, 0, 0], vec![]), - (vec![], vec![]), - ]; - for (buf, expected) in test_cases { - let mut secret = SharedSecret::from(&buf[..]); - assert_eq!(secret.secret_bytes(), buf); - secret.strip_leading_zeros(); - assert_eq!(secret.secret_bytes(), expected); - } - } -} diff --git a/vendor/rustls/src/crypto/ring/hash.rs b/vendor/rustls/src/crypto/ring/hash.rs deleted file mode 100644 index 220dc536..00000000 --- a/vendor/rustls/src/crypto/ring/hash.rs +++ /dev/null @@ -1,60 +0,0 @@ -#![allow(clippy::duplicate_mod)] - -use alloc::boxed::Box; - -use super::ring_like::digest; -use crate::crypto; -use crate::msgs::enums::HashAlgorithm; - -pub(crate) static SHA256: Hash = Hash(&digest::SHA256, HashAlgorithm::SHA256); -pub(crate) static SHA384: Hash = Hash(&digest::SHA384, HashAlgorithm::SHA384); - -pub(crate) struct Hash(&'static digest::Algorithm, HashAlgorithm); - -impl crypto::hash::Hash for Hash { - fn start(&self) -> Box<dyn crypto::hash::Context> { - Box::new(Context(digest::Context::new(self.0))) - } - - fn hash(&self, bytes: &[u8]) -> crypto::hash::Output { - let mut ctx = digest::Context::new(self.0); - ctx.update(bytes); - convert(ctx.finish()) - } - - fn output_len(&self) -> usize { - self.0.output_len() - } - - fn algorithm(&self) -> HashAlgorithm { - self.1 - } - - fn fips(&self) -> bool { - super::fips() - } -} - -struct Context(digest::Context); - -impl crypto::hash::Context for Context { - fn fork_finish(&self) -> crypto::hash::Output { - convert(self.0.clone().finish()) - } - - fn fork(&self) -> Box<dyn crypto::hash::Context> { - Box::new(Self(self.0.clone())) - } - - fn finish(self: Box<Self>) -> crypto::hash::Output { - convert(self.0.finish()) - } - - fn update(&mut self, data: &[u8]) { - self.0.update(data); - } -} - -fn convert(val: digest::Digest) -> crypto::hash::Output { - crypto::hash::Output::new(val.as_ref()) -} diff --git a/vendor/rustls/src/crypto/ring/hmac.rs b/vendor/rustls/src/crypto/ring/hmac.rs deleted file mode 100644 index 7f30aba4..00000000 --- a/vendor/rustls/src/crypto/ring/hmac.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![allow(clippy::duplicate_mod)] - -use alloc::boxed::Box; - -use super::ring_like; -use crate::crypto; - -pub(crate) static HMAC_SHA256: Hmac = Hmac(&ring_like::hmac::HMAC_SHA256); -pub(crate) static HMAC_SHA384: Hmac = Hmac(&ring_like::hmac::HMAC_SHA384); -#[allow(dead_code)] // Only used for TLS 1.2 prf test, and aws-lc-rs HPKE suites. -pub(crate) static HMAC_SHA512: Hmac = Hmac(&ring_like::hmac::HMAC_SHA512); - -pub(crate) struct Hmac(&'static ring_like::hmac::Algorithm); - -impl crypto::hmac::Hmac for Hmac { - fn with_key(&self, key: &[u8]) -> Box<dyn crypto::hmac::Key> { - Box::new(Key(ring_like::hmac::Key::new(*self.0, key))) - } - - fn hash_output_len(&self) -> usize { - self.0.digest_algorithm().output_len() - } - - fn fips(&self) -> bool { - super::fips() - } -} - -struct Key(ring_like::hmac::Key); - -impl crypto::hmac::Key for Key { - fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag { - let mut ctx = ring_like::hmac::Context::with_key(&self.0); - ctx.update(first); - for d in middle { - ctx.update(d); - } - ctx.update(last); - crypto::hmac::Tag::new(ctx.sign().as_ref()) - } - - fn tag_len(&self) -> usize { - self.0 - .algorithm() - .digest_algorithm() - .output_len() - } -} diff --git a/vendor/rustls/src/crypto/ring/kx.rs b/vendor/rustls/src/crypto/ring/kx.rs deleted file mode 100644 index 6e0da227..00000000 --- a/vendor/rustls/src/crypto/ring/kx.rs +++ /dev/null @@ -1,188 +0,0 @@ -#![allow(clippy::duplicate_mod)] - -use alloc::boxed::Box; -use core::fmt; - -use super::ring_like::agreement; -use super::ring_like::rand::SystemRandom; -use crate::crypto::{ActiveKeyExchange, FfdheGroup, SharedSecret, SupportedKxGroup}; -use crate::error::{Error, PeerMisbehaved}; -use crate::msgs::enums::NamedGroup; -use crate::rand::GetRandomFailed; - -/// A key-exchange group supported by *ring*. -struct KxGroup { - /// The IANA "TLS Supported Groups" name of the group - name: NamedGroup, - - /// The corresponding ring agreement::Algorithm - agreement_algorithm: &'static agreement::Algorithm, - - /// Whether the algorithm is allowed by FIPS - /// - /// `SupportedKxGroup::fips()` is true if and only if the algorithm is allowed, - /// _and_ the implementation is FIPS-validated. - fips_allowed: bool, - - /// aws-lc-rs 1.9 and later accepts more formats of public keys than - /// just uncompressed. - /// - /// That is not compatible with TLS: - /// - TLS1.3 outlaws other encodings, - /// - TLS1.2 negotiates other encodings (we only offer uncompressed), and - /// defaults to uncompressed if negotiation is not done. - /// - /// This function should return `true` if the basic shape of its argument - /// is consistent with an uncompressed point encoding. It does not need - /// to verify that the point is on the curve (if the curve requires that - /// for security); aws-lc-rs/ring must do that. - pub_key_validator: fn(&[u8]) -> bool, -} - -impl SupportedKxGroup for KxGroup { - fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> { - let rng = SystemRandom::new(); - let priv_key = agreement::EphemeralPrivateKey::generate(self.agreement_algorithm, &rng) - .map_err(|_| GetRandomFailed)?; - - let pub_key = priv_key - .compute_public_key() - .map_err(|_| GetRandomFailed)?; - - Ok(Box::new(KeyExchange { - name: self.name, - agreement_algorithm: self.agreement_algorithm, - priv_key, - pub_key, - pub_key_validator: self.pub_key_validator, - })) - } - - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - None - } - - fn name(&self) -> NamedGroup { - self.name - } - - fn fips(&self) -> bool { - self.fips_allowed && super::fips() - } -} - -impl fmt::Debug for KxGroup { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.name.fmt(f) - } -} - -/// Ephemeral ECDH on curve25519 (see RFC7748) -pub static X25519: &dyn SupportedKxGroup = &KxGroup { - name: NamedGroup::X25519, - agreement_algorithm: &agreement::X25519, - - // "Curves that are included in SP 800-186 but not included in SP 800-56Arev3 are - // not approved for key agreement. E.g., the ECDH X25519 and X448 key agreement - // schemes (defined in RFC 7748) that use Curve25519 and Curve448, respectively, - // are not compliant to SP 800-56Arev3." - // -- <https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf> - fips_allowed: false, - - pub_key_validator: |point: &[u8]| point.len() == 32, -}; - -/// Ephemeral ECDH on secp256r1 (aka NIST-P256) -pub static SECP256R1: &dyn SupportedKxGroup = &KxGroup { - name: NamedGroup::secp256r1, - agreement_algorithm: &agreement::ECDH_P256, - fips_allowed: true, - pub_key_validator: uncompressed_point, -}; - -/// Ephemeral ECDH on secp384r1 (aka NIST-P384) -pub static SECP384R1: &dyn SupportedKxGroup = &KxGroup { - name: NamedGroup::secp384r1, - agreement_algorithm: &agreement::ECDH_P384, - fips_allowed: true, - pub_key_validator: uncompressed_point, -}; - -fn uncompressed_point(point: &[u8]) -> bool { - // See `UncompressedPointRepresentation`, which is a retelling of - // SEC1 section 2.3.3 "Elliptic-Curve-Point-to-Octet-String Conversion" - // <https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.8.2> - matches!(point.first(), Some(0x04)) -} - -/// An in-progress key exchange. This has the algorithm, -/// our private key, and our public key. -struct KeyExchange { - name: NamedGroup, - agreement_algorithm: &'static agreement::Algorithm, - priv_key: agreement::EphemeralPrivateKey, - pub_key: agreement::PublicKey, - pub_key_validator: fn(&[u8]) -> bool, -} - -impl ActiveKeyExchange for KeyExchange { - /// Completes the key exchange, given the peer's public key. - fn complete(self: Box<Self>, peer: &[u8]) -> Result<SharedSecret, Error> { - if !(self.pub_key_validator)(peer) { - return Err(PeerMisbehaved::InvalidKeyShare.into()); - } - let peer_key = agreement::UnparsedPublicKey::new(self.agreement_algorithm, peer); - super::ring_shim::agree_ephemeral(self.priv_key, &peer_key) - .map_err(|_| PeerMisbehaved::InvalidKeyShare.into()) - } - - fn ffdhe_group(&self) -> Option<FfdheGroup<'static>> { - None - } - - /// Return the group being used. - fn group(&self) -> NamedGroup { - self.name - } - - /// Return the public key being used. - fn pub_key(&self) -> &[u8] { - self.pub_key.as_ref() - } -} - -#[cfg(test)] -mod tests { - use std::format; - - #[test] - fn kxgroup_fmt_yields_name() { - assert_eq!("X25519", format!("{:?}", super::X25519)); - } -} - -#[cfg(bench)] -mod benchmarks { - #[bench] - fn bench_x25519(b: &mut test::Bencher) { - bench_any(b, super::X25519); - } - - #[bench] - fn bench_ecdh_p256(b: &mut test::Bencher) { - bench_any(b, super::SECP256R1); - } - - #[bench] - fn bench_ecdh_p384(b: &mut test::Bencher) { - bench_any(b, super::SECP384R1); - } - - fn bench_any(b: &mut test::Bencher, kxg: &dyn super::SupportedKxGroup) { - b.iter(|| { - let akx = kxg.start().unwrap(); - let pub_key = akx.pub_key().to_vec(); - test::black_box(akx.complete(&pub_key).unwrap()); - }); - } -} diff --git a/vendor/rustls/src/crypto/ring/mod.rs b/vendor/rustls/src/crypto/ring/mod.rs deleted file mode 100644 index 3ce99b15..00000000 --- a/vendor/rustls/src/crypto/ring/mod.rs +++ /dev/null @@ -1,203 +0,0 @@ -use pki_types::PrivateKeyDer; -pub(crate) use ring as ring_like; -use webpki::ring as webpki_algs; - -use crate::Error; -use crate::crypto::{CryptoProvider, KeyProvider, SecureRandom, SupportedKxGroup}; -use crate::enums::SignatureScheme; -use crate::rand::GetRandomFailed; -use crate::sign::SigningKey; -use crate::suites::SupportedCipherSuite; -use crate::sync::Arc; -use crate::webpki::WebPkiSupportedAlgorithms; - -/// Using software keys for authentication. -pub mod sign; - -pub(crate) mod hash; -#[cfg(any(test, feature = "tls12"))] -pub(crate) mod hmac; -pub(crate) mod kx; -pub(crate) mod quic; -#[cfg(feature = "std")] -pub(crate) mod ticketer; -#[cfg(feature = "tls12")] -pub(crate) mod tls12; -pub(crate) mod tls13; - -/// A `CryptoProvider` backed by the [*ring*] crate. -/// -/// [*ring*]: https://github.com/briansmith/ring -pub fn default_provider() -> CryptoProvider { - CryptoProvider { - cipher_suites: DEFAULT_CIPHER_SUITES.to_vec(), - kx_groups: DEFAULT_KX_GROUPS.to_vec(), - signature_verification_algorithms: SUPPORTED_SIG_ALGS, - secure_random: &Ring, - key_provider: &Ring, - } -} - -/// Default crypto provider. -#[derive(Debug)] -struct Ring; - -impl SecureRandom for Ring { - fn fill(&self, buf: &mut [u8]) -> Result<(), GetRandomFailed> { - use ring_like::rand::SecureRandom; - - ring_like::rand::SystemRandom::new() - .fill(buf) - .map_err(|_| GetRandomFailed) - } -} - -impl KeyProvider for Ring { - fn load_private_key( - &self, - key_der: PrivateKeyDer<'static>, - ) -> Result<Arc<dyn SigningKey>, Error> { - sign::any_supported_type(&key_der) - } -} - -/// The cipher suite configuration that an application should use by default. -/// -/// This will be [`ALL_CIPHER_SUITES`] sans any supported cipher suites that -/// shouldn't be enabled by most applications. -pub static DEFAULT_CIPHER_SUITES: &[SupportedCipherSuite] = ALL_CIPHER_SUITES; - -/// A list of all the cipher suites supported by the rustls *ring* provider. -pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[ - // TLS1.3 suites - tls13::TLS13_AES_256_GCM_SHA384, - tls13::TLS13_AES_128_GCM_SHA256, - tls13::TLS13_CHACHA20_POLY1305_SHA256, - // TLS1.2 suites - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - #[cfg(feature = "tls12")] - tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, -]; - -/// All defined cipher suites supported by *ring* appear in this module. -pub mod cipher_suite { - #[cfg(feature = "tls12")] - pub use super::tls12::{ - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - }; - pub use super::tls13::{ - TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256, - }; -} - -/// A `WebPkiSupportedAlgorithms` value that reflects webpki's capabilities when -/// compiled against *ring*. -static SUPPORTED_SIG_ALGS: WebPkiSupportedAlgorithms = WebPkiSupportedAlgorithms { - all: &[ - webpki_algs::ECDSA_P256_SHA256, - webpki_algs::ECDSA_P256_SHA384, - webpki_algs::ECDSA_P384_SHA256, - webpki_algs::ECDSA_P384_SHA384, - webpki_algs::ED25519, - webpki_algs::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, - webpki_algs::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, - webpki_algs::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, - webpki_algs::RSA_PKCS1_2048_8192_SHA256, - webpki_algs::RSA_PKCS1_2048_8192_SHA384, - webpki_algs::RSA_PKCS1_2048_8192_SHA512, - webpki_algs::RSA_PKCS1_2048_8192_SHA256_ABSENT_PARAMS, - webpki_algs::RSA_PKCS1_2048_8192_SHA384_ABSENT_PARAMS, - webpki_algs::RSA_PKCS1_2048_8192_SHA512_ABSENT_PARAMS, - ], - mapping: &[ - // Note: for TLS1.2 the curve is not fixed by SignatureScheme. For TLS1.3 it is. - ( - SignatureScheme::ECDSA_NISTP384_SHA384, - &[ - webpki_algs::ECDSA_P384_SHA384, - webpki_algs::ECDSA_P256_SHA384, - ], - ), - ( - SignatureScheme::ECDSA_NISTP256_SHA256, - &[ - webpki_algs::ECDSA_P256_SHA256, - webpki_algs::ECDSA_P384_SHA256, - ], - ), - (SignatureScheme::ED25519, &[webpki_algs::ED25519]), - ( - SignatureScheme::RSA_PSS_SHA512, - &[webpki_algs::RSA_PSS_2048_8192_SHA512_LEGACY_KEY], - ), - ( - SignatureScheme::RSA_PSS_SHA384, - &[webpki_algs::RSA_PSS_2048_8192_SHA384_LEGACY_KEY], - ), - ( - SignatureScheme::RSA_PSS_SHA256, - &[webpki_algs::RSA_PSS_2048_8192_SHA256_LEGACY_KEY], - ), - ( - SignatureScheme::RSA_PKCS1_SHA512, - &[webpki_algs::RSA_PKCS1_2048_8192_SHA512], - ), - ( - SignatureScheme::RSA_PKCS1_SHA384, - &[webpki_algs::RSA_PKCS1_2048_8192_SHA384], - ), - ( - SignatureScheme::RSA_PKCS1_SHA256, - &[webpki_algs::RSA_PKCS1_2048_8192_SHA256], - ), - ], -}; - -/// All defined key exchange groups supported by *ring* appear in this module. -/// -/// [`ALL_KX_GROUPS`] is provided as an array of all of these values. -/// [`DEFAULT_KX_GROUPS`] is provided as an array of this provider's defaults. -pub mod kx_group { - pub use super::kx::{SECP256R1, SECP384R1, X25519}; -} - -/// A list of the default key exchange groups supported by this provider. -pub static DEFAULT_KX_GROUPS: &[&dyn SupportedKxGroup] = ALL_KX_GROUPS; - -/// A list of all the key exchange groups supported by this provider. -pub static ALL_KX_GROUPS: &[&dyn SupportedKxGroup] = - &[kx_group::X25519, kx_group::SECP256R1, kx_group::SECP384R1]; - -#[cfg(feature = "std")] -pub use ticketer::Ticketer; - -/// Compatibility shims between ring 0.16.x and 0.17.x API -mod ring_shim { - use super::ring_like; - use crate::crypto::SharedSecret; - - pub(super) fn agree_ephemeral( - priv_key: ring_like::agreement::EphemeralPrivateKey, - peer_key: &ring_like::agreement::UnparsedPublicKey<&[u8]>, - ) -> Result<SharedSecret, ()> { - ring_like::agreement::agree_ephemeral(priv_key, peer_key, |secret| { - SharedSecret::from(secret) - }) - .map_err(|_| ()) - } -} - -pub(super) fn fips() -> bool { - false -} diff --git a/vendor/rustls/src/crypto/ring/quic.rs b/vendor/rustls/src/crypto/ring/quic.rs deleted file mode 100644 index 3d0dc928..00000000 --- a/vendor/rustls/src/crypto/ring/quic.rs +++ /dev/null @@ -1,416 +0,0 @@ -#![allow(clippy::duplicate_mod)] - -use alloc::boxed::Box; - -use super::ring_like::aead; -use crate::crypto::cipher::{AeadKey, Iv, Nonce}; -use crate::error::Error; -use crate::quic; - -pub(crate) struct HeaderProtectionKey(aead::quic::HeaderProtectionKey); - -impl HeaderProtectionKey { - pub(crate) fn new(key: AeadKey, alg: &'static aead::quic::Algorithm) -> Self { - Self(aead::quic::HeaderProtectionKey::new(alg, key.as_ref()).unwrap()) - } - - fn xor_in_place( - &self, - sample: &[u8], - first: &mut u8, - packet_number: &mut [u8], - masked: bool, - ) -> Result<(), Error> { - // This implements "Header Protection Application" almost verbatim. - // <https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1> - - let mask = self - .0 - .new_mask(sample) - .map_err(|_| Error::General("sample of invalid length".into()))?; - - // The `unwrap()` will not panic because `new_mask` returns a - // non-empty result. - let (first_mask, pn_mask) = mask.split_first().unwrap(); - - // It is OK for the `mask` to be longer than `packet_number`, - // but a valid `packet_number` will never be longer than `mask`. - if packet_number.len() > pn_mask.len() { - return Err(Error::General("packet number too long".into())); - } - - // Infallible from this point on. Before this point, `first` and - // `packet_number` are unchanged. - - const LONG_HEADER_FORM: u8 = 0x80; - let bits = match *first & LONG_HEADER_FORM == LONG_HEADER_FORM { - true => 0x0f, // Long header: 4 bits masked - false => 0x1f, // Short header: 5 bits masked - }; - - let first_plain = match masked { - // When unmasking, use the packet length bits after unmasking - true => *first ^ (first_mask & bits), - // When masking, use the packet length bits before masking - false => *first, - }; - let pn_len = (first_plain & 0x03) as usize + 1; - - *first ^= first_mask & bits; - for (dst, m) in packet_number - .iter_mut() - .zip(pn_mask) - .take(pn_len) - { - *dst ^= m; - } - - Ok(()) - } -} - -impl quic::HeaderProtectionKey for HeaderProtectionKey { - fn encrypt_in_place( - &self, - sample: &[u8], - first: &mut u8, - packet_number: &mut [u8], - ) -> Result<(), Error> { - self.xor_in_place(sample, first, packet_number, false) - } - - fn decrypt_in_place( - &self, - sample: &[u8], - first: &mut u8, - packet_number: &mut [u8], - ) -> Result<(), Error> { - self.xor_in_place(sample, first, packet_number, true) - } - - #[inline] - fn sample_len(&self) -> usize { - self.0.algorithm().sample_len() - } -} - -pub(crate) struct PacketKey { - /// Encrypts or decrypts a packet's payload - key: aead::LessSafeKey, - /// Computes unique nonces for each packet - iv: Iv, - /// Confidentiality limit (see [`quic::PacketKey::confidentiality_limit`]) - confidentiality_limit: u64, - /// Integrity limit (see [`quic::PacketKey::integrity_limit`]) - integrity_limit: u64, -} - -impl PacketKey { - pub(crate) fn new( - key: AeadKey, - iv: Iv, - confidentiality_limit: u64, - integrity_limit: u64, - aead_algorithm: &'static aead::Algorithm, - ) -> Self { - Self { - key: aead::LessSafeKey::new( - aead::UnboundKey::new(aead_algorithm, key.as_ref()).unwrap(), - ), - iv, - confidentiality_limit, - integrity_limit, - } - } -} - -impl quic::PacketKey for PacketKey { - fn encrypt_in_place( - &self, - packet_number: u64, - header: &[u8], - payload: &mut [u8], - ) -> Result<quic::Tag, Error> { - let aad = aead::Aad::from(header); - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, packet_number).0); - let tag = self - .key - .seal_in_place_separate_tag(nonce, aad, payload) - .map_err(|_| Error::EncryptError)?; - Ok(quic::Tag::from(tag.as_ref())) - } - - /// Decrypt a QUIC packet - /// - /// Takes the packet `header`, which is used as the additional authenticated data, and the - /// `payload`, which includes the authentication tag. - /// - /// If the return value is `Ok`, the decrypted payload can be found in `payload`, up to the - /// length found in the return value. - fn decrypt_in_place<'a>( - &self, - packet_number: u64, - header: &[u8], - payload: &'a mut [u8], - ) -> Result<&'a [u8], Error> { - let payload_len = payload.len(); - let aad = aead::Aad::from(header); - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, packet_number).0); - self.key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)?; - - let plain_len = payload_len - self.key.algorithm().tag_len(); - Ok(&payload[..plain_len]) - } - - /// Tag length for the underlying AEAD algorithm - #[inline] - fn tag_len(&self) -> usize { - self.key.algorithm().tag_len() - } - - /// Confidentiality limit (see [`quic::PacketKey::confidentiality_limit`]) - fn confidentiality_limit(&self) -> u64 { - self.confidentiality_limit - } - - /// Integrity limit (see [`quic::PacketKey::integrity_limit`]) - fn integrity_limit(&self) -> u64 { - self.integrity_limit - } -} - -pub(crate) struct KeyBuilder { - pub(crate) packet_alg: &'static aead::Algorithm, - pub(crate) header_alg: &'static aead::quic::Algorithm, - pub(crate) confidentiality_limit: u64, - pub(crate) integrity_limit: u64, -} - -impl quic::Algorithm for KeyBuilder { - fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn quic::PacketKey> { - Box::new(PacketKey::new( - key, - iv, - self.confidentiality_limit, - self.integrity_limit, - self.packet_alg, - )) - } - - fn header_protection_key(&self, key: AeadKey) -> Box<dyn quic::HeaderProtectionKey> { - Box::new(HeaderProtectionKey::new(key, self.header_alg)) - } - - fn aead_key_len(&self) -> usize { - self.packet_alg.key_len() - } - - fn fips(&self) -> bool { - super::fips() - } -} - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use std::dbg; - - use super::provider::tls13::{ - TLS13_AES_128_GCM_SHA256_INTERNAL, TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, - }; - use crate::common_state::Side; - use crate::crypto::tls13::OkmBlock; - use crate::quic::*; - - fn test_short_packet(version: Version, expected: &[u8]) { - const PN: u64 = 654360564; - const SECRET: &[u8] = &[ - 0x9a, 0xc3, 0x12, 0xa7, 0xf8, 0x77, 0x46, 0x8e, 0xbe, 0x69, 0x42, 0x27, 0x48, 0xad, - 0x00, 0xa1, 0x54, 0x43, 0xf1, 0x82, 0x03, 0xa0, 0x7d, 0x60, 0x60, 0xf6, 0x88, 0xf3, - 0x0f, 0x21, 0x63, 0x2b, - ]; - - let secret = OkmBlock::new(SECRET); - let builder = KeyBuilder::new( - &secret, - version, - TLS13_CHACHA20_POLY1305_SHA256_INTERNAL - .quic - .unwrap(), - TLS13_CHACHA20_POLY1305_SHA256_INTERNAL.hkdf_provider, - ); - let packet = builder.packet_key(); - let hpk = builder.header_protection_key(); - - const PLAIN: &[u8] = &[0x42, 0x00, 0xbf, 0xf4, 0x01]; - - let mut buf = PLAIN.to_vec(); - let (header, payload) = buf.split_at_mut(4); - let tag = packet - .encrypt_in_place(PN, header, payload) - .unwrap(); - buf.extend(tag.as_ref()); - - let pn_offset = 1; - let (header, sample) = buf.split_at_mut(pn_offset + 4); - let (first, rest) = header.split_at_mut(1); - let sample = &sample[..hpk.sample_len()]; - hpk.encrypt_in_place(sample, &mut first[0], dbg!(rest)) - .unwrap(); - - assert_eq!(&buf, expected); - - let (header, sample) = buf.split_at_mut(pn_offset + 4); - let (first, rest) = header.split_at_mut(1); - let sample = &sample[..hpk.sample_len()]; - hpk.decrypt_in_place(sample, &mut first[0], rest) - .unwrap(); - - let (header, payload_tag) = buf.split_at_mut(4); - let plain = packet - .decrypt_in_place(PN, header, payload_tag) - .unwrap(); - - assert_eq!(plain, &PLAIN[4..]); - } - - #[test] - fn short_packet_header_protection() { - // https://www.rfc-editor.org/rfc/rfc9001.html#name-chacha20-poly1305-short-hea - test_short_packet( - Version::V1, - &[ - 0x4c, 0xfe, 0x41, 0x89, 0x65, 0x5e, 0x5c, 0xd5, 0x5c, 0x41, 0xf6, 0x90, 0x80, 0x57, - 0x5d, 0x79, 0x99, 0xc2, 0x5a, 0x5b, 0xfb, - ], - ); - } - - #[test] - fn key_update_test_vector() { - fn equal_okm(x: &OkmBlock, y: &OkmBlock) -> bool { - x.as_ref() == y.as_ref() - } - - let mut secrets = Secrets::new( - // Constant dummy values for reproducibility - OkmBlock::new( - &[ - 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e, - 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0, - 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf, - ][..], - ), - OkmBlock::new( - &[ - 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61, - 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82, - 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55, - ][..], - ), - TLS13_AES_128_GCM_SHA256_INTERNAL, - TLS13_AES_128_GCM_SHA256_INTERNAL - .quic - .unwrap(), - Side::Client, - Version::V1, - ); - secrets.update(); - - assert!(equal_okm( - &secrets.client, - &OkmBlock::new( - &[ - 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf, - 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1, - 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce - ][..] - ) - )); - assert!(equal_okm( - &secrets.server, - &OkmBlock::new( - &[ - 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca, - 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0, - 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a - ][..] - ) - )); - } - - #[test] - fn short_packet_header_protection_v2() { - // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-chacha20-poly1305-short-head - test_short_packet( - Version::V2, - &[ - 0x55, 0x58, 0xb1, 0xc6, 0x0a, 0xe7, 0xb6, 0xb9, 0x32, 0xbc, 0x27, 0xd7, 0x86, 0xf4, - 0xbc, 0x2b, 0xb2, 0x0f, 0x21, 0x62, 0xba, - ], - ); - } - - #[test] - fn initial_test_vector_v2() { - // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-sample-packet-protection-2 - let icid = [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08]; - let server = Keys::initial( - Version::V2, - TLS13_AES_128_GCM_SHA256_INTERNAL, - TLS13_AES_128_GCM_SHA256_INTERNAL - .quic - .unwrap(), - &icid, - Side::Server, - ); - let mut server_payload = [ - 0x02, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x40, 0x5a, 0x02, 0x00, 0x00, 0x56, 0x03, - 0x03, 0xee, 0xfc, 0xe7, 0xf7, 0xb3, 0x7b, 0xa1, 0xd1, 0x63, 0x2e, 0x96, 0x67, 0x78, - 0x25, 0xdd, 0xf7, 0x39, 0x88, 0xcf, 0xc7, 0x98, 0x25, 0xdf, 0x56, 0x6d, 0xc5, 0x43, - 0x0b, 0x9a, 0x04, 0x5a, 0x12, 0x00, 0x13, 0x01, 0x00, 0x00, 0x2e, 0x00, 0x33, 0x00, - 0x24, 0x00, 0x1d, 0x00, 0x20, 0x9d, 0x3c, 0x94, 0x0d, 0x89, 0x69, 0x0b, 0x84, 0xd0, - 0x8a, 0x60, 0x99, 0x3c, 0x14, 0x4e, 0xca, 0x68, 0x4d, 0x10, 0x81, 0x28, 0x7c, 0x83, - 0x4d, 0x53, 0x11, 0xbc, 0xf3, 0x2b, 0xb9, 0xda, 0x1a, 0x00, 0x2b, 0x00, 0x02, 0x03, - 0x04, - ]; - let mut server_header = [ - 0xd1, 0x6b, 0x33, 0x43, 0xcf, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, - 0xb5, 0x00, 0x40, 0x75, 0x00, 0x01, - ]; - let tag = server - .local - .packet - .encrypt_in_place(1, &server_header, &mut server_payload) - .unwrap(); - let (first, rest) = server_header.split_at_mut(1); - let rest_len = rest.len(); - server - .local - .header - .encrypt_in_place( - &server_payload[2..18], - &mut first[0], - &mut rest[rest_len - 2..], - ) - .unwrap(); - let mut server_packet = server_header.to_vec(); - server_packet.extend(server_payload); - server_packet.extend(tag.as_ref()); - let expected_server_packet = [ - 0xdc, 0x6b, 0x33, 0x43, 0xcf, 0x00, 0x08, 0xf0, 0x67, 0xa5, 0x50, 0x2a, 0x42, 0x62, - 0xb5, 0x00, 0x40, 0x75, 0xd9, 0x2f, 0xaa, 0xf1, 0x6f, 0x05, 0xd8, 0xa4, 0x39, 0x8c, - 0x47, 0x08, 0x96, 0x98, 0xba, 0xee, 0xa2, 0x6b, 0x91, 0xeb, 0x76, 0x1d, 0x9b, 0x89, - 0x23, 0x7b, 0xbf, 0x87, 0x26, 0x30, 0x17, 0x91, 0x53, 0x58, 0x23, 0x00, 0x35, 0xf7, - 0xfd, 0x39, 0x45, 0xd8, 0x89, 0x65, 0xcf, 0x17, 0xf9, 0xaf, 0x6e, 0x16, 0x88, 0x6c, - 0x61, 0xbf, 0xc7, 0x03, 0x10, 0x6f, 0xba, 0xf3, 0xcb, 0x4c, 0xfa, 0x52, 0x38, 0x2d, - 0xd1, 0x6a, 0x39, 0x3e, 0x42, 0x75, 0x75, 0x07, 0x69, 0x80, 0x75, 0xb2, 0xc9, 0x84, - 0xc7, 0x07, 0xf0, 0xa0, 0x81, 0x2d, 0x8c, 0xd5, 0xa6, 0x88, 0x1e, 0xaf, 0x21, 0xce, - 0xda, 0x98, 0xf4, 0xbd, 0x23, 0xf6, 0xfe, 0x1a, 0x3e, 0x2c, 0x43, 0xed, 0xd9, 0xce, - 0x7c, 0xa8, 0x4b, 0xed, 0x85, 0x21, 0xe2, 0xe1, 0x40, - ]; - assert_eq!(server_packet[..], expected_server_packet[..]); - } -} diff --git a/vendor/rustls/src/crypto/ring/sign.rs b/vendor/rustls/src/crypto/ring/sign.rs deleted file mode 100644 index ad318270..00000000 --- a/vendor/rustls/src/crypto/ring/sign.rs +++ /dev/null @@ -1,822 +0,0 @@ -#![allow(clippy::duplicate_mod)] - -use alloc::boxed::Box; -use alloc::string::ToString; -use alloc::vec::Vec; -use alloc::{format, vec}; -use core::fmt::{self, Debug, Formatter}; - -use pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer, SubjectPublicKeyInfoDer, alg_id}; - -use super::ring_like::rand::{SecureRandom, SystemRandom}; -use super::ring_like::signature::{self, EcdsaKeyPair, Ed25519KeyPair, KeyPair, RsaKeyPair}; -use crate::crypto::signer::{Signer, SigningKey, public_key_to_spki}; -use crate::enums::{SignatureAlgorithm, SignatureScheme}; -use crate::error::Error; -use crate::sync::Arc; -use crate::x509::{wrap_concat_in_sequence, wrap_in_octet_string}; - -/// Parse `der` as any supported key encoding/type, returning -/// the first which works. -pub fn any_supported_type(der: &PrivateKeyDer<'_>) -> Result<Arc<dyn SigningKey>, Error> { - if let Ok(rsa) = RsaSigningKey::new(der) { - return Ok(Arc::new(rsa)); - } - - if let Ok(ecdsa) = any_ecdsa_type(der) { - return Ok(ecdsa); - } - - if let PrivateKeyDer::Pkcs8(pkcs8) = der { - if let Ok(eddsa) = any_eddsa_type(pkcs8) { - return Ok(eddsa); - } - } - - Err(Error::General( - "failed to parse private key as RSA, ECDSA, or EdDSA".into(), - )) -} - -/// Parse `der` as any ECDSA key type, returning the first which works. -/// -/// Both SEC1 (PEM section starting with 'BEGIN EC PRIVATE KEY') and PKCS8 -/// (PEM section starting with 'BEGIN PRIVATE KEY') encodings are supported. -pub fn any_ecdsa_type(der: &PrivateKeyDer<'_>) -> Result<Arc<dyn SigningKey>, Error> { - if let Ok(ecdsa_p256) = EcdsaSigningKey::new( - der, - SignatureScheme::ECDSA_NISTP256_SHA256, - &signature::ECDSA_P256_SHA256_ASN1_SIGNING, - ) { - return Ok(Arc::new(ecdsa_p256)); - } - - if let Ok(ecdsa_p384) = EcdsaSigningKey::new( - der, - SignatureScheme::ECDSA_NISTP384_SHA384, - &signature::ECDSA_P384_SHA384_ASN1_SIGNING, - ) { - return Ok(Arc::new(ecdsa_p384)); - } - - Err(Error::General( - "failed to parse ECDSA private key as PKCS#8 or SEC1".into(), - )) -} - -/// Parse `der` as any EdDSA key type, returning the first which works. -/// -/// Note that, at the time of writing, Ed25519 does not have wide support -/// in browsers. It is also not supported by the WebPKI, because the -/// CA/Browser Forum Baseline Requirements do not support it for publicly -/// trusted certificates. -pub fn any_eddsa_type(der: &PrivatePkcs8KeyDer<'_>) -> Result<Arc<dyn SigningKey>, Error> { - // TODO: Add support for Ed448 - Ok(Arc::new(Ed25519SigningKey::new( - der, - SignatureScheme::ED25519, - )?)) -} - -/// A `SigningKey` for RSA-PKCS1 or RSA-PSS. -/// -/// This is used by the test suite, so it must be `pub`, but it isn't part of -/// the public, stable, API. -#[doc(hidden)] -pub struct RsaSigningKey { - key: Arc<RsaKeyPair>, -} - -static ALL_RSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA256, -]; - -impl RsaSigningKey { - /// Make a new `RsaSigningKey` from a DER encoding, in either - /// PKCS#1 or PKCS#8 format. - pub fn new(der: &PrivateKeyDer<'_>) -> Result<Self, Error> { - let key_pair = match der { - PrivateKeyDer::Pkcs1(pkcs1) => RsaKeyPair::from_der(pkcs1.secret_pkcs1_der()), - PrivateKeyDer::Pkcs8(pkcs8) => RsaKeyPair::from_pkcs8(pkcs8.secret_pkcs8_der()), - _ => { - return Err(Error::General( - "failed to parse RSA private key as either PKCS#1 or PKCS#8".into(), - )); - } - } - .map_err(|key_rejected| { - Error::General(format!("failed to parse RSA private key: {key_rejected}")) - })?; - - Ok(Self { - key: Arc::new(key_pair), - }) - } -} - -impl SigningKey for RsaSigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> { - ALL_RSA_SCHEMES - .iter() - .find(|scheme| offered.contains(scheme)) - .map(|scheme| RsaSigner::new(self.key.clone(), *scheme)) - } - - fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> { - Some(public_key_to_spki( - &alg_id::RSA_ENCRYPTION, - self.key.public_key(), - )) - } - - fn algorithm(&self) -> SignatureAlgorithm { - SignatureAlgorithm::RSA - } -} - -impl Debug for RsaSigningKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("RsaSigningKey") - .field("algorithm", &self.algorithm()) - .finish() - } -} - -struct RsaSigner { - key: Arc<RsaKeyPair>, - scheme: SignatureScheme, - encoding: &'static dyn signature::RsaEncoding, -} - -impl RsaSigner { - fn new(key: Arc<RsaKeyPair>, scheme: SignatureScheme) -> Box<dyn Signer> { - let encoding: &dyn signature::RsaEncoding = match scheme { - SignatureScheme::RSA_PKCS1_SHA256 => &signature::RSA_PKCS1_SHA256, - SignatureScheme::RSA_PKCS1_SHA384 => &signature::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA512 => &signature::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PSS_SHA256 => &signature::RSA_PSS_SHA256, - SignatureScheme::RSA_PSS_SHA384 => &signature::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA512 => &signature::RSA_PSS_SHA512, - _ => unreachable!(), - }; - - Box::new(Self { - key, - scheme, - encoding, - }) - } -} - -impl Signer for RsaSigner { - fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> { - let mut sig = vec![0; self.key.public().modulus_len()]; - - let rng = SystemRandom::new(); - self.key - .sign(self.encoding, &rng, message, &mut sig) - .map(|_| sig) - .map_err(|_| Error::General("signing failed".to_string())) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -impl Debug for RsaSigner { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("RsaSigner") - .field("scheme", &self.scheme) - .finish() - } -} - -/// A SigningKey that uses exactly one TLS-level SignatureScheme -/// and one ring-level signature::SigningAlgorithm. -/// -/// Compare this to RsaSigningKey, which for a particular key is -/// willing to sign with several algorithms. This is quite poor -/// cryptography practice, but is necessary because a given RSA key -/// is expected to work in TLS1.2 (PKCS#1 signatures) and TLS1.3 -/// (PSS signatures) -- nobody is willing to obtain certificates for -/// different protocol versions. -/// -/// Currently this is only implemented for ECDSA keys. -struct EcdsaSigningKey { - key: Arc<EcdsaKeyPair>, - scheme: SignatureScheme, -} - -impl EcdsaSigningKey { - /// Make a new `ECDSASigningKey` from a DER encoding in PKCS#8 or SEC1 - /// format, expecting a key usable with precisely the given signature - /// scheme. - fn new( - der: &PrivateKeyDer<'_>, - scheme: SignatureScheme, - sigalg: &'static signature::EcdsaSigningAlgorithm, - ) -> Result<Self, ()> { - let rng = SystemRandom::new(); - let key_pair = match der { - PrivateKeyDer::Sec1(sec1) => { - Self::convert_sec1_to_pkcs8(scheme, sigalg, sec1.secret_sec1_der(), &rng)? - } - PrivateKeyDer::Pkcs8(pkcs8) => { - EcdsaKeyPair::from_pkcs8(sigalg, pkcs8.secret_pkcs8_der(), &rng).map_err(|_| ())? - } - _ => return Err(()), - }; - - Ok(Self { - key: Arc::new(key_pair), - scheme, - }) - } - - /// Convert a SEC1 encoding to PKCS8, and ask ring to parse it. This - /// can be removed once <https://github.com/briansmith/ring/pull/1456> - /// (or equivalent) is landed. - fn convert_sec1_to_pkcs8( - scheme: SignatureScheme, - sigalg: &'static signature::EcdsaSigningAlgorithm, - maybe_sec1_der: &[u8], - rng: &dyn SecureRandom, - ) -> Result<EcdsaKeyPair, ()> { - let pkcs8_prefix = match scheme { - SignatureScheme::ECDSA_NISTP256_SHA256 => &PKCS8_PREFIX_ECDSA_NISTP256, - SignatureScheme::ECDSA_NISTP384_SHA384 => &PKCS8_PREFIX_ECDSA_NISTP384, - _ => unreachable!(), // all callers are in this file - }; - - let sec1_wrap = wrap_in_octet_string(maybe_sec1_der); - let pkcs8 = wrap_concat_in_sequence(pkcs8_prefix, &sec1_wrap); - - EcdsaKeyPair::from_pkcs8(sigalg, &pkcs8, rng).map_err(|_| ()) - } -} - -// This is (line-by-line): -// - INTEGER Version = 0 -// - SEQUENCE (privateKeyAlgorithm) -// - id-ecPublicKey OID -// - prime256v1 OID -const PKCS8_PREFIX_ECDSA_NISTP256: &[u8] = b"\x02\x01\x00\ - \x30\x13\ - \x06\x07\x2a\x86\x48\xce\x3d\x02\x01\ - \x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"; - -// This is (line-by-line): -// - INTEGER Version = 0 -// - SEQUENCE (privateKeyAlgorithm) -// - id-ecPublicKey OID -// - secp384r1 OID -const PKCS8_PREFIX_ECDSA_NISTP384: &[u8] = b"\x02\x01\x00\ - \x30\x10\ - \x06\x07\x2a\x86\x48\xce\x3d\x02\x01\ - \x06\x05\x2b\x81\x04\x00\x22"; - -impl SigningKey for EcdsaSigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> { - if offered.contains(&self.scheme) { - Some(Box::new(EcdsaSigner { - key: self.key.clone(), - scheme: self.scheme, - })) - } else { - None - } - } - - fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> { - let id = match self.scheme { - SignatureScheme::ECDSA_NISTP256_SHA256 => alg_id::ECDSA_P256, - SignatureScheme::ECDSA_NISTP384_SHA384 => alg_id::ECDSA_P384, - _ => unreachable!(), - }; - - Some(public_key_to_spki(&id, self.key.public_key())) - } - - fn algorithm(&self) -> SignatureAlgorithm { - self.scheme.algorithm() - } -} - -impl Debug for EcdsaSigningKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("EcdsaSigningKey") - .field("algorithm", &self.algorithm()) - .finish() - } -} - -struct EcdsaSigner { - key: Arc<EcdsaKeyPair>, - scheme: SignatureScheme, -} - -impl Signer for EcdsaSigner { - fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> { - let rng = SystemRandom::new(); - self.key - .sign(&rng, message) - .map_err(|_| Error::General("signing failed".into())) - .map(|sig| sig.as_ref().into()) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -impl Debug for EcdsaSigner { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("EcdsaSigner") - .field("scheme", &self.scheme) - .finish() - } -} - -/// A SigningKey that uses exactly one TLS-level SignatureScheme -/// and one ring-level signature::SigningAlgorithm. -/// -/// Compare this to RsaSigningKey, which for a particular key is -/// willing to sign with several algorithms. This is quite poor -/// cryptography practice, but is necessary because a given RSA key -/// is expected to work in TLS1.2 (PKCS#1 signatures) and TLS1.3 -/// (PSS signatures) -- nobody is willing to obtain certificates for -/// different protocol versions. -/// -/// Currently this is only implemented for Ed25519 keys. -struct Ed25519SigningKey { - key: Arc<Ed25519KeyPair>, - scheme: SignatureScheme, -} - -impl Ed25519SigningKey { - /// Make a new `Ed25519SigningKey` from a DER encoding in PKCS#8 format, - /// expecting a key usable with precisely the given signature scheme. - fn new(der: &PrivatePkcs8KeyDer<'_>, scheme: SignatureScheme) -> Result<Self, Error> { - match Ed25519KeyPair::from_pkcs8_maybe_unchecked(der.secret_pkcs8_der()) { - Ok(key_pair) => Ok(Self { - key: Arc::new(key_pair), - scheme, - }), - Err(e) => Err(Error::General(format!( - "failed to parse Ed25519 private key: {e}" - ))), - } - } -} - -impl SigningKey for Ed25519SigningKey { - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> { - if offered.contains(&self.scheme) { - Some(Box::new(Ed25519Signer { - key: self.key.clone(), - scheme: self.scheme, - })) - } else { - None - } - } - - fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> { - Some(public_key_to_spki(&alg_id::ED25519, self.key.public_key())) - } - - fn algorithm(&self) -> SignatureAlgorithm { - self.scheme.algorithm() - } -} - -impl Debug for Ed25519SigningKey { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Ed25519SigningKey") - .field("algorithm", &self.algorithm()) - .finish() - } -} - -struct Ed25519Signer { - key: Arc<Ed25519KeyPair>, - scheme: SignatureScheme, -} - -impl Signer for Ed25519Signer { - fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> { - Ok(self.key.sign(message).as_ref().into()) - } - - fn scheme(&self) -> SignatureScheme { - self.scheme - } -} - -impl Debug for Ed25519Signer { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Ed25519Signer") - .field("scheme", &self.scheme) - .finish() - } -} - -#[cfg(test)] -mod tests { - use alloc::format; - - use pki_types::{PrivatePkcs1KeyDer, PrivateSec1KeyDer}; - - use super::*; - - #[test] - fn can_load_ecdsa_nistp256_pkcs8() { - let key = - PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/nistp256key.pkcs8.der")[..]); - assert!(any_eddsa_type(&key).is_err()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_load_ecdsa_nistp256_sec1() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp256key.der")[..], - )); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_sign_ecdsa_nistp256() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp256key.der")[..], - )); - - let k = any_supported_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "EcdsaSigningKey { algorithm: ECDSA }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::ECDSA); - - assert!( - k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384]) - .is_none() - ); - let s = k - .choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .unwrap(); - assert_eq!( - format!("{s:?}"), - "EcdsaSigner { scheme: ECDSA_NISTP256_SHA256 }" - ); - assert_eq!(s.scheme(), SignatureScheme::ECDSA_NISTP256_SHA256); - // nb. signature is variable length and asn.1-encoded - assert!( - s.sign(b"hello") - .unwrap() - .starts_with(&[0x30]) - ); - } - - #[test] - fn can_load_ecdsa_nistp384_pkcs8() { - let key = - PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/nistp384key.pkcs8.der")[..]); - assert!(any_eddsa_type(&key).is_err()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_load_ecdsa_nistp384_sec1() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp384key.der")[..], - )); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_ok()); - } - - #[test] - fn can_sign_ecdsa_nistp384() { - let key = PrivateKeyDer::Sec1(PrivateSec1KeyDer::from( - &include_bytes!("../../testdata/nistp384key.der")[..], - )); - - let k = any_supported_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "EcdsaSigningKey { algorithm: ECDSA }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::ECDSA); - - assert!( - k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .is_none() - ); - let s = k - .choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384]) - .unwrap(); - assert_eq!( - format!("{s:?}"), - "EcdsaSigner { scheme: ECDSA_NISTP384_SHA384 }" - ); - assert_eq!(s.scheme(), SignatureScheme::ECDSA_NISTP384_SHA384); - // nb. signature is variable length and asn.1-encoded - assert!( - s.sign(b"hello") - .unwrap() - .starts_with(&[0x30]) - ); - } - - #[test] - fn can_load_eddsa_pkcs8() { - let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]); - assert!(any_eddsa_type(&key).is_ok()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_err()); - } - - #[test] - fn can_sign_eddsa() { - let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]); - - let k = any_eddsa_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "Ed25519SigningKey { algorithm: ED25519 }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::ED25519); - - assert!( - k.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .is_none() - ); - let s = k - .choose_scheme(&[SignatureScheme::ED25519]) - .unwrap(); - assert_eq!(format!("{s:?}"), "Ed25519Signer { scheme: ED25519 }"); - assert_eq!(s.scheme(), SignatureScheme::ED25519); - assert_eq!(s.sign(b"hello").unwrap().len(), 64); - } - - #[test] - fn can_load_rsa2048_pkcs8() { - let key = - PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..]); - assert!(any_eddsa_type(&key).is_err()); - let key = PrivateKeyDer::Pkcs8(key); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_err()); - } - - #[test] - fn can_load_rsa2048_pkcs1() { - let key = PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs1.der")[..], - )); - assert!(any_supported_type(&key).is_ok()); - assert!(any_ecdsa_type(&key).is_err()); - } - - #[test] - fn can_sign_rsa2048() { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..], - )); - - let k = any_supported_type(&key).unwrap(); - assert_eq!(format!("{k:?}"), "RsaSigningKey { algorithm: RSA }"); - assert_eq!(k.algorithm(), SignatureAlgorithm::RSA); - - assert!( - k.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .is_none() - ); - assert!( - k.choose_scheme(&[SignatureScheme::ED25519]) - .is_none() - ); - - let s = k - .choose_scheme(&[SignatureScheme::RSA_PSS_SHA256]) - .unwrap(); - assert_eq!(format!("{s:?}"), "RsaSigner { scheme: RSA_PSS_SHA256 }"); - assert_eq!(s.scheme(), SignatureScheme::RSA_PSS_SHA256); - assert_eq!(s.sign(b"hello").unwrap().len(), 256); - - for scheme in &[ - SignatureScheme::RSA_PKCS1_SHA256, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA512, - ] { - k.choose_scheme(&[*scheme]).unwrap(); - } - } - - #[test] - fn cannot_load_invalid_pkcs8_encoding() { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(&b"invalid"[..])); - assert_eq!( - any_supported_type(&key).err(), - Some(Error::General( - "failed to parse private key as RSA, ECDSA, or EdDSA".into() - )) - ); - assert_eq!( - any_ecdsa_type(&key).err(), - Some(Error::General( - "failed to parse ECDSA private key as PKCS#8 or SEC1".into() - )) - ); - assert_eq!( - RsaSigningKey::new(&key).err(), - Some(Error::General( - "failed to parse RSA private key: InvalidEncoding".into() - )) - ); - } -} - -#[cfg(bench)] -mod benchmarks { - use super::{PrivateKeyDer, PrivatePkcs8KeyDer, SignatureScheme}; - - #[bench] - fn bench_rsa2048_pkcs1_sha256(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_rsa2048_pss_sha256(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::RSA_PSS_SHA256]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_eddsa(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/eddsakey.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::ED25519]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_ecdsa_p256_sha256(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp256key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_ecdsa_p384_sha384(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp384key.pkcs8.der")[..], - )); - let sk = super::any_supported_type(&key).unwrap(); - let signer = sk - .choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384]) - .unwrap(); - - b.iter(|| { - test::black_box( - signer - .sign(SAMPLE_TLS13_MESSAGE) - .unwrap(), - ); - }); - } - - #[bench] - fn bench_load_and_validate_rsa2048(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa2048key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_supported_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_rsa4096(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/rsa4096key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_supported_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_p256(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp256key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_ecdsa_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_p384(b: &mut test::Bencher) { - let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from( - &include_bytes!("../../testdata/nistp384key.pkcs8.der")[..], - )); - - b.iter(|| { - test::black_box(super::any_ecdsa_type(&key).unwrap()); - }); - } - - #[bench] - fn bench_load_and_validate_eddsa(b: &mut test::Bencher) { - let key = PrivatePkcs8KeyDer::from(&include_bytes!("../../testdata/eddsakey.der")[..]); - - b.iter(|| { - test::black_box(super::any_eddsa_type(&key).unwrap()); - }); - } - - const SAMPLE_TLS13_MESSAGE: &[u8] = &[ - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x54, 0x4c, 0x53, 0x20, 0x31, 0x2e, 0x33, 0x2c, 0x20, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x00, 0x04, 0xca, 0xc4, 0x48, 0x0e, 0x70, 0xf2, - 0x1b, 0xa9, 0x1c, 0x16, 0xca, 0x90, 0x48, 0xbe, 0x28, 0x2f, 0xc7, 0xf8, 0x9b, 0x87, 0x72, - 0x93, 0xda, 0x4d, 0x2f, 0x80, 0x80, 0x60, 0x1a, 0xd3, 0x08, 0xe2, 0xb7, 0x86, 0x14, 0x1b, - 0x54, 0xda, 0x9a, 0xc9, 0x6d, 0xe9, 0x66, 0xb4, 0x9f, 0xe2, 0x2c, - ]; -} diff --git a/vendor/rustls/src/crypto/ring/ticketer.rs b/vendor/rustls/src/crypto/ring/ticketer.rs deleted file mode 100644 index 45dcc27a..00000000 --- a/vendor/rustls/src/crypto/ring/ticketer.rs +++ /dev/null @@ -1,366 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt; -use core::fmt::{Debug, Formatter}; -use core::sync::atomic::{AtomicUsize, Ordering}; - -use subtle::ConstantTimeEq; - -use super::ring_like::aead; -use super::ring_like::rand::{SecureRandom, SystemRandom}; -use crate::error::Error; -#[cfg(debug_assertions)] -use crate::log::debug; -use crate::polyfill::try_split_at; -use crate::rand::GetRandomFailed; -use crate::server::ProducesTickets; -use crate::sync::Arc; - -/// A concrete, safe ticket creation mechanism. -pub struct Ticketer {} - -impl Ticketer { - /// Make the recommended `Ticketer`. This produces tickets - /// with a 12 hour life and randomly generated keys. - /// - /// The encryption mechanism used is Chacha20Poly1305. - #[cfg(feature = "std")] - pub fn new() -> Result<Arc<dyn ProducesTickets>, Error> { - Ok(Arc::new(crate::ticketer::TicketRotator::new( - 6 * 60 * 60, - make_ticket_generator, - )?)) - } -} - -fn make_ticket_generator() -> Result<Box<dyn ProducesTickets>, GetRandomFailed> { - Ok(Box::new(AeadTicketer::new()?)) -} - -/// This is a `ProducesTickets` implementation which uses -/// any *ring* `aead::Algorithm` to encrypt and authentication -/// the ticket payload. It does not enforce any lifetime -/// constraint. -struct AeadTicketer { - alg: &'static aead::Algorithm, - key: aead::LessSafeKey, - key_name: [u8; 16], - lifetime: u32, - - /// Tracks the largest ciphertext produced by `encrypt`, and - /// uses it to early-reject `decrypt` queries that are too long. - /// - /// Accepting excessively long ciphertexts means a "Partitioning - /// Oracle Attack" (see <https://eprint.iacr.org/2020/1491.pdf>) - /// can be more efficient, though also note that these are thought - /// to be cryptographically hard if the key is full-entropy (as it - /// is here). - maximum_ciphertext_len: AtomicUsize, -} - -impl AeadTicketer { - fn new() -> Result<Self, GetRandomFailed> { - let mut key = [0u8; 32]; - SystemRandom::new() - .fill(&mut key) - .map_err(|_| GetRandomFailed)?; - - let key = aead::UnboundKey::new(TICKETER_AEAD, &key).unwrap(); - - let mut key_name = [0u8; 16]; - SystemRandom::new() - .fill(&mut key_name) - .map_err(|_| GetRandomFailed)?; - - Ok(Self { - alg: TICKETER_AEAD, - key: aead::LessSafeKey::new(key), - key_name, - lifetime: 60 * 60 * 12, - maximum_ciphertext_len: AtomicUsize::new(0), - }) - } -} - -impl ProducesTickets for AeadTicketer { - fn enabled(&self) -> bool { - true - } - - fn lifetime(&self) -> u32 { - self.lifetime - } - - /// Encrypt `message` and return the ciphertext. - fn encrypt(&self, message: &[u8]) -> Option<Vec<u8>> { - // Random nonce, because a counter is a privacy leak. - let mut nonce_buf = [0u8; 12]; - SystemRandom::new() - .fill(&mut nonce_buf) - .ok()?; - let nonce = aead::Nonce::assume_unique_for_key(nonce_buf); - let aad = aead::Aad::from(self.key_name); - - // ciphertext structure is: - // key_name: [u8; 16] - // nonce: [u8; 12] - // message: [u8, _] - // tag: [u8; 16] - - let mut ciphertext = Vec::with_capacity( - self.key_name.len() + nonce_buf.len() + message.len() + self.key.algorithm().tag_len(), - ); - ciphertext.extend(self.key_name); - ciphertext.extend(nonce_buf); - ciphertext.extend(message); - let ciphertext = self - .key - .seal_in_place_separate_tag( - nonce, - aad, - &mut ciphertext[self.key_name.len() + nonce_buf.len()..], - ) - .map(|tag| { - ciphertext.extend(tag.as_ref()); - ciphertext - }) - .ok()?; - - self.maximum_ciphertext_len - .fetch_max(ciphertext.len(), Ordering::SeqCst); - Some(ciphertext) - } - - /// Decrypt `ciphertext` and recover the original message. - fn decrypt(&self, ciphertext: &[u8]) -> Option<Vec<u8>> { - if ciphertext.len() - > self - .maximum_ciphertext_len - .load(Ordering::SeqCst) - { - #[cfg(debug_assertions)] - debug!("rejected over-length ticket"); - return None; - } - - let (alleged_key_name, ciphertext) = try_split_at(ciphertext, self.key_name.len())?; - - let (nonce, ciphertext) = try_split_at(ciphertext, self.alg.nonce_len())?; - - // checking the key_name is the expected one, *and* then putting it into the - // additionally authenticated data is duplicative. this check quickly rejects - // tickets for a different ticketer (see `TicketSwitcher`), while including it - // in the AAD ensures it is authenticated independent of that check and that - // any attempted attack on the integrity such as [^1] must happen for each - // `key_label`, not over a population of potential keys. this approach - // is overall similar to [^2]. - // - // [^1]: https://eprint.iacr.org/2020/1491.pdf - // [^2]: "Authenticated Encryption with Key Identification", fig 6 - // <https://eprint.iacr.org/2022/1680.pdf> - if ConstantTimeEq::ct_ne(&self.key_name[..], alleged_key_name).into() { - #[cfg(debug_assertions)] - debug!("rejected ticket with wrong ticket_name"); - return None; - } - - // This won't fail since `nonce` has the required length. - let nonce = aead::Nonce::try_assume_unique_for_key(nonce).ok()?; - - let mut out = Vec::from(ciphertext); - - let plain_len = self - .key - .open_in_place(nonce, aead::Aad::from(alleged_key_name), &mut out) - .ok()? - .len(); - out.truncate(plain_len); - - Some(out) - } -} - -impl Debug for AeadTicketer { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - // Note: we deliberately omit the key from the debug output. - f.debug_struct("AeadTicketer") - .field("alg", &self.alg) - .field("lifetime", &self.lifetime) - .finish() - } -} - -static TICKETER_AEAD: &aead::Algorithm = &aead::CHACHA20_POLY1305; - -#[cfg(test)] -mod tests { - use core::time::Duration; - - use pki_types::UnixTime; - - use super::*; - - #[test] - fn basic_pairwise_test() { - let t = Ticketer::new().unwrap(); - assert!(t.enabled()); - let cipher = t.encrypt(b"hello world").unwrap(); - let plain = t.decrypt(&cipher).unwrap(); - assert_eq!(plain, b"hello world"); - } - - #[test] - fn refuses_decrypt_before_encrypt() { - let t = Ticketer::new().unwrap(); - assert_eq!(t.decrypt(b"hello"), None); - } - - #[test] - fn refuses_decrypt_larger_than_largest_encryption() { - let t = Ticketer::new().unwrap(); - let mut cipher = t.encrypt(b"hello world").unwrap(); - assert_eq!(t.decrypt(&cipher), Some(b"hello world".to_vec())); - - // obviously this would never work anyway, but this - // and `cannot_decrypt_before_encrypt` exercise the - // first branch in `decrypt()` - cipher.push(0); - assert_eq!(t.decrypt(&cipher), None); - } - - #[test] - fn ticketrotator_switching_test() { - let t = Arc::new(crate::ticketer::TicketRotator::new(1, make_ticket_generator).unwrap()); - let now = UnixTime::now(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - { - // Trigger new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 10, - ))); - } - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - { - // Trigger new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 20, - ))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_none()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); - } - - #[test] - fn ticketrotator_remains_usable_over_temporary_ticketer_creation_failure() { - let mut t = crate::ticketer::TicketRotator::new(1, make_ticket_generator).unwrap(); - let now = UnixTime::now(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - t.generator = fail_generator; - { - // Failed new ticketer; this means we still need to - // rotate. - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 10, - ))); - } - - // check post-failure encryption/decryption still works - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - - // do the rotation for real - t.generator = make_ticket_generator; - { - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 20, - ))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_some()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); - } - - #[test] - fn ticketswitcher_switching_test() { - #[expect(deprecated)] - let t = Arc::new(crate::ticketer::TicketSwitcher::new(1, make_ticket_generator).unwrap()); - let now = UnixTime::now(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - { - // Trigger new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 10, - ))); - } - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - { - // Trigger new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 20, - ))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_none()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); - } - - #[test] - fn ticketswitcher_recover_test() { - #[expect(deprecated)] - let mut t = crate::ticketer::TicketSwitcher::new(1, make_ticket_generator).unwrap(); - let now = UnixTime::now(); - let cipher1 = t.encrypt(b"ticket 1").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - t.generator = fail_generator; - { - // Failed new ticketer - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 10, - ))); - } - t.generator = make_ticket_generator; - let cipher2 = t.encrypt(b"ticket 2").unwrap(); - assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - { - // recover - t.maybe_roll(UnixTime::since_unix_epoch(Duration::from_secs( - now.as_secs() + 20, - ))); - } - let cipher3 = t.encrypt(b"ticket 3").unwrap(); - assert!(t.decrypt(&cipher1).is_none()); - assert_eq!(t.decrypt(&cipher2).unwrap(), b"ticket 2"); - assert_eq!(t.decrypt(&cipher3).unwrap(), b"ticket 3"); - } - - #[test] - fn aeadticketer_is_debug_and_producestickets() { - use alloc::format; - - use super::*; - - let t = make_ticket_generator().unwrap(); - - let expect = format!("AeadTicketer {{ alg: {TICKETER_AEAD:?}, lifetime: 43200 }}"); - assert_eq!(format!("{t:?}"), expect); - assert!(t.enabled()); - assert_eq!(t.lifetime(), 43200); - } - - fn fail_generator() -> Result<Box<dyn ProducesTickets>, GetRandomFailed> { - Err(GetRandomFailed) - } -} diff --git a/vendor/rustls/src/crypto/ring/tls12.rs b/vendor/rustls/src/crypto/ring/tls12.rs deleted file mode 100644 index 63dfae8b..00000000 --- a/vendor/rustls/src/crypto/ring/tls12.rs +++ /dev/null @@ -1,406 +0,0 @@ -use alloc::boxed::Box; - -use super::ring_like::aead; -use crate::crypto::KeyExchangeAlgorithm; -use crate::crypto::cipher::{ - AeadKey, InboundOpaqueMessage, Iv, KeyBlockShape, MessageDecrypter, MessageEncrypter, - NONCE_LEN, Nonce, Tls12AeadAlgorithm, UnsupportedOperationError, make_tls12_aad, -}; -use crate::crypto::tls12::PrfUsingHmac; -use crate::enums::{CipherSuite, SignatureScheme}; -use crate::error::Error; -use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; -use crate::msgs::message::{ - InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, -}; -use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; -use crate::tls12::Tls12CipherSuite; - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256. -pub static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: u64::MAX, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - aead_alg: &ChaCha20Poly1305, - prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 -pub static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: u64::MAX, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - aead_alg: &ChaCha20Poly1305, - prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 -pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: 1 << 24, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - aead_alg: &AES128_GCM, - prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 -pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - hash_provider: &super::hash::SHA384, - confidentiality_limit: 1 << 24, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_RSA_SCHEMES, - aead_alg: &AES256_GCM, - prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 -pub static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: 1 << 24, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - aead_alg: &AES128_GCM, - prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA256), - }); - -/// The TLS1.2 ciphersuite TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 -pub static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - hash_provider: &super::hash::SHA384, - confidentiality_limit: 1 << 24, - }, - kx: KeyExchangeAlgorithm::ECDHE, - sign: TLS12_ECDSA_SCHEMES, - aead_alg: &AES256_GCM, - prf_provider: &PrfUsingHmac(&super::hmac::HMAC_SHA384), - }); - -static TLS12_ECDSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::ED25519, - SignatureScheme::ECDSA_NISTP521_SHA512, - SignatureScheme::ECDSA_NISTP384_SHA384, - SignatureScheme::ECDSA_NISTP256_SHA256, -]; - -static TLS12_RSA_SCHEMES: &[SignatureScheme] = &[ - SignatureScheme::RSA_PSS_SHA512, - SignatureScheme::RSA_PSS_SHA384, - SignatureScheme::RSA_PSS_SHA256, - SignatureScheme::RSA_PKCS1_SHA512, - SignatureScheme::RSA_PKCS1_SHA384, - SignatureScheme::RSA_PKCS1_SHA256, -]; - -pub(crate) static AES128_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_128_GCM); -pub(crate) static AES256_GCM: GcmAlgorithm = GcmAlgorithm(&aead::AES_256_GCM); - -pub(crate) struct GcmAlgorithm(&'static aead::Algorithm); - -impl Tls12AeadAlgorithm for GcmAlgorithm { - fn decrypter(&self, dec_key: AeadKey, dec_iv: &[u8]) -> Box<dyn MessageDecrypter> { - let dec_key = - aead::LessSafeKey::new(aead::UnboundKey::new(self.0, dec_key.as_ref()).unwrap()); - - let mut ret = GcmMessageDecrypter { - dec_key, - dec_salt: [0u8; 4], - }; - - debug_assert_eq!(dec_iv.len(), 4); - ret.dec_salt.copy_from_slice(dec_iv); - Box::new(ret) - } - - fn encrypter( - &self, - enc_key: AeadKey, - write_iv: &[u8], - explicit: &[u8], - ) -> Box<dyn MessageEncrypter> { - let enc_key = - aead::LessSafeKey::new(aead::UnboundKey::new(self.0, enc_key.as_ref()).unwrap()); - let iv = gcm_iv(write_iv, explicit); - Box::new(GcmMessageEncrypter { enc_key, iv }) - } - - fn key_block_shape(&self) -> KeyBlockShape { - KeyBlockShape { - enc_key_len: self.0.key_len(), - fixed_iv_len: 4, - explicit_nonce_len: 8, - } - } - - fn extract_keys( - &self, - key: AeadKey, - write_iv: &[u8], - explicit: &[u8], - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - let iv = gcm_iv(write_iv, explicit); - Ok(match self.0.key_len() { - 16 => ConnectionTrafficSecrets::Aes128Gcm { key, iv }, - 32 => ConnectionTrafficSecrets::Aes256Gcm { key, iv }, - _ => unreachable!(), - }) - } - - fn fips(&self) -> bool { - super::fips() - } -} - -pub(crate) struct ChaCha20Poly1305; - -impl Tls12AeadAlgorithm for ChaCha20Poly1305 { - fn decrypter(&self, dec_key: AeadKey, iv: &[u8]) -> Box<dyn MessageDecrypter> { - let dec_key = aead::LessSafeKey::new( - aead::UnboundKey::new(&aead::CHACHA20_POLY1305, dec_key.as_ref()).unwrap(), - ); - Box::new(ChaCha20Poly1305MessageDecrypter { - dec_key, - dec_offset: Iv::copy(iv), - }) - } - - fn encrypter(&self, enc_key: AeadKey, enc_iv: &[u8], _: &[u8]) -> Box<dyn MessageEncrypter> { - let enc_key = aead::LessSafeKey::new( - aead::UnboundKey::new(&aead::CHACHA20_POLY1305, enc_key.as_ref()).unwrap(), - ); - Box::new(ChaCha20Poly1305MessageEncrypter { - enc_key, - enc_offset: Iv::copy(enc_iv), - }) - } - - fn key_block_shape(&self) -> KeyBlockShape { - KeyBlockShape { - enc_key_len: 32, - fixed_iv_len: 12, - explicit_nonce_len: 0, - } - } - - fn extract_keys( - &self, - key: AeadKey, - iv: &[u8], - _explicit: &[u8], - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - // This should always be true because KeyBlockShape and the Iv nonce len are in agreement. - debug_assert_eq!(aead::NONCE_LEN, iv.len()); - Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { - key, - iv: Iv::new(iv[..].try_into().unwrap()), - }) - } - - fn fips(&self) -> bool { - false // not fips approved - } -} - -/// A `MessageEncrypter` for AES-GCM AEAD ciphersuites. TLS 1.2 only. -struct GcmMessageEncrypter { - enc_key: aead::LessSafeKey, - iv: Iv, -} - -/// A `MessageDecrypter` for AES-GCM AEAD ciphersuites. TLS1.2 only. -struct GcmMessageDecrypter { - dec_key: aead::LessSafeKey, - dec_salt: [u8; 4], -} - -const GCM_EXPLICIT_NONCE_LEN: usize = 8; -const GCM_OVERHEAD: usize = GCM_EXPLICIT_NONCE_LEN + 16; - -impl MessageDecrypter for GcmMessageDecrypter { - fn decrypt<'a>( - &mut self, - mut msg: InboundOpaqueMessage<'a>, - seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - let payload = &msg.payload; - if payload.len() < GCM_OVERHEAD { - return Err(Error::DecryptError); - } - - let nonce = { - let mut nonce = [0u8; 12]; - nonce[..4].copy_from_slice(&self.dec_salt); - nonce[4..].copy_from_slice(&payload[..8]); - aead::Nonce::assume_unique_for_key(nonce) - }; - - let aad = aead::Aad::from(make_tls12_aad( - seq, - msg.typ, - msg.version, - payload.len() - GCM_OVERHEAD, - )); - - let payload = &mut msg.payload; - let plain_len = self - .dec_key - .open_within(nonce, aad, payload, GCM_EXPLICIT_NONCE_LEN..) - .map_err(|_| Error::DecryptError)? - .len(); - - if plain_len > MAX_FRAGMENT_LEN { - return Err(Error::PeerSentOversizedRecord); - } - - payload.truncate(plain_len); - Ok(msg.into_plain_message()) - } -} - -impl MessageEncrypter for GcmMessageEncrypter { - fn encrypt( - &mut self, - msg: OutboundPlainMessage<'_>, - seq: u64, - ) -> Result<OutboundOpaqueMessage, Error> { - let total_len = self.encrypted_payload_len(msg.payload.len()); - let mut payload = PrefixedPayload::with_capacity(total_len); - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); - let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len())); - payload.extend_from_slice(&nonce.as_ref()[4..]); - payload.extend_from_chunks(&msg.payload); - - self.enc_key - .seal_in_place_separate_tag(nonce, aad, &mut payload.as_mut()[GCM_EXPLICIT_NONCE_LEN..]) - .map(|tag| payload.extend_from_slice(tag.as_ref())) - .map_err(|_| Error::EncryptError)?; - - Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload)) - } - - fn encrypted_payload_len(&self, payload_len: usize) -> usize { - payload_len + GCM_EXPLICIT_NONCE_LEN + self.enc_key.algorithm().tag_len() - } -} - -/// The RFC7905/RFC7539 ChaCha20Poly1305 construction. -/// This implementation does the AAD construction required in TLS1.2. -/// TLS1.3 uses `TLS13MessageEncrypter`. -struct ChaCha20Poly1305MessageEncrypter { - enc_key: aead::LessSafeKey, - enc_offset: Iv, -} - -/// The RFC7905/RFC7539 ChaCha20Poly1305 construction. -/// This implementation does the AAD construction required in TLS1.2. -/// TLS1.3 uses `TLS13MessageDecrypter`. -struct ChaCha20Poly1305MessageDecrypter { - dec_key: aead::LessSafeKey, - dec_offset: Iv, -} - -const CHACHAPOLY1305_OVERHEAD: usize = 16; - -impl MessageDecrypter for ChaCha20Poly1305MessageDecrypter { - fn decrypt<'a>( - &mut self, - mut msg: InboundOpaqueMessage<'a>, - seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - let payload = &msg.payload; - - if payload.len() < CHACHAPOLY1305_OVERHEAD { - return Err(Error::DecryptError); - } - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.dec_offset, seq).0); - let aad = aead::Aad::from(make_tls12_aad( - seq, - msg.typ, - msg.version, - payload.len() - CHACHAPOLY1305_OVERHEAD, - )); - - let payload = &mut msg.payload; - let plain_len = self - .dec_key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)? - .len(); - - if plain_len > MAX_FRAGMENT_LEN { - return Err(Error::PeerSentOversizedRecord); - } - - payload.truncate(plain_len); - Ok(msg.into_plain_message()) - } -} - -impl MessageEncrypter for ChaCha20Poly1305MessageEncrypter { - fn encrypt( - &mut self, - msg: OutboundPlainMessage<'_>, - seq: u64, - ) -> Result<OutboundOpaqueMessage, Error> { - let total_len = self.encrypted_payload_len(msg.payload.len()); - let mut payload = PrefixedPayload::with_capacity(total_len); - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.enc_offset, seq).0); - let aad = aead::Aad::from(make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len())); - payload.extend_from_chunks(&msg.payload); - - self.enc_key - .seal_in_place_append_tag(nonce, aad, &mut payload) - .map_err(|_| Error::EncryptError)?; - - Ok(OutboundOpaqueMessage::new(msg.typ, msg.version, payload)) - } - - fn encrypted_payload_len(&self, payload_len: usize) -> usize { - payload_len + self.enc_key.algorithm().tag_len() - } -} - -fn gcm_iv(write_iv: &[u8], explicit: &[u8]) -> Iv { - debug_assert_eq!(write_iv.len(), 4); - debug_assert_eq!(explicit.len(), 8); - - // The GCM nonce is constructed from a 32-bit 'salt' derived - // from the master-secret, and a 64-bit explicit part, - // with no specified construction. Thanks for that. - // - // We use the same construction as TLS1.3/ChaCha20Poly1305: - // a starting point extracted from the key block, xored with - // the sequence number. - let mut iv = [0; NONCE_LEN]; - iv[..4].copy_from_slice(write_iv); - iv[4..].copy_from_slice(explicit); - - Iv::new(iv) -} diff --git a/vendor/rustls/src/crypto/ring/tls13.rs b/vendor/rustls/src/crypto/ring/tls13.rs deleted file mode 100644 index ef488b62..00000000 --- a/vendor/rustls/src/crypto/ring/tls13.rs +++ /dev/null @@ -1,336 +0,0 @@ -use alloc::boxed::Box; - -use super::ring_like::hkdf::KeyType; -use super::ring_like::{aead, hkdf, hmac}; -use crate::crypto; -use crate::crypto::cipher::{ - AeadKey, InboundOpaqueMessage, Iv, MessageDecrypter, MessageEncrypter, Nonce, - Tls13AeadAlgorithm, UnsupportedOperationError, make_tls13_aad, -}; -use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock, OutputLengthError}; -use crate::enums::{CipherSuite, ContentType, ProtocolVersion}; -use crate::error::Error; -use crate::msgs::message::{ - InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload, -}; -use crate::suites::{CipherSuiteCommon, ConnectionTrafficSecrets, SupportedCipherSuite}; -use crate::tls13::Tls13CipherSuite; - -/// The TLS1.3 ciphersuite TLS_CHACHA20_POLY1305_SHA256 -pub static TLS13_CHACHA20_POLY1305_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls13(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); - -pub(crate) static TLS13_CHACHA20_POLY1305_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, - hash_provider: &super::hash::SHA256, - // ref: <https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.2.1> - confidentiality_limit: u64::MAX, - }, - hkdf_provider: &RingHkdf(hkdf::HKDF_SHA256, hmac::HMAC_SHA256), - aead_alg: &Chacha20Poly1305Aead(AeadAlgorithm(&aead::CHACHA20_POLY1305)), - quic: Some(&super::quic::KeyBuilder { - packet_alg: &aead::CHACHA20_POLY1305, - header_alg: &aead::quic::CHACHA20, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6> - confidentiality_limit: u64::MAX, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-6.6> - integrity_limit: 1 << 36, - }), -}; - -/// The TLS1.3 ciphersuite TLS_AES_256_GCM_SHA384 -pub static TLS13_AES_256_GCM_SHA384: SupportedCipherSuite = - SupportedCipherSuite::Tls13(&Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_AES_256_GCM_SHA384, - hash_provider: &super::hash::SHA384, - confidentiality_limit: 1 << 24, - }, - hkdf_provider: &RingHkdf(hkdf::HKDF_SHA384, hmac::HMAC_SHA384), - aead_alg: &Aes256GcmAead(AeadAlgorithm(&aead::AES_256_GCM)), - quic: Some(&super::quic::KeyBuilder { - packet_alg: &aead::AES_256_GCM, - header_alg: &aead::quic::AES_256, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1> - confidentiality_limit: 1 << 23, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2> - integrity_limit: 1 << 52, - }), - }); - -/// The TLS1.3 ciphersuite TLS_AES_128_GCM_SHA256 -pub static TLS13_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls13(TLS13_AES_128_GCM_SHA256_INTERNAL); - -pub(crate) static TLS13_AES_128_GCM_SHA256_INTERNAL: &Tls13CipherSuite = &Tls13CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS13_AES_128_GCM_SHA256, - hash_provider: &super::hash::SHA256, - confidentiality_limit: 1 << 24, - }, - hkdf_provider: &RingHkdf(hkdf::HKDF_SHA256, hmac::HMAC_SHA256), - aead_alg: &Aes128GcmAead(AeadAlgorithm(&aead::AES_128_GCM)), - quic: Some(&super::quic::KeyBuilder { - packet_alg: &aead::AES_128_GCM, - header_alg: &aead::quic::AES_128, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.1> - confidentiality_limit: 1 << 23, - // ref: <https://datatracker.ietf.org/doc/html/rfc9001#section-b.1.2> - integrity_limit: 1 << 52, - }), -}; - -struct Chacha20Poly1305Aead(AeadAlgorithm); - -impl Tls13AeadAlgorithm for Chacha20Poly1305Aead { - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { - self.0.encrypter(key, iv) - } - - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { - self.0.decrypter(key, iv) - } - - fn key_len(&self) -> usize { - self.0.key_len() - } - - fn extract_keys( - &self, - key: AeadKey, - iv: Iv, - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }) - } - - fn fips(&self) -> bool { - false // chacha20poly1305 not FIPS approved - } -} - -struct Aes256GcmAead(AeadAlgorithm); - -impl Tls13AeadAlgorithm for Aes256GcmAead { - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { - self.0.encrypter(key, iv) - } - - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { - self.0.decrypter(key, iv) - } - - fn key_len(&self) -> usize { - self.0.key_len() - } - - fn extract_keys( - &self, - key: AeadKey, - iv: Iv, - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - Ok(ConnectionTrafficSecrets::Aes256Gcm { key, iv }) - } - - fn fips(&self) -> bool { - super::fips() - } -} - -struct Aes128GcmAead(AeadAlgorithm); - -impl Tls13AeadAlgorithm for Aes128GcmAead { - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { - self.0.encrypter(key, iv) - } - - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { - self.0.decrypter(key, iv) - } - - fn key_len(&self) -> usize { - self.0.key_len() - } - - fn extract_keys( - &self, - key: AeadKey, - iv: Iv, - ) -> Result<ConnectionTrafficSecrets, UnsupportedOperationError> { - Ok(ConnectionTrafficSecrets::Aes128Gcm { key, iv }) - } - - fn fips(&self) -> bool { - super::fips() - } -} - -// common encrypter/decrypter/key_len items for above Tls13AeadAlgorithm impls -struct AeadAlgorithm(&'static aead::Algorithm); - -impl AeadAlgorithm { - fn encrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageEncrypter> { - // safety: the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. - Box::new(Tls13MessageEncrypter { - enc_key: aead::LessSafeKey::new(aead::UnboundKey::new(self.0, key.as_ref()).unwrap()), - iv, - }) - } - - fn decrypter(&self, key: AeadKey, iv: Iv) -> Box<dyn MessageDecrypter> { - // safety: the caller arranges that `key` is `key_len()` in bytes, so this unwrap is safe. - Box::new(Tls13MessageDecrypter { - dec_key: aead::LessSafeKey::new(aead::UnboundKey::new(self.0, key.as_ref()).unwrap()), - iv, - }) - } - - fn key_len(&self) -> usize { - self.0.key_len() - } -} - -struct Tls13MessageEncrypter { - enc_key: aead::LessSafeKey, - iv: Iv, -} - -struct Tls13MessageDecrypter { - dec_key: aead::LessSafeKey, - iv: Iv, -} - -impl MessageEncrypter for Tls13MessageEncrypter { - fn encrypt( - &mut self, - msg: OutboundPlainMessage<'_>, - seq: u64, - ) -> Result<OutboundOpaqueMessage, Error> { - let total_len = self.encrypted_payload_len(msg.payload.len()); - let mut payload = PrefixedPayload::with_capacity(total_len); - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); - let aad = aead::Aad::from(make_tls13_aad(total_len)); - payload.extend_from_chunks(&msg.payload); - payload.extend_from_slice(&msg.typ.to_array()); - - self.enc_key - .seal_in_place_append_tag(nonce, aad, &mut payload) - .map_err(|_| Error::EncryptError)?; - - Ok(OutboundOpaqueMessage::new( - ContentType::ApplicationData, - // Note: all TLS 1.3 application data records use TLSv1_2 (0x0303) as the legacy record - // protocol version, see https://www.rfc-editor.org/rfc/rfc8446#section-5.1 - ProtocolVersion::TLSv1_2, - payload, - )) - } - - fn encrypted_payload_len(&self, payload_len: usize) -> usize { - payload_len + 1 + self.enc_key.algorithm().tag_len() - } -} - -impl MessageDecrypter for Tls13MessageDecrypter { - fn decrypt<'a>( - &mut self, - mut msg: InboundOpaqueMessage<'a>, - seq: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - let payload = &mut msg.payload; - if payload.len() < self.dec_key.algorithm().tag_len() { - return Err(Error::DecryptError); - } - - let nonce = aead::Nonce::assume_unique_for_key(Nonce::new(&self.iv, seq).0); - let aad = aead::Aad::from(make_tls13_aad(payload.len())); - let plain_len = self - .dec_key - .open_in_place(nonce, aad, payload) - .map_err(|_| Error::DecryptError)? - .len(); - - payload.truncate(plain_len); - msg.into_tls13_unpadded_message() - } -} - -struct RingHkdf(hkdf::Algorithm, hmac::Algorithm); - -impl Hkdf for RingHkdf { - fn extract_from_zero_ikm(&self, salt: Option<&[u8]>) -> Box<dyn HkdfExpander> { - let zeroes = [0u8; OkmBlock::MAX_LEN]; - let salt = match salt { - Some(salt) => salt, - None => &zeroes[..self.0.len()], - }; - Box::new(RingHkdfExpander { - alg: self.0, - prk: hkdf::Salt::new(self.0, salt).extract(&zeroes[..self.0.len()]), - }) - } - - fn extract_from_secret(&self, salt: Option<&[u8]>, secret: &[u8]) -> Box<dyn HkdfExpander> { - let zeroes = [0u8; OkmBlock::MAX_LEN]; - let salt = match salt { - Some(salt) => salt, - None => &zeroes[..self.0.len()], - }; - Box::new(RingHkdfExpander { - alg: self.0, - prk: hkdf::Salt::new(self.0, salt).extract(secret), - }) - } - - fn expander_for_okm(&self, okm: &OkmBlock) -> Box<dyn HkdfExpander> { - Box::new(RingHkdfExpander { - alg: self.0, - prk: hkdf::Prk::new_less_safe(self.0, okm.as_ref()), - }) - } - - fn hmac_sign(&self, key: &OkmBlock, message: &[u8]) -> crypto::hmac::Tag { - crypto::hmac::Tag::new(hmac::sign(&hmac::Key::new(self.1, key.as_ref()), message).as_ref()) - } - - fn fips(&self) -> bool { - super::fips() - } -} - -struct RingHkdfExpander { - alg: hkdf::Algorithm, - prk: hkdf::Prk, -} - -impl HkdfExpander for RingHkdfExpander { - fn expand_slice(&self, info: &[&[u8]], output: &mut [u8]) -> Result<(), OutputLengthError> { - self.prk - .expand(info, Len(output.len())) - .and_then(|okm| okm.fill(output)) - .map_err(|_| OutputLengthError) - } - - fn expand_block(&self, info: &[&[u8]]) -> OkmBlock { - let mut buf = [0u8; OkmBlock::MAX_LEN]; - let output = &mut buf[..self.hash_len()]; - self.prk - .expand(info, Len(output.len())) - .and_then(|okm| okm.fill(output)) - .unwrap(); - OkmBlock::new(output) - } - - fn hash_len(&self) -> usize { - self.alg.len() - } -} - -struct Len(usize); - -impl KeyType for Len { - fn len(&self) -> usize { - self.0 - } -} diff --git a/vendor/rustls/src/crypto/signer.rs b/vendor/rustls/src/crypto/signer.rs deleted file mode 100644 index 8028e74b..00000000 --- a/vendor/rustls/src/crypto/signer.rs +++ /dev/null @@ -1,233 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt::Debug; - -use pki_types::{AlgorithmIdentifier, CertificateDer, PrivateKeyDer, SubjectPublicKeyInfoDer}; - -use super::CryptoProvider; -use crate::client::ResolvesClientCert; -use crate::enums::{SignatureAlgorithm, SignatureScheme}; -use crate::error::{Error, InconsistentKeys}; -use crate::server::{ClientHello, ParsedCertificate, ResolvesServerCert}; -use crate::sync::Arc; -use crate::x509; - -/// An abstract signing key. -/// -/// This interface is used by rustls to use a private signing key -/// for authentication. This includes server and client authentication. -/// -/// Objects of this type are always used within Rustls as -/// `Arc<dyn SigningKey>`. There are no concrete public structs in Rustls -/// that implement this trait. -/// -/// There are two main ways to get a signing key: -/// -/// - [`KeyProvider::load_private_key()`], or -/// - some other method outside of the `KeyProvider` extension trait, -/// for instance: -/// - [`crypto::ring::sign::any_ecdsa_type()`] -/// - [`crypto::ring::sign::any_eddsa_type()`] -/// - [`crypto::ring::sign::any_supported_type()`] -/// - [`crypto::aws_lc_rs::sign::any_ecdsa_type()`] -/// - [`crypto::aws_lc_rs::sign::any_eddsa_type()`] -/// - [`crypto::aws_lc_rs::sign::any_supported_type()`] -/// -/// The `KeyProvider` method `load_private_key()` is called under the hood by -/// [`ConfigBuilder::with_single_cert()`], -/// [`ConfigBuilder::with_client_auth_cert()`], and -/// [`ConfigBuilder::with_single_cert_with_ocsp()`]. -/// -/// A signing key created outside of the `KeyProvider` extension trait can be used -/// to create a [`CertifiedKey`], which in turn can be used to create a -/// [`ResolvesServerCertUsingSni`]. Alternately, a `CertifiedKey` can be returned from a -/// custom implementation of the [`ResolvesServerCert`] or [`ResolvesClientCert`] traits. -/// -/// [`KeyProvider::load_private_key()`]: crate::crypto::KeyProvider::load_private_key -/// [`ConfigBuilder::with_single_cert()`]: crate::ConfigBuilder::with_single_cert -/// [`ConfigBuilder::with_single_cert_with_ocsp()`]: crate::ConfigBuilder::with_single_cert_with_ocsp -/// [`ConfigBuilder::with_client_auth_cert()`]: crate::ConfigBuilder::with_client_auth_cert -/// [`crypto::ring::sign::any_ecdsa_type()`]: crate::crypto::ring::sign::any_ecdsa_type -/// [`crypto::ring::sign::any_eddsa_type()`]: crate::crypto::ring::sign::any_eddsa_type -/// [`crypto::ring::sign::any_supported_type()`]: crate::crypto::ring::sign::any_supported_type -/// [`crypto::aws_lc_rs::sign::any_ecdsa_type()`]: crate::crypto::aws_lc_rs::sign::any_ecdsa_type -/// [`crypto::aws_lc_rs::sign::any_eddsa_type()`]: crate::crypto::aws_lc_rs::sign::any_eddsa_type -/// [`crypto::aws_lc_rs::sign::any_supported_type()`]: crate::crypto::aws_lc_rs::sign::any_supported_type -/// [`ResolvesServerCertUsingSni`]: crate::server::ResolvesServerCertUsingSni -/// [`ResolvesServerCert`]: crate::server::ResolvesServerCert -/// [`ResolvesClientCert`]: crate::client::ResolvesClientCert -pub trait SigningKey: Debug + Send + Sync { - /// Choose a `SignatureScheme` from those offered. - /// - /// Expresses the choice by returning something that implements `Signer`, - /// using the chosen scheme. - fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>>; - - /// Get the RFC 5280-compliant SubjectPublicKeyInfo (SPKI) of this [`SigningKey`] if available. - fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>> { - // Opt-out by default - None - } - - /// What kind of key we have. - fn algorithm(&self) -> SignatureAlgorithm; -} - -/// A thing that can sign a message. -pub trait Signer: Debug + Send + Sync { - /// Signs `message` using the selected scheme. - /// - /// `message` is not hashed; the implementer must hash it using the hash function - /// implicit in [`Self::scheme()`]. - /// - /// The returned signature format is also defined by [`Self::scheme()`]. - fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error>; - - /// Reveals which scheme will be used when you call [`Self::sign()`]. - fn scheme(&self) -> SignatureScheme; -} - -/// Server certificate resolver which always resolves to the same certificate and key. -/// -/// For use with [`ConfigBuilder::with_cert_resolver()`]. -/// -/// [`ConfigBuilder::with_cert_resolver()`]: crate::ConfigBuilder::with_cert_resolver -#[derive(Debug)] -pub struct SingleCertAndKey(Arc<CertifiedKey>); - -impl From<CertifiedKey> for SingleCertAndKey { - fn from(certified_key: CertifiedKey) -> Self { - Self(Arc::new(certified_key)) - } -} - -impl From<Arc<CertifiedKey>> for SingleCertAndKey { - fn from(certified_key: Arc<CertifiedKey>) -> Self { - Self(certified_key) - } -} - -impl ResolvesClientCert for SingleCertAndKey { - fn resolve( - &self, - _root_hint_subjects: &[&[u8]], - _sigschemes: &[SignatureScheme], - ) -> Option<Arc<CertifiedKey>> { - Some(self.0.clone()) - } - - fn has_certs(&self) -> bool { - true - } -} - -impl ResolvesServerCert for SingleCertAndKey { - fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<CertifiedKey>> { - Some(self.0.clone()) - } -} - -/// A packaged-together certificate chain, matching `SigningKey` and -/// optional stapled OCSP response. -/// -/// Note: this struct is also used to represent an [RFC 7250] raw public key, -/// when the client/server is configured to use raw public keys instead of -/// certificates. -/// -/// [RFC 7250]: https://tools.ietf.org/html/rfc7250 -#[derive(Clone, Debug)] -pub struct CertifiedKey { - /// The certificate chain or raw public key. - pub cert: Vec<CertificateDer<'static>>, - - /// The certified key. - pub key: Arc<dyn SigningKey>, - - /// An optional OCSP response from the certificate issuer, - /// attesting to its continued validity. - pub ocsp: Option<Vec<u8>>, -} - -impl CertifiedKey { - /// Create a new `CertifiedKey` from a certificate chain and DER-encoded private key. - /// - /// Attempt to parse the private key with the given [`CryptoProvider`]'s [`KeyProvider`] and - /// verify that it matches the public key in the first certificate of the `cert_chain` - /// if possible. - /// - /// [`KeyProvider`]: crate::crypto::KeyProvider - pub fn from_der( - cert_chain: Vec<CertificateDer<'static>>, - key: PrivateKeyDer<'static>, - provider: &CryptoProvider, - ) -> Result<Self, Error> { - let private_key = provider - .key_provider - .load_private_key(key)?; - - let certified_key = Self::new(cert_chain, private_key); - match certified_key.keys_match() { - // Don't treat unknown consistency as an error - Ok(()) | Err(Error::InconsistentKeys(InconsistentKeys::Unknown)) => Ok(certified_key), - Err(err) => Err(err), - } - } - - /// Make a new CertifiedKey, with the given chain and key. - /// - /// The cert chain must not be empty. The first certificate in the chain - /// must be the end-entity certificate. - pub fn new(cert: Vec<CertificateDer<'static>>, key: Arc<dyn SigningKey>) -> Self { - Self { - cert, - key, - ocsp: None, - } - } - - /// Verify the consistency of this [`CertifiedKey`]'s public and private keys. - /// This is done by performing a comparison of SubjectPublicKeyInfo bytes. - pub fn keys_match(&self) -> Result<(), Error> { - let Some(key_spki) = self.key.public_key() else { - return Err(InconsistentKeys::Unknown.into()); - }; - - let cert = ParsedCertificate::try_from(self.end_entity_cert()?)?; - match key_spki == cert.subject_public_key_info() { - true => Ok(()), - false => Err(InconsistentKeys::KeyMismatch.into()), - } - } - - /// The end-entity certificate. - pub fn end_entity_cert(&self) -> Result<&CertificateDer<'_>, Error> { - self.cert - .first() - .ok_or(Error::NoCertificatesPresented) - } -} - -#[cfg_attr(not(any(feature = "aws_lc_rs", feature = "ring")), allow(dead_code))] -pub(crate) fn public_key_to_spki( - alg_id: &AlgorithmIdentifier, - public_key: impl AsRef<[u8]>, -) -> SubjectPublicKeyInfoDer<'static> { - // SubjectPublicKeyInfo ::= SEQUENCE { - // algorithm AlgorithmIdentifier, - // subjectPublicKey BIT STRING } - // - // AlgorithmIdentifier ::= SEQUENCE { - // algorithm OBJECT IDENTIFIER, - // parameters ANY DEFINED BY algorithm OPTIONAL } - // - // note that the `pki_types::AlgorithmIdentifier` type is the - // concatenation of `algorithm` and `parameters`, but misses the - // outer `Sequence`. - - let mut spki_inner = x509::wrap_in_sequence(alg_id.as_ref()); - spki_inner.extend(&x509::wrap_in_bit_string(public_key.as_ref())); - - let spki = x509::wrap_in_sequence(&spki_inner); - - SubjectPublicKeyInfoDer::from(spki) -} diff --git a/vendor/rustls/src/crypto/tls12.rs b/vendor/rustls/src/crypto/tls12.rs deleted file mode 100644 index 7128de4b..00000000 --- a/vendor/rustls/src/crypto/tls12.rs +++ /dev/null @@ -1,169 +0,0 @@ -use alloc::boxed::Box; - -use super::{ActiveKeyExchange, hmac}; -use crate::error::Error; -use crate::version::TLS12; - -/// Implements [`Prf`] using a [`hmac::Hmac`]. -pub struct PrfUsingHmac<'a>(pub &'a dyn hmac::Hmac); - -impl Prf for PrfUsingHmac<'_> { - fn for_key_exchange( - &self, - output: &mut [u8; 48], - kx: Box<dyn ActiveKeyExchange>, - peer_pub_key: &[u8], - label: &[u8], - seed: &[u8], - ) -> Result<(), Error> { - prf( - output, - self.0 - .with_key( - kx.complete_for_tls_version(peer_pub_key, &TLS12)? - .secret_bytes(), - ) - .as_ref(), - label, - seed, - ); - Ok(()) - } - - fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]) { - prf(output, self.0.with_key(secret).as_ref(), label, seed); - } -} - -/// An instantiation of the TLS1.2 PRF with a specific, implicit hash function. -/// -/// See the definition in [RFC5246 section 5](https://www.rfc-editor.org/rfc/rfc5246#section-5). -/// -/// See [`PrfUsingHmac`] as a route to implementing this trait with just -/// an implementation of [`hmac::Hmac`]. -pub trait Prf: Send + Sync { - /// Computes `PRF(secret, label, seed)` using the secret from a completed key exchange. - /// - /// Completes the given key exchange, and then uses the resulting shared secret - /// to compute the PRF, writing the result into `output`. - /// - /// The caller guarantees that `label`, `seed` are non-empty. The caller makes no - /// guarantees about the contents of `peer_pub_key`. It must be validated by - /// [`ActiveKeyExchange::complete`]. - fn for_key_exchange( - &self, - output: &mut [u8; 48], - kx: Box<dyn ActiveKeyExchange>, - peer_pub_key: &[u8], - label: &[u8], - seed: &[u8], - ) -> Result<(), Error>; - - /// Computes `PRF(secret, label, seed)`, writing the result into `output`. - /// - /// The caller guarantees that `secret`, `label`, and `seed` are non-empty. - fn for_secret(&self, output: &mut [u8], secret: &[u8], label: &[u8], seed: &[u8]); - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } -} - -pub(crate) fn prf(out: &mut [u8], hmac_key: &dyn hmac::Key, label: &[u8], seed: &[u8]) { - // A(1) - let mut current_a = hmac_key.sign(&[label, seed]); - - let chunk_size = hmac_key.tag_len(); - for chunk in out.chunks_mut(chunk_size) { - // P_hash[i] = HMAC_hash(secret, A(i) + seed) - let p_term = hmac_key.sign(&[current_a.as_ref(), label, seed]); - chunk.copy_from_slice(&p_term.as_ref()[..chunk.len()]); - - // A(i+1) = HMAC_hash(secret, A(i)) - current_a = hmac_key.sign(&[current_a.as_ref()]); - } -} - -#[cfg(all(test, feature = "ring"))] -mod tests { - use crate::crypto::hmac::Hmac; - // nb: crypto::aws_lc_rs provider doesn't provide (or need) hmac, - // so cannot be used for this test. - use crate::crypto::ring::hmac; - - // Below known answer tests come from https://mailarchive.ietf.org/arch/msg/tls/fzVCzk-z3FShgGJ6DOXqM1ydxms/ - - #[test] - fn check_sha256() { - let secret = b"\x9b\xbe\x43\x6b\xa9\x40\xf0\x17\xb1\x76\x52\x84\x9a\x71\xdb\x35"; - let seed = b"\xa0\xba\x9f\x93\x6c\xda\x31\x18\x27\xa6\xf7\x96\xff\xd5\x19\x8c"; - let label = b"test label"; - let expect = include_bytes!("../testdata/prf-result.1.bin"); - let mut output = [0u8; 100]; - - super::prf( - &mut output, - &*hmac::HMAC_SHA256.with_key(secret), - label, - seed, - ); - assert_eq!(expect.len(), output.len()); - assert_eq!(expect.to_vec(), output.to_vec()); - } - - #[test] - fn check_sha512() { - let secret = b"\xb0\x32\x35\x23\xc1\x85\x35\x99\x58\x4d\x88\x56\x8b\xbb\x05\xeb"; - let seed = b"\xd4\x64\x0e\x12\xe4\xbc\xdb\xfb\x43\x7f\x03\xe6\xae\x41\x8e\xe5"; - let label = b"test label"; - let expect = include_bytes!("../testdata/prf-result.2.bin"); - let mut output = [0u8; 196]; - - super::prf( - &mut output, - &*hmac::HMAC_SHA512.with_key(secret), - label, - seed, - ); - assert_eq!(expect.len(), output.len()); - assert_eq!(expect.to_vec(), output.to_vec()); - } - - #[test] - fn check_sha384() { - let secret = b"\xb8\x0b\x73\x3d\x6c\xee\xfc\xdc\x71\x56\x6e\xa4\x8e\x55\x67\xdf"; - let seed = b"\xcd\x66\x5c\xf6\xa8\x44\x7d\xd6\xff\x8b\x27\x55\x5e\xdb\x74\x65"; - let label = b"test label"; - let expect = include_bytes!("../testdata/prf-result.3.bin"); - let mut output = [0u8; 148]; - - super::prf( - &mut output, - &*hmac::HMAC_SHA384.with_key(secret), - label, - seed, - ); - assert_eq!(expect.len(), output.len()); - assert_eq!(expect.to_vec(), output.to_vec()); - } -} - -#[cfg(all(bench, feature = "ring"))] -mod benchmarks { - #[bench] - fn bench_sha256(b: &mut test::Bencher) { - use crate::crypto::hmac::Hmac; - use crate::crypto::ring::hmac; - - let label = &b"extended master secret"[..]; - let seed = [0u8; 32]; - let key = &b"secret"[..]; - - b.iter(|| { - let mut out = [0u8; 48]; - super::prf(&mut out, &*hmac::HMAC_SHA256.with_key(key), &label, &seed); - test::black_box(out); - }); - } -} diff --git a/vendor/rustls/src/crypto/tls13.rs b/vendor/rustls/src/crypto/tls13.rs deleted file mode 100644 index 50ecaa89..00000000 --- a/vendor/rustls/src/crypto/tls13.rs +++ /dev/null @@ -1,406 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; - -use zeroize::Zeroize; - -use super::{ActiveKeyExchange, hmac}; -use crate::error::Error; -use crate::version::TLS13; - -/// Implementation of `HkdfExpander` via `hmac::Key`. -pub struct HkdfExpanderUsingHmac(Box<dyn hmac::Key>); - -impl HkdfExpanderUsingHmac { - fn expand_unchecked(&self, info: &[&[u8]], output: &mut [u8]) { - let mut term = hmac::Tag::new(b""); - - for (n, chunk) in output - .chunks_mut(self.0.tag_len()) - .enumerate() - { - term = self - .0 - .sign_concat(term.as_ref(), info, &[(n + 1) as u8]); - chunk.copy_from_slice(&term.as_ref()[..chunk.len()]); - } - } -} - -impl HkdfExpander for HkdfExpanderUsingHmac { - fn expand_slice(&self, info: &[&[u8]], output: &mut [u8]) -> Result<(), OutputLengthError> { - if output.len() > 255 * self.0.tag_len() { - return Err(OutputLengthError); - } - - self.expand_unchecked(info, output); - Ok(()) - } - - fn expand_block(&self, info: &[&[u8]]) -> OkmBlock { - let mut tag = [0u8; hmac::Tag::MAX_LEN]; - let reduced_tag = &mut tag[..self.0.tag_len()]; - self.expand_unchecked(info, reduced_tag); - OkmBlock::new(reduced_tag) - } - - fn hash_len(&self) -> usize { - self.0.tag_len() - } -} - -/// Implementation of `Hkdf` (and thence `HkdfExpander`) via `hmac::Hmac`. -pub struct HkdfUsingHmac<'a>(pub &'a dyn hmac::Hmac); - -impl Hkdf for HkdfUsingHmac<'_> { - fn extract_from_zero_ikm(&self, salt: Option<&[u8]>) -> Box<dyn HkdfExpander> { - let zeroes = [0u8; hmac::Tag::MAX_LEN]; - Box::new(HkdfExpanderUsingHmac(self.0.with_key( - &self.extract_prk_from_secret(salt, &zeroes[..self.0.hash_output_len()]), - ))) - } - - fn extract_from_secret(&self, salt: Option<&[u8]>, secret: &[u8]) -> Box<dyn HkdfExpander> { - Box::new(HkdfExpanderUsingHmac( - self.0 - .with_key(&self.extract_prk_from_secret(salt, secret)), - )) - } - - fn expander_for_okm(&self, okm: &OkmBlock) -> Box<dyn HkdfExpander> { - Box::new(HkdfExpanderUsingHmac(self.0.with_key(okm.as_ref()))) - } - - fn hmac_sign(&self, key: &OkmBlock, message: &[u8]) -> hmac::Tag { - self.0 - .with_key(key.as_ref()) - .sign(&[message]) - } -} - -impl HkdfPrkExtract for HkdfUsingHmac<'_> { - fn extract_prk_from_secret(&self, salt: Option<&[u8]>, secret: &[u8]) -> Vec<u8> { - let zeroes = [0u8; hmac::Tag::MAX_LEN]; - let salt = match salt { - Some(salt) => salt, - None => &zeroes[..self.0.hash_output_len()], - }; - self.0 - .with_key(salt) - .sign(&[secret]) - .as_ref() - .to_vec() - } -} - -/// Implementation of `HKDF-Expand` with an implicitly stored and immutable `PRK`. -pub trait HkdfExpander: Send + Sync { - /// `HKDF-Expand(PRK, info, L)` into a slice. - /// - /// Where: - /// - /// - `PRK` is the implicit key material represented by this instance. - /// - `L` is `output.len()`. - /// - `info` is a slice of byte slices, which should be processed sequentially - /// (or concatenated if that is not possible). - /// - /// Returns `Err(OutputLengthError)` if `L` is larger than `255 * HashLen`. - /// Otherwise, writes to `output`. - fn expand_slice(&self, info: &[&[u8]], output: &mut [u8]) -> Result<(), OutputLengthError>; - - /// `HKDF-Expand(PRK, info, L=HashLen)` returned as a value. - /// - /// - `PRK` is the implicit key material represented by this instance. - /// - `L := HashLen`. - /// - `info` is a slice of byte slices, which should be processed sequentially - /// (or concatenated if that is not possible). - /// - /// This is infallible, because by definition `OkmBlock` is always exactly - /// `HashLen` bytes long. - fn expand_block(&self, info: &[&[u8]]) -> OkmBlock; - - /// Return what `HashLen` is for this instance. - /// - /// This must be no larger than [`OkmBlock::MAX_LEN`]. - fn hash_len(&self) -> usize; -} - -/// A HKDF implementation oriented to the needs of TLS1.3. -/// -/// See [RFC5869](https://datatracker.ietf.org/doc/html/rfc5869) for the terminology -/// used in this definition. -/// -/// You can use [`HkdfUsingHmac`] which implements this trait on top of an implementation -/// of [`hmac::Hmac`]. -pub trait Hkdf: Send + Sync { - /// `HKDF-Extract(salt, 0_HashLen)` - /// - /// `0_HashLen` is a string of `HashLen` zero bytes. - /// - /// A `salt` of `None` should be treated as a sequence of `HashLen` zero bytes. - fn extract_from_zero_ikm(&self, salt: Option<&[u8]>) -> Box<dyn HkdfExpander>; - - /// `HKDF-Extract(salt, secret)` - /// - /// A `salt` of `None` should be treated as a sequence of `HashLen` zero bytes. - fn extract_from_secret(&self, salt: Option<&[u8]>, secret: &[u8]) -> Box<dyn HkdfExpander>; - - /// `HKDF-Extract(salt, shared_secret)` where `shared_secret` is the result of a key exchange. - /// - /// Custom implementations should complete the key exchange by calling - /// `kx.complete(peer_pub_key)` and then using this as the input keying material to - /// `HKDF-Extract`. - /// - /// A `salt` of `None` should be treated as a sequence of `HashLen` zero bytes. - fn extract_from_kx_shared_secret( - &self, - salt: Option<&[u8]>, - kx: Box<dyn ActiveKeyExchange>, - peer_pub_key: &[u8], - ) -> Result<Box<dyn HkdfExpander>, Error> { - Ok(self.extract_from_secret( - salt, - kx.complete_for_tls_version(peer_pub_key, &TLS13)? - .secret_bytes(), - )) - } - - /// Build a `HkdfExpander` using `okm` as the secret PRK. - fn expander_for_okm(&self, okm: &OkmBlock) -> Box<dyn HkdfExpander>; - - /// Signs `message` using `key` viewed as a HMAC key. - /// - /// This should use the same hash function as the HKDF functions in this - /// trait. - /// - /// See [RFC2104](https://datatracker.ietf.org/doc/html/rfc2104) for the - /// definition of HMAC. - fn hmac_sign(&self, key: &OkmBlock, message: &[u8]) -> hmac::Tag; - - /// Return `true` if this is backed by a FIPS-approved implementation. - fn fips(&self) -> bool { - false - } -} - -/// An extended HKDF implementation that supports directly extracting a pseudo-random key (PRK). -/// -/// The base [`Hkdf`] trait is tailored to the needs of TLS 1.3, where all extracted PRKs -/// are expanded as-is, and so can be safely encapsulated without exposing the caller -/// to the key material. -/// -/// In other contexts (for example, hybrid public key encryption (HPKE)) it may be necessary -/// to use the extracted PRK directly for purposes other than an immediate expansion. -/// This trait can be implemented to offer this functionality when it is required. -pub(crate) trait HkdfPrkExtract: Hkdf { - /// `HKDF-Extract(salt, secret)` - /// - /// A `salt` of `None` should be treated as a sequence of `HashLen` zero bytes. - /// - /// In most cases you should prefer [`Hkdf::extract_from_secret`] and using the - /// returned [HkdfExpander] instead of handling the PRK directly. - fn extract_prk_from_secret(&self, salt: Option<&[u8]>, secret: &[u8]) -> Vec<u8>; -} - -/// `HKDF-Expand(PRK, info, L)` to construct any type from a byte array. -/// -/// - `PRK` is the implicit key material represented by this instance. -/// - `L := N`; N is the size of the byte array. -/// - `info` is a slice of byte slices, which should be processed sequentially -/// (or concatenated if that is not possible). -/// -/// This is infallible, because the set of types (and therefore their length) is known -/// at compile time. -pub fn expand<T, const N: usize>(expander: &dyn HkdfExpander, info: &[&[u8]]) -> T -where - T: From<[u8; N]>, -{ - let mut output = [0u8; N]; - expander - .expand_slice(info, &mut output) - .expect("expand type parameter T is too large"); - T::from(output) -} - -/// Output key material from HKDF, as a value type. -#[derive(Clone)] -pub struct OkmBlock { - buf: [u8; Self::MAX_LEN], - used: usize, -} - -impl OkmBlock { - /// Build a single OKM block by copying a byte slice. - /// - /// The slice can be up to [`OkmBlock::MAX_LEN`] bytes in length. - pub fn new(bytes: &[u8]) -> Self { - let mut tag = Self { - buf: [0u8; Self::MAX_LEN], - used: bytes.len(), - }; - tag.buf[..bytes.len()].copy_from_slice(bytes); - tag - } - - /// Maximum supported HMAC tag size: supports up to SHA512. - pub const MAX_LEN: usize = 64; -} - -impl Drop for OkmBlock { - fn drop(&mut self) { - self.buf.zeroize(); - } -} - -impl AsRef<[u8]> for OkmBlock { - fn as_ref(&self) -> &[u8] { - &self.buf[..self.used] - } -} - -/// An error type used for `HkdfExpander::expand_slice` when -/// the slice exceeds the maximum HKDF output length. -#[derive(Debug)] -pub struct OutputLengthError; - -#[cfg(all(test, feature = "ring"))] -mod tests { - use std::prelude::v1::*; - - use super::{Hkdf, HkdfUsingHmac, expand}; - // nb: crypto::aws_lc_rs provider doesn't provide (or need) hmac, - // so cannot be used for this test. - use crate::crypto::ring::hmac; - - struct ByteArray<const N: usize>([u8; N]); - - impl<const N: usize> From<[u8; N]> for ByteArray<N> { - fn from(array: [u8; N]) -> Self { - Self(array) - } - } - - /// Test cases from appendix A in the RFC, minus cases requiring SHA1. - - #[test] - fn test_case_1() { - let hkdf = HkdfUsingHmac(&hmac::HMAC_SHA256); - let ikm = &[0x0b; 22]; - let salt = &[ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, - ]; - let info: &[&[u8]] = &[ - &[0xf0, 0xf1, 0xf2], - &[0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9], - ]; - - let output: ByteArray<42> = expand( - hkdf.extract_from_secret(Some(salt), ikm) - .as_ref(), - info, - ); - - assert_eq!( - &output.0, - &[ - 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, - 0x2f, 0x2a, 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, 0x5d, 0xb0, 0x2d, 0x56, - 0xec, 0xc4, 0xc5, 0xbf, 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, 0x58, 0x65 - ] - ); - } - - #[test] - fn test_case_2() { - let hkdf = HkdfUsingHmac(&hmac::HMAC_SHA256); - let ikm: Vec<u8> = (0x00u8..=0x4f).collect(); - let salt: Vec<u8> = (0x60u8..=0xaf).collect(); - let info: Vec<u8> = (0xb0u8..=0xff).collect(); - - let output: ByteArray<82> = expand( - hkdf.extract_from_secret(Some(&salt), &ikm) - .as_ref(), - &[&info], - ); - - assert_eq!( - &output.0, - &[ - 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, - 0x49, 0x34, 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, 0xa0, 0x50, 0xcc, 0x4c, - 0x19, 0xaf, 0xa9, 0x7c, 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, 0x71, 0xcb, - 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, - 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, - 0x3e, 0x87, 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, 0x1d, 0x87 - ] - ); - } - - #[test] - fn test_case_3() { - let hkdf = HkdfUsingHmac(&hmac::HMAC_SHA256); - let ikm = &[0x0b; 22]; - let salt = &[]; - let info = &[]; - - let output: ByteArray<42> = expand( - hkdf.extract_from_secret(Some(salt), ikm) - .as_ref(), - info, - ); - - assert_eq!( - &output.0, - &[ - 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, - 0x5a, 0x31, 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, 0xc3, 0x45, 0x4e, 0x5f, - 0x3c, 0x73, 0x8d, 0x2d, 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, 0x96, 0xc8 - ] - ); - } - - #[test] - fn test_salt_not_provided() { - // can't use test case 7, because we don't have (or want) SHA1. - // - // this output is generated with cryptography.io: - // - // >>> hkdf.HKDF(algorithm=hashes.SHA384(), length=96, salt=None, info=b"hello").derive(b"\x0b" * 40) - - let hkdf = HkdfUsingHmac(&hmac::HMAC_SHA384); - let ikm = &[0x0b; 40]; - let info = &[&b"hel"[..], &b"lo"[..]]; - - let output: ByteArray<96> = expand( - hkdf.extract_from_secret(None, ikm) - .as_ref(), - info, - ); - - assert_eq!( - &output.0, - &[ - 0xd5, 0x45, 0xdd, 0x3a, 0xff, 0x5b, 0x19, 0x46, 0xd4, 0x86, 0xfd, 0xb8, 0xd8, 0x88, - 0x2e, 0xe0, 0x1c, 0xc1, 0xa5, 0x48, 0xb6, 0x05, 0x75, 0xe4, 0xd7, 0x5d, 0x0f, 0x5f, - 0x23, 0x40, 0xee, 0x6c, 0x9e, 0x7c, 0x65, 0xd0, 0xee, 0x79, 0xdb, 0xb2, 0x07, 0x1d, - 0x66, 0xa5, 0x50, 0xc4, 0x8a, 0xa3, 0x93, 0x86, 0x8b, 0x7c, 0x69, 0x41, 0x6b, 0x3e, - 0x61, 0x44, 0x98, 0xb8, 0xc2, 0xfc, 0x82, 0x82, 0xae, 0xcd, 0x46, 0xcf, 0xb1, 0x47, - 0xdc, 0xd0, 0x69, 0x0d, 0x19, 0xad, 0xe6, 0x6c, 0x70, 0xfe, 0x87, 0x92, 0x04, 0xb6, - 0x82, 0x2d, 0x97, 0x7e, 0x46, 0x80, 0x4c, 0xe5, 0x76, 0x72, 0xb4, 0xb8 - ] - ); - } - - #[test] - fn test_output_length_bounds() { - let hkdf = HkdfUsingHmac(&hmac::HMAC_SHA256); - let ikm = &[]; - let info = &[]; - - let mut output = [0u8; 32 * 255 + 1]; - assert!( - hkdf.extract_from_secret(None, ikm) - .expand_slice(info, &mut output) - .is_err() - ); - } -} diff --git a/vendor/rustls/src/enums.rs b/vendor/rustls/src/enums.rs deleted file mode 100644 index f59ca3f9..00000000 --- a/vendor/rustls/src/enums.rs +++ /dev/null @@ -1,691 +0,0 @@ -#![allow(non_camel_case_types)] -#![allow(missing_docs)] -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::HashAlgorithm; - -enum_builder! { - /// The `AlertDescription` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum AlertDescription { - CloseNotify => 0x00, - UnexpectedMessage => 0x0a, - BadRecordMac => 0x14, - DecryptionFailed => 0x15, - RecordOverflow => 0x16, - DecompressionFailure => 0x1e, - HandshakeFailure => 0x28, - NoCertificate => 0x29, - BadCertificate => 0x2a, - UnsupportedCertificate => 0x2b, - CertificateRevoked => 0x2c, - CertificateExpired => 0x2d, - CertificateUnknown => 0x2e, - IllegalParameter => 0x2f, - UnknownCA => 0x30, - AccessDenied => 0x31, - DecodeError => 0x32, - DecryptError => 0x33, - ExportRestriction => 0x3c, - ProtocolVersion => 0x46, - InsufficientSecurity => 0x47, - InternalError => 0x50, - InappropriateFallback => 0x56, - UserCanceled => 0x5a, - NoRenegotiation => 0x64, - MissingExtension => 0x6d, - UnsupportedExtension => 0x6e, - CertificateUnobtainable => 0x6f, - UnrecognisedName => 0x70, - BadCertificateStatusResponse => 0x71, - BadCertificateHashValue => 0x72, - UnknownPSKIdentity => 0x73, - CertificateRequired => 0x74, - NoApplicationProtocol => 0x78, - EncryptedClientHelloRequired => 0x79, // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-11.2 - } -} - -enum_builder! { - /// The `HandshakeType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum HandshakeType { - HelloRequest => 0x00, - ClientHello => 0x01, - ServerHello => 0x02, - HelloVerifyRequest => 0x03, - NewSessionTicket => 0x04, - EndOfEarlyData => 0x05, - HelloRetryRequest => 0x06, - EncryptedExtensions => 0x08, - Certificate => 0x0b, - ServerKeyExchange => 0x0c, - CertificateRequest => 0x0d, - ServerHelloDone => 0x0e, - CertificateVerify => 0x0f, - ClientKeyExchange => 0x10, - Finished => 0x14, - CertificateURL => 0x15, - CertificateStatus => 0x16, - KeyUpdate => 0x18, - CompressedCertificate => 0x19, - MessageHash => 0xfe, - } -} - -enum_builder! { - /// The `ContentType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum ContentType { - ChangeCipherSpec => 0x14, - Alert => 0x15, - Handshake => 0x16, - ApplicationData => 0x17, - Heartbeat => 0x18, - } -} - -enum_builder! { - /// The `ProtocolVersion` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u16)] - pub enum ProtocolVersion { - SSLv2 => 0x0002, - SSLv3 => 0x0300, - TLSv1_0 => 0x0301, - TLSv1_1 => 0x0302, - TLSv1_2 => 0x0303, - TLSv1_3 => 0x0304, - DTLSv1_0 => 0xFEFF, - DTLSv1_2 => 0xFEFD, - DTLSv1_3 => 0xFEFC, - } -} - -enum_builder! { - /// The `CipherSuite` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u16)] - pub enum CipherSuite { - TLS_NULL_WITH_NULL_NULL => 0x0000, - TLS_PSK_WITH_AES_128_GCM_SHA256 => 0x00a8, - TLS_PSK_WITH_AES_256_GCM_SHA384 => 0x00a9, - TLS_EMPTY_RENEGOTIATION_INFO_SCSV => 0x00ff, - TLS13_AES_128_GCM_SHA256 => 0x1301, - TLS13_AES_256_GCM_SHA384 => 0x1302, - TLS13_CHACHA20_POLY1305_SHA256 => 0x1303, - TLS13_AES_128_CCM_SHA256 => 0x1304, - TLS13_AES_128_CCM_8_SHA256 => 0x1305, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA => 0xc009, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA => 0xc00a, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA => 0xc013, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA => 0xc014, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 => 0xc023, - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 => 0xc024, - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 => 0xc027, - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 => 0xc028, - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 => 0xc02b, - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 => 0xc02c, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 => 0xc02f, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 => 0xc030, - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => 0xcca8, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 => 0xcca9, - - !Debug: - TLS_RSA_WITH_NULL_MD5 => 0x0001, - TLS_RSA_WITH_NULL_SHA => 0x0002, - TLS_RSA_EXPORT_WITH_RC4_40_MD5 => 0x0003, - TLS_RSA_WITH_RC4_128_MD5 => 0x0004, - TLS_RSA_WITH_RC4_128_SHA => 0x0005, - TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 => 0x0006, - TLS_RSA_WITH_IDEA_CBC_SHA => 0x0007, - TLS_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x0008, - TLS_RSA_WITH_DES_CBC_SHA => 0x0009, - TLS_RSA_WITH_3DES_EDE_CBC_SHA => 0x000a, - TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA => 0x000b, - TLS_DH_DSS_WITH_DES_CBC_SHA => 0x000c, - TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA => 0x000d, - TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x000e, - TLS_DH_RSA_WITH_DES_CBC_SHA => 0x000f, - TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA => 0x0010, - TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA => 0x0011, - TLS_DHE_DSS_WITH_DES_CBC_SHA => 0x0012, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA => 0x0013, - TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA => 0x0014, - TLS_DHE_RSA_WITH_DES_CBC_SHA => 0x0015, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA => 0x0016, - TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 => 0x0017, - TLS_DH_anon_WITH_RC4_128_MD5 => 0x0018, - TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA => 0x0019, - TLS_DH_anon_WITH_DES_CBC_SHA => 0x001a, - TLS_DH_anon_WITH_3DES_EDE_CBC_SHA => 0x001b, - SSL_FORTEZZA_KEA_WITH_NULL_SHA => 0x001c, - SSL_FORTEZZA_KEA_WITH_FORTEZZA_CBC_SHA => 0x001d, - TLS_KRB5_WITH_DES_CBC_SHA_or_SSL_FORTEZZA_KEA_WITH_RC4_128_SHA => 0x001e, - TLS_KRB5_WITH_3DES_EDE_CBC_SHA => 0x001f, - TLS_KRB5_WITH_RC4_128_SHA => 0x0020, - TLS_KRB5_WITH_IDEA_CBC_SHA => 0x0021, - TLS_KRB5_WITH_DES_CBC_MD5 => 0x0022, - TLS_KRB5_WITH_3DES_EDE_CBC_MD5 => 0x0023, - TLS_KRB5_WITH_RC4_128_MD5 => 0x0024, - TLS_KRB5_WITH_IDEA_CBC_MD5 => 0x0025, - TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA => 0x0026, - TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA => 0x0027, - TLS_KRB5_EXPORT_WITH_RC4_40_SHA => 0x0028, - TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 => 0x0029, - TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 => 0x002a, - TLS_KRB5_EXPORT_WITH_RC4_40_MD5 => 0x002b, - TLS_PSK_WITH_NULL_SHA => 0x002c, - TLS_DHE_PSK_WITH_NULL_SHA => 0x002d, - TLS_RSA_PSK_WITH_NULL_SHA => 0x002e, - TLS_RSA_WITH_AES_128_CBC_SHA => 0x002f, - TLS_DH_DSS_WITH_AES_128_CBC_SHA => 0x0030, - TLS_DH_RSA_WITH_AES_128_CBC_SHA => 0x0031, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA => 0x0032, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA => 0x0033, - TLS_DH_anon_WITH_AES_128_CBC_SHA => 0x0034, - TLS_RSA_WITH_AES_256_CBC_SHA => 0x0035, - TLS_DH_DSS_WITH_AES_256_CBC_SHA => 0x0036, - TLS_DH_RSA_WITH_AES_256_CBC_SHA => 0x0037, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA => 0x0038, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA => 0x0039, - TLS_DH_anon_WITH_AES_256_CBC_SHA => 0x003a, - TLS_RSA_WITH_NULL_SHA256 => 0x003b, - TLS_RSA_WITH_AES_128_CBC_SHA256 => 0x003c, - TLS_RSA_WITH_AES_256_CBC_SHA256 => 0x003d, - TLS_DH_DSS_WITH_AES_128_CBC_SHA256 => 0x003e, - TLS_DH_RSA_WITH_AES_128_CBC_SHA256 => 0x003f, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 => 0x0040, - TLS_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0041, - TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA => 0x0042, - TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0043, - TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA => 0x0044, - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA => 0x0045, - TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA => 0x0046, - TLS_ECDH_ECDSA_WITH_NULL_SHA_draft => 0x0047, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA_draft => 0x0048, - TLS_ECDH_ECDSA_WITH_DES_CBC_SHA_draft => 0x0049, - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA_draft => 0x004a, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA_draft => 0x004b, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA_draft => 0x004c, - TLS_ECDH_ECNRA_WITH_DES_CBC_SHA_draft => 0x004d, - TLS_ECDH_ECNRA_WITH_3DES_EDE_CBC_SHA_draft => 0x004e, - TLS_ECMQV_ECDSA_NULL_SHA_draft => 0x004f, - TLS_ECMQV_ECDSA_WITH_RC4_128_SHA_draft => 0x0050, - TLS_ECMQV_ECDSA_WITH_DES_CBC_SHA_draft => 0x0051, - TLS_ECMQV_ECDSA_WITH_3DES_EDE_CBC_SHA_draft => 0x0052, - TLS_ECMQV_ECNRA_NULL_SHA_draft => 0x0053, - TLS_ECMQV_ECNRA_WITH_RC4_128_SHA_draft => 0x0054, - TLS_ECMQV_ECNRA_WITH_DES_CBC_SHA_draft => 0x0055, - TLS_ECMQV_ECNRA_WITH_3DES_EDE_CBC_SHA_draft => 0x0056, - TLS_ECDH_anon_NULL_WITH_SHA_draft => 0x0057, - TLS_ECDH_anon_WITH_RC4_128_SHA_draft => 0x0058, - TLS_ECDH_anon_WITH_DES_CBC_SHA_draft => 0x0059, - TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA_draft => 0x005a, - TLS_ECDH_anon_EXPORT_WITH_DES40_CBC_SHA_draft => 0x005b, - TLS_ECDH_anon_EXPORT_WITH_RC4_40_SHA_draft => 0x005c, - TLS_RSA_EXPORT1024_WITH_RC4_56_MD5 => 0x0060, - TLS_RSA_EXPORT1024_WITH_RC2_CBC_56_MD5 => 0x0061, - TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA => 0x0062, - TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA => 0x0063, - TLS_RSA_EXPORT1024_WITH_RC4_56_SHA => 0x0064, - TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA => 0x0065, - TLS_DHE_DSS_WITH_RC4_128_SHA => 0x0066, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 => 0x0067, - TLS_DH_DSS_WITH_AES_256_CBC_SHA256 => 0x0068, - TLS_DH_RSA_WITH_AES_256_CBC_SHA256 => 0x0069, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 => 0x006a, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 => 0x006b, - TLS_DH_anon_WITH_AES_128_CBC_SHA256 => 0x006c, - TLS_DH_anon_WITH_AES_256_CBC_SHA256 => 0x006d, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD => 0x0072, - TLS_DHE_DSS_WITH_AES_128_CBC_RMD => 0x0073, - TLS_DHE_DSS_WITH_AES_256_CBC_RMD => 0x0074, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD => 0x0077, - TLS_DHE_RSA_WITH_AES_128_CBC_RMD => 0x0078, - TLS_DHE_RSA_WITH_AES_256_CBC_RMD => 0x0079, - TLS_RSA_WITH_3DES_EDE_CBC_RMD => 0x007c, - TLS_RSA_WITH_AES_128_CBC_RMD => 0x007d, - TLS_RSA_WITH_AES_256_CBC_RMD => 0x007e, - TLS_GOSTR341094_WITH_28147_CNT_IMIT => 0x0080, - TLS_GOSTR341001_WITH_28147_CNT_IMIT => 0x0081, - TLS_GOSTR341094_WITH_NULL_GOSTR3411 => 0x0082, - TLS_GOSTR341001_WITH_NULL_GOSTR3411 => 0x0083, - TLS_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0084, - TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA => 0x0085, - TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0086, - TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA => 0x0087, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA => 0x0088, - TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA => 0x0089, - TLS_PSK_WITH_RC4_128_SHA => 0x008a, - TLS_PSK_WITH_3DES_EDE_CBC_SHA => 0x008b, - TLS_PSK_WITH_AES_128_CBC_SHA => 0x008c, - TLS_PSK_WITH_AES_256_CBC_SHA => 0x008d, - TLS_DHE_PSK_WITH_RC4_128_SHA => 0x008e, - TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA => 0x008f, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA => 0x0090, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA => 0x0091, - TLS_RSA_PSK_WITH_RC4_128_SHA => 0x0092, - TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA => 0x0093, - TLS_RSA_PSK_WITH_AES_128_CBC_SHA => 0x0094, - TLS_RSA_PSK_WITH_AES_256_CBC_SHA => 0x0095, - TLS_RSA_WITH_SEED_CBC_SHA => 0x0096, - TLS_DH_DSS_WITH_SEED_CBC_SHA => 0x0097, - TLS_DH_RSA_WITH_SEED_CBC_SHA => 0x0098, - TLS_DHE_DSS_WITH_SEED_CBC_SHA => 0x0099, - TLS_DHE_RSA_WITH_SEED_CBC_SHA => 0x009a, - TLS_DH_anon_WITH_SEED_CBC_SHA => 0x009b, - TLS_RSA_WITH_AES_128_GCM_SHA256 => 0x009c, - TLS_RSA_WITH_AES_256_GCM_SHA384 => 0x009d, - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 => 0x009e, - TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 => 0x009f, - TLS_DH_RSA_WITH_AES_128_GCM_SHA256 => 0x00a0, - TLS_DH_RSA_WITH_AES_256_GCM_SHA384 => 0x00a1, - TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 => 0x00a2, - TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 => 0x00a3, - TLS_DH_DSS_WITH_AES_128_GCM_SHA256 => 0x00a4, - TLS_DH_DSS_WITH_AES_256_GCM_SHA384 => 0x00a5, - TLS_DH_anon_WITH_AES_128_GCM_SHA256 => 0x00a6, - TLS_DH_anon_WITH_AES_256_GCM_SHA384 => 0x00a7, - TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 => 0x00aa, - TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 => 0x00ab, - TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 => 0x00ac, - TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 => 0x00ad, - TLS_PSK_WITH_AES_128_CBC_SHA256 => 0x00ae, - TLS_PSK_WITH_AES_256_CBC_SHA384 => 0x00af, - TLS_PSK_WITH_NULL_SHA256 => 0x00b0, - TLS_PSK_WITH_NULL_SHA384 => 0x00b1, - TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 => 0x00b2, - TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 => 0x00b3, - TLS_DHE_PSK_WITH_NULL_SHA256 => 0x00b4, - TLS_DHE_PSK_WITH_NULL_SHA384 => 0x00b5, - TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 => 0x00b6, - TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 => 0x00b7, - TLS_RSA_PSK_WITH_NULL_SHA256 => 0x00b8, - TLS_RSA_PSK_WITH_NULL_SHA384 => 0x00b9, - TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00ba, - TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bb, - TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bc, - TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bd, - TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0x00be, - TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 => 0x00bf, - TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c0, - TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c1, - TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c2, - TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c3, - TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c4, - TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 => 0x00c5, - TLS_ECDH_ECDSA_WITH_NULL_SHA => 0xc001, - TLS_ECDH_ECDSA_WITH_RC4_128_SHA => 0xc002, - TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA => 0xc003, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA => 0xc004, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA => 0xc005, - TLS_ECDHE_ECDSA_WITH_NULL_SHA => 0xc006, - TLS_ECDHE_ECDSA_WITH_RC4_128_SHA => 0xc007, - TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA => 0xc008, - TLS_ECDH_RSA_WITH_NULL_SHA => 0xc00b, - TLS_ECDH_RSA_WITH_RC4_128_SHA => 0xc00c, - TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA => 0xc00d, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA => 0xc00e, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA => 0xc00f, - TLS_ECDHE_RSA_WITH_NULL_SHA => 0xc010, - TLS_ECDHE_RSA_WITH_RC4_128_SHA => 0xc011, - TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA => 0xc012, - TLS_ECDH_anon_WITH_NULL_SHA => 0xc015, - TLS_ECDH_anon_WITH_RC4_128_SHA => 0xc016, - TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA => 0xc017, - TLS_ECDH_anon_WITH_AES_128_CBC_SHA => 0xc018, - TLS_ECDH_anon_WITH_AES_256_CBC_SHA => 0xc019, - TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA => 0xc01a, - TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA => 0xc01b, - TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA => 0xc01c, - TLS_SRP_SHA_WITH_AES_128_CBC_SHA => 0xc01d, - TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA => 0xc01e, - TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA => 0xc01f, - TLS_SRP_SHA_WITH_AES_256_CBC_SHA => 0xc020, - TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA => 0xc021, - TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA => 0xc022, - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 => 0xc025, - TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 => 0xc026, - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 => 0xc029, - TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 => 0xc02a, - TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 => 0xc02d, - TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 => 0xc02e, - TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 => 0xc031, - TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 => 0xc032, - TLS_ECDHE_PSK_WITH_RC4_128_SHA => 0xc033, - TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA => 0xc034, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA => 0xc035, - TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA => 0xc036, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 => 0xc037, - TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 => 0xc038, - TLS_ECDHE_PSK_WITH_NULL_SHA => 0xc039, - TLS_ECDHE_PSK_WITH_NULL_SHA256 => 0xc03a, - TLS_ECDHE_PSK_WITH_NULL_SHA384 => 0xc03b, - TLS_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc03c, - TLS_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc03d, - TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 => 0xc03e, - TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 => 0xc03f, - TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc040, - TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc041, - TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 => 0xc042, - TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 => 0xc043, - TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc044, - TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc045, - TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 => 0xc046, - TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 => 0xc047, - TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 => 0xc048, - TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 => 0xc049, - TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 => 0xc04a, - TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 => 0xc04b, - TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc04c, - TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc04d, - TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 => 0xc04e, - TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 => 0xc04f, - TLS_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc050, - TLS_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc051, - TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc052, - TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc053, - TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc054, - TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc055, - TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 => 0xc056, - TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 => 0xc057, - TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 => 0xc058, - TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 => 0xc059, - TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 => 0xc05a, - TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 => 0xc05b, - TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 => 0xc05c, - TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 => 0xc05d, - TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 => 0xc05e, - TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 => 0xc05f, - TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc060, - TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc061, - TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 => 0xc062, - TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 => 0xc063, - TLS_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc064, - TLS_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc065, - TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc066, - TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc067, - TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc068, - TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc069, - TLS_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06a, - TLS_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06b, - TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06c, - TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06d, - TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 => 0xc06e, - TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 => 0xc06f, - TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 => 0xc070, - TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 => 0xc071, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc072, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc073, - TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc074, - TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc075, - TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc076, - TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc077, - TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 => 0xc078, - TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 => 0xc079, - TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07a, - TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07b, - TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07c, - TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07d, - TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc07e, - TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc07f, - TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 => 0xc080, - TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 => 0xc081, - TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 => 0xc082, - TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 => 0xc083, - TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 => 0xc084, - TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 => 0xc085, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc086, - TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc087, - TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc088, - TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc089, - TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08a, - TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08b, - TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08c, - TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08d, - TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc08e, - TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc08f, - TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc090, - TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc091, - TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 => 0xc092, - TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 => 0xc093, - TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc094, - TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc095, - TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc096, - TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc097, - TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc098, - TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc099, - TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 => 0xc09a, - TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 => 0xc09b, - TLS_RSA_WITH_AES_128_CCM => 0xc09c, - TLS_RSA_WITH_AES_256_CCM => 0xc09d, - TLS_DHE_RSA_WITH_AES_128_CCM => 0xc09e, - TLS_DHE_RSA_WITH_AES_256_CCM => 0xc09f, - TLS_RSA_WITH_AES_128_CCM_8 => 0xc0a0, - TLS_RSA_WITH_AES_256_CCM_8 => 0xc0a1, - TLS_DHE_RSA_WITH_AES_128_CCM_8 => 0xc0a2, - TLS_DHE_RSA_WITH_AES_256_CCM_8 => 0xc0a3, - TLS_PSK_WITH_AES_128_CCM => 0xc0a4, - TLS_PSK_WITH_AES_256_CCM => 0xc0a5, - TLS_DHE_PSK_WITH_AES_128_CCM => 0xc0a6, - TLS_DHE_PSK_WITH_AES_256_CCM => 0xc0a7, - TLS_PSK_WITH_AES_128_CCM_8 => 0xc0a8, - TLS_PSK_WITH_AES_256_CCM_8 => 0xc0a9, - TLS_PSK_DHE_WITH_AES_128_CCM_8 => 0xc0aa, - TLS_PSK_DHE_WITH_AES_256_CCM_8 => 0xc0ab, - TLS_ECDHE_ECDSA_WITH_AES_128_CCM => 0xc0ac, - TLS_ECDHE_ECDSA_WITH_AES_256_CCM => 0xc0ad, - TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 => 0xc0ae, - TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 => 0xc0af, - TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 => 0xccaa, - TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccab, - TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccac, - TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccad, - TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 => 0xccae, - SSL_RSA_FIPS_WITH_DES_CBC_SHA => 0xfefe, - SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA => 0xfeff, - } -} - -enum_builder! { - /// The `SignatureScheme` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u16)] - pub enum SignatureScheme { - RSA_PKCS1_SHA1 => 0x0201, - ECDSA_SHA1_Legacy => 0x0203, - RSA_PKCS1_SHA256 => 0x0401, - ECDSA_NISTP256_SHA256 => 0x0403, - RSA_PKCS1_SHA384 => 0x0501, - ECDSA_NISTP384_SHA384 => 0x0503, - RSA_PKCS1_SHA512 => 0x0601, - ECDSA_NISTP521_SHA512 => 0x0603, - RSA_PSS_SHA256 => 0x0804, - RSA_PSS_SHA384 => 0x0805, - RSA_PSS_SHA512 => 0x0806, - ED25519 => 0x0807, - ED448 => 0x0808, - // https://datatracker.ietf.org/doc/html/draft-ietf-tls-mldsa-00#name-iana-considerations - ML_DSA_44 => 0x0904, - ML_DSA_65 => 0x0905, - ML_DSA_87 => 0x0906, - } -} - -impl SignatureScheme { - pub(crate) fn algorithm(&self) -> SignatureAlgorithm { - match *self { - Self::RSA_PKCS1_SHA1 - | Self::RSA_PKCS1_SHA256 - | Self::RSA_PKCS1_SHA384 - | Self::RSA_PKCS1_SHA512 - | Self::RSA_PSS_SHA256 - | Self::RSA_PSS_SHA384 - | Self::RSA_PSS_SHA512 => SignatureAlgorithm::RSA, - Self::ECDSA_SHA1_Legacy - | Self::ECDSA_NISTP256_SHA256 - | Self::ECDSA_NISTP384_SHA384 - | Self::ECDSA_NISTP521_SHA512 => SignatureAlgorithm::ECDSA, - Self::ED25519 => SignatureAlgorithm::ED25519, - Self::ED448 => SignatureAlgorithm::ED448, - _ => SignatureAlgorithm::Unknown(0), - } - } - - /// Whether a particular `SignatureScheme` is allowed for TLS protocol signatures - /// in TLS1.3. - /// - /// This prevents (eg) RSA_PKCS1_SHA256 being offered or accepted, even if our - /// verifier supports it for other protocol versions. - /// - /// See RFC8446 s4.2.3: <https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.3> - /// - /// This is a denylist so that newly-allocated `SignatureScheme`s values are - /// allowed in TLS1.3 by default. - pub(crate) fn supported_in_tls13(&self) -> bool { - let [hash, sign] = self.to_array(); - - // This covers both disallowing SHA1 items in `SignatureScheme`, and - // old hash functions. See the section beginning "Legacy algorithms:" - // and item starting "In TLS 1.2, the extension contained hash/signature - // pairs" in RFC8446 section 4.2.3. - match HashAlgorithm::from(hash) { - HashAlgorithm::NONE - | HashAlgorithm::MD5 - | HashAlgorithm::SHA1 - | HashAlgorithm::SHA224 => return false, - _ => (), - }; - - // RSA-PKCS1 is also disallowed for TLS1.3, see the section beginning - // "RSASSA-PKCS1-v1_5 algorithms:" in RFC8446 section 4.2.3. - // - // (nb. SignatureAlgorithm::RSA is RSA-PKCS1, and does not cover RSA-PSS - // or RSAE-PSS.) - // - // This also covers the outlawing of DSA mentioned elsewhere in 4.2.3. - !matches!( - SignatureAlgorithm::from(sign), - SignatureAlgorithm::Anonymous | SignatureAlgorithm::RSA | SignatureAlgorithm::DSA - ) - } -} - -enum_builder! { - /// The `SignatureAlgorithm` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum SignatureAlgorithm { - Anonymous => 0x00, - RSA => 0x01, - DSA => 0x02, - ECDSA => 0x03, - ED25519 => 0x07, - ED448 => 0x08, - } -} - -enum_builder! { - /// The "TLS Certificate Compression Algorithm IDs" TLS protocol enum. - /// Values in this enum are taken from [RFC8879]. - /// - /// [RFC8879]: https://www.rfc-editor.org/rfc/rfc8879.html#section-7.3 - #[repr(u16)] - pub enum CertificateCompressionAlgorithm { - Zlib => 1, - Brotli => 2, - Zstd => 3, - } -} - -enum_builder! { - /// The `CertificateType` enum sent in the cert_type extensions. - /// Values in this enum are taken from the various RFCs covering TLS, and are listed by IANA. - /// - /// [RFC 6091 Section 5]: <https://datatracker.ietf.org/doc/html/rfc6091#section-5> - /// [RFC 7250 Section 7]: <https://datatracker.ietf.org/doc/html/rfc7250#section-7> - #[repr(u8)] - pub enum CertificateType { - X509 => 0x00, - RawPublicKey => 0x02, - } -} - -enum_builder! { - /// The type of Encrypted Client Hello (`EchClientHelloType`). - /// - /// Specified in [draft-ietf-tls-esni Section 5]. - /// - /// [draft-ietf-tls-esni Section 5]: <https://www.ietf.org/archive/id/draft-ietf-tls-esni-18.html#section-5> - #[repr(u8)] - pub enum EchClientHelloType { - ClientHelloOuter => 0, - ClientHelloInner => 1 - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::msgs::enums::tests::{test_enum8, test_enum16}; - - #[test] - fn test_enums() { - test_enum8::<SignatureAlgorithm>(SignatureAlgorithm::Anonymous, SignatureAlgorithm::ECDSA); - test_enum8::<ContentType>(ContentType::ChangeCipherSpec, ContentType::Heartbeat); - test_enum8::<HandshakeType>(HandshakeType::HelloRequest, HandshakeType::MessageHash); - test_enum8::<AlertDescription>( - AlertDescription::CloseNotify, - AlertDescription::NoApplicationProtocol, - ); - test_enum16::<CertificateCompressionAlgorithm>( - CertificateCompressionAlgorithm::Zlib, - CertificateCompressionAlgorithm::Zstd, - ); - test_enum8::<CertificateType>(CertificateType::X509, CertificateType::RawPublicKey); - } - - #[test] - fn tls13_signature_restrictions() { - // rsa-pkcs1 denied - assert!(!SignatureScheme::RSA_PKCS1_SHA1.supported_in_tls13()); - assert!(!SignatureScheme::RSA_PKCS1_SHA256.supported_in_tls13()); - assert!(!SignatureScheme::RSA_PKCS1_SHA384.supported_in_tls13()); - assert!(!SignatureScheme::RSA_PKCS1_SHA512.supported_in_tls13()); - - // dsa denied - assert!(!SignatureScheme::from(0x0201).supported_in_tls13()); - assert!(!SignatureScheme::from(0x0202).supported_in_tls13()); - assert!(!SignatureScheme::from(0x0203).supported_in_tls13()); - assert!(!SignatureScheme::from(0x0204).supported_in_tls13()); - assert!(!SignatureScheme::from(0x0205).supported_in_tls13()); - assert!(!SignatureScheme::from(0x0206).supported_in_tls13()); - - // common - assert!(SignatureScheme::ED25519.supported_in_tls13()); - assert!(SignatureScheme::ED448.supported_in_tls13()); - assert!(SignatureScheme::RSA_PSS_SHA256.supported_in_tls13()); - assert!(SignatureScheme::RSA_PSS_SHA384.supported_in_tls13()); - assert!(SignatureScheme::RSA_PSS_SHA512.supported_in_tls13()); - - // rsa_pss_rsae_* - assert!(SignatureScheme::from(0x0804).supported_in_tls13()); - assert!(SignatureScheme::from(0x0805).supported_in_tls13()); - assert!(SignatureScheme::from(0x0806).supported_in_tls13()); - - // ecdsa_brainpool* - assert!(SignatureScheme::from(0x081a).supported_in_tls13()); - assert!(SignatureScheme::from(0x081b).supported_in_tls13()); - assert!(SignatureScheme::from(0x081c).supported_in_tls13()); - } -} diff --git a/vendor/rustls/src/error.rs b/vendor/rustls/src/error.rs deleted file mode 100644 index 3aaf3bb3..00000000 --- a/vendor/rustls/src/error.rs +++ /dev/null @@ -1,1387 +0,0 @@ -use alloc::format; -use alloc::string::String; -use alloc::vec::Vec; -use core::fmt; -#[cfg(feature = "std")] -use std::time::SystemTimeError; - -use pki_types::{AlgorithmIdentifier, ServerName, UnixTime}; -use webpki::KeyUsage; - -use crate::enums::{AlertDescription, ContentType, HandshakeType}; -use crate::msgs::handshake::{EchConfigPayload, KeyExchangeAlgorithm}; -use crate::rand; - -/// rustls reports protocol errors using this type. -#[non_exhaustive] -#[derive(Debug, PartialEq, Clone)] -pub enum Error { - /// We received a TLS message that isn't valid right now. - /// `expect_types` lists the message types we can expect right now. - /// `got_type` is the type we found. This error is typically - /// caused by a buggy TLS stack (the peer or this one), a broken - /// network, or an attack. - InappropriateMessage { - /// Which types we expected - expect_types: Vec<ContentType>, - /// What type we received - got_type: ContentType, - }, - - /// We received a TLS handshake message that isn't valid right now. - /// `expect_types` lists the handshake message types we can expect - /// right now. `got_type` is the type we found. - InappropriateHandshakeMessage { - /// Which handshake type we expected - expect_types: Vec<HandshakeType>, - /// What handshake type we received - got_type: HandshakeType, - }, - - /// An error occurred while handling Encrypted Client Hello (ECH). - InvalidEncryptedClientHello(EncryptedClientHelloError), - - /// The peer sent us a TLS message with invalid contents. - InvalidMessage(InvalidMessage), - - /// The peer didn't give us any certificates. - NoCertificatesPresented, - - /// The certificate verifier doesn't support the given type of name. - UnsupportedNameType, - - /// We couldn't decrypt a message. This is invariably fatal. - DecryptError, - - /// We couldn't encrypt a message because it was larger than the allowed message size. - /// This should never happen if the application is using valid record sizes. - EncryptError, - - /// The peer doesn't support a protocol version/feature we require. - /// The parameter gives a hint as to what version/feature it is. - PeerIncompatible(PeerIncompatible), - - /// The peer deviated from the standard TLS protocol. - /// The parameter gives a hint where. - PeerMisbehaved(PeerMisbehaved), - - /// We received a fatal alert. This means the peer is unhappy. - AlertReceived(AlertDescription), - - /// We saw an invalid certificate. - /// - /// The contained error is from the certificate validation trait - /// implementation. - InvalidCertificate(CertificateError), - - /// A provided certificate revocation list (CRL) was invalid. - InvalidCertRevocationList(CertRevocationListError), - - /// A catch-all error for unlikely errors. - General(String), - - /// We failed to figure out what time it currently is. - FailedToGetCurrentTime, - - /// We failed to acquire random bytes from the system. - FailedToGetRandomBytes, - - /// This function doesn't work until the TLS handshake - /// is complete. - HandshakeNotComplete, - - /// The peer sent an oversized record/fragment. - PeerSentOversizedRecord, - - /// An incoming connection did not support any known application protocol. - NoApplicationProtocol, - - /// The `max_fragment_size` value supplied in configuration was too small, - /// or too large. - BadMaxFragmentSize, - - /// Specific failure cases from [`keys_match`] or a [`crate::crypto::signer::SigningKey`] that cannot produce a corresponding public key. - /// - /// [`keys_match`]: crate::crypto::signer::CertifiedKey::keys_match - InconsistentKeys(InconsistentKeys), - - /// Any other error. - /// - /// This variant should only be used when the error is not better described by a more - /// specific variant. For example, if a custom crypto provider returns a - /// provider specific error. - /// - /// Enums holding this variant will never compare equal to each other. - Other(OtherError), -} - -/// Specific failure cases from [`keys_match`] or a [`crate::crypto::signer::SigningKey`] that cannot produce a corresponding public key. -/// -/// [`keys_match`]: crate::crypto::signer::CertifiedKey::keys_match -#[non_exhaustive] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum InconsistentKeys { - /// The public key returned by the [`SigningKey`] does not match the public key information in the certificate. - /// - /// [`SigningKey`]: crate::crypto::signer::SigningKey - KeyMismatch, - - /// The [`SigningKey`] cannot produce its corresponding public key. - /// - /// [`SigningKey`]: crate::crypto::signer::SigningKey - Unknown, -} - -impl From<InconsistentKeys> for Error { - #[inline] - fn from(e: InconsistentKeys) -> Self { - Self::InconsistentKeys(e) - } -} - -/// A corrupt TLS message payload that resulted in an error. -#[non_exhaustive] -#[derive(Debug, Clone, Copy, PartialEq)] -pub enum InvalidMessage { - /// A certificate payload exceeded rustls's 64KB limit - CertificatePayloadTooLarge, - /// An advertised message was larger then expected. - HandshakePayloadTooLarge, - /// The peer sent us a syntactically incorrect ChangeCipherSpec payload. - InvalidCcs, - /// An unknown content type was encountered during message decoding. - InvalidContentType, - /// A peer sent an invalid certificate status type - InvalidCertificateStatusType, - /// Context was incorrectly attached to a certificate request during a handshake. - InvalidCertRequest, - /// A peer's DH params could not be decoded - InvalidDhParams, - /// A message was zero-length when its record kind forbids it. - InvalidEmptyPayload, - /// A peer sent an unexpected key update request. - InvalidKeyUpdate, - /// A peer's server name could not be decoded - InvalidServerName, - /// A TLS message payload was larger then allowed by the specification. - MessageTooLarge, - /// Message is shorter than the expected length - MessageTooShort, - /// Missing data for the named handshake payload value - MissingData(&'static str), - /// A peer did not advertise its supported key exchange groups. - MissingKeyExchange, - /// A peer sent an empty list of signature schemes - NoSignatureSchemes, - /// Trailing data found for the named handshake payload value - TrailingData(&'static str), - /// A peer sent an unexpected message type. - UnexpectedMessage(&'static str), - /// An unknown TLS protocol was encountered during message decoding. - UnknownProtocolVersion, - /// A peer sent a non-null compression method. - UnsupportedCompression, - /// A peer sent an unknown elliptic curve type. - UnsupportedCurveType, - /// A peer sent an unsupported key exchange algorithm. - UnsupportedKeyExchangeAlgorithm(KeyExchangeAlgorithm), - /// A server sent an empty ticket - EmptyTicketValue, - /// A peer sent an empty list of items, but a non-empty list is required. - /// - /// The argument names the context. - IllegalEmptyList(&'static str), - /// A peer sent an empty value, but a non-empty value is required. - IllegalEmptyValue, - /// A peer sent a message where a given extension type was repeated - DuplicateExtension(u16), - /// A peer sent a message with a PSK offer extension in wrong position - PreSharedKeyIsNotFinalExtension, - /// A server sent a HelloRetryRequest with an unknown extension - UnknownHelloRetryRequestExtension, - /// The peer sent a TLS1.3 Certificate with an unknown extension - UnknownCertificateExtension, -} - -impl From<InvalidMessage> for Error { - #[inline] - fn from(e: InvalidMessage) -> Self { - Self::InvalidMessage(e) - } -} - -impl From<InvalidMessage> for AlertDescription { - fn from(e: InvalidMessage) -> Self { - match e { - InvalidMessage::PreSharedKeyIsNotFinalExtension => Self::IllegalParameter, - InvalidMessage::DuplicateExtension(_) => Self::IllegalParameter, - InvalidMessage::UnknownHelloRetryRequestExtension => Self::UnsupportedExtension, - _ => Self::DecodeError, - } - } -} - -#[non_exhaustive] -#[allow(missing_docs)] -#[derive(Debug, PartialEq, Clone)] -/// The set of cases where we failed to make a connection because we thought -/// the peer was misbehaving. -/// -/// This is `non_exhaustive`: we might add or stop using items here in minor -/// versions. We also don't document what they mean. Generally a user of -/// rustls shouldn't vary its behaviour on these error codes, and there is -/// nothing it can do to improve matters. -/// -/// Please file a bug against rustls if you see `Error::PeerMisbehaved` in -/// the wild. -pub enum PeerMisbehaved { - AttemptedDowngradeToTls12WhenTls13IsSupported, - BadCertChainExtensions, - DisallowedEncryptedExtension, - DuplicateClientHelloExtensions, - DuplicateEncryptedExtensions, - DuplicateHelloRetryRequestExtensions, - DuplicateNewSessionTicketExtensions, - DuplicateServerHelloExtensions, - DuplicateServerNameTypes, - EarlyDataAttemptedInSecondClientHello, - EarlyDataExtensionWithoutResumption, - EarlyDataOfferedWithVariedCipherSuite, - HandshakeHashVariedAfterRetry, - IllegalHelloRetryRequestWithEmptyCookie, - IllegalHelloRetryRequestWithNoChanges, - IllegalHelloRetryRequestWithOfferedGroup, - IllegalHelloRetryRequestWithUnofferedCipherSuite, - IllegalHelloRetryRequestWithUnofferedNamedGroup, - IllegalHelloRetryRequestWithUnsupportedVersion, - IllegalHelloRetryRequestWithWrongSessionId, - IllegalHelloRetryRequestWithInvalidEch, - IllegalMiddleboxChangeCipherSpec, - IllegalTlsInnerPlaintext, - IncorrectBinder, - InvalidCertCompression, - InvalidMaxEarlyDataSize, - InvalidKeyShare, - KeyEpochWithPendingFragment, - KeyUpdateReceivedInQuicConnection, - MessageInterleavedWithHandshakeMessage, - MissingBinderInPskExtension, - MissingKeyShare, - MissingPskModesExtension, - MissingQuicTransportParameters, - OfferedDuplicateCertificateCompressions, - OfferedDuplicateKeyShares, - OfferedEarlyDataWithOldProtocolVersion, - OfferedEmptyApplicationProtocol, - OfferedIncorrectCompressions, - PskExtensionMustBeLast, - PskExtensionWithMismatchedIdsAndBinders, - RefusedToFollowHelloRetryRequest, - RejectedEarlyDataInterleavedWithHandshakeMessage, - ResumptionAttemptedWithVariedEms, - ResumptionOfferedWithVariedCipherSuite, - ResumptionOfferedWithVariedEms, - ResumptionOfferedWithIncompatibleCipherSuite, - SelectedDifferentCipherSuiteAfterRetry, - SelectedInvalidPsk, - SelectedTls12UsingTls13VersionExtension, - SelectedUnofferedApplicationProtocol, - SelectedUnofferedCertCompression, - SelectedUnofferedCipherSuite, - SelectedUnofferedCompression, - SelectedUnofferedKxGroup, - SelectedUnofferedPsk, - SelectedUnusableCipherSuiteForVersion, - ServerEchoedCompatibilitySessionId, - ServerHelloMustOfferUncompressedEcPoints, - ServerNameDifferedOnRetry, - ServerNameMustContainOneHostName, - SignedKxWithWrongAlgorithm, - SignedHandshakeWithUnadvertisedSigScheme, - TooManyEmptyFragments, - TooManyKeyUpdateRequests, - TooManyRenegotiationRequests, - TooManyWarningAlertsReceived, - TooMuchEarlyDataReceived, - UnexpectedCleartextExtension, - UnsolicitedCertExtension, - UnsolicitedEncryptedExtension, - UnsolicitedSctList, - UnsolicitedServerHelloExtension, - WrongGroupForKeyShare, - UnsolicitedEchExtension, -} - -impl From<PeerMisbehaved> for Error { - #[inline] - fn from(e: PeerMisbehaved) -> Self { - Self::PeerMisbehaved(e) - } -} - -#[non_exhaustive] -#[allow(missing_docs)] -#[derive(Debug, PartialEq, Clone)] -/// The set of cases where we failed to make a connection because a peer -/// doesn't support a TLS version/feature we require. -/// -/// This is `non_exhaustive`: we might add or stop using items here in minor -/// versions. -pub enum PeerIncompatible { - EcPointsExtensionRequired, - ExtendedMasterSecretExtensionRequired, - IncorrectCertificateTypeExtension, - KeyShareExtensionRequired, - NamedGroupsExtensionRequired, - NoCertificateRequestSignatureSchemesInCommon, - NoCipherSuitesInCommon, - NoEcPointFormatsInCommon, - NoKxGroupsInCommon, - NoSignatureSchemesInCommon, - NullCompressionRequired, - ServerDoesNotSupportTls12Or13, - ServerSentHelloRetryRequestWithUnknownExtension, - ServerTlsVersionIsDisabledByOurConfig, - SignatureAlgorithmsExtensionRequired, - SupportedVersionsExtensionRequired, - Tls12NotOffered, - Tls12NotOfferedOrEnabled, - Tls13RequiredForQuic, - UncompressedEcPointsRequired, - UnsolicitedCertificateTypeExtension, - ServerRejectedEncryptedClientHello(Option<Vec<EchConfigPayload>>), -} - -impl From<PeerIncompatible> for Error { - #[inline] - fn from(e: PeerIncompatible) -> Self { - Self::PeerIncompatible(e) - } -} - -#[non_exhaustive] -#[derive(Debug, Clone)] -/// The ways in which certificate validators can express errors. -/// -/// Note that the rustls TLS protocol code interprets specifically these -/// error codes to send specific TLS alerts. Therefore, if a -/// custom certificate validator uses incorrect errors the library as -/// a whole will send alerts that do not match the standard (this is usually -/// a minor issue, but could be misleading). -pub enum CertificateError { - /// The certificate is not correctly encoded. - BadEncoding, - - /// The current time is after the `notAfter` time in the certificate. - Expired, - - /// The current time is after the `notAfter` time in the certificate. - /// - /// This variant is semantically the same as `Expired`, but includes - /// extra data to improve error reports. - ExpiredContext { - /// The validation time. - time: UnixTime, - /// The `notAfter` time of the certificate. - not_after: UnixTime, - }, - - /// The current time is before the `notBefore` time in the certificate. - NotValidYet, - - /// The current time is before the `notBefore` time in the certificate. - /// - /// This variant is semantically the same as `NotValidYet`, but includes - /// extra data to improve error reports. - NotValidYetContext { - /// The validation time. - time: UnixTime, - /// The `notBefore` time of the certificate. - not_before: UnixTime, - }, - - /// The certificate has been revoked. - Revoked, - - /// The certificate contains an extension marked critical, but it was - /// not processed by the certificate validator. - UnhandledCriticalExtension, - - /// The certificate chain is not issued by a known root certificate. - UnknownIssuer, - - /// The certificate's revocation status could not be determined. - UnknownRevocationStatus, - - /// The certificate's revocation status could not be determined, because the CRL is expired. - ExpiredRevocationList, - - /// The certificate's revocation status could not be determined, because the CRL is expired. - /// - /// This variant is semantically the same as `ExpiredRevocationList`, but includes - /// extra data to improve error reports. - ExpiredRevocationListContext { - /// The validation time. - time: UnixTime, - /// The nextUpdate time of the CRL. - next_update: UnixTime, - }, - - /// A certificate is not correctly signed by the key of its alleged - /// issuer. - BadSignature, - - /// A signature inside a certificate or on a handshake was made with an unsupported algorithm. - #[deprecated( - since = "0.23.29", - note = "use `UnsupportedSignatureAlgorithmContext` instead" - )] - UnsupportedSignatureAlgorithm, - - /// A signature inside a certificate or on a handshake was made with an unsupported algorithm. - UnsupportedSignatureAlgorithmContext { - /// The signature algorithm OID that was unsupported. - signature_algorithm_id: Vec<u8>, - /// Supported algorithms that were available for signature verification. - supported_algorithms: Vec<AlgorithmIdentifier>, - }, - - /// A signature was made with an algorithm that doesn't match the relevant public key. - UnsupportedSignatureAlgorithmForPublicKeyContext { - /// The signature algorithm OID. - signature_algorithm_id: Vec<u8>, - /// The public key algorithm OID. - public_key_algorithm_id: Vec<u8>, - }, - - /// The subject names in an end-entity certificate do not include - /// the expected name. - NotValidForName, - - /// The subject names in an end-entity certificate do not include - /// the expected name. - /// - /// This variant is semantically the same as `NotValidForName`, but includes - /// extra data to improve error reports. - NotValidForNameContext { - /// Expected server name. - expected: ServerName<'static>, - - /// The names presented in the end entity certificate. - /// - /// These are the subject names as present in the leaf certificate and may contain DNS names - /// with or without a wildcard label as well as IP address names. - presented: Vec<String>, - }, - - /// The certificate is being used for a different purpose than allowed. - InvalidPurpose, - - /// The certificate is being used for a different purpose than allowed. - /// - /// This variant is semantically the same as `InvalidPurpose`, but includes - /// extra data to improve error reports. - InvalidPurposeContext { - /// Extended key purpose that was required by the application. - required: ExtendedKeyPurpose, - /// Extended key purposes that were presented in the peer's certificate. - presented: Vec<ExtendedKeyPurpose>, - }, - - /// The OCSP response provided to the verifier was invalid. - /// - /// This should be returned from [`ServerCertVerifier::verify_server_cert()`] - /// when a verifier checks its `ocsp_response` parameter and finds it invalid. - /// - /// This maps to [`AlertDescription::BadCertificateStatusResponse`]. - /// - /// [`ServerCertVerifier::verify_server_cert()`]: crate::client::danger::ServerCertVerifier::verify_server_cert - InvalidOcspResponse, - - /// The certificate is valid, but the handshake is rejected for other - /// reasons. - ApplicationVerificationFailure, - - /// Any other error. - /// - /// This can be used by custom verifiers to expose the underlying error - /// (where they are not better described by the more specific errors - /// above). - /// - /// It is also used by the default verifier in case its error is - /// not covered by the above common cases. - /// - /// Enums holding this variant will never compare equal to each other. - Other(OtherError), -} - -impl PartialEq<Self> for CertificateError { - fn eq(&self, other: &Self) -> bool { - use CertificateError::*; - #[allow(clippy::match_like_matches_macro)] - match (self, other) { - (BadEncoding, BadEncoding) => true, - (Expired, Expired) => true, - ( - ExpiredContext { - time: left_time, - not_after: left_not_after, - }, - ExpiredContext { - time: right_time, - not_after: right_not_after, - }, - ) => (left_time, left_not_after) == (right_time, right_not_after), - (NotValidYet, NotValidYet) => true, - ( - NotValidYetContext { - time: left_time, - not_before: left_not_before, - }, - NotValidYetContext { - time: right_time, - not_before: right_not_before, - }, - ) => (left_time, left_not_before) == (right_time, right_not_before), - (Revoked, Revoked) => true, - (UnhandledCriticalExtension, UnhandledCriticalExtension) => true, - (UnknownIssuer, UnknownIssuer) => true, - (BadSignature, BadSignature) => true, - #[allow(deprecated)] - (UnsupportedSignatureAlgorithm, UnsupportedSignatureAlgorithm) => true, - ( - UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: left_signature_algorithm_id, - supported_algorithms: left_supported_algorithms, - }, - UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: right_signature_algorithm_id, - supported_algorithms: right_supported_algorithms, - }, - ) => { - (left_signature_algorithm_id, left_supported_algorithms) - == (right_signature_algorithm_id, right_supported_algorithms) - } - ( - UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: left_signature_algorithm_id, - public_key_algorithm_id: left_public_key_algorithm_id, - }, - UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: right_signature_algorithm_id, - public_key_algorithm_id: right_public_key_algorithm_id, - }, - ) => { - (left_signature_algorithm_id, left_public_key_algorithm_id) - == (right_signature_algorithm_id, right_public_key_algorithm_id) - } - (NotValidForName, NotValidForName) => true, - ( - NotValidForNameContext { - expected: left_expected, - presented: left_presented, - }, - NotValidForNameContext { - expected: right_expected, - presented: right_presented, - }, - ) => (left_expected, left_presented) == (right_expected, right_presented), - (InvalidPurpose, InvalidPurpose) => true, - ( - InvalidPurposeContext { - required: left_required, - presented: left_presented, - }, - InvalidPurposeContext { - required: right_required, - presented: right_presented, - }, - ) => (left_required, left_presented) == (right_required, right_presented), - (InvalidOcspResponse, InvalidOcspResponse) => true, - (ApplicationVerificationFailure, ApplicationVerificationFailure) => true, - (UnknownRevocationStatus, UnknownRevocationStatus) => true, - (ExpiredRevocationList, ExpiredRevocationList) => true, - ( - ExpiredRevocationListContext { - time: left_time, - next_update: left_next_update, - }, - ExpiredRevocationListContext { - time: right_time, - next_update: right_next_update, - }, - ) => (left_time, left_next_update) == (right_time, right_next_update), - _ => false, - } - } -} - -// The following mapping are heavily referenced in: -// * [OpenSSL Implementation](https://github.com/openssl/openssl/blob/45bb98bfa223efd3258f445ad443f878011450f0/ssl/statem/statem_lib.c#L1434) -// * [BoringSSL Implementation](https://github.com/google/boringssl/blob/583c60bd4bf76d61b2634a58bcda99a92de106cb/ssl/ssl_x509.cc#L1323) -impl From<CertificateError> for AlertDescription { - fn from(e: CertificateError) -> Self { - use CertificateError::*; - match e { - BadEncoding - | UnhandledCriticalExtension - | NotValidForName - | NotValidForNameContext { .. } => Self::BadCertificate, - // RFC 5246/RFC 8446 - // certificate_expired - // A certificate has expired or **is not currently valid**. - Expired | ExpiredContext { .. } | NotValidYet | NotValidYetContext { .. } => { - Self::CertificateExpired - } - Revoked => Self::CertificateRevoked, - // OpenSSL, BoringSSL and AWS-LC all generate an Unknown CA alert for - // the case where revocation status can not be determined, so we do the same here. - UnknownIssuer - | UnknownRevocationStatus - | ExpiredRevocationList - | ExpiredRevocationListContext { .. } => Self::UnknownCA, - InvalidOcspResponse => Self::BadCertificateStatusResponse, - #[allow(deprecated)] - BadSignature - | UnsupportedSignatureAlgorithm - | UnsupportedSignatureAlgorithmContext { .. } - | UnsupportedSignatureAlgorithmForPublicKeyContext { .. } => Self::DecryptError, - InvalidPurpose | InvalidPurposeContext { .. } => Self::UnsupportedCertificate, - ApplicationVerificationFailure => Self::AccessDenied, - // RFC 5246/RFC 8446 - // certificate_unknown - // Some other (unspecified) issue arose in processing the - // certificate, rendering it unacceptable. - Other(..) => Self::CertificateUnknown, - } - } -} - -impl fmt::Display for CertificateError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - #[cfg(feature = "std")] - Self::NotValidForNameContext { - expected, - presented, - } => { - write!( - f, - "certificate not valid for name {:?}; certificate ", - expected.to_str() - )?; - - match presented.as_slice() { - &[] => write!( - f, - "is not valid for any names (according to its subjectAltName extension)" - ), - [one] => write!(f, "is only valid for {one}"), - many => { - write!(f, "is only valid for ")?; - - let n = many.len(); - let all_but_last = &many[..n - 1]; - let last = &many[n - 1]; - - for (i, name) in all_but_last.iter().enumerate() { - write!(f, "{name}")?; - if i < n - 2 { - write!(f, ", ")?; - } - } - write!(f, " or {last}") - } - } - } - - Self::ExpiredContext { time, not_after } => write!( - f, - "certificate expired: verification time {} (UNIX), \ - but certificate is not valid after {} \ - ({} seconds ago)", - time.as_secs(), - not_after.as_secs(), - time.as_secs() - .saturating_sub(not_after.as_secs()) - ), - - Self::NotValidYetContext { time, not_before } => write!( - f, - "certificate not valid yet: verification time {} (UNIX), \ - but certificate is not valid before {} \ - ({} seconds in future)", - time.as_secs(), - not_before.as_secs(), - not_before - .as_secs() - .saturating_sub(time.as_secs()) - ), - - Self::ExpiredRevocationListContext { time, next_update } => write!( - f, - "certificate revocation list expired: \ - verification time {} (UNIX), \ - but CRL is not valid after {} \ - ({} seconds ago)", - time.as_secs(), - next_update.as_secs(), - time.as_secs() - .saturating_sub(next_update.as_secs()) - ), - - Self::InvalidPurposeContext { - required, - presented, - } => { - write!( - f, - "certificate does not allow extended key usage for {required}, allows " - )?; - for (i, eku) in presented.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{eku}")?; - } - Ok(()) - } - - other => write!(f, "{other:?}"), - } - } -} - -impl From<CertificateError> for Error { - #[inline] - fn from(e: CertificateError) -> Self { - Self::InvalidCertificate(e) - } -} - -/// Extended Key Usage (EKU) purpose values. -/// -/// These are usually represented as OID values in the certificate's extension (if present), but -/// we represent the values that are most relevant to rustls as named enum variants. -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum ExtendedKeyPurpose { - /// Client authentication - ClientAuth, - /// Server authentication - ServerAuth, - /// Other EKU values - /// - /// Represented here as a `Vec<usize>` for human readability. - Other(Vec<usize>), -} - -impl ExtendedKeyPurpose { - pub(crate) fn for_values(values: impl Iterator<Item = usize>) -> Self { - let values = values.collect::<Vec<_>>(); - match &*values { - KeyUsage::CLIENT_AUTH_REPR => Self::ClientAuth, - KeyUsage::SERVER_AUTH_REPR => Self::ServerAuth, - _ => Self::Other(values), - } - } -} - -impl fmt::Display for ExtendedKeyPurpose { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::ClientAuth => write!(f, "client authentication"), - Self::ServerAuth => write!(f, "server authentication"), - Self::Other(values) => { - for (i, value) in values.iter().enumerate() { - if i > 0 { - write!(f, ", ")?; - } - write!(f, "{value}")?; - } - Ok(()) - } - } - } -} - -#[non_exhaustive] -#[derive(Debug, Clone)] -/// The ways in which a certificate revocation list (CRL) can be invalid. -pub enum CertRevocationListError { - /// The CRL had a bad signature from its issuer. - BadSignature, - - /// The CRL had an unsupported signature from its issuer. - #[deprecated( - since = "0.23.29", - note = "use `UnsupportedSignatureAlgorithmContext` instead" - )] - UnsupportedSignatureAlgorithm, - - /// A signature inside a certificate or on a handshake was made with an unsupported algorithm. - UnsupportedSignatureAlgorithmContext { - /// The signature algorithm OID that was unsupported. - signature_algorithm_id: Vec<u8>, - /// Supported algorithms that were available for signature verification. - supported_algorithms: Vec<AlgorithmIdentifier>, - }, - - /// A signature was made with an algorithm that doesn't match the relevant public key. - UnsupportedSignatureAlgorithmForPublicKeyContext { - /// The signature algorithm OID. - signature_algorithm_id: Vec<u8>, - /// The public key algorithm OID. - public_key_algorithm_id: Vec<u8>, - }, - - /// The CRL contained an invalid CRL number. - InvalidCrlNumber, - - /// The CRL contained a revoked certificate with an invalid serial number. - InvalidRevokedCertSerialNumber, - - /// The CRL issuer does not specify the cRLSign key usage. - IssuerInvalidForCrl, - - /// The CRL is invalid for some other reason. - /// - /// Enums holding this variant will never compare equal to each other. - Other(OtherError), - - /// The CRL is not correctly encoded. - ParseError, - - /// The CRL is not a v2 X.509 CRL. - UnsupportedCrlVersion, - - /// The CRL, or a revoked certificate in the CRL, contained an unsupported critical extension. - UnsupportedCriticalExtension, - - /// The CRL is an unsupported delta CRL, containing only changes relative to another CRL. - UnsupportedDeltaCrl, - - /// The CRL is an unsupported indirect CRL, containing revoked certificates issued by a CA - /// other than the issuer of the CRL. - UnsupportedIndirectCrl, - - /// The CRL contained a revoked certificate with an unsupported revocation reason. - /// See RFC 5280 Section 5.3.1[^1] for a list of supported revocation reasons. - /// - /// [^1]: <https://www.rfc-editor.org/rfc/rfc5280#section-5.3.1> - UnsupportedRevocationReason, -} - -impl PartialEq<Self> for CertRevocationListError { - fn eq(&self, other: &Self) -> bool { - use CertRevocationListError::*; - #[allow(clippy::match_like_matches_macro)] - match (self, other) { - (BadSignature, BadSignature) => true, - #[allow(deprecated)] - (UnsupportedSignatureAlgorithm, UnsupportedSignatureAlgorithm) => true, - ( - UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: left_signature_algorithm_id, - supported_algorithms: left_supported_algorithms, - }, - UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: right_signature_algorithm_id, - supported_algorithms: right_supported_algorithms, - }, - ) => { - (left_signature_algorithm_id, left_supported_algorithms) - == (right_signature_algorithm_id, right_supported_algorithms) - } - ( - UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: left_signature_algorithm_id, - public_key_algorithm_id: left_public_key_algorithm_id, - }, - UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: right_signature_algorithm_id, - public_key_algorithm_id: right_public_key_algorithm_id, - }, - ) => { - (left_signature_algorithm_id, left_public_key_algorithm_id) - == (right_signature_algorithm_id, right_public_key_algorithm_id) - } - (InvalidCrlNumber, InvalidCrlNumber) => true, - (InvalidRevokedCertSerialNumber, InvalidRevokedCertSerialNumber) => true, - (IssuerInvalidForCrl, IssuerInvalidForCrl) => true, - (ParseError, ParseError) => true, - (UnsupportedCrlVersion, UnsupportedCrlVersion) => true, - (UnsupportedCriticalExtension, UnsupportedCriticalExtension) => true, - (UnsupportedDeltaCrl, UnsupportedDeltaCrl) => true, - (UnsupportedIndirectCrl, UnsupportedIndirectCrl) => true, - (UnsupportedRevocationReason, UnsupportedRevocationReason) => true, - _ => false, - } - } -} - -impl From<CertRevocationListError> for Error { - #[inline] - fn from(e: CertRevocationListError) -> Self { - Self::InvalidCertRevocationList(e) - } -} - -#[non_exhaustive] -#[derive(Debug, Clone, Eq, PartialEq)] -/// An error that occurred while handling Encrypted Client Hello (ECH). -pub enum EncryptedClientHelloError { - /// The provided ECH configuration list was invalid. - InvalidConfigList, - /// No compatible ECH configuration. - NoCompatibleConfig, - /// The client configuration has server name indication (SNI) disabled. - SniRequired, -} - -impl From<EncryptedClientHelloError> for Error { - #[inline] - fn from(e: EncryptedClientHelloError) -> Self { - Self::InvalidEncryptedClientHello(e) - } -} - -fn join<T: fmt::Debug>(items: &[T]) -> String { - items - .iter() - .map(|x| format!("{x:?}")) - .collect::<Vec<String>>() - .join(" or ") -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::InappropriateMessage { - expect_types, - got_type, - } => write!( - f, - "received unexpected message: got {:?} when expecting {}", - got_type, - join::<ContentType>(expect_types) - ), - Self::InappropriateHandshakeMessage { - expect_types, - got_type, - } => write!( - f, - "received unexpected handshake message: got {:?} when expecting {}", - got_type, - join::<HandshakeType>(expect_types) - ), - Self::InvalidMessage(typ) => { - write!(f, "received corrupt message of type {typ:?}") - } - Self::PeerIncompatible(why) => write!(f, "peer is incompatible: {why:?}"), - Self::PeerMisbehaved(why) => write!(f, "peer misbehaved: {why:?}"), - Self::AlertReceived(alert) => write!(f, "received fatal alert: {alert:?}"), - Self::InvalidCertificate(err) => { - write!(f, "invalid peer certificate: {err}") - } - Self::InvalidCertRevocationList(err) => { - write!(f, "invalid certificate revocation list: {err:?}") - } - Self::NoCertificatesPresented => write!(f, "peer sent no certificates"), - Self::UnsupportedNameType => write!(f, "presented server name type wasn't supported"), - Self::DecryptError => write!(f, "cannot decrypt peer's message"), - Self::InvalidEncryptedClientHello(err) => { - write!(f, "encrypted client hello failure: {err:?}") - } - Self::EncryptError => write!(f, "cannot encrypt message"), - Self::PeerSentOversizedRecord => write!(f, "peer sent excess record size"), - Self::HandshakeNotComplete => write!(f, "handshake not complete"), - Self::NoApplicationProtocol => write!(f, "peer doesn't support any known protocol"), - Self::FailedToGetCurrentTime => write!(f, "failed to get current time"), - Self::FailedToGetRandomBytes => write!(f, "failed to get random bytes"), - Self::BadMaxFragmentSize => { - write!(f, "the supplied max_fragment_size was too small or large") - } - Self::InconsistentKeys(why) => { - write!(f, "keys may not be consistent: {why:?}") - } - Self::General(err) => write!(f, "unexpected error: {err}"), - Self::Other(err) => write!(f, "other error: {err}"), - } - } -} - -#[cfg(feature = "std")] -impl From<SystemTimeError> for Error { - #[inline] - fn from(_: SystemTimeError) -> Self { - Self::FailedToGetCurrentTime - } -} - -#[cfg(feature = "std")] -impl std::error::Error for Error {} - -impl From<rand::GetRandomFailed> for Error { - fn from(_: rand::GetRandomFailed) -> Self { - Self::FailedToGetRandomBytes - } -} - -mod other_error { - use core::fmt; - #[cfg(feature = "std")] - use std::error::Error as StdError; - - use super::Error; - #[cfg(feature = "std")] - use crate::sync::Arc; - - /// Any other error that cannot be expressed by a more specific [`Error`] variant. - /// - /// For example, an `OtherError` could be produced by a custom crypto provider - /// exposing a provider specific error. - /// - /// Enums holding this type will never compare equal to each other. - #[derive(Debug, Clone)] - pub struct OtherError(#[cfg(feature = "std")] pub Arc<dyn StdError + Send + Sync>); - - impl PartialEq<Self> for OtherError { - fn eq(&self, _other: &Self) -> bool { - false - } - } - - impl From<OtherError> for Error { - fn from(value: OtherError) -> Self { - Self::Other(value) - } - } - - impl fmt::Display for OtherError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(feature = "std")] - { - write!(f, "{}", self.0) - } - #[cfg(not(feature = "std"))] - { - f.write_str("no further information available") - } - } - } - - #[cfg(feature = "std")] - impl StdError for OtherError { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - Some(self.0.as_ref()) - } - } -} - -pub use other_error::OtherError; - -#[cfg(test)] -mod tests { - use core::time::Duration; - use std::prelude::v1::*; - use std::{println, vec}; - - use pki_types::ServerName; - - use super::{ - CertRevocationListError, Error, InconsistentKeys, InvalidMessage, OtherError, UnixTime, - }; - #[cfg(feature = "std")] - use crate::sync::Arc; - - #[test] - fn certificate_error_equality() { - use super::CertificateError::*; - assert_eq!(BadEncoding, BadEncoding); - assert_eq!(Expired, Expired); - let context = ExpiredContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - not_after: UnixTime::since_unix_epoch(Duration::from_secs(123)), - }; - assert_eq!(context, context); - assert_ne!( - context, - ExpiredContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(12345)), - not_after: UnixTime::since_unix_epoch(Duration::from_secs(123)), - } - ); - assert_ne!( - context, - ExpiredContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - not_after: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - } - ); - assert_eq!(NotValidYet, NotValidYet); - let context = NotValidYetContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(123)), - not_before: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - }; - assert_eq!(context, context); - assert_ne!( - context, - NotValidYetContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - not_before: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - } - ); - assert_ne!( - context, - NotValidYetContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(123)), - not_before: UnixTime::since_unix_epoch(Duration::from_secs(12345)), - } - ); - assert_eq!(Revoked, Revoked); - assert_eq!(UnhandledCriticalExtension, UnhandledCriticalExtension); - assert_eq!(UnknownIssuer, UnknownIssuer); - assert_eq!(ExpiredRevocationList, ExpiredRevocationList); - assert_eq!(UnknownRevocationStatus, UnknownRevocationStatus); - let context = ExpiredRevocationListContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - next_update: UnixTime::since_unix_epoch(Duration::from_secs(123)), - }; - assert_eq!(context, context); - assert_ne!( - context, - ExpiredRevocationListContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(12345)), - next_update: UnixTime::since_unix_epoch(Duration::from_secs(123)), - } - ); - assert_ne!( - context, - ExpiredRevocationListContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - next_update: UnixTime::since_unix_epoch(Duration::from_secs(1234)), - } - ); - assert_eq!(BadSignature, BadSignature); - #[allow(deprecated)] - { - assert_eq!(UnsupportedSignatureAlgorithm, UnsupportedSignatureAlgorithm); - } - assert_eq!( - UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: vec![1, 2, 3], - supported_algorithms: vec![] - }, - UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: vec![1, 2, 3], - supported_algorithms: vec![] - } - ); - assert_eq!( - UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: vec![1, 2, 3], - public_key_algorithm_id: vec![4, 5, 6] - }, - UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: vec![1, 2, 3], - public_key_algorithm_id: vec![4, 5, 6] - } - ); - assert_eq!(NotValidForName, NotValidForName); - let context = NotValidForNameContext { - expected: ServerName::try_from("example.com") - .unwrap() - .to_owned(), - presented: vec!["other.com".into()], - }; - assert_eq!(context, context); - assert_ne!( - context, - NotValidForNameContext { - expected: ServerName::try_from("example.com") - .unwrap() - .to_owned(), - presented: vec![] - } - ); - assert_ne!( - context, - NotValidForNameContext { - expected: ServerName::try_from("huh.com") - .unwrap() - .to_owned(), - presented: vec!["other.com".into()], - } - ); - assert_eq!(InvalidPurpose, InvalidPurpose); - assert_eq!( - ApplicationVerificationFailure, - ApplicationVerificationFailure - ); - assert_eq!(InvalidOcspResponse, InvalidOcspResponse); - let other = Other(OtherError( - #[cfg(feature = "std")] - Arc::from(Box::from("")), - )); - assert_ne!(other, other); - assert_ne!(BadEncoding, Expired); - } - - #[test] - fn crl_error_equality() { - use super::CertRevocationListError::*; - assert_eq!(BadSignature, BadSignature); - #[allow(deprecated)] - { - assert_eq!(UnsupportedSignatureAlgorithm, UnsupportedSignatureAlgorithm); - } - assert_eq!( - UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: vec![1, 2, 3], - supported_algorithms: vec![] - }, - UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: vec![1, 2, 3], - supported_algorithms: vec![] - } - ); - assert_eq!( - UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: vec![1, 2, 3], - public_key_algorithm_id: vec![4, 5, 6] - }, - UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: vec![1, 2, 3], - public_key_algorithm_id: vec![4, 5, 6] - } - ); - assert_eq!(InvalidCrlNumber, InvalidCrlNumber); - assert_eq!( - InvalidRevokedCertSerialNumber, - InvalidRevokedCertSerialNumber - ); - assert_eq!(IssuerInvalidForCrl, IssuerInvalidForCrl); - assert_eq!(ParseError, ParseError); - assert_eq!(UnsupportedCriticalExtension, UnsupportedCriticalExtension); - assert_eq!(UnsupportedCrlVersion, UnsupportedCrlVersion); - assert_eq!(UnsupportedDeltaCrl, UnsupportedDeltaCrl); - assert_eq!(UnsupportedIndirectCrl, UnsupportedIndirectCrl); - assert_eq!(UnsupportedRevocationReason, UnsupportedRevocationReason); - let other = Other(OtherError( - #[cfg(feature = "std")] - Arc::from(Box::from("")), - )); - assert_ne!(other, other); - assert_ne!(BadSignature, InvalidCrlNumber); - } - - #[test] - #[cfg(feature = "std")] - fn other_error_equality() { - let other_error = OtherError(Arc::from(Box::from(""))); - assert_ne!(other_error, other_error); - let other: Error = other_error.into(); - assert_ne!(other, other); - } - - #[test] - fn smoke() { - use crate::enums::{AlertDescription, ContentType, HandshakeType}; - - let all = vec![ - Error::InappropriateMessage { - expect_types: vec![ContentType::Alert], - got_type: ContentType::Handshake, - }, - Error::InappropriateHandshakeMessage { - expect_types: vec![HandshakeType::ClientHello, HandshakeType::Finished], - got_type: HandshakeType::ServerHello, - }, - Error::InvalidMessage(InvalidMessage::InvalidCcs), - Error::NoCertificatesPresented, - Error::DecryptError, - super::PeerIncompatible::Tls12NotOffered.into(), - super::PeerMisbehaved::UnsolicitedCertExtension.into(), - Error::AlertReceived(AlertDescription::ExportRestriction), - super::CertificateError::Expired.into(), - super::CertificateError::NotValidForNameContext { - expected: ServerName::try_from("example.com") - .unwrap() - .to_owned(), - presented: vec![], - } - .into(), - super::CertificateError::NotValidForNameContext { - expected: ServerName::try_from("example.com") - .unwrap() - .to_owned(), - presented: vec!["DnsName(\"hello.com\")".into()], - } - .into(), - super::CertificateError::NotValidForNameContext { - expected: ServerName::try_from("example.com") - .unwrap() - .to_owned(), - presented: vec![ - "DnsName(\"hello.com\")".into(), - "DnsName(\"goodbye.com\")".into(), - ], - } - .into(), - super::CertificateError::NotValidYetContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(300)), - not_before: UnixTime::since_unix_epoch(Duration::from_secs(320)), - } - .into(), - super::CertificateError::ExpiredContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(320)), - not_after: UnixTime::since_unix_epoch(Duration::from_secs(300)), - } - .into(), - super::CertificateError::ExpiredRevocationListContext { - time: UnixTime::since_unix_epoch(Duration::from_secs(320)), - next_update: UnixTime::since_unix_epoch(Duration::from_secs(300)), - } - .into(), - super::CertificateError::InvalidOcspResponse.into(), - Error::General("undocumented error".to_string()), - Error::FailedToGetCurrentTime, - Error::FailedToGetRandomBytes, - Error::HandshakeNotComplete, - Error::PeerSentOversizedRecord, - Error::NoApplicationProtocol, - Error::BadMaxFragmentSize, - Error::InconsistentKeys(InconsistentKeys::KeyMismatch), - Error::InconsistentKeys(InconsistentKeys::Unknown), - Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), - Error::Other(OtherError( - #[cfg(feature = "std")] - Arc::from(Box::from("")), - )), - ]; - - for err in all { - println!("{err:?}:"); - println!(" fmt '{err}'"); - } - } - - #[test] - fn rand_error_mapping() { - use super::rand; - let err: Error = rand::GetRandomFailed.into(); - assert_eq!(err, Error::FailedToGetRandomBytes); - } - - #[cfg(feature = "std")] - #[test] - fn time_error_mapping() { - use std::time::SystemTime; - - let time_error = SystemTime::UNIX_EPOCH - .duration_since(SystemTime::now()) - .unwrap_err(); - let err: Error = time_error.into(); - assert_eq!(err, Error::FailedToGetCurrentTime); - } -} diff --git a/vendor/rustls/src/hash_hs.rs b/vendor/rustls/src/hash_hs.rs deleted file mode 100644 index 8b4edc68..00000000 --- a/vendor/rustls/src/hash_hs.rs +++ /dev/null @@ -1,347 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::mem; - -use crate::crypto::hash; -use crate::msgs::codec::Codec; -use crate::msgs::enums::HashAlgorithm; -use crate::msgs::handshake::HandshakeMessagePayload; -use crate::msgs::message::{Message, MessagePayload}; - -/// Early stage buffering of handshake payloads. -/// -/// Before we know the hash algorithm to use to verify the handshake, we just buffer the messages. -/// During the handshake, we may restart the transcript due to a HelloRetryRequest, reverting -/// from the `HandshakeHash` to a `HandshakeHashBuffer` again. -#[derive(Clone)] -pub(crate) struct HandshakeHashBuffer { - buffer: Vec<u8>, - client_auth_enabled: bool, -} - -impl HandshakeHashBuffer { - pub(crate) fn new() -> Self { - Self { - buffer: Vec::new(), - client_auth_enabled: false, - } - } - - /// We might be doing client auth, so need to keep a full - /// log of the handshake. - pub(crate) fn set_client_auth_enabled(&mut self) { - self.client_auth_enabled = true; - } - - /// Hash/buffer a handshake message. - pub(crate) fn add_message(&mut self, m: &Message<'_>) { - match &m.payload { - MessagePayload::Handshake { encoded, .. } => self.add_raw(encoded.bytes()), - MessagePayload::HandshakeFlight(payload) => self.add_raw(payload.bytes()), - _ => {} - }; - } - - /// Hash or buffer a byte slice. - fn add_raw(&mut self, buf: &[u8]) { - self.buffer.extend_from_slice(buf); - } - - /// Get the hash value if we were to hash `extra` too. - pub(crate) fn hash_given( - &self, - provider: &'static dyn hash::Hash, - extra: &[u8], - ) -> hash::Output { - let mut ctx = provider.start(); - ctx.update(&self.buffer); - ctx.update(extra); - ctx.finish() - } - - /// We now know what hash function the verify_data will use. - pub(crate) fn start_hash(self, provider: &'static dyn hash::Hash) -> HandshakeHash { - let mut ctx = provider.start(); - ctx.update(&self.buffer); - HandshakeHash { - provider, - ctx, - client_auth: match self.client_auth_enabled { - true => Some(self.buffer), - false => None, - }, - } - } -} - -/// This deals with keeping a running hash of the handshake -/// payloads. This is computed by buffering initially. Once -/// we know what hash function we need to use we switch to -/// incremental hashing. -/// -/// For client auth, we also need to buffer all the messages. -/// This is disabled in cases where client auth is not possible. -pub(crate) struct HandshakeHash { - provider: &'static dyn hash::Hash, - ctx: Box<dyn hash::Context>, - - /// buffer for client-auth. - client_auth: Option<Vec<u8>>, -} - -impl HandshakeHash { - /// We decided not to do client auth after all, so discard - /// the transcript. - pub(crate) fn abandon_client_auth(&mut self) { - self.client_auth = None; - } - - /// Hash/buffer a handshake message. - pub(crate) fn add_message(&mut self, m: &Message<'_>) -> &mut Self { - match &m.payload { - MessagePayload::Handshake { encoded, .. } => self.add_raw(encoded.bytes()), - MessagePayload::HandshakeFlight(payload) => self.add_raw(payload.bytes()), - _ => self, - } - } - - /// Hash/buffer an encoded handshake message. - pub(crate) fn add(&mut self, bytes: &[u8]) { - self.add_raw(bytes); - } - - /// Hash or buffer a byte slice. - fn add_raw(&mut self, buf: &[u8]) -> &mut Self { - self.ctx.update(buf); - - if let Some(buffer) = &mut self.client_auth { - buffer.extend_from_slice(buf); - } - - self - } - - /// Get the hash value if we were to hash `extra` too, - /// using hash function `hash`. - pub(crate) fn hash_given(&self, extra: &[u8]) -> hash::Output { - let mut ctx = self.ctx.fork(); - ctx.update(extra); - ctx.finish() - } - - pub(crate) fn into_hrr_buffer(self) -> HandshakeHashBuffer { - let old_hash = self.ctx.finish(); - let old_handshake_hash_msg = - HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref()); - - HandshakeHashBuffer { - client_auth_enabled: self.client_auth.is_some(), - buffer: old_handshake_hash_msg.get_encoding(), - } - } - - /// Take the current hash value, and encapsulate it in a - /// 'handshake_hash' handshake message. Start this hash - /// again, with that message at the front. - pub(crate) fn rollup_for_hrr(&mut self) { - let ctx = &mut self.ctx; - - let old_ctx = mem::replace(ctx, self.provider.start()); - let old_hash = old_ctx.finish(); - let old_handshake_hash_msg = - HandshakeMessagePayload::build_handshake_hash(old_hash.as_ref()); - - self.add_raw(&old_handshake_hash_msg.get_encoding()); - } - - /// Get the current hash value. - pub(crate) fn current_hash(&self) -> hash::Output { - self.ctx.fork_finish() - } - - /// Takes this object's buffer containing all handshake messages - /// so far. This method only works once; it resets the buffer - /// to empty. - #[cfg(feature = "tls12")] - pub(crate) fn take_handshake_buf(&mut self) -> Option<Vec<u8>> { - self.client_auth.take() - } - - /// The hashing algorithm - pub(crate) fn algorithm(&self) -> HashAlgorithm { - self.provider.algorithm() - } -} - -impl Clone for HandshakeHash { - fn clone(&self) -> Self { - Self { - provider: self.provider, - ctx: self.ctx.fork(), - client_auth: self.client_auth.clone(), - } - } -} - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use super::provider::hash::SHA256; - use super::*; - use crate::crypto::hash::Hash; - use crate::enums::ProtocolVersion; - use crate::msgs::base::Payload; - use crate::msgs::handshake::{HandshakeMessagePayload, HandshakePayload}; - - #[test] - fn hashes_correctly() { - let mut hhb = HandshakeHashBuffer::new(); - hhb.add_raw(b"hello"); - assert_eq!(hhb.buffer.len(), 5); - let mut hh = hhb.start_hash(&SHA256); - assert!(hh.client_auth.is_none()); - hh.add_raw(b"world"); - let h = hh.current_hash(); - let h = h.as_ref(); - assert_eq!(h[0], 0x93); - assert_eq!(h[1], 0x6a); - assert_eq!(h[2], 0x18); - assert_eq!(h[3], 0x5c); - } - - #[test] - fn hashes_message_types() { - // handshake protocol encoding of 0x0e 00 00 00 - let server_hello_done_message = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ServerHelloDone, - )), - }; - - let app_data_ignored = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::ApplicationData(Payload::Borrowed(b"hello")), - }; - - let end_of_early_data_flight = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::HandshakeFlight(Payload::Borrowed(b"\x05\x00\x00\x00")), - }; - - // buffered mode - let mut hhb = HandshakeHashBuffer::new(); - hhb.add_message(&server_hello_done_message); - hhb.add_message(&app_data_ignored); - hhb.add_message(&end_of_early_data_flight); - assert_eq!( - hhb.start_hash(&SHA256) - .current_hash() - .as_ref(), - SHA256 - .hash(b"\x0e\x00\x00\x00\x05\x00\x00\x00") - .as_ref() - ); - - // non-buffered mode - let mut hh = HandshakeHashBuffer::new().start_hash(&SHA256); - hh.add_message(&server_hello_done_message); - hh.add_message(&app_data_ignored); - hh.add_message(&end_of_early_data_flight); - assert_eq!( - hh.current_hash().as_ref(), - SHA256 - .hash(b"\x0e\x00\x00\x00\x05\x00\x00\x00") - .as_ref() - ); - } - - #[cfg(feature = "tls12")] - #[test] - fn buffers_correctly() { - let mut hhb = HandshakeHashBuffer::new(); - hhb.set_client_auth_enabled(); - hhb.add_raw(b"hello"); - assert_eq!(hhb.buffer.len(), 5); - let mut hh = hhb.start_hash(&SHA256); - assert_eq!( - hh.client_auth - .as_ref() - .map(|buf| buf.len()), - Some(5) - ); - hh.add_raw(b"world"); - assert_eq!( - hh.client_auth - .as_ref() - .map(|buf| buf.len()), - Some(10) - ); - let h = hh.current_hash(); - let h = h.as_ref(); - assert_eq!(h[0], 0x93); - assert_eq!(h[1], 0x6a); - assert_eq!(h[2], 0x18); - assert_eq!(h[3], 0x5c); - let buf = hh.take_handshake_buf(); - assert_eq!(Some(b"helloworld".to_vec()), buf); - } - - #[test] - fn abandon() { - let mut hhb = HandshakeHashBuffer::new(); - hhb.set_client_auth_enabled(); - hhb.add_raw(b"hello"); - assert_eq!(hhb.buffer.len(), 5); - let mut hh = hhb.start_hash(&SHA256); - assert_eq!( - hh.client_auth - .as_ref() - .map(|buf| buf.len()), - Some(5) - ); - hh.abandon_client_auth(); - assert_eq!(hh.client_auth, None); - hh.add_raw(b"world"); - assert_eq!(hh.client_auth, None); - let h = hh.current_hash(); - let h = h.as_ref(); - assert_eq!(h[0], 0x93); - assert_eq!(h[1], 0x6a); - assert_eq!(h[2], 0x18); - assert_eq!(h[3], 0x5c); - } - - #[test] - fn clones_correctly() { - let mut hhb = HandshakeHashBuffer::new(); - hhb.set_client_auth_enabled(); - hhb.add_raw(b"hello"); - assert_eq!(hhb.buffer.len(), 5); - - // Cloning the HHB should result in the same buffer and client auth state. - let mut hhb_prime = hhb.clone(); - assert_eq!(hhb_prime.buffer, hhb.buffer); - assert!(hhb_prime.client_auth_enabled); - - // Updating the HHB clone shouldn't affect the original. - hhb_prime.add_raw(b"world"); - assert_eq!(hhb_prime.buffer.len(), 10); - assert_ne!(hhb.buffer, hhb_prime.buffer); - - let hh = hhb.start_hash(&SHA256); - let hh_hash = hh.current_hash(); - let hh_hash = hh_hash.as_ref(); - - // Cloning the HH should result in the same current hash. - let mut hh_prime = hh.clone(); - let hh_prime_hash = hh_prime.current_hash(); - let hh_prime_hash = hh_prime_hash.as_ref(); - assert_eq!(hh_hash, hh_prime_hash); - - // Updating the HH clone shouldn't affect the original. - hh_prime.add_raw(b"goodbye"); - assert_eq!(hh.current_hash().as_ref(), hh_hash); - assert_ne!(hh_prime.current_hash().as_ref(), hh_hash); - } -} diff --git a/vendor/rustls/src/key_log.rs b/vendor/rustls/src/key_log.rs deleted file mode 100644 index 0ffcccfe..00000000 --- a/vendor/rustls/src/key_log.rs +++ /dev/null @@ -1,61 +0,0 @@ -use core::fmt::Debug; - -#[cfg(all(doc, feature = "std"))] -use crate::KeyLogFile; - -/// This trait represents the ability to do something useful -/// with key material, such as logging it to a file for debugging. -/// -/// Naturally, secrets passed over the interface are *extremely* -/// sensitive and can break the security of past, present and -/// future sessions. -/// -/// You'll likely want some interior mutability in your -/// implementation to make this useful. -/// -/// See [`KeyLogFile`] that implements the standard -/// `SSLKEYLOGFILE` environment variable behaviour. -pub trait KeyLog: Debug + Send + Sync { - /// Log the given `secret`. `client_random` is provided for - /// session identification. `label` describes precisely what - /// `secret` means: - /// - /// - `CLIENT_RANDOM`: `secret` is the master secret for a TLSv1.2 session. - /// - `CLIENT_EARLY_TRAFFIC_SECRET`: `secret` encrypts early data - /// transmitted by a client - /// - `SERVER_HANDSHAKE_TRAFFIC_SECRET`: `secret` encrypts - /// handshake messages from the server during a TLSv1.3 handshake. - /// - `CLIENT_HANDSHAKE_TRAFFIC_SECRET`: `secret` encrypts - /// handshake messages from the client during a TLSv1.3 handshake. - /// - `SERVER_TRAFFIC_SECRET_0`: `secret` encrypts post-handshake data - /// from the server in a TLSv1.3 session. - /// - `CLIENT_TRAFFIC_SECRET_0`: `secret` encrypts post-handshake data - /// from the client in a TLSv1.3 session. - /// - `EXPORTER_SECRET`: `secret` is the post-handshake exporter secret - /// in a TLSv1.3 session. - /// - /// These strings are selected to match the NSS key log format: - /// <https://nss-crypto.org/reference/security/nss/legacy/key_log_format/index.html> - fn log(&self, label: &str, client_random: &[u8], secret: &[u8]); - - /// Indicates whether the secret with label `label` will be logged. - /// - /// If `will_log` returns true then `log` will be called with the secret. - /// Otherwise, `log` will not be called for the secret. This is a - /// performance optimization. - fn will_log(&self, _label: &str) -> bool { - true - } -} - -/// KeyLog that does exactly nothing. -#[derive(Debug)] -pub struct NoKeyLog; - -impl KeyLog for NoKeyLog { - fn log(&self, _: &str, _: &[u8], _: &[u8]) {} - #[inline] - fn will_log(&self, _label: &str) -> bool { - false - } -} diff --git a/vendor/rustls/src/key_log_file.rs b/vendor/rustls/src/key_log_file.rs deleted file mode 100644 index 45f29da5..00000000 --- a/vendor/rustls/src/key_log_file.rs +++ /dev/null @@ -1,162 +0,0 @@ -use alloc::vec::Vec; -use core::fmt::{Debug, Formatter}; -use std::env::var_os; -use std::ffi::OsString; -use std::fs::{File, OpenOptions}; -use std::io; -use std::io::Write; -use std::sync::Mutex; - -use crate::KeyLog; -use crate::log::warn; - -// Internal mutable state for KeyLogFile -struct KeyLogFileInner { - file: Option<File>, - buf: Vec<u8>, -} - -impl KeyLogFileInner { - fn new(var: Option<OsString>) -> Self { - let Some(path) = &var else { - return Self { - file: None, - buf: Vec::new(), - }; - }; - - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - let file = match OpenOptions::new() - .append(true) - .create(true) - .open(path) - { - Ok(f) => Some(f), - Err(e) => { - warn!("unable to create key log file {path:?}: {e}"); - None - } - }; - - Self { - file, - buf: Vec::new(), - } - } - - fn try_write(&mut self, label: &str, client_random: &[u8], secret: &[u8]) -> io::Result<()> { - let Some(file) = &mut self.file else { - return Ok(()); - }; - - self.buf.truncate(0); - write!(self.buf, "{label} ")?; - for b in client_random.iter() { - write!(self.buf, "{b:02x}")?; - } - write!(self.buf, " ")?; - for b in secret.iter() { - write!(self.buf, "{b:02x}")?; - } - writeln!(self.buf)?; - file.write_all(&self.buf) - } -} - -impl Debug for KeyLogFileInner { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("KeyLogFileInner") - // Note: we omit self.buf deliberately as it may contain key data. - .field("file", &self.file) - .finish() - } -} - -/// [`KeyLog`] implementation that opens a file whose name is -/// given by the `SSLKEYLOGFILE` environment variable, and writes -/// keys into it. -/// -/// If `SSLKEYLOGFILE` is not set, this does nothing. -/// -/// If such a file cannot be opened, or cannot be written then -/// this does nothing but logs errors at warning-level. -pub struct KeyLogFile(Mutex<KeyLogFileInner>); - -impl KeyLogFile { - /// Makes a new `KeyLogFile`. The environment variable is - /// inspected and the named file is opened during this call. - pub fn new() -> Self { - let var = var_os("SSLKEYLOGFILE"); - Self(Mutex::new(KeyLogFileInner::new(var))) - } -} - -impl KeyLog for KeyLogFile { - fn log(&self, label: &str, client_random: &[u8], secret: &[u8]) { - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - match self - .0 - .lock() - .unwrap() - .try_write(label, client_random, secret) - { - Ok(()) => {} - Err(e) => { - warn!("error writing to key log file: {e}"); - } - } - } -} - -impl Debug for KeyLogFile { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - match self.0.try_lock() { - Ok(key_log_file) => write!(f, "{key_log_file:?}"), - Err(_) => write!(f, "KeyLogFile {{ <locked> }}"), - } - } -} - -#[cfg(all(test, target_os = "linux"))] -mod tests { - use super::*; - - fn init() { - let _ = env_logger::builder() - .is_test(true) - .try_init(); - } - - #[test] - fn test_env_var_is_not_set() { - init(); - let mut inner = KeyLogFileInner::new(None); - assert!( - inner - .try_write("label", b"random", b"secret") - .is_ok() - ); - } - - #[test] - fn test_env_var_cannot_be_opened() { - init(); - let mut inner = KeyLogFileInner::new(Some("/dev/does-not-exist".into())); - assert!( - inner - .try_write("label", b"random", b"secret") - .is_ok() - ); - } - - #[test] - fn test_env_var_cannot_be_written() { - init(); - let mut inner = KeyLogFileInner::new(Some("/dev/full".into())); - assert!( - inner - .try_write("label", b"random", b"secret") - .is_err() - ); - } -} diff --git a/vendor/rustls/src/lib.rs b/vendor/rustls/src/lib.rs deleted file mode 100644 index 845f4e94..00000000 --- a/vendor/rustls/src/lib.rs +++ /dev/null @@ -1,715 +0,0 @@ -//! # Rustls - a modern TLS library -//! -//! Rustls is a TLS library that aims to provide a good level of cryptographic security, -//! requires no configuration to achieve that security, and provides no unsafe features or -//! obsolete cryptography by default. -//! -//! Rustls implements TLS1.2 and TLS1.3 for both clients and servers. See [the full -//! list of protocol features](manual::_04_features). -//! -//! ### Platform support -//! -//! While Rustls itself is platform independent, by default it uses [`aws-lc-rs`] for implementing -//! the cryptography in TLS. See [the aws-lc-rs FAQ][aws-lc-rs-platforms-faq] for more details of the -//! platform/architecture support constraints in aws-lc-rs. -//! -//! [`ring`] is also available via the `ring` crate feature: see -//! [the supported `ring` target platforms][ring-target-platforms]. -//! -//! By providing a custom instance of the [`crypto::CryptoProvider`] struct, you -//! can replace all cryptography dependencies of rustls. This is a route to being portable -//! to a wider set of architectures and environments, or compliance requirements. See the -//! [`crypto::CryptoProvider`] documentation for more details. -//! -//! Specifying `default-features = false` when depending on rustls will remove the implicit -//! dependency on aws-lc-rs. -//! -//! Rustls requires Rust 1.71 or later. It has an optional dependency on zlib-rs which requires 1.75 or later. -//! -//! [ring-target-platforms]: https://github.com/briansmith/ring/blob/2e8363b433fa3b3962c877d9ed2e9145612f3160/include/ring-core/target.h#L18-L64 -//! [`crypto::CryptoProvider`]: crate::crypto::CryptoProvider -//! [`ring`]: https://crates.io/crates/ring -//! [aws-lc-rs-platforms-faq]: https://aws.github.io/aws-lc-rs/faq.html#can-i-run-aws-lc-rs-on-x-platform-or-architecture -//! [`aws-lc-rs`]: https://crates.io/crates/aws-lc-rs -//! -//! ### Cryptography providers -//! -//! Since Rustls 0.22 it has been possible to choose the provider of the cryptographic primitives -//! that Rustls uses. This may be appealing if you have specific platform, compliance or feature -//! requirements that aren't met by the default provider, [`aws-lc-rs`]. -//! -//! Users that wish to customize the provider in use can do so when constructing `ClientConfig` -//! and `ServerConfig` instances using the `with_crypto_provider` method on the respective config -//! builder types. See the [`crypto::CryptoProvider`] documentation for more details. -//! -//! #### Built-in providers -//! -//! Rustls ships with two built-in providers controlled by associated crate features: -//! -//! * [`aws-lc-rs`] - enabled by default, available with the `aws_lc_rs` crate feature enabled. -//! * [`ring`] - available with the `ring` crate feature enabled. -//! -//! See the documentation for [`crypto::CryptoProvider`] for details on how providers are -//! selected. -//! -//! #### Third-party providers -//! -//! The community has also started developing third-party providers for Rustls: -//! -//! * [`boring-rustls-provider`] - a work-in-progress provider that uses [`boringssl`] for -//! cryptography. -//! * [`rustls-graviola`] - a provider that uses [`graviola`] for cryptography. -//! * [`rustls-mbedtls-provider`] - a provider that uses [`mbedtls`] for cryptography. -//! * [`rustls-openssl`] - a provider that uses [OpenSSL] for cryptography. -//! * [`rustls-rustcrypto`] - an experimental provider that uses the crypto primitives -//! from [`RustCrypto`] for cryptography. -//! * [`rustls-symcrypt`] - a provider that uses Microsoft's [SymCrypt] library. -//! * [`rustls-wolfcrypt-provider`] - a work-in-progress provider that uses [`wolfCrypt`] for cryptography. -//! -//! [`rustls-graviola`]: https://crates.io/crates/rustls-graviola -//! [`graviola`]: https://github.com/ctz/graviola -//! [`rustls-mbedtls-provider`]: https://github.com/fortanix/rustls-mbedtls-provider -//! [`mbedtls`]: https://github.com/Mbed-TLS/mbedtls -//! [`rustls-openssl`]: https://github.com/tofay/rustls-openssl -//! [OpenSSL]: https://openssl-library.org/ -//! [`rustls-symcrypt`]: https://github.com/microsoft/rustls-symcrypt -//! [SymCrypt]: https://github.com/microsoft/SymCrypt -//! [`boring-rustls-provider`]: https://github.com/janrueth/boring-rustls-provider -//! [`boringssl`]: https://github.com/google/boringssl -//! [`rustls-rustcrypto`]: https://github.com/RustCrypto/rustls-rustcrypto -//! [`RustCrypto`]: https://github.com/RustCrypto -//! [`rustls-wolfcrypt-provider`]: https://github.com/wolfSSL/rustls-wolfcrypt-provider -//! [`wolfCrypt`]: https://www.wolfssl.com/products/wolfcrypt -//! -//! #### Custom provider -//! -//! We also provide a simple example of writing your own provider in the [custom provider example]. -//! This example implements a minimal provider using parts of the [`RustCrypto`] ecosystem. -//! -//! See the [Making a custom CryptoProvider] section of the documentation for more information -//! on this topic. -//! -//! [custom provider example]: https://github.com/rustls/rustls/tree/main/provider-example/ -//! [`RustCrypto`]: https://github.com/RustCrypto -//! [Making a custom CryptoProvider]: https://docs.rs/rustls/latest/rustls/crypto/struct.CryptoProvider.html#making-a-custom-cryptoprovider -//! -//! ## Design overview -//! -//! Rustls is a low-level library. If your goal is to make HTTPS connections you may prefer -//! to use a library built on top of Rustls like [hyper] or [ureq]. -//! -//! [hyper]: https://crates.io/crates/hyper -//! [ureq]: https://crates.io/crates/ureq -//! -//! ### Rustls does not take care of network IO -//! It doesn't make or accept TCP connections, or do DNS, or read or write files. -//! -//! Our [examples] directory contains demos that show how to handle I/O using the -//! [`stream::Stream`] helper, as well as more complex asynchronous I/O using [`mio`]. -//! If you're already using Tokio for an async runtime you may prefer to use [`tokio-rustls`] instead -//! of interacting with rustls directly. -//! -//! [examples]: https://github.com/rustls/rustls/tree/main/examples -//! [`tokio-rustls`]: https://github.com/rustls/tokio-rustls -//! -//! ### Rustls provides encrypted pipes -//! These are the [`ServerConnection`] and [`ClientConnection`] types. You supply raw TLS traffic -//! on the left (via the [`read_tls()`] and [`write_tls()`] methods) and then read/write the -//! plaintext on the right: -//! -//! [`read_tls()`]: Connection::read_tls -//! [`write_tls()`]: Connection::read_tls -//! -//! ```text -//! TLS Plaintext -//! === ========= -//! read_tls() +-----------------------+ reader() as io::Read -//! | | -//! +---------> ClientConnection +---------> -//! | or | -//! <---------+ ServerConnection <---------+ -//! | | -//! write_tls() +-----------------------+ writer() as io::Write -//! ``` -//! -//! ### Rustls takes care of server certificate verification -//! You do not need to provide anything other than a set of root certificates to trust. -//! Certificate verification cannot be turned off or disabled in the main API. -//! -//! ## Getting started -//! This is the minimum you need to do to make a TLS client connection. -//! -//! First we load some root certificates. These are used to authenticate the server. -//! The simplest way is to depend on the [`webpki_roots`] crate which contains -//! the Mozilla set of root certificates. -//! -//! ```rust,no_run -//! # #[cfg(feature = "aws-lc-rs")] { -//! let root_store = rustls::RootCertStore::from_iter( -//! webpki_roots::TLS_SERVER_ROOTS -//! .iter() -//! .cloned(), -//! ); -//! # } -//! ``` -//! -//! [`webpki_roots`]: https://crates.io/crates/webpki-roots -//! -//! Next, we make a `ClientConfig`. You're likely to make one of these per process, -//! and use it for all connections made by that process. -//! -//! ```rust,no_run -//! # #[cfg(feature = "aws_lc_rs")] { -//! # let root_store: rustls::RootCertStore = panic!(); -//! let config = rustls::ClientConfig::builder() -//! .with_root_certificates(root_store) -//! .with_no_client_auth(); -//! # } -//! ``` -//! -//! Now we can make a connection. You need to provide the server's hostname so we -//! know what to expect to find in the server's certificate. -//! -//! ```rust -//! # #[cfg(feature = "aws_lc_rs")] { -//! # use rustls; -//! # use webpki; -//! # use std::sync::Arc; -//! # rustls::crypto::aws_lc_rs::default_provider().install_default(); -//! # let root_store = rustls::RootCertStore::from_iter( -//! # webpki_roots::TLS_SERVER_ROOTS -//! # .iter() -//! # .cloned(), -//! # ); -//! # let config = rustls::ClientConfig::builder() -//! # .with_root_certificates(root_store) -//! # .with_no_client_auth(); -//! let rc_config = Arc::new(config); -//! let example_com = "example.com".try_into().unwrap(); -//! let mut client = rustls::ClientConnection::new(rc_config, example_com); -//! # } -//! ``` -//! -//! Now you should do appropriate IO for the `client` object. If `client.wants_read()` yields -//! true, you should call `client.read_tls()` when the underlying connection has data. -//! Likewise, if `client.wants_write()` yields true, you should call `client.write_tls()` -//! when the underlying connection is able to send data. You should continue doing this -//! as long as the connection is valid. -//! -//! The return types of `read_tls()` and `write_tls()` only tell you if the IO worked. No -//! parsing or processing of the TLS messages is done. After each `read_tls()` you should -//! therefore call `client.process_new_packets()` which parses and processes the messages. -//! Any error returned from `process_new_packets` is fatal to the connection, and will tell you -//! why. For example, if the server's certificate is expired `process_new_packets` will -//! return `Err(InvalidCertificate(Expired))`. From this point on, -//! `process_new_packets` will not do any new work and will return that error continually. -//! -//! You can extract newly received data by calling `client.reader()` (which implements the -//! `io::Read` trait). You can send data to the peer by calling `client.writer()` (which -//! implements `io::Write` trait). Note that `client.writer().write()` buffers data you -//! send if the TLS connection is not yet established: this is useful for writing (say) a -//! HTTP request, but this is buffered so avoid large amounts of data. -//! -//! The following code uses a fictional socket IO API for illustration, and does not handle -//! errors. -//! -//! ```rust,no_run -//! # #[cfg(feature = "aws_lc_rs")] { -//! # let mut client = rustls::ClientConnection::new(panic!(), panic!()).unwrap(); -//! # struct Socket { } -//! # impl Socket { -//! # fn ready_for_write(&self) -> bool { false } -//! # fn ready_for_read(&self) -> bool { false } -//! # fn wait_for_something_to_happen(&self) { } -//! # } -//! # -//! # use std::io::{Read, Write, Result}; -//! # impl Read for Socket { -//! # fn read(&mut self, buf: &mut [u8]) -> Result<usize> { panic!() } -//! # } -//! # impl Write for Socket { -//! # fn write(&mut self, buf: &[u8]) -> Result<usize> { panic!() } -//! # fn flush(&mut self) -> Result<()> { panic!() } -//! # } -//! # -//! # fn connect(_address: &str, _port: u16) -> Socket { -//! # panic!(); -//! # } -//! use std::io; -//! use rustls::Connection; -//! -//! client.writer().write(b"GET / HTTP/1.0\r\n\r\n").unwrap(); -//! let mut socket = connect("example.com", 443); -//! loop { -//! if client.wants_read() && socket.ready_for_read() { -//! client.read_tls(&mut socket).unwrap(); -//! client.process_new_packets().unwrap(); -//! -//! let mut plaintext = Vec::new(); -//! client.reader().read_to_end(&mut plaintext).unwrap(); -//! io::stdout().write(&plaintext).unwrap(); -//! } -//! -//! if client.wants_write() && socket.ready_for_write() { -//! client.write_tls(&mut socket).unwrap(); -//! } -//! -//! socket.wait_for_something_to_happen(); -//! } -//! # } -//! ``` -//! -//! # Examples -//! -//! You can find several client and server examples of varying complexity in the [examples] -//! directory, including [`tlsserver-mio`](https://github.com/rustls/rustls/blob/main/examples/src/bin/tlsserver-mio.rs) -//! and [`tlsclient-mio`](https://github.com/rustls/rustls/blob/main/examples/src/bin/tlsclient-mio.rs) -//! \- full worked examples using [`mio`]. -//! -//! [`mio`]: https://docs.rs/mio/latest/mio/ -//! -//! # Manual -//! -//! The [rustls manual](crate::manual) explains design decisions and includes how-to guidance. -//! -//! # Crate features -//! Here's a list of what features are exposed by the rustls crate and what -//! they mean. -//! -//! - `std` (enabled by default): enable the high-level (buffered) Connection API and other functionality -//! which relies on the `std` library. -//! -//! - `aws_lc_rs` (enabled by default): makes the rustls crate depend on the [`aws-lc-rs`] crate. -//! Use `rustls::crypto::aws_lc_rs::default_provider().install_default()` to -//! use it as the default `CryptoProvider`, or provide it explicitly -//! when making a `ClientConfig` or `ServerConfig`. -//! -//! Note that aws-lc-rs has additional build-time dependencies like cmake. -//! See [the documentation](https://aws.github.io/aws-lc-rs/requirements/index.html) for details. -//! -//! - `ring`: makes the rustls crate depend on the *ring* crate for cryptography. -//! Use `rustls::crypto::ring::default_provider().install_default()` to -//! use it as the default `CryptoProvider`, or provide it explicitly -//! when making a `ClientConfig` or `ServerConfig`. -//! -//! - `fips`: enable support for FIPS140-3-approved cryptography, via the [`aws-lc-rs`] crate. -//! This feature enables the `aws_lc_rs` crate feature, which makes the rustls crate depend -//! on [aws-lc-rs](https://github.com/aws/aws-lc-rs). It also changes the default -//! for [`ServerConfig::require_ems`] and [`ClientConfig::require_ems`]. -//! -//! See [manual::_06_fips] for more details. -//! -//! - `prefer-post-quantum` (enabled by default): for the [`aws-lc-rs`]-backed provider, -//! prioritizes post-quantum secure key exchange by default (using X25519MLKEM768). -//! This feature merely alters the order of `rustls::crypto::aws_lc_rs::DEFAULT_KX_GROUPS`. -//! See [the manual][x25519mlkem768-manual] for more details. -//! -//! - `custom-provider`: disables implicit use of built-in providers (`aws-lc-rs` or `ring`). This forces -//! applications to manually install one, for instance, when using a custom `CryptoProvider`. -//! -//! - `tls12` (enabled by default): enable support for TLS version 1.2. Note that, due to the -//! additive nature of Cargo features and because it is enabled by default, other crates -//! in your dependency graph could re-enable it for your application. If you want to disable -//! TLS 1.2 for security reasons, consider explicitly enabling TLS 1.3 only in the config -//! builder API. -//! -//! - `logging` (enabled by default): make the rustls crate depend on the `log` crate. -//! rustls outputs interesting protocol-level messages at `trace!` and `debug!` level, -//! and protocol-level errors at `warn!` and `error!` level. The log messages do not -//! contain secret key data, and so are safe to archive without affecting session security. -//! -//! - `read_buf`: when building with Rust Nightly, adds support for the unstable -//! `std::io::ReadBuf` and related APIs. This reduces costs from initializing -//! buffers. Will do nothing on non-Nightly releases. -//! -//! - `brotli`: uses the `brotli` crate for RFC8879 certificate compression support. -//! -//! - `zlib`: uses the `zlib-rs` crate for RFC8879 certificate compression support. -//! -//! [x25519mlkem768-manual]: manual::_05_defaults#about-the-post-quantum-secure-key-exchange-x25519mlkem768 - -// Require docs for public APIs, deny unsafe code, etc. -#![forbid(unsafe_code, unused_must_use)] -#![cfg_attr(not(any(read_buf, bench, coverage_nightly)), forbid(unstable_features))] -#![warn( - clippy::alloc_instead_of_core, - clippy::manual_let_else, - clippy::std_instead_of_core, - clippy::use_self, - clippy::upper_case_acronyms, - elided_lifetimes_in_paths, - missing_docs, - trivial_casts, - trivial_numeric_casts, - unreachable_pub, - unused_import_braces, - unused_extern_crates, - unused_qualifications -)] -// Relax these clippy lints: -// - ptr_arg: this triggers on references to type aliases that are Vec -// underneath. -// - too_many_arguments: some things just need a lot of state, wrapping it -// doesn't necessarily make it easier to follow what's going on -// - new_ret_no_self: we sometimes return `Arc<Self>`, which seems fine -// - single_component_path_imports: our top-level `use log` import causes -// a false positive, https://github.com/rust-lang/rust-clippy/issues/5210 -// - new_without_default: for internal constructors, the indirection is not -// helpful -#![allow( - clippy::too_many_arguments, - clippy::new_ret_no_self, - clippy::ptr_arg, - clippy::single_component_path_imports, - clippy::new_without_default -)] -// Enable documentation for all features on docs.rs -#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -// Enable coverage() attr for nightly coverage builds, see -// <https://github.com/rust-lang/rust/issues/84605> -// (`coverage_nightly` is a cfg set by `cargo-llvm-cov`) -#![cfg_attr(coverage_nightly, feature(coverage_attribute))] -// XXX: Because of https://github.com/rust-lang/rust/issues/54726, we cannot -// write `#![rustversion::attr(nightly, feature(read_buf))]` here. Instead, -// build.rs set `read_buf` for (only) Rust Nightly to get the same effect. -// -// All the other conditional logic in the crate could use -// `#[rustversion::nightly]` instead of `#[cfg(read_buf)]`; `#[cfg(read_buf)]` -// is used to avoid needing `rustversion` to be compiled twice during -// cross-compiling. -#![cfg_attr(read_buf, feature(read_buf))] -#![cfg_attr(read_buf, feature(core_io_borrowed_buf))] -#![cfg_attr(bench, feature(test))] -#![no_std] - -extern crate alloc; -// This `extern crate` plus the `#![no_std]` attribute changes the default prelude from -// `std::prelude` to `core::prelude`. That forces one to _explicitly_ import (`use`) everything that -// is in `std::prelude` but not in `core::prelude`. This helps maintain no-std support as even -// developers that are not interested in, or aware of, no-std support and / or that never run -// `cargo build --no-default-features` locally will get errors when they rely on `std::prelude` API. -#[cfg(any(feature = "std", test))] -extern crate std; - -#[cfg(doc)] -use crate::crypto::CryptoProvider; - -// Import `test` sysroot crate for `Bencher` definitions. -#[cfg(bench)] -#[allow(unused_extern_crates)] -extern crate test; - -// log for logging (optional). -#[cfg(feature = "logging")] -use log; - -#[cfg(not(feature = "logging"))] -mod log { - macro_rules! trace ( ($($tt:tt)*) => {{}} ); - macro_rules! debug ( ($($tt:tt)*) => {{}} ); - macro_rules! error ( ($($tt:tt)*) => {{}} ); - macro_rules! _warn ( ($($tt:tt)*) => {{}} ); - pub(crate) use {_warn as warn, debug, error, trace}; -} - -#[cfg(test)] -#[macro_use] -mod test_macros; - -/// This internal `sync` module aliases the `Arc` implementation to allow downstream forks -/// of rustls targeting architectures without atomic pointers to replace the implementation -/// with another implementation such as `portable_atomic_util::Arc` in one central location. -mod sync { - #[allow(clippy::disallowed_types)] - pub(crate) type Arc<T> = alloc::sync::Arc<T>; - #[allow(clippy::disallowed_types)] - pub(crate) type Weak<T> = alloc::sync::Weak<T>; -} - -#[macro_use] -mod msgs; -mod common_state; -pub mod compress; -mod conn; -/// Crypto provider interface. -pub mod crypto; -mod error; -mod hash_hs; -#[cfg(any(feature = "std", feature = "hashbrown"))] -mod limited_cache; -mod rand; -mod record_layer; -#[cfg(feature = "std")] -mod stream; -#[cfg(feature = "tls12")] -mod tls12; -mod tls13; -mod vecbuf; -mod verify; -#[cfg(test)] -mod verifybench; -mod x509; -#[macro_use] -mod check; -#[cfg(feature = "logging")] -mod bs_debug; -mod builder; -mod enums; -mod key_log; -#[cfg(feature = "std")] -mod key_log_file; -mod suites; -mod versions; -mod webpki; - -/// Internal classes that are used in integration tests. -/// The contents of this section DO NOT form part of the stable interface. -#[allow(missing_docs)] -#[doc(hidden)] -pub mod internal { - /// Low-level TLS message parsing and encoding functions. - pub mod msgs { - pub mod base { - pub use crate::msgs::base::{Payload, PayloadU16}; - } - pub mod codec { - pub use crate::msgs::codec::{Codec, Reader}; - } - pub mod enums { - pub use crate::msgs::enums::{ - AlertLevel, EchVersion, ExtensionType, HpkeAead, HpkeKdf, HpkeKem, - }; - } - pub mod fragmenter { - pub use crate::msgs::fragmenter::MessageFragmenter; - } - pub mod handshake { - pub use crate::msgs::handshake::{ - EchConfigContents, EchConfigPayload, HpkeKeyConfig, HpkeSymmetricCipherSuite, - }; - } - pub mod message { - pub use crate::msgs::message::{ - Message, MessagePayload, OutboundOpaqueMessage, PlainMessage, - }; - } - pub mod persist { - pub use crate::msgs::persist::ServerSessionValue; - } - } - - pub use crate::tls13::key_schedule::{derive_traffic_iv, derive_traffic_key}; - - pub mod fuzzing { - pub use crate::msgs::deframer::fuzz_deframer; - } -} - -/// Unbuffered connection API -/// -/// This is an alternative to the [`crate::ConnectionCommon`] API that does not internally buffer -/// TLS nor plaintext data. Instead those buffers are managed by the API user so they have -/// control over when and how to allocate, resize and dispose of them. -/// -/// This API is lower level than the `ConnectionCommon` API and is built around a state machine -/// interface where the API user must handle each state to advance and complete the -/// handshake process. -/// -/// Like the `ConnectionCommon` API, no IO happens internally so all IO must be handled by the API -/// user. Unlike the `ConnectionCommon` API, this API does not make use of the [`std::io::Read`] and -/// [`std::io::Write`] traits so it's usable in no-std context. -/// -/// The entry points into this API are [`crate::client::UnbufferedClientConnection::new`], -/// [`crate::server::UnbufferedServerConnection::new`] and -/// [`unbuffered::UnbufferedConnectionCommon::process_tls_records`]. The state machine API is -/// documented in [`unbuffered::ConnectionState`]. -/// -/// # Examples -/// -/// [`unbuffered-client`] and [`unbuffered-server`] are examples that fully exercise the API in -/// std, non-async context. -/// -/// [`unbuffered-client`]: https://github.com/rustls/rustls/blob/main/examples/src/bin/unbuffered-client.rs -/// [`unbuffered-server`]: https://github.com/rustls/rustls/blob/main/examples/src/bin/unbuffered-server.rs -pub mod unbuffered { - pub use crate::conn::UnbufferedConnectionCommon; - pub use crate::conn::unbuffered::{ - AppDataRecord, ConnectionState, EncodeError, EncodeTlsData, EncryptError, - InsufficientSizeError, ReadEarlyData, ReadTraffic, TransmitTlsData, UnbufferedStatus, - WriteTraffic, - }; -} - -// The public interface is: -pub use crate::builder::{ConfigBuilder, ConfigSide, WantsVerifier, WantsVersions}; -pub use crate::common_state::{CommonState, HandshakeKind, IoState, Side}; -#[cfg(feature = "std")] -pub use crate::conn::{Connection, Reader, Writer}; -pub use crate::conn::{ConnectionCommon, SideData, kernel}; -pub use crate::enums::{ - AlertDescription, CertificateCompressionAlgorithm, CipherSuite, ContentType, HandshakeType, - ProtocolVersion, SignatureAlgorithm, SignatureScheme, -}; -pub use crate::error::{ - CertRevocationListError, CertificateError, EncryptedClientHelloError, Error, - ExtendedKeyPurpose, InconsistentKeys, InvalidMessage, OtherError, PeerIncompatible, - PeerMisbehaved, -}; -pub use crate::key_log::{KeyLog, NoKeyLog}; -#[cfg(feature = "std")] -pub use crate::key_log_file::KeyLogFile; -pub use crate::msgs::enums::NamedGroup; -pub use crate::msgs::ffdhe_groups; -pub use crate::msgs::handshake::DistinguishedName; -#[cfg(feature = "std")] -pub use crate::stream::{Stream, StreamOwned}; -pub use crate::suites::{ - CipherSuiteCommon, ConnectionTrafficSecrets, ExtractedSecrets, SupportedCipherSuite, -}; -#[cfg(feature = "std")] -pub use crate::ticketer::TicketRotator; -#[cfg(any(feature = "std", feature = "hashbrown"))] // < XXX: incorrect feature gate -pub use crate::ticketer::TicketSwitcher; -#[cfg(feature = "tls12")] -pub use crate::tls12::Tls12CipherSuite; -pub use crate::tls13::Tls13CipherSuite; -pub use crate::verify::DigitallySignedStruct; -pub use crate::versions::{ALL_VERSIONS, DEFAULT_VERSIONS, SupportedProtocolVersion}; -pub use crate::webpki::RootCertStore; - -/// Items for use in a client. -pub mod client { - pub(super) mod builder; - mod client_conn; - mod common; - mod ech; - pub(super) mod handy; - mod hs; - #[cfg(test)] - mod test; - #[cfg(feature = "tls12")] - mod tls12; - mod tls13; - - pub use builder::WantsClientCert; - pub use client_conn::{ - ClientConfig, ClientConnectionData, ClientSessionStore, EarlyDataError, ResolvesClientCert, - Resumption, Tls12Resumption, UnbufferedClientConnection, - }; - #[cfg(feature = "std")] - pub use client_conn::{ClientConnection, WriteEarlyData}; - pub use ech::{EchConfig, EchGreaseConfig, EchMode, EchStatus}; - pub use handy::AlwaysResolvesClientRawPublicKeys; - #[cfg(any(feature = "std", feature = "hashbrown"))] - pub use handy::ClientSessionMemoryCache; - - /// Dangerous configuration that should be audited and used with extreme care. - pub mod danger { - pub use super::builder::danger::DangerousClientConfigBuilder; - pub use super::client_conn::danger::DangerousClientConfig; - pub use crate::verify::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier}; - } - - pub use crate::msgs::persist::{Tls12ClientSessionValue, Tls13ClientSessionValue}; - pub use crate::webpki::{ - ServerCertVerifierBuilder, VerifierBuilderError, WebPkiServerVerifier, - verify_server_cert_signed_by_trust_anchor, verify_server_name, - }; -} - -pub use client::ClientConfig; -#[cfg(feature = "std")] -pub use client::ClientConnection; - -/// Items for use in a server. -pub mod server { - pub(crate) mod builder; - mod common; - pub(crate) mod handy; - mod hs; - mod server_conn; - #[cfg(test)] - mod test; - #[cfg(feature = "tls12")] - mod tls12; - mod tls13; - - pub use builder::WantsServerCert; - #[cfg(any(feature = "std", feature = "hashbrown"))] - pub use handy::ResolvesServerCertUsingSni; - #[cfg(any(feature = "std", feature = "hashbrown"))] - pub use handy::ServerSessionMemoryCache; - pub use handy::{AlwaysResolvesServerRawPublicKeys, NoServerSessionStorage}; - pub use server_conn::{ - Accepted, ClientHello, ProducesTickets, ResolvesServerCert, ServerConfig, - ServerConnectionData, StoresServerSessions, UnbufferedServerConnection, - }; - #[cfg(feature = "std")] - pub use server_conn::{AcceptedAlert, Acceptor, ReadEarlyData, ServerConnection}; - - pub use crate::enums::CertificateType; - pub use crate::verify::NoClientAuth; - pub use crate::webpki::{ - ClientCertVerifierBuilder, ParsedCertificate, VerifierBuilderError, WebPkiClientVerifier, - }; - - /// Dangerous configuration that should be audited and used with extreme care. - pub mod danger { - pub use crate::verify::{ClientCertVerified, ClientCertVerifier}; - } -} - -pub use server::ServerConfig; -#[cfg(feature = "std")] -pub use server::ServerConnection; - -/// All defined protocol versions appear in this module. -/// -/// ALL_VERSIONS is a provided as an array of all of these values. -pub mod version { - #[cfg(feature = "tls12")] - pub use crate::versions::TLS12; - pub use crate::versions::TLS13; -} - -/// Re-exports the contents of the [rustls-pki-types](https://docs.rs/rustls-pki-types) crate for easy access -pub mod pki_types { - #[doc(no_inline)] - pub use pki_types::*; -} - -/// Message signing interfaces. -pub mod sign { - pub use crate::crypto::signer::{CertifiedKey, Signer, SigningKey, SingleCertAndKey}; -} - -/// APIs for implementing QUIC TLS -pub mod quic; - -#[cfg(any(feature = "std", feature = "hashbrown"))] // < XXX: incorrect feature gate -/// APIs for implementing TLS tickets -pub mod ticketer; - -/// This is the rustls manual. -pub mod manual; - -pub mod time_provider; - -/// APIs abstracting over locking primitives. -pub mod lock; - -/// Polyfills for features that are not yet stabilized or available with current MSRV. -pub(crate) mod polyfill; - -#[cfg(any(feature = "std", feature = "hashbrown"))] -mod hash_map { - #[cfg(feature = "std")] - pub(crate) use std::collections::HashMap; - #[cfg(feature = "std")] - pub(crate) use std::collections::hash_map::Entry; - - #[cfg(all(not(feature = "std"), feature = "hashbrown"))] - pub(crate) use hashbrown::HashMap; - #[cfg(all(not(feature = "std"), feature = "hashbrown"))] - pub(crate) use hashbrown::hash_map::Entry; -} diff --git a/vendor/rustls/src/limited_cache.rs b/vendor/rustls/src/limited_cache.rs deleted file mode 100644 index 6ae8bf94..00000000 --- a/vendor/rustls/src/limited_cache.rs +++ /dev/null @@ -1,250 +0,0 @@ -use alloc::collections::VecDeque; -use core::borrow::Borrow; -use core::hash::Hash; - -use crate::hash_map::{Entry, HashMap}; - -/// A HashMap-alike, which never gets larger than a specified -/// capacity, and evicts the oldest insertion to maintain this. -/// -/// The requested capacity may be rounded up by the underlying -/// collections. This implementation uses all the allocated -/// storage. -/// -/// This is inefficient: it stores keys twice. -pub(crate) struct LimitedCache<K: Clone + Hash + Eq, V> { - map: HashMap<K, V>, - - // first item is the oldest key - oldest: VecDeque<K>, -} - -impl<K, V> LimitedCache<K, V> -where - K: Eq + Hash + Clone + core::fmt::Debug, - V: Default, -{ - pub(crate) fn get_or_insert_default_and_edit(&mut self, k: K, edit: impl FnOnce(&mut V)) { - let inserted_new_item = match self.map.entry(k) { - Entry::Occupied(value) => { - edit(value.into_mut()); - false - } - entry @ Entry::Vacant(_) => { - self.oldest - .push_back(entry.key().clone()); - edit(entry.or_insert_with(V::default)); - true - } - }; - - // ensure next insertion does not require a realloc - if inserted_new_item && self.oldest.capacity() == self.oldest.len() { - if let Some(oldest_key) = self.oldest.pop_front() { - self.map.remove(&oldest_key); - } - } - } - - pub(crate) fn get_mut<Q: Hash + Eq + ?Sized>(&mut self, k: &Q) -> Option<&mut V> - where - K: Borrow<Q>, - { - self.map.get_mut(k) - } -} - -impl<K, V> LimitedCache<K, V> -where - K: Eq + Hash + Clone + core::fmt::Debug, - V: Default, -{ - /// Create a new LimitedCache with the given rough capacity. - pub(crate) fn new(capacity_order_of_magnitude: usize) -> Self { - Self { - map: HashMap::with_capacity(capacity_order_of_magnitude), - oldest: VecDeque::with_capacity(capacity_order_of_magnitude), - } - } - - pub(crate) fn insert(&mut self, k: K, v: V) { - let inserted_new_item = match self.map.entry(k) { - Entry::Occupied(mut old) => { - // Note: does not freshen entry in `oldest` - old.insert(v); - false - } - - entry @ Entry::Vacant(_) => { - self.oldest - .push_back(entry.key().clone()); - entry.or_insert(v); - true - } - }; - - // ensure next insertion does not require a realloc - if inserted_new_item && self.oldest.capacity() == self.oldest.len() { - if let Some(oldest_key) = self.oldest.pop_front() { - self.map.remove(&oldest_key); - } - } - } - - pub(crate) fn get<Q: Hash + Eq + ?Sized>(&self, k: &Q) -> Option<&V> - where - K: Borrow<Q>, - { - self.map.get(k) - } - - pub(crate) fn remove<Q: Hash + Eq + ?Sized>(&mut self, k: &Q) -> Option<V> - where - K: Borrow<Q>, - { - let value = self.map.remove(k)?; - - // O(N) search, followed by O(N) removal - if let Some(index) = self - .oldest - .iter() - .position(|item| item.borrow() == k) - { - self.oldest.remove(index); - } - - Some(value) - } -} - -#[cfg(test)] -mod tests { - use std::prelude::v1::*; - - type Test = super::LimitedCache<String, usize>; - - #[test] - fn test_updates_existing_item() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("abc".into(), 2); - assert_eq!(t.get("abc"), Some(&2)); - } - - #[test] - fn test_evicts_oldest_item() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - t.insert("ghi".into(), 3); - - assert_eq!(t.get("abc"), None); - assert_eq!(t.get("def"), Some(&2)); - assert_eq!(t.get("ghi"), Some(&3)); - } - - #[test] - fn test_evicts_second_oldest_item_if_first_removed() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - - assert_eq!(t.remove("abc"), Some(1)); - - t.insert("ghi".into(), 3); - t.insert("jkl".into(), 4); - - assert_eq!(t.get("abc"), None); - assert_eq!(t.get("def"), None); - assert_eq!(t.get("ghi"), Some(&3)); - assert_eq!(t.get("jkl"), Some(&4)); - } - - #[test] - fn test_evicts_after_second_oldest_item_removed() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - - assert_eq!(t.remove("def"), Some(2)); - assert_eq!(t.get("abc"), Some(&1)); - - t.insert("ghi".into(), 3); - t.insert("jkl".into(), 4); - - assert_eq!(t.get("abc"), None); - assert_eq!(t.get("def"), None); - assert_eq!(t.get("ghi"), Some(&3)); - assert_eq!(t.get("jkl"), Some(&4)); - } - - #[test] - fn test_removes_all_items() { - let mut t = Test::new(3); - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - - assert_eq!(t.remove("def"), Some(2)); - assert_eq!(t.remove("abc"), Some(1)); - - t.insert("ghi".into(), 3); - t.insert("jkl".into(), 4); - t.insert("mno".into(), 5); - - assert_eq!(t.get("abc"), None); - assert_eq!(t.get("def"), None); - assert_eq!(t.get("ghi"), None); - assert_eq!(t.get("jkl"), Some(&4)); - assert_eq!(t.get("mno"), Some(&5)); - } - - #[test] - fn test_inserts_many_items() { - let mut t = Test::new(3); - - for _ in 0..10000 { - t.insert("abc".into(), 1); - t.insert("def".into(), 2); - t.insert("ghi".into(), 3); - } - } - - #[test] - fn test_get_or_insert_default_and_edit_evicts_old_items_to_meet_capacity() { - let mut t = Test::new(3); - - t.get_or_insert_default_and_edit("abc".into(), |v| *v += 1); - t.get_or_insert_default_and_edit("def".into(), |v| *v += 2); - - // evicts "abc" - t.get_or_insert_default_and_edit("ghi".into(), |v| *v += 3); - assert_eq!(t.get("abc"), None); - - // evicts "def" - t.get_or_insert_default_and_edit("jkl".into(), |v| *v += 4); - assert_eq!(t.get("def"), None); - - // evicts "ghi" - t.get_or_insert_default_and_edit("abc".into(), |v| *v += 5); - assert_eq!(t.get("ghi"), None); - - // evicts "jkl" - t.get_or_insert_default_and_edit("def".into(), |v| *v += 6); - - assert_eq!(t.get("abc"), Some(&5)); - assert_eq!(t.get("def"), Some(&6)); - assert_eq!(t.get("ghi"), None); - assert_eq!(t.get("jkl"), None); - } - - #[test] - fn test_get_or_insert_default_and_edit_edits_existing_item() { - let mut t = Test::new(3); - - t.get_or_insert_default_and_edit("abc".into(), |v| *v += 1); - t.get_or_insert_default_and_edit("abc".into(), |v| *v += 2); - t.get_or_insert_default_and_edit("abc".into(), |v| *v += 3); - - assert_eq!(t.get("abc"), Some(&6)); - } -} diff --git a/vendor/rustls/src/lock.rs b/vendor/rustls/src/lock.rs deleted file mode 100644 index b632b2c5..00000000 --- a/vendor/rustls/src/lock.rs +++ /dev/null @@ -1,89 +0,0 @@ -#[cfg(not(feature = "std"))] -pub use no_std_lock::*; -#[cfg(feature = "std")] -pub use std_lock::*; - -#[cfg(feature = "std")] -mod std_lock { - use std::sync::Mutex as StdMutex; - pub use std::sync::MutexGuard; - - /// A wrapper around [`std::sync::Mutex`]. - #[derive(Debug)] - pub struct Mutex<T> { - inner: StdMutex<T>, - } - - impl<T> Mutex<T> { - /// Creates a new mutex in an unlocked state ready for use. - pub fn new(data: T) -> Self { - Self { - inner: StdMutex::new(data), - } - } - - /// Acquires the mutex, blocking the current thread until it is able to do so. - /// - /// This will return `None` in the case the mutex is poisoned. - #[inline] - pub fn lock(&self) -> Option<MutexGuard<'_, T>> { - self.inner.lock().ok() - } - } -} - -#[cfg(not(feature = "std"))] -mod no_std_lock { - use alloc::boxed::Box; - use core::fmt::Debug; - use core::ops::DerefMut; - - use crate::sync::Arc; - - /// A no-std compatible wrapper around [`Lock`]. - #[derive(Debug)] - pub struct Mutex<T> { - inner: Arc<dyn Lock<T>>, - } - - impl<T: Send + 'static> Mutex<T> { - /// Creates a new mutex in an unlocked state ready for use. - pub fn new<M>(val: T) -> Self - where - M: MakeMutex, - T: Send + 'static, - { - Self { - inner: M::make_mutex(val), - } - } - - /// Acquires the mutex, blocking the current thread until it is able to do so. - /// - /// This will return `None` in the case the mutex is poisoned. - #[inline] - pub fn lock(&self) -> Option<MutexGuard<'_, T>> { - self.inner.lock().ok() - } - } - - /// A lock protecting shared data. - pub trait Lock<T>: Debug + Send + Sync { - /// Acquire the lock. - fn lock(&self) -> Result<MutexGuard<'_, T>, Poisoned>; - } - - /// A lock builder. - pub trait MakeMutex { - /// Create a new mutex. - fn make_mutex<T>(value: T) -> Arc<dyn Lock<T>> - where - T: Send + 'static; - } - - /// A no-std compatible mutex guard. - pub type MutexGuard<'a, T> = Box<dyn DerefMut<Target = T> + 'a>; - - /// A marker type used to indicate `Lock::lock` failed due to a poisoned lock. - pub struct Poisoned; -} diff --git a/vendor/rustls/src/manual/defaults.rs b/vendor/rustls/src/manual/defaults.rs deleted file mode 100644 index f6f70dc0..00000000 --- a/vendor/rustls/src/manual/defaults.rs +++ /dev/null @@ -1,71 +0,0 @@ -/*! - -## Rationale for defaults - -### Why is AES-256 preferred over AES-128? - -This is a trade-off between: - -1. classical security level: searching a 2^128 key space is as implausible as 2^256. -2. post-quantum security level: the difference is more meaningful, and AES-256 seems like the conservative choice. -3. performance: AES-256 is around 40% slower than AES-128, though hardware acceleration typically narrows this gap. - -The choice is frankly quite marginal. - -### Why is AES-GCM preferred over chacha20-poly1305? - -Hardware support for accelerating AES-GCM is widespread, and hardware-accelerated AES-GCM -is quicker than un-accelerated chacha20-poly1305. - -However, if you know your application will run on a platform without that, you should -_definitely_ change the default order to prefer chacha20-poly1305: both the performance and -the implementation security will be improved. We think this is an uncommon case. - -### Why is x25519 preferred for key exchange over nistp256? - -Both provide roughly the same classical security level, but x25519 has better performance and -it's _much_ more likely that both peers will have good quality implementations. - -### About the post-quantum-secure key exchange `X25519MLKEM768` - -[`X25519MLKEM768`] -- a hybrid[^1], post-quantum-secure[^2] key exchange -algorithm -- is available when using the aws-lc-rs provider. - -The `prefer-post-quantum` crate feature makes `X25519MLKEM768` the -highest-priority key exchange algorithm. Otherwise, it is available but -not highest-priority. - -[X25519MLKEM768] is pre-standardization, but is now widely deployed, -for example, by [Chrome] and [Cloudflare]. - -You may see unexpected connection failures (such as [tldr.fail]) --- [please report these to us][interop-bug]. - -The two components of this key exchange are well regarded: -X25519 alone is already used by default by rustls, and tends to have -higher quality implementations than other elliptic curves. -ML-KEM-768 was standardized by NIST in [FIPS203]. - -[`MLKEM768`] is available separately, but is not currently enabled -by default out of conservatism. - -[^1]: meaning: a construction that runs a classical and post-quantum - key exchange, and uses the output of both together. This is a hedge - against the post-quantum half being broken. - -[^2]: a "post-quantum-secure" algorithm is one posited to be invulnerable - to attack using a cryptographically-relevant quantum computer. In contrast, - classical algorithms would be broken by such a computer. Note that such computers - do not currently exist, and may never exist, but current traffic could be captured - now and attacked later. - -[X25519MLKEM768]: <https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/> -[`X25519MLKEM768`]: crate::crypto::aws_lc_rs::kx_group::X25519MLKEM768 -[`MLKEM768`]: crate::crypto::aws_lc_rs::kx_group::MLKEM768 -[FIPS203]: <https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf> -[Chrome]: <https://security.googleblog.com/2024/09/a-new-path-for-kyber-on-web.html> -[Cloudflare]: <https://blog.cloudflare.com/pq-2024/#ml-kem-768-and-x25519> -[interop-bug]: <https://github.com/rustls/rustls/issues/new?assignees=&labels=&projects=&template=bug_report.md&title=> -[tldr.fail]: <https://tldr.fail/> - -*/ diff --git a/vendor/rustls/src/manual/features.rs b/vendor/rustls/src/manual/features.rs deleted file mode 100644 index 69daf48a..00000000 --- a/vendor/rustls/src/manual/features.rs +++ /dev/null @@ -1,100 +0,0 @@ -/*! - -The below list reflects the support provided with the default crate features. -Items marked with an asterisk `*` can be extended or altered via public -APIs ([`CryptoProvider`] for example). - -[`CryptoProvider`]: crate::crypto::CryptoProvider - -## Current features - -* TLS1.2 and TLS1.3 -* ECDSA, Ed25519 or RSA server authentication by clients `*` -* ECDSA, Ed25519[^1] or RSA server authentication by servers `*` -* Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves `*` -* Post-quantum hybrid key exchange with [X25519MLKEM768](https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/) [^2] `*` -* AES128-GCM and AES256-GCM bulk encryption, with safe nonces `*` -* ChaCha20-Poly1305 bulk encryption ([RFC7905](https://tools.ietf.org/html/rfc7905)) `*` -* ALPN support -* SNI support -* Tunable fragment size to make TLS messages match size of underlying transport -* Optional use of vectored IO to minimise system calls -* TLS1.2 session resumption -* TLS1.2 resumption via tickets ([RFC5077](https://tools.ietf.org/html/rfc5077)) -* TLS1.3 resumption via tickets or session storage -* TLS1.3 0-RTT data -* Server and optional client authentication -* Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)) -* Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)) -* OCSP stapling by servers -* [RFC7250](https://tools.ietf.org/html/rfc7250) raw public keys for TLS1.3 -* [RFC8879](https://tools.ietf.org/html/rfc8879) certificate compression by clients - and servers `*` -* Client-side Encrypted client hello (ECH) - ([draft-ietf-tls-esni](https://datatracker.ietf.org/doc/draft-ietf-tls-esni/)). - -[^1]: Note that, at the time of writing, Ed25519 does not have wide support - in browsers. It is also not supported by the WebPKI, because the - CA/Browser Forum Baseline Requirements do not support it for publicly - trusted certificates. -[^2]: See [the documentation][crate::manual::_05_defaults#about-the-post-quantum-secure-key-exchange-x25519mlkem768] - -## Non-features - -For reasons explained in the other sections of this manual, rustls does not -and will not support: - -* SSL1, SSL2, SSL3, TLS1 or TLS1.1 -* RC4 -* DES or triple DES -* EXPORT ciphersuites -* MAC-then-encrypt ciphersuites -* Ciphersuites without forward secrecy -* Renegotiation -* Kerberos -* TLS 1.2 protocol compression -* Discrete-log Diffie-Hellman `*` -* Automatic protocol version downgrade -* Using CA certificates directly to authenticate a server/client (often called "self-signed - certificates"). _Rustls' default certificate verifier does not support using a trust anchor as - both a CA certificate and an end-entity certificate in order to limit complexity and risk in - path building. While dangerous, all authentication can be turned off if required -- - see the [example code](https://github.com/rustls/rustls/blob/v/0.23.23/examples/src/bin/tlsclient-mio.rs#L338)_ `*` - -### About "custom extensions" - -OpenSSL allows an application to add arbitrary TLS extensions (via -the `SSL_CTX_add_custom_ext` function and associated APIs). We don't -support this, with the following rationale: - -Such an API is limited to extensions that are quite narrow in scope: -they cannot change the meaning of standard messages, or introduce new -messages, or make any changes to the connection's cryptography. - -However, there is no reasonable way to technically limit that API to -that set of extensions. That makes the API pretty unsafe (in the -TLS and cryptography sense, not memory safety sense). This could -cause security or interop failures. - -Instead, we suggest that potential users of that API consider: - -- whether their use can fit in standard extensions such as ALPN, - or [ALPS][alps][^3]. -- if not, whether they can fit in a more general extension, and define - and standardize that in the [IETF TLSWG][tlswg]. - -Note the above is not a guarantee or offer that rustls will implement -any specific extensions that are standardized by the IETF TLSWG. -It is a non-goal of this project to implement absolutely everything. - -For experimentation and pre-standardization testing, we suggest -forking rustls. - -See also: [Go's position on such an API][golang]. - -[alps]: https://datatracker.ietf.org/doc/html/draft-vvv-tls-alps -[golang]: https://github.com/golang/go/issues/51497 -[tlswg]: https://datatracker.ietf.org/wg/tls/charter/ -[^3]: rustls does not currently implement ALPS, but it is something we - would consider once standardised and deployed. -*/ diff --git a/vendor/rustls/src/manual/fips.rs b/vendor/rustls/src/manual/fips.rs deleted file mode 100644 index 203a759e..00000000 --- a/vendor/rustls/src/manual/fips.rs +++ /dev/null @@ -1,62 +0,0 @@ -/*! # Using rustls with FIPS-approved cryptography - -To use FIPS-approved cryptography with rustls, you should take -these actions: - -## 1. Enable the `fips` crate feature for rustls. - -Use: - -```toml -rustls = { version = "0.23", features = [ "fips" ] } -``` - -## 2. Use the FIPS `CryptoProvider` - -This is [`default_fips_provider()`]: - -```rust,ignore -rustls::crypto::default_fips_provider() - .install_default() - .expect("default provider already set elsewhere"); -``` - -This snippet makes use of the process-default provider, -and that assumes all your uses of rustls use that. -See [`CryptoProvider`] documentation for other ways to -specify which `CryptoProvider` to use. - -## 3. Validate the FIPS status of your `ClientConfig`/`ServerConfig` at run-time - -See [`ClientConfig::fips()`] or [`ServerConfig::fips()`]. - -You could, for example: - -```rust,ignore -# let client_config = unreachable!(); -assert!(client_config.fips()); -``` - -But maybe your application has an error handling -or health-check strategy better than panicking. - -# aws-lc-rs FIPS approval status - -This is covered by [FIPS 140-3 certificate #4816][cert-4816]. -See [the security policy][policy-4816] for precisely which -environments and functions this certificate covers. - -Later releases of aws-lc-rs may be covered by later certificates, -or be pending certification. - -For the most up-to-date details see the latest documentation -for the [`aws-lc-fips-sys`] crate. - -[`aws-lc-fips-sys`]: https://crates.io/crates/aws-lc-fips-sys -[`default_fips_provider()`]: crate::crypto::default_fips_provider -[`CryptoProvider`]: crate::crypto::CryptoProvider -[`ClientConfig::fips()`]: crate::client::ClientConfig::fips -[`ServerConfig::fips()`]: crate::server::ServerConfig::fips -[cert-4816]: https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4816 -[policy-4816]: https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp4816.pdf -*/ diff --git a/vendor/rustls/src/manual/howto.rs b/vendor/rustls/src/manual/howto.rs deleted file mode 100644 index 6c00c695..00000000 --- a/vendor/rustls/src/manual/howto.rs +++ /dev/null @@ -1,124 +0,0 @@ -/*! # Customising private key usage - -By default rustls supports PKCS#8-format[^1] RSA or ECDSA keys, plus PKCS#1-format RSA keys. - -However, if your private key resides in a HSM, or in another process, or perhaps -another machine, rustls has some extension points to support this: - -The main trait you must implement is [`sign::SigningKey`][signing_key]. The primary method here -is [`choose_scheme()`][choose_scheme] where you are given a set of [`SignatureScheme`s][sig_scheme] the client says -it supports: you must choose one (or return `None` -- this aborts the handshake). Having -done that, you return an implementation of the [`sign::Signer`][signer] trait. -The [`sign()`][sign_method] performs the signature and returns it. - -(Unfortunately this is currently designed for keys with low latency access, like in a -PKCS#11 provider, Microsoft CryptoAPI, etc. so is blocking rather than asynchronous. -It's a TODO to make these and other extension points async.) - -Once you have these two pieces, configuring a server to use them involves, briefly: - -- packaging your [`sign::SigningKey`][signing_key] with the matching certificate chain into a [`sign::CertifiedKey`][certified_key] -- making a [`ResolvesServerCertUsingSni`][cert_using_sni] and feeding in your [`sign::CertifiedKey`][certified_key] for all SNI hostnames you want to use it for, -- setting that as your `ServerConfig`'s [`cert_resolver`][cert_resolver] - -For a complete example of implementing a custom [`sign::SigningKey`][signing_key] and -[`sign::Signer`][signer] see the [`signer` module in the `rustls-cng` crate][rustls-cng-signer]. - -[signing_key]: crate::crypto::signer::SigningKey -[choose_scheme]: crate::crypto::signer::SigningKey::choose_scheme -[sig_scheme]: crate::SignatureScheme -[signer]: crate::crypto::signer::Signer -[sign_method]: crate::crypto::signer::Signer::sign -[certified_key]: crate::crypto::signer::CertifiedKey -[cert_using_sni]: crate::server::ResolvesServerCertUsingSni -[cert_resolver]: crate::ServerConfig::cert_resolver -[rustls-cng-signer]: https://github.com/rustls/rustls-cng/blob/dev/src/signer.rs - -[^1]: For PKCS#8 it does not support password encryption -- there's not a meaningful threat - model addressed by this, and the encryption supported is typically extremely poor. - -# Unexpected EOF - -TLS has a `close_notify` mechanism to prevent truncation attacks[^2]. -According to the TLS RFCs, each party is required to send a `close_notify` message before -closing the write side of the connection. However, some implementations don't send it. -So long as the application layer protocol (for instance HTTP/2) has message length framing -and can reject truncated messages, this is not a security problem. - -Rustls treats an EOF without `close_notify` as an error of type `std::io::Error` with -`ErrorKind::UnexpectedEof`. In some situations it's appropriate for the application to handle -this error the same way it would handle a normal EOF (a read returning `Ok(0)`). In particular -if `UnexpectedEof` occurs on an idle connection it is appropriate to treat it the same way as a -clean shutdown. And if an application always uses messages with length framing (in other words, -messages are never delimited by the close of the TCP connection), it can unconditionally -ignore `UnexpectedEof` errors from rustls. - -[^2]: <https://datatracker.ietf.org/doc/html/rfc8446#section-6.1> - -# Debugging - -If you encounter a bug with Rustls it can be helpful to collect up as much diagnostic -information as possible. - -## Collecting logs - -If your bug reproduces with one of the [Rustls examples] you can use the -[`RUST_LOG`] environment variable to increase the log verbosity. If you're using -your own application, you may need to configure it with a logging backend -like `env_logger`. - -Consider reproducing your bug with `RUST_LOG=rustls=trace` and sharing the result -in a [GitHub gist]. - -[Rustls examples]: https://github.com/rustls/rustls/tree/main/examples -[`RUST_LOG`]: https://docs.rs/env_logger/latest/env_logger/#enabling-logging -[`env_logger`]: https://docs.rs/env_logger/ -[GitHub gist]: https://docs.github.com/en/get-started/writing-on-github/editing-and-sharing-content-with-gists/creating-gists - -## Taking a packet capture - -When logs aren't enough taking a packet capture ("pcap") is another helpful tool. -The details of how to accomplish this vary by operating system/context. - -### tcpdump - -As one example, on Linux using [`tcpdump`] is often easiest. - -If you know the IP address of the remote server your bug demonstrates with you -could take a short packet capture with this command (after replacing -`XX.XX.XX.XX` with the correct IP address): - -```bash -sudo tcpdump -i any tcp and dst host XX.XX.XX.XX -C5 -w rustls.pcap -``` - -The `-i any` captures on any network interface. The `tcp and dst host XX.XX.XX.XX` -portion target the capture to TCP traffic to the specified IP address. The `-C5` -argument limits the capture to at most 5MB. Lastly the `-w` argument writes the -capture to `rustls.pcap`. - -Another approach is to use `tcp and port XXXX` instead of `tcp and dst host XX.XX.XX.XX` -to capture all traffic to a specific port instead of a specific host server. - -[`tcpdump`]: https://www.redhat.com/en/blog/introduction-using-tcpdump-linux-command-line - -### SSLKEYLOGFILE - -If the bug you are reporting happens after data is encrypted you may also wish to -share the secret keys required to decrypt the post-handshake traffic. - -If you're using one of the [Rustls examples] you can set the `SSLKEYLOGFILE` environment -variable to a path where secrets will be written. E.g. `SSLKEYLOGFILE=rustls.pcap.keys`. - -If you're using your own application you may need to customize the Rustls `ClientConfig` -or `ServerConfig`'s `key_log` setting like the example applications do. - -With the file from `SSLKEYLOGFILE` it is possible to use [Wireshark] or another tool to -decrypt the post-handshake messages, following [these instructions][curl-sslkeylogfile]. - -Remember this allows plaintext decryption and should only be done in testing contexts -where no sensitive data (API keys, etc) are being shared. - -[Wireshark]: https://www.wireshark.org/download.html -[curl-sslkeylogfile]: https://everything.curl.dev/usingcurl/tls/sslkeylogfile.html -*/ diff --git a/vendor/rustls/src/manual/implvulns.rs b/vendor/rustls/src/manual/implvulns.rs deleted file mode 100644 index a073350c..00000000 --- a/vendor/rustls/src/manual/implvulns.rs +++ /dev/null @@ -1,104 +0,0 @@ -/*! # A review of TLS Implementation Vulnerabilities - -An important part of engineering involves studying and learning from the mistakes of the past. -It would be tremendously unfortunate to spend effort re-discovering and re-fixing the same -vulnerabilities that were discovered in the past. - -## Memory safety - -Being written entirely in the safe-subset of Rust immediately offers us freedom from the entire -class of memory safety vulnerabilities. There are too many to exhaustively list, and there will -certainly be more in the future. - -Examples: - -- Heartbleed [CVE-2014-0160](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-0160) (OpenSSL) -- Memory corruption in ASN.1 decoder [CVE-2016-2108](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2108) (OpenSSL) -- Buffer overflow in read_server_hello [CVE-2014-3466](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3466) (GnuTLS) - -## `goto fail` - -This is the name of a vulnerability in Apple Secure Transport [CVE-2014-1266](https://nvd.nist.gov/vuln/detail/CVE-2014-1266). -This boiled down to the following code, which validates the server's signature on the key exchange: - -```c - if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) - goto fail; - if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) - goto fail; -> goto fail; - if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) - goto fail; -``` - -The marked line was duplicated, likely accidentally during a merge. This meant -the remaining part of the function (including the actual signature validation) -was unconditionally skipped. - -Ultimately the one countermeasure to this type of bug is basic testing: that a -valid signature returns success, and that an invalid one does not. rustls -has such testing, but this is really table stakes for security code. - -Further than this, though, we could consider that the *lack* of an error from -this function is a poor indicator that the signature was valid. rustls, instead, -has zero-size and non-copyable types that indicate a particular signature validation -has been performed. These types can be thought of as *capabilities* originated only -by designated signature verification functions -- such functions can then be a focus -of manual code review. Like capabilities, values of these types are otherwise unforgeable, -and are communicable only by Rust's move semantics. - -Values of these types are threaded through the protocol state machine, leading to terminal -states that look like: - -```ignore -struct ExpectTraffic { - (...) - _cert_verified: verify::ServerCertVerified, - _sig_verified: verify::HandshakeSignatureValid, - _fin_verified: verify::FinishedMessageVerified, -} -``` - -Since this state requires a value of these types, it will be a compile-time error to -reach that state without performing the requisite security-critical operations. - -This approach is not infallible, but it has zero runtime cost. - -## State machine attacks: EarlyCCS and SMACK/SKIP/FREAK - -EarlyCCS [CVE-2014-0224](https://nvd.nist.gov/vuln/detail/CVE-2014-0224) was a vulnerability in OpenSSL -found in 2014. The TLS `ChangeCipherSpec` message would be processed at inappropriate times, leading -to data being encrypted with the wrong keys (specifically, keys which were not secret). This resulted -from OpenSSL taking a *reactive* strategy to incoming messages ("when I get a message X, I should do Y") -which allows it to diverge from the proper state machine under attacker control. - -[SMACK](https://mitls.org/pages/attacks/SMACK) is a similar suite of vulnerabilities found in JSSE, -CyaSSL, OpenSSL, Mono and axTLS. "SKIP-TLS" demonstrated that some implementations allowed handshake -messages (and in one case, the entire handshake!) to be skipped leading to breaks in security. "FREAK" -found that some implementations incorrectly allowed export-only state transitions (i.e., transitions that -were only valid when an export ciphersuite was in use). - -rustls represents its protocol state machine carefully to avoid these defects. We model the handshake, -CCS and application data subprotocols in the same single state machine. Each state in this machine is -represented with a single struct, and transitions are modelled as functions that consume the current state -plus one TLS message[^1] and return a struct representing the next state. These functions fully validate -the message type before further operations. - -A sample sequence for a full TLSv1.2 handshake by a client looks like: - -- `hs::ExpectServerHello` (Note: ClientHello is logically sent before this state); transition to `tls12::ExpectCertificate` -- `tls12::ExpectCertificate`; transition to `tls12::ExpectServerKX` -- `tls12::ExpectServerKX`; transition to `tls12::ExpectServerDoneOrCertReq` -- `tls12::ExpectServerDoneOrCertReq`; delegates to `tls12::ExpectCertificateRequest` or `tls12::ExpectServerDone` depending on incoming message. - - `tls12::ExpectServerDone`; transition to `tls12::ExpectCCS` -- `tls12::ExpectCCS`; transition to `tls12::ExpectFinished` -- `tls12::ExpectFinished`; transition to `tls12::ExpectTraffic` -- `tls12::ExpectTraffic`; terminal state; transitions to `tls12::ExpectTraffic` - -In the future we plan to formally prove that all possible transitions modelled in this system of types -are correct with respect to the standard(s). At the moment we rely merely on exhaustive testing. - -[^1]: a logical TLS message: post-decryption, post-fragmentation. - - -*/ diff --git a/vendor/rustls/src/manual/mod.rs b/vendor/rustls/src/manual/mod.rs deleted file mode 100644 index 0e4fddce..00000000 --- a/vendor/rustls/src/manual/mod.rs +++ /dev/null @@ -1,34 +0,0 @@ -/*! - -This documentation primarily aims to explain design decisions taken in rustls. - -It does this from a few aspects: how rustls attempts to avoid construction errors -that occurred in other TLS libraries, how rustls attempts to avoid past TLS -protocol vulnerabilities, and assorted advice for achieving common tasks with rustls. -*/ -#![allow(non_snake_case)] - -/// This section discusses vulnerabilities in other TLS implementations, theorising their -/// root cause and how we aim to avoid them in rustls. -#[path = "implvulns.rs"] -pub mod _01_impl_vulnerabilities; - -/// This section discusses vulnerabilities and design errors in the TLS protocol. -#[path = "tlsvulns.rs"] -pub mod _02_tls_vulnerabilities; - -/// This section collects together goal-oriented documentation. -#[path = "howto.rs"] -pub mod _03_howto; - -/// This section documents rustls itself: what protocol features are and are not implemented. -#[path = "features.rs"] -pub mod _04_features; - -/// This section provides rationale for the defaults in rustls. -#[path = "defaults.rs"] -pub mod _05_defaults; - -/// This section provides guidance on using rustls with FIPS-approved cryptography. -#[path = "fips.rs"] -pub mod _06_fips; diff --git a/vendor/rustls/src/manual/tlsvulns.rs b/vendor/rustls/src/manual/tlsvulns.rs deleted file mode 100644 index 6d2220e3..00000000 --- a/vendor/rustls/src/manual/tlsvulns.rs +++ /dev/null @@ -1,175 +0,0 @@ -/*! # A review of protocol vulnerabilities - -## CBC MAC-then-encrypt ciphersuites - -Back in 2000 [Bellare and Namprempre](https://eprint.iacr.org/2000/025) discussed how to make authenticated -encryption by composing separate encryption and authentication primitives. That paper included this table: - -| Composition Method | Privacy | | | Integrity | | -|--------------------|---------|-|-|-----------|-| -|| IND-CPA | IND-CCA | NM-CPA | INT-PTXT | INT-CTXT | -| Encrypt-and-MAC | insecure | insecure | insecure | secure | insecure | -| MAC-then-encrypt | secure | insecure | insecure | secure | insecure | -| Encrypt-then-MAC | secure | secure | secure | secure | secure | - -One may assume from this fairly clear result that encrypt-and-MAC and MAC-then-encrypt compositions would be quickly abandoned -in favour of the remaining proven-secure option. But that didn't happen, not in TLSv1.1 (2006) nor in TLSv1.2 (2008). Worse, -both RFCs included incorrect advice on countermeasures for implementers, suggesting that the flaw was "not believed to be large -enough to be exploitable". - -[Lucky 13](http://www.isg.rhul.ac.uk/tls/Lucky13.html) (2013) exploited this flaw and affected all implementations, including -those written [after discovery](https://aws.amazon.com/blogs/security/s2n-and-lucky-13/). OpenSSL even had a -[memory safety vulnerability in the fix for Lucky 13](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2107), which -gives a flavour of the kind of complexity required to remove the side channel. - -rustls does not implement CBC MAC-then-encrypt ciphersuites for these reasons. TLSv1.3 removed support for these -ciphersuites in 2018. - -There are some further rejected options worth mentioning: [RFC7366](https://tools.ietf.org/html/rfc7366) defines -Encrypt-then-MAC for TLS, but unfortunately cannot be negotiated without also supporting MAC-then-encrypt -(clients cannot express "I offer CBC, but only EtM and not MtE"). - -## RSA PKCS#1 encryption - -"RSA key exchange" in TLS involves the client choosing a large random value and encrypting it using the server's -public key. This has two overall problems: - -1. It provides no _forward secrecy_: later compromise of the server's private key breaks confidentiality of - *all* past sessions using that key. This is a crucial property in the presence of software that is often - [poor at keeping a secret](http://heartbleed.com/). -2. The padding used in practice in TLS ("PKCS#1", or fully "RSAES-PKCS1-v1_5") has been known to be broken since - [1998](http://archiv.infsec.ethz.ch/education/fs08/secsem/bleichenbacher98.pdf). - -In a similar pattern to the MAC-then-encrypt problem discussed above, TLSv1.0 (1999), TLSv1.1 (2006) and TLSv1.2 (2008) -continued to specify use of PKCS#1 encryption, again with incrementally more complex and incorrect advice on countermeasures. - -[ROBOT](https://robotattack.org/) (2018) showed that implementations were still vulnerable to these attacks twenty years later. -[The Marvin Attack](https://people.redhat.com/~hkario/marvin/) (2023) demonstrated the same a further five years later. - -rustls does not support RSA key exchange. TLSv1.3 also removed support. - -## BEAST - -[BEAST](https://vnhacker.blogspot.com/2011/09/beast.html) ([CVE-2011-3389](https://nvd.nist.gov/vuln/detail/CVE-2011-3389)) -was demonstrated in 2011 by Thai Duong and Juliano Rizzo, -and was another vulnerability in CBC-based ciphersuites in SSLv3.0 and TLSv1.0. CBC mode is vulnerable to adaptive -chosen-plaintext attacks if the IV is predictable. In the case of these protocol versions, the IV was the previous -block of ciphertext (as if the entire TLS session was one CBC ciphertext, albeit revealed incrementally). This was -obviously predictable, since it was published on the wire. - -OpenSSL contained a countermeasure for this problem from 2002 onwards: it encrypts an empty message before each real -one, so that the IV used in the real message is unpredictable. This was turned off by default due to bugs in IE6. - -TLSv1.1 fix this vulnerability, but not any of the other deficiencies of CBC mode (see above). - -rustls does not support these ciphersuites. - -## CRIME - -In 2002 [John Kelsey](https://www.iacr.org/cryptodb/archive/2002/FSE/3091/3091.pdf) discussed the length side channel -as applied to compression of combined secret and attacker-chosen strings. - -Compression continued to be an option in TLSv1.1 (2006) and in TLSv1.2 (2008). Support in libraries was widespread. - -[CRIME](https://en.wikipedia.org/wiki/CRIME) ([CVE-2012-4929](https://nvd.nist.gov/vuln/detail/CVE-2012-4929)) -was demonstrated in 2012, again by Thai Duong and Juliano Rizzo. It attacked several protocols offering transparent -compression of application data, allowing quick adaptive chosen-plaintext attacks against secret values like cookies. - -rustls does not implement compression. TLSv1.3 also removed support. - -## Logjam / FREAK - -Way back when SSL was first being born, circa 1995, the US government considered cryptography a munition requiring -export control. SSL contained specific ciphersuites with dramatically small key sizes that were not subject -to export control. These controls were dropped in 2000. - -Since the "export-grade" ciphersuites no longer fulfilled any purpose, and because they were actively harmful to users, -one may have expected software support to disappear quickly. This did not happen. - -In 2015 [the FREAK attack](https://mitls.org/pages/attacks/SMACK#freak) ([CVE-2015-0204](https://nvd.nist.gov/vuln/detail/CVE-2015-0204)) -and [the Logjam attack](https://weakdh.org/) ([CVE-2015-4000](https://nvd.nist.gov/vuln/detail/CVE-2015-4000)) both -demonstrated total breaks of security in the presence of servers that accepted export ciphersuites. FREAK factored -512-bit RSA keys, while Logjam optimised solving discrete logs in the 512-bit group used by many different servers. - -Naturally, rustls does not implement any of these ciphersuites. - -## SWEET32 - -Block ciphers are vulnerable to birthday attacks, where the probability of repeating a block increases dramatically -once a particular key has been used for many blocks. For block ciphers with 64-bit blocks, this becomes probable -once a given key encrypts the order of 32GB of data. - -[Sweet32](https://sweet32.info/) ([CVE-2016-2183](https://nvd.nist.gov/vuln/detail/CVE-2016-2183)) attacked this fact -in the context of TLS support for 3DES, breaking confidentiality by analysing a large amount of attacker-induced traffic -in one session. - -rustls does not support any 64-bit block ciphers. - -## DROWN - -[DROWN](https://drownattack.com/) ([CVE-2016-0800](https://nvd.nist.gov/vuln/detail/CVE-2016-0800)) is a cross-protocol -attack that breaks the security of TLSv1.2 and earlier (when used with RSA key exchange) by using SSLv2. It is required -that the server uses the same key for both protocol versions. - -rustls naturally does not support SSLv2, but most importantly does not support RSA key exchange for TLSv1.2. - -## Poodle - -[POODLE](https://cdn1.vox-cdn.com/uploads/chorus_asset/file/2354994/ssl-poodle.0.pdf) ([CVE-2014-3566](https://nvd.nist.gov/vuln/detail/CVE-2014-3566)) -is an attack against CBC mode ciphersuites in SSLv3. This was possible in most cases because some clients willingly -downgraded to SSLv3 after failed handshakes for later versions. - -rustls does not support CBC mode ciphersuites, or SSLv3. Note that rustls does not need to implement `TLS_FALLBACK_SCSV` -introduced as a countermeasure because it contains no ability to downgrade from TLS 1.2 to earlier protocol versions, -and TLS 1.3 has protocol-level downgrade protection based on the [ServerHello server random value](https://www.rfc-editor.org/rfc/rfc8446#section-4.1.3). - -## GCM nonces - -[RFC5288](https://tools.ietf.org/html/rfc5288) introduced GCM-based ciphersuites for use in TLS. Unfortunately -the design was poor; it reused design for an unrelated security setting proposed in RFC5116. - -GCM is a typical nonce-based AEAD: it requires a unique (but not necessarily unpredictable) 96-bit nonce for each encryption -with a given key. The design specified by RFC5288 left two-thirds of the nonce construction up to implementations: - -- wasting 8 bytes per TLS ciphertext, -- meaning correct operation cannot be tested for (e.g., in protocol-level test vectors). - -There were no trade-offs here: TLS has a 64-bit sequence number that is not allowed to wrap and would make an ideal nonce. - -As a result, a [2016 study](https://eprint.iacr.org/2016/475.pdf) found: - -- implementations from IBM, A10 and Citrix used randomly-chosen nonces, which are unlikely to be unique over long connections, -- an implementation from Radware used the same nonce for the first two messages. - -rustls uses a counter from a random starting point for GCM nonces. TLSv1.3 and the Chacha20-Poly1305 TLSv1.2 ciphersuite -standardise this method. - -## Renegotiation - -In 2009 Marsh Ray and Steve Dispensa [discovered](https://kryptera.se/Renegotiating%20TLS.pdf) that the renegotiation -feature of all versions of TLS allows a MitM to splice a request of their choice onto the front of the client's real HTTP -request. A countermeasure was proposed and widely implemented to bind renegotiations to their previous negotiations; -unfortunately this was insufficient. - -rustls does not support renegotiation in TLSv1.2. TLSv1.3 also no longer supports renegotiation. - -## 3SHAKE - -[3SHAKE](https://www.mitls.org/pages/attacks/3SHAKE) (2014) described a complex attack that broke the "Secure Renegotiation" extension -introduced as a countermeasure to the previous protocol flaw. - -rustls does not support renegotiation for TLSv1.2 connections, or RSA key exchange, and both are required for this attack -to work. rustls implements the "Extended Master Secret" (RFC7627) extension for TLSv1.2 which was standardised as a countermeasure. - -TLSv1.3 no longer supports renegotiation and RSA key exchange. It also effectively incorporates the improvements made in RFC7627. - -## KCI - -[This vulnerability](https://kcitls.org/) makes use of TLS ciphersuites (those offering static DH) which were standardised -yet not widely used. However, they were implemented by libraries, and as a result enabled for various clients. It coupled -this with misconfigured certificates (on services including facebook.com) which allowed their misuse to MitM connections. - -rustls does not support static DH/EC-DH ciphersuites. We assert that it is misissuance to sign an EC certificate -with the keyUsage extension allowing both signatures and key exchange. That it isn't is probably a failure -of CAB Forum baseline requirements. -*/ diff --git a/vendor/rustls/src/msgs/alert.rs b/vendor/rustls/src/msgs/alert.rs deleted file mode 100644 index e66f64cf..00000000 --- a/vendor/rustls/src/msgs/alert.rs +++ /dev/null @@ -1,26 +0,0 @@ -use alloc::vec::Vec; - -use crate::enums::AlertDescription; -use crate::error::InvalidMessage; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::AlertLevel; - -#[derive(Debug)] -pub struct AlertMessagePayload { - pub level: AlertLevel, - pub description: AlertDescription, -} - -impl Codec<'_> for AlertMessagePayload { - fn encode(&self, bytes: &mut Vec<u8>) { - self.level.encode(bytes); - self.description.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let level = AlertLevel::read(r)?; - let description = AlertDescription::read(r)?; - r.expect_empty("AlertMessagePayload") - .map(|_| Self { level, description }) - } -} diff --git a/vendor/rustls/src/msgs/base.rs b/vendor/rustls/src/msgs/base.rs deleted file mode 100644 index 4204714d..00000000 --- a/vendor/rustls/src/msgs/base.rs +++ /dev/null @@ -1,238 +0,0 @@ -use alloc::vec::Vec; -use core::fmt; -use core::marker::PhantomData; - -use pki_types::CertificateDer; -use zeroize::Zeroize; - -use crate::error::InvalidMessage; -use crate::msgs::codec; -use crate::msgs::codec::{Codec, Reader}; - -/// An externally length'd payload -#[derive(Clone, Eq, PartialEq)] -pub enum Payload<'a> { - Borrowed(&'a [u8]), - Owned(Vec<u8>), -} - -impl<'a> Codec<'a> for Payload<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - bytes.extend_from_slice(self.bytes()); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - Ok(Self::read(r)) - } -} - -impl<'a> Payload<'a> { - pub fn bytes(&self) -> &[u8] { - match self { - Self::Borrowed(bytes) => bytes, - Self::Owned(bytes) => bytes, - } - } - - pub fn into_owned(self) -> Payload<'static> { - Payload::Owned(self.into_vec()) - } - - pub fn into_vec(self) -> Vec<u8> { - match self { - Self::Borrowed(bytes) => bytes.to_vec(), - Self::Owned(bytes) => bytes, - } - } - - pub fn read(r: &mut Reader<'a>) -> Self { - Self::Borrowed(r.rest()) - } -} - -impl Payload<'static> { - pub fn new(bytes: impl Into<Vec<u8>>) -> Self { - Self::Owned(bytes.into()) - } - - pub fn empty() -> Self { - Self::Borrowed(&[]) - } -} - -impl<'a> Codec<'a> for CertificateDer<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - codec::u24(self.as_ref().len() as u32).encode(bytes); - bytes.extend(self.as_ref()); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let len = codec::u24::read(r)?.0 as usize; - let mut sub = r.sub(len)?; - let body = sub.rest(); - Ok(Self::from(body)) - } -} - -impl fmt::Debug for Payload<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex(f, self.bytes()) - } -} - -/// An arbitrary, unknown-content, u24-length-prefixed payload -#[derive(Clone, Eq, PartialEq)] -pub(crate) struct PayloadU24<'a>(pub(crate) Payload<'a>); - -impl PayloadU24<'_> { - pub(crate) fn into_owned(self) -> PayloadU24<'static> { - PayloadU24(self.0.into_owned()) - } -} - -impl<'a> Codec<'a> for PayloadU24<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - let inner = self.0.bytes(); - codec::u24(inner.len() as u32).encode(bytes); - bytes.extend_from_slice(inner); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let len = codec::u24::read(r)?.0 as usize; - let mut sub = r.sub(len)?; - Ok(Self(Payload::read(&mut sub))) - } -} - -impl fmt::Debug for PayloadU24<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -/// An arbitrary, unknown-content, u16-length-prefixed payload -/// -/// The `C` type parameter controls whether decoded values may -/// be empty. -#[derive(Clone, Eq, PartialEq)] -pub struct PayloadU16<C: Cardinality = MaybeEmpty>(pub(crate) Vec<u8>, PhantomData<C>); - -impl<C: Cardinality> PayloadU16<C> { - pub fn new(bytes: Vec<u8>) -> Self { - debug_assert!(bytes.len() >= C::MIN); - Self(bytes, PhantomData) - } -} - -impl PayloadU16<MaybeEmpty> { - pub(crate) fn empty() -> Self { - Self::new(Vec::new()) - } -} - -impl<C: Cardinality> Codec<'_> for PayloadU16<C> { - fn encode(&self, bytes: &mut Vec<u8>) { - debug_assert!(self.0.len() >= C::MIN); - (self.0.len() as u16).encode(bytes); - bytes.extend_from_slice(&self.0); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let len = u16::read(r)? as usize; - if len < C::MIN { - return Err(InvalidMessage::IllegalEmptyValue); - } - let mut sub = r.sub(len)?; - let body = sub.rest().to_vec(); - Ok(Self(body, PhantomData)) - } -} - -impl<C: Cardinality> fmt::Debug for PayloadU16<C> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex(f, &self.0) - } -} - -/// An arbitrary, unknown-content, u8-length-prefixed payload -/// -/// `C` controls the minimum length accepted when decoding. -#[derive(Clone, Eq, PartialEq)] -pub(crate) struct PayloadU8<C: Cardinality = MaybeEmpty>(pub(crate) Vec<u8>, PhantomData<C>); - -impl<C: Cardinality> PayloadU8<C> { - pub(crate) fn encode_slice(slice: &[u8], bytes: &mut Vec<u8>) { - (slice.len() as u8).encode(bytes); - bytes.extend_from_slice(slice); - } - - pub(crate) fn new(bytes: Vec<u8>) -> Self { - debug_assert!(bytes.len() >= C::MIN); - Self(bytes, PhantomData) - } -} - -impl PayloadU8<MaybeEmpty> { - pub(crate) fn empty() -> Self { - Self(Vec::new(), PhantomData) - } -} - -impl<C: Cardinality> Codec<'_> for PayloadU8<C> { - fn encode(&self, bytes: &mut Vec<u8>) { - debug_assert!(self.0.len() >= C::MIN); - (self.0.len() as u8).encode(bytes); - bytes.extend_from_slice(&self.0); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let len = u8::read(r)? as usize; - if len < C::MIN { - return Err(InvalidMessage::IllegalEmptyValue); - } - let mut sub = r.sub(len)?; - let body = sub.rest().to_vec(); - Ok(Self(body, PhantomData)) - } -} - -impl<C: Cardinality> Zeroize for PayloadU8<C> { - fn zeroize(&mut self) { - self.0.zeroize(); - } -} - -impl<C: Cardinality> fmt::Debug for PayloadU8<C> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - hex(f, &self.0) - } -} - -pub trait Cardinality: Clone + Eq + PartialEq { - const MIN: usize; -} - -#[derive(Clone, Eq, PartialEq)] -pub struct MaybeEmpty; - -impl Cardinality for MaybeEmpty { - const MIN: usize = 0; -} - -#[derive(Clone, Eq, PartialEq)] -pub struct NonEmpty; - -impl Cardinality for NonEmpty { - const MIN: usize = 1; -} - -// Format an iterator of u8 into a hex string -pub(super) fn hex<'a>( - f: &mut fmt::Formatter<'_>, - payload: impl IntoIterator<Item = &'a u8>, -) -> fmt::Result { - for b in payload { - write!(f, "{b:02x}")?; - } - Ok(()) -} diff --git a/vendor/rustls/src/msgs/ccs.rs b/vendor/rustls/src/msgs/ccs.rs deleted file mode 100644 index ac2c9e6a..00000000 --- a/vendor/rustls/src/msgs/ccs.rs +++ /dev/null @@ -1,23 +0,0 @@ -use alloc::vec::Vec; - -use crate::error::InvalidMessage; -use crate::msgs::codec::{Codec, Reader}; - -#[derive(Debug)] -pub struct ChangeCipherSpecPayload; - -impl Codec<'_> for ChangeCipherSpecPayload { - fn encode(&self, bytes: &mut Vec<u8>) { - 1u8.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let typ = u8::read(r)?; - if typ != 1 { - return Err(InvalidMessage::InvalidCcs); - } - - r.expect_empty("ChangeCipherSpecPayload") - .map(|_| Self {}) - } -} diff --git a/vendor/rustls/src/msgs/codec.rs b/vendor/rustls/src/msgs/codec.rs deleted file mode 100644 index bd62cd3a..00000000 --- a/vendor/rustls/src/msgs/codec.rs +++ /dev/null @@ -1,404 +0,0 @@ -use alloc::vec::Vec; -use core::fmt::Debug; -use core::marker::PhantomData; - -use crate::error::InvalidMessage; - -/// Wrapper over a slice of bytes that allows reading chunks from -/// with the current position state held using a cursor. -/// -/// A new reader for a sub section of the buffer can be created -/// using the `sub` function or a section of a certain length can -/// be obtained using the `take` function -pub struct Reader<'a> { - /// The underlying buffer storing the readers content - buffer: &'a [u8], - /// Stores the current reading position for the buffer - cursor: usize, -} - -impl<'a> Reader<'a> { - /// Creates a new Reader of the provided `bytes` slice with - /// the initial cursor position of zero. - pub fn init(bytes: &'a [u8]) -> Self { - Reader { - buffer: bytes, - cursor: 0, - } - } - - /// Attempts to create a new Reader on a sub section of this - /// readers bytes by taking a slice of the provided `length` - /// will return None if there is not enough bytes - pub fn sub(&mut self, length: usize) -> Result<Self, InvalidMessage> { - match self.take(length) { - Some(bytes) => Ok(Reader::init(bytes)), - None => Err(InvalidMessage::MessageTooShort), - } - } - - /// Borrows a slice of all the remaining bytes - /// that appear after the cursor position. - /// - /// Moves the cursor to the end of the buffer length. - pub fn rest(&mut self) -> &'a [u8] { - let rest = &self.buffer[self.cursor..]; - self.cursor = self.buffer.len(); - rest - } - - /// Attempts to borrow a slice of bytes from the current - /// cursor position of `length` if there is not enough - /// bytes remaining after the cursor to take the length - /// then None is returned instead. - pub fn take(&mut self, length: usize) -> Option<&'a [u8]> { - if self.left() < length { - return None; - } - let current = self.cursor; - self.cursor += length; - Some(&self.buffer[current..current + length]) - } - - /// Used to check whether the reader has any content left - /// after the cursor (cursor has not reached end of buffer) - pub fn any_left(&self) -> bool { - self.cursor < self.buffer.len() - } - - pub fn expect_empty(&self, name: &'static str) -> Result<(), InvalidMessage> { - match self.any_left() { - true => Err(InvalidMessage::TrailingData(name)), - false => Ok(()), - } - } - - /// Returns the cursor position which is also the number - /// of bytes that have been read from the buffer. - pub fn used(&self) -> usize { - self.cursor - } - - /// Returns the number of bytes that are still able to be - /// read (The number of remaining takes) - pub fn left(&self) -> usize { - self.buffer.len() - self.cursor - } -} - -/// Trait for implementing encoding and decoding functionality -/// on something. -pub trait Codec<'a>: Debug + Sized { - /// Function for encoding itself by appending itself to - /// the provided vec of bytes. - fn encode(&self, bytes: &mut Vec<u8>); - - /// Function for decoding itself from the provided reader - /// will return Some if the decoding was successful or - /// None if it was not. - fn read(_: &mut Reader<'a>) -> Result<Self, InvalidMessage>; - - /// Convenience function for encoding the implementation - /// into a vec and returning it - fn get_encoding(&self) -> Vec<u8> { - let mut bytes = Vec::new(); - self.encode(&mut bytes); - bytes - } - - /// Function for wrapping a call to the read function in - /// a Reader for the slice of bytes provided - /// - /// Returns `Err(InvalidMessage::ExcessData(_))` if - /// `Self::read` does not read the entirety of `bytes`. - fn read_bytes(bytes: &'a [u8]) -> Result<Self, InvalidMessage> { - let mut reader = Reader::init(bytes); - Self::read(&mut reader).and_then(|r| { - reader.expect_empty("read_bytes")?; - Ok(r) - }) - } -} - -impl Codec<'_> for u8 { - fn encode(&self, bytes: &mut Vec<u8>) { - bytes.push(*self); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - match r.take(1) { - Some(&[byte]) => Ok(byte), - _ => Err(InvalidMessage::MissingData("u8")), - } - } -} - -pub(crate) fn put_u16(v: u16, out: &mut [u8]) { - let out: &mut [u8; 2] = (&mut out[..2]).try_into().unwrap(); - *out = u16::to_be_bytes(v); -} - -impl Codec<'_> for u16 { - fn encode(&self, bytes: &mut Vec<u8>) { - let mut b16 = [0u8; 2]; - put_u16(*self, &mut b16); - bytes.extend_from_slice(&b16); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - match r.take(2) { - Some(&[b1, b2]) => Ok(Self::from_be_bytes([b1, b2])), - _ => Err(InvalidMessage::MissingData("u16")), - } - } -} - -// Make a distinct type for u24, even though it's a u32 underneath -#[allow(non_camel_case_types)] -#[derive(Debug, Copy, Clone)] -pub struct u24(pub u32); - -#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] -impl From<u24> for usize { - #[inline] - fn from(v: u24) -> Self { - v.0 as Self - } -} - -impl Codec<'_> for u24 { - fn encode(&self, bytes: &mut Vec<u8>) { - let be_bytes = u32::to_be_bytes(self.0); - bytes.extend_from_slice(&be_bytes[1..]); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - match r.take(3) { - Some(&[a, b, c]) => Ok(Self(u32::from_be_bytes([0, a, b, c]))), - _ => Err(InvalidMessage::MissingData("u24")), - } - } -} - -impl Codec<'_> for u32 { - fn encode(&self, bytes: &mut Vec<u8>) { - bytes.extend(Self::to_be_bytes(*self)); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - match r.take(4) { - Some(&[a, b, c, d]) => Ok(Self::from_be_bytes([a, b, c, d])), - _ => Err(InvalidMessage::MissingData("u32")), - } - } -} - -pub(crate) fn put_u64(v: u64, bytes: &mut [u8]) { - let bytes: &mut [u8; 8] = (&mut bytes[..8]).try_into().unwrap(); - *bytes = u64::to_be_bytes(v); -} - -impl Codec<'_> for u64 { - fn encode(&self, bytes: &mut Vec<u8>) { - let mut b64 = [0u8; 8]; - put_u64(*self, &mut b64); - bytes.extend_from_slice(&b64); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - match r.take(8) { - Some(&[a, b, c, d, e, f, g, h]) => Ok(Self::from_be_bytes([a, b, c, d, e, f, g, h])), - _ => Err(InvalidMessage::MissingData("u64")), - } - } -} - -/// Implement `Codec` for lists of elements that implement `TlsListElement`. -/// -/// `TlsListElement` provides the size of the length prefix for the list. -impl<'a, T: Codec<'a> + TlsListElement + Debug> Codec<'a> for Vec<T> { - fn encode(&self, bytes: &mut Vec<u8>) { - let nest = LengthPrefixedBuffer::new(T::SIZE_LEN, bytes); - - for i in self { - i.encode(nest.buf); - } - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let mut ret = Self::new(); - for item in TlsListIter::<T>::new(r)? { - ret.push(item?); - } - - Ok(ret) - } -} - -/// An iterator over a vector of `TlsListElements`. -/// -/// All uses _MUST_ exhaust the iterator, as errors may be delayed -/// until the last element. -pub(crate) struct TlsListIter<'a, T: Codec<'a> + TlsListElement + Debug> { - sub: Reader<'a>, - _t: PhantomData<T>, -} - -impl<'a, T: Codec<'a> + TlsListElement + Debug> TlsListIter<'a, T> { - pub(crate) fn new(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let len = T::SIZE_LEN.read(r)?; - let sub = r.sub(len)?; - Ok(Self { - sub, - _t: PhantomData, - }) - } -} - -impl<'a, T: Codec<'a> + TlsListElement + Debug> Iterator for TlsListIter<'a, T> { - type Item = Result<T, InvalidMessage>; - - fn next(&mut self) -> Option<Self::Item> { - match self.sub.any_left() { - true => Some(T::read(&mut self.sub)), - false => None, - } - } -} - -impl Codec<'_> for () { - fn encode(&self, _: &mut Vec<u8>) {} - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - r.expect_empty("Empty") - } -} - -/// A trait for types that can be encoded and decoded in a list. -/// -/// This trait is used to implement `Codec` for `Vec<T>`. Lists in the TLS wire format are -/// prefixed with a length, the size of which depends on the type of the list elements. -/// As such, the `Codec` implementation for `Vec<T>` requires an implementation of this trait -/// for its element type `T`. -pub(crate) trait TlsListElement { - const SIZE_LEN: ListLength; -} - -/// The length of the length prefix for a list. -/// -/// The types that appear in lists are limited to three kinds of length prefixes: -/// 1, 2, and 3 bytes. For the latter kind, we require a `TlsListElement` implementer -/// to specify a maximum length and error if the actual length is larger. -pub(crate) enum ListLength { - /// U8 but non-empty - NonZeroU8 { empty_error: InvalidMessage }, - - /// U16, perhaps empty - U16, - - /// U16 but non-empty - NonZeroU16 { empty_error: InvalidMessage }, - - /// U24 with imposed upper bound - U24 { max: usize, error: InvalidMessage }, -} - -impl ListLength { - pub(crate) fn read(&self, r: &mut Reader<'_>) -> Result<usize, InvalidMessage> { - Ok(match self { - Self::NonZeroU8 { empty_error } => match usize::from(u8::read(r)?) { - 0 => return Err(*empty_error), - len => len, - }, - Self::U16 => usize::from(u16::read(r)?), - Self::NonZeroU16 { empty_error } => match usize::from(u16::read(r)?) { - 0 => return Err(*empty_error), - len => len, - }, - Self::U24 { max, error } => match usize::from(u24::read(r)?) { - len if len > *max => return Err(*error), - len => len, - }, - }) - } -} - -/// Tracks encoding a length-delimited structure in a single pass. -pub(crate) struct LengthPrefixedBuffer<'a> { - pub(crate) buf: &'a mut Vec<u8>, - len_offset: usize, - size_len: ListLength, -} - -impl<'a> LengthPrefixedBuffer<'a> { - /// Inserts a dummy length into `buf`, and remembers where it went. - /// - /// After this, the body of the length-delimited structure should be appended to `LengthPrefixedBuffer::buf`. - /// The length header is corrected in `LengthPrefixedBuffer::drop`. - pub(crate) fn new(size_len: ListLength, buf: &'a mut Vec<u8>) -> Self { - let len_offset = buf.len(); - buf.extend(match size_len { - ListLength::NonZeroU8 { .. } => &[0xff][..], - ListLength::U16 | ListLength::NonZeroU16 { .. } => &[0xff, 0xff], - ListLength::U24 { .. } => &[0xff, 0xff, 0xff], - }); - - Self { - buf, - len_offset, - size_len, - } - } -} - -impl Drop for LengthPrefixedBuffer<'_> { - /// Goes back and corrects the length previously inserted at the start of the structure. - fn drop(&mut self) { - match self.size_len { - ListLength::NonZeroU8 { .. } => { - let len = self.buf.len() - self.len_offset - 1; - debug_assert!(len <= 0xff); - self.buf[self.len_offset] = len as u8; - } - ListLength::U16 | ListLength::NonZeroU16 { .. } => { - let len = self.buf.len() - self.len_offset - 2; - debug_assert!(len <= 0xffff); - let out: &mut [u8; 2] = (&mut self.buf[self.len_offset..self.len_offset + 2]) - .try_into() - .unwrap(); - *out = u16::to_be_bytes(len as u16); - } - ListLength::U24 { .. } => { - let len = self.buf.len() - self.len_offset - 3; - debug_assert!(len <= 0xff_ffff); - let len_bytes = u32::to_be_bytes(len as u32); - let out: &mut [u8; 3] = (&mut self.buf[self.len_offset..self.len_offset + 3]) - .try_into() - .unwrap(); - out.copy_from_slice(&len_bytes[1..]); - } - } - } -} - -#[cfg(test)] -mod tests { - use std::prelude::v1::*; - use std::vec; - - use super::*; - - #[test] - fn interrupted_length_prefixed_buffer_leaves_maximum_length() { - let mut buf = Vec::new(); - let nested = LengthPrefixedBuffer::new(ListLength::U16, &mut buf); - nested.buf.push(0xaa); - assert_eq!(nested.buf, &vec![0xff, 0xff, 0xaa]); - // <- if the buffer is accidentally read here, there is no possibility - // that the contents of the length-prefixed buffer are interpreted - // as a subsequent encoding (perhaps allowing injection of a different - // extension) - drop(nested); - assert_eq!(buf, vec![0x00, 0x01, 0xaa]); - } -} diff --git a/vendor/rustls/src/msgs/deframer/buffers.rs b/vendor/rustls/src/msgs/deframer/buffers.rs deleted file mode 100644 index bf098740..00000000 --- a/vendor/rustls/src/msgs/deframer/buffers.rs +++ /dev/null @@ -1,296 +0,0 @@ -use alloc::vec::Vec; -use core::mem; -use core::ops::Range; -#[cfg(feature = "std")] -use std::io; - -#[cfg(feature = "std")] -use crate::msgs::message::MAX_WIRE_SIZE; - -/// Conversion from a slice within a larger buffer into -/// a `Range` offset within. -#[derive(Debug)] -pub(crate) struct Locator { - bounds: Range<*const u8>, -} - -impl Locator { - #[inline] - pub(crate) fn new(slice: &[u8]) -> Self { - Self { - bounds: slice.as_ptr_range(), - } - } - - #[inline] - pub(crate) fn locate(&self, slice: &[u8]) -> Range<usize> { - let bounds = slice.as_ptr_range(); - debug_assert!(self.fully_contains(slice)); - let start = bounds.start as usize - self.bounds.start as usize; - let len = bounds.end as usize - bounds.start as usize; - Range { - start, - end: start + len, - } - } - - #[inline] - pub(crate) fn fully_contains(&self, slice: &[u8]) -> bool { - let bounds = slice.as_ptr_range(); - bounds.start >= self.bounds.start && bounds.end <= self.bounds.end - } -} - -/// Conversion from a `Range` offset to the original slice. -pub(crate) struct Delocator<'b> { - slice: &'b [u8], -} - -impl<'b> Delocator<'b> { - #[inline] - pub(crate) fn new(slice: &'b [u8]) -> Self { - Self { slice } - } - - #[inline] - pub(crate) fn slice_from_range(&'_ self, range: &Range<usize>) -> &'b [u8] { - // safety: this unwrap is safe so long as `range` came from `locate()` - // for the same buffer - self.slice.get(range.clone()).unwrap() - } - - #[inline] - pub(crate) fn locator(self) -> Locator { - Locator::new(self.slice) - } -} - -/// Reordering the underlying buffer based on ranges. -pub(crate) struct Coalescer<'b> { - slice: &'b mut [u8], -} - -impl<'b> Coalescer<'b> { - #[inline] - pub(crate) fn new(slice: &'b mut [u8]) -> Self { - Self { slice } - } - - #[inline] - pub(crate) fn copy_within(&mut self, from: Range<usize>, to: Range<usize>) { - debug_assert!(from.len() == to.len()); - debug_assert!(self.slice.get(from.clone()).is_some()); - debug_assert!(self.slice.get(to.clone()).is_some()); - self.slice.copy_within(from, to.start); - } - - #[inline] - pub(crate) fn delocator(self) -> Delocator<'b> { - Delocator::new(self.slice) - } -} - -/// Accounting structure tracking progress in parsing a single buffer. -#[derive(Clone, Debug)] -pub(crate) struct BufferProgress { - /// Prefix of the buffer that has been processed so far. - /// - /// `processed` may exceed `discard`, that means we have parsed - /// some buffer, but are still using it. This happens due to - /// in-place decryption of incoming records, and in-place - /// reassembly of handshake messages. - /// - /// 0 <= processed <= len - processed: usize, - - /// Prefix of the buffer that can be removed. - /// - /// If `discard` exceeds `processed`, that means we are ignoring - /// data without processing it. - /// - /// 0 <= discard <= len - discard: usize, -} - -impl BufferProgress { - pub(super) fn new(processed: usize) -> Self { - Self { - processed, - discard: 0, - } - } - - #[inline] - pub(crate) fn add_discard(&mut self, discard: usize) { - self.discard += discard; - } - - #[inline] - pub(crate) fn add_processed(&mut self, processed: usize) { - self.processed += processed; - } - - #[inline] - pub(crate) fn take_discard(&mut self) -> usize { - // the caller is about to discard `discard` bytes - // from the front of the buffer. adjust `processed` - // down by the same amount. - self.processed = self - .processed - .saturating_sub(self.discard); - mem::take(&mut self.discard) - } - - #[inline] - pub(crate) fn processed(&self) -> usize { - self.processed - } -} - -#[derive(Default, Debug)] -pub(crate) struct DeframerVecBuffer { - /// Buffer of data read from the socket, in the process of being parsed into messages. - /// - /// For buffer size management, checkout out the [`DeframerVecBuffer::prepare_read()`] method. - buf: Vec<u8>, - - /// What size prefix of `buf` is used. - used: usize, -} - -impl DeframerVecBuffer { - /// Discard `taken` bytes from the start of our buffer. - pub(crate) fn discard(&mut self, taken: usize) { - #[allow(clippy::comparison_chain)] - if taken < self.used { - /* Before: - * +----------+----------+----------+ - * | taken | pending |xxxxxxxxxx| - * +----------+----------+----------+ - * 0 ^ taken ^ self.used - * - * After: - * +----------+----------+----------+ - * | pending |xxxxxxxxxxxxxxxxxxxxx| - * +----------+----------+----------+ - * 0 ^ self.used - */ - - self.buf - .copy_within(taken..self.used, 0); - self.used -= taken; - } else if taken >= self.used { - self.used = 0; - } - } - - pub(crate) fn filled_mut(&mut self) -> &mut [u8] { - &mut self.buf[..self.used] - } - - pub(crate) fn filled(&self) -> &[u8] { - &self.buf[..self.used] - } -} - -#[cfg(feature = "std")] -impl DeframerVecBuffer { - /// Read some bytes from `rd`, and add them to the buffer. - pub(crate) fn read(&mut self, rd: &mut dyn io::Read, in_handshake: bool) -> io::Result<usize> { - if let Err(err) = self.prepare_read(in_handshake) { - return Err(io::Error::new(io::ErrorKind::InvalidData, err)); - } - - // Try to do the largest reads possible. Note that if - // we get a message with a length field out of range here, - // we do a zero length read. That looks like an EOF to - // the next layer up, which is fine. - let new_bytes = rd.read(&mut self.buf[self.used..])?; - self.used += new_bytes; - Ok(new_bytes) - } - - /// Resize the internal `buf` if necessary for reading more bytes. - fn prepare_read(&mut self, is_joining_hs: bool) -> Result<(), &'static str> { - /// TLS allows for handshake messages of up to 16MB. We - /// restrict that to 64KB to limit potential for denial-of- - /// service. - const MAX_HANDSHAKE_SIZE: u32 = 0xffff; - - const READ_SIZE: usize = 4096; - - // We allow a maximum of 64k of buffered data for handshake messages only. Enforce this - // by varying the maximum allowed buffer size here based on whether a prefix of a - // handshake payload is currently being buffered. Given that the first read of such a - // payload will only ever be 4k bytes, the next time we come around here we allow a - // larger buffer size. Once the large message and any following handshake messages in - // the same flight have been consumed, `pop()` will call `discard()` to reset `used`. - // At this point, the buffer resizing logic below should reduce the buffer size. - let allow_max = match is_joining_hs { - true => MAX_HANDSHAKE_SIZE as usize, - false => MAX_WIRE_SIZE, - }; - - if self.used >= allow_max { - return Err("message buffer full"); - } - - // If we can and need to increase the buffer size to allow a 4k read, do so. After - // dealing with a large handshake message (exceeding `OutboundOpaqueMessage::MAX_WIRE_SIZE`), - // make sure to reduce the buffer size again (large messages should be rare). - // Also, reduce the buffer size if there are neither full nor partial messages in it, - // which usually means that the other side suspended sending data. - let need_capacity = Ord::min(allow_max, self.used + READ_SIZE); - if need_capacity > self.buf.len() { - self.buf.resize(need_capacity, 0); - } else if self.used == 0 || self.buf.len() > allow_max { - self.buf.resize(need_capacity, 0); - self.buf.shrink_to(need_capacity); - } - - Ok(()) - } - - /// Append `bytes` to the end of this buffer. - /// - /// Return a `Range` saying where it went. - pub(crate) fn extend(&mut self, bytes: &[u8]) -> Range<usize> { - let len = bytes.len(); - let start = self.used; - let end = start + len; - if self.buf.len() < end { - self.buf.resize(end, 0); - } - self.buf[start..end].copy_from_slice(bytes); - self.used += len; - Range { start, end } - } -} - -/// A borrowed version of [`DeframerVecBuffer`] that tracks discard operations -#[derive(Debug)] -pub(crate) struct DeframerSliceBuffer<'a> { - // a fully initialized buffer that will be deframed - buf: &'a mut [u8], - // number of bytes to discard from the front of `buf` at a later time - discard: usize, -} - -impl<'a> DeframerSliceBuffer<'a> { - pub(crate) fn new(buf: &'a mut [u8]) -> Self { - Self { buf, discard: 0 } - } - - /// Tracks a pending discard operation of `num_bytes` - pub(crate) fn queue_discard(&mut self, num_bytes: usize) { - self.discard += num_bytes; - } - - pub(crate) fn pending_discard(&self) -> usize { - self.discard - } - - pub(crate) fn filled_mut(&mut self) -> &mut [u8] { - &mut self.buf[self.discard..] - } -} diff --git a/vendor/rustls/src/msgs/deframer/handshake.rs b/vendor/rustls/src/msgs/deframer/handshake.rs deleted file mode 100644 index 0d91f0ea..00000000 --- a/vendor/rustls/src/msgs/deframer/handshake.rs +++ /dev/null @@ -1,525 +0,0 @@ -use alloc::vec::Vec; -use core::mem; -use core::ops::Range; - -use super::buffers::{BufferProgress, Coalescer, Delocator, Locator}; -use crate::error::InvalidMessage; -use crate::msgs::codec::{Codec, u24}; -use crate::msgs::message::InboundPlainMessage; -use crate::{ContentType, ProtocolVersion}; - -#[derive(Debug)] -pub(crate) struct HandshakeDeframer { - /// Spans covering individual handshake payloads, in order of receipt. - spans: Vec<FragmentSpan>, - - /// Discard value, tracking the rightmost extent of the last message - /// in `spans`. - outer_discard: usize, -} - -impl HandshakeDeframer { - /// Accepts a message into the deframer. - /// - /// `containing_buffer` allows mapping the message payload to its position - /// in the input buffer, and thereby avoid retaining a borrow on the input - /// buffer. - /// - /// That is required because our processing of handshake messages requires - /// them to be contiguous (and avoiding that would mean supporting gather-based - /// parsing in a large number of places, including `core`, `webpki`, and the - /// `CryptoProvider` interface). `coalesce()` arranges for that to happen, but - /// to do so it needs to move the fragments together in the original buffer. - /// This would not be possible if the messages were borrowing from that buffer. - /// - /// `outer_discard` is the rightmost extent of the original message. - pub(crate) fn input_message( - &mut self, - msg: InboundPlainMessage<'_>, - containing_buffer: &Locator, - outer_discard: usize, - ) { - debug_assert_eq!(msg.typ, ContentType::Handshake); - debug_assert!(containing_buffer.fully_contains(msg.payload)); - debug_assert!(self.outer_discard <= outer_discard); - - self.outer_discard = outer_discard; - - // if our last span is incomplete, we can blindly add this as a new span -- - // no need to attempt parsing it with `DissectHandshakeIter`. - // - // `coalesce()` will later move this new message to be contiguous with - // `_last_incomplete`, and reparse the result. - // - // we cannot merge these processes, because `coalesce` mutates the underlying - // buffer, and `msg` borrows it. - if let Some(_last_incomplete) = self - .spans - .last() - .filter(|span| !span.is_complete()) - { - self.spans.push(FragmentSpan { - version: msg.version, - size: None, - bounds: containing_buffer.locate(msg.payload), - }); - return; - } - - // otherwise, we can expect `msg` to contain a handshake header introducing - // a new message (and perhaps several of them.) - for span in DissectHandshakeIter::new(msg, containing_buffer) { - self.spans.push(span); - } - } - - /// Returns a `BufferProgress` that skips over unprocessed handshake data. - pub(crate) fn progress(&self) -> BufferProgress { - BufferProgress::new(self.outer_discard) - } - - /// Do we have a message ready? ie, would `iter().next()` return `Some`? - pub(crate) fn has_message_ready(&self) -> bool { - match self.spans.first() { - Some(span) => span.is_complete(), - None => false, - } - } - - /// Do we have any message data, partial or otherwise? - pub(crate) fn is_active(&self) -> bool { - !self.spans.is_empty() - } - - /// We are "aligned" if there is no partial fragment of a handshake - /// message. - pub(crate) fn is_aligned(&self) -> bool { - self.spans - .iter() - .all(|span| span.is_complete()) - } - - /// Iterate over the complete messages. - pub(crate) fn iter<'a, 'b>(&'a mut self, containing_buffer: &'b [u8]) -> HandshakeIter<'a, 'b> { - HandshakeIter { - deframer: self, - containing_buffer: Delocator::new(containing_buffer), - index: 0, - } - } - - /// Coalesce the handshake portions of the given buffer, - /// if needed. - /// - /// This does nothing if there is nothing to do. - /// - /// In a normal TLS stream, handshake messages need not be contiguous. - /// For example, each handshake message could be delivered in its own - /// outer TLS message. This would mean the handshake messages are - /// separated by the outer TLS message headers, and likely also - /// separated by encryption overhead (any explicit nonce in front, - /// any padding and authentication tag afterwards). - /// - /// For a toy example of one handshake message in two fragments, and: - /// - /// - the letter `h` for handshake header octets - /// - the letter `H` for handshake payload octets - /// - the letter `x` for octets in the buffer ignored by this code, - /// - /// the buffer and `spans` data structure could look like: - /// - /// ```text - /// 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 - /// x x x x x h h h h H H H x x x x x H H H H H H x x x - /// '------------' '----------' - /// | | - /// spans = [ { bounds = (5, 12), | - /// size = Some(9), .. }, | - /// { bounds = (17, 23), .. } ] - /// ``` - /// - /// In this case, `requires_coalesce` returns `Some(0)`. Then - /// `coalesce_one` moves the second range leftwards: - /// - /// ```text - /// 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 - /// x x x x x h h h h H H H x x x x x H H H H H H x x x - /// '----------' - /// ^ '----------' - /// | v - /// '--<---<--' - /// copy_within(from = (17, 23), - /// to = (12, 18)) - /// ``` - /// - /// Leaving the buffer and spans: - /// - /// ```text - /// 0 1 2 3 4 5 6 7 8 9 a b c d e f 0 1 2 3 4 5 6 7 8 9 - /// x x x x x h h h h H H H H H H H H H x x x x x x x x - /// '------------------------' - /// | - /// spans = [ { bounds = (5, 18), size = Some(9), .. } ] - /// ``` - pub(crate) fn coalesce(&mut self, containing_buffer: &mut [u8]) -> Result<(), InvalidMessage> { - // Strategy: while there is work to do, scan `spans` - // for a pair where the first is not complete. move - // the second down towards the first, then reparse the contents. - while let Some(i) = self.requires_coalesce() { - self.coalesce_one(i, Coalescer::new(containing_buffer)); - } - - // check resulting spans pass our imposed length limit - match self - .spans - .iter() - .any(|span| span.size.unwrap_or_default() > MAX_HANDSHAKE_SIZE) - { - true => Err(InvalidMessage::HandshakePayloadTooLarge), - false => Ok(()), - } - } - - /// Within `containing_buffer`, move `span[index+1]` to be contiguous - /// with `span[index]`. - fn coalesce_one(&mut self, index: usize, mut containing_buffer: Coalescer<'_>) { - let second = self.spans.remove(index + 1); - let mut first = self.spans.remove(index); - - // move the entirety of `second` to be contiguous with `first` - let len = second.bounds.len(); - let target = Range { - start: first.bounds.end, - end: first.bounds.end + len, - }; - - containing_buffer.copy_within(second.bounds, target); - let delocator = containing_buffer.delocator(); - - // now adjust `first` to cover both - first.bounds.end += len; - - // finally, attempt to re-dissect `first` - let msg = InboundPlainMessage { - typ: ContentType::Handshake, - version: first.version, - payload: delocator.slice_from_range(&first.bounds), - }; - - for (i, span) in DissectHandshakeIter::new(msg, &delocator.locator()).enumerate() { - self.spans.insert(index + i, span); - } - } - - /// We require coalescing if any span except the last is not complete. - /// - /// Returns an index into `spans` for the first non-complete span: - /// this will never be the last item. - fn requires_coalesce(&self) -> Option<usize> { - self.spans - .split_last() - .and_then(|(_last, elements)| { - elements - .iter() - .enumerate() - .find_map(|(i, span)| (!span.is_complete()).then_some(i)) - }) - } -} - -impl Default for HandshakeDeframer { - fn default() -> Self { - Self { - // capacity: a typical upper limit on handshake messages in - // a single flight - spans: Vec::with_capacity(16), - outer_discard: 0, - } - } -} - -struct DissectHandshakeIter<'a, 'b> { - version: ProtocolVersion, - payload: &'b [u8], - containing_buffer: &'a Locator, -} - -impl<'a, 'b> DissectHandshakeIter<'a, 'b> { - fn new(msg: InboundPlainMessage<'b>, containing_buffer: &'a Locator) -> Self { - Self { - version: msg.version, - payload: msg.payload, - containing_buffer, - } - } -} - -impl Iterator for DissectHandshakeIter<'_, '_> { - type Item = FragmentSpan; - - fn next(&mut self) -> Option<Self::Item> { - if self.payload.is_empty() { - return None; - } - - // If there is not enough data to have a header the length is unknown - if self.payload.len() < HANDSHAKE_HEADER_LEN { - let buf = mem::take(&mut self.payload); - let bounds = self.containing_buffer.locate(buf); - return Some(FragmentSpan { - version: self.version, - size: None, - bounds: bounds.clone(), - }); - } - - let (header, rest) = mem::take(&mut self.payload).split_at(HANDSHAKE_HEADER_LEN); - - // safety: header[1..] is exactly 3 bytes, so `u24::read_bytes` cannot fail - let size = u24::read_bytes(&header[1..]) - .unwrap() - .into(); - - let available = if size < rest.len() { - self.payload = &rest[size..]; - size - } else { - rest.len() - }; - - let mut bounds = self.containing_buffer.locate(header); - bounds.end += available; - Some(FragmentSpan { - version: self.version, - size: Some(size), - bounds: bounds.clone(), - }) - } -} - -pub(crate) struct HandshakeIter<'a, 'b> { - deframer: &'a mut HandshakeDeframer, - containing_buffer: Delocator<'b>, - index: usize, -} - -impl<'b> Iterator for HandshakeIter<'_, 'b> { - type Item = (InboundPlainMessage<'b>, usize); - - fn next(&mut self) -> Option<Self::Item> { - let next_span = self.deframer.spans.get(self.index)?; - - if !next_span.is_complete() { - return None; - } - - // if this is the last handshake message, then we'll end - // up with an empty `spans` and can discard the remainder - // of the input buffer. - let discard = if self.deframer.spans.len() - 1 == self.index { - mem::take(&mut self.deframer.outer_discard) - } else { - 0 - }; - - self.index += 1; - Some(( - InboundPlainMessage { - typ: ContentType::Handshake, - version: next_span.version, - payload: self - .containing_buffer - .slice_from_range(&next_span.bounds), - }, - discard, - )) - } -} - -impl Drop for HandshakeIter<'_, '_> { - fn drop(&mut self) { - self.deframer.spans.drain(..self.index); - } -} - -#[derive(Debug)] -struct FragmentSpan { - /// version taken from containing message. - version: ProtocolVersion, - - /// size of the handshake message body (excluding header) - /// - /// `None` means the size is unknown, because `bounds` is not - /// large enough to encompass a whole header. - size: Option<usize>, - - /// bounds of the handshake message, including header - bounds: Range<usize>, -} - -impl FragmentSpan { - /// A `FragmentSpan` is "complete" if its size is known, and its - /// bounds exactly encompasses one handshake message. - fn is_complete(&self) -> bool { - match self.size { - Some(sz) => sz + HANDSHAKE_HEADER_LEN == self.bounds.len(), - None => false, - } - } -} - -const HANDSHAKE_HEADER_LEN: usize = 1 + 3; - -/// TLS allows for handshake messages of up to 16MB. We -/// restrict that to 64KB to limit potential for denial-of- -/// service. -const MAX_HANDSHAKE_SIZE: usize = 0xffff; - -#[cfg(test)] -mod tests { - use std::vec; - - use super::*; - use crate::msgs::deframer::DeframerIter; - - fn add_bytes(hs: &mut HandshakeDeframer, slice: &[u8], within: &[u8]) { - let msg = InboundPlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_3, - payload: slice, - }; - let locator = Locator::new(within); - let discard = locator.locate(slice).end; - hs.input_message(msg, &locator, discard); - } - - #[test] - fn coalesce() { - let mut input = vec![0, 0, 0, 0x21, 0, 0, 0, 0, 0x01, 0xff, 0x00, 0x01]; - let mut hs = HandshakeDeframer::default(); - - add_bytes(&mut hs, &input[3..4], &input); - assert_eq!(hs.requires_coalesce(), None); - add_bytes(&mut hs, &input[4..6], &input); - assert_eq!(hs.requires_coalesce(), Some(0)); - add_bytes(&mut hs, &input[8..10], &input); - assert_eq!(hs.requires_coalesce(), Some(0)); - - std::println!("before: {hs:?}"); - hs.coalesce(&mut input).unwrap(); - std::println!("after: {hs:?}"); - - let (msg, discard) = hs.iter(&input).next().unwrap(); - std::println!("msg {msg:?} discard {discard:?}"); - assert_eq!(msg.typ, ContentType::Handshake); - assert_eq!(msg.version, ProtocolVersion::TLSv1_3); - assert_eq!(msg.payload, &[0x21, 0x00, 0x00, 0x01, 0xff]); - - input.drain(..discard); - assert_eq!(input, &[0, 1]); - } - - #[test] - fn append() { - let mut input = vec![0, 0, 0, 0x21, 0, 0, 5, 0, 0, 1, 2, 3, 4, 5, 0]; - let mut hs = HandshakeDeframer::default(); - - add_bytes(&mut hs, &input[3..7], &input); - add_bytes(&mut hs, &input[9..14], &input); - assert_eq!(hs.spans.len(), 2); - - hs.coalesce(&mut input).unwrap(); - assert_eq!(hs.spans.len(), 1); - - let (msg, discard) = std::dbg!(hs.iter(&input).next().unwrap()); - assert_eq!(msg.typ, ContentType::Handshake); - assert_eq!(msg.version, ProtocolVersion::TLSv1_3); - assert_eq!(msg.payload, &[0x21, 0x00, 0x00, 0x05, 1, 2, 3, 4, 5]); - - input.drain(..discard); - assert_eq!(input, &[0]); - } - - #[test] - fn coalesce_rejects_excess_size_message() { - const X: u8 = 0xff; - let mut input = vec![0x21, 0x01, 0x00, X, 0x00, 0xab, X]; - let mut hs = HandshakeDeframer::default(); - - // split header over multiple messages, which motivates doing - // this check in `coalesce()` - add_bytes(&mut hs, &input[0..3], &input); - add_bytes(&mut hs, &input[4..6], &input); - - assert_eq!( - hs.coalesce(&mut input), - Err(InvalidMessage::HandshakePayloadTooLarge) - ); - } - - #[test] - fn iter_only_returns_full_messages() { - let input = [0, 0, 0, 0x21, 0, 0, 1, 0xab, 0x21, 0, 0, 1]; - - let mut hs = HandshakeDeframer::default(); - - add_bytes(&mut hs, &input[3..8], &input); - add_bytes(&mut hs, &input[8..12], &input); - - let mut iter = hs.iter(&input); - let (msg, discard) = iter.next().unwrap(); - assert!(iter.next().is_none()); - - assert_eq!(msg.typ, ContentType::Handshake); - assert_eq!(msg.version, ProtocolVersion::TLSv1_3); - assert_eq!(msg.payload, &[0x21, 0x00, 0x00, 0x01, 0xab]); - assert_eq!(discard, 0); - } - - #[test] - fn handshake_flight() { - // intended to be a realistic example - let mut input = include_bytes!("../../testdata/handshake-test.1.bin").to_vec(); - let locator = Locator::new(&input); - - let mut hs = HandshakeDeframer::default(); - - let mut iter = DeframerIter::new(&mut input[..]); - - while let Some(message) = iter.next() { - let plain = message.unwrap().into_plain_message(); - std::println!("message {plain:?}"); - - hs.input_message(plain, &locator, iter.bytes_consumed()); - } - - hs.coalesce(&mut input[..]).unwrap(); - - let mut iter = hs.iter(&input[..]); - for _ in 0..4 { - let (msg, discard) = iter.next().unwrap(); - assert!(matches!( - msg, - InboundPlainMessage { - typ: ContentType::Handshake, - .. - } - )); - assert_eq!(discard, 0); - } - - let (msg, discard) = iter.next().unwrap(); - assert!(matches!( - msg, - InboundPlainMessage { - typ: ContentType::Handshake, - .. - } - )); - assert_eq!(discard, 4280); - drop(iter); - - input.drain(0..discard); - assert!(input.is_empty()); - } -} diff --git a/vendor/rustls/src/msgs/deframer/mod.rs b/vendor/rustls/src/msgs/deframer/mod.rs deleted file mode 100644 index 4122b525..00000000 --- a/vendor/rustls/src/msgs/deframer/mod.rs +++ /dev/null @@ -1,238 +0,0 @@ -use core::mem; - -use crate::error::{Error, InvalidMessage}; -use crate::msgs::codec::Reader; -use crate::msgs::message::{ - HEADER_SIZE, InboundOpaqueMessage, MessageError, read_opaque_message_header, -}; - -pub(crate) mod buffers; -pub(crate) mod handshake; - -/// A deframer of TLS wire messages. -/// -/// Returns `Some(Ok(_))` containing each `InboundOpaqueMessage` deframed -/// from the buffer. -/// -/// Returns `None` if no further messages can be deframed from the -/// buffer. More data is required for further progress. -/// -/// Returns `Some(Err(_))` if the peer is not talking TLS, but some -/// other protocol. The caller should abort the connection, because -/// the deframer cannot recover. -/// -/// Call `bytes_consumed()` to learn how many bytes the iterator has -/// processed from the front of the original buffer. This is only updated -/// when a message is successfully deframed (ie. `Some(Ok(_))` is returned). -pub(crate) struct DeframerIter<'a> { - buf: &'a mut [u8], - consumed: usize, -} - -impl<'a> DeframerIter<'a> { - /// Make a new `DeframerIter` - pub(crate) fn new(buf: &'a mut [u8]) -> Self { - Self { buf, consumed: 0 } - } - - /// How many bytes were processed successfully from the front - /// of the buffer passed to `new()`? - pub(crate) fn bytes_consumed(&self) -> usize { - self.consumed - } -} - -impl<'a> Iterator for DeframerIter<'a> { - type Item = Result<InboundOpaqueMessage<'a>, Error>; - - fn next(&mut self) -> Option<Self::Item> { - let mut reader = Reader::init(self.buf); - - let (typ, version, len) = match read_opaque_message_header(&mut reader) { - Ok(header) => header, - Err(err) => { - let err = match err { - MessageError::TooShortForHeader | MessageError::TooShortForLength => { - return None; - } - MessageError::InvalidEmptyPayload => InvalidMessage::InvalidEmptyPayload, - MessageError::MessageTooLarge => InvalidMessage::MessageTooLarge, - MessageError::InvalidContentType => InvalidMessage::InvalidContentType, - MessageError::UnknownProtocolVersion => InvalidMessage::UnknownProtocolVersion, - }; - return Some(Err(err.into())); - } - }; - - let end = HEADER_SIZE + len as usize; - - self.buf.get(HEADER_SIZE..end)?; - - // we now have a TLS header and body on the front of `self.buf`. remove - // it from the front. - let (consumed, remainder) = mem::take(&mut self.buf).split_at_mut(end); - self.buf = remainder; - self.consumed += end; - - Some(Ok(InboundOpaqueMessage::new( - typ, - version, - &mut consumed[HEADER_SIZE..], - ))) - } -} - -pub fn fuzz_deframer(data: &[u8]) { - let mut buf = data.to_vec(); - let mut iter = DeframerIter::new(&mut buf); - - for message in iter.by_ref() { - if message.is_err() { - break; - } - } - - assert!(iter.bytes_consumed() <= buf.len()); -} - -#[cfg(feature = "std")] -#[cfg(test)] -mod tests { - use alloc::vec::Vec; - use std::prelude::v1::*; - - use super::*; - use crate::ContentType; - - #[test] - fn iterator_empty_before_header_received() { - assert!( - DeframerIter::new(&mut []) - .next() - .is_none() - ); - assert!( - DeframerIter::new(&mut [0x16]) - .next() - .is_none() - ); - assert!( - DeframerIter::new(&mut [0x16, 0x03]) - .next() - .is_none() - ); - assert!( - DeframerIter::new(&mut [0x16, 0x03, 0x03]) - .next() - .is_none() - ); - assert!( - DeframerIter::new(&mut [0x16, 0x03, 0x03, 0x00]) - .next() - .is_none() - ); - assert!( - DeframerIter::new(&mut [0x16, 0x03, 0x03, 0x00, 0x01]) - .next() - .is_none() - ); - } - - #[test] - fn iterate_one_message() { - let mut buffer = [0x17, 0x03, 0x03, 0x00, 0x01, 0x00]; - let mut iter = DeframerIter::new(&mut buffer); - assert_eq!( - iter.next().unwrap().unwrap().typ, - ContentType::ApplicationData - ); - assert_eq!(iter.bytes_consumed(), 6); - assert!(iter.next().is_none()); - } - - #[test] - fn iterate_two_messages() { - let mut buffer = [ - 0x16, 0x03, 0x03, 0x00, 0x01, 0x00, 0x17, 0x03, 0x03, 0x00, 0x01, 0x00, - ]; - let mut iter = DeframerIter::new(&mut buffer); - assert_eq!(iter.next().unwrap().unwrap().typ, ContentType::Handshake); - assert_eq!(iter.bytes_consumed(), 6); - assert_eq!( - iter.next().unwrap().unwrap().typ, - ContentType::ApplicationData - ); - assert_eq!(iter.bytes_consumed(), 12); - assert!(iter.next().is_none()); - } - - #[test] - fn iterator_invalid_protocol_version_rejected() { - let mut buffer = include_bytes!("../../testdata/deframer-invalid-version.bin").to_vec(); - let mut iter = DeframerIter::new(&mut buffer); - assert_eq!( - iter.next().unwrap().err(), - Some(Error::InvalidMessage( - InvalidMessage::UnknownProtocolVersion - )) - ); - } - - #[test] - fn iterator_invalid_content_type_rejected() { - let mut buffer = include_bytes!("../../testdata/deframer-invalid-contenttype.bin").to_vec(); - let mut iter = DeframerIter::new(&mut buffer); - assert_eq!( - iter.next().unwrap().err(), - Some(Error::InvalidMessage(InvalidMessage::InvalidContentType)) - ); - } - - #[test] - fn iterator_excess_message_length_rejected() { - let mut buffer = include_bytes!("../../testdata/deframer-invalid-length.bin").to_vec(); - let mut iter = DeframerIter::new(&mut buffer); - assert_eq!( - iter.next().unwrap().err(), - Some(Error::InvalidMessage(InvalidMessage::MessageTooLarge)) - ); - } - - #[test] - fn iterator_zero_message_length_rejected() { - let mut buffer = include_bytes!("../../testdata/deframer-invalid-empty.bin").to_vec(); - let mut iter = DeframerIter::new(&mut buffer); - assert_eq!( - iter.next().unwrap().err(), - Some(Error::InvalidMessage(InvalidMessage::InvalidEmptyPayload)) - ); - } - - #[test] - fn iterator_over_many_messages() { - let client_hello = include_bytes!("../../testdata/deframer-test.1.bin"); - let mut buffer = Vec::with_capacity(3 * client_hello.len()); - buffer.extend(client_hello); - buffer.extend(client_hello); - buffer.extend(client_hello); - let mut iter = DeframerIter::new(&mut buffer); - let mut count = 0; - - for message in iter.by_ref() { - let message = message.unwrap(); - assert_eq!(ContentType::Handshake, message.typ); - count += 1; - } - - assert_eq!(count, 3); - assert_eq!(client_hello.len() * 3, iter.bytes_consumed()); - } - - #[test] - fn exercise_fuzz_deframer() { - fuzz_deframer(&[0xff, 0xff, 0xff, 0xff, 0xff]); - for prefix in 0..7 { - fuzz_deframer(&[0x16, 0x03, 0x03, 0x00, 0x01, 0xff][..prefix]); - } - } -} diff --git a/vendor/rustls/src/msgs/enums.rs b/vendor/rustls/src/msgs/enums.rs deleted file mode 100644 index 6eaa2b32..00000000 --- a/vendor/rustls/src/msgs/enums.rs +++ /dev/null @@ -1,510 +0,0 @@ -#![allow(clippy::upper_case_acronyms)] -#![allow(non_camel_case_types)] -use crate::crypto::{KeyExchangeAlgorithm, hash}; -use crate::msgs::codec::{Codec, Reader}; - -enum_builder! { - /// The `HashAlgorithm` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum HashAlgorithm { - NONE => 0x00, - MD5 => 0x01, - SHA1 => 0x02, - SHA224 => 0x03, - SHA256 => 0x04, - SHA384 => 0x05, - SHA512 => 0x06, - } -} - -impl HashAlgorithm { - /// Returns the hash of the empty input. - /// - /// This returns `None` for some hash algorithms, so the caller - /// should be prepared to do the computation themselves in this case. - pub(crate) fn hash_for_empty_input(&self) -> Option<hash::Output> { - match self { - Self::SHA256 => Some(hash::Output::new( - b"\xe3\xb0\xc4\x42\x98\xfc\x1c\x14\ - \x9a\xfb\xf4\xc8\x99\x6f\xb9\x24\ - \x27\xae\x41\xe4\x64\x9b\x93\x4c\ - \xa4\x95\x99\x1b\x78\x52\xb8\x55", - )), - Self::SHA384 => Some(hash::Output::new( - b"\x38\xb0\x60\xa7\x51\xac\x96\x38\ - \x4c\xd9\x32\x7e\xb1\xb1\xe3\x6a\ - \x21\xfd\xb7\x11\x14\xbe\x07\x43\ - \x4c\x0c\xc7\xbf\x63\xf6\xe1\xda\ - \x27\x4e\xde\xbf\xe7\x6f\x65\xfb\ - \xd5\x1a\xd2\xf1\x48\x98\xb9\x5b", - )), - _ => None, - } - } -} - -enum_builder! { - /// The `ClientCertificateType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub(crate) enum ClientCertificateType { - RSASign => 0x01, - DSSSign => 0x02, - RSAFixedDH => 0x03, - DSSFixedDH => 0x04, - RSAEphemeralDH => 0x05, - DSSEphemeralDH => 0x06, - FortezzaDMS => 0x14, - ECDSASign => 0x40, - RSAFixedECDH => 0x41, - ECDSAFixedECDH => 0x42, - } -} - -enum_builder! { - /// The `Compression` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum Compression { - Null => 0x00, - Deflate => 0x01, - LSZ => 0x40, - } -} - -enum_builder! { - /// The `AlertLevel` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum AlertLevel { - Warning => 0x01, - Fatal => 0x02, - } -} - -enum_builder! { - /// The `HeartbeatMessageType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub(crate) enum HeartbeatMessageType { - Request => 0x01, - Response => 0x02, - } -} - -enum_builder! { - /// The `ExtensionType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u16)] - pub enum ExtensionType { - ServerName => 0x0000, - MaxFragmentLength => 0x0001, - ClientCertificateUrl => 0x0002, - TrustedCAKeys => 0x0003, - TruncatedHMAC => 0x0004, - StatusRequest => 0x0005, - UserMapping => 0x0006, - ClientAuthz => 0x0007, - ServerAuthz => 0x0008, - CertificateType => 0x0009, - EllipticCurves => 0x000a, - ECPointFormats => 0x000b, - SRP => 0x000c, - SignatureAlgorithms => 0x000d, - UseSRTP => 0x000e, - Heartbeat => 0x000f, - ALProtocolNegotiation => 0x0010, - SCT => 0x0012, - ClientCertificateType => 0x0013, - ServerCertificateType => 0x0014, - Padding => 0x0015, - ExtendedMasterSecret => 0x0017, - CompressCertificate => 0x001b, - SessionTicket => 0x0023, - PreSharedKey => 0x0029, - EarlyData => 0x002a, - SupportedVersions => 0x002b, - Cookie => 0x002c, - PSKKeyExchangeModes => 0x002d, - TicketEarlyDataInfo => 0x002e, - CertificateAuthorities => 0x002f, - OIDFilters => 0x0030, - PostHandshakeAuth => 0x0031, - SignatureAlgorithmsCert => 0x0032, - KeyShare => 0x0033, - TransportParameters => 0x0039, - NextProtocolNegotiation => 0x3374, - ChannelId => 0x754f, - RenegotiationInfo => 0xff01, - TransportParametersDraft => 0xffa5, - EncryptedClientHello => 0xfe0d, // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-11.1 - EncryptedClientHelloOuterExtensions => 0xfd00, // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-5.1 - } -} - -impl ExtensionType { - /// Returns true if the extension type can be compressed in an "inner" client hello for ECH. - /// - /// This function should only return true for extension types where the inner hello and outer - /// hello extensions values will always be identical. Extensions that may be identical - /// sometimes (e.g. server name, cert compression methods), but not always, SHOULD NOT be - /// compressed. - /// - /// See [draft-ietf-esni-18 §5](https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-5) - /// and [draft-ietf-esni-18 §10.5](https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-10.5) - /// for more information. - pub(crate) fn ech_compress(&self) -> bool { - // We match which extensions we will compress with BoringSSL and Go's stdlib. - matches!( - self, - Self::StatusRequest - | Self::EllipticCurves - | Self::SignatureAlgorithms - | Self::SignatureAlgorithmsCert - | Self::ALProtocolNegotiation - | Self::SupportedVersions - | Self::Cookie - | Self::KeyShare - | Self::PSKKeyExchangeModes - ) - } -} - -enum_builder! { - /// The `ServerNameType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub(crate) enum ServerNameType { - HostName => 0x00, - } -} - -enum_builder! { - /// The `NamedCurve` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - /// - /// This enum is used for recognizing elliptic curve parameters advertised - /// by a peer during a TLS handshake. It is **not** a list of curves that - /// Rustls supports. See [`crate::crypto::ring::kx_group`] for the list of supported - /// elliptic curve groups. - #[repr(u16)] - pub(crate) enum NamedCurve { - sect163k1 => 0x0001, - sect163r1 => 0x0002, - sect163r2 => 0x0003, - sect193r1 => 0x0004, - sect193r2 => 0x0005, - sect233k1 => 0x0006, - sect233r1 => 0x0007, - sect239k1 => 0x0008, - sect283k1 => 0x0009, - sect283r1 => 0x000a, - sect409k1 => 0x000b, - sect409r1 => 0x000c, - sect571k1 => 0x000d, - sect571r1 => 0x000e, - secp160k1 => 0x000f, - secp160r1 => 0x0010, - secp160r2 => 0x0011, - secp192k1 => 0x0012, - secp192r1 => 0x0013, - secp224k1 => 0x0014, - secp224r1 => 0x0015, - secp256k1 => 0x0016, - secp256r1 => 0x0017, - secp384r1 => 0x0018, - secp521r1 => 0x0019, - brainpoolp256r1 => 0x001a, - brainpoolp384r1 => 0x001b, - brainpoolp512r1 => 0x001c, - X25519 => 0x001d, - X448 => 0x001e, - arbitrary_explicit_prime_curves => 0xff01, - arbitrary_explicit_char2_curves => 0xff02, - } -} - -enum_builder! { - /// The `NamedGroup` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u16)] - pub enum NamedGroup { - secp256r1 => 0x0017, - secp384r1 => 0x0018, - secp521r1 => 0x0019, - X25519 => 0x001d, - X448 => 0x001e, - FFDHE2048 => 0x0100, - FFDHE3072 => 0x0101, - FFDHE4096 => 0x0102, - FFDHE6144 => 0x0103, - FFDHE8192 => 0x0104, - MLKEM512 => 0x0200, - MLKEM768 => 0x0201, - MLKEM1024 => 0x0202, - secp256r1MLKEM768 => 0x11eb, - X25519MLKEM768 => 0x11ec, - } -} - -impl NamedGroup { - /// Return the key exchange algorithm associated with this `NamedGroup` - pub fn key_exchange_algorithm(self) -> KeyExchangeAlgorithm { - match u16::from(self) { - x if (0x100..0x200).contains(&x) => KeyExchangeAlgorithm::DHE, - _ => KeyExchangeAlgorithm::ECDHE, - } - } -} - -enum_builder! { - /// The `ECPointFormat` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum ECPointFormat { - Uncompressed => 0x00, - ANSIX962CompressedPrime => 0x01, - ANSIX962CompressedChar2 => 0x02, - } -} - -enum_builder! { - /// The `HeartbeatMode` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub(crate) enum HeartbeatMode { - PeerAllowedToSend => 0x01, - PeerNotAllowedToSend => 0x02, - } -} - -enum_builder! { - /// The `ECCurveType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub(crate) enum ECCurveType { - ExplicitPrime => 0x01, - ExplicitChar2 => 0x02, - NamedCurve => 0x03, - } -} - -enum_builder! { - /// The `PskKeyExchangeMode` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum PskKeyExchangeMode { - PSK_KE => 0x00, - PSK_DHE_KE => 0x01, - } -} - -enum_builder! { - /// The `KeyUpdateRequest` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum KeyUpdateRequest { - UpdateNotRequested => 0x00, - UpdateRequested => 0x01, - } -} - -enum_builder! { - /// The `CertificateStatusType` TLS protocol enum. Values in this enum are taken - /// from the various RFCs covering TLS, and are listed by IANA. - /// The `Unknown` item is used when processing unrecognised ordinals. - #[repr(u8)] - pub enum CertificateStatusType { - OCSP => 0x01, - } -} - -enum_builder! { - /// The Key Encapsulation Mechanism (`Kem`) type for HPKE operations. - /// Listed by IANA, as specified in [RFC 9180 Section 7.1] - /// - /// [RFC 9180 Section 7.1]: <https://datatracker.ietf.org/doc/html/rfc9180#kemid-values> - #[repr(u16)] - pub enum HpkeKem { - DHKEM_P256_HKDF_SHA256 => 0x0010, - DHKEM_P384_HKDF_SHA384 => 0x0011, - DHKEM_P521_HKDF_SHA512 => 0x0012, - DHKEM_X25519_HKDF_SHA256 => 0x0020, - DHKEM_X448_HKDF_SHA512 => 0x0021, - } -} - -enum_builder! { - /// The Key Derivation Function (`Kdf`) type for HPKE operations. - /// Listed by IANA, as specified in [RFC 9180 Section 7.2] - /// - /// [RFC 9180 Section 7.2]: <https://datatracker.ietf.org/doc/html/rfc9180#name-key-derivation-functions-kd> - #[repr(u16)] - pub enum HpkeKdf { - HKDF_SHA256 => 0x0001, - HKDF_SHA384 => 0x0002, - HKDF_SHA512 => 0x0003, - } -} - -impl Default for HpkeKdf { - // TODO(XXX): revisit the default configuration. This is just what Cloudflare ships right now. - fn default() -> Self { - Self::HKDF_SHA256 - } -} - -enum_builder! { - /// The Authenticated Encryption with Associated Data (`Aead`) type for HPKE operations. - /// Listed by IANA, as specified in [RFC 9180 Section 7.3] - /// - /// [RFC 9180 Section 7.3]: <https://datatracker.ietf.org/doc/html/rfc9180#name-authenticated-encryption-wi> - #[repr(u16)] - pub enum HpkeAead { - AES_128_GCM => 0x0001, - AES_256_GCM => 0x0002, - CHACHA20_POLY_1305 => 0x0003, - EXPORT_ONLY => 0xFFFF, - } -} - -impl HpkeAead { - /// Returns the length of the tag for the AEAD algorithm, or none if the AEAD is EXPORT_ONLY. - pub(crate) fn tag_len(&self) -> Option<usize> { - match self { - // See RFC 9180 Section 7.3, column `Nt`, the length in bytes of the authentication tag - // for the algorithm. - // https://www.rfc-editor.org/rfc/rfc9180.html#section-7.3 - Self::AES_128_GCM | Self::AES_256_GCM | Self::CHACHA20_POLY_1305 => Some(16), - _ => None, - } - } -} - -impl Default for HpkeAead { - // TODO(XXX): revisit the default configuration. This is just what Cloudflare ships right now. - fn default() -> Self { - Self::AES_128_GCM - } -} - -enum_builder! { - /// The Encrypted Client Hello protocol version (`EchVersion`). - /// - /// Specified in [draft-ietf-tls-esni Section 4]. - /// TODO(XXX): Update reference once RFC is published. - /// - /// [draft-ietf-tls-esni Section 4]: <https://www.ietf.org/archive/id/draft-ietf-tls-esni-17.html#section-4> - #[repr(u16)] - pub enum EchVersion { - V18 => 0xfe0d, - } -} - -#[cfg(test)] -pub(crate) mod tests { - // These tests are intended to provide coverage and - // check panic-safety of relatively unused values. - - use std::prelude::v1::*; - - use super::*; - - #[test] - fn test_enums() { - test_enum8::<HashAlgorithm>(HashAlgorithm::NONE, HashAlgorithm::SHA512); - test_enum8::<ClientCertificateType>( - ClientCertificateType::RSASign, - ClientCertificateType::ECDSAFixedECDH, - ); - test_enum8::<Compression>(Compression::Null, Compression::LSZ); - test_enum8::<AlertLevel>(AlertLevel::Warning, AlertLevel::Fatal); - test_enum8::<HeartbeatMessageType>( - HeartbeatMessageType::Request, - HeartbeatMessageType::Response, - ); - test_enum16::<ExtensionType>(ExtensionType::ServerName, ExtensionType::RenegotiationInfo); - test_enum8::<ServerNameType>(ServerNameType::HostName, ServerNameType::HostName); - test_enum16::<NamedCurve>( - NamedCurve::sect163k1, - NamedCurve::arbitrary_explicit_char2_curves, - ); - test_enum16::<NamedGroup>(NamedGroup::secp256r1, NamedGroup::FFDHE8192); - test_enum8::<ECPointFormat>( - ECPointFormat::Uncompressed, - ECPointFormat::ANSIX962CompressedChar2, - ); - test_enum8::<HeartbeatMode>( - HeartbeatMode::PeerAllowedToSend, - HeartbeatMode::PeerNotAllowedToSend, - ); - test_enum8::<ECCurveType>(ECCurveType::ExplicitPrime, ECCurveType::NamedCurve); - test_enum8::<PskKeyExchangeMode>( - PskKeyExchangeMode::PSK_KE, - PskKeyExchangeMode::PSK_DHE_KE, - ); - test_enum8::<KeyUpdateRequest>( - KeyUpdateRequest::UpdateNotRequested, - KeyUpdateRequest::UpdateRequested, - ); - test_enum8::<CertificateStatusType>( - CertificateStatusType::OCSP, - CertificateStatusType::OCSP, - ); - } - - pub(crate) fn test_enum8<T: for<'a> Codec<'a>>(first: T, last: T) { - let first_v = get8(&first); - let last_v = get8(&last); - - for val in first_v..last_v + 1 { - let mut buf = Vec::new(); - val.encode(&mut buf); - assert_eq!(buf.len(), 1); - - let t = T::read_bytes(&buf).unwrap(); - assert_eq!(val, get8(&t)); - } - } - - pub(crate) fn test_enum16<T: for<'a> Codec<'a>>(first: T, last: T) { - let first_v = get16(&first); - let last_v = get16(&last); - - for val in first_v..last_v + 1 { - let mut buf = Vec::new(); - val.encode(&mut buf); - assert_eq!(buf.len(), 2); - - let t = T::read_bytes(&buf).unwrap(); - assert_eq!(val, get16(&t)); - } - } - - fn get8<T: for<'a> Codec<'a>>(enum_value: &T) -> u8 { - let enc = enum_value.get_encoding(); - assert_eq!(enc.len(), 1); - enc[0] - } - - fn get16<T: for<'a> Codec<'a>>(enum_value: &T) -> u16 { - let enc = enum_value.get_encoding(); - assert_eq!(enc.len(), 2); - (enc[0] as u16 >> 8) | (enc[1] as u16) - } -} diff --git a/vendor/rustls/src/msgs/ffdhe_groups.rs b/vendor/rustls/src/msgs/ffdhe_groups.rs deleted file mode 100644 index ac105b59..00000000 --- a/vendor/rustls/src/msgs/ffdhe_groups.rs +++ /dev/null @@ -1,323 +0,0 @@ -//! This module contains parameters for FFDHE named groups as defined -//! in [RFC 7919 Appendix A](https://datatracker.ietf.org/doc/html/rfc7919#appendix-A). - -use crate::NamedGroup; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -/// Parameters of an FFDHE group, with Big-endian byte order -pub struct FfdheGroup<'a> { - pub p: &'a [u8], - pub g: &'a [u8], -} - -impl FfdheGroup<'static> { - /// Return the `FfdheGroup` corresponding to the provided `NamedGroup` - /// if it is indeed an FFDHE group - #[deprecated( - since = "0.23.13", - note = "This function is linker-unfriendly. Use `SupportedKxGroup::ffdhe_group()` instead" - )] - pub fn from_named_group(named_group: NamedGroup) -> Option<Self> { - match named_group { - NamedGroup::FFDHE2048 => Some(FFDHE2048), - NamedGroup::FFDHE3072 => Some(FFDHE3072), - NamedGroup::FFDHE4096 => Some(FFDHE4096), - NamedGroup::FFDHE6144 => Some(FFDHE6144), - NamedGroup::FFDHE8192 => Some(FFDHE8192), - _ => None, - } - } -} - -impl<'a> FfdheGroup<'a> { - /// Return the `NamedGroup` for the `FfdheGroup` if it represents one. - #[deprecated( - since = "0.23.13", - note = "This function is linker-unfriendly. Use `SupportedKxGroup::name()` instead" - )] - pub fn named_group(&self) -> Option<NamedGroup> { - match *self { - FFDHE2048 => Some(NamedGroup::FFDHE2048), - FFDHE3072 => Some(NamedGroup::FFDHE3072), - FFDHE4096 => Some(NamedGroup::FFDHE4096), - FFDHE6144 => Some(NamedGroup::FFDHE6144), - FFDHE8192 => Some(NamedGroup::FFDHE8192), - _ => None, - } - } - - /// Construct an `FfdheGroup` from the given `p` and `g`, trimming any potential leading zeros. - pub fn from_params_trimming_leading_zeros(p: &'a [u8], g: &'a [u8]) -> Self { - fn trim_leading_zeros(buf: &[u8]) -> &[u8] { - for start in 0..buf.len() { - if buf[start] != 0 { - return &buf[start..]; - } - } - &[] - } - - FfdheGroup { - p: trim_leading_zeros(p), - g: trim_leading_zeros(g), - } - } -} - -/// FFDHE2048 group defined in [RFC 7919 Appendix A.1] -/// -/// [RFC 7919 Appendix A.1]: https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.1 -pub const FFDHE2048: FfdheGroup<'static> = FfdheGroup { - p: &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, - 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, - 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, - 0x9b, 0x3e, 0xf9, 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, - 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, - 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, - 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, - 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, - 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, - 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, 0x91, 0x72, 0xfe, - 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, - 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, - 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x28, 0x5c, 0x97, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, - ], - g: &[2], -}; - -/// FFDHE3072 group defined in [RFC 7919 Appendix A.2] -/// -/// [RFC 7919 Appendix A.2]: https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.2 -pub const FFDHE3072: FfdheGroup<'static> = FfdheGroup { - p: &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, - 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, - 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, - 0x9b, 0x3e, 0xf9, 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, - 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, - 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, - 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, - 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, - 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, - 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, 0x91, 0x72, 0xfe, - 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, - 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, - 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, 0x65, 0x19, 0x03, - 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, - 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, - 0x86, 0xd9, 0x1c, 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, - 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, 0x64, 0xf2, 0xe2, - 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, - 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, - 0xbf, 0x9a, 0x42, 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, - 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, 0x66, 0xc6, 0x2e, - 0x37, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - ], - g: &[2], -}; - -/// FFDHE4096 group defined in [RFC 7919 Appendix A.3] -/// -/// [RFC 7919 Appendix A.3]: https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.3 -pub const FFDHE4096: FfdheGroup<'static> = FfdheGroup { - p: &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, - 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, - 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, - 0x9b, 0x3e, 0xf9, 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, - 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, - 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, - 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, - 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, - 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, - 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, 0x91, 0x72, 0xfe, - 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, - 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, - 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, 0x65, 0x19, 0x03, - 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, - 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, - 0x86, 0xd9, 0x1c, 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, - 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, 0x64, 0xf2, 0xe2, - 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, - 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, - 0xbf, 0x9a, 0x42, 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, - 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, 0x66, 0x9e, 0x1e, - 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, - 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, - 0x03, 0x40, 0x04, 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, - 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, 0xa9, 0x07, 0x60, - 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, - 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, - 0x4e, 0xce, 0xa9, 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, - 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, 0xf4, 0x41, 0x82, - 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x65, 0x5f, 0x6a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, - ], - g: &[2], -}; - -/// FFDHE6144 group defined in [RFC 7919 Appendix A.4] -/// -/// [RFC 7919 Appendix A.4]: https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.4 -pub const FFDHE6144: FfdheGroup<'static> = FfdheGroup { - p: &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, - 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, - 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, - 0x9b, 0x3e, 0xf9, 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, - 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, - 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, - 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, - 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, - 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, - 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, 0x91, 0x72, 0xfe, - 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, - 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, - 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, 0x65, 0x19, 0x03, - 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, - 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, - 0x86, 0xd9, 0x1c, 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, - 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, 0x64, 0xf2, 0xe2, - 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, - 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, - 0xbf, 0x9a, 0x42, 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, - 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, 0x66, 0x9e, 0x1e, - 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, - 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, - 0x03, 0x40, 0x04, 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, - 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, 0xa9, 0x07, 0x60, - 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, - 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, - 0x4e, 0xce, 0xa9, 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, - 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, 0xf4, 0x41, 0x82, - 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x0d, 0xd9, 0x02, 0x0b, 0xfd, 0x64, 0xb6, 0x45, 0x03, - 0x6c, 0x7a, 0x4e, 0x67, 0x7d, 0x2c, 0x38, 0x53, 0x2a, 0x3a, 0x23, 0xba, 0x44, 0x42, 0xca, - 0xf5, 0x3e, 0xa6, 0x3b, 0xb4, 0x54, 0x32, 0x9b, 0x76, 0x24, 0xc8, 0x91, 0x7b, 0xdd, 0x64, - 0xb1, 0xc0, 0xfd, 0x4c, 0xb3, 0x8e, 0x8c, 0x33, 0x4c, 0x70, 0x1c, 0x3a, 0xcd, 0xad, 0x06, - 0x57, 0xfc, 0xcf, 0xec, 0x71, 0x9b, 0x1f, 0x5c, 0x3e, 0x4e, 0x46, 0x04, 0x1f, 0x38, 0x81, - 0x47, 0xfb, 0x4c, 0xfd, 0xb4, 0x77, 0xa5, 0x24, 0x71, 0xf7, 0xa9, 0xa9, 0x69, 0x10, 0xb8, - 0x55, 0x32, 0x2e, 0xdb, 0x63, 0x40, 0xd8, 0xa0, 0x0e, 0xf0, 0x92, 0x35, 0x05, 0x11, 0xe3, - 0x0a, 0xbe, 0xc1, 0xff, 0xf9, 0xe3, 0xa2, 0x6e, 0x7f, 0xb2, 0x9f, 0x8c, 0x18, 0x30, 0x23, - 0xc3, 0x58, 0x7e, 0x38, 0xda, 0x00, 0x77, 0xd9, 0xb4, 0x76, 0x3e, 0x4e, 0x4b, 0x94, 0xb2, - 0xbb, 0xc1, 0x94, 0xc6, 0x65, 0x1e, 0x77, 0xca, 0xf9, 0x92, 0xee, 0xaa, 0xc0, 0x23, 0x2a, - 0x28, 0x1b, 0xf6, 0xb3, 0xa7, 0x39, 0xc1, 0x22, 0x61, 0x16, 0x82, 0x0a, 0xe8, 0xdb, 0x58, - 0x47, 0xa6, 0x7c, 0xbe, 0xf9, 0xc9, 0x09, 0x1b, 0x46, 0x2d, 0x53, 0x8c, 0xd7, 0x2b, 0x03, - 0x74, 0x6a, 0xe7, 0x7f, 0x5e, 0x62, 0x29, 0x2c, 0x31, 0x15, 0x62, 0xa8, 0x46, 0x50, 0x5d, - 0xc8, 0x2d, 0xb8, 0x54, 0x33, 0x8a, 0xe4, 0x9f, 0x52, 0x35, 0xc9, 0x5b, 0x91, 0x17, 0x8c, - 0xcf, 0x2d, 0xd5, 0xca, 0xce, 0xf4, 0x03, 0xec, 0x9d, 0x18, 0x10, 0xc6, 0x27, 0x2b, 0x04, - 0x5b, 0x3b, 0x71, 0xf9, 0xdc, 0x6b, 0x80, 0xd6, 0x3f, 0xdd, 0x4a, 0x8e, 0x9a, 0xdb, 0x1e, - 0x69, 0x62, 0xa6, 0x95, 0x26, 0xd4, 0x31, 0x61, 0xc1, 0xa4, 0x1d, 0x57, 0x0d, 0x79, 0x38, - 0xda, 0xd4, 0xa4, 0x0e, 0x32, 0x9c, 0xd0, 0xe4, 0x0e, 0x65, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, - ], - g: &[2], -}; - -/// FFDHE8192 group defined in [RFC 7919 Appendix A.5] -/// -/// [RFC 7919 Appendix A.5]: https://datatracker.ietf.org/doc/html/rfc7919#appendix-A.5 -pub const FFDHE8192: FfdheGroup<'static> = FfdheGroup { - p: &[ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xad, 0xf8, 0x54, 0x58, 0xa2, 0xbb, 0x4a, - 0x9a, 0xaf, 0xdc, 0x56, 0x20, 0x27, 0x3d, 0x3c, 0xf1, 0xd8, 0xb9, 0xc5, 0x83, 0xce, 0x2d, - 0x36, 0x95, 0xa9, 0xe1, 0x36, 0x41, 0x14, 0x64, 0x33, 0xfb, 0xcc, 0x93, 0x9d, 0xce, 0x24, - 0x9b, 0x3e, 0xf9, 0x7d, 0x2f, 0xe3, 0x63, 0x63, 0x0c, 0x75, 0xd8, 0xf6, 0x81, 0xb2, 0x02, - 0xae, 0xc4, 0x61, 0x7a, 0xd3, 0xdf, 0x1e, 0xd5, 0xd5, 0xfd, 0x65, 0x61, 0x24, 0x33, 0xf5, - 0x1f, 0x5f, 0x06, 0x6e, 0xd0, 0x85, 0x63, 0x65, 0x55, 0x3d, 0xed, 0x1a, 0xf3, 0xb5, 0x57, - 0x13, 0x5e, 0x7f, 0x57, 0xc9, 0x35, 0x98, 0x4f, 0x0c, 0x70, 0xe0, 0xe6, 0x8b, 0x77, 0xe2, - 0xa6, 0x89, 0xda, 0xf3, 0xef, 0xe8, 0x72, 0x1d, 0xf1, 0x58, 0xa1, 0x36, 0xad, 0xe7, 0x35, - 0x30, 0xac, 0xca, 0x4f, 0x48, 0x3a, 0x79, 0x7a, 0xbc, 0x0a, 0xb1, 0x82, 0xb3, 0x24, 0xfb, - 0x61, 0xd1, 0x08, 0xa9, 0x4b, 0xb2, 0xc8, 0xe3, 0xfb, 0xb9, 0x6a, 0xda, 0xb7, 0x60, 0xd7, - 0xf4, 0x68, 0x1d, 0x4f, 0x42, 0xa3, 0xde, 0x39, 0x4d, 0xf4, 0xae, 0x56, 0xed, 0xe7, 0x63, - 0x72, 0xbb, 0x19, 0x0b, 0x07, 0xa7, 0xc8, 0xee, 0x0a, 0x6d, 0x70, 0x9e, 0x02, 0xfc, 0xe1, - 0xcd, 0xf7, 0xe2, 0xec, 0xc0, 0x34, 0x04, 0xcd, 0x28, 0x34, 0x2f, 0x61, 0x91, 0x72, 0xfe, - 0x9c, 0xe9, 0x85, 0x83, 0xff, 0x8e, 0x4f, 0x12, 0x32, 0xee, 0xf2, 0x81, 0x83, 0xc3, 0xfe, - 0x3b, 0x1b, 0x4c, 0x6f, 0xad, 0x73, 0x3b, 0xb5, 0xfc, 0xbc, 0x2e, 0xc2, 0x20, 0x05, 0xc5, - 0x8e, 0xf1, 0x83, 0x7d, 0x16, 0x83, 0xb2, 0xc6, 0xf3, 0x4a, 0x26, 0xc1, 0xb2, 0xef, 0xfa, - 0x88, 0x6b, 0x42, 0x38, 0x61, 0x1f, 0xcf, 0xdc, 0xde, 0x35, 0x5b, 0x3b, 0x65, 0x19, 0x03, - 0x5b, 0xbc, 0x34, 0xf4, 0xde, 0xf9, 0x9c, 0x02, 0x38, 0x61, 0xb4, 0x6f, 0xc9, 0xd6, 0xe6, - 0xc9, 0x07, 0x7a, 0xd9, 0x1d, 0x26, 0x91, 0xf7, 0xf7, 0xee, 0x59, 0x8c, 0xb0, 0xfa, 0xc1, - 0x86, 0xd9, 0x1c, 0xae, 0xfe, 0x13, 0x09, 0x85, 0x13, 0x92, 0x70, 0xb4, 0x13, 0x0c, 0x93, - 0xbc, 0x43, 0x79, 0x44, 0xf4, 0xfd, 0x44, 0x52, 0xe2, 0xd7, 0x4d, 0xd3, 0x64, 0xf2, 0xe2, - 0x1e, 0x71, 0xf5, 0x4b, 0xff, 0x5c, 0xae, 0x82, 0xab, 0x9c, 0x9d, 0xf6, 0x9e, 0xe8, 0x6d, - 0x2b, 0xc5, 0x22, 0x36, 0x3a, 0x0d, 0xab, 0xc5, 0x21, 0x97, 0x9b, 0x0d, 0xea, 0xda, 0x1d, - 0xbf, 0x9a, 0x42, 0xd5, 0xc4, 0x48, 0x4e, 0x0a, 0xbc, 0xd0, 0x6b, 0xfa, 0x53, 0xdd, 0xef, - 0x3c, 0x1b, 0x20, 0xee, 0x3f, 0xd5, 0x9d, 0x7c, 0x25, 0xe4, 0x1d, 0x2b, 0x66, 0x9e, 0x1e, - 0xf1, 0x6e, 0x6f, 0x52, 0xc3, 0x16, 0x4d, 0xf4, 0xfb, 0x79, 0x30, 0xe9, 0xe4, 0xe5, 0x88, - 0x57, 0xb6, 0xac, 0x7d, 0x5f, 0x42, 0xd6, 0x9f, 0x6d, 0x18, 0x77, 0x63, 0xcf, 0x1d, 0x55, - 0x03, 0x40, 0x04, 0x87, 0xf5, 0x5b, 0xa5, 0x7e, 0x31, 0xcc, 0x7a, 0x71, 0x35, 0xc8, 0x86, - 0xef, 0xb4, 0x31, 0x8a, 0xed, 0x6a, 0x1e, 0x01, 0x2d, 0x9e, 0x68, 0x32, 0xa9, 0x07, 0x60, - 0x0a, 0x91, 0x81, 0x30, 0xc4, 0x6d, 0xc7, 0x78, 0xf9, 0x71, 0xad, 0x00, 0x38, 0x09, 0x29, - 0x99, 0xa3, 0x33, 0xcb, 0x8b, 0x7a, 0x1a, 0x1d, 0xb9, 0x3d, 0x71, 0x40, 0x00, 0x3c, 0x2a, - 0x4e, 0xce, 0xa9, 0xf9, 0x8d, 0x0a, 0xcc, 0x0a, 0x82, 0x91, 0xcd, 0xce, 0xc9, 0x7d, 0xcf, - 0x8e, 0xc9, 0xb5, 0x5a, 0x7f, 0x88, 0xa4, 0x6b, 0x4d, 0xb5, 0xa8, 0x51, 0xf4, 0x41, 0x82, - 0xe1, 0xc6, 0x8a, 0x00, 0x7e, 0x5e, 0x0d, 0xd9, 0x02, 0x0b, 0xfd, 0x64, 0xb6, 0x45, 0x03, - 0x6c, 0x7a, 0x4e, 0x67, 0x7d, 0x2c, 0x38, 0x53, 0x2a, 0x3a, 0x23, 0xba, 0x44, 0x42, 0xca, - 0xf5, 0x3e, 0xa6, 0x3b, 0xb4, 0x54, 0x32, 0x9b, 0x76, 0x24, 0xc8, 0x91, 0x7b, 0xdd, 0x64, - 0xb1, 0xc0, 0xfd, 0x4c, 0xb3, 0x8e, 0x8c, 0x33, 0x4c, 0x70, 0x1c, 0x3a, 0xcd, 0xad, 0x06, - 0x57, 0xfc, 0xcf, 0xec, 0x71, 0x9b, 0x1f, 0x5c, 0x3e, 0x4e, 0x46, 0x04, 0x1f, 0x38, 0x81, - 0x47, 0xfb, 0x4c, 0xfd, 0xb4, 0x77, 0xa5, 0x24, 0x71, 0xf7, 0xa9, 0xa9, 0x69, 0x10, 0xb8, - 0x55, 0x32, 0x2e, 0xdb, 0x63, 0x40, 0xd8, 0xa0, 0x0e, 0xf0, 0x92, 0x35, 0x05, 0x11, 0xe3, - 0x0a, 0xbe, 0xc1, 0xff, 0xf9, 0xe3, 0xa2, 0x6e, 0x7f, 0xb2, 0x9f, 0x8c, 0x18, 0x30, 0x23, - 0xc3, 0x58, 0x7e, 0x38, 0xda, 0x00, 0x77, 0xd9, 0xb4, 0x76, 0x3e, 0x4e, 0x4b, 0x94, 0xb2, - 0xbb, 0xc1, 0x94, 0xc6, 0x65, 0x1e, 0x77, 0xca, 0xf9, 0x92, 0xee, 0xaa, 0xc0, 0x23, 0x2a, - 0x28, 0x1b, 0xf6, 0xb3, 0xa7, 0x39, 0xc1, 0x22, 0x61, 0x16, 0x82, 0x0a, 0xe8, 0xdb, 0x58, - 0x47, 0xa6, 0x7c, 0xbe, 0xf9, 0xc9, 0x09, 0x1b, 0x46, 0x2d, 0x53, 0x8c, 0xd7, 0x2b, 0x03, - 0x74, 0x6a, 0xe7, 0x7f, 0x5e, 0x62, 0x29, 0x2c, 0x31, 0x15, 0x62, 0xa8, 0x46, 0x50, 0x5d, - 0xc8, 0x2d, 0xb8, 0x54, 0x33, 0x8a, 0xe4, 0x9f, 0x52, 0x35, 0xc9, 0x5b, 0x91, 0x17, 0x8c, - 0xcf, 0x2d, 0xd5, 0xca, 0xce, 0xf4, 0x03, 0xec, 0x9d, 0x18, 0x10, 0xc6, 0x27, 0x2b, 0x04, - 0x5b, 0x3b, 0x71, 0xf9, 0xdc, 0x6b, 0x80, 0xd6, 0x3f, 0xdd, 0x4a, 0x8e, 0x9a, 0xdb, 0x1e, - 0x69, 0x62, 0xa6, 0x95, 0x26, 0xd4, 0x31, 0x61, 0xc1, 0xa4, 0x1d, 0x57, 0x0d, 0x79, 0x38, - 0xda, 0xd4, 0xa4, 0x0e, 0x32, 0x9c, 0xcf, 0xf4, 0x6a, 0xaa, 0x36, 0xad, 0x00, 0x4c, 0xf6, - 0x00, 0xc8, 0x38, 0x1e, 0x42, 0x5a, 0x31, 0xd9, 0x51, 0xae, 0x64, 0xfd, 0xb2, 0x3f, 0xce, - 0xc9, 0x50, 0x9d, 0x43, 0x68, 0x7f, 0xeb, 0x69, 0xed, 0xd1, 0xcc, 0x5e, 0x0b, 0x8c, 0xc3, - 0xbd, 0xf6, 0x4b, 0x10, 0xef, 0x86, 0xb6, 0x31, 0x42, 0xa3, 0xab, 0x88, 0x29, 0x55, 0x5b, - 0x2f, 0x74, 0x7c, 0x93, 0x26, 0x65, 0xcb, 0x2c, 0x0f, 0x1c, 0xc0, 0x1b, 0xd7, 0x02, 0x29, - 0x38, 0x88, 0x39, 0xd2, 0xaf, 0x05, 0xe4, 0x54, 0x50, 0x4a, 0xc7, 0x8b, 0x75, 0x82, 0x82, - 0x28, 0x46, 0xc0, 0xba, 0x35, 0xc3, 0x5f, 0x5c, 0x59, 0x16, 0x0c, 0xc0, 0x46, 0xfd, 0x82, - 0x51, 0x54, 0x1f, 0xc6, 0x8c, 0x9c, 0x86, 0xb0, 0x22, 0xbb, 0x70, 0x99, 0x87, 0x6a, 0x46, - 0x0e, 0x74, 0x51, 0xa8, 0xa9, 0x31, 0x09, 0x70, 0x3f, 0xee, 0x1c, 0x21, 0x7e, 0x6c, 0x38, - 0x26, 0xe5, 0x2c, 0x51, 0xaa, 0x69, 0x1e, 0x0e, 0x42, 0x3c, 0xfc, 0x99, 0xe9, 0xe3, 0x16, - 0x50, 0xc1, 0x21, 0x7b, 0x62, 0x48, 0x16, 0xcd, 0xad, 0x9a, 0x95, 0xf9, 0xd5, 0xb8, 0x01, - 0x94, 0x88, 0xd9, 0xc0, 0xa0, 0xa1, 0xfe, 0x30, 0x75, 0xa5, 0x77, 0xe2, 0x31, 0x83, 0xf8, - 0x1d, 0x4a, 0x3f, 0x2f, 0xa4, 0x57, 0x1e, 0xfc, 0x8c, 0xe0, 0xba, 0x8a, 0x4f, 0xe8, 0xb6, - 0x85, 0x5d, 0xfe, 0x72, 0xb0, 0xa6, 0x6e, 0xde, 0xd2, 0xfb, 0xab, 0xfb, 0xe5, 0x8a, 0x30, - 0xfa, 0xfa, 0xbe, 0x1c, 0x5d, 0x71, 0xa8, 0x7e, 0x2f, 0x74, 0x1e, 0xf8, 0xc1, 0xfe, 0x86, - 0xfe, 0xa6, 0xbb, 0xfd, 0xe5, 0x30, 0x67, 0x7f, 0x0d, 0x97, 0xd1, 0x1d, 0x49, 0xf7, 0xa8, - 0x44, 0x3d, 0x08, 0x22, 0xe5, 0x06, 0xa9, 0xf4, 0x61, 0x4e, 0x01, 0x1e, 0x2a, 0x94, 0x83, - 0x8f, 0xf8, 0x8c, 0xd6, 0x8c, 0x8b, 0xb7, 0xc5, 0xc6, 0x42, 0x4c, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - ], - g: &[2], -}; - -#[test] -fn named_group_ffdhe_group_roundtrip() { - use NamedGroup::*; - let ffdhe_groups = [FFDHE2048, FFDHE3072, FFDHE4096, FFDHE6144, FFDHE8192]; - for g in ffdhe_groups { - #[allow(deprecated)] - let roundtrip = FfdheGroup::from_named_group(g) - .unwrap() - .named_group(); - assert_eq!(roundtrip, Some(g)); - } -} diff --git a/vendor/rustls/src/msgs/fragmenter.rs b/vendor/rustls/src/msgs/fragmenter.rs deleted file mode 100644 index 48636777..00000000 --- a/vendor/rustls/src/msgs/fragmenter.rs +++ /dev/null @@ -1,232 +0,0 @@ -use crate::Error; -use crate::enums::{ContentType, ProtocolVersion}; -use crate::msgs::message::{OutboundChunks, OutboundPlainMessage, PlainMessage}; -pub(crate) const MAX_FRAGMENT_LEN: usize = 16384; -pub(crate) const PACKET_OVERHEAD: usize = 1 + 2 + 2; -pub(crate) const MAX_FRAGMENT_SIZE: usize = MAX_FRAGMENT_LEN + PACKET_OVERHEAD; - -pub struct MessageFragmenter { - max_frag: usize, -} - -impl Default for MessageFragmenter { - fn default() -> Self { - Self { - max_frag: MAX_FRAGMENT_LEN, - } - } -} - -impl MessageFragmenter { - /// Take `msg` and fragment it into new messages with the same type and version. - /// - /// Each returned message size is no more than `max_frag`. - /// - /// Return an iterator across those messages. - /// - /// Payloads are borrowed from `msg`. - pub fn fragment_message<'a>( - &self, - msg: &'a PlainMessage, - ) -> impl Iterator<Item = OutboundPlainMessage<'a>> + 'a { - self.fragment_payload(msg.typ, msg.version, msg.payload.bytes().into()) - } - - /// Take `payload` and fragment it into new messages with given type and version. - /// - /// Each returned message size is no more than `max_frag`. - /// - /// Return an iterator across those messages. - /// - /// Payloads are borrowed from `payload`. - pub(crate) fn fragment_payload<'a>( - &self, - typ: ContentType, - version: ProtocolVersion, - payload: OutboundChunks<'a>, - ) -> impl ExactSizeIterator<Item = OutboundPlainMessage<'a>> { - Chunker::new(payload, self.max_frag).map(move |payload| OutboundPlainMessage { - typ, - version, - payload, - }) - } - - /// Set the maximum fragment size that will be produced. - /// - /// This includes overhead. A `max_fragment_size` of 10 will produce TLS fragments - /// up to 10 bytes long. - /// - /// A `max_fragment_size` of `None` sets the highest allowable fragment size. - /// - /// Returns BadMaxFragmentSize if the size is smaller than 32 or larger than 16389. - pub fn set_max_fragment_size(&mut self, max_fragment_size: Option<usize>) -> Result<(), Error> { - self.max_frag = match max_fragment_size { - Some(sz @ 32..=MAX_FRAGMENT_SIZE) => sz - PACKET_OVERHEAD, - None => MAX_FRAGMENT_LEN, - _ => return Err(Error::BadMaxFragmentSize), - }; - Ok(()) - } -} - -/// An iterator over borrowed fragments of a payload -struct Chunker<'a> { - payload: OutboundChunks<'a>, - limit: usize, -} - -impl<'a> Chunker<'a> { - fn new(payload: OutboundChunks<'a>, limit: usize) -> Self { - Self { payload, limit } - } -} - -impl<'a> Iterator for Chunker<'a> { - type Item = OutboundChunks<'a>; - - fn next(&mut self) -> Option<Self::Item> { - if self.payload.is_empty() { - return None; - } - - let (before, after) = self.payload.split_at(self.limit); - self.payload = after; - Some(before) - } -} - -impl ExactSizeIterator for Chunker<'_> { - fn len(&self) -> usize { - (self.payload.len() + self.limit - 1) / self.limit - } -} - -#[cfg(test)] -mod tests { - use std::prelude::v1::*; - use std::vec; - - use super::{MessageFragmenter, PACKET_OVERHEAD}; - use crate::enums::{ContentType, ProtocolVersion}; - use crate::msgs::base::Payload; - use crate::msgs::message::{OutboundChunks, OutboundPlainMessage, PlainMessage}; - - fn msg_eq( - m: &OutboundPlainMessage<'_>, - total_len: usize, - typ: &ContentType, - version: &ProtocolVersion, - bytes: &[u8], - ) { - assert_eq!(&m.typ, typ); - assert_eq!(&m.version, version); - assert_eq!(m.payload.to_vec(), bytes); - - let buf = m.to_unencrypted_opaque().encode(); - - assert_eq!(total_len, buf.len()); - } - - #[test] - fn smoke() { - let typ = ContentType::Handshake; - let version = ProtocolVersion::TLSv1_2; - let data: Vec<u8> = (1..70u8).collect(); - let m = PlainMessage { - typ, - version, - payload: Payload::new(data), - }; - - let mut frag = MessageFragmenter::default(); - frag.set_max_fragment_size(Some(32)) - .unwrap(); - let q = frag - .fragment_message(&m) - .collect::<Vec<_>>(); - assert_eq!(q.len(), 3); - msg_eq( - &q[0], - 32, - &typ, - &version, - &[ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, - ], - ); - msg_eq( - &q[1], - 32, - &typ, - &version, - &[ - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, - ], - ); - msg_eq( - &q[2], - 20, - &typ, - &version, - &[55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69], - ); - } - - #[test] - fn non_fragment() { - let m = PlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_2, - payload: Payload::new(b"\x01\x02\x03\x04\x05\x06\x07\x08".to_vec()), - }; - - let mut frag = MessageFragmenter::default(); - frag.set_max_fragment_size(Some(32)) - .unwrap(); - let q = frag - .fragment_message(&m) - .collect::<Vec<_>>(); - assert_eq!(q.len(), 1); - msg_eq( - &q[0], - PACKET_OVERHEAD + 8, - &ContentType::Handshake, - &ProtocolVersion::TLSv1_2, - b"\x01\x02\x03\x04\x05\x06\x07\x08", - ); - } - - #[test] - fn fragment_multiple_slices() { - let typ = ContentType::Handshake; - let version = ProtocolVersion::TLSv1_2; - let payload_owner: Vec<&[u8]> = vec![&[b'a'; 8], &[b'b'; 12], &[b'c'; 32], &[b'd'; 20]]; - let borrowed_payload = OutboundChunks::new(&payload_owner); - let mut frag = MessageFragmenter::default(); - frag.set_max_fragment_size(Some(37)) // 32 + packet overhead - .unwrap(); - - let fragments = frag - .fragment_payload(typ, version, borrowed_payload) - .collect::<Vec<_>>(); - assert_eq!(fragments.len(), 3); - msg_eq( - &fragments[0], - 37, - &typ, - &version, - b"aaaaaaaabbbbbbbbbbbbcccccccccccc", - ); - msg_eq( - &fragments[1], - 37, - &typ, - &version, - b"ccccccccccccccccccccdddddddddddd", - ); - msg_eq(&fragments[2], 13, &typ, &version, b"dddddddd"); - } -} diff --git a/vendor/rustls/src/msgs/handshake.rs b/vendor/rustls/src/msgs/handshake.rs deleted file mode 100644 index 093f2d12..00000000 --- a/vendor/rustls/src/msgs/handshake.rs +++ /dev/null @@ -1,3210 +0,0 @@ -use alloc::boxed::Box; -use alloc::collections::BTreeSet; -#[cfg(feature = "logging")] -use alloc::string::String; -use alloc::vec; -use alloc::vec::Vec; -use core::ops::{Deref, DerefMut}; -use core::{fmt, iter}; - -use pki_types::{CertificateDer, DnsName}; - -#[cfg(feature = "tls12")] -use crate::crypto::ActiveKeyExchange; -use crate::crypto::SecureRandom; -use crate::enums::{ - CertificateCompressionAlgorithm, CertificateType, CipherSuite, EchClientHelloType, - HandshakeType, ProtocolVersion, SignatureScheme, -}; -use crate::error::InvalidMessage; -#[cfg(feature = "tls12")] -use crate::ffdhe_groups::FfdheGroup; -use crate::log::warn; -use crate::msgs::base::{MaybeEmpty, NonEmpty, Payload, PayloadU8, PayloadU16, PayloadU24}; -use crate::msgs::codec::{ - self, Codec, LengthPrefixedBuffer, ListLength, Reader, TlsListElement, TlsListIter, -}; -use crate::msgs::enums::{ - CertificateStatusType, ClientCertificateType, Compression, ECCurveType, ECPointFormat, - EchVersion, ExtensionType, HpkeAead, HpkeKdf, HpkeKem, KeyUpdateRequest, NamedGroup, - PskKeyExchangeMode, ServerNameType, -}; -use crate::rand; -use crate::sync::Arc; -use crate::verify::DigitallySignedStruct; -use crate::x509::wrap_in_sequence; - -/// Create a newtype wrapper around a given type. -/// -/// This is used to create newtypes for the various TLS message types which is used to wrap -/// the `PayloadU8` or `PayloadU16` types. This is typically used for types where we don't need -/// anything other than access to the underlying bytes. -macro_rules! wrapped_payload( - ($(#[$comment:meta])* $vis:vis struct $name:ident, $inner:ident$(<$inner_ty:ty>)?,) => { - $(#[$comment])* - #[derive(Clone, Debug)] - $vis struct $name($inner$(<$inner_ty>)?); - - impl From<Vec<u8>> for $name { - fn from(v: Vec<u8>) -> Self { - Self($inner::new(v)) - } - } - - impl AsRef<[u8]> for $name { - fn as_ref(&self) -> &[u8] { - self.0.0.as_slice() - } - } - - impl Codec<'_> for $name { - fn encode(&self, bytes: &mut Vec<u8>) { - self.0.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self($inner::read(r)?)) - } - } - } -); - -#[derive(Clone, Copy, Eq, PartialEq)] -pub(crate) struct Random(pub(crate) [u8; 32]); - -impl fmt::Debug for Random { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - super::base::hex(f, &self.0) - } -} - -static HELLO_RETRY_REQUEST_RANDOM: Random = Random([ - 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91, - 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c, -]); - -static ZERO_RANDOM: Random = Random([0u8; 32]); - -impl Codec<'_> for Random { - fn encode(&self, bytes: &mut Vec<u8>) { - bytes.extend_from_slice(&self.0); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let Some(bytes) = r.take(32) else { - return Err(InvalidMessage::MissingData("Random")); - }; - - let mut opaque = [0; 32]; - opaque.clone_from_slice(bytes); - Ok(Self(opaque)) - } -} - -impl Random { - pub(crate) fn new(secure_random: &dyn SecureRandom) -> Result<Self, rand::GetRandomFailed> { - let mut data = [0u8; 32]; - secure_random.fill(&mut data)?; - Ok(Self(data)) - } -} - -impl From<[u8; 32]> for Random { - #[inline] - fn from(bytes: [u8; 32]) -> Self { - Self(bytes) - } -} - -#[derive(Copy, Clone)] -pub(crate) struct SessionId { - len: usize, - data: [u8; 32], -} - -impl fmt::Debug for SessionId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - super::base::hex(f, &self.data[..self.len]) - } -} - -impl PartialEq for SessionId { - fn eq(&self, other: &Self) -> bool { - if self.len != other.len { - return false; - } - - let mut diff = 0u8; - for i in 0..self.len { - diff |= self.data[i] ^ other.data[i]; - } - - diff == 0u8 - } -} - -impl Codec<'_> for SessionId { - fn encode(&self, bytes: &mut Vec<u8>) { - debug_assert!(self.len <= 32); - bytes.push(self.len as u8); - bytes.extend_from_slice(self.as_ref()); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let len = u8::read(r)? as usize; - if len > 32 { - return Err(InvalidMessage::TrailingData("SessionID")); - } - - let Some(bytes) = r.take(len) else { - return Err(InvalidMessage::MissingData("SessionID")); - }; - - let mut out = [0u8; 32]; - out[..len].clone_from_slice(&bytes[..len]); - Ok(Self { data: out, len }) - } -} - -impl SessionId { - pub(crate) fn random(secure_random: &dyn SecureRandom) -> Result<Self, rand::GetRandomFailed> { - let mut data = [0u8; 32]; - secure_random.fill(&mut data)?; - Ok(Self { data, len: 32 }) - } - - pub(crate) fn empty() -> Self { - Self { - data: [0u8; 32], - len: 0, - } - } - - #[cfg(feature = "tls12")] - pub(crate) fn is_empty(&self) -> bool { - self.len == 0 - } -} - -impl AsRef<[u8]> for SessionId { - fn as_ref(&self) -> &[u8] { - &self.data[..self.len] - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct UnknownExtension { - pub(crate) typ: ExtensionType, - pub(crate) payload: Payload<'static>, -} - -impl UnknownExtension { - fn encode(&self, bytes: &mut Vec<u8>) { - self.payload.encode(bytes); - } - - fn read(typ: ExtensionType, r: &mut Reader<'_>) -> Self { - let payload = Payload::read(r).into_owned(); - Self { typ, payload } - } -} - -#[derive(Clone, Copy, Debug)] -pub(crate) struct SupportedEcPointFormats { - pub(crate) uncompressed: bool, -} - -impl Codec<'_> for SupportedEcPointFormats { - fn encode(&self, bytes: &mut Vec<u8>) { - let inner = LengthPrefixedBuffer::new(ECPointFormat::SIZE_LEN, bytes); - - if self.uncompressed { - ECPointFormat::Uncompressed.encode(inner.buf); - } - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let mut uncompressed = false; - - for pf in TlsListIter::<ECPointFormat>::new(r)? { - if let ECPointFormat::Uncompressed = pf? { - uncompressed = true; - } - } - - Ok(Self { uncompressed }) - } -} - -impl Default for SupportedEcPointFormats { - fn default() -> Self { - Self { uncompressed: true } - } -} - -/// RFC8422: `ECPointFormat ec_point_format_list<1..2^8-1>` -impl TlsListElement for ECPointFormat { - const SIZE_LEN: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("ECPointFormats"), - }; -} - -/// RFC8422: `NamedCurve named_curve_list<2..2^16-1>` -impl TlsListElement for NamedGroup { - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::IllegalEmptyList("NamedGroups"), - }; -} - -/// RFC8446: `SignatureScheme supported_signature_algorithms<2..2^16-2>;` -impl TlsListElement for SignatureScheme { - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::NoSignatureSchemes, - }; -} - -#[derive(Clone, Debug)] -pub(crate) enum ServerNamePayload<'a> { - /// A successfully decoded value: - SingleDnsName(DnsName<'a>), - - /// A DNS name which was actually an IP address - IpAddress, - - /// A successfully decoded, but syntactically-invalid value. - Invalid, -} - -impl ServerNamePayload<'_> { - fn into_owned(self) -> ServerNamePayload<'static> { - match self { - Self::SingleDnsName(d) => ServerNamePayload::SingleDnsName(d.to_owned()), - Self::IpAddress => ServerNamePayload::IpAddress, - Self::Invalid => ServerNamePayload::Invalid, - } - } - - /// RFC6066: `ServerName server_name_list<1..2^16-1>` - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::IllegalEmptyList("ServerNames"), - }; -} - -/// Simplified encoding/decoding for a `ServerName` extension payload to/from `DnsName` -/// -/// This is possible because: -/// -/// - the spec (RFC6066) disallows multiple names for a given name type -/// - name types other than ServerNameType::HostName are not defined, and they and -/// any data that follows them cannot be skipped over. -impl<'a> Codec<'a> for ServerNamePayload<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - let server_name_list = LengthPrefixedBuffer::new(Self::SIZE_LEN, bytes); - - let ServerNamePayload::SingleDnsName(dns_name) = self else { - return; - }; - - ServerNameType::HostName.encode(server_name_list.buf); - let name_slice = dns_name.as_ref().as_bytes(); - (name_slice.len() as u16).encode(server_name_list.buf); - server_name_list - .buf - .extend_from_slice(name_slice); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let mut found = None; - - let len = Self::SIZE_LEN.read(r)?; - let mut sub = r.sub(len)?; - - while sub.any_left() { - let typ = ServerNameType::read(&mut sub)?; - - let payload = match typ { - ServerNameType::HostName => HostNamePayload::read(&mut sub)?, - _ => { - // Consume remainder of extension bytes. Since the length of the item - // is an unknown encoding, we cannot continue. - sub.rest(); - break; - } - }; - - // "The ServerNameList MUST NOT contain more than one name of - // the same name_type." - RFC6066 - if found.is_some() { - warn!("Illegal SNI extension: duplicate host_name received"); - return Err(InvalidMessage::InvalidServerName); - } - - found = match payload { - HostNamePayload::HostName(dns_name) => { - Some(Self::SingleDnsName(dns_name.to_owned())) - } - - HostNamePayload::IpAddress(_invalid) => { - warn!( - "Illegal SNI extension: ignoring IP address presented as hostname ({_invalid:?})" - ); - Some(Self::IpAddress) - } - - HostNamePayload::Invalid(_invalid) => { - warn!( - "Illegal SNI hostname received {:?}", - String::from_utf8_lossy(&_invalid.0) - ); - Some(Self::Invalid) - } - }; - } - - Ok(found.unwrap_or(Self::Invalid)) - } -} - -impl<'a> From<&DnsName<'a>> for ServerNamePayload<'static> { - fn from(value: &DnsName<'a>) -> Self { - Self::SingleDnsName(trim_hostname_trailing_dot_for_sni(value)) - } -} - -#[derive(Clone, Debug)] -pub(crate) enum HostNamePayload { - HostName(DnsName<'static>), - IpAddress(PayloadU16<NonEmpty>), - Invalid(PayloadU16<NonEmpty>), -} - -impl HostNamePayload { - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - use pki_types::ServerName; - let raw = PayloadU16::<NonEmpty>::read(r)?; - - match ServerName::try_from(raw.0.as_slice()) { - Ok(ServerName::DnsName(d)) => Ok(Self::HostName(d.to_owned())), - Ok(ServerName::IpAddress(_)) => Ok(Self::IpAddress(raw)), - Ok(_) | Err(_) => Ok(Self::Invalid(raw)), - } - } -} - -wrapped_payload!( - /// RFC7301: `opaque ProtocolName<1..2^8-1>;` - pub(crate) struct ProtocolName, PayloadU8<NonEmpty>, -); - -impl PartialEq for ProtocolName { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl Deref for ProtocolName { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - self.as_ref() - } -} - -/// RFC7301: `ProtocolName protocol_name_list<2..2^16-1>` -impl TlsListElement for ProtocolName { - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::IllegalEmptyList("ProtocolNames"), - }; -} - -/// RFC7301 encodes a single protocol name as `Vec<ProtocolName>` -#[derive(Clone, Debug)] -pub(crate) struct SingleProtocolName(ProtocolName); - -impl SingleProtocolName { - pub(crate) fn new(single: ProtocolName) -> Self { - Self(single) - } - - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::IllegalEmptyList("ProtocolNames"), - }; -} - -impl Codec<'_> for SingleProtocolName { - fn encode(&self, bytes: &mut Vec<u8>) { - let body = LengthPrefixedBuffer::new(Self::SIZE_LEN, bytes); - self.0.encode(body.buf); - } - - fn read(reader: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let len = Self::SIZE_LEN.read(reader)?; - let mut sub = reader.sub(len)?; - - let item = ProtocolName::read(&mut sub)?; - - if sub.any_left() { - Err(InvalidMessage::TrailingData("SingleProtocolName")) - } else { - Ok(Self(item)) - } - } -} - -impl AsRef<ProtocolName> for SingleProtocolName { - fn as_ref(&self) -> &ProtocolName { - &self.0 - } -} - -// --- TLS 1.3 Key shares --- -#[derive(Clone, Debug)] -pub(crate) struct KeyShareEntry { - pub(crate) group: NamedGroup, - /// RFC8446: `opaque key_exchange<1..2^16-1>;` - pub(crate) payload: PayloadU16<NonEmpty>, -} - -impl KeyShareEntry { - pub(crate) fn new(group: NamedGroup, payload: impl Into<Vec<u8>>) -> Self { - Self { - group, - payload: PayloadU16::new(payload.into()), - } - } -} - -impl Codec<'_> for KeyShareEntry { - fn encode(&self, bytes: &mut Vec<u8>) { - self.group.encode(bytes); - self.payload.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let group = NamedGroup::read(r)?; - let payload = PayloadU16::read(r)?; - - Ok(Self { group, payload }) - } -} - -// --- TLS 1.3 PresharedKey offers --- -#[derive(Clone, Debug)] -pub(crate) struct PresharedKeyIdentity { - /// RFC8446: `opaque identity<1..2^16-1>;` - pub(crate) identity: PayloadU16<NonEmpty>, - pub(crate) obfuscated_ticket_age: u32, -} - -impl PresharedKeyIdentity { - pub(crate) fn new(id: Vec<u8>, age: u32) -> Self { - Self { - identity: PayloadU16::new(id), - obfuscated_ticket_age: age, - } - } -} - -impl Codec<'_> for PresharedKeyIdentity { - fn encode(&self, bytes: &mut Vec<u8>) { - self.identity.encode(bytes); - self.obfuscated_ticket_age.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - identity: PayloadU16::read(r)?, - obfuscated_ticket_age: u32::read(r)?, - }) - } -} - -/// RFC8446: `PskIdentity identities<7..2^16-1>;` -impl TlsListElement for PresharedKeyIdentity { - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::IllegalEmptyList("PskIdentities"), - }; -} - -wrapped_payload!( - /// RFC8446: `opaque PskBinderEntry<32..255>;` - pub(crate) struct PresharedKeyBinder, PayloadU8<NonEmpty>, -); - -/// RFC8446: `PskBinderEntry binders<33..2^16-1>;` -impl TlsListElement for PresharedKeyBinder { - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::IllegalEmptyList("PskBinders"), - }; -} - -#[derive(Clone, Debug)] -pub(crate) struct PresharedKeyOffer { - pub(crate) identities: Vec<PresharedKeyIdentity>, - pub(crate) binders: Vec<PresharedKeyBinder>, -} - -impl PresharedKeyOffer { - /// Make a new one with one entry. - pub(crate) fn new(id: PresharedKeyIdentity, binder: Vec<u8>) -> Self { - Self { - identities: vec![id], - binders: vec![PresharedKeyBinder::from(binder)], - } - } -} - -impl Codec<'_> for PresharedKeyOffer { - fn encode(&self, bytes: &mut Vec<u8>) { - self.identities.encode(bytes); - self.binders.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - identities: Vec::read(r)?, - binders: Vec::read(r)?, - }) - } -} - -// --- RFC6066 certificate status request --- -wrapped_payload!(pub(crate) struct ResponderId, PayloadU16,); - -/// RFC6066: `ResponderID responder_id_list<0..2^16-1>;` -impl TlsListElement for ResponderId { - const SIZE_LEN: ListLength = ListLength::U16; -} - -#[derive(Clone, Debug)] -pub(crate) struct OcspCertificateStatusRequest { - pub(crate) responder_ids: Vec<ResponderId>, - pub(crate) extensions: PayloadU16, -} - -impl Codec<'_> for OcspCertificateStatusRequest { - fn encode(&self, bytes: &mut Vec<u8>) { - CertificateStatusType::OCSP.encode(bytes); - self.responder_ids.encode(bytes); - self.extensions.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - responder_ids: Vec::read(r)?, - extensions: PayloadU16::read(r)?, - }) - } -} - -#[derive(Clone, Debug)] -pub(crate) enum CertificateStatusRequest { - Ocsp(OcspCertificateStatusRequest), - Unknown((CertificateStatusType, Payload<'static>)), -} - -impl Codec<'_> for CertificateStatusRequest { - fn encode(&self, bytes: &mut Vec<u8>) { - match self { - Self::Ocsp(r) => r.encode(bytes), - Self::Unknown((typ, payload)) => { - typ.encode(bytes); - payload.encode(bytes); - } - } - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let typ = CertificateStatusType::read(r)?; - - match typ { - CertificateStatusType::OCSP => { - let ocsp_req = OcspCertificateStatusRequest::read(r)?; - Ok(Self::Ocsp(ocsp_req)) - } - _ => { - let data = Payload::read(r).into_owned(); - Ok(Self::Unknown((typ, data))) - } - } - } -} - -impl CertificateStatusRequest { - pub(crate) fn build_ocsp() -> Self { - let ocsp = OcspCertificateStatusRequest { - responder_ids: Vec::new(), - extensions: PayloadU16::empty(), - }; - Self::Ocsp(ocsp) - } -} - -// --- - -/// RFC8446: `PskKeyExchangeMode ke_modes<1..255>;` -#[derive(Clone, Copy, Debug, Default)] -pub(crate) struct PskKeyExchangeModes { - pub(crate) psk_dhe: bool, - pub(crate) psk: bool, -} - -impl Codec<'_> for PskKeyExchangeModes { - fn encode(&self, bytes: &mut Vec<u8>) { - let inner = LengthPrefixedBuffer::new(PskKeyExchangeMode::SIZE_LEN, bytes); - if self.psk_dhe { - PskKeyExchangeMode::PSK_DHE_KE.encode(inner.buf); - } - if self.psk { - PskKeyExchangeMode::PSK_KE.encode(inner.buf); - } - } - - fn read(reader: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let mut psk_dhe = false; - let mut psk = false; - - for ke in TlsListIter::<PskKeyExchangeMode>::new(reader)? { - match ke? { - PskKeyExchangeMode::PSK_DHE_KE => psk_dhe = true, - PskKeyExchangeMode::PSK_KE => psk = true, - _ => continue, - }; - } - - Ok(Self { psk_dhe, psk }) - } -} - -impl TlsListElement for PskKeyExchangeMode { - const SIZE_LEN: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("PskKeyExchangeModes"), - }; -} - -/// RFC8446: `KeyShareEntry client_shares<0..2^16-1>;` -impl TlsListElement for KeyShareEntry { - const SIZE_LEN: ListLength = ListLength::U16; -} - -/// The body of the `SupportedVersions` extension when it appears in a -/// `ClientHello` -/// -/// This is documented as a preference-order vector, but we (as a server) -/// ignore the preference of the client. -/// -/// RFC8446: `ProtocolVersion versions<2..254>;` -#[derive(Clone, Copy, Debug, Default)] -pub(crate) struct SupportedProtocolVersions { - pub(crate) tls13: bool, - pub(crate) tls12: bool, -} - -impl SupportedProtocolVersions { - /// Return true if `filter` returns true for any enabled version. - pub(crate) fn any(&self, filter: impl Fn(ProtocolVersion) -> bool) -> bool { - if self.tls13 && filter(ProtocolVersion::TLSv1_3) { - return true; - } - if self.tls12 && filter(ProtocolVersion::TLSv1_2) { - return true; - } - false - } - - const LIST_LENGTH: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("ProtocolVersions"), - }; -} - -impl Codec<'_> for SupportedProtocolVersions { - fn encode(&self, bytes: &mut Vec<u8>) { - let inner = LengthPrefixedBuffer::new(Self::LIST_LENGTH, bytes); - if self.tls13 { - ProtocolVersion::TLSv1_3.encode(inner.buf); - } - if self.tls12 { - ProtocolVersion::TLSv1_2.encode(inner.buf); - } - } - - fn read(reader: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let mut tls12 = false; - let mut tls13 = false; - - for pv in TlsListIter::<ProtocolVersion>::new(reader)? { - match pv? { - ProtocolVersion::TLSv1_3 => tls13 = true, - ProtocolVersion::TLSv1_2 => tls12 = true, - _ => continue, - }; - } - - Ok(Self { tls13, tls12 }) - } -} - -impl TlsListElement for ProtocolVersion { - const SIZE_LEN: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("ProtocolVersions"), - }; -} - -/// RFC7250: `CertificateType client_certificate_types<1..2^8-1>;` -/// -/// Ditto `CertificateType server_certificate_types<1..2^8-1>;` -impl TlsListElement for CertificateType { - const SIZE_LEN: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("CertificateTypes"), - }; -} - -/// RFC8879: `CertificateCompressionAlgorithm algorithms<2..2^8-2>;` -impl TlsListElement for CertificateCompressionAlgorithm { - const SIZE_LEN: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("CertificateCompressionAlgorithms"), - }; -} - -/// A precursor to `ClientExtensions`, allowing customisation. -/// -/// This is smaller than `ClientExtensions`, as it only contains the extensions -/// we need to vary between different protocols (eg, TCP-TLS versus QUIC). -#[derive(Clone, Default)] -pub(crate) struct ClientExtensionsInput<'a> { - /// QUIC transport parameters - pub(crate) transport_parameters: Option<TransportParameters<'a>>, - - /// ALPN protocols - pub(crate) protocols: Option<Vec<ProtocolName>>, -} - -impl ClientExtensionsInput<'_> { - pub(crate) fn from_alpn(alpn_protocols: Vec<Vec<u8>>) -> ClientExtensionsInput<'static> { - let protocols = match alpn_protocols.is_empty() { - true => None, - false => Some( - alpn_protocols - .into_iter() - .map(ProtocolName::from) - .collect::<Vec<_>>(), - ), - }; - - ClientExtensionsInput { - transport_parameters: None, - protocols, - } - } - - pub(crate) fn into_owned(self) -> ClientExtensionsInput<'static> { - let Self { - transport_parameters, - protocols, - } = self; - ClientExtensionsInput { - transport_parameters: transport_parameters.map(|x| x.into_owned()), - protocols, - } - } -} - -#[derive(Clone)] -pub(crate) enum TransportParameters<'a> { - /// QUIC transport parameters (RFC9001 prior to draft 33) - QuicDraft(Payload<'a>), - - /// QUIC transport parameters (RFC9001) - Quic(Payload<'a>), -} - -impl TransportParameters<'_> { - pub(crate) fn into_owned(self) -> TransportParameters<'static> { - match self { - Self::QuicDraft(v) => TransportParameters::QuicDraft(v.into_owned()), - Self::Quic(v) => TransportParameters::Quic(v.into_owned()), - } - } -} - -extension_struct! { - /// A representation of extensions present in a `ClientHello` message - /// - /// All extensions are optional (by definition) so are represented with `Option<T>`. - /// - /// Some extensions have an empty value and are represented with Option<()>. - /// - /// Unknown extensions are dropped during parsing. - pub(crate) struct ClientExtensions<'a> { - /// Requested server name indication (RFC6066) - ExtensionType::ServerName => - pub(crate) server_name: Option<ServerNamePayload<'a>>, - - /// Certificate status is requested (RFC6066) - ExtensionType::StatusRequest => - pub(crate) certificate_status_request: Option<CertificateStatusRequest>, - - /// Supported groups (RFC4492/RFC8446) - ExtensionType::EllipticCurves => - pub(crate) named_groups: Option<Vec<NamedGroup>>, - - /// Supported EC point formats (RFC4492) - ExtensionType::ECPointFormats => - pub(crate) ec_point_formats: Option<SupportedEcPointFormats>, - - /// Supported signature schemes (RFC5246/RFC8446) - ExtensionType::SignatureAlgorithms => - pub(crate) signature_schemes: Option<Vec<SignatureScheme>>, - - /// Offered ALPN protocols (RFC6066) - ExtensionType::ALProtocolNegotiation => - pub(crate) protocols: Option<Vec<ProtocolName>>, - - /// Available client certificate types (RFC7250) - ExtensionType::ClientCertificateType => - pub(crate) client_certificate_types: Option<Vec<CertificateType>>, - - /// Acceptable server certificate types (RFC7250) - ExtensionType::ServerCertificateType => - pub(crate) server_certificate_types: Option<Vec<CertificateType>>, - - /// Extended master secret is requested (RFC7627) - ExtensionType::ExtendedMasterSecret => - pub(crate) extended_master_secret_request: Option<()>, - - /// Offered certificate compression methods (RFC8879) - ExtensionType::CompressCertificate => - pub(crate) certificate_compression_algorithms: Option<Vec<CertificateCompressionAlgorithm>>, - - /// Session ticket offer or request (RFC5077/RFC8446) - ExtensionType::SessionTicket => - pub(crate) session_ticket: Option<ClientSessionTicket>, - - /// Offered preshared keys (RFC8446) - ExtensionType::PreSharedKey => - pub(crate) preshared_key_offer: Option<PresharedKeyOffer>, - - /// Early data is requested (RFC8446) - ExtensionType::EarlyData => - pub(crate) early_data_request: Option<()>, - - /// Supported TLS versions (RFC8446) - ExtensionType::SupportedVersions => - pub(crate) supported_versions: Option<SupportedProtocolVersions>, - - /// Stateless HelloRetryRequest cookie (RFC8446) - ExtensionType::Cookie => - pub(crate) cookie: Option<PayloadU16<NonEmpty>>, - - /// Offered preshared key modes (RFC8446) - ExtensionType::PSKKeyExchangeModes => - pub(crate) preshared_key_modes: Option<PskKeyExchangeModes>, - - /// Certificate authority names (RFC8446) - ExtensionType::CertificateAuthorities => - pub(crate) certificate_authority_names: Option<Vec<DistinguishedName>>, - - /// Offered key exchange shares (RFC8446) - ExtensionType::KeyShare => - pub(crate) key_shares: Option<Vec<KeyShareEntry>>, - - /// QUIC transport parameters (RFC9001) - ExtensionType::TransportParameters => - pub(crate) transport_parameters: Option<Payload<'a>>, - - /// Secure renegotiation (RFC5746) - ExtensionType::RenegotiationInfo => - pub(crate) renegotiation_info: Option<PayloadU8>, - - /// QUIC transport parameters (RFC9001 prior to draft 33) - ExtensionType::TransportParametersDraft => - pub(crate) transport_parameters_draft: Option<Payload<'a>>, - - /// Encrypted inner client hello (draft-ietf-tls-esni) - ExtensionType::EncryptedClientHello => - pub(crate) encrypted_client_hello: Option<EncryptedClientHello>, - - /// Encrypted client hello outer extensions (draft-ietf-tls-esni) - ExtensionType::EncryptedClientHelloOuterExtensions => - pub(crate) encrypted_client_hello_outer: Option<Vec<ExtensionType>>, - } + { - /// Order randomization seed. - pub(crate) order_seed: u16, - - /// Extensions that must appear contiguously. - pub(crate) contiguous_extensions: Vec<ExtensionType>, - } -} - -impl ClientExtensions<'_> { - pub(crate) fn into_owned(self) -> ClientExtensions<'static> { - let Self { - server_name, - certificate_status_request, - named_groups, - ec_point_formats, - signature_schemes, - protocols, - client_certificate_types, - server_certificate_types, - extended_master_secret_request, - certificate_compression_algorithms, - session_ticket, - preshared_key_offer, - early_data_request, - supported_versions, - cookie, - preshared_key_modes, - certificate_authority_names, - key_shares, - transport_parameters, - renegotiation_info, - transport_parameters_draft, - encrypted_client_hello, - encrypted_client_hello_outer, - order_seed, - contiguous_extensions, - } = self; - ClientExtensions { - server_name: server_name.map(|x| x.into_owned()), - certificate_status_request, - named_groups, - ec_point_formats, - signature_schemes, - protocols, - client_certificate_types, - server_certificate_types, - extended_master_secret_request, - certificate_compression_algorithms, - session_ticket, - preshared_key_offer, - early_data_request, - supported_versions, - cookie, - preshared_key_modes, - certificate_authority_names, - key_shares, - transport_parameters: transport_parameters.map(|x| x.into_owned()), - renegotiation_info, - transport_parameters_draft: transport_parameters_draft.map(|x| x.into_owned()), - encrypted_client_hello, - encrypted_client_hello_outer, - order_seed, - contiguous_extensions, - } - } - - pub(crate) fn used_extensions_in_encoding_order(&self) -> Vec<ExtensionType> { - let mut exts = self.order_insensitive_extensions_in_random_order(); - exts.extend(&self.contiguous_extensions); - - if self - .encrypted_client_hello_outer - .is_some() - { - exts.push(ExtensionType::EncryptedClientHelloOuterExtensions); - } - if self.encrypted_client_hello.is_some() { - exts.push(ExtensionType::EncryptedClientHello); - } - if self.preshared_key_offer.is_some() { - exts.push(ExtensionType::PreSharedKey); - } - exts - } - - /// Returns extensions which don't need a specific order, in randomized order. - /// - /// Extensions are encoded in three portions: - /// - /// - First, extensions not otherwise dealt with by other cases. - /// These are encoded in random order, controlled by `self.order_seed`, - /// and this is the set of extensions returned by this function. - /// - /// - Second, extensions named in `self.contiguous_extensions`, in the order - /// given by that field. - /// - /// - Lastly, any ECH and PSK extensions (in that order). These - /// are required to be last by the standard. - fn order_insensitive_extensions_in_random_order(&self) -> Vec<ExtensionType> { - let mut order = self.collect_used(); - - // Remove extensions which have specific order requirements. - order.retain(|ext| { - !(matches!( - ext, - ExtensionType::PreSharedKey - | ExtensionType::EncryptedClientHello - | ExtensionType::EncryptedClientHelloOuterExtensions - ) || self.contiguous_extensions.contains(ext)) - }); - - order.sort_by_cached_key(|new_ext| { - let seed = ((self.order_seed as u32) << 16) | (u16::from(*new_ext) as u32); - low_quality_integer_hash(seed) - }); - - order - } -} - -impl<'a> Codec<'a> for ClientExtensions<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - let order = self.used_extensions_in_encoding_order(); - - if order.is_empty() { - return; - } - - let body = LengthPrefixedBuffer::new(ListLength::U16, bytes); - for item in order { - self.encode_one(item, body.buf); - } - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let mut out = Self::default(); - - // extensions length can be absent if no extensions - if !r.any_left() { - return Ok(out); - } - - let mut checker = DuplicateExtensionChecker::new(); - - let len = usize::from(u16::read(r)?); - let mut sub = r.sub(len)?; - - while sub.any_left() { - let typ = out.read_one(&mut sub, |unknown| checker.check(unknown))?; - - // PreSharedKey offer must come last - if typ == ExtensionType::PreSharedKey && sub.any_left() { - return Err(InvalidMessage::PreSharedKeyIsNotFinalExtension); - } - } - - Ok(out) - } -} - -fn trim_hostname_trailing_dot_for_sni(dns_name: &DnsName<'_>) -> DnsName<'static> { - let dns_name_str = dns_name.as_ref(); - - // RFC6066: "The hostname is represented as a byte string using - // ASCII encoding without a trailing dot" - if dns_name_str.ends_with('.') { - let trimmed = &dns_name_str[0..dns_name_str.len() - 1]; - DnsName::try_from(trimmed) - .unwrap() - .to_owned() - } else { - dns_name.to_owned() - } -} - -#[derive(Clone, Debug)] -pub(crate) enum ClientSessionTicket { - Request, - Offer(Payload<'static>), -} - -impl<'a> Codec<'a> for ClientSessionTicket { - fn encode(&self, bytes: &mut Vec<u8>) { - match self { - Self::Request => (), - Self::Offer(p) => p.encode(bytes), - } - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - Ok(match r.left() { - 0 => Self::Request, - _ => Self::Offer(Payload::read(r).into_owned()), - }) - } -} - -#[derive(Default)] -pub(crate) struct ServerExtensionsInput<'a> { - /// QUIC transport parameters - pub(crate) transport_parameters: Option<TransportParameters<'a>>, -} - -extension_struct! { - pub(crate) struct ServerExtensions<'a> { - /// Supported EC point formats (RFC4492) - ExtensionType::ECPointFormats => - pub(crate) ec_point_formats: Option<SupportedEcPointFormats>, - - /// Server name indication acknowledgement (RFC6066) - ExtensionType::ServerName => - pub(crate) server_name_ack: Option<()>, - - /// Session ticket acknowledgement (RFC5077) - ExtensionType::SessionTicket => - pub(crate) session_ticket_ack: Option<()>, - - ExtensionType::RenegotiationInfo => - pub(crate) renegotiation_info: Option<PayloadU8>, - - /// Selected ALPN protocol (RFC7301) - ExtensionType::ALProtocolNegotiation => - pub(crate) selected_protocol: Option<SingleProtocolName>, - - /// Key exchange server share (RFC8446) - ExtensionType::KeyShare => - pub(crate) key_share: Option<KeyShareEntry>, - - /// Selected preshared key index (RFC8446) - ExtensionType::PreSharedKey => - pub(crate) preshared_key: Option<u16>, - - /// Required client certificate type (RFC7250) - ExtensionType::ClientCertificateType => - pub(crate) client_certificate_type: Option<CertificateType>, - - /// Selected server certificate type (RFC7250) - ExtensionType::ServerCertificateType => - pub(crate) server_certificate_type: Option<CertificateType>, - - /// Extended master secret is in use (RFC7627) - ExtensionType::ExtendedMasterSecret => - pub(crate) extended_master_secret_ack: Option<()>, - - /// Certificate status acknowledgement (RFC6066) - ExtensionType::StatusRequest => - pub(crate) certificate_status_request_ack: Option<()>, - - /// Selected TLS version (RFC8446) - ExtensionType::SupportedVersions => - pub(crate) selected_version: Option<ProtocolVersion>, - - /// QUIC transport parameters (RFC9001) - ExtensionType::TransportParameters => - pub(crate) transport_parameters: Option<Payload<'a>>, - - /// QUIC transport parameters (RFC9001 prior to draft 33) - ExtensionType::TransportParametersDraft => - pub(crate) transport_parameters_draft: Option<Payload<'a>>, - - /// Early data is accepted (RFC8446) - ExtensionType::EarlyData => - pub(crate) early_data_ack: Option<()>, - - /// Encrypted inner client hello response (draft-ietf-tls-esni) - ExtensionType::EncryptedClientHello => - pub(crate) encrypted_client_hello_ack: Option<ServerEncryptedClientHello>, - } + { - pub(crate) unknown_extensions: BTreeSet<u16>, - } -} - -impl ServerExtensions<'_> { - fn into_owned(self) -> ServerExtensions<'static> { - let Self { - ec_point_formats, - server_name_ack, - session_ticket_ack, - renegotiation_info, - selected_protocol, - key_share, - preshared_key, - client_certificate_type, - server_certificate_type, - extended_master_secret_ack, - certificate_status_request_ack, - selected_version, - transport_parameters, - transport_parameters_draft, - early_data_ack, - encrypted_client_hello_ack, - unknown_extensions, - } = self; - ServerExtensions { - ec_point_formats, - server_name_ack, - session_ticket_ack, - renegotiation_info, - selected_protocol, - key_share, - preshared_key, - client_certificate_type, - server_certificate_type, - extended_master_secret_ack, - certificate_status_request_ack, - selected_version, - transport_parameters: transport_parameters.map(|x| x.into_owned()), - transport_parameters_draft: transport_parameters_draft.map(|x| x.into_owned()), - early_data_ack, - encrypted_client_hello_ack, - unknown_extensions, - } - } -} - -impl<'a> Codec<'a> for ServerExtensions<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - let extensions = LengthPrefixedBuffer::new(ListLength::U16, bytes); - - for ext in Self::ALL_EXTENSIONS { - self.encode_one(*ext, extensions.buf); - } - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let mut out = Self::default(); - let mut checker = DuplicateExtensionChecker::new(); - - let len = usize::from(u16::read(r)?); - let mut sub = r.sub(len)?; - - while sub.any_left() { - out.read_one(&mut sub, |unknown| checker.check(unknown))?; - } - - out.unknown_extensions = checker.0; - Ok(out) - } -} - -#[derive(Clone, Debug)] -pub(crate) struct ClientHelloPayload { - pub(crate) client_version: ProtocolVersion, - pub(crate) random: Random, - pub(crate) session_id: SessionId, - pub(crate) cipher_suites: Vec<CipherSuite>, - pub(crate) compression_methods: Vec<Compression>, - pub(crate) extensions: Box<ClientExtensions<'static>>, -} - -impl ClientHelloPayload { - pub(crate) fn ech_inner_encoding(&self, to_compress: Vec<ExtensionType>) -> Vec<u8> { - let mut bytes = Vec::new(); - self.payload_encode(&mut bytes, Encoding::EchInnerHello { to_compress }); - bytes - } - - pub(crate) fn payload_encode(&self, bytes: &mut Vec<u8>, purpose: Encoding) { - self.client_version.encode(bytes); - self.random.encode(bytes); - - match purpose { - // SessionID is required to be empty in the encoded inner client hello. - Encoding::EchInnerHello { .. } => SessionId::empty().encode(bytes), - _ => self.session_id.encode(bytes), - } - - self.cipher_suites.encode(bytes); - self.compression_methods.encode(bytes); - - let to_compress = match purpose { - Encoding::EchInnerHello { to_compress } if !to_compress.is_empty() => to_compress, - _ => { - self.extensions.encode(bytes); - return; - } - }; - - let mut compressed = self.extensions.clone(); - - // First, eliminate the full-fat versions of the extensions - for e in &to_compress { - compressed.clear(*e); - } - - // Replace with the marker noting which extensions were elided. - compressed.encrypted_client_hello_outer = Some(to_compress); - - // And encode as normal. - compressed.encode(bytes); - } - - pub(crate) fn has_keyshare_extension_with_duplicates(&self) -> bool { - self.key_shares - .as_ref() - .map(|entries| { - has_duplicates::<_, _, u16>( - entries - .iter() - .map(|kse| u16::from(kse.group)), - ) - }) - .unwrap_or_default() - } - - pub(crate) fn has_certificate_compression_extension_with_duplicates(&self) -> bool { - if let Some(algs) = &self.certificate_compression_algorithms { - has_duplicates::<_, _, u16>(algs.iter().cloned()) - } else { - false - } - } -} - -impl Codec<'_> for ClientHelloPayload { - fn encode(&self, bytes: &mut Vec<u8>) { - self.payload_encode(bytes, Encoding::Standard) - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let ret = Self { - client_version: ProtocolVersion::read(r)?, - random: Random::read(r)?, - session_id: SessionId::read(r)?, - cipher_suites: Vec::read(r)?, - compression_methods: Vec::read(r)?, - extensions: Box::new(ClientExtensions::read(r)?.into_owned()), - }; - - match r.any_left() { - true => Err(InvalidMessage::TrailingData("ClientHelloPayload")), - false => Ok(ret), - } - } -} - -impl Deref for ClientHelloPayload { - type Target = ClientExtensions<'static>; - fn deref(&self) -> &Self::Target { - &self.extensions - } -} - -impl DerefMut for ClientHelloPayload { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.extensions - } -} - -/// RFC8446: `CipherSuite cipher_suites<2..2^16-2>;` -impl TlsListElement for CipherSuite { - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::IllegalEmptyList("CipherSuites"), - }; -} - -/// RFC5246: `CompressionMethod compression_methods<1..2^8-1>;` -impl TlsListElement for Compression { - const SIZE_LEN: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("Compressions"), - }; -} - -/// draft-ietf-tls-esni-17: `ExtensionType OuterExtensions<2..254>;` -impl TlsListElement for ExtensionType { - const SIZE_LEN: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("ExtensionTypes"), - }; -} - -extension_struct! { - /// A representation of extensions present in a `HelloRetryRequest` message - pub(crate) struct HelloRetryRequestExtensions<'a> { - ExtensionType::KeyShare => - pub(crate) key_share: Option<NamedGroup>, - - ExtensionType::Cookie => - pub(crate) cookie: Option<PayloadU16<NonEmpty>>, - - ExtensionType::SupportedVersions => - pub(crate) supported_versions: Option<ProtocolVersion>, - - ExtensionType::EncryptedClientHello => - pub(crate) encrypted_client_hello: Option<Payload<'a>>, - } + { - /// Records decoding order of records, and controls encoding order. - pub(crate) order: Option<Vec<ExtensionType>>, - } -} - -impl HelloRetryRequestExtensions<'_> { - fn into_owned(self) -> HelloRetryRequestExtensions<'static> { - let Self { - key_share, - cookie, - supported_versions, - encrypted_client_hello, - order, - } = self; - HelloRetryRequestExtensions { - key_share, - cookie, - supported_versions, - encrypted_client_hello: encrypted_client_hello.map(|x| x.into_owned()), - order, - } - } -} - -impl<'a> Codec<'a> for HelloRetryRequestExtensions<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - let extensions = LengthPrefixedBuffer::new(ListLength::U16, bytes); - - for ext in self - .order - .as_deref() - .unwrap_or(Self::ALL_EXTENSIONS) - { - self.encode_one(*ext, extensions.buf); - } - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let mut out = Self::default(); - - // we must record order, so re-encoding round trips. this is needed, - // unfortunately, for ECH HRR confirmation - let mut order = vec![]; - - let len = usize::from(u16::read(r)?); - let mut sub = r.sub(len)?; - - while sub.any_left() { - let typ = out.read_one(&mut sub, |_unk| { - Err(InvalidMessage::UnknownHelloRetryRequestExtension) - })?; - - order.push(typ); - } - - out.order = Some(order); - Ok(out) - } -} - -#[derive(Clone, Debug)] -pub(crate) struct HelloRetryRequest { - pub(crate) legacy_version: ProtocolVersion, - pub(crate) session_id: SessionId, - pub(crate) cipher_suite: CipherSuite, - pub(crate) extensions: HelloRetryRequestExtensions<'static>, -} - -impl Codec<'_> for HelloRetryRequest { - fn encode(&self, bytes: &mut Vec<u8>) { - self.payload_encode(bytes, Encoding::Standard) - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let session_id = SessionId::read(r)?; - let cipher_suite = CipherSuite::read(r)?; - let compression = Compression::read(r)?; - - if compression != Compression::Null { - return Err(InvalidMessage::UnsupportedCompression); - } - - Ok(Self { - legacy_version: ProtocolVersion::Unknown(0), - session_id, - cipher_suite, - extensions: HelloRetryRequestExtensions::read(r)?.into_owned(), - }) - } -} - -impl HelloRetryRequest { - fn payload_encode(&self, bytes: &mut Vec<u8>, purpose: Encoding) { - self.legacy_version.encode(bytes); - HELLO_RETRY_REQUEST_RANDOM.encode(bytes); - self.session_id.encode(bytes); - self.cipher_suite.encode(bytes); - Compression::Null.encode(bytes); - - match purpose { - // For the purpose of ECH confirmation, the Encrypted Client Hello extension - // must have its payload replaced by 8 zero bytes. - // - // See draft-ietf-tls-esni-18 7.2.1: - // <https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#name-sending-helloretryrequest-2> - Encoding::EchConfirmation - if self - .extensions - .encrypted_client_hello - .is_some() => - { - let hrr_confirmation = [0u8; 8]; - HelloRetryRequestExtensions { - encrypted_client_hello: Some(Payload::Borrowed(&hrr_confirmation)), - ..self.extensions.clone() - } - .encode(bytes); - } - _ => self.extensions.encode(bytes), - } - } -} - -impl Deref for HelloRetryRequest { - type Target = HelloRetryRequestExtensions<'static>; - fn deref(&self) -> &Self::Target { - &self.extensions - } -} - -impl DerefMut for HelloRetryRequest { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.extensions - } -} - -#[derive(Clone, Debug)] -pub(crate) struct ServerHelloPayload { - pub(crate) legacy_version: ProtocolVersion, - pub(crate) random: Random, - pub(crate) session_id: SessionId, - pub(crate) cipher_suite: CipherSuite, - pub(crate) compression_method: Compression, - pub(crate) extensions: Box<ServerExtensions<'static>>, -} - -impl Codec<'_> for ServerHelloPayload { - fn encode(&self, bytes: &mut Vec<u8>) { - self.payload_encode(bytes, Encoding::Standard) - } - - // minus version and random, which have already been read. - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let session_id = SessionId::read(r)?; - let suite = CipherSuite::read(r)?; - let compression = Compression::read(r)?; - - // RFC5246: - // "The presence of extensions can be detected by determining whether - // there are bytes following the compression_method field at the end of - // the ServerHello." - let extensions = Box::new( - if r.any_left() { - ServerExtensions::read(r)? - } else { - ServerExtensions::default() - } - .into_owned(), - ); - - let ret = Self { - legacy_version: ProtocolVersion::Unknown(0), - random: ZERO_RANDOM, - session_id, - cipher_suite: suite, - compression_method: compression, - extensions, - }; - - r.expect_empty("ServerHelloPayload") - .map(|_| ret) - } -} - -impl ServerHelloPayload { - fn payload_encode(&self, bytes: &mut Vec<u8>, encoding: Encoding) { - debug_assert!( - !matches!(encoding, Encoding::EchConfirmation), - "we cannot compute an ECH confirmation on a received ServerHello" - ); - - self.legacy_version.encode(bytes); - self.random.encode(bytes); - self.session_id.encode(bytes); - self.cipher_suite.encode(bytes); - self.compression_method.encode(bytes); - self.extensions.encode(bytes); - } -} - -impl Deref for ServerHelloPayload { - type Target = ServerExtensions<'static>; - fn deref(&self) -> &Self::Target { - &self.extensions - } -} - -impl DerefMut for ServerHelloPayload { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.extensions - } -} - -#[derive(Clone, Default, Debug)] -pub(crate) struct CertificateChain<'a>(pub(crate) Vec<CertificateDer<'a>>); - -impl CertificateChain<'_> { - pub(crate) fn into_owned(self) -> CertificateChain<'static> { - CertificateChain( - self.0 - .into_iter() - .map(|c| c.into_owned()) - .collect(), - ) - } -} - -impl<'a> Codec<'a> for CertificateChain<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - Vec::encode(&self.0, bytes) - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - Vec::read(r).map(Self) - } -} - -impl<'a> Deref for CertificateChain<'a> { - type Target = [CertificateDer<'a>]; - - fn deref(&self) -> &[CertificateDer<'a>] { - &self.0 - } -} - -impl TlsListElement for CertificateDer<'_> { - const SIZE_LEN: ListLength = ListLength::U24 { - max: CERTIFICATE_MAX_SIZE_LIMIT, - error: InvalidMessage::CertificatePayloadTooLarge, - }; -} - -/// TLS has a 16MB size limit on any handshake message, -/// plus a 16MB limit on any given certificate. -/// -/// We contract that to 64KB to limit the amount of memory allocation -/// that is directly controllable by the peer. -pub(crate) const CERTIFICATE_MAX_SIZE_LIMIT: usize = 0x1_0000; - -extension_struct! { - pub(crate) struct CertificateExtensions<'a> { - ExtensionType::StatusRequest => - pub(crate) status: Option<CertificateStatus<'a>>, - } -} - -impl CertificateExtensions<'_> { - fn into_owned(self) -> CertificateExtensions<'static> { - CertificateExtensions { - status: self.status.map(|s| s.into_owned()), - } - } -} - -impl<'a> Codec<'a> for CertificateExtensions<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - let extensions = LengthPrefixedBuffer::new(ListLength::U16, bytes); - - for ext in Self::ALL_EXTENSIONS { - self.encode_one(*ext, extensions.buf); - } - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let mut out = Self::default(); - - let len = usize::from(u16::read(r)?); - let mut sub = r.sub(len)?; - - while sub.any_left() { - out.read_one(&mut sub, |_unk| { - Err(InvalidMessage::UnknownCertificateExtension) - })?; - } - - Ok(out) - } -} - -#[derive(Debug)] -pub(crate) struct CertificateEntry<'a> { - pub(crate) cert: CertificateDer<'a>, - pub(crate) extensions: CertificateExtensions<'a>, -} - -impl<'a> Codec<'a> for CertificateEntry<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - self.cert.encode(bytes); - self.extensions.encode(bytes); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - Ok(Self { - cert: CertificateDer::read(r)?, - extensions: CertificateExtensions::read(r)?.into_owned(), - }) - } -} - -impl<'a> CertificateEntry<'a> { - pub(crate) fn new(cert: CertificateDer<'a>) -> Self { - Self { - cert, - extensions: CertificateExtensions::default(), - } - } - - pub(crate) fn into_owned(self) -> CertificateEntry<'static> { - CertificateEntry { - cert: self.cert.into_owned(), - extensions: self.extensions.into_owned(), - } - } -} - -impl TlsListElement for CertificateEntry<'_> { - const SIZE_LEN: ListLength = ListLength::U24 { - max: CERTIFICATE_MAX_SIZE_LIMIT, - error: InvalidMessage::CertificatePayloadTooLarge, - }; -} - -#[derive(Debug)] -pub(crate) struct CertificatePayloadTls13<'a> { - pub(crate) context: PayloadU8, - pub(crate) entries: Vec<CertificateEntry<'a>>, -} - -impl<'a> Codec<'a> for CertificatePayloadTls13<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - self.context.encode(bytes); - self.entries.encode(bytes); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - Ok(Self { - context: PayloadU8::read(r)?, - entries: Vec::read(r)?, - }) - } -} - -impl<'a> CertificatePayloadTls13<'a> { - pub(crate) fn new( - certs: impl Iterator<Item = &'a CertificateDer<'a>>, - ocsp_response: Option<&'a [u8]>, - ) -> Self { - Self { - context: PayloadU8::empty(), - entries: certs - // zip certificate iterator with `ocsp_response` followed by - // an infinite-length iterator of `None`. - .zip( - ocsp_response - .into_iter() - .map(Some) - .chain(iter::repeat(None)), - ) - .map(|(cert, ocsp)| { - let mut e = CertificateEntry::new(cert.clone()); - if let Some(ocsp) = ocsp { - e.extensions.status = Some(CertificateStatus::new(ocsp)); - } - e - }) - .collect(), - } - } - - pub(crate) fn into_owned(self) -> CertificatePayloadTls13<'static> { - CertificatePayloadTls13 { - context: self.context, - entries: self - .entries - .into_iter() - .map(CertificateEntry::into_owned) - .collect(), - } - } - - pub(crate) fn end_entity_ocsp(&self) -> Vec<u8> { - let Some(entry) = self.entries.first() else { - return vec![]; - }; - entry - .extensions - .status - .as_ref() - .map(|status| { - status - .ocsp_response - .0 - .clone() - .into_vec() - }) - .unwrap_or_default() - } - - pub(crate) fn into_certificate_chain(self) -> CertificateChain<'a> { - CertificateChain( - self.entries - .into_iter() - .map(|e| e.cert) - .collect(), - ) - } -} - -/// Describes supported key exchange mechanisms. -#[derive(Clone, Copy, Debug, PartialEq)] -#[non_exhaustive] -pub enum KeyExchangeAlgorithm { - /// Diffie-Hellman Key exchange (with only known parameters as defined in [RFC 7919]). - /// - /// [RFC 7919]: https://datatracker.ietf.org/doc/html/rfc7919 - DHE, - /// Key exchange performed via elliptic curve Diffie-Hellman. - ECDHE, -} - -pub(crate) static ALL_KEY_EXCHANGE_ALGORITHMS: &[KeyExchangeAlgorithm] = - &[KeyExchangeAlgorithm::ECDHE, KeyExchangeAlgorithm::DHE]; - -// We don't support arbitrary curves. It's a terrible -// idea and unnecessary attack surface. Please, -// get a grip. -#[derive(Debug)] -pub(crate) struct EcParameters { - pub(crate) curve_type: ECCurveType, - pub(crate) named_group: NamedGroup, -} - -impl Codec<'_> for EcParameters { - fn encode(&self, bytes: &mut Vec<u8>) { - self.curve_type.encode(bytes); - self.named_group.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let ct = ECCurveType::read(r)?; - if ct != ECCurveType::NamedCurve { - return Err(InvalidMessage::UnsupportedCurveType); - } - - let grp = NamedGroup::read(r)?; - - Ok(Self { - curve_type: ct, - named_group: grp, - }) - } -} - -#[cfg(feature = "tls12")] -pub(crate) trait KxDecode<'a>: fmt::Debug + Sized { - /// Decode a key exchange message given the key_exchange `algo` - fn decode(r: &mut Reader<'a>, algo: KeyExchangeAlgorithm) -> Result<Self, InvalidMessage>; -} - -#[cfg(feature = "tls12")] -#[derive(Debug)] -pub(crate) enum ClientKeyExchangeParams { - Ecdh(ClientEcdhParams), - Dh(ClientDhParams), -} - -#[cfg(feature = "tls12")] -impl ClientKeyExchangeParams { - pub(crate) fn pub_key(&self) -> &[u8] { - match self { - Self::Ecdh(ecdh) => &ecdh.public.0, - Self::Dh(dh) => &dh.public.0, - } - } - - pub(crate) fn encode(&self, buf: &mut Vec<u8>) { - match self { - Self::Ecdh(ecdh) => ecdh.encode(buf), - Self::Dh(dh) => dh.encode(buf), - } - } -} - -#[cfg(feature = "tls12")] -impl KxDecode<'_> for ClientKeyExchangeParams { - fn decode(r: &mut Reader<'_>, algo: KeyExchangeAlgorithm) -> Result<Self, InvalidMessage> { - use KeyExchangeAlgorithm::*; - Ok(match algo { - ECDHE => Self::Ecdh(ClientEcdhParams::read(r)?), - DHE => Self::Dh(ClientDhParams::read(r)?), - }) - } -} - -#[cfg(feature = "tls12")] -#[derive(Debug)] -pub(crate) struct ClientEcdhParams { - /// RFC4492: `opaque point <1..2^8-1>;` - pub(crate) public: PayloadU8<NonEmpty>, -} - -#[cfg(feature = "tls12")] -impl Codec<'_> for ClientEcdhParams { - fn encode(&self, bytes: &mut Vec<u8>) { - self.public.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let pb = PayloadU8::read(r)?; - Ok(Self { public: pb }) - } -} - -#[cfg(feature = "tls12")] -#[derive(Debug)] -pub(crate) struct ClientDhParams { - /// RFC5246: `opaque dh_Yc<1..2^16-1>;` - pub(crate) public: PayloadU16<NonEmpty>, -} - -#[cfg(feature = "tls12")] -impl Codec<'_> for ClientDhParams { - fn encode(&self, bytes: &mut Vec<u8>) { - self.public.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - public: PayloadU16::read(r)?, - }) - } -} - -#[derive(Debug)] -pub(crate) struct ServerEcdhParams { - pub(crate) curve_params: EcParameters, - /// RFC4492: `opaque point <1..2^8-1>;` - pub(crate) public: PayloadU8<NonEmpty>, -} - -impl ServerEcdhParams { - #[cfg(feature = "tls12")] - pub(crate) fn new(kx: &dyn ActiveKeyExchange) -> Self { - Self { - curve_params: EcParameters { - curve_type: ECCurveType::NamedCurve, - named_group: kx.group(), - }, - public: PayloadU8::new(kx.pub_key().to_vec()), - } - } -} - -impl Codec<'_> for ServerEcdhParams { - fn encode(&self, bytes: &mut Vec<u8>) { - self.curve_params.encode(bytes); - self.public.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let cp = EcParameters::read(r)?; - let pb = PayloadU8::read(r)?; - - Ok(Self { - curve_params: cp, - public: pb, - }) - } -} - -#[derive(Debug)] -#[allow(non_snake_case)] -pub(crate) struct ServerDhParams { - /// RFC5246: `opaque dh_p<1..2^16-1>;` - pub(crate) dh_p: PayloadU16<NonEmpty>, - /// RFC5246: `opaque dh_g<1..2^16-1>;` - pub(crate) dh_g: PayloadU16<NonEmpty>, - /// RFC5246: `opaque dh_Ys<1..2^16-1>;` - pub(crate) dh_Ys: PayloadU16<NonEmpty>, -} - -impl ServerDhParams { - #[cfg(feature = "tls12")] - pub(crate) fn new(kx: &dyn ActiveKeyExchange) -> Self { - let Some(params) = kx.ffdhe_group() else { - panic!("invalid NamedGroup for DHE key exchange: {:?}", kx.group()); - }; - - Self { - dh_p: PayloadU16::new(params.p.to_vec()), - dh_g: PayloadU16::new(params.g.to_vec()), - dh_Ys: PayloadU16::new(kx.pub_key().to_vec()), - } - } - - #[cfg(feature = "tls12")] - pub(crate) fn as_ffdhe_group(&self) -> FfdheGroup<'_> { - FfdheGroup::from_params_trimming_leading_zeros(&self.dh_p.0, &self.dh_g.0) - } -} - -impl Codec<'_> for ServerDhParams { - fn encode(&self, bytes: &mut Vec<u8>) { - self.dh_p.encode(bytes); - self.dh_g.encode(bytes); - self.dh_Ys.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - dh_p: PayloadU16::read(r)?, - dh_g: PayloadU16::read(r)?, - dh_Ys: PayloadU16::read(r)?, - }) - } -} - -#[allow(dead_code)] -#[derive(Debug)] -pub(crate) enum ServerKeyExchangeParams { - Ecdh(ServerEcdhParams), - Dh(ServerDhParams), -} - -impl ServerKeyExchangeParams { - #[cfg(feature = "tls12")] - pub(crate) fn new(kx: &dyn ActiveKeyExchange) -> Self { - match kx.group().key_exchange_algorithm() { - KeyExchangeAlgorithm::DHE => Self::Dh(ServerDhParams::new(kx)), - KeyExchangeAlgorithm::ECDHE => Self::Ecdh(ServerEcdhParams::new(kx)), - } - } - - #[cfg(feature = "tls12")] - pub(crate) fn pub_key(&self) -> &[u8] { - match self { - Self::Ecdh(ecdh) => &ecdh.public.0, - Self::Dh(dh) => &dh.dh_Ys.0, - } - } - - pub(crate) fn encode(&self, buf: &mut Vec<u8>) { - match self { - Self::Ecdh(ecdh) => ecdh.encode(buf), - Self::Dh(dh) => dh.encode(buf), - } - } -} - -#[cfg(feature = "tls12")] -impl KxDecode<'_> for ServerKeyExchangeParams { - fn decode(r: &mut Reader<'_>, algo: KeyExchangeAlgorithm) -> Result<Self, InvalidMessage> { - use KeyExchangeAlgorithm::*; - Ok(match algo { - ECDHE => Self::Ecdh(ServerEcdhParams::read(r)?), - DHE => Self::Dh(ServerDhParams::read(r)?), - }) - } -} - -#[derive(Debug)] -pub(crate) struct ServerKeyExchange { - pub(crate) params: ServerKeyExchangeParams, - pub(crate) dss: DigitallySignedStruct, -} - -impl ServerKeyExchange { - pub(crate) fn encode(&self, buf: &mut Vec<u8>) { - self.params.encode(buf); - self.dss.encode(buf); - } -} - -#[derive(Debug)] -pub(crate) enum ServerKeyExchangePayload { - Known(ServerKeyExchange), - Unknown(Payload<'static>), -} - -impl From<ServerKeyExchange> for ServerKeyExchangePayload { - fn from(value: ServerKeyExchange) -> Self { - Self::Known(value) - } -} - -impl Codec<'_> for ServerKeyExchangePayload { - fn encode(&self, bytes: &mut Vec<u8>) { - match self { - Self::Known(x) => x.encode(bytes), - Self::Unknown(x) => x.encode(bytes), - } - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - // read as Unknown, fully parse when we know the - // KeyExchangeAlgorithm - Ok(Self::Unknown(Payload::read(r).into_owned())) - } -} - -impl ServerKeyExchangePayload { - #[cfg(feature = "tls12")] - pub(crate) fn unwrap_given_kxa(&self, kxa: KeyExchangeAlgorithm) -> Option<ServerKeyExchange> { - if let Self::Unknown(unk) = self { - let mut rd = Reader::init(unk.bytes()); - - let result = ServerKeyExchange { - params: ServerKeyExchangeParams::decode(&mut rd, kxa).ok()?, - dss: DigitallySignedStruct::read(&mut rd).ok()?, - }; - - if !rd.any_left() { - return Some(result); - }; - } - - None - } -} - -/// RFC5246: `ClientCertificateType certificate_types<1..2^8-1>;` -impl TlsListElement for ClientCertificateType { - const SIZE_LEN: ListLength = ListLength::NonZeroU8 { - empty_error: InvalidMessage::IllegalEmptyList("ClientCertificateTypes"), - }; -} - -wrapped_payload!( - /// A `DistinguishedName` is a `Vec<u8>` wrapped in internal types. - /// - /// It contains the DER or BER encoded [`Subject` field from RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6) - /// for a single certificate. The Subject field is [encoded as an RFC 5280 `Name`](https://datatracker.ietf.org/doc/html/rfc5280#page-116). - /// It can be decoded using [x509-parser's FromDer trait](https://docs.rs/x509-parser/latest/x509_parser/prelude/trait.FromDer.html). - /// - /// ```ignore - /// for name in distinguished_names { - /// use x509_parser::prelude::FromDer; - /// println!("{}", x509_parser::x509::X509Name::from_der(&name.0)?.1); - /// } - /// ``` - /// - /// The TLS encoding is defined in RFC5246: `opaque DistinguishedName<1..2^16-1>;` - pub struct DistinguishedName, - PayloadU16<NonEmpty>, -); - -impl DistinguishedName { - /// Create a [`DistinguishedName`] after prepending its outer SEQUENCE encoding. - /// - /// This can be decoded using [x509-parser's FromDer trait](https://docs.rs/x509-parser/latest/x509_parser/prelude/trait.FromDer.html). - /// - /// ```ignore - /// use x509_parser::prelude::FromDer; - /// println!("{}", x509_parser::x509::X509Name::from_der(dn.as_ref())?.1); - /// ``` - pub fn in_sequence(bytes: &[u8]) -> Self { - Self(PayloadU16::new(wrap_in_sequence(bytes))) - } -} - -/// RFC8446: `DistinguishedName authorities<3..2^16-1>;` however, -/// RFC5246: `DistinguishedName certificate_authorities<0..2^16-1>;` -impl TlsListElement for DistinguishedName { - const SIZE_LEN: ListLength = ListLength::U16; -} - -#[derive(Debug)] -pub(crate) struct CertificateRequestPayload { - pub(crate) certtypes: Vec<ClientCertificateType>, - pub(crate) sigschemes: Vec<SignatureScheme>, - pub(crate) canames: Vec<DistinguishedName>, -} - -impl Codec<'_> for CertificateRequestPayload { - fn encode(&self, bytes: &mut Vec<u8>) { - self.certtypes.encode(bytes); - self.sigschemes.encode(bytes); - self.canames.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let certtypes = Vec::read(r)?; - let sigschemes = Vec::read(r)?; - let canames = Vec::read(r)?; - - if sigschemes.is_empty() { - warn!("meaningless CertificateRequest message"); - Err(InvalidMessage::NoSignatureSchemes) - } else { - Ok(Self { - certtypes, - sigschemes, - canames, - }) - } - } -} - -extension_struct! { - pub(crate) struct CertificateRequestExtensions { - ExtensionType::SignatureAlgorithms => - pub(crate) signature_algorithms: Option<Vec<SignatureScheme>>, - - ExtensionType::CertificateAuthorities => - pub(crate) authority_names: Option<Vec<DistinguishedName>>, - - ExtensionType::CompressCertificate => - pub(crate) certificate_compression_algorithms: Option<Vec<CertificateCompressionAlgorithm>>, - } -} - -impl Codec<'_> for CertificateRequestExtensions { - fn encode(&self, bytes: &mut Vec<u8>) { - let extensions = LengthPrefixedBuffer::new(ListLength::U16, bytes); - - for ext in Self::ALL_EXTENSIONS { - self.encode_one(*ext, extensions.buf); - } - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let mut out = Self::default(); - - let mut checker = DuplicateExtensionChecker::new(); - - let len = usize::from(u16::read(r)?); - let mut sub = r.sub(len)?; - - while sub.any_left() { - out.read_one(&mut sub, |unknown| checker.check(unknown))?; - } - - if out - .signature_algorithms - .as_ref() - .map(|algs| algs.is_empty()) - .unwrap_or_default() - { - return Err(InvalidMessage::NoSignatureSchemes); - } - - Ok(out) - } -} - -#[derive(Debug)] -pub(crate) struct CertificateRequestPayloadTls13 { - pub(crate) context: PayloadU8, - pub(crate) extensions: CertificateRequestExtensions, -} - -impl Codec<'_> for CertificateRequestPayloadTls13 { - fn encode(&self, bytes: &mut Vec<u8>) { - self.context.encode(bytes); - self.extensions.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let context = PayloadU8::read(r)?; - let extensions = CertificateRequestExtensions::read(r)?; - - Ok(Self { - context, - extensions, - }) - } -} - -// -- NewSessionTicket -- -#[derive(Debug)] -pub(crate) struct NewSessionTicketPayload { - pub(crate) lifetime_hint: u32, - // Tickets can be large (KB), so we deserialise this straight - // into an Arc, so it can be passed directly into the client's - // session object without copying. - pub(crate) ticket: Arc<PayloadU16>, -} - -impl NewSessionTicketPayload { - #[cfg(feature = "tls12")] - pub(crate) fn new(lifetime_hint: u32, ticket: Vec<u8>) -> Self { - Self { - lifetime_hint, - ticket: Arc::new(PayloadU16::new(ticket)), - } - } -} - -impl Codec<'_> for NewSessionTicketPayload { - fn encode(&self, bytes: &mut Vec<u8>) { - self.lifetime_hint.encode(bytes); - self.ticket.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let lifetime = u32::read(r)?; - let ticket = Arc::new(PayloadU16::read(r)?); - - Ok(Self { - lifetime_hint: lifetime, - ticket, - }) - } -} - -// -- NewSessionTicket electric boogaloo -- -extension_struct! { - pub(crate) struct NewSessionTicketExtensions { - ExtensionType::EarlyData => - pub(crate) max_early_data_size: Option<u32>, - } -} - -impl Codec<'_> for NewSessionTicketExtensions { - fn encode(&self, bytes: &mut Vec<u8>) { - let extensions = LengthPrefixedBuffer::new(ListLength::U16, bytes); - - for ext in Self::ALL_EXTENSIONS { - self.encode_one(*ext, extensions.buf); - } - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let mut out = Self::default(); - - let mut checker = DuplicateExtensionChecker::new(); - - let len = usize::from(u16::read(r)?); - let mut sub = r.sub(len)?; - - while sub.any_left() { - out.read_one(&mut sub, |unknown| checker.check(unknown))?; - } - - Ok(out) - } -} - -#[derive(Debug)] -pub(crate) struct NewSessionTicketPayloadTls13 { - pub(crate) lifetime: u32, - pub(crate) age_add: u32, - pub(crate) nonce: PayloadU8, - pub(crate) ticket: Arc<PayloadU16>, - pub(crate) extensions: NewSessionTicketExtensions, -} - -impl NewSessionTicketPayloadTls13 { - pub(crate) fn new(lifetime: u32, age_add: u32, nonce: Vec<u8>, ticket: Vec<u8>) -> Self { - Self { - lifetime, - age_add, - nonce: PayloadU8::new(nonce), - ticket: Arc::new(PayloadU16::new(ticket)), - extensions: NewSessionTicketExtensions::default(), - } - } -} - -impl Codec<'_> for NewSessionTicketPayloadTls13 { - fn encode(&self, bytes: &mut Vec<u8>) { - self.lifetime.encode(bytes); - self.age_add.encode(bytes); - self.nonce.encode(bytes); - self.ticket.encode(bytes); - self.extensions.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let lifetime = u32::read(r)?; - let age_add = u32::read(r)?; - let nonce = PayloadU8::read(r)?; - // nb. RFC8446: `opaque ticket<1..2^16-1>;` - let ticket = Arc::new(match PayloadU16::<NonEmpty>::read(r) { - Err(InvalidMessage::IllegalEmptyValue) => Err(InvalidMessage::EmptyTicketValue), - Err(err) => Err(err), - Ok(pl) => Ok(PayloadU16::new(pl.0)), - }?); - let extensions = NewSessionTicketExtensions::read(r)?; - - Ok(Self { - lifetime, - age_add, - nonce, - ticket, - extensions, - }) - } -} - -// -- RFC6066 certificate status types - -/// Only supports OCSP -#[derive(Clone, Debug)] -pub(crate) struct CertificateStatus<'a> { - pub(crate) ocsp_response: PayloadU24<'a>, -} - -impl<'a> Codec<'a> for CertificateStatus<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - CertificateStatusType::OCSP.encode(bytes); - self.ocsp_response.encode(bytes); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - let typ = CertificateStatusType::read(r)?; - - match typ { - CertificateStatusType::OCSP => Ok(Self { - ocsp_response: PayloadU24::read(r)?, - }), - _ => Err(InvalidMessage::InvalidCertificateStatusType), - } - } -} - -impl<'a> CertificateStatus<'a> { - pub(crate) fn new(ocsp: &'a [u8]) -> Self { - CertificateStatus { - ocsp_response: PayloadU24(Payload::Borrowed(ocsp)), - } - } - - #[cfg(feature = "tls12")] - pub(crate) fn into_inner(self) -> Vec<u8> { - self.ocsp_response.0.into_vec() - } - - pub(crate) fn into_owned(self) -> CertificateStatus<'static> { - CertificateStatus { - ocsp_response: self.ocsp_response.into_owned(), - } - } -} - -// -- RFC8879 compressed certificates - -#[derive(Debug)] -pub(crate) struct CompressedCertificatePayload<'a> { - pub(crate) alg: CertificateCompressionAlgorithm, - pub(crate) uncompressed_len: u32, - pub(crate) compressed: PayloadU24<'a>, -} - -impl<'a> Codec<'a> for CompressedCertificatePayload<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - self.alg.encode(bytes); - codec::u24(self.uncompressed_len).encode(bytes); - self.compressed.encode(bytes); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - Ok(Self { - alg: CertificateCompressionAlgorithm::read(r)?, - uncompressed_len: codec::u24::read(r)?.0, - compressed: PayloadU24::read(r)?, - }) - } -} - -impl CompressedCertificatePayload<'_> { - fn into_owned(self) -> CompressedCertificatePayload<'static> { - CompressedCertificatePayload { - compressed: self.compressed.into_owned(), - ..self - } - } - - pub(crate) fn as_borrowed(&self) -> CompressedCertificatePayload<'_> { - CompressedCertificatePayload { - alg: self.alg, - uncompressed_len: self.uncompressed_len, - compressed: PayloadU24(Payload::Borrowed(self.compressed.0.bytes())), - } - } -} - -#[derive(Debug)] -pub(crate) enum HandshakePayload<'a> { - HelloRequest, - ClientHello(ClientHelloPayload), - ServerHello(ServerHelloPayload), - HelloRetryRequest(HelloRetryRequest), - Certificate(CertificateChain<'a>), - CertificateTls13(CertificatePayloadTls13<'a>), - CompressedCertificate(CompressedCertificatePayload<'a>), - ServerKeyExchange(ServerKeyExchangePayload), - CertificateRequest(CertificateRequestPayload), - CertificateRequestTls13(CertificateRequestPayloadTls13), - CertificateVerify(DigitallySignedStruct), - ServerHelloDone, - EndOfEarlyData, - ClientKeyExchange(Payload<'a>), - NewSessionTicket(NewSessionTicketPayload), - NewSessionTicketTls13(NewSessionTicketPayloadTls13), - EncryptedExtensions(Box<ServerExtensions<'a>>), - KeyUpdate(KeyUpdateRequest), - Finished(Payload<'a>), - CertificateStatus(CertificateStatus<'a>), - MessageHash(Payload<'a>), - Unknown((HandshakeType, Payload<'a>)), -} - -impl HandshakePayload<'_> { - fn encode(&self, bytes: &mut Vec<u8>) { - use self::HandshakePayload::*; - match self { - HelloRequest | ServerHelloDone | EndOfEarlyData => {} - ClientHello(x) => x.encode(bytes), - ServerHello(x) => x.encode(bytes), - HelloRetryRequest(x) => x.encode(bytes), - Certificate(x) => x.encode(bytes), - CertificateTls13(x) => x.encode(bytes), - CompressedCertificate(x) => x.encode(bytes), - ServerKeyExchange(x) => x.encode(bytes), - ClientKeyExchange(x) => x.encode(bytes), - CertificateRequest(x) => x.encode(bytes), - CertificateRequestTls13(x) => x.encode(bytes), - CertificateVerify(x) => x.encode(bytes), - NewSessionTicket(x) => x.encode(bytes), - NewSessionTicketTls13(x) => x.encode(bytes), - EncryptedExtensions(x) => x.encode(bytes), - KeyUpdate(x) => x.encode(bytes), - Finished(x) => x.encode(bytes), - CertificateStatus(x) => x.encode(bytes), - MessageHash(x) => x.encode(bytes), - Unknown((_, x)) => x.encode(bytes), - } - } - - pub(crate) fn handshake_type(&self) -> HandshakeType { - use self::HandshakePayload::*; - match self { - HelloRequest => HandshakeType::HelloRequest, - ClientHello(_) => HandshakeType::ClientHello, - ServerHello(_) => HandshakeType::ServerHello, - HelloRetryRequest(_) => HandshakeType::HelloRetryRequest, - Certificate(_) | CertificateTls13(_) => HandshakeType::Certificate, - CompressedCertificate(_) => HandshakeType::CompressedCertificate, - ServerKeyExchange(_) => HandshakeType::ServerKeyExchange, - CertificateRequest(_) | CertificateRequestTls13(_) => HandshakeType::CertificateRequest, - CertificateVerify(_) => HandshakeType::CertificateVerify, - ServerHelloDone => HandshakeType::ServerHelloDone, - EndOfEarlyData => HandshakeType::EndOfEarlyData, - ClientKeyExchange(_) => HandshakeType::ClientKeyExchange, - NewSessionTicket(_) | NewSessionTicketTls13(_) => HandshakeType::NewSessionTicket, - EncryptedExtensions(_) => HandshakeType::EncryptedExtensions, - KeyUpdate(_) => HandshakeType::KeyUpdate, - Finished(_) => HandshakeType::Finished, - CertificateStatus(_) => HandshakeType::CertificateStatus, - MessageHash(_) => HandshakeType::MessageHash, - Unknown((t, _)) => *t, - } - } - - fn wire_handshake_type(&self) -> HandshakeType { - match self.handshake_type() { - // A `HelloRetryRequest` appears on the wire as a `ServerHello` with a magic `random` value. - HandshakeType::HelloRetryRequest => HandshakeType::ServerHello, - other => other, - } - } - - fn into_owned(self) -> HandshakePayload<'static> { - use HandshakePayload::*; - - match self { - HelloRequest => HelloRequest, - ClientHello(x) => ClientHello(x), - ServerHello(x) => ServerHello(x), - HelloRetryRequest(x) => HelloRetryRequest(x), - Certificate(x) => Certificate(x.into_owned()), - CertificateTls13(x) => CertificateTls13(x.into_owned()), - CompressedCertificate(x) => CompressedCertificate(x.into_owned()), - ServerKeyExchange(x) => ServerKeyExchange(x), - CertificateRequest(x) => CertificateRequest(x), - CertificateRequestTls13(x) => CertificateRequestTls13(x), - CertificateVerify(x) => CertificateVerify(x), - ServerHelloDone => ServerHelloDone, - EndOfEarlyData => EndOfEarlyData, - ClientKeyExchange(x) => ClientKeyExchange(x.into_owned()), - NewSessionTicket(x) => NewSessionTicket(x), - NewSessionTicketTls13(x) => NewSessionTicketTls13(x), - EncryptedExtensions(x) => EncryptedExtensions(Box::new(x.into_owned())), - KeyUpdate(x) => KeyUpdate(x), - Finished(x) => Finished(x.into_owned()), - CertificateStatus(x) => CertificateStatus(x.into_owned()), - MessageHash(x) => MessageHash(x.into_owned()), - Unknown((t, x)) => Unknown((t, x.into_owned())), - } - } -} - -#[derive(Debug)] -pub struct HandshakeMessagePayload<'a>(pub(crate) HandshakePayload<'a>); - -impl<'a> Codec<'a> for HandshakeMessagePayload<'a> { - fn encode(&self, bytes: &mut Vec<u8>) { - self.payload_encode(bytes, Encoding::Standard); - } - - fn read(r: &mut Reader<'a>) -> Result<Self, InvalidMessage> { - Self::read_version(r, ProtocolVersion::TLSv1_2) - } -} - -impl<'a> HandshakeMessagePayload<'a> { - pub(crate) fn read_version( - r: &mut Reader<'a>, - vers: ProtocolVersion, - ) -> Result<Self, InvalidMessage> { - let typ = HandshakeType::read(r)?; - let len = codec::u24::read(r)?.0 as usize; - let mut sub = r.sub(len)?; - - let payload = match typ { - HandshakeType::HelloRequest if sub.left() == 0 => HandshakePayload::HelloRequest, - HandshakeType::ClientHello => { - HandshakePayload::ClientHello(ClientHelloPayload::read(&mut sub)?) - } - HandshakeType::ServerHello => { - let version = ProtocolVersion::read(&mut sub)?; - let random = Random::read(&mut sub)?; - - if random == HELLO_RETRY_REQUEST_RANDOM { - let mut hrr = HelloRetryRequest::read(&mut sub)?; - hrr.legacy_version = version; - HandshakePayload::HelloRetryRequest(hrr) - } else { - let mut shp = ServerHelloPayload::read(&mut sub)?; - shp.legacy_version = version; - shp.random = random; - HandshakePayload::ServerHello(shp) - } - } - HandshakeType::Certificate if vers == ProtocolVersion::TLSv1_3 => { - let p = CertificatePayloadTls13::read(&mut sub)?; - HandshakePayload::CertificateTls13(p) - } - HandshakeType::Certificate => { - HandshakePayload::Certificate(CertificateChain::read(&mut sub)?) - } - HandshakeType::ServerKeyExchange => { - let p = ServerKeyExchangePayload::read(&mut sub)?; - HandshakePayload::ServerKeyExchange(p) - } - HandshakeType::ServerHelloDone => { - sub.expect_empty("ServerHelloDone")?; - HandshakePayload::ServerHelloDone - } - HandshakeType::ClientKeyExchange => { - HandshakePayload::ClientKeyExchange(Payload::read(&mut sub)) - } - HandshakeType::CertificateRequest if vers == ProtocolVersion::TLSv1_3 => { - let p = CertificateRequestPayloadTls13::read(&mut sub)?; - HandshakePayload::CertificateRequestTls13(p) - } - HandshakeType::CertificateRequest => { - let p = CertificateRequestPayload::read(&mut sub)?; - HandshakePayload::CertificateRequest(p) - } - HandshakeType::CompressedCertificate => HandshakePayload::CompressedCertificate( - CompressedCertificatePayload::read(&mut sub)?, - ), - HandshakeType::CertificateVerify => { - HandshakePayload::CertificateVerify(DigitallySignedStruct::read(&mut sub)?) - } - HandshakeType::NewSessionTicket if vers == ProtocolVersion::TLSv1_3 => { - let p = NewSessionTicketPayloadTls13::read(&mut sub)?; - HandshakePayload::NewSessionTicketTls13(p) - } - HandshakeType::NewSessionTicket => { - let p = NewSessionTicketPayload::read(&mut sub)?; - HandshakePayload::NewSessionTicket(p) - } - HandshakeType::EncryptedExtensions => { - HandshakePayload::EncryptedExtensions(Box::new(ServerExtensions::read(&mut sub)?)) - } - HandshakeType::KeyUpdate => { - HandshakePayload::KeyUpdate(KeyUpdateRequest::read(&mut sub)?) - } - HandshakeType::EndOfEarlyData => { - sub.expect_empty("EndOfEarlyData")?; - HandshakePayload::EndOfEarlyData - } - HandshakeType::Finished => HandshakePayload::Finished(Payload::read(&mut sub)), - HandshakeType::CertificateStatus => { - HandshakePayload::CertificateStatus(CertificateStatus::read(&mut sub)?) - } - HandshakeType::MessageHash => { - // does not appear on the wire - return Err(InvalidMessage::UnexpectedMessage("MessageHash")); - } - HandshakeType::HelloRetryRequest => { - // not legal on wire - return Err(InvalidMessage::UnexpectedMessage("HelloRetryRequest")); - } - _ => HandshakePayload::Unknown((typ, Payload::read(&mut sub))), - }; - - sub.expect_empty("HandshakeMessagePayload") - .map(|_| Self(payload)) - } - - pub(crate) fn encoding_for_binder_signing(&self) -> Vec<u8> { - let mut ret = self.get_encoding(); - let ret_len = ret.len() - self.total_binder_length(); - ret.truncate(ret_len); - ret - } - - pub(crate) fn total_binder_length(&self) -> usize { - match &self.0 { - HandshakePayload::ClientHello(ch) => match &ch.preshared_key_offer { - Some(offer) => { - let mut binders_encoding = Vec::new(); - offer - .binders - .encode(&mut binders_encoding); - binders_encoding.len() - } - _ => 0, - }, - _ => 0, - } - } - - pub(crate) fn payload_encode(&self, bytes: &mut Vec<u8>, encoding: Encoding) { - // output type, length, and encoded payload - self.0 - .wire_handshake_type() - .encode(bytes); - - let nested = LengthPrefixedBuffer::new( - ListLength::U24 { - max: usize::MAX, - error: InvalidMessage::MessageTooLarge, - }, - bytes, - ); - - match &self.0 { - // for Server Hello and HelloRetryRequest payloads we need to encode the payload - // differently based on the purpose of the encoding. - HandshakePayload::ServerHello(payload) => payload.payload_encode(nested.buf, encoding), - HandshakePayload::HelloRetryRequest(payload) => { - payload.payload_encode(nested.buf, encoding) - } - - // All other payload types are encoded the same regardless of purpose. - _ => self.0.encode(nested.buf), - } - } - - pub(crate) fn build_handshake_hash(hash: &[u8]) -> Self { - Self(HandshakePayload::MessageHash(Payload::new(hash.to_vec()))) - } - - pub(crate) fn into_owned(self) -> HandshakeMessagePayload<'static> { - HandshakeMessagePayload(self.0.into_owned()) - } -} - -#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] -pub struct HpkeSymmetricCipherSuite { - pub kdf_id: HpkeKdf, - pub aead_id: HpkeAead, -} - -impl Codec<'_> for HpkeSymmetricCipherSuite { - fn encode(&self, bytes: &mut Vec<u8>) { - self.kdf_id.encode(bytes); - self.aead_id.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - kdf_id: HpkeKdf::read(r)?, - aead_id: HpkeAead::read(r)?, - }) - } -} - -/// draft-ietf-tls-esni-24: `HpkeSymmetricCipherSuite cipher_suites<4..2^16-4>;` -impl TlsListElement for HpkeSymmetricCipherSuite { - const SIZE_LEN: ListLength = ListLength::NonZeroU16 { - empty_error: InvalidMessage::IllegalEmptyList("HpkeSymmetricCipherSuites"), - }; -} - -#[derive(Clone, Debug, PartialEq)] -pub struct HpkeKeyConfig { - pub config_id: u8, - pub kem_id: HpkeKem, - /// draft-ietf-tls-esni-24: `opaque HpkePublicKey<1..2^16-1>;` - pub public_key: PayloadU16<NonEmpty>, - pub symmetric_cipher_suites: Vec<HpkeSymmetricCipherSuite>, -} - -impl Codec<'_> for HpkeKeyConfig { - fn encode(&self, bytes: &mut Vec<u8>) { - self.config_id.encode(bytes); - self.kem_id.encode(bytes); - self.public_key.encode(bytes); - self.symmetric_cipher_suites - .encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - config_id: u8::read(r)?, - kem_id: HpkeKem::read(r)?, - public_key: PayloadU16::read(r)?, - symmetric_cipher_suites: Vec::<HpkeSymmetricCipherSuite>::read(r)?, - }) - } -} - -#[derive(Clone, Debug, PartialEq)] -pub struct EchConfigContents { - pub key_config: HpkeKeyConfig, - pub maximum_name_length: u8, - pub public_name: DnsName<'static>, - pub extensions: Vec<EchConfigExtension>, -} - -impl EchConfigContents { - /// Returns true if there is more than one extension of a given - /// type. - pub(crate) fn has_duplicate_extension(&self) -> bool { - has_duplicates::<_, _, u16>( - self.extensions - .iter() - .map(|ext| ext.ext_type()), - ) - } - - /// Returns true if there is at least one mandatory unsupported extension. - pub(crate) fn has_unknown_mandatory_extension(&self) -> bool { - self.extensions - .iter() - // An extension is considered mandatory if the high bit of its type is set. - .any(|ext| { - matches!(ext.ext_type(), ExtensionType::Unknown(_)) - && u16::from(ext.ext_type()) & 0x8000 != 0 - }) - } -} - -impl Codec<'_> for EchConfigContents { - fn encode(&self, bytes: &mut Vec<u8>) { - self.key_config.encode(bytes); - self.maximum_name_length.encode(bytes); - let dns_name = &self.public_name.borrow(); - PayloadU8::<MaybeEmpty>::encode_slice(dns_name.as_ref().as_ref(), bytes); - self.extensions.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - key_config: HpkeKeyConfig::read(r)?, - maximum_name_length: u8::read(r)?, - public_name: { - DnsName::try_from( - PayloadU8::<MaybeEmpty>::read(r)? - .0 - .as_slice(), - ) - .map_err(|_| InvalidMessage::InvalidServerName)? - .to_owned() - }, - extensions: Vec::read(r)?, - }) - } -} - -/// An encrypted client hello (ECH) config. -#[derive(Clone, Debug, PartialEq)] -pub enum EchConfigPayload { - /// A recognized V18 ECH configuration. - V18(EchConfigContents), - /// An unknown version ECH configuration. - Unknown { - version: EchVersion, - contents: PayloadU16, - }, -} - -impl TlsListElement for EchConfigPayload { - const SIZE_LEN: ListLength = ListLength::U16; -} - -impl Codec<'_> for EchConfigPayload { - fn encode(&self, bytes: &mut Vec<u8>) { - match self { - Self::V18(c) => { - // Write the version, the length, and the contents. - EchVersion::V18.encode(bytes); - let inner = LengthPrefixedBuffer::new(ListLength::U16, bytes); - c.encode(inner.buf); - } - Self::Unknown { version, contents } => { - // Unknown configuration versions are opaque. - version.encode(bytes); - contents.encode(bytes); - } - } - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let version = EchVersion::read(r)?; - let length = u16::read(r)?; - let mut contents = r.sub(length as usize)?; - - Ok(match version { - EchVersion::V18 => Self::V18(EchConfigContents::read(&mut contents)?), - _ => { - // Note: we don't PayloadU16::read() here because we've already read the length prefix. - let data = PayloadU16::new(contents.rest().into()); - Self::Unknown { - version, - contents: data, - } - } - }) - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum EchConfigExtension { - Unknown(UnknownExtension), -} - -impl EchConfigExtension { - pub(crate) fn ext_type(&self) -> ExtensionType { - match self { - Self::Unknown(r) => r.typ, - } - } -} - -impl Codec<'_> for EchConfigExtension { - fn encode(&self, bytes: &mut Vec<u8>) { - self.ext_type().encode(bytes); - - let nested = LengthPrefixedBuffer::new(ListLength::U16, bytes); - match self { - Self::Unknown(r) => r.encode(nested.buf), - } - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let typ = ExtensionType::read(r)?; - let len = u16::read(r)? as usize; - let mut sub = r.sub(len)?; - - #[allow(clippy::match_single_binding)] // Future-proofing. - let ext = match typ { - _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), - }; - - sub.expect_empty("EchConfigExtension") - .map(|_| ext) - } -} - -impl TlsListElement for EchConfigExtension { - const SIZE_LEN: ListLength = ListLength::U16; -} - -/// Representation of the `ECHClientHello` client extension specified in -/// [draft-ietf-tls-esni Section 5]. -/// -/// [draft-ietf-tls-esni Section 5]: <https://www.ietf.org/archive/id/draft-ietf-tls-esni-18.html#section-5> -#[derive(Clone, Debug)] -pub(crate) enum EncryptedClientHello { - /// A `ECHClientHello` with type [EchClientHelloType::ClientHelloOuter]. - Outer(EncryptedClientHelloOuter), - /// An empty `ECHClientHello` with type [EchClientHelloType::ClientHelloInner]. - /// - /// This variant has no payload. - Inner, -} - -impl Codec<'_> for EncryptedClientHello { - fn encode(&self, bytes: &mut Vec<u8>) { - match self { - Self::Outer(payload) => { - EchClientHelloType::ClientHelloOuter.encode(bytes); - payload.encode(bytes); - } - Self::Inner => { - EchClientHelloType::ClientHelloInner.encode(bytes); - // Empty payload. - } - } - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - match EchClientHelloType::read(r)? { - EchClientHelloType::ClientHelloOuter => { - Ok(Self::Outer(EncryptedClientHelloOuter::read(r)?)) - } - EchClientHelloType::ClientHelloInner => Ok(Self::Inner), - _ => Err(InvalidMessage::InvalidContentType), - } - } -} - -/// Representation of the ECHClientHello extension with type outer specified in -/// [draft-ietf-tls-esni Section 5]. -/// -/// [draft-ietf-tls-esni Section 5]: <https://www.ietf.org/archive/id/draft-ietf-tls-esni-18.html#section-5> -#[derive(Clone, Debug)] -pub(crate) struct EncryptedClientHelloOuter { - /// The cipher suite used to encrypt ClientHelloInner. Must match a value from - /// ECHConfigContents.cipher_suites list. - pub cipher_suite: HpkeSymmetricCipherSuite, - /// The ECHConfigContents.key_config.config_id for the chosen ECHConfig. - pub config_id: u8, - /// The HPKE encapsulated key, used by servers to decrypt the corresponding payload field. - /// This field is empty in a ClientHelloOuter sent in response to a HelloRetryRequest. - pub enc: PayloadU16, - /// The serialized and encrypted ClientHelloInner structure, encrypted using HPKE. - pub payload: PayloadU16<NonEmpty>, -} - -impl Codec<'_> for EncryptedClientHelloOuter { - fn encode(&self, bytes: &mut Vec<u8>) { - self.cipher_suite.encode(bytes); - self.config_id.encode(bytes); - self.enc.encode(bytes); - self.payload.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - cipher_suite: HpkeSymmetricCipherSuite::read(r)?, - config_id: u8::read(r)?, - enc: PayloadU16::read(r)?, - payload: PayloadU16::read(r)?, - }) - } -} - -/// Representation of the ECHEncryptedExtensions extension specified in -/// [draft-ietf-tls-esni Section 5]. -/// -/// [draft-ietf-tls-esni Section 5]: <https://www.ietf.org/archive/id/draft-ietf-tls-esni-18.html#section-5> -#[derive(Clone, Debug)] -pub(crate) struct ServerEncryptedClientHello { - pub(crate) retry_configs: Vec<EchConfigPayload>, -} - -impl Codec<'_> for ServerEncryptedClientHello { - fn encode(&self, bytes: &mut Vec<u8>) { - self.retry_configs.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - Ok(Self { - retry_configs: Vec::<EchConfigPayload>::read(r)?, - }) - } -} - -/// The method of encoding to use for a handshake message. -/// -/// In some cases a handshake message may be encoded differently depending on the purpose -/// the encoded message is being used for. -pub(crate) enum Encoding { - /// Standard RFC 8446 encoding. - Standard, - /// Encoding for ECH confirmation for HRR. - EchConfirmation, - /// Encoding for ECH inner client hello. - EchInnerHello { to_compress: Vec<ExtensionType> }, -} - -fn has_duplicates<I: IntoIterator<Item = E>, E: Into<T>, T: Eq + Ord>(iter: I) -> bool { - let mut seen = BTreeSet::new(); - - for x in iter { - if !seen.insert(x.into()) { - return true; - } - } - - false -} - -struct DuplicateExtensionChecker(BTreeSet<u16>); - -impl DuplicateExtensionChecker { - fn new() -> Self { - Self(BTreeSet::new()) - } - - fn check(&mut self, typ: ExtensionType) -> Result<(), InvalidMessage> { - let u = u16::from(typ); - match self.0.insert(u) { - true => Ok(()), - false => Err(InvalidMessage::DuplicateExtension(u)), - } - } -} - -fn low_quality_integer_hash(mut x: u32) -> u32 { - x = x - .wrapping_add(0x7ed55d16) - .wrapping_add(x << 12); - x = (x ^ 0xc761c23c) ^ (x >> 19); - x = x - .wrapping_add(0x165667b1) - .wrapping_add(x << 5); - x = x.wrapping_add(0xd3a2646c) ^ (x << 9); - x = x - .wrapping_add(0xfd7046c5) - .wrapping_add(x << 3); - x = (x ^ 0xb55a4f09) ^ (x >> 16); - x -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_ech_config_dupe_exts() { - let unknown_ext = EchConfigExtension::Unknown(UnknownExtension { - typ: ExtensionType::Unknown(0x42), - payload: Payload::new(vec![0x42]), - }); - let mut config = config_template(); - config - .extensions - .push(unknown_ext.clone()); - config.extensions.push(unknown_ext); - - assert!(config.has_duplicate_extension()); - assert!(!config.has_unknown_mandatory_extension()); - } - - #[test] - fn test_ech_config_mandatory_exts() { - let mandatory_unknown_ext = EchConfigExtension::Unknown(UnknownExtension { - typ: ExtensionType::Unknown(0x42 | 0x8000), // Note: high bit set. - payload: Payload::new(vec![0x42]), - }); - let mut config = config_template(); - config - .extensions - .push(mandatory_unknown_ext); - - assert!(!config.has_duplicate_extension()); - assert!(config.has_unknown_mandatory_extension()); - } - - fn config_template() -> EchConfigContents { - EchConfigContents { - key_config: HpkeKeyConfig { - config_id: 0, - kem_id: HpkeKem::DHKEM_P256_HKDF_SHA256, - public_key: PayloadU16::new(b"xxx".into()), - symmetric_cipher_suites: vec![HpkeSymmetricCipherSuite { - kdf_id: HpkeKdf::HKDF_SHA256, - aead_id: HpkeAead::AES_128_GCM, - }], - }, - maximum_name_length: 0, - public_name: DnsName::try_from("example.com").unwrap(), - extensions: vec![], - } - } -} diff --git a/vendor/rustls/src/msgs/handshake_test.rs b/vendor/rustls/src/msgs/handshake_test.rs deleted file mode 100644 index 53cf88fa..00000000 --- a/vendor/rustls/src/msgs/handshake_test.rs +++ /dev/null @@ -1,1051 +0,0 @@ -use std::prelude::v1::*; -use std::{format, println, vec}; - -use pki_types::{CertificateDer, DnsName}; - -use super::base::{Payload, PayloadU8, PayloadU16, PayloadU24}; -use super::codec::{Codec, Reader, put_u16}; -use super::enums::{ - ClientCertificateType, Compression, ECCurveType, ExtensionType, KeyUpdateRequest, NamedGroup, -}; -use super::handshake::{ - CertificateChain, CertificateEntry, CertificateExtensions, CertificatePayloadTls13, - CertificateRequestExtensions, CertificateRequestPayload, CertificateRequestPayloadTls13, - CertificateStatus, CertificateStatusRequest, ClientExtensions, ClientHelloPayload, - ClientSessionTicket, CompressedCertificatePayload, DistinguishedName, EcParameters, - EncryptedClientHello, HandshakeMessagePayload, HandshakePayload, HelloRetryRequest, - HelloRetryRequestExtensions, KeyShareEntry, NewSessionTicketExtensions, - NewSessionTicketPayload, NewSessionTicketPayloadTls13, PresharedKeyBinder, - PresharedKeyIdentity, PresharedKeyOffer, ProtocolName, PskKeyExchangeModes, Random, - ServerDhParams, ServerEcdhParams, ServerEncryptedClientHello, ServerExtensions, - ServerHelloPayload, ServerKeyExchange, ServerKeyExchangeParams, ServerKeyExchangePayload, - ServerNamePayload, SessionId, SingleProtocolName, SupportedEcPointFormats, - SupportedProtocolVersions, -}; -use crate::enums::{ - CertificateCompressionAlgorithm, CertificateType, CipherSuite, HandshakeType, ProtocolVersion, - SignatureScheme, -}; -use crate::error::InvalidMessage; -use crate::sync::Arc; -use crate::verify::DigitallySignedStruct; - -#[test] -fn rejects_short_random() { - let bytes = [0x01; 31]; - let mut rd = Reader::init(&bytes); - assert!(Random::read(&mut rd).is_err()); -} - -#[test] -fn reads_random() { - let bytes = [0x01; 32]; - let mut rd = Reader::init(&bytes); - let rnd = Random::read(&mut rd).unwrap(); - println!("{rnd:?}"); - - assert!(!rd.any_left()); -} - -#[test] -fn debug_random() { - assert_eq!( - "0101010101010101010101010101010101010101010101010101010101010101", - format!("{:?}", Random::from([1; 32])) - ); -} - -#[test] -fn rejects_truncated_session_id() { - let bytes = [32; 32]; - let mut rd = Reader::init(&bytes); - assert!(SessionId::read(&mut rd).is_err()); -} - -#[test] -fn rejects_session_id_with_bad_length() { - let bytes = [33; 33]; - let mut rd = Reader::init(&bytes); - assert!(SessionId::read(&mut rd).is_err()); -} - -#[test] -fn session_id_with_different_lengths_are_unequal() { - let a = SessionId::read(&mut Reader::init(&[1u8, 1])).unwrap(); - let b = SessionId::read(&mut Reader::init(&[2u8, 1, 2])).unwrap(); - assert_ne!(a, b); -} - -#[test] -fn accepts_short_session_id() { - let bytes = [1; 2]; - let mut rd = Reader::init(&bytes); - let sess = SessionId::read(&mut rd).unwrap(); - println!("{sess:?}"); - - #[cfg(feature = "tls12")] - assert!(!sess.is_empty()); - assert_ne!(sess, SessionId::empty()); - assert!(!rd.any_left()); -} - -#[test] -fn accepts_empty_session_id() { - let bytes = [0; 1]; - let mut rd = Reader::init(&bytes); - let sess = SessionId::read(&mut rd).unwrap(); - println!("{sess:?}"); - - #[cfg(feature = "tls12")] - assert!(sess.is_empty()); - assert_eq!(sess, SessionId::empty()); - assert!(!rd.any_left()); -} - -#[test] -fn debug_session_id() { - let bytes = [ - 32, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, - ]; - let mut rd = Reader::init(&bytes); - let sess = SessionId::read(&mut rd).unwrap(); - assert_eq!( - "0101010101010101010101010101010101010101010101010101010101010101", - format!("{sess:?}") - ); -} - -#[test] -fn refuses_client_exts_with_unparsed_bytes() { - let bytes = [0x00u8, 0x08, 0x00, 0x0b, 0x00, 0x04, 0x02, 0xf8, 0x01, 0x02]; - assert_eq!( - ClientExtensions::read_bytes(&bytes).unwrap_err(), - InvalidMessage::TrailingData("ClientExtensions") - ); -} - -#[test] -fn refuses_server_ext_with_unparsed_bytes() { - let bytes = [0x00u8, 0x08, 0x00, 0x0b, 0x00, 0x04, 0x02, 0xf8, 0x01, 0x02]; - assert_eq!( - ServerExtensions::read_bytes(&bytes).unwrap_err(), - InvalidMessage::TrailingData("ServerExtensions") - ); -} - -#[test] -fn refuses_certificate_ext_with_unparsed_bytes() { - let bytes = [ - 0x00u8, 0x09, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x01, - ]; - assert_eq!( - CertificateExtensions::read_bytes(&bytes).unwrap_err(), - InvalidMessage::TrailingData("CertificateExtensions") - ); -} - -#[test] -fn refuses_certificate_ext_with_unknown_type() { - let bytes = [0x00u8, 0x08, 0x00, 0x05, 0x00, 0x03, 0x99, 0x00, 0x00, 0x00]; - assert_eq!( - CertificateExtensions::read_bytes(&bytes).unwrap_err(), - InvalidMessage::InvalidCertificateStatusType - ); -} - -#[test] -fn refuses_certificate_req_ext_with_unparsed_bytes() { - let bytes = [ - 0x00u8, 0x09, 0x00, 0x0d, 0x00, 0x05, 0x00, 0x02, 0x01, 0x02, 0xff, - ]; - assert_eq!( - CertificateRequestExtensions::read_bytes(&bytes).unwrap_err(), - InvalidMessage::TrailingData("CertificateRequestExtensions") - ); -} - -#[test] -fn refuses_certificate_req_ext_with_duplicate() { - let bytes = [0x00u8, 0x08, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00]; - assert_eq!( - CertificateRequestExtensions::read_bytes(&bytes).unwrap_err(), - InvalidMessage::DuplicateExtension(0x0099) - ); -} - -#[test] -fn refuses_new_session_ticket_ext_with_unparsed_bytes() { - let bytes = [ - 0x00u8, 0x09, 0x00, 0x2a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01, - ]; - assert_eq!( - NewSessionTicketExtensions::read_bytes(&bytes).unwrap_err(), - InvalidMessage::TrailingData("NewSessionTicketExtensions") - ); -} - -#[test] -fn refuses_new_session_ticket_ext_with_duplicate_extension() { - let bytes = [0x00u8, 0x08, 0x00, 0x99, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00]; - assert_eq!( - NewSessionTicketExtensions::read_bytes(&bytes).unwrap_err(), - InvalidMessage::DuplicateExtension(0x0099) - ); -} - -#[test] -fn rejects_truncated_sni() { - let bytes = [0, 1, 0]; - assert!(ServerNamePayload::read(&mut Reader::init(&bytes)).is_err()); - - let bytes = [0, 2, 0, 1]; - assert!(ServerNamePayload::read(&mut Reader::init(&bytes)).is_err()); - - let bytes = [0, 3, 0, 1, 0]; - assert!(ServerNamePayload::read(&mut Reader::init(&bytes)).is_err()); - - let bytes = [0, 4, 0, 2, 0, 0]; - assert!(ServerNamePayload::read(&mut Reader::init(&bytes)).is_err()); - - let bytes = [0, 5, 0, 3, 0, 0, 0]; - assert!(ServerNamePayload::read(&mut Reader::init(&bytes)).is_err()); - - let bytes = [0, 5, 0, 3, 0, 0, 1]; - assert!(ServerNamePayload::read(&mut Reader::init(&bytes)).is_err()); - - let bytes = [0, 6, 0, 4, 0, 0, 2, 0x68]; - assert!(ServerNamePayload::read(&mut Reader::init(&bytes)).is_err()); -} - -#[test] -fn rejects_empty_sni_extension() { - assert_eq!( - ClientExtensions::read_bytes(&[0, 6, 0, 0, 0, 2, 0, 0]).unwrap_err(), - InvalidMessage::IllegalEmptyList("ServerNames") - ); -} - -#[test] -fn rejects_duplicate_names_in_sni_extension() { - assert_eq!( - ClientExtensions::read_bytes(&[0, 14, 0, 0, 0, 10, 0, 8, 0, 0, 1, b'a', 0, 0, 1, b'b',]) - .unwrap_err(), - InvalidMessage::InvalidServerName - ); -} - -#[test] -fn can_round_trip_psk_identity() { - let bytes = [0, 1, 0x99, 0x11, 0x22, 0x33, 0x44]; - let psk_id = PresharedKeyIdentity::read(&mut Reader::init(&bytes)).unwrap(); - println!("{psk_id:?}"); - assert_eq!(psk_id.obfuscated_ticket_age, 0x11223344); - assert_eq!(psk_id.get_encoding(), bytes.to_vec()); - - let bytes = [0, 5, 0x1, 0x2, 0x3, 0x4, 0x5, 0x11, 0x22, 0x33, 0x44]; - let psk_id = PresharedKeyIdentity::read(&mut Reader::init(&bytes)).unwrap(); - println!("{psk_id:?}"); - assert_eq!(psk_id.identity.0, vec![0x1, 0x2, 0x3, 0x4, 0x5]); - assert_eq!(psk_id.obfuscated_ticket_age, 0x11223344); - assert_eq!(psk_id.get_encoding(), bytes.to_vec()); -} - -#[test] -fn can_round_trip_psk_offer() { - let bytes = [ - 0, 7, 0, 1, 0x99, 0x11, 0x22, 0x33, 0x44, 0, 4, 3, 0x01, 0x02, 0x3, - ]; - let psko = PresharedKeyOffer::read(&mut Reader::init(&bytes)).unwrap(); - println!("{psko:?}"); - - assert_eq!(psko.identities.len(), 1); - assert_eq!(psko.identities[0].identity.0, vec![0x99]); - assert_eq!(psko.identities[0].obfuscated_ticket_age, 0x11223344); - assert_eq!(psko.binders.len(), 1); - assert_eq!(psko.binders[0].as_ref(), &[1, 2, 3]); - assert_eq!(psko.get_encoding(), bytes.to_vec()); -} - -#[test] -fn can_round_trip_cert_status_req_for_ocsp() { - let ext = CertificateStatusRequest::build_ocsp(); - println!("{ext:?}"); - - let bytes = [ - 0, 11, 1, // OCSP - 0, 5, 0, 3, 0, 1, 1, 0, 1, 2, - ]; - - let csr = CertificateStatusRequest::read(&mut Reader::init(&bytes)).unwrap(); - println!("{csr:?}"); - assert_eq!(csr.get_encoding(), bytes.to_vec()); -} - -#[test] -fn can_round_trip_cert_status_req_for_other() { - let bytes = [ - 0, 5, 2, // !OCSP - 1, 2, 3, 4, - ]; - - let csr = CertificateStatusRequest::read(&mut Reader::init(&bytes)).unwrap(); - println!("{csr:?}"); - assert_eq!(csr.get_encoding(), bytes.to_vec()); -} - -#[test] -fn can_print_all_client_extensions() { - println!("client hello {:?}", sample_client_hello_payload()); -} - -#[test] -fn can_clone_all_client_extensions() { - let exts = sample_client_hello_payload().extensions; - let exts2 = exts.clone(); - println!("{exts:?}, {exts2:?}"); -} - -#[test] -fn client_extensions_basics() { - let src = ClientExtensions { - early_data_request: Some(()), - ..Default::default() - }; - let mut target = ClientExtensions::default(); - - assert_eq!(src.collect_used(), vec![ExtensionType::EarlyData]); - assert_eq!(target.collect_used(), vec![]); - - target.clone_one(&src, ExtensionType::EarlyData); - assert_eq!(target.collect_used(), vec![ExtensionType::EarlyData]); -} - -#[test] -fn client_extensions_empty() { - // both sides of empty-encoding branch - assert_eq!(ClientExtensions::default().get_encoding(), Vec::<u8>::new()); - assert_eq!( - ClientExtensions::read_bytes(&[]) - .unwrap() - .collect_used(), - vec![] - ); - - let early_data = b"\x00\x04\x00\x2a\x00\x00"; - assert_eq!( - ClientExtensions { - early_data_request: Some(()), - ..Default::default() - } - .get_encoding(), - early_data - ); - assert_eq!( - ClientExtensions::read_bytes(early_data) - .unwrap() - .collect_used(), - vec![ExtensionType::EarlyData] - ); -} - -#[test] -fn client_extensions_decode_checks_duplicates() { - // base - ClientExtensions::read_bytes(b"\x00\x04\x00\x2a\x00\x00").unwrap(); - - // duplicate known - assert_eq!( - ClientExtensions::read_bytes(b"\x00\x08\x00\x2a\x00\x00\x00\x2a\x00\x00").unwrap_err(), - InvalidMessage::DuplicateExtension(0x002a) - ); - - // duplicate unknown - assert_eq!( - ClientExtensions::read_bytes(b"\x00\x08\xff\xff\x00\x00\xff\xff\x00\x00").unwrap_err(), - InvalidMessage::DuplicateExtension(0xffff) - ); -} - -#[test] -fn client_extensions_ordering() { - // the important thing here is that PSK requests come last, - // ECH requests come second to last, and order of other extensions - // do vary. - - let psk_offer = PresharedKeyOffer { - identities: vec![], - binders: vec![], - }; - - let psk_and_ech = ClientExtensions { - early_data_request: Some(()), - extended_master_secret_request: Some(()), - preshared_key_offer: Some(psk_offer.clone()), - encrypted_client_hello: Some(EncryptedClientHello::Inner), - ..Default::default() - }; - - let psk_and_ech_with_contiguous = ClientExtensions { - contiguous_extensions: vec![ExtensionType::ExtendedMasterSecret], - ..psk_and_ech.clone() - }; - - let ech = ClientExtensions { - early_data_request: Some(()), - extended_master_secret_request: Some(()), - encrypted_client_hello: Some(EncryptedClientHello::Inner), - ..Default::default() - }; - - let psk = ClientExtensions { - early_data_request: Some(()), - extended_master_secret_request: Some(()), - preshared_key_offer: Some(psk_offer), - ..Default::default() - }; - - let neither = ClientExtensions { - early_data_request: Some(()), - extended_master_secret_request: Some(()), - ..Default::default() - }; - - fn encoding_with_order(order_seed: u16, exts: &ClientExtensions<'_>) -> Vec<u8> { - let mut e = exts.clone(); - e.order_seed = order_seed; - e.get_encoding() - } - - assert_ne!( - encoding_with_order(0, &psk_and_ech), - encoding_with_order(1, &psk_and_ech) - ); - assert_eq!( - encoding_with_order(0, &psk_and_ech_with_contiguous), - encoding_with_order(1, &psk_and_ech_with_contiguous) - ); - assert_ne!(encoding_with_order(0, &ech), encoding_with_order(1, &ech)); - assert_ne!(encoding_with_order(0, &psk), encoding_with_order(1, &psk)); - assert_ne!( - encoding_with_order(0, &neither), - encoding_with_order(1, &neither) - ); - - // check order invariants hold for all seeds - for seed in 0..=0xffff { - // must end with ECH and then PSK - assert!(encoding_with_order(seed, &psk_and_ech).ends_with( - b"\xfe\x0d\x00\x01\x01\ - \x00\x29\x00\x04\x00\x00\x00\x00" - )); - - // must end with EMS, then ECH and then PSK - assert!( - encoding_with_order(seed, &psk_and_ech_with_contiguous).ends_with( - b"\x00\x17\x00\x00\ - \xfe\x0d\x00\x01\x01\ - \x00\x29\x00\x04\x00\x00\x00\x00" - ) - ); - - // just PSK - assert!(encoding_with_order(seed, &psk).ends_with(b"\x00\x29\x00\x04\x00\x00\x00\x00")); - - // just ECH - assert!(encoding_with_order(seed, &ech).ends_with(b"\xfe\x0d\x00\x01\x01")); - } -} - -#[test] -fn test_truncated_psk_offer() { - let ext = PresharedKeyOffer { - identities: vec![PresharedKeyIdentity::new(vec![3, 4, 5], 123456)], - binders: vec![PresharedKeyBinder::from(vec![1, 2, 3])], - }; - - let mut enc = ext.get_encoding(); - println!("testing {ext:?} enc {enc:?}"); - for l in 0..enc.len() { - if l == 9 { - continue; - } - put_u16(l as u16, &mut enc); - let rc = PresharedKeyOffer::read_bytes(&enc); - assert!(rc.is_err()); - } -} - -#[test] -fn test_truncated_client_hello_is_detected() { - let ch = sample_client_hello_payload(); - let enc = ch.get_encoding(); - println!("testing {ch:?} enc {enc:?}"); - - for l in 0..enc.len() { - println!("len {:?} enc {:?}", l, &enc[..l]); - if l == 41 { - continue; // where extensions are empty - } - assert!(ClientHelloPayload::read_bytes(&enc[..l]).is_err()); - } -} - -#[test] -fn test_truncated_client_extension_is_detected() { - let chp = sample_client_hello_payload(); - - let enc = chp.extensions.get_encoding(); - println!("testing enc {enc:?}"); - - // "outer" truncation, i.e., where the extension-level length is longer than - // the input - for l in 1..enc.len() { - assert!(ClientExtensions::read_bytes(&enc[..l]).is_err()); - } -} - -#[test] -fn test_truncated_hello_retry_extension_is_detected() { - let hrr = sample_hello_retry_request(); - - let mut enc = hrr.extensions.get_encoding(); - println!("testing enc {enc:?}"); - - // "outer" truncation, i.e., where the extension-level length is longer than - // the input - for l in 0..enc.len() { - assert!(HelloRetryRequestExtensions::read_bytes(&enc[..l]).is_err()); - } - - // "inner" truncation, where the extension-level length agrees with the input - // length, but isn't long enough for the type of extension - for l in 0..(enc.len() - 4) { - put_u16(l as u16, &mut enc); - println!(" encoding {enc:?} len {l:?}"); - assert!(HelloRetryRequestExtensions::read_bytes(&enc).is_err()); - } -} - -#[test] -fn test_truncated_server_extension_is_detected() { - let shp = sample_server_hello_payload(); - - let mut enc = shp.extensions.get_encoding(); - println!("testing enc {enc:?}"); - - // "outer" truncation, i.e., where the extension-level length is longer than - // the input - for l in 0..enc.len() { - assert!(ServerExtensions::read_bytes(&enc[..l]).is_err()); - } - - // "inner" truncation, where the extension-level length agrees with the input - // length, but isn't long enough for the type of extension - for l in 0..(enc.len() - 4) { - put_u16(l as u16, &mut enc[..2]); - println!(" encoding {enc:?} len {l:?}"); - assert!(ServerExtensions::read_bytes(&enc).is_err()); - } -} - -#[test] -fn can_print_all_server_extensions() { - println!("server hello {:?}", sample_server_hello_payload()); -} - -#[test] -fn can_clone_all_server_extensions() { - let exts = sample_server_hello_payload().extensions; - let exts2 = exts.clone(); - println!("{exts:?}, {exts2:?}"); -} - -#[test] -fn can_round_trip_all_tls12_handshake_payloads() { - for hm in all_tls12_handshake_payloads().iter() { - println!("{:?}", hm.0.handshake_type()); - let bytes = hm.get_encoding(); - let mut rd = Reader::init(&bytes); - let other = HandshakeMessagePayload::read(&mut rd).unwrap(); - assert!(!rd.any_left()); - assert_eq!(hm.get_encoding(), other.get_encoding()); - - println!("{hm:?}"); - println!("{other:?}"); - } -} - -#[test] -fn can_into_owned_all_tls12_handshake_payloads() { - for hm in all_tls12_handshake_payloads().drain(..) { - let enc = hm.get_encoding(); - let debug = format!("{hm:?}"); - let other = hm.into_owned(); - assert_eq!(enc, other.get_encoding()); - assert_eq!(debug, format!("{other:?}")); - } -} - -#[test] -fn can_detect_truncation_of_all_tls12_handshake_payloads() { - for hm in all_tls12_handshake_payloads().iter() { - let mut enc = hm.get_encoding(); - println!("test {hm:?} enc {enc:?}"); - - // outer truncation - for l in 0..enc.len() { - assert!(HandshakeMessagePayload::read_bytes(&enc[..l]).is_err()) - } - - // inner truncation - for l in 0..enc.len() - 4 { - put_u24(l as u32, &mut enc[1..]); - println!(" check len {l:?} enc {enc:?}"); - - match (hm.0.handshake_type(), l) { - (HandshakeType::ClientHello, 41) - | (HandshakeType::ServerHello, 38) - | (HandshakeType::ServerKeyExchange, _) - | (HandshakeType::ClientKeyExchange, _) - | (HandshakeType::Finished, _) - | (HandshakeType::Unknown(_), _) => continue, - _ => {} - }; - - assert!( - HandshakeMessagePayload::read_version( - &mut Reader::init(&enc), - ProtocolVersion::TLSv1_2 - ) - .is_err() - ); - assert!(HandshakeMessagePayload::read_bytes(&enc).is_err()); - } - } -} - -#[test] -fn can_round_trip_all_tls13_handshake_payloads() { - for hm in all_tls13_handshake_payloads().iter() { - println!("{:?}", hm.0.handshake_type()); - let bytes = hm.get_encoding(); - let mut rd = Reader::init(&bytes); - - let other = - HandshakeMessagePayload::read_version(&mut rd, ProtocolVersion::TLSv1_3).unwrap(); - assert!(!rd.any_left()); - assert_eq!(hm.get_encoding(), other.get_encoding()); - - println!("{hm:?}"); - println!("{other:?}"); - } -} - -#[test] -fn can_into_owned_all_tls13_handshake_payloads() { - for hm in all_tls13_handshake_payloads().drain(..) { - let enc = hm.get_encoding(); - let debug = format!("{hm:?}"); - let other = hm.into_owned(); - assert_eq!(enc, other.get_encoding()); - assert_eq!(debug, format!("{other:?}")); - } -} - -#[test] -fn can_detect_truncation_of_all_tls13_handshake_payloads() { - for hm in all_tls13_handshake_payloads().iter() { - let mut enc = hm.get_encoding(); - println!("test {hm:?} enc {enc:?}"); - - // outer truncation - for l in 0..enc.len() { - assert!(HandshakeMessagePayload::read_bytes(&enc[..l]).is_err()) - } - - // inner truncation - for l in 0..enc.len() - 4 { - put_u24(l as u32, &mut enc[1..]); - println!(" check len {l:?} enc {enc:?}"); - - match (hm.0.handshake_type(), l) { - (HandshakeType::ClientHello, 41) - | (HandshakeType::ServerHello, 38) - | (HandshakeType::ServerKeyExchange, _) - | (HandshakeType::ClientKeyExchange, _) - | (HandshakeType::Finished, _) - | (HandshakeType::Unknown(_), _) => continue, - _ => {} - }; - - assert!( - HandshakeMessagePayload::read_version( - &mut Reader::init(&enc), - ProtocolVersion::TLSv1_3 - ) - .is_err() - ); - } - } -} - -fn put_u24(u: u32, b: &mut [u8]) { - b[0] = (u >> 16) as u8; - b[1] = (u >> 8) as u8; - b[2] = u as u8; -} - -#[test] -fn cannot_read_message_hash_from_network() { - let mh = HandshakeMessagePayload(HandshakePayload::MessageHash(Payload::new(vec![1, 2, 3]))); - println!("mh {mh:?}"); - let enc = mh.get_encoding(); - assert!(HandshakeMessagePayload::read_bytes(&enc).is_err()); -} - -#[test] -fn cannot_decode_huge_certificate() { - let mut buf = [0u8; 65 * 1024]; - // exactly 64KB decodes fine - buf[0] = 0x0b; - buf[1] = 0x01; - buf[2] = 0x00; - buf[3] = 0x03; - buf[4] = 0x01; - buf[5] = 0x00; - buf[6] = 0x00; - buf[7] = 0x00; - buf[8] = 0xff; - buf[9] = 0xfd; - HandshakeMessagePayload::read_bytes(&buf[..0x10000 + 7]).unwrap(); - - // however 64KB + 1 byte does not - buf[1] = 0x01; - buf[2] = 0x00; - buf[3] = 0x04; - buf[4] = 0x01; - buf[5] = 0x00; - buf[6] = 0x01; - assert_eq!( - HandshakeMessagePayload::read_bytes(&buf[..0x10001 + 7]).unwrap_err(), - InvalidMessage::CertificatePayloadTooLarge - ); -} - -#[test] -fn can_decode_server_hello_from_api_devicecheck_apple_com() { - let data = include_bytes!("../testdata/hello-api.devicecheck.apple.com.bin"); - let mut r = Reader::init(data); - let hm = HandshakeMessagePayload::read(&mut r).unwrap(); - println!("msg: {hm:?}"); -} - -#[test] -fn wrapped_dn_encoding() { - let subject = b"subject"; - let dn = DistinguishedName::in_sequence(&subject[..]); - const DER_SEQUENCE_TAG: u8 = 0x30; - let expected_prefix = vec![DER_SEQUENCE_TAG, subject.len() as u8]; - assert_eq!(dn.as_ref(), [expected_prefix, subject.to_vec()].concat()); -} - -fn sample_hello_retry_request() -> HelloRetryRequest { - HelloRetryRequest { - legacy_version: ProtocolVersion::TLSv1_2, - session_id: SessionId::empty(), - cipher_suite: CipherSuite::TLS_NULL_WITH_NULL_NULL, - extensions: HelloRetryRequestExtensions { - key_share: Some(NamedGroup::X25519), - cookie: Some(PayloadU16::new(vec![0])), - supported_versions: Some(ProtocolVersion::TLSv1_2), - encrypted_client_hello: Some(Payload::new(vec![1, 2, 3])), - order: None, - }, - } -} - -fn sample_client_hello_payload() -> ClientHelloPayload { - ClientHelloPayload { - client_version: ProtocolVersion::TLSv1_2, - random: Random::from([0; 32]), - session_id: SessionId::empty(), - cipher_suites: vec![CipherSuite::TLS_NULL_WITH_NULL_NULL], - compression_methods: vec![Compression::Null], - extensions: Box::new(ClientExtensions { - server_name: Some(ServerNamePayload::from( - &DnsName::try_from("hello").unwrap(), - )), - cookie: Some(PayloadU16::new(vec![1, 2, 3])), - signature_schemes: Some(vec![SignatureScheme::ECDSA_NISTP256_SHA256]), - session_ticket: Some(ClientSessionTicket::Request), - ec_point_formats: Some(SupportedEcPointFormats::default()), - named_groups: Some(vec![NamedGroup::X25519]), - protocols: Some(vec![ProtocolName::from(vec![0])]), - supported_versions: Some(SupportedProtocolVersions { - tls13: true, - ..Default::default() - }), - key_shares: Some(vec![KeyShareEntry::new(NamedGroup::X25519, &[1, 2, 3][..])]), - preshared_key_modes: Some(PskKeyExchangeModes { - psk_dhe: true, - psk: false, - }), - preshared_key_offer: Some(PresharedKeyOffer { - identities: vec![ - PresharedKeyIdentity::new(vec![3, 4, 5], 123456), - PresharedKeyIdentity::new(vec![6, 7, 8], 7891011), - ], - binders: vec![ - PresharedKeyBinder::from(vec![1, 2, 3]), - PresharedKeyBinder::from(vec![3, 4, 5]), - ], - }), - extended_master_secret_request: Some(()), - certificate_status_request: Some(CertificateStatusRequest::build_ocsp()), - server_certificate_types: Some(vec![CertificateType::RawPublicKey]), - client_certificate_types: Some(vec![CertificateType::RawPublicKey]), - transport_parameters: Some(Payload::new(vec![1, 2, 3])), - early_data_request: Some(()), - certificate_compression_algorithms: Some(vec![CertificateCompressionAlgorithm::Brotli]), - encrypted_client_hello: Some(EncryptedClientHello::Inner), - encrypted_client_hello_outer: Some(vec![ExtensionType::SCT]), - ..Default::default() - }), - } -} - -fn sample_server_hello_payload() -> ServerHelloPayload { - ServerHelloPayload { - legacy_version: ProtocolVersion::TLSv1_2, - random: Random::from([0; 32]), - session_id: SessionId::empty(), - cipher_suite: CipherSuite::TLS_NULL_WITH_NULL_NULL, - compression_method: Compression::Null, - extensions: Box::new(ServerExtensions { - ec_point_formats: Some(SupportedEcPointFormats::default()), - server_name_ack: Some(()), - session_ticket_ack: Some(()), - renegotiation_info: Some(PayloadU8::new(vec![0])), - selected_protocol: Some(SingleProtocolName::new(ProtocolName::from(vec![0]))), - key_share: Some(KeyShareEntry::new(NamedGroup::X25519, &[1, 2, 3][..])), - preshared_key: Some(3), - early_data_ack: Some(()), - encrypted_client_hello_ack: Some(ServerEncryptedClientHello { - retry_configs: vec![], - }), - extended_master_secret_ack: Some(()), - certificate_status_request_ack: Some(()), - selected_version: Some(ProtocolVersion::TLSv1_2), - transport_parameters: Some(Payload::new(vec![1, 2, 3])), - transport_parameters_draft: None, - client_certificate_type: Some(CertificateType::RawPublicKey), - server_certificate_type: Some(CertificateType::RawPublicKey), - unknown_extensions: Default::default(), - }), - } -} - -fn all_tls12_handshake_payloads() -> Vec<HandshakeMessagePayload<'static>> { - vec![ - HandshakeMessagePayload(HandshakePayload::HelloRequest), - HandshakeMessagePayload(HandshakePayload::ClientHello(sample_client_hello_payload())), - HandshakeMessagePayload(HandshakePayload::ServerHello(sample_server_hello_payload())), - HandshakeMessagePayload(HandshakePayload::HelloRetryRequest( - sample_hello_retry_request(), - )), - HandshakeMessagePayload(HandshakePayload::Certificate(CertificateChain(vec![ - CertificateDer::from(vec![1, 2, 3]), - ]))), - HandshakeMessagePayload(HandshakePayload::ServerKeyExchange( - sample_ecdhe_server_key_exchange_payload(), - )), - HandshakeMessagePayload(HandshakePayload::ServerKeyExchange( - sample_dhe_server_key_exchange_payload(), - )), - HandshakeMessagePayload(HandshakePayload::ServerKeyExchange( - sample_unknown_server_key_exchange_payload(), - )), - HandshakeMessagePayload(HandshakePayload::CertificateRequest( - sample_certificate_request_payload(), - )), - HandshakeMessagePayload(HandshakePayload::ServerHelloDone), - HandshakeMessagePayload(HandshakePayload::ClientKeyExchange(Payload::Borrowed(&[ - 1, 2, 3, - ]))), - HandshakeMessagePayload(HandshakePayload::NewSessionTicket( - sample_new_session_ticket_payload(), - )), - HandshakeMessagePayload(HandshakePayload::EncryptedExtensions( - sample_encrypted_extensions(), - )), - HandshakeMessagePayload(HandshakePayload::KeyUpdate( - KeyUpdateRequest::UpdateRequested, - )), - HandshakeMessagePayload(HandshakePayload::KeyUpdate( - KeyUpdateRequest::UpdateNotRequested, - )), - HandshakeMessagePayload(HandshakePayload::Finished(Payload::Borrowed(&[1, 2, 3]))), - HandshakeMessagePayload(HandshakePayload::CertificateStatus( - sample_certificate_status(), - )), - HandshakeMessagePayload(HandshakePayload::Unknown(( - HandshakeType::Unknown(99), - Payload::Borrowed(&[1, 2, 3]), - ))), - ] -} - -fn all_tls13_handshake_payloads() -> Vec<HandshakeMessagePayload<'static>> { - vec![ - HandshakeMessagePayload(HandshakePayload::HelloRequest), - HandshakeMessagePayload(HandshakePayload::ClientHello(sample_client_hello_payload())), - HandshakeMessagePayload(HandshakePayload::ServerHello(sample_server_hello_payload())), - HandshakeMessagePayload(HandshakePayload::HelloRetryRequest( - sample_hello_retry_request(), - )), - HandshakeMessagePayload(HandshakePayload::CertificateTls13( - sample_certificate_payload_tls13(), - )), - HandshakeMessagePayload(HandshakePayload::CompressedCertificate( - sample_compressed_certificate(), - )), - HandshakeMessagePayload(HandshakePayload::ServerKeyExchange( - sample_ecdhe_server_key_exchange_payload(), - )), - HandshakeMessagePayload(HandshakePayload::ServerKeyExchange( - sample_dhe_server_key_exchange_payload(), - )), - HandshakeMessagePayload(HandshakePayload::ServerKeyExchange( - sample_unknown_server_key_exchange_payload(), - )), - HandshakeMessagePayload(HandshakePayload::CertificateRequestTls13( - sample_certificate_request_payload_tls13(), - )), - HandshakeMessagePayload(HandshakePayload::CertificateVerify( - DigitallySignedStruct::new(SignatureScheme::ECDSA_NISTP256_SHA256, vec![1, 2, 3]), - )), - HandshakeMessagePayload(HandshakePayload::ServerHelloDone), - HandshakeMessagePayload(HandshakePayload::ClientKeyExchange(Payload::Borrowed(&[ - 1, 2, 3, - ]))), - HandshakeMessagePayload(HandshakePayload::NewSessionTicketTls13( - sample_new_session_ticket_payload_tls13(), - )), - HandshakeMessagePayload(HandshakePayload::EncryptedExtensions( - sample_encrypted_extensions(), - )), - HandshakeMessagePayload(HandshakePayload::KeyUpdate( - KeyUpdateRequest::UpdateRequested, - )), - HandshakeMessagePayload(HandshakePayload::KeyUpdate( - KeyUpdateRequest::UpdateNotRequested, - )), - HandshakeMessagePayload(HandshakePayload::Finished(Payload::Borrowed(&[1, 2, 3]))), - HandshakeMessagePayload(HandshakePayload::CertificateStatus( - sample_certificate_status(), - )), - HandshakeMessagePayload(HandshakePayload::Unknown(( - HandshakeType::Unknown(99), - Payload::Borrowed(&[1, 2, 3]), - ))), - ] -} - -fn sample_certificate_payload_tls13() -> CertificatePayloadTls13<'static> { - CertificatePayloadTls13 { - context: PayloadU8::new(vec![1, 2, 3]), - entries: vec![CertificateEntry { - cert: CertificateDer::from(vec![3, 4, 5]), - extensions: CertificateExtensions { - status: Some(CertificateStatus { - ocsp_response: PayloadU24(Payload::new(vec![1, 2, 3])), - }), - }, - }], - } -} - -fn sample_compressed_certificate() -> CompressedCertificatePayload<'static> { - CompressedCertificatePayload { - alg: CertificateCompressionAlgorithm::Brotli, - uncompressed_len: 123, - compressed: PayloadU24(Payload::new(vec![1, 2, 3])), - } -} - -fn sample_ecdhe_server_key_exchange_payload() -> ServerKeyExchangePayload { - ServerKeyExchangePayload::Known(ServerKeyExchange { - params: ServerKeyExchangeParams::Ecdh(ServerEcdhParams { - curve_params: EcParameters { - curve_type: ECCurveType::NamedCurve, - named_group: NamedGroup::X25519, - }, - public: PayloadU8::new(vec![1, 2, 3]), - }), - dss: DigitallySignedStruct::new(SignatureScheme::RSA_PSS_SHA256, vec![1, 2, 3]), - }) -} - -fn sample_dhe_server_key_exchange_payload() -> ServerKeyExchangePayload { - ServerKeyExchangePayload::Known(ServerKeyExchange { - params: ServerKeyExchangeParams::Dh(ServerDhParams { - dh_p: PayloadU16::new(vec![1, 2, 3]), - dh_g: PayloadU16::new(vec![2]), - dh_Ys: PayloadU16::new(vec![1, 2]), - }), - dss: DigitallySignedStruct::new(SignatureScheme::RSA_PSS_SHA256, vec![1, 2, 3]), - }) -} - -fn sample_unknown_server_key_exchange_payload() -> ServerKeyExchangePayload { - ServerKeyExchangePayload::Unknown(Payload::Borrowed(&[1, 2, 3])) -} - -fn sample_certificate_request_payload() -> CertificateRequestPayload { - CertificateRequestPayload { - certtypes: vec![ClientCertificateType::RSASign], - sigschemes: vec![SignatureScheme::ECDSA_NISTP256_SHA256], - canames: vec![DistinguishedName::from(vec![1, 2, 3])], - } -} - -fn sample_certificate_request_payload_tls13() -> CertificateRequestPayloadTls13 { - CertificateRequestPayloadTls13 { - context: PayloadU8::new(vec![1, 2, 3]), - extensions: CertificateRequestExtensions { - signature_algorithms: Some(vec![SignatureScheme::ECDSA_NISTP256_SHA256]), - authority_names: Some(vec![DistinguishedName::from(vec![1, 2, 3])]), - certificate_compression_algorithms: Some(vec![CertificateCompressionAlgorithm::Zlib]), - }, - } -} - -fn sample_new_session_ticket_payload() -> NewSessionTicketPayload { - NewSessionTicketPayload { - lifetime_hint: 1234, - ticket: Arc::new(PayloadU16::new(vec![1, 2, 3])), - } -} - -fn sample_new_session_ticket_payload_tls13() -> NewSessionTicketPayloadTls13 { - NewSessionTicketPayloadTls13 { - lifetime: 123, - age_add: 1234, - nonce: PayloadU8::new(vec![1, 2, 3]), - ticket: Arc::new(PayloadU16::new(vec![4, 5, 6])), - extensions: NewSessionTicketExtensions { - max_early_data_size: Some(1234), - }, - } -} - -fn sample_encrypted_extensions() -> Box<ServerExtensions<'static>> { - sample_server_hello_payload().extensions -} - -fn sample_certificate_status() -> CertificateStatus<'static> { - CertificateStatus { - ocsp_response: PayloadU24(Payload::new(vec![1, 2, 3])), - } -} diff --git a/vendor/rustls/src/msgs/macros.rs b/vendor/rustls/src/msgs/macros.rs deleted file mode 100644 index 53252a20..00000000 --- a/vendor/rustls/src/msgs/macros.rs +++ /dev/null @@ -1,313 +0,0 @@ -/// A macro which defines an enum type. -macro_rules! enum_builder { - ( - $(#[doc = $comment:literal])* - #[repr($uint:ty)] - $enum_vis:vis enum $enum_name:ident - { - $( $enum_var:ident => $enum_val:literal),* $(,)? - $( !Debug: - $( $enum_var_nd:ident => $enum_val_nd:literal),* $(,)? - )? - } - ) => { - $(#[doc = $comment])* - #[non_exhaustive] - #[derive(PartialEq, Eq, Clone, Copy)] - $enum_vis enum $enum_name { - $( $enum_var),* - $(, $($enum_var_nd),* )? - ,Unknown($uint) - } - - impl $enum_name { - // NOTE(allow) generated irrespective if there are callers - #[allow(dead_code)] - $enum_vis fn to_array(self) -> [u8; core::mem::size_of::<$uint>()] { - <$uint>::from(self).to_be_bytes() - } - - // NOTE(allow) generated irrespective if there are callers - #[allow(dead_code)] - $enum_vis fn as_str(&self) -> Option<&'static str> { - match self { - $( $enum_name::$enum_var => Some(stringify!($enum_var))),* - $(, $( $enum_name::$enum_var_nd => Some(stringify!($enum_var_nd))),* )? - ,$enum_name::Unknown(_) => None, - } - } - } - - impl Codec<'_> for $enum_name { - // NOTE(allow) fully qualified Vec is only needed in no-std mode - #[allow(unused_qualifications)] - fn encode(&self, bytes: &mut alloc::vec::Vec<u8>) { - <$uint>::from(*self).encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, crate::error::InvalidMessage> { - match <$uint>::read(r) { - Ok(x) => Ok($enum_name::from(x)), - Err(_) => Err(crate::error::InvalidMessage::MissingData(stringify!($enum_name))), - } - } - } - - impl From<$uint> for $enum_name { - fn from(x: $uint) -> Self { - match x { - $($enum_val => $enum_name::$enum_var),* - $(, $($enum_val_nd => $enum_name::$enum_var_nd),* )? - , x => $enum_name::Unknown(x), - } - } - } - - impl From<$enum_name> for $uint { - fn from(value: $enum_name) -> Self { - match value { - $( $enum_name::$enum_var => $enum_val),* - $(, $( $enum_name::$enum_var_nd => $enum_val_nd),* )? - ,$enum_name::Unknown(x) => x - } - } - } - - impl core::fmt::Debug for $enum_name { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - match self { - $( $enum_name::$enum_var => f.write_str(stringify!($enum_var)), )* - _ => write!(f, "{}(0x{:x?})", stringify!($enum_name), <$uint>::from(*self)), - } - } - } - }; -} - -/// A macro which defines a structure containing TLS extensions -/// -/// The contents are defined by two blocks, which are merged to -/// give the struct's items. The second block is optional. -/// -/// The first block defines the items read-into by decoding, -/// and used for encoding. -/// -/// The type of each item in the first block _must_ be an `Option`. -/// This records the presence of that extension. -/// -/// Each item in the first block is prefixed with a match arm, -/// which must match an `ExtensionType` variant. This maps -/// the item to its extension type. -/// -/// Items in the second block are not encoded or decoded-to. -/// They therefore must have a reasonable `Default` value. -/// -/// All items must have a `Default`, `Debug` and `Clone`. -macro_rules! extension_struct { - ( - $(#[doc = $comment:literal])* - $struct_vis:vis struct $struct_name:ident$(<$struct_lt:lifetime>)* - { - $( - $(#[$item_attr:meta])* - $item_id:path => $item_vis:vis $item_slot:ident : Option<$item_ty:ty>, - )+ - } $( + { - $( - $(#[$meta_attr:meta])* - $meta_vis:vis $meta_slot:ident : $meta_ty:ty, - )+ - })* - ) => { - $(#[doc = $comment])* - #[non_exhaustive] - #[derive(Clone, Default)] - $struct_vis struct $struct_name$(<$struct_lt>)* { - $( - $(#[$item_attr])* - $item_vis $item_slot: Option<$item_ty>, - )+ - $($( - $(#[$meta_attr])* - $meta_vis $meta_slot: $meta_ty, - )+)* - } - - impl<'a> $struct_name$(<$struct_lt>)* { - /// Reads one extension typ, length and body from `r`. - /// - /// Unhandled extensions (according to `read_extension_body()` are inserted into `unknown_extensions`) - fn read_one( - &mut self, - r: &mut Reader<'a>, - mut unknown: impl FnMut(ExtensionType) -> Result<(), InvalidMessage>, - ) -> Result<ExtensionType, InvalidMessage> { - let typ = ExtensionType::read(r)?; - let len = usize::from(u16::read(r)?); - let mut ext_body = r.sub(len)?; - match self.read_extension_body(typ, &mut ext_body)? { - true => ext_body.expect_empty(stringify!($struct_name))?, - false => unknown(typ)?, - - }; - Ok(typ) - } - - /// Reads one extension body for an extension named by `typ`. - /// - /// Returns `true` if handled, `false` otherwise. - /// - /// `r` is fully consumed if `typ` is unhandled. - fn read_extension_body( - &mut self, - typ: ExtensionType, - r: &mut Reader<'a>, - ) -> Result<bool, InvalidMessage> { - match typ { - $( - $item_id => Self::read_once(r, $item_id, &mut self.$item_slot)?, - )* - - // read and ignore unhandled extensions - _ => { - r.rest(); - return Ok(false); - } - } - - Ok(true) - } - - /// Decode `r` as `T` into `out`, only if `out` is `None`. - fn read_once<T>(r: &mut Reader<'a>, id: ExtensionType, out: &mut Option<T>) -> Result<(), InvalidMessage> - where T: Codec<'a>, - { - if let Some(_) = out { - return Err(InvalidMessage::DuplicateExtension(u16::from(id))); - } - - *out = Some(T::read(r)?); - Ok(()) - } - - /// Encode one extension body for `typ` into `output`. - /// - /// Adds nothing to `output` if `typ` is absent from this - /// struct, either because it is `None` or unhandled by - /// this struct. - fn encode_one( - &self, - typ: ExtensionType, - output: &mut Vec<u8>, - ) { - match typ { - $( - $item_id => if let Some(item) = &self.$item_slot { - typ.encode(output); - item.encode(LengthPrefixedBuffer::new(ListLength::U16, output).buf); - }, - - )* - _ => {}, - } - } - - /// Return a list of extensions whose items are `Some` - #[allow(dead_code)] - pub(crate) fn collect_used(&self) -> Vec<ExtensionType> { - let mut r = Vec::with_capacity(Self::ALL_EXTENSIONS.len()); - - $( - if let Some(_) = &self.$item_slot { - r.push($item_id); - } - )* - - r - } - - /// Clone the value of the extension identified by `typ` from `source` to `self`. - /// - /// Does nothing if `typ` is not an extension handled by this object. - #[allow(dead_code)] - pub(crate) fn clone_one( - &mut self, - source: &Self, - typ: ExtensionType, - ) { - match typ { - $( - $item_id => self.$item_slot = source.$item_slot.clone(), - )* - _ => {}, - } - } - - /// Remove the extension identified by `typ` from `self`. - #[allow(dead_code)] - pub(crate) fn clear(&mut self, typ: ExtensionType) { - match typ { - $( - $item_id => self.$item_slot = None, - )* - _ => {}, - } - } - - /// Return true if all present extensions are named in `allowed` - #[allow(dead_code)] - pub(crate) fn only_contains(&self, allowed: &[ExtensionType]) -> bool { - $( - if let Some(_) = &self.$item_slot { - if !allowed.contains(&$item_id) { - return false; - } - } - )* - - true - } - - /// Return true if any extension named in `exts` is present. - #[allow(dead_code)] - pub(crate) fn contains_any(&self, exts: &[ExtensionType]) -> bool { - for e in exts { - if self.contains(*e) { - return true; - } - } - false - } - - fn contains(&self, e: ExtensionType) -> bool { - match e { - $( - - $item_id => self.$item_slot.is_some(), - )* - _ => false, - } - } - - /// Every `ExtensionType` this structure may encode/decode. - const ALL_EXTENSIONS: &'static [ExtensionType] = &[ - $($item_id,)* - ]; - } - - impl<'a> core::fmt::Debug for $struct_name$(<$struct_lt>)* { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut ds = f.debug_struct(stringify!($struct_name)); - $( - if let Some(ext) = &self.$item_slot { - ds.field(stringify!($item_slot), ext); - } - )* - $($( - ds.field(stringify!($meta_slot), &self.$meta_slot); - )+)* - ds.finish_non_exhaustive() - } - } - } -} diff --git a/vendor/rustls/src/msgs/message/inbound.rs b/vendor/rustls/src/msgs/message/inbound.rs deleted file mode 100644 index f8b2181c..00000000 --- a/vendor/rustls/src/msgs/message/inbound.rs +++ /dev/null @@ -1,161 +0,0 @@ -use core::ops::{Deref, DerefMut, Range}; - -use crate::enums::{ContentType, ProtocolVersion}; -use crate::error::{Error, PeerMisbehaved}; -use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; - -/// A TLS frame, named TLSPlaintext in the standard. -/// -/// This inbound type borrows its encrypted payload from a buffer elsewhere. -/// It is used for joining and is consumed by decryption. -pub struct InboundOpaqueMessage<'a> { - pub typ: ContentType, - pub version: ProtocolVersion, - pub payload: BorrowedPayload<'a>, -} - -impl<'a> InboundOpaqueMessage<'a> { - /// Construct a new `InboundOpaqueMessage` from constituent fields. - /// - /// `payload` is borrowed. - pub fn new(typ: ContentType, version: ProtocolVersion, payload: &'a mut [u8]) -> Self { - Self { - typ, - version, - payload: BorrowedPayload(payload), - } - } - - /// Force conversion into a plaintext message. - /// - /// This should only be used for messages that are known to be in plaintext. Otherwise, the - /// `InboundOpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`. - pub fn into_plain_message(self) -> InboundPlainMessage<'a> { - InboundPlainMessage { - typ: self.typ, - version: self.version, - payload: self.payload.into_inner(), - } - } - - /// Force conversion into a plaintext message. - /// - /// `range` restricts the resulting message: this function panics if it is out of range for - /// the underlying message payload. - /// - /// This should only be used for messages that are known to be in plaintext. Otherwise, the - /// `InboundOpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`. - pub fn into_plain_message_range(self, range: Range<usize>) -> InboundPlainMessage<'a> { - InboundPlainMessage { - typ: self.typ, - version: self.version, - payload: &self.payload.into_inner()[range], - } - } - - /// For TLS1.3 (only), checks the length msg.payload is valid and removes the padding. - /// - /// Returns an error if the message (pre-unpadding) is too long, or the padding is invalid, - /// or the message (post-unpadding) is too long. - pub fn into_tls13_unpadded_message(mut self) -> Result<InboundPlainMessage<'a>, Error> { - let payload = &mut self.payload; - - if payload.len() > MAX_FRAGMENT_LEN + 1 { - return Err(Error::PeerSentOversizedRecord); - } - - self.typ = unpad_tls13_payload(payload); - if self.typ == ContentType::Unknown(0) { - return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into()); - } - - if payload.len() > MAX_FRAGMENT_LEN { - return Err(Error::PeerSentOversizedRecord); - } - - self.version = ProtocolVersion::TLSv1_3; - Ok(self.into_plain_message()) - } -} - -pub struct BorrowedPayload<'a>(&'a mut [u8]); - -impl Deref for BorrowedPayload<'_> { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - self.0 - } -} - -impl DerefMut for BorrowedPayload<'_> { - fn deref_mut(&mut self) -> &mut Self::Target { - self.0 - } -} - -impl<'a> BorrowedPayload<'a> { - pub fn truncate(&mut self, len: usize) { - if len >= self.len() { - return; - } - - self.0 = core::mem::take(&mut self.0) - .split_at_mut(len) - .0; - } - - pub(crate) fn into_inner(self) -> &'a mut [u8] { - self.0 - } - - pub(crate) fn pop(&mut self) -> Option<u8> { - if self.is_empty() { - return None; - } - - let len = self.len(); - let last = self[len - 1]; - self.truncate(len - 1); - Some(last) - } -} - -/// A TLS frame, named `TLSPlaintext` in the standard. -/// -/// This inbound type borrows its decrypted payload from the original buffer. -/// It results from decryption. -#[derive(Debug)] -pub struct InboundPlainMessage<'a> { - pub typ: ContentType, - pub version: ProtocolVersion, - pub payload: &'a [u8], -} - -impl InboundPlainMessage<'_> { - /// Returns true if the payload is a CCS message. - /// - /// We passthrough ChangeCipherSpec messages in the deframer without decrypting them. - /// Note: this is prior to the record layer, so is unencrypted. See - /// third paragraph of section 5 in RFC8446. - pub(crate) fn is_valid_ccs(&self) -> bool { - self.typ == ContentType::ChangeCipherSpec && self.payload == [0x01] - } -} - -/// Decode a TLS1.3 `TLSInnerPlaintext` encoding. -/// -/// `p` is a message payload, immediately post-decryption. This function -/// removes zero padding bytes, until a non-zero byte is encountered which is -/// the content type, which is returned. See RFC8446 s5.2. -/// -/// ContentType(0) is returned if the message payload is empty or all zeroes. -fn unpad_tls13_payload(p: &mut BorrowedPayload<'_>) -> ContentType { - loop { - match p.pop() { - Some(0) => {} - Some(content_type) => return ContentType::from(content_type), - None => return ContentType::Unknown(0), - } - } -} diff --git a/vendor/rustls/src/msgs/message/mod.rs b/vendor/rustls/src/msgs/message/mod.rs deleted file mode 100644 index d5cecc94..00000000 --- a/vendor/rustls/src/msgs/message/mod.rs +++ /dev/null @@ -1,262 +0,0 @@ -use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion}; -use crate::error::InvalidMessage; -use crate::msgs::alert::AlertMessagePayload; -use crate::msgs::base::Payload; -use crate::msgs::ccs::ChangeCipherSpecPayload; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::{AlertLevel, KeyUpdateRequest}; -use crate::msgs::handshake::{HandshakeMessagePayload, HandshakePayload}; - -mod inbound; -pub use inbound::{BorrowedPayload, InboundOpaqueMessage, InboundPlainMessage}; - -mod outbound; -use alloc::vec::Vec; - -pub(crate) use outbound::read_opaque_message_header; -pub use outbound::{OutboundChunks, OutboundOpaqueMessage, OutboundPlainMessage, PrefixedPayload}; - -#[derive(Debug)] -pub enum MessagePayload<'a> { - Alert(AlertMessagePayload), - // one handshake message, parsed - Handshake { - parsed: HandshakeMessagePayload<'a>, - encoded: Payload<'a>, - }, - // (potentially) multiple handshake messages, unparsed - HandshakeFlight(Payload<'a>), - ChangeCipherSpec(ChangeCipherSpecPayload), - ApplicationData(Payload<'a>), -} - -impl<'a> MessagePayload<'a> { - pub fn encode(&self, bytes: &mut Vec<u8>) { - match self { - Self::Alert(x) => x.encode(bytes), - Self::Handshake { encoded, .. } => bytes.extend(encoded.bytes()), - Self::HandshakeFlight(x) => bytes.extend(x.bytes()), - Self::ChangeCipherSpec(x) => x.encode(bytes), - Self::ApplicationData(x) => x.encode(bytes), - } - } - - pub fn handshake(parsed: HandshakeMessagePayload<'a>) -> Self { - Self::Handshake { - encoded: Payload::new(parsed.get_encoding()), - parsed, - } - } - - pub fn new( - typ: ContentType, - vers: ProtocolVersion, - payload: &'a [u8], - ) -> Result<Self, InvalidMessage> { - let mut r = Reader::init(payload); - match typ { - ContentType::ApplicationData => Ok(Self::ApplicationData(Payload::Borrowed(payload))), - ContentType::Alert => AlertMessagePayload::read(&mut r).map(MessagePayload::Alert), - ContentType::Handshake => { - HandshakeMessagePayload::read_version(&mut r, vers).map(|parsed| Self::Handshake { - parsed, - encoded: Payload::Borrowed(payload), - }) - } - ContentType::ChangeCipherSpec => { - ChangeCipherSpecPayload::read(&mut r).map(MessagePayload::ChangeCipherSpec) - } - _ => Err(InvalidMessage::InvalidContentType), - } - } - - pub fn content_type(&self) -> ContentType { - match self { - Self::Alert(_) => ContentType::Alert, - Self::Handshake { .. } | Self::HandshakeFlight(_) => ContentType::Handshake, - Self::ChangeCipherSpec(_) => ContentType::ChangeCipherSpec, - Self::ApplicationData(_) => ContentType::ApplicationData, - } - } - - pub(crate) fn into_owned(self) -> MessagePayload<'static> { - use MessagePayload::*; - match self { - Alert(x) => Alert(x), - Handshake { parsed, encoded } => Handshake { - parsed: parsed.into_owned(), - encoded: encoded.into_owned(), - }, - HandshakeFlight(x) => HandshakeFlight(x.into_owned()), - ChangeCipherSpec(x) => ChangeCipherSpec(x), - ApplicationData(x) => ApplicationData(x.into_owned()), - } - } -} - -impl From<Message<'_>> for PlainMessage { - fn from(msg: Message<'_>) -> Self { - let typ = msg.payload.content_type(); - let payload = match msg.payload { - MessagePayload::ApplicationData(payload) => payload.into_owned(), - _ => { - let mut buf = Vec::new(); - msg.payload.encode(&mut buf); - Payload::Owned(buf) - } - }; - - Self { - typ, - version: msg.version, - payload, - } - } -} - -/// A decrypted TLS frame -/// -/// This type owns all memory for its interior parts. It can be decrypted from an OpaqueMessage -/// or encrypted into an OpaqueMessage, and it is also used for joining and fragmenting. -#[derive(Clone, Debug)] -pub struct PlainMessage { - pub typ: ContentType, - pub version: ProtocolVersion, - pub payload: Payload<'static>, -} - -impl PlainMessage { - pub fn into_unencrypted_opaque(self) -> OutboundOpaqueMessage { - OutboundOpaqueMessage { - version: self.version, - typ: self.typ, - payload: PrefixedPayload::from(self.payload.bytes()), - } - } - - pub fn borrow_inbound(&self) -> InboundPlainMessage<'_> { - InboundPlainMessage { - version: self.version, - typ: self.typ, - payload: self.payload.bytes(), - } - } - - pub fn borrow_outbound(&self) -> OutboundPlainMessage<'_> { - OutboundPlainMessage { - version: self.version, - typ: self.typ, - payload: self.payload.bytes().into(), - } - } -} - -/// A message with decoded payload -#[derive(Debug)] -pub struct Message<'a> { - pub version: ProtocolVersion, - pub payload: MessagePayload<'a>, -} - -impl Message<'_> { - pub fn is_handshake_type(&self, hstyp: HandshakeType) -> bool { - // Bit of a layering violation, but OK. - if let MessagePayload::Handshake { parsed, .. } = &self.payload { - parsed.0.handshake_type() == hstyp - } else { - false - } - } - - pub fn build_alert(level: AlertLevel, desc: AlertDescription) -> Self { - Self { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::Alert(AlertMessagePayload { - level, - description: desc, - }), - } - } - - pub fn build_key_update_notify() -> Self { - Self { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), - )), - } - } - - pub fn build_key_update_request() -> Self { - Self { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateRequested), - )), - } - } - - #[cfg(feature = "std")] - pub(crate) fn into_owned(self) -> Message<'static> { - let Self { version, payload } = self; - Message { - version, - payload: payload.into_owned(), - } - } - - #[cfg(test)] - pub(crate) fn into_wire_bytes(self) -> Vec<u8> { - PlainMessage::from(self) - .into_unencrypted_opaque() - .encode() - } -} - -impl TryFrom<PlainMessage> for Message<'static> { - type Error = InvalidMessage; - - fn try_from(plain: PlainMessage) -> Result<Self, Self::Error> { - Ok(Self { - version: plain.version, - payload: MessagePayload::new(plain.typ, plain.version, plain.payload.bytes())? - .into_owned(), - }) - } -} - -/// Parses a plaintext message into a well-typed [`Message`]. -/// -/// A [`PlainMessage`] must contain plaintext content. Encrypted content should be stored in an -/// [`InboundOpaqueMessage`] and decrypted before being stored into a [`PlainMessage`]. -impl<'a> TryFrom<InboundPlainMessage<'a>> for Message<'a> { - type Error = InvalidMessage; - - fn try_from(plain: InboundPlainMessage<'a>) -> Result<Self, Self::Error> { - Ok(Self { - version: plain.version, - payload: MessagePayload::new(plain.typ, plain.version, plain.payload)?, - }) - } -} - -#[derive(Debug)] -pub enum MessageError { - TooShortForHeader, - TooShortForLength, - InvalidEmptyPayload, - MessageTooLarge, - InvalidContentType, - UnknownProtocolVersion, -} - -/// Content type, version and size. -pub(crate) const HEADER_SIZE: usize = 1 + 2 + 2; - -/// Maximum message payload size. -/// That's 2^14 payload bytes and a 2KB allowance for ciphertext overheads. -const MAX_PAYLOAD: u16 = 16_384 + 2048; - -/// Maximum on-the-wire message size. -#[cfg(feature = "std")] -pub(crate) const MAX_WIRE_SIZE: usize = MAX_PAYLOAD as usize + HEADER_SIZE; diff --git a/vendor/rustls/src/msgs/message/outbound.rs b/vendor/rustls/src/msgs/message/outbound.rs deleted file mode 100644 index 810c066c..00000000 --- a/vendor/rustls/src/msgs/message/outbound.rs +++ /dev/null @@ -1,422 +0,0 @@ -use alloc::vec::Vec; - -use super::{HEADER_SIZE, MAX_PAYLOAD, MessageError, PlainMessage}; -use crate::enums::{ContentType, ProtocolVersion}; -use crate::msgs::base::Payload; -use crate::msgs::codec::{Codec, Reader}; -use crate::record_layer::RecordLayer; - -/// A TLS frame, named `TLSPlaintext` in the standard. -/// -/// This outbound type borrows its "to be encrypted" payload from the "user". -/// It is used for fragmenting and is consumed by encryption. -#[derive(Debug)] -pub struct OutboundPlainMessage<'a> { - pub typ: ContentType, - pub version: ProtocolVersion, - pub payload: OutboundChunks<'a>, -} - -impl OutboundPlainMessage<'_> { - pub(crate) fn encoded_len(&self, record_layer: &RecordLayer) -> usize { - HEADER_SIZE + record_layer.encrypted_len(self.payload.len()) - } - - pub(crate) fn to_unencrypted_opaque(&self) -> OutboundOpaqueMessage { - let mut payload = PrefixedPayload::with_capacity(self.payload.len()); - payload.extend_from_chunks(&self.payload); - OutboundOpaqueMessage { - version: self.version, - typ: self.typ, - payload, - } - } -} - -/// A collection of borrowed plaintext slices. -/// -/// Warning: OutboundChunks does not guarantee that the simplest variant is used. -/// Multiple can hold non fragmented or empty payloads. -#[derive(Debug, Clone)] -pub enum OutboundChunks<'a> { - /// A single byte slice. Contrary to `Multiple`, this uses a single pointer indirection - Single(&'a [u8]), - /// A collection of chunks (byte slices) - /// and cursors to single out a fragmented range of bytes. - /// OutboundChunks assumes that start <= end - Multiple { - chunks: &'a [&'a [u8]], - start: usize, - end: usize, - }, -} - -impl<'a> OutboundChunks<'a> { - /// Create a payload from a slice of byte slices. - /// If fragmented the cursors are added by default: start = 0, end = length - pub fn new(chunks: &'a [&'a [u8]]) -> Self { - if chunks.len() == 1 { - Self::Single(chunks[0]) - } else { - Self::Multiple { - chunks, - start: 0, - end: chunks - .iter() - .map(|chunk| chunk.len()) - .sum(), - } - } - } - - /// Create a payload with a single empty slice - pub fn new_empty() -> Self { - Self::Single(&[]) - } - - /// Flatten the slice of byte slices to an owned vector of bytes - pub fn to_vec(&self) -> Vec<u8> { - let mut vec = Vec::with_capacity(self.len()); - self.copy_to_vec(&mut vec); - vec - } - - /// Append all bytes to a vector - pub fn copy_to_vec(&self, vec: &mut Vec<u8>) { - match *self { - Self::Single(chunk) => vec.extend_from_slice(chunk), - Self::Multiple { chunks, start, end } => { - let mut size = 0; - for chunk in chunks.iter() { - let psize = size; - let len = chunk.len(); - size += len; - if size <= start || psize >= end { - continue; - } - let start = start.saturating_sub(psize); - let end = if end - psize < len { end - psize } else { len }; - vec.extend_from_slice(&chunk[start..end]); - } - } - } - } - - /// Split self in two, around an index - /// Works similarly to `split_at` in the core library, except it doesn't panic if out of bound - pub fn split_at(&self, mid: usize) -> (Self, Self) { - match *self { - Self::Single(chunk) => { - let mid = Ord::min(mid, chunk.len()); - (Self::Single(&chunk[..mid]), Self::Single(&chunk[mid..])) - } - Self::Multiple { chunks, start, end } => { - let mid = Ord::min(start + mid, end); - ( - Self::Multiple { - chunks, - start, - end: mid, - }, - Self::Multiple { - chunks, - start: mid, - end, - }, - ) - } - } - } - - /// Returns true if the payload is empty - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the cumulative length of all chunks - pub fn len(&self) -> usize { - match self { - Self::Single(chunk) => chunk.len(), - Self::Multiple { start, end, .. } => end - start, - } - } -} - -impl<'a> From<&'a [u8]> for OutboundChunks<'a> { - fn from(payload: &'a [u8]) -> Self { - Self::Single(payload) - } -} - -/// A TLS frame, named `TLSPlaintext` in the standard. -/// -/// This outbound type owns all memory for its interior parts. -/// It results from encryption and is used for io write. -#[derive(Clone, Debug)] -pub struct OutboundOpaqueMessage { - pub typ: ContentType, - pub version: ProtocolVersion, - pub payload: PrefixedPayload, -} - -impl OutboundOpaqueMessage { - /// Construct a new `OpaqueMessage` from constituent fields. - /// - /// `body` is moved into the `payload` field. - pub fn new(typ: ContentType, version: ProtocolVersion, payload: PrefixedPayload) -> Self { - Self { - typ, - version, - payload, - } - } - - /// Construct by decoding from a [`Reader`]. - /// - /// `MessageError` allows callers to distinguish between valid prefixes (might - /// become valid if we read more data) and invalid data. - pub fn read(r: &mut Reader<'_>) -> Result<Self, MessageError> { - let (typ, version, len) = read_opaque_message_header(r)?; - - let content = r - .take(len as usize) - .ok_or(MessageError::TooShortForLength)?; - - Ok(Self { - typ, - version, - payload: PrefixedPayload::from(content), - }) - } - - pub fn encode(self) -> Vec<u8> { - let length = self.payload.len() as u16; - let mut encoded_payload = self.payload.0; - encoded_payload[0] = self.typ.into(); - encoded_payload[1..3].copy_from_slice(&self.version.to_array()); - encoded_payload[3..5].copy_from_slice(&(length).to_be_bytes()); - encoded_payload - } - - /// Force conversion into a plaintext message. - /// - /// This should only be used for messages that are known to be in plaintext. Otherwise, the - /// `OutboundOpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`. - pub fn into_plain_message(self) -> PlainMessage { - PlainMessage { - version: self.version, - typ: self.typ, - payload: Payload::Owned(self.payload.as_ref().to_vec()), - } - } -} - -#[derive(Clone, Debug)] -pub struct PrefixedPayload(Vec<u8>); - -impl PrefixedPayload { - pub fn with_capacity(capacity: usize) -> Self { - let mut prefixed_payload = Vec::with_capacity(HEADER_SIZE + capacity); - prefixed_payload.resize(HEADER_SIZE, 0); - Self(prefixed_payload) - } - - pub fn extend_from_slice(&mut self, slice: &[u8]) { - self.0.extend_from_slice(slice) - } - - pub fn extend_from_chunks(&mut self, chunks: &OutboundChunks<'_>) { - chunks.copy_to_vec(&mut self.0) - } - - pub fn truncate(&mut self, len: usize) { - self.0.truncate(len + HEADER_SIZE) - } - - fn len(&self) -> usize { - self.0.len() - HEADER_SIZE - } -} - -impl AsRef<[u8]> for PrefixedPayload { - fn as_ref(&self) -> &[u8] { - &self.0[HEADER_SIZE..] - } -} - -impl AsMut<[u8]> for PrefixedPayload { - fn as_mut(&mut self) -> &mut [u8] { - &mut self.0[HEADER_SIZE..] - } -} - -impl<'a> Extend<&'a u8> for PrefixedPayload { - fn extend<T: IntoIterator<Item = &'a u8>>(&mut self, iter: T) { - self.0.extend(iter) - } -} - -impl From<&[u8]> for PrefixedPayload { - fn from(content: &[u8]) -> Self { - let mut payload = Vec::with_capacity(HEADER_SIZE + content.len()); - payload.extend(&[0u8; HEADER_SIZE]); - payload.extend(content); - Self(payload) - } -} - -impl<const N: usize> From<&[u8; N]> for PrefixedPayload { - fn from(content: &[u8; N]) -> Self { - Self::from(&content[..]) - } -} - -pub(crate) fn read_opaque_message_header( - r: &mut Reader<'_>, -) -> Result<(ContentType, ProtocolVersion, u16), MessageError> { - let typ = ContentType::read(r).map_err(|_| MessageError::TooShortForHeader)?; - // Don't accept any new content-types. - if let ContentType::Unknown(_) = typ { - return Err(MessageError::InvalidContentType); - } - - let version = ProtocolVersion::read(r).map_err(|_| MessageError::TooShortForHeader)?; - // Accept only versions 0x03XX for any XX. - match &version { - ProtocolVersion::Unknown(v) if (v & 0xff00) != 0x0300 => { - return Err(MessageError::UnknownProtocolVersion); - } - _ => {} - }; - - let len = u16::read(r).map_err(|_| MessageError::TooShortForHeader)?; - - // Reject undersize messages - // implemented per section 5.1 of RFC8446 (TLSv1.3) - // per section 6.2.1 of RFC5246 (TLSv1.2) - if typ != ContentType::ApplicationData && len == 0 { - return Err(MessageError::InvalidEmptyPayload); - } - - // Reject oversize messages - if len >= MAX_PAYLOAD { - return Err(MessageError::MessageTooLarge); - } - - Ok((typ, version, len)) -} - -#[cfg(test)] -mod tests { - use std::{println, vec}; - - use super::*; - - #[test] - fn split_at_with_single_slice() { - let owner: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7]; - let borrowed_payload = OutboundChunks::Single(owner); - - let (before, after) = borrowed_payload.split_at(6); - println!("before:{before:?}\nafter:{after:?}"); - assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5]); - assert_eq!(after.to_vec(), &[6, 7]); - } - - #[test] - fn split_at_with_multiple_slices() { - let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]]; - let borrowed_payload = OutboundChunks::new(&owner); - - let (before, after) = borrowed_payload.split_at(3); - println!("before:{before:?}\nafter:{after:?}"); - assert_eq!(before.to_vec(), &[0, 1, 2]); - assert_eq!(after.to_vec(), &[3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); - - let (before, after) = borrowed_payload.split_at(8); - println!("before:{before:?}\nafter:{after:?}"); - assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7]); - assert_eq!(after.to_vec(), &[8, 9, 10, 11, 12]); - - let (before, after) = borrowed_payload.split_at(11); - println!("before:{before:?}\nafter:{after:?}"); - assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); - assert_eq!(after.to_vec(), &[11, 12]); - } - - #[test] - fn split_out_of_bounds() { - let owner: Vec<&[u8]> = vec![&[0, 1, 2, 3], &[4, 5], &[6, 7, 8], &[9, 10, 11, 12]]; - - let single_payload = OutboundChunks::Single(owner[0]); - let (before, after) = single_payload.split_at(17); - println!("before:{before:?}\nafter:{after:?}"); - assert_eq!(before.to_vec(), &[0, 1, 2, 3]); - assert!(after.is_empty()); - - let multiple_payload = OutboundChunks::new(&owner); - let (before, after) = multiple_payload.split_at(17); - println!("before:{before:?}\nafter:{after:?}"); - assert_eq!(before.to_vec(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]); - assert!(after.is_empty()); - - let empty_payload = OutboundChunks::new_empty(); - let (before, after) = empty_payload.split_at(17); - println!("before:{before:?}\nafter:{after:?}"); - assert!(before.is_empty()); - assert!(after.is_empty()); - } - - #[test] - fn empty_slices_mixed() { - let owner: Vec<&[u8]> = vec![&[], &[], &[0], &[], &[1, 2], &[], &[3], &[4], &[], &[]]; - let mut borrowed_payload = OutboundChunks::new(&owner); - let mut fragment_count = 0; - let mut fragment; - let expected_fragments: &[&[u8]] = &[&[0, 1], &[2, 3], &[4]]; - - while !borrowed_payload.is_empty() { - (fragment, borrowed_payload) = borrowed_payload.split_at(2); - println!("{fragment:?}"); - assert_eq!(&expected_fragments[fragment_count], &fragment.to_vec()); - fragment_count += 1; - } - assert_eq!(fragment_count, expected_fragments.len()); - } - - #[test] - fn exhaustive_splitting() { - let owner: Vec<u8> = (0..127).collect(); - let slices = (0..7) - .map(|i| &owner[((1 << i) - 1)..((1 << (i + 1)) - 1)]) - .collect::<Vec<_>>(); - let payload = OutboundChunks::new(&slices); - - assert_eq!(payload.to_vec(), owner); - println!("{payload:#?}"); - - for start in 0..128 { - for end in start..128 { - for mid in 0..(end - start) { - let witness = owner[start..end].split_at(mid); - let split_payload = payload - .split_at(end) - .0 - .split_at(start) - .1 - .split_at(mid); - assert_eq!( - witness.0, - split_payload.0.to_vec(), - "start: {start}, mid:{mid}, end:{end}" - ); - assert_eq!( - witness.1, - split_payload.1.to_vec(), - "start: {start}, mid:{mid}, end:{end}" - ); - } - } - } - } -} diff --git a/vendor/rustls/src/msgs/message_test.rs b/vendor/rustls/src/msgs/message_test.rs deleted file mode 100644 index 965a3572..00000000 --- a/vendor/rustls/src/msgs/message_test.rs +++ /dev/null @@ -1,124 +0,0 @@ -use std::io::Read; -use std::path::{Path, PathBuf}; -use std::prelude::v1::*; -use std::{format, fs, println, vec}; - -use super::base::Payload; -use super::codec::Reader; -use super::enums::AlertLevel; -use super::message::{Message, OutboundOpaqueMessage, PlainMessage}; -use crate::enums::{AlertDescription, HandshakeType}; -use crate::msgs::base::{MaybeEmpty, NonEmpty, PayloadU8, PayloadU16, PayloadU24}; - -#[test] -fn test_read_fuzz_corpus() { - fn corpus_dir() -> PathBuf { - let from_subcrate = Path::new("../fuzz/corpus/message"); - let from_root = Path::new("fuzz/corpus/message"); - - if from_root.is_dir() { - from_root.to_path_buf() - } else { - from_subcrate.to_path_buf() - } - } - - for file in fs::read_dir(corpus_dir()).unwrap() { - let mut f = fs::File::open(file.unwrap().path()).unwrap(); - let mut bytes = Vec::new(); - f.read_to_end(&mut bytes).unwrap(); - - let mut rd = Reader::init(&bytes); - let msg = OutboundOpaqueMessage::read(&mut rd) - .unwrap() - .into_plain_message(); - println!("{msg:?}"); - - let Ok(msg) = Message::try_from(msg) else { - continue; - }; - - let enc = PlainMessage::from(msg) - .into_unencrypted_opaque() - .encode(); - assert_eq!(bytes.to_vec(), enc); - assert_eq!(bytes[..rd.used()].to_vec(), enc); - } -} - -#[test] -fn can_read_safari_client_hello_with_ip_address_in_sni_extension() { - let _ = env_logger::Builder::new() - .filter(None, log::LevelFilter::Trace) - .try_init(); - - let bytes = b"\ - \x16\x03\x01\x00\xeb\x01\x00\x00\xe7\x03\x03\xb6\x1f\xe4\x3a\x55\ - \x90\x3e\xc0\x28\x9c\x12\xe0\x5c\x84\xea\x90\x1b\xfb\x11\xfc\xbd\ - \x25\x55\xda\x9f\x51\x93\x1b\x8d\x92\x66\xfd\x00\x00\x2e\xc0\x2c\ - \xc0\x2b\xc0\x24\xc0\x23\xc0\x0a\xc0\x09\xcc\xa9\xc0\x30\xc0\x2f\ - \xc0\x28\xc0\x27\xc0\x14\xc0\x13\xcc\xa8\x00\x9d\x00\x9c\x00\x3d\ - \x00\x3c\x00\x35\x00\x2f\xc0\x08\xc0\x12\x00\x0a\x01\x00\x00\x90\ - \xff\x01\x00\x01\x00\x00\x00\x00\x0e\x00\x0c\x00\x00\x09\x31\x32\ - \x37\x2e\x30\x2e\x30\x2e\x31\x00\x17\x00\x00\x00\x0d\x00\x18\x00\ - \x16\x04\x03\x08\x04\x04\x01\x05\x03\x02\x03\x08\x05\x08\x05\x05\ - \x01\x08\x06\x06\x01\x02\x01\x00\x05\x00\x05\x01\x00\x00\x00\x00\ - \x33\x74\x00\x00\x00\x12\x00\x00\x00\x10\x00\x30\x00\x2e\x02\x68\ - \x32\x05\x68\x32\x2d\x31\x36\x05\x68\x32\x2d\x31\x35\x05\x68\x32\ - \x2d\x31\x34\x08\x73\x70\x64\x79\x2f\x33\x2e\x31\x06\x73\x70\x64\ - \x79\x2f\x33\x08\x68\x74\x74\x70\x2f\x31\x2e\x31\x00\x0b\x00\x02\ - \x01\x00\x00\x0a\x00\x0a\x00\x08\x00\x1d\x00\x17\x00\x18\x00\x19"; - let mut rd = Reader::init(bytes); - let m = OutboundOpaqueMessage::read(&mut rd).unwrap(); - println!("m = {m:?}"); - Message::try_from(m.into_plain_message()).unwrap(); -} - -#[test] -fn alert_is_not_handshake() { - let m = Message::build_alert(AlertLevel::Fatal, AlertDescription::DecodeError); - assert!(!m.is_handshake_type(HandshakeType::ClientHello)); -} - -#[test] -fn construct_all_types() { - let samples = [ - &b"\x14\x03\x04\x00\x01\x01"[..], - &b"\x15\x03\x04\x00\x02\x01\x16"[..], - &b"\x16\x03\x04\x00\x05\x18\x00\x00\x01\x00"[..], - &b"\x17\x03\x04\x00\x04\x11\x22\x33\x44"[..], - &b"\x18\x03\x04\x00\x04\x11\x22\x33\x44"[..], - ]; - for &bytes in samples.iter() { - let m = OutboundOpaqueMessage::read(&mut Reader::init(bytes)).unwrap(); - println!("m = {m:?}"); - let m = Message::try_from(m.into_plain_message()); - println!("m' = {m:?}"); - } -} - -#[test] -fn debug_payload() { - assert_eq!("01020304", format!("{:?}", Payload::new(vec![1, 2, 3, 4]))); - assert_eq!( - "01020304", - format!("{:?}", PayloadU8::<NonEmpty>::new(vec![1, 2, 3, 4])) - ); - assert_eq!( - "01020304", - format!("{:?}", PayloadU16::<MaybeEmpty>::new(vec![1, 2, 3, 4])) - ); - assert_eq!( - "01020304", - format!("{:?}", PayloadU24(Payload::new(vec![1, 2, 3, 4]))) - ); -} - -#[test] -fn into_wire_format() { - // Message::into_wire_bytes() include both message-level and handshake-level headers - assert_eq!( - Message::build_key_update_request().into_wire_bytes(), - &[0x16, 0x3, 0x4, 0x0, 0x5, 0x18, 0x0, 0x0, 0x1, 0x1] - ); -} diff --git a/vendor/rustls/src/msgs/mod.rs b/vendor/rustls/src/msgs/mod.rs deleted file mode 100644 index 270c2dbc..00000000 --- a/vendor/rustls/src/msgs/mod.rs +++ /dev/null @@ -1,74 +0,0 @@ -#![allow(missing_docs)] -//! <https://langsec.org> cat says: -//! -//! ```text -//! ___ _ _ _ _ ___ ___ ___ ___ ___ _ _ ___ _____ ___ ___ _ _ -//! | __| | | | | | | | _ \ __/ __/ _ \ / __| \| |_ _|_ _|_ _/ _ \| \| | -//! | _|| |_| | |__| |__ | / _| (_| (_) | (_ | .` || | | | | | (_) | .` | -//! |_| \___/|____|____| |_|_\___\___\___/ \___|_|\_|___| |_| |___\___/|_|\_| -//! -//! -//! .__....._ _.....__, -//! .": o :': ;': o :". -//! `. `-' .'. .'. `-' .' -//! `---' `---' -//! -//! _...----... ... ... ...----..._ -//! .-'__..-""'---- `. `"` .' ----'""-..__`-. -//! '.-' _.--"""' `-._.-' '"""--._ `-.` -//! ' .-"' : `"-. ` -//! ' `. _.'"'._ .' ` -//! `. ,.-'" "'-., .' -//! `. .' -//! `-._ _.-' -//! `"'--...___...--'"` -//! -//! ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ _ _ ___ -//! | _ ) __| __/ _ \| _ \ __| | _ \ _ \/ _ \ / __| __/ __/ __|_ _| \| |/ __| -//! | _ \ _|| _| (_) | / _| | _/ / (_) | (__| _|\__ \__ \| || .` | (_ | -//! |___/___|_| \___/|_|_\___| |_| |_|_\\___/ \___|___|___/___/___|_|\_|\___| -//! ``` -//! -//! <https://langsec.org/ForWantOfANail-h2hc2014.pdf> - -#[macro_use] -mod macros; - -pub(crate) mod alert; -pub(crate) mod base; -pub(crate) mod ccs; -pub(crate) mod codec; -pub(crate) mod deframer; -pub(crate) mod enums; -pub(crate) mod fragmenter; -pub(crate) mod handshake; -pub(crate) mod message; -pub(crate) mod persist; - -#[cfg(test)] -mod handshake_test; - -pub mod ffdhe_groups; -#[cfg(test)] -mod message_test; - -#[cfg(test)] -mod tests { - use super::codec::Reader; - use super::message::{Message, OutboundOpaqueMessage}; - - #[test] - fn smoketest() { - let bytes = include_bytes!("../testdata/handshake-test.1.bin"); - let mut r = Reader::init(bytes); - - while r.any_left() { - let m = OutboundOpaqueMessage::read(&mut r).unwrap(); - - let out = m.clone().encode(); - assert!(!out.is_empty()); - - Message::try_from(m.into_plain_message()).unwrap(); - } - } -} diff --git a/vendor/rustls/src/msgs/persist.rs b/vendor/rustls/src/msgs/persist.rs deleted file mode 100644 index 8231c8ff..00000000 --- a/vendor/rustls/src/msgs/persist.rs +++ /dev/null @@ -1,492 +0,0 @@ -use alloc::vec::Vec; -use core::cmp; - -use pki_types::{DnsName, UnixTime}; -use zeroize::Zeroizing; - -use crate::client::ResolvesClientCert; -use crate::enums::{CipherSuite, ProtocolVersion}; -use crate::error::InvalidMessage; -use crate::msgs::base::{MaybeEmpty, PayloadU8, PayloadU16}; -use crate::msgs::codec::{Codec, Reader}; -#[cfg(feature = "tls12")] -use crate::msgs::handshake::SessionId; -use crate::msgs::handshake::{CertificateChain, ProtocolName}; -use crate::sync::{Arc, Weak}; -#[cfg(feature = "tls12")] -use crate::tls12::Tls12CipherSuite; -use crate::tls13::Tls13CipherSuite; -use crate::verify::ServerCertVerifier; - -pub(crate) struct Retrieved<T> { - pub(crate) value: T, - retrieved_at: UnixTime, -} - -impl<T> Retrieved<T> { - pub(crate) fn new(value: T, retrieved_at: UnixTime) -> Self { - Self { - value, - retrieved_at, - } - } - - pub(crate) fn map<M>(&self, f: impl FnOnce(&T) -> Option<&M>) -> Option<Retrieved<&M>> { - Some(Retrieved { - value: f(&self.value)?, - retrieved_at: self.retrieved_at, - }) - } -} - -impl Retrieved<&Tls13ClientSessionValue> { - pub(crate) fn obfuscated_ticket_age(&self) -> u32 { - let age_secs = self - .retrieved_at - .as_secs() - .saturating_sub(self.value.common.epoch); - let age_millis = age_secs as u32 * 1000; - age_millis.wrapping_add(self.value.age_add) - } -} - -impl<T: core::ops::Deref<Target = ClientSessionCommon>> Retrieved<T> { - pub(crate) fn has_expired(&self) -> bool { - let common = &*self.value; - common.lifetime_secs != 0 - && common - .epoch - .saturating_add(u64::from(common.lifetime_secs)) - < self.retrieved_at.as_secs() - } -} - -impl<T> core::ops::Deref for Retrieved<T> { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.value - } -} - -#[derive(Debug)] -pub struct Tls13ClientSessionValue { - suite: &'static Tls13CipherSuite, - age_add: u32, - max_early_data_size: u32, - pub(crate) common: ClientSessionCommon, - quic_params: PayloadU16, -} - -impl Tls13ClientSessionValue { - pub(crate) fn new( - suite: &'static Tls13CipherSuite, - ticket: Arc<PayloadU16>, - secret: &[u8], - server_cert_chain: CertificateChain<'static>, - server_cert_verifier: &Arc<dyn ServerCertVerifier>, - client_creds: &Arc<dyn ResolvesClientCert>, - time_now: UnixTime, - lifetime_secs: u32, - age_add: u32, - max_early_data_size: u32, - ) -> Self { - Self { - suite, - age_add, - max_early_data_size, - common: ClientSessionCommon::new( - ticket, - secret, - time_now, - lifetime_secs, - server_cert_chain, - server_cert_verifier, - client_creds, - ), - quic_params: PayloadU16::new(Vec::new()), - } - } - - pub fn max_early_data_size(&self) -> u32 { - self.max_early_data_size - } - - pub fn suite(&self) -> &'static Tls13CipherSuite { - self.suite - } - - #[doc(hidden)] - /// Test only: rewind epoch by `delta` seconds. - pub fn rewind_epoch(&mut self, delta: u32) { - self.common.epoch -= delta as u64; - } - - #[doc(hidden)] - /// Test only: replace `max_early_data_size` with `new` - pub fn _private_set_max_early_data_size(&mut self, new: u32) { - self.max_early_data_size = new; - } - - pub fn set_quic_params(&mut self, quic_params: &[u8]) { - self.quic_params = PayloadU16::new(quic_params.to_vec()); - } - - pub fn quic_params(&self) -> Vec<u8> { - self.quic_params.0.clone() - } -} - -impl core::ops::Deref for Tls13ClientSessionValue { - type Target = ClientSessionCommon; - - fn deref(&self) -> &Self::Target { - &self.common - } -} - -#[derive(Debug, Clone)] -pub struct Tls12ClientSessionValue { - #[cfg(feature = "tls12")] - suite: &'static Tls12CipherSuite, - #[cfg(feature = "tls12")] - pub(crate) session_id: SessionId, - #[cfg(feature = "tls12")] - extended_ms: bool, - #[doc(hidden)] - #[cfg(feature = "tls12")] - pub(crate) common: ClientSessionCommon, -} - -#[cfg(feature = "tls12")] -impl Tls12ClientSessionValue { - pub(crate) fn new( - suite: &'static Tls12CipherSuite, - session_id: SessionId, - ticket: Arc<PayloadU16>, - master_secret: &[u8], - server_cert_chain: CertificateChain<'static>, - server_cert_verifier: &Arc<dyn ServerCertVerifier>, - client_creds: &Arc<dyn ResolvesClientCert>, - time_now: UnixTime, - lifetime_secs: u32, - extended_ms: bool, - ) -> Self { - Self { - suite, - session_id, - extended_ms, - common: ClientSessionCommon::new( - ticket, - master_secret, - time_now, - lifetime_secs, - server_cert_chain, - server_cert_verifier, - client_creds, - ), - } - } - - pub(crate) fn ticket(&mut self) -> Arc<PayloadU16> { - self.common.ticket.clone() - } - - pub(crate) fn extended_ms(&self) -> bool { - self.extended_ms - } - - pub(crate) fn suite(&self) -> &'static Tls12CipherSuite { - self.suite - } - - #[doc(hidden)] - /// Test only: rewind epoch by `delta` seconds. - pub fn rewind_epoch(&mut self, delta: u32) { - self.common.epoch -= delta as u64; - } -} - -#[cfg(feature = "tls12")] -impl core::ops::Deref for Tls12ClientSessionValue { - type Target = ClientSessionCommon; - - fn deref(&self) -> &Self::Target { - &self.common - } -} - -#[derive(Debug, Clone)] -pub struct ClientSessionCommon { - ticket: Arc<PayloadU16>, - secret: Zeroizing<PayloadU8>, - epoch: u64, - lifetime_secs: u32, - server_cert_chain: Arc<CertificateChain<'static>>, - server_cert_verifier: Weak<dyn ServerCertVerifier>, - client_creds: Weak<dyn ResolvesClientCert>, -} - -impl ClientSessionCommon { - fn new( - ticket: Arc<PayloadU16>, - secret: &[u8], - time_now: UnixTime, - lifetime_secs: u32, - server_cert_chain: CertificateChain<'static>, - server_cert_verifier: &Arc<dyn ServerCertVerifier>, - client_creds: &Arc<dyn ResolvesClientCert>, - ) -> Self { - Self { - ticket, - secret: Zeroizing::new(PayloadU8::new(secret.to_vec())), - epoch: time_now.as_secs(), - lifetime_secs: cmp::min(lifetime_secs, MAX_TICKET_LIFETIME), - server_cert_chain: Arc::new(server_cert_chain), - server_cert_verifier: Arc::downgrade(server_cert_verifier), - client_creds: Arc::downgrade(client_creds), - } - } - - pub(crate) fn compatible_config( - &self, - server_cert_verifier: &Arc<dyn ServerCertVerifier>, - client_creds: &Arc<dyn ResolvesClientCert>, - ) -> bool { - let same_verifier = Weak::ptr_eq( - &Arc::downgrade(server_cert_verifier), - &self.server_cert_verifier, - ); - let same_creds = Weak::ptr_eq(&Arc::downgrade(client_creds), &self.client_creds); - - match (same_verifier, same_creds) { - (true, true) => true, - (false, _) => { - crate::log::trace!("resumption not allowed between different ServerCertVerifiers"); - false - } - (_, _) => { - crate::log::trace!( - "resumption not allowed between different ResolvesClientCert values" - ); - false - } - } - } - - pub(crate) fn server_cert_chain(&self) -> &CertificateChain<'static> { - &self.server_cert_chain - } - - pub(crate) fn secret(&self) -> &[u8] { - self.secret.0.as_ref() - } - - pub(crate) fn ticket(&self) -> &[u8] { - self.ticket.0.as_ref() - } -} - -static MAX_TICKET_LIFETIME: u32 = 7 * 24 * 60 * 60; - -/// This is the maximum allowed skew between server and client clocks, over -/// the maximum ticket lifetime period. This encompasses TCP retransmission -/// times in case packet loss occurs when the client sends the ClientHello -/// or receives the NewSessionTicket, _and_ actual clock skew over this period. -static MAX_FRESHNESS_SKEW_MS: u32 = 60 * 1000; - -// --- Server types --- -#[derive(Debug)] -pub struct ServerSessionValue { - pub(crate) sni: Option<DnsName<'static>>, - pub(crate) version: ProtocolVersion, - pub(crate) cipher_suite: CipherSuite, - pub(crate) master_secret: Zeroizing<PayloadU8>, - pub(crate) extended_ms: bool, - pub(crate) client_cert_chain: Option<CertificateChain<'static>>, - pub(crate) alpn: Option<PayloadU8>, - pub(crate) application_data: PayloadU16, - pub creation_time_sec: u64, - pub(crate) age_obfuscation_offset: u32, - freshness: Option<bool>, -} - -impl Codec<'_> for ServerSessionValue { - fn encode(&self, bytes: &mut Vec<u8>) { - if let Some(sni) = &self.sni { - 1u8.encode(bytes); - let sni_bytes: &str = sni.as_ref(); - PayloadU8::<MaybeEmpty>::encode_slice(sni_bytes.as_bytes(), bytes); - } else { - 0u8.encode(bytes); - } - self.version.encode(bytes); - self.cipher_suite.encode(bytes); - self.master_secret.encode(bytes); - (u8::from(self.extended_ms)).encode(bytes); - if let Some(chain) = &self.client_cert_chain { - 1u8.encode(bytes); - chain.encode(bytes); - } else { - 0u8.encode(bytes); - } - if let Some(alpn) = &self.alpn { - 1u8.encode(bytes); - alpn.encode(bytes); - } else { - 0u8.encode(bytes); - } - self.application_data.encode(bytes); - self.creation_time_sec.encode(bytes); - self.age_obfuscation_offset - .encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let has_sni = u8::read(r)?; - let sni = if has_sni == 1 { - let dns_name = PayloadU8::<MaybeEmpty>::read(r)?; - let dns_name = match DnsName::try_from(dns_name.0.as_slice()) { - Ok(dns_name) => dns_name.to_owned(), - Err(_) => return Err(InvalidMessage::InvalidServerName), - }; - - Some(dns_name) - } else { - None - }; - - let v = ProtocolVersion::read(r)?; - let cs = CipherSuite::read(r)?; - let ms = Zeroizing::new(PayloadU8::read(r)?); - let ems = u8::read(r)?; - let has_ccert = u8::read(r)? == 1; - let ccert = if has_ccert { - Some(CertificateChain::read(r)?.into_owned()) - } else { - None - }; - let has_alpn = u8::read(r)? == 1; - let alpn = if has_alpn { - Some(PayloadU8::read(r)?) - } else { - None - }; - let application_data = PayloadU16::read(r)?; - let creation_time_sec = u64::read(r)?; - let age_obfuscation_offset = u32::read(r)?; - - Ok(Self { - sni, - version: v, - cipher_suite: cs, - master_secret: ms, - extended_ms: ems == 1u8, - client_cert_chain: ccert, - alpn, - application_data, - creation_time_sec, - age_obfuscation_offset, - freshness: None, - }) - } -} - -impl ServerSessionValue { - pub(crate) fn new( - sni: Option<&DnsName<'_>>, - v: ProtocolVersion, - cs: CipherSuite, - ms: &[u8], - client_cert_chain: Option<CertificateChain<'static>>, - alpn: Option<ProtocolName>, - application_data: Vec<u8>, - creation_time: UnixTime, - age_obfuscation_offset: u32, - ) -> Self { - Self { - sni: sni.map(|dns| dns.to_owned()), - version: v, - cipher_suite: cs, - master_secret: Zeroizing::new(PayloadU8::new(ms.to_vec())), - extended_ms: false, - client_cert_chain, - alpn: alpn.map(|p| PayloadU8::new(p.as_ref().to_vec())), - application_data: PayloadU16::new(application_data), - creation_time_sec: creation_time.as_secs(), - age_obfuscation_offset, - freshness: None, - } - } - - #[cfg(feature = "tls12")] - pub(crate) fn set_extended_ms_used(&mut self) { - self.extended_ms = true; - } - - pub(crate) fn set_freshness( - mut self, - obfuscated_client_age_ms: u32, - time_now: UnixTime, - ) -> Self { - let client_age_ms = obfuscated_client_age_ms.wrapping_sub(self.age_obfuscation_offset); - let server_age_ms = (time_now - .as_secs() - .saturating_sub(self.creation_time_sec) as u32) - .saturating_mul(1000); - - let age_difference = server_age_ms.abs_diff(client_age_ms); - - self.freshness = Some(age_difference <= MAX_FRESHNESS_SKEW_MS); - self - } - - pub(crate) fn is_fresh(&self) -> bool { - self.freshness.unwrap_or_default() - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[cfg(feature = "std")] // for UnixTime::now - #[test] - fn serversessionvalue_is_debug() { - use std::{println, vec}; - let ssv = ServerSessionValue::new( - None, - ProtocolVersion::TLSv1_3, - CipherSuite::TLS13_AES_128_GCM_SHA256, - &[1, 2, 3], - None, - None, - vec![4, 5, 6], - UnixTime::now(), - 0x12345678, - ); - println!("{ssv:?}"); - } - - #[test] - fn serversessionvalue_no_sni() { - let bytes = [ - 0x00, 0x03, 0x03, 0xc0, 0x23, 0x03, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0xfe, 0xed, 0xf0, 0x0d, - ]; - let mut rd = Reader::init(&bytes); - let ssv = ServerSessionValue::read(&mut rd).unwrap(); - assert_eq!(ssv.get_encoding(), bytes); - } - - #[test] - fn serversessionvalue_with_cert() { - let bytes = [ - 0x00, 0x03, 0x03, 0xc0, 0x23, 0x03, 0x01, 0x02, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0xfe, 0xed, 0xf0, 0x0d, - ]; - let mut rd = Reader::init(&bytes); - let ssv = ServerSessionValue::read(&mut rd).unwrap(); - assert_eq!(ssv.get_encoding(), bytes); - } -} diff --git a/vendor/rustls/src/polyfill.rs b/vendor/rustls/src/polyfill.rs deleted file mode 100644 index 82571a22..00000000 --- a/vendor/rustls/src/polyfill.rs +++ /dev/null @@ -1,9 +0,0 @@ -/// Non-panicking `let (nonce, ciphertext) = ciphertext.split_at(...)`. -// TODO(XXX): remove once MSRV reaches 1.80 -#[allow(dead_code)] // Complicated conditional compilation guards elided -pub(crate) fn try_split_at(slice: &[u8], mid: usize) -> Option<(&[u8], &[u8])> { - match mid > slice.len() { - true => None, - false => Some(slice.split_at(mid)), - } -} diff --git a/vendor/rustls/src/quic.rs b/vendor/rustls/src/quic.rs deleted file mode 100644 index f00f3bba..00000000 --- a/vendor/rustls/src/quic.rs +++ /dev/null @@ -1,1022 +0,0 @@ -use alloc::boxed::Box; -use alloc::collections::VecDeque; -use alloc::vec::Vec; -#[cfg(feature = "std")] -use core::fmt::Debug; - -/// This module contains optional APIs for implementing QUIC TLS. -use crate::common_state::Side; -use crate::crypto::cipher::{AeadKey, Iv}; -use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock}; -use crate::enums::AlertDescription; -use crate::error::Error; -use crate::tls13::Tls13CipherSuite; -use crate::tls13::key_schedule::{ - hkdf_expand_label, hkdf_expand_label_aead_key, hkdf_expand_label_block, -}; - -#[cfg(feature = "std")] -mod connection { - use alloc::vec::Vec; - use core::fmt::{self, Debug}; - use core::ops::{Deref, DerefMut}; - - use pki_types::ServerName; - - use super::{DirectionalKeys, KeyChange, Version}; - use crate::client::{ClientConfig, ClientConnectionData}; - use crate::common_state::{CommonState, DEFAULT_BUFFER_LIMIT, Protocol}; - use crate::conn::{ConnectionCore, SideData}; - use crate::enums::{AlertDescription, ContentType, ProtocolVersion}; - use crate::error::Error; - use crate::msgs::base::Payload; - use crate::msgs::deframer::buffers::{DeframerVecBuffer, Locator}; - use crate::msgs::handshake::{ - ClientExtensionsInput, ServerExtensionsInput, TransportParameters, - }; - use crate::msgs::message::InboundPlainMessage; - use crate::server::{ServerConfig, ServerConnectionData}; - use crate::sync::Arc; - use crate::vecbuf::ChunkVecBuffer; - - /// A QUIC client or server connection. - #[derive(Debug)] - pub enum Connection { - /// A client connection - Client(ClientConnection), - /// A server connection - Server(ServerConnection), - } - - impl Connection { - /// Return the TLS-encoded transport parameters for the session's peer. - /// - /// See [`ConnectionCommon::quic_transport_parameters()`] for more details. - pub fn quic_transport_parameters(&self) -> Option<&[u8]> { - match self { - Self::Client(conn) => conn.quic_transport_parameters(), - Self::Server(conn) => conn.quic_transport_parameters(), - } - } - - /// Compute the keys for encrypting/decrypting 0-RTT packets, if available - pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> { - match self { - Self::Client(conn) => conn.zero_rtt_keys(), - Self::Server(conn) => conn.zero_rtt_keys(), - } - } - - /// Consume unencrypted TLS handshake data. - /// - /// Handshake data obtained from separate encryption levels should be supplied in separate calls. - pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { - match self { - Self::Client(conn) => conn.read_hs(plaintext), - Self::Server(conn) => conn.read_hs(plaintext), - } - } - - /// Emit unencrypted TLS handshake data. - /// - /// When this returns `Some(_)`, the new keys must be used for future handshake data. - pub fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> { - match self { - Self::Client(conn) => conn.write_hs(buf), - Self::Server(conn) => conn.write_hs(buf), - } - } - - /// Emit the TLS description code of a fatal alert, if one has arisen. - /// - /// Check after `read_hs` returns `Err(_)`. - pub fn alert(&self) -> Option<AlertDescription> { - match self { - Self::Client(conn) => conn.alert(), - Self::Server(conn) => conn.alert(), - } - } - - /// Derives key material from the agreed connection secrets. - /// - /// This function fills in `output` with `output.len()` bytes of key - /// material derived from the master session secret using `label` - /// and `context` for diversification. Ownership of the buffer is taken - /// by the function and returned via the Ok result to ensure no key - /// material leaks if the function fails. - /// - /// See RFC5705 for more details on what this does and is for. - /// - /// For TLS1.3 connections, this function does not use the - /// "early" exporter at any point. - /// - /// This function fails if called prior to the handshake completing; - /// check with [`CommonState::is_handshaking`] first. - #[inline] - pub fn export_keying_material<T: AsMut<[u8]>>( - &self, - output: T, - label: &[u8], - context: Option<&[u8]>, - ) -> Result<T, Error> { - match self { - Self::Client(conn) => conn - .core - .export_keying_material(output, label, context), - Self::Server(conn) => conn - .core - .export_keying_material(output, label, context), - } - } - } - - impl Deref for Connection { - type Target = CommonState; - - fn deref(&self) -> &Self::Target { - match self { - Self::Client(conn) => &conn.core.common_state, - Self::Server(conn) => &conn.core.common_state, - } - } - } - - impl DerefMut for Connection { - fn deref_mut(&mut self) -> &mut Self::Target { - match self { - Self::Client(conn) => &mut conn.core.common_state, - Self::Server(conn) => &mut conn.core.common_state, - } - } - } - - /// A QUIC client connection. - pub struct ClientConnection { - inner: ConnectionCommon<ClientConnectionData>, - } - - impl ClientConnection { - /// Make a new QUIC ClientConnection. - /// - /// This differs from `ClientConnection::new()` in that it takes an extra `params` argument, - /// which contains the TLS-encoded transport parameters to send. - pub fn new( - config: Arc<ClientConfig>, - quic_version: Version, - name: ServerName<'static>, - params: Vec<u8>, - ) -> Result<Self, Error> { - Self::new_with_alpn( - config.clone(), - quic_version, - name, - params, - config.alpn_protocols.clone(), - ) - } - - /// Make a new QUIC ClientConnection with custom ALPN protocols. - pub fn new_with_alpn( - config: Arc<ClientConfig>, - quic_version: Version, - name: ServerName<'static>, - params: Vec<u8>, - alpn_protocols: Vec<Vec<u8>>, - ) -> Result<Self, Error> { - if !config.supports_version(ProtocolVersion::TLSv1_3) { - return Err(Error::General( - "TLS 1.3 support is required for QUIC".into(), - )); - } - - if !config.supports_protocol(Protocol::Quic) { - return Err(Error::General( - "at least one ciphersuite must support QUIC".into(), - )); - } - - let exts = ClientExtensionsInput { - transport_parameters: Some(match quic_version { - Version::V1Draft => TransportParameters::QuicDraft(Payload::new(params)), - Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)), - }), - - ..ClientExtensionsInput::from_alpn(alpn_protocols) - }; - - let mut inner = ConnectionCore::for_client(config, name, exts, Protocol::Quic)?; - inner.common_state.quic.version = quic_version; - Ok(Self { - inner: inner.into(), - }) - } - - /// Returns True if the server signalled it will process early data. - /// - /// If you sent early data and this returns false at the end of the - /// handshake then the server will not process the data. This - /// is not an error, but you may wish to resend the data. - pub fn is_early_data_accepted(&self) -> bool { - self.inner.core.is_early_data_accepted() - } - - /// Returns the number of TLS1.3 tickets that have been received. - pub fn tls13_tickets_received(&self) -> u32 { - self.inner.tls13_tickets_received - } - } - - impl Deref for ClientConnection { - type Target = ConnectionCommon<ClientConnectionData>; - - fn deref(&self) -> &Self::Target { - &self.inner - } - } - - impl DerefMut for ClientConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } - } - - impl Debug for ClientConnection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("quic::ClientConnection") - .finish() - } - } - - impl From<ClientConnection> for Connection { - fn from(c: ClientConnection) -> Self { - Self::Client(c) - } - } - - /// A QUIC server connection. - pub struct ServerConnection { - inner: ConnectionCommon<ServerConnectionData>, - } - - impl ServerConnection { - /// Make a new QUIC ServerConnection. - /// - /// This differs from `ServerConnection::new()` in that it takes an extra `params` argument, - /// which contains the TLS-encoded transport parameters to send. - pub fn new( - config: Arc<ServerConfig>, - quic_version: Version, - params: Vec<u8>, - ) -> Result<Self, Error> { - if !config.supports_version(ProtocolVersion::TLSv1_3) { - return Err(Error::General( - "TLS 1.3 support is required for QUIC".into(), - )); - } - - if !config.supports_protocol(Protocol::Quic) { - return Err(Error::General( - "at least one ciphersuite must support QUIC".into(), - )); - } - - if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff { - return Err(Error::General( - "QUIC sessions must set a max early data of 0 or 2^32-1".into(), - )); - } - - let exts = ServerExtensionsInput { - transport_parameters: Some(match quic_version { - Version::V1Draft => TransportParameters::QuicDraft(Payload::new(params)), - Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)), - }), - }; - - let mut core = ConnectionCore::for_server(config, exts)?; - core.common_state.protocol = Protocol::Quic; - core.common_state.quic.version = quic_version; - Ok(Self { inner: core.into() }) - } - - /// Explicitly discard early data, notifying the client - /// - /// Useful if invariants encoded in `received_resumption_data()` cannot be respected. - /// - /// Must be called while `is_handshaking` is true. - pub fn reject_early_data(&mut self) { - self.inner.core.reject_early_data() - } - - /// Retrieves the server name, if any, used to select the certificate and - /// private key. - /// - /// This returns `None` until some time after the client's server name indication - /// (SNI) extension value is processed during the handshake. It will never be - /// `None` when the connection is ready to send or process application data, - /// unless the client does not support SNI. - /// - /// This is useful for application protocols that need to enforce that the - /// server name matches an application layer protocol hostname. For - /// example, HTTP/1.1 servers commonly expect the `Host:` header field of - /// every request on a connection to match the hostname in the SNI extension - /// when the client provides the SNI extension. - /// - /// The server name is also used to match sessions during session resumption. - pub fn server_name(&self) -> Option<&str> { - self.inner.core.get_sni_str() - } - } - - impl Deref for ServerConnection { - type Target = ConnectionCommon<ServerConnectionData>; - - fn deref(&self) -> &Self::Target { - &self.inner - } - } - - impl DerefMut for ServerConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } - } - - impl Debug for ServerConnection { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("quic::ServerConnection") - .finish() - } - } - - impl From<ServerConnection> for Connection { - fn from(c: ServerConnection) -> Self { - Self::Server(c) - } - } - - /// A shared interface for QUIC connections. - pub struct ConnectionCommon<Data> { - core: ConnectionCore<Data>, - deframer_buffer: DeframerVecBuffer, - sendable_plaintext: ChunkVecBuffer, - } - - impl<Data: SideData> ConnectionCommon<Data> { - /// Return the TLS-encoded transport parameters for the session's peer. - /// - /// While the transport parameters are technically available prior to the - /// completion of the handshake, they cannot be fully trusted until the - /// handshake completes, and reliance on them should be minimized. - /// However, any tampering with the parameters will cause the handshake - /// to fail. - pub fn quic_transport_parameters(&self) -> Option<&[u8]> { - self.core - .common_state - .quic - .params - .as_ref() - .map(|v| v.as_ref()) - } - - /// Compute the keys for encrypting/decrypting 0-RTT packets, if available - pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> { - let suite = self - .core - .common_state - .suite - .and_then(|suite| suite.tls13())?; - Some(DirectionalKeys::new( - suite, - suite.quic?, - self.core - .common_state - .quic - .early_secret - .as_ref()?, - self.core.common_state.quic.version, - )) - } - - /// Consume unencrypted TLS handshake data. - /// - /// Handshake data obtained from separate encryption levels should be supplied in separate calls. - pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> { - let range = self.deframer_buffer.extend(plaintext); - - self.core.hs_deframer.input_message( - InboundPlainMessage { - typ: ContentType::Handshake, - version: ProtocolVersion::TLSv1_3, - payload: &self.deframer_buffer.filled()[range.clone()], - }, - &Locator::new(self.deframer_buffer.filled()), - range.end, - ); - - self.core - .hs_deframer - .coalesce(self.deframer_buffer.filled_mut())?; - - self.core - .process_new_packets(&mut self.deframer_buffer, &mut self.sendable_plaintext)?; - - Ok(()) - } - - /// Emit unencrypted TLS handshake data. - /// - /// When this returns `Some(_)`, the new keys must be used for future handshake data. - pub fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> { - self.core - .common_state - .quic - .write_hs(buf) - } - - /// Emit the TLS description code of a fatal alert, if one has arisen. - /// - /// Check after `read_hs` returns `Err(_)`. - pub fn alert(&self) -> Option<AlertDescription> { - self.core.common_state.quic.alert - } - } - - impl<Data> Deref for ConnectionCommon<Data> { - type Target = CommonState; - - fn deref(&self) -> &Self::Target { - &self.core.common_state - } - } - - impl<Data> DerefMut for ConnectionCommon<Data> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.core.common_state - } - } - - impl<Data> From<ConnectionCore<Data>> for ConnectionCommon<Data> { - fn from(core: ConnectionCore<Data>) -> Self { - Self { - core, - deframer_buffer: DeframerVecBuffer::default(), - sendable_plaintext: ChunkVecBuffer::new(Some(DEFAULT_BUFFER_LIMIT)), - } - } - } -} - -#[cfg(feature = "std")] -pub use connection::{ClientConnection, Connection, ConnectionCommon, ServerConnection}; - -#[derive(Default)] -pub(crate) struct Quic { - /// QUIC transport parameters received from the peer during the handshake - pub(crate) params: Option<Vec<u8>>, - pub(crate) alert: Option<AlertDescription>, - pub(crate) hs_queue: VecDeque<(bool, Vec<u8>)>, - pub(crate) early_secret: Option<OkmBlock>, - pub(crate) hs_secrets: Option<Secrets>, - pub(crate) traffic_secrets: Option<Secrets>, - /// Whether keys derived from traffic_secrets have been passed to the QUIC implementation - #[cfg(feature = "std")] - pub(crate) returned_traffic_keys: bool, - pub(crate) version: Version, -} - -#[cfg(feature = "std")] -impl Quic { - pub(crate) fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> { - while let Some((_, msg)) = self.hs_queue.pop_front() { - buf.extend_from_slice(&msg); - if let Some(&(true, _)) = self.hs_queue.front() { - if self.hs_secrets.is_some() { - // Allow the caller to switch keys before proceeding. - break; - } - } - } - - if let Some(secrets) = self.hs_secrets.take() { - return Some(KeyChange::Handshake { - keys: Keys::new(&secrets), - }); - } - - if let Some(mut secrets) = self.traffic_secrets.take() { - if !self.returned_traffic_keys { - self.returned_traffic_keys = true; - let keys = Keys::new(&secrets); - secrets.update(); - return Some(KeyChange::OneRtt { - keys, - next: secrets, - }); - } - } - - None - } -} - -/// Secrets used to encrypt/decrypt traffic -#[derive(Clone)] -pub struct Secrets { - /// Secret used to encrypt packets transmitted by the client - pub(crate) client: OkmBlock, - /// Secret used to encrypt packets transmitted by the server - pub(crate) server: OkmBlock, - /// Cipher suite used with these secrets - suite: &'static Tls13CipherSuite, - quic: &'static dyn Algorithm, - side: Side, - version: Version, -} - -impl Secrets { - pub(crate) fn new( - client: OkmBlock, - server: OkmBlock, - suite: &'static Tls13CipherSuite, - quic: &'static dyn Algorithm, - side: Side, - version: Version, - ) -> Self { - Self { - client, - server, - suite, - quic, - side, - version, - } - } - - /// Derive the next set of packet keys - pub fn next_packet_keys(&mut self) -> PacketKeySet { - let keys = PacketKeySet::new(self); - self.update(); - keys - } - - pub(crate) fn update(&mut self) { - self.client = hkdf_expand_label_block( - self.suite - .hkdf_provider - .expander_for_okm(&self.client) - .as_ref(), - self.version.key_update_label(), - &[], - ); - self.server = hkdf_expand_label_block( - self.suite - .hkdf_provider - .expander_for_okm(&self.server) - .as_ref(), - self.version.key_update_label(), - &[], - ); - } - - fn local_remote(&self) -> (&OkmBlock, &OkmBlock) { - match self.side { - Side::Client => (&self.client, &self.server), - Side::Server => (&self.server, &self.client), - } - } -} - -/// Keys used to communicate in a single direction -pub struct DirectionalKeys { - /// Encrypts or decrypts a packet's headers - pub header: Box<dyn HeaderProtectionKey>, - /// Encrypts or decrypts the payload of a packet - pub packet: Box<dyn PacketKey>, -} - -impl DirectionalKeys { - pub(crate) fn new( - suite: &'static Tls13CipherSuite, - quic: &'static dyn Algorithm, - secret: &OkmBlock, - version: Version, - ) -> Self { - let builder = KeyBuilder::new(secret, version, quic, suite.hkdf_provider); - Self { - header: builder.header_protection_key(), - packet: builder.packet_key(), - } - } -} - -/// All AEADs we support have 16-byte tags. -const TAG_LEN: usize = 16; - -/// Authentication tag from an AEAD seal operation. -pub struct Tag([u8; TAG_LEN]); - -impl From<&[u8]> for Tag { - fn from(value: &[u8]) -> Self { - let mut array = [0u8; TAG_LEN]; - array.copy_from_slice(value); - Self(array) - } -} - -impl AsRef<[u8]> for Tag { - fn as_ref(&self) -> &[u8] { - &self.0 - } -} - -/// How a `Tls13CipherSuite` generates `PacketKey`s and `HeaderProtectionKey`s. -pub trait Algorithm: Send + Sync { - /// Produce a `PacketKey` encrypter/decrypter for this suite. - /// - /// `suite` is the entire suite this `Algorithm` appeared in. - /// `key` and `iv` is the key material to use. - fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>; - - /// Produce a `HeaderProtectionKey` encrypter/decrypter for this suite. - /// - /// `key` is the key material, which is `aead_key_len()` bytes in length. - fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>; - - /// The length in bytes of keys for this Algorithm. - /// - /// This controls the size of `AeadKey`s presented to `packet_key()` and `header_protection_key()`. - fn aead_key_len(&self) -> usize; - - /// Whether this algorithm is FIPS-approved. - fn fips(&self) -> bool { - false - } -} - -/// A QUIC header protection key -pub trait HeaderProtectionKey: Send + Sync { - /// Adds QUIC Header Protection. - /// - /// `sample` must contain the sample of encrypted payload; see - /// [Header Protection Sample]. - /// - /// `first` must reference the first byte of the header, referred to as - /// `packet[0]` in [Header Protection Application]. - /// - /// `packet_number` must reference the Packet Number field; this is - /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application]. - /// - /// Returns an error without modifying anything if `sample` is not - /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]), - /// or `packet_number` is longer than allowed (see [Packet Number Encoding and Decoding]). - /// - /// Otherwise, `first` and `packet_number` will have the header protection added. - /// - /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1 - /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2 - /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1 - fn encrypt_in_place( - &self, - sample: &[u8], - first: &mut u8, - packet_number: &mut [u8], - ) -> Result<(), Error>; - - /// Removes QUIC Header Protection. - /// - /// `sample` must contain the sample of encrypted payload; see - /// [Header Protection Sample]. - /// - /// `first` must reference the first byte of the header, referred to as - /// `packet[0]` in [Header Protection Application]. - /// - /// `packet_number` must reference the Packet Number field; this is - /// `packet[pn_offset:pn_offset+pn_length]` in [Header Protection Application]. - /// - /// Returns an error without modifying anything if `sample` is not - /// the correct length (see [Header Protection Sample] and [`Self::sample_len()`]), - /// or `packet_number` is longer than allowed (see - /// [Packet Number Encoding and Decoding]). - /// - /// Otherwise, `first` and `packet_number` will have the header protection removed. - /// - /// [Header Protection Application]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.1 - /// [Header Protection Sample]: https://datatracker.ietf.org/doc/html/rfc9001#section-5.4.2 - /// [Packet Number Encoding and Decoding]: https://datatracker.ietf.org/doc/html/rfc9000#section-17.1 - fn decrypt_in_place( - &self, - sample: &[u8], - first: &mut u8, - packet_number: &mut [u8], - ) -> Result<(), Error>; - - /// Expected sample length for the key's algorithm - fn sample_len(&self) -> usize; -} - -/// Keys to encrypt or decrypt the payload of a packet -pub trait PacketKey: Send + Sync { - /// Encrypt a QUIC packet - /// - /// Takes a `packet_number`, used to derive the nonce; the packet `header`, which is used as - /// the additional authenticated data; and the `payload`. The authentication tag is returned if - /// encryption succeeds. - /// - /// Fails if and only if the payload is longer than allowed by the cipher suite's AEAD algorithm. - fn encrypt_in_place( - &self, - packet_number: u64, - header: &[u8], - payload: &mut [u8], - ) -> Result<Tag, Error>; - - /// Decrypt a QUIC packet - /// - /// Takes the packet `header`, which is used as the additional authenticated data, and the - /// `payload`, which includes the authentication tag. - /// - /// If the return value is `Ok`, the decrypted payload can be found in `payload`, up to the - /// length found in the return value. - fn decrypt_in_place<'a>( - &self, - packet_number: u64, - header: &[u8], - payload: &'a mut [u8], - ) -> Result<&'a [u8], Error>; - - /// Tag length for the underlying AEAD algorithm - fn tag_len(&self) -> usize; - - /// Number of QUIC messages that can be safely encrypted with a single key of this type. - /// - /// Once a `MessageEncrypter` produced for this suite has encrypted more than - /// `confidentiality_limit` messages, an attacker gains an advantage in distinguishing it - /// from an ideal pseudorandom permutation (PRP). - /// - /// This is to be set on the assumption that messages are maximally sized -- - /// 2 ** 16. For non-QUIC TCP connections see [`CipherSuiteCommon::confidentiality_limit`][csc-limit]. - /// - /// [csc-limit]: crate::crypto::CipherSuiteCommon::confidentiality_limit - fn confidentiality_limit(&self) -> u64; - - /// Number of QUIC messages that can be safely decrypted with a single key of this type - /// - /// Once a `MessageDecrypter` produced for this suite has failed to decrypt `integrity_limit` - /// messages, an attacker gains an advantage in forging messages. - /// - /// This is not relevant for TLS over TCP (which is also implemented in this crate) - /// because a single failed decryption is fatal to the connection. - /// However, this quantity is used by QUIC. - fn integrity_limit(&self) -> u64; -} - -/// Packet protection keys for bidirectional 1-RTT communication -pub struct PacketKeySet { - /// Encrypts outgoing packets - pub local: Box<dyn PacketKey>, - /// Decrypts incoming packets - pub remote: Box<dyn PacketKey>, -} - -impl PacketKeySet { - fn new(secrets: &Secrets) -> Self { - let (local, remote) = secrets.local_remote(); - let (version, alg, hkdf) = (secrets.version, secrets.quic, secrets.suite.hkdf_provider); - Self { - local: KeyBuilder::new(local, version, alg, hkdf).packet_key(), - remote: KeyBuilder::new(remote, version, alg, hkdf).packet_key(), - } - } -} - -pub(crate) struct KeyBuilder<'a> { - expander: Box<dyn HkdfExpander>, - version: Version, - alg: &'a dyn Algorithm, -} - -impl<'a> KeyBuilder<'a> { - pub(crate) fn new( - secret: &OkmBlock, - version: Version, - alg: &'a dyn Algorithm, - hkdf: &'a dyn Hkdf, - ) -> Self { - Self { - expander: hkdf.expander_for_okm(secret), - version, - alg, - } - } - - /// Derive packet keys - pub(crate) fn packet_key(&self) -> Box<dyn PacketKey> { - let aead_key_len = self.alg.aead_key_len(); - let packet_key = hkdf_expand_label_aead_key( - self.expander.as_ref(), - aead_key_len, - self.version.packet_key_label(), - &[], - ); - - let packet_iv = - hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]); - self.alg - .packet_key(packet_key, packet_iv) - } - - /// Derive header protection keys - pub(crate) fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> { - let header_key = hkdf_expand_label_aead_key( - self.expander.as_ref(), - self.alg.aead_key_len(), - self.version.header_key_label(), - &[], - ); - self.alg - .header_protection_key(header_key) - } -} - -/// Produces QUIC initial keys from a TLS 1.3 ciphersuite and a QUIC key generation algorithm. -#[derive(Clone, Copy)] -pub struct Suite { - /// The TLS 1.3 ciphersuite used to derive keys. - pub suite: &'static Tls13CipherSuite, - /// The QUIC key generation algorithm used to derive keys. - pub quic: &'static dyn Algorithm, -} - -impl Suite { - /// Produce a set of initial keys given the connection ID, side and version - pub fn keys(&self, client_dst_connection_id: &[u8], side: Side, version: Version) -> Keys { - Keys::initial( - version, - self.suite, - self.quic, - client_dst_connection_id, - side, - ) - } -} - -/// Complete set of keys used to communicate with the peer -pub struct Keys { - /// Encrypts outgoing packets - pub local: DirectionalKeys, - /// Decrypts incoming packets - pub remote: DirectionalKeys, -} - -impl Keys { - /// Construct keys for use with initial packets - pub fn initial( - version: Version, - suite: &'static Tls13CipherSuite, - quic: &'static dyn Algorithm, - client_dst_connection_id: &[u8], - side: Side, - ) -> Self { - const CLIENT_LABEL: &[u8] = b"client in"; - const SERVER_LABEL: &[u8] = b"server in"; - let salt = version.initial_salt(); - let hs_secret = suite - .hkdf_provider - .extract_from_secret(Some(salt), client_dst_connection_id); - - let secrets = Secrets { - version, - client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]), - server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]), - suite, - quic, - side, - }; - Self::new(&secrets) - } - - fn new(secrets: &Secrets) -> Self { - let (local, remote) = secrets.local_remote(); - Self { - local: DirectionalKeys::new(secrets.suite, secrets.quic, local, secrets.version), - remote: DirectionalKeys::new(secrets.suite, secrets.quic, remote, secrets.version), - } - } -} - -/// Key material for use in QUIC packet spaces -/// -/// QUIC uses 4 different sets of keys (and progressive key updates for long-running connections): -/// -/// * Initial: these can be created from [`Keys::initial()`] -/// * 0-RTT keys: can be retrieved from [`ConnectionCommon::zero_rtt_keys()`] -/// * Handshake: these are returned from [`ConnectionCommon::write_hs()`] after `ClientHello` and -/// `ServerHello` messages have been exchanged -/// * 1-RTT keys: these are returned from [`ConnectionCommon::write_hs()`] after the handshake is done -/// -/// Once the 1-RTT keys have been exchanged, either side may initiate a key update. Progressive -/// update keys can be obtained from the [`Secrets`] returned in [`KeyChange::OneRtt`]. Note that -/// only packet keys are updated by key updates; header protection keys remain the same. -pub enum KeyChange { - /// Keys for the handshake space - Handshake { - /// Header and packet keys for the handshake space - keys: Keys, - }, - /// Keys for 1-RTT data - OneRtt { - /// Header and packet keys for 1-RTT data - keys: Keys, - /// Secrets to derive updated keys from - next: Secrets, - }, -} - -/// QUIC protocol version -/// -/// Governs version-specific behavior in the TLS layer -#[non_exhaustive] -#[derive(Clone, Copy, Debug)] -pub enum Version { - /// Draft versions 29, 30, 31 and 32 - V1Draft, - /// First stable RFC - V1, - /// Anti-ossification variant of V1 - V2, -} - -impl Version { - fn initial_salt(self) -> &'static [u8; 20] { - match self { - Self::V1Draft => &[ - // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-32#section-5.2 - 0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, - 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99, - ], - Self::V1 => &[ - // https://www.rfc-editor.org/rfc/rfc9001.html#name-initial-secrets - 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, - 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a, - ], - Self::V2 => &[ - // https://www.ietf.org/archive/id/draft-ietf-quic-v2-10.html#name-initial-salt-2 - 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26, - 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9, - ], - } - } - - /// Key derivation label for packet keys. - pub(crate) fn packet_key_label(&self) -> &'static [u8] { - match self { - Self::V1Draft | Self::V1 => b"quic key", - Self::V2 => b"quicv2 key", - } - } - - /// Key derivation label for packet "IV"s. - pub(crate) fn packet_iv_label(&self) -> &'static [u8] { - match self { - Self::V1Draft | Self::V1 => b"quic iv", - Self::V2 => b"quicv2 iv", - } - } - - /// Key derivation for header keys. - pub(crate) fn header_key_label(&self) -> &'static [u8] { - match self { - Self::V1Draft | Self::V1 => b"quic hp", - Self::V2 => b"quicv2 hp", - } - } - - fn key_update_label(&self) -> &'static [u8] { - match self { - Self::V1Draft | Self::V1 => b"quic ku", - Self::V2 => b"quicv2 ku", - } - } -} - -impl Default for Version { - fn default() -> Self { - Self::V1 - } -} - -#[cfg(test)] -mod tests { - use std::prelude::v1::*; - - use super::PacketKey; - use crate::quic::HeaderProtectionKey; - - #[test] - fn auto_traits() { - fn assert_auto<T: Send + Sync>() {} - assert_auto::<Box<dyn PacketKey>>(); - assert_auto::<Box<dyn HeaderProtectionKey>>(); - } -} diff --git a/vendor/rustls/src/rand.rs b/vendor/rustls/src/rand.rs deleted file mode 100644 index 23593863..00000000 --- a/vendor/rustls/src/rand.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! The single place where we generate random material for our own use. - -use alloc::vec; -use alloc::vec::Vec; - -use crate::crypto::SecureRandom; - -/// Make a [`Vec<u8>`] of the given size containing random material. -pub(crate) fn random_vec( - secure_random: &dyn SecureRandom, - len: usize, -) -> Result<Vec<u8>, GetRandomFailed> { - let mut v = vec![0; len]; - secure_random.fill(&mut v)?; - Ok(v) -} - -/// Return a uniformly random [`u32`]. -pub(crate) fn random_u32(secure_random: &dyn SecureRandom) -> Result<u32, GetRandomFailed> { - let mut buf = [0u8; 4]; - secure_random.fill(&mut buf)?; - Ok(u32::from_be_bytes(buf)) -} - -/// Return a uniformly random [`u16`]. -pub(crate) fn random_u16(secure_random: &dyn SecureRandom) -> Result<u16, GetRandomFailed> { - let mut buf = [0u8; 2]; - secure_random.fill(&mut buf)?; - Ok(u16::from_be_bytes(buf)) -} - -/// Random material generation failed. -#[derive(Debug)] -pub struct GetRandomFailed; diff --git a/vendor/rustls/src/record_layer.rs b/vendor/rustls/src/record_layer.rs deleted file mode 100644 index 8c2ea6b9..00000000 --- a/vendor/rustls/src/record_layer.rs +++ /dev/null @@ -1,336 +0,0 @@ -use alloc::boxed::Box; -use core::cmp::min; - -use crate::crypto::cipher::{InboundOpaqueMessage, MessageDecrypter, MessageEncrypter}; -use crate::error::Error; -use crate::log::trace; -use crate::msgs::message::{InboundPlainMessage, OutboundOpaqueMessage, OutboundPlainMessage}; - -#[derive(PartialEq)] -enum DirectionState { - /// No keying material. - Invalid, - - /// Keying material present, but not yet in use. - Prepared, - - /// Keying material in use. - Active, -} - -/// Record layer that tracks decryption and encryption keys. -pub(crate) struct RecordLayer { - message_encrypter: Box<dyn MessageEncrypter>, - message_decrypter: Box<dyn MessageDecrypter>, - write_seq_max: u64, - write_seq: u64, - read_seq: u64, - has_decrypted: bool, - encrypt_state: DirectionState, - decrypt_state: DirectionState, - - // Message encrypted with other keys may be encountered, so failures - // should be swallowed by the caller. This struct tracks the amount - // of message size this is allowed for. - trial_decryption_len: Option<usize>, -} - -impl RecordLayer { - /// Create new record layer with no keys. - pub(crate) fn new() -> Self { - Self { - message_encrypter: <dyn MessageEncrypter>::invalid(), - message_decrypter: <dyn MessageDecrypter>::invalid(), - write_seq_max: 0, - write_seq: 0, - read_seq: 0, - has_decrypted: false, - encrypt_state: DirectionState::Invalid, - decrypt_state: DirectionState::Invalid, - trial_decryption_len: None, - } - } - - /// Decrypt a TLS message. - /// - /// `encr` is a decoded message allegedly received from the peer. - /// If it can be decrypted, its decryption is returned. Otherwise, - /// an error is returned. - pub(crate) fn decrypt_incoming<'a>( - &mut self, - encr: InboundOpaqueMessage<'a>, - ) -> Result<Option<Decrypted<'a>>, Error> { - if self.decrypt_state != DirectionState::Active { - return Ok(Some(Decrypted { - want_close_before_decrypt: false, - plaintext: encr.into_plain_message(), - })); - } - - // Set to `true` if the peer appears to getting close to encrypting - // too many messages with this key. - // - // Perhaps if we send an alert well before their counter wraps, a - // buggy peer won't make a terrible mistake here? - // - // Note that there's no reason to refuse to decrypt: the security - // failure has already happened. - let want_close_before_decrypt = self.read_seq == SEQ_SOFT_LIMIT; - - let encrypted_len = encr.payload.len(); - match self - .message_decrypter - .decrypt(encr, self.read_seq) - { - Ok(plaintext) => { - self.read_seq += 1; - if !self.has_decrypted { - self.has_decrypted = true; - } - Ok(Some(Decrypted { - want_close_before_decrypt, - plaintext, - })) - } - Err(Error::DecryptError) if self.doing_trial_decryption(encrypted_len) => { - trace!("Dropping undecryptable message after aborted early_data"); - Ok(None) - } - Err(err) => Err(err), - } - } - - /// Encrypt a TLS message. - /// - /// `plain` is a TLS message we'd like to send. This function - /// panics if the requisite keying material hasn't been established yet. - pub(crate) fn encrypt_outgoing( - &mut self, - plain: OutboundPlainMessage<'_>, - ) -> OutboundOpaqueMessage { - debug_assert!(self.encrypt_state == DirectionState::Active); - assert!(self.next_pre_encrypt_action() != PreEncryptAction::Refuse); - let seq = self.write_seq; - self.write_seq += 1; - self.message_encrypter - .encrypt(plain, seq) - .unwrap() - } - - /// Prepare to use the given `MessageEncrypter` for future message encryption. - /// It is not used until you call `start_encrypting`. - pub(crate) fn prepare_message_encrypter( - &mut self, - cipher: Box<dyn MessageEncrypter>, - max_messages: u64, - ) { - self.message_encrypter = cipher; - self.write_seq = 0; - self.write_seq_max = min(SEQ_SOFT_LIMIT, max_messages); - self.encrypt_state = DirectionState::Prepared; - } - - /// Prepare to use the given `MessageDecrypter` for future message decryption. - /// It is not used until you call `start_decrypting`. - pub(crate) fn prepare_message_decrypter(&mut self, cipher: Box<dyn MessageDecrypter>) { - self.message_decrypter = cipher; - self.read_seq = 0; - self.decrypt_state = DirectionState::Prepared; - } - - /// Start using the `MessageEncrypter` previously provided to the previous - /// call to `prepare_message_encrypter`. - pub(crate) fn start_encrypting(&mut self) { - debug_assert!(self.encrypt_state == DirectionState::Prepared); - self.encrypt_state = DirectionState::Active; - } - - /// Start using the `MessageDecrypter` previously provided to the previous - /// call to `prepare_message_decrypter`. - pub(crate) fn start_decrypting(&mut self) { - debug_assert!(self.decrypt_state == DirectionState::Prepared); - self.decrypt_state = DirectionState::Active; - } - - /// Set and start using the given `MessageEncrypter` for future outgoing - /// message encryption. - pub(crate) fn set_message_encrypter( - &mut self, - cipher: Box<dyn MessageEncrypter>, - max_messages: u64, - ) { - self.prepare_message_encrypter(cipher, max_messages); - self.start_encrypting(); - } - - /// Set and start using the given `MessageDecrypter` for future incoming - /// message decryption. - pub(crate) fn set_message_decrypter(&mut self, cipher: Box<dyn MessageDecrypter>) { - self.prepare_message_decrypter(cipher); - self.start_decrypting(); - self.trial_decryption_len = None; - } - - /// Set and start using the given `MessageDecrypter` for future incoming - /// message decryption, and enable "trial decryption" mode for when TLS1.3 - /// 0-RTT is attempted but rejected by the server. - pub(crate) fn set_message_decrypter_with_trial_decryption( - &mut self, - cipher: Box<dyn MessageDecrypter>, - max_length: usize, - ) { - self.prepare_message_decrypter(cipher); - self.start_decrypting(); - self.trial_decryption_len = Some(max_length); - } - - pub(crate) fn finish_trial_decryption(&mut self) { - self.trial_decryption_len = None; - } - - pub(crate) fn next_pre_encrypt_action(&self) -> PreEncryptAction { - self.pre_encrypt_action(0) - } - - /// Return a remedial action when we are near to encrypting too many messages. - /// - /// `add` is added to the current sequence number. `add` as `0` means - /// "the next message processed by `encrypt_outgoing`" - pub(crate) fn pre_encrypt_action(&self, add: u64) -> PreEncryptAction { - match self.write_seq.saturating_add(add) { - v if v == self.write_seq_max => PreEncryptAction::RefreshOrClose, - SEQ_HARD_LIMIT.. => PreEncryptAction::Refuse, - _ => PreEncryptAction::Nothing, - } - } - - pub(crate) fn is_encrypting(&self) -> bool { - self.encrypt_state == DirectionState::Active - } - - /// Return true if we have ever decrypted a message. This is used in place - /// of checking the read_seq since that will be reset on key updates. - pub(crate) fn has_decrypted(&self) -> bool { - self.has_decrypted - } - - pub(crate) fn write_seq(&self) -> u64 { - self.write_seq - } - - pub(crate) fn read_seq(&self) -> u64 { - self.read_seq - } - - pub(crate) fn encrypted_len(&self, payload_len: usize) -> usize { - self.message_encrypter - .encrypted_payload_len(payload_len) - } - - fn doing_trial_decryption(&mut self, requested: usize) -> bool { - match self - .trial_decryption_len - .and_then(|value| value.checked_sub(requested)) - { - Some(remaining) => { - self.trial_decryption_len = Some(remaining); - true - } - _ => false, - } - } -} - -/// Result of decryption. -#[derive(Debug)] -pub(crate) struct Decrypted<'a> { - /// Whether the peer appears to be getting close to encrypting too many messages with this key. - pub(crate) want_close_before_decrypt: bool, - /// The decrypted message. - pub(crate) plaintext: InboundPlainMessage<'a>, -} - -#[derive(Debug, Eq, PartialEq)] -pub(crate) enum PreEncryptAction { - /// No action is needed before calling `encrypt_outgoing` - Nothing, - - /// A `key_update` request should be sent ASAP. - /// - /// If that is not possible (for example, the connection is TLS1.2), a `close_notify` - /// alert should be sent instead. - RefreshOrClose, - - /// Do not call `encrypt_outgoing` further, it will panic rather than - /// over-use the key. - Refuse, -} - -const SEQ_SOFT_LIMIT: u64 = 0xffff_ffff_ffff_0000u64; -const SEQ_HARD_LIMIT: u64 = 0xffff_ffff_ffff_fffeu64; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_has_decrypted() { - use crate::{ContentType, ProtocolVersion}; - - struct PassThroughDecrypter; - impl MessageDecrypter for PassThroughDecrypter { - fn decrypt<'a>( - &mut self, - m: InboundOpaqueMessage<'a>, - _: u64, - ) -> Result<InboundPlainMessage<'a>, Error> { - Ok(m.into_plain_message()) - } - } - - // A record layer starts out invalid, having never decrypted. - let mut record_layer = RecordLayer::new(); - assert!(matches!( - record_layer.decrypt_state, - DirectionState::Invalid - )); - assert_eq!(record_layer.read_seq, 0); - assert!(!record_layer.has_decrypted()); - - // Preparing the record layer should update the decrypt state, but shouldn't affect whether it - // has decrypted. - record_layer.prepare_message_decrypter(Box::new(PassThroughDecrypter)); - assert!(matches!( - record_layer.decrypt_state, - DirectionState::Prepared - )); - assert_eq!(record_layer.read_seq, 0); - assert!(!record_layer.has_decrypted()); - - // Starting decryption should update the decrypt state, but not affect whether it has decrypted. - record_layer.start_decrypting(); - assert!(matches!(record_layer.decrypt_state, DirectionState::Active)); - assert_eq!(record_layer.read_seq, 0); - assert!(!record_layer.has_decrypted()); - - // Decrypting a message should update the read_seq and track that we have now performed - // a decryption. - record_layer - .decrypt_incoming(InboundOpaqueMessage::new( - ContentType::Handshake, - ProtocolVersion::TLSv1_2, - &mut [0xC0, 0xFF, 0xEE], - )) - .unwrap(); - assert!(matches!(record_layer.decrypt_state, DirectionState::Active)); - assert_eq!(record_layer.read_seq, 1); - assert!(record_layer.has_decrypted()); - - // Resetting the record layer message decrypter (as if a key update occurred) should reset - // the read_seq number, but not our knowledge of whether we have decrypted previously. - record_layer.set_message_decrypter(Box::new(PassThroughDecrypter)); - assert!(matches!(record_layer.decrypt_state, DirectionState::Active)); - assert_eq!(record_layer.read_seq, 0); - assert!(record_layer.has_decrypted()); - } -} diff --git a/vendor/rustls/src/server/builder.rs b/vendor/rustls/src/server/builder.rs deleted file mode 100644 index d1b7b24a..00000000 --- a/vendor/rustls/src/server/builder.rs +++ /dev/null @@ -1,127 +0,0 @@ -use alloc::vec::Vec; -use core::marker::PhantomData; - -use pki_types::{CertificateDer, PrivateKeyDer}; - -use super::{ResolvesServerCert, ServerConfig, handy}; -use crate::builder::{ConfigBuilder, WantsVerifier}; -use crate::error::Error; -use crate::sign::{CertifiedKey, SingleCertAndKey}; -use crate::sync::Arc; -use crate::verify::{ClientCertVerifier, NoClientAuth}; -use crate::{NoKeyLog, compress, versions}; - -impl ConfigBuilder<ServerConfig, WantsVerifier> { - /// Choose how to verify client certificates. - pub fn with_client_cert_verifier( - self, - client_cert_verifier: Arc<dyn ClientCertVerifier>, - ) -> ConfigBuilder<ServerConfig, WantsServerCert> { - ConfigBuilder { - state: WantsServerCert { - versions: self.state.versions, - verifier: client_cert_verifier, - }, - provider: self.provider, - time_provider: self.time_provider, - side: PhantomData, - } - } - - /// Disable client authentication. - pub fn with_no_client_auth(self) -> ConfigBuilder<ServerConfig, WantsServerCert> { - self.with_client_cert_verifier(Arc::new(NoClientAuth)) - } -} - -/// A config builder state where the caller must supply how to provide a server certificate to -/// the connecting peer. -/// -/// For more information, see the [`ConfigBuilder`] documentation. -#[derive(Clone, Debug)] -pub struct WantsServerCert { - versions: versions::EnabledVersions, - verifier: Arc<dyn ClientCertVerifier>, -} - -impl ConfigBuilder<ServerConfig, WantsServerCert> { - /// Sets a single certificate chain and matching private key. This - /// certificate and key is used for all subsequent connections, - /// irrespective of things like SNI hostname. - /// - /// Note that the end-entity certificate must have the - /// [Subject Alternative Name](https://tools.ietf.org/html/rfc6125#section-4.1) - /// extension to describe, e.g., the valid DNS name. The `commonName` field is - /// disregarded. - /// - /// `cert_chain` is a vector of DER-encoded certificates. - /// `key_der` is a DER-encoded private key as PKCS#1, PKCS#8, or SEC1. The - /// `aws-lc-rs` and `ring` [`CryptoProvider`][crate::CryptoProvider]s support - /// all three encodings, but other `CryptoProviders` may not. - /// - /// This function fails if `key_der` is invalid, or if the - /// `SubjectPublicKeyInfo` from the private key does not match the public - /// key for the end-entity certificate from the `cert_chain`. - pub fn with_single_cert( - self, - cert_chain: Vec<CertificateDer<'static>>, - key_der: PrivateKeyDer<'static>, - ) -> Result<ServerConfig, Error> { - let certified_key = CertifiedKey::from_der(cert_chain, key_der, self.crypto_provider())?; - Ok(self.with_cert_resolver(Arc::new(SingleCertAndKey::from(certified_key)))) - } - - /// Sets a single certificate chain, matching private key and optional OCSP - /// response. This certificate and key is used for all - /// subsequent connections, irrespective of things like SNI hostname. - /// - /// `cert_chain` is a vector of DER-encoded certificates. - /// `key_der` is a DER-encoded private key as PKCS#1, PKCS#8, or SEC1. The - /// `aws-lc-rs` and `ring` [`CryptoProvider`][crate::CryptoProvider]s support - /// all three encodings, but other `CryptoProviders` may not. - /// `ocsp` is a DER-encoded OCSP response. Ignored if zero length. - /// - /// This function fails if `key_der` is invalid, or if the - /// `SubjectPublicKeyInfo` from the private key does not match the public - /// key for the end-entity certificate from the `cert_chain`. - pub fn with_single_cert_with_ocsp( - self, - cert_chain: Vec<CertificateDer<'static>>, - key_der: PrivateKeyDer<'static>, - ocsp: Vec<u8>, - ) -> Result<ServerConfig, Error> { - let mut certified_key = - CertifiedKey::from_der(cert_chain, key_der, self.crypto_provider())?; - certified_key.ocsp = Some(ocsp); - Ok(self.with_cert_resolver(Arc::new(SingleCertAndKey::from(certified_key)))) - } - - /// Sets a custom [`ResolvesServerCert`]. - pub fn with_cert_resolver(self, cert_resolver: Arc<dyn ResolvesServerCert>) -> ServerConfig { - ServerConfig { - provider: self.provider, - verifier: self.state.verifier, - cert_resolver, - ignore_client_order: false, - max_fragment_size: None, - #[cfg(feature = "std")] - session_storage: handy::ServerSessionMemoryCache::new(256), - #[cfg(not(feature = "std"))] - session_storage: Arc::new(handy::NoServerSessionStorage {}), - ticketer: Arc::new(handy::NeverProducesTickets {}), - alpn_protocols: Vec::new(), - versions: self.state.versions, - key_log: Arc::new(NoKeyLog {}), - enable_secret_extraction: false, - max_early_data_size: 0, - send_half_rtt_data: false, - send_tls13_tickets: 2, - #[cfg(feature = "tls12")] - require_ems: cfg!(feature = "fips"), - time_provider: self.time_provider, - cert_compressors: compress::default_cert_compressors().to_vec(), - cert_compression_cache: Arc::new(compress::CompressionCache::default()), - cert_decompressors: compress::default_cert_decompressors().to_vec(), - } - } -} diff --git a/vendor/rustls/src/server/common.rs b/vendor/rustls/src/server/common.rs deleted file mode 100644 index 8310998a..00000000 --- a/vendor/rustls/src/server/common.rs +++ /dev/null @@ -1,35 +0,0 @@ -use pki_types::CertificateDer; - -use crate::sign; - -/// ActiveCertifiedKey wraps [`sign::CertifiedKey`] and tracks OSCP state in a single handshake. -pub(super) struct ActiveCertifiedKey<'a> { - key: &'a sign::CertifiedKey, - ocsp: Option<&'a [u8]>, -} - -impl ActiveCertifiedKey<'_> { - pub(super) fn from_certified_key(key: &sign::CertifiedKey) -> ActiveCertifiedKey<'_> { - ActiveCertifiedKey { - key, - ocsp: key.ocsp.as_deref(), - } - } - - /// Get the certificate chain - #[inline] - pub(super) fn get_cert(&self) -> &[CertificateDer<'static>] { - &self.key.cert - } - - /// Get the signing key - #[inline] - pub(super) fn get_key(&self) -> &dyn sign::SigningKey { - &*self.key.key - } - - #[inline] - pub(super) fn get_ocsp(&self) -> Option<&[u8]> { - self.ocsp - } -} diff --git a/vendor/rustls/src/server/handy.rs b/vendor/rustls/src/server/handy.rs deleted file mode 100644 index ea3ec5d9..00000000 --- a/vendor/rustls/src/server/handy.rs +++ /dev/null @@ -1,356 +0,0 @@ -use alloc::vec::Vec; -use core::fmt::Debug; - -use crate::server::ClientHello; -use crate::sync::Arc; -use crate::{server, sign}; - -/// Something which never stores sessions. -#[derive(Debug)] -pub struct NoServerSessionStorage {} - -impl server::StoresServerSessions for NoServerSessionStorage { - fn put(&self, _id: Vec<u8>, _sec: Vec<u8>) -> bool { - false - } - fn get(&self, _id: &[u8]) -> Option<Vec<u8>> { - None - } - fn take(&self, _id: &[u8]) -> Option<Vec<u8>> { - None - } - fn can_cache(&self) -> bool { - false - } -} - -#[cfg(any(feature = "std", feature = "hashbrown"))] -mod cache { - use alloc::vec::Vec; - use core::fmt::{Debug, Formatter}; - - use crate::lock::Mutex; - use crate::sync::Arc; - use crate::{limited_cache, server}; - - /// An implementer of `StoresServerSessions` that stores everything - /// in memory. If enforces a limit on the number of stored sessions - /// to bound memory usage. - pub struct ServerSessionMemoryCache { - cache: Mutex<limited_cache::LimitedCache<Vec<u8>, Vec<u8>>>, - } - - impl ServerSessionMemoryCache { - /// Make a new ServerSessionMemoryCache. `size` is the maximum - /// number of stored sessions, and may be rounded-up for - /// efficiency. - #[cfg(feature = "std")] - pub fn new(size: usize) -> Arc<Self> { - Arc::new(Self { - cache: Mutex::new(limited_cache::LimitedCache::new(size)), - }) - } - - /// Make a new ServerSessionMemoryCache. `size` is the maximum - /// number of stored sessions, and may be rounded-up for - /// efficiency. - #[cfg(not(feature = "std"))] - pub fn new<M: crate::lock::MakeMutex>(size: usize) -> Arc<Self> { - Arc::new(Self { - cache: Mutex::new::<M>(limited_cache::LimitedCache::new(size)), - }) - } - } - - impl server::StoresServerSessions for ServerSessionMemoryCache { - fn put(&self, key: Vec<u8>, value: Vec<u8>) -> bool { - self.cache - .lock() - .unwrap() - .insert(key, value); - true - } - - fn get(&self, key: &[u8]) -> Option<Vec<u8>> { - self.cache - .lock() - .unwrap() - .get(key) - .cloned() - } - - fn take(&self, key: &[u8]) -> Option<Vec<u8>> { - self.cache.lock().unwrap().remove(key) - } - - fn can_cache(&self) -> bool { - true - } - } - - impl Debug for ServerSessionMemoryCache { - fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { - f.debug_struct("ServerSessionMemoryCache") - .finish() - } - } - - #[cfg(test)] - mod tests { - use std::vec; - - use super::*; - use crate::server::StoresServerSessions; - - #[test] - fn test_serversessionmemorycache_accepts_put() { - let c = ServerSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - } - - #[test] - fn test_serversessionmemorycache_persists_put() { - let c = ServerSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - assert_eq!(c.get(&[0x01]), Some(vec![0x02])); - assert_eq!(c.get(&[0x01]), Some(vec![0x02])); - } - - #[test] - fn test_serversessionmemorycache_overwrites_put() { - let c = ServerSessionMemoryCache::new(4); - assert!(c.put(vec![0x01], vec![0x02])); - assert!(c.put(vec![0x01], vec![0x04])); - assert_eq!(c.get(&[0x01]), Some(vec![0x04])); - } - - #[test] - fn test_serversessionmemorycache_drops_to_maintain_size_invariant() { - let c = ServerSessionMemoryCache::new(2); - assert!(c.put(vec![0x01], vec![0x02])); - assert!(c.put(vec![0x03], vec![0x04])); - assert!(c.put(vec![0x05], vec![0x06])); - assert!(c.put(vec![0x07], vec![0x08])); - assert!(c.put(vec![0x09], vec![0x0a])); - - let count = c.get(&[0x01]).iter().count() - + c.get(&[0x03]).iter().count() - + c.get(&[0x05]).iter().count() - + c.get(&[0x07]).iter().count() - + c.get(&[0x09]).iter().count(); - - assert!(count < 5); - } - } -} - -#[cfg(any(feature = "std", feature = "hashbrown"))] -pub use cache::ServerSessionMemoryCache; - -/// Something which never produces tickets. -#[derive(Debug)] -pub(super) struct NeverProducesTickets {} - -impl server::ProducesTickets for NeverProducesTickets { - fn enabled(&self) -> bool { - false - } - fn lifetime(&self) -> u32 { - 0 - } - fn encrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> { - None - } - fn decrypt(&self, _bytes: &[u8]) -> Option<Vec<u8>> { - None - } -} - -/// An exemplar `ResolvesServerCert` implementation that always resolves to a single -/// [RFC 7250] raw public key. -/// -/// [RFC 7250]: https://tools.ietf.org/html/rfc7250 -#[derive(Clone, Debug)] -pub struct AlwaysResolvesServerRawPublicKeys(Arc<sign::CertifiedKey>); - -impl AlwaysResolvesServerRawPublicKeys { - /// Create a new `AlwaysResolvesServerRawPublicKeys` instance. - pub fn new(certified_key: Arc<sign::CertifiedKey>) -> Self { - Self(certified_key) - } -} - -impl server::ResolvesServerCert for AlwaysResolvesServerRawPublicKeys { - fn resolve(&self, _client_hello: ClientHello<'_>) -> Option<Arc<sign::CertifiedKey>> { - Some(self.0.clone()) - } - - fn only_raw_public_keys(&self) -> bool { - true - } -} - -#[cfg(any(feature = "std", feature = "hashbrown"))] -mod sni_resolver { - use alloc::string::{String, ToString}; - use core::fmt::Debug; - - use pki_types::{DnsName, ServerName}; - - use crate::error::Error; - use crate::hash_map::HashMap; - use crate::server::ClientHello; - use crate::sync::Arc; - use crate::webpki::{ParsedCertificate, verify_server_name}; - use crate::{server, sign}; - - /// Something that resolves do different cert chains/keys based - /// on client-supplied server name (via SNI). - #[derive(Debug)] - pub struct ResolvesServerCertUsingSni { - by_name: HashMap<String, Arc<sign::CertifiedKey>>, - } - - impl ResolvesServerCertUsingSni { - /// Create a new and empty (i.e., knows no certificates) resolver. - pub fn new() -> Self { - Self { - by_name: HashMap::new(), - } - } - - /// Add a new `sign::CertifiedKey` to be used for the given SNI `name`. - /// - /// This function fails if `name` is not a valid DNS name, or if - /// it's not valid for the supplied certificate, or if the certificate - /// chain is syntactically faulty. - pub fn add(&mut self, name: &str, ck: sign::CertifiedKey) -> Result<(), Error> { - let server_name = { - let checked_name = DnsName::try_from(name) - .map_err(|_| Error::General("Bad DNS name".into())) - .map(|name| name.to_lowercase_owned())?; - ServerName::DnsName(checked_name) - }; - - // Check the certificate chain for validity: - // - it should be non-empty list - // - the first certificate should be parsable as a x509v3, - // - the first certificate should quote the given server name - // (if provided) - // - // These checks are not security-sensitive. They are the - // *server* attempting to detect accidental misconfiguration. - - ck.end_entity_cert() - .and_then(ParsedCertificate::try_from) - .and_then(|cert| verify_server_name(&cert, &server_name))?; - - if let ServerName::DnsName(name) = server_name { - self.by_name - .insert(name.as_ref().to_string(), Arc::new(ck)); - } - Ok(()) - } - } - - impl server::ResolvesServerCert for ResolvesServerCertUsingSni { - fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<sign::CertifiedKey>> { - if let Some(name) = client_hello.server_name() { - self.by_name.get(name).cloned() - } else { - // This kind of resolver requires SNI - None - } - } - } - - #[cfg(test)] - mod tests { - use super::*; - use crate::server::ResolvesServerCert; - - #[test] - fn test_resolvesservercertusingsni_requires_sni() { - let rscsni = ResolvesServerCertUsingSni::new(); - assert!( - rscsni - .resolve(ClientHello { - server_name: &None, - signature_schemes: &[], - alpn: None, - server_cert_types: None, - client_cert_types: None, - cipher_suites: &[], - certificate_authorities: None, - named_groups: None, - }) - .is_none() - ); - } - - #[test] - fn test_resolvesservercertusingsni_handles_unknown_name() { - let rscsni = ResolvesServerCertUsingSni::new(); - let name = DnsName::try_from("hello.com") - .unwrap() - .to_owned(); - assert!( - rscsni - .resolve(ClientHello { - server_name: &Some(name), - signature_schemes: &[], - alpn: None, - server_cert_types: None, - client_cert_types: None, - cipher_suites: &[], - certificate_authorities: None, - named_groups: None, - }) - .is_none() - ); - } - } -} - -#[cfg(any(feature = "std", feature = "hashbrown"))] -pub use sni_resolver::ResolvesServerCertUsingSni; - -#[cfg(test)] -mod tests { - use std::vec; - - use super::*; - use crate::server::{ProducesTickets, StoresServerSessions}; - - #[test] - fn test_noserversessionstorage_drops_put() { - let c = NoServerSessionStorage {}; - assert!(!c.put(vec![0x01], vec![0x02])); - } - - #[test] - fn test_noserversessionstorage_denies_gets() { - let c = NoServerSessionStorage {}; - c.put(vec![0x01], vec![0x02]); - assert_eq!(c.get(&[]), None); - assert_eq!(c.get(&[0x01]), None); - assert_eq!(c.get(&[0x02]), None); - } - - #[test] - fn test_noserversessionstorage_denies_takes() { - let c = NoServerSessionStorage {}; - assert_eq!(c.take(&[]), None); - assert_eq!(c.take(&[0x01]), None); - assert_eq!(c.take(&[0x02]), None); - } - - #[test] - fn test_neverproducestickets_does_nothing() { - let npt = NeverProducesTickets {}; - assert!(!npt.enabled()); - assert_eq!(0, npt.lifetime()); - assert_eq!(None, npt.encrypt(&[])); - assert_eq!(None, npt.decrypt(&[])); - } -} diff --git a/vendor/rustls/src/server/hs.rs b/vendor/rustls/src/server/hs.rs deleted file mode 100644 index d98336e4..00000000 --- a/vendor/rustls/src/server/hs.rs +++ /dev/null @@ -1,763 +0,0 @@ -use alloc::borrow::ToOwned; -use alloc::boxed::Box; -use alloc::vec::Vec; - -use pki_types::DnsName; - -use super::server_conn::ServerConnectionData; -#[cfg(feature = "tls12")] -use super::tls12; -use crate::common_state::{KxState, Protocol, State}; -use crate::conn::ConnectionRandoms; -use crate::crypto::SupportedKxGroup; -use crate::enums::{ - AlertDescription, CertificateType, CipherSuite, HandshakeType, ProtocolVersion, - SignatureAlgorithm, SignatureScheme, -}; -use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; -use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; -use crate::log::{debug, trace}; -use crate::msgs::enums::{Compression, ExtensionType, NamedGroup}; -#[cfg(feature = "tls12")] -use crate::msgs::handshake::SessionId; -use crate::msgs::handshake::{ - ClientHelloPayload, HandshakePayload, KeyExchangeAlgorithm, ProtocolName, Random, - ServerExtensions, ServerExtensionsInput, ServerNamePayload, SingleProtocolName, - TransportParameters, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::server::common::ActiveCertifiedKey; -use crate::server::{ClientHello, ServerConfig, tls13}; -use crate::sync::Arc; -use crate::{SupportedCipherSuite, suites}; - -pub(super) type NextState<'a> = Box<dyn State<ServerConnectionData> + 'a>; -pub(super) type NextStateOrError<'a> = Result<NextState<'a>, Error>; -pub(super) type ServerContext<'a> = crate::common_state::Context<'a, ServerConnectionData>; - -pub(super) fn can_resume( - suite: SupportedCipherSuite, - sni: &Option<DnsName<'_>>, - using_ems: bool, - resumedata: &persist::ServerSessionValue, -) -> bool { - // The RFCs underspecify what happens if we try to resume to - // an unoffered/varying suite. We merely don't resume in weird cases. - // - // RFC 6066 says "A server that implements this extension MUST NOT accept - // the request to resume the session if the server_name extension contains - // a different name. Instead, it proceeds with a full handshake to - // establish a new session." - // - // RFC 8446: "The server MUST ensure that it selects - // a compatible PSK (if any) and cipher suite." - resumedata.cipher_suite == suite.suite() - && (resumedata.extended_ms == using_ems || (resumedata.extended_ms && !using_ems)) - && &resumedata.sni == sni -} - -#[derive(Default)] -pub(super) struct ExtensionProcessing { - // extensions to reply with - pub(super) extensions: Box<ServerExtensions<'static>>, - #[cfg(feature = "tls12")] - pub(super) send_ticket: bool, -} - -impl ExtensionProcessing { - pub(super) fn new(extra_exts: ServerExtensionsInput<'static>) -> Self { - let ServerExtensionsInput { - transport_parameters, - } = extra_exts; - - let mut extensions = Box::new(ServerExtensions::default()); - match transport_parameters { - Some(TransportParameters::Quic(v)) => extensions.transport_parameters = Some(v), - Some(TransportParameters::QuicDraft(v)) => { - extensions.transport_parameters_draft = Some(v) - } - None => {} - } - - Self { - extensions, - #[cfg(feature = "tls12")] - send_ticket: false, - } - } - - pub(super) fn process_common( - &mut self, - config: &ServerConfig, - cx: &mut ServerContext<'_>, - ocsp_response: &mut Option<&[u8]>, - hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>, - ) -> Result<(), Error> { - // ALPN - let our_protocols = &config.alpn_protocols; - if let Some(their_protocols) = &hello.protocols { - cx.common.alpn_protocol = our_protocols - .iter() - .find(|ours| { - their_protocols - .iter() - .any(|theirs| theirs.as_ref() == ours.as_slice()) - }) - .map(|bytes| ProtocolName::from(bytes.clone())); - if let Some(selected_protocol) = &cx.common.alpn_protocol { - debug!("Chosen ALPN protocol {selected_protocol:?}"); - - self.extensions.selected_protocol = - Some(SingleProtocolName::new(selected_protocol.clone())); - } else if !our_protocols.is_empty() { - return Err(cx.common.send_fatal_alert( - AlertDescription::NoApplicationProtocol, - Error::NoApplicationProtocol, - )); - } - } - - if cx.common.is_quic() { - // QUIC has strict ALPN, unlike TLS's more backwards-compatible behavior. RFC 9001 - // says: "The server MUST treat the inability to select a compatible application - // protocol as a connection error of type 0x0178". We judge that ALPN was desired - // (rather than some out-of-band protocol negotiation mechanism) if and only if any ALPN - // protocols were configured locally or offered by the client. This helps prevent - // successful establishment of connections between peers that can't understand - // each other. - if cx.common.alpn_protocol.is_none() - && (!our_protocols.is_empty() || hello.protocols.is_some()) - { - return Err(cx.common.send_fatal_alert( - AlertDescription::NoApplicationProtocol, - Error::NoApplicationProtocol, - )); - } - - let transport_params = hello - .transport_parameters - .as_ref() - .or(hello - .transport_parameters_draft - .as_ref()); - match transport_params { - Some(params) => cx.common.quic.params = Some(params.to_owned().into_vec()), - None => { - return Err(cx - .common - .missing_extension(PeerMisbehaved::MissingQuicTransportParameters)); - } - } - } - - let for_resume = resumedata.is_some(); - // SNI - if let (false, Some(ServerNamePayload::SingleDnsName(_))) = (for_resume, &hello.server_name) - { - self.extensions.server_name_ack = Some(()); - } - - // Send status_request response if we have one. This is not allowed - // if we're resuming, and is only triggered if we have an OCSP response - // to send. - if !for_resume - && hello - .certificate_status_request - .is_some() - { - if ocsp_response.is_some() && !cx.common.is_tls13() { - // Only TLS1.2 sends confirmation in ServerHello - self.extensions - .certificate_status_request_ack = Some(()); - } - } else { - // Throw away any OCSP response so we don't try to send it later. - ocsp_response.take(); - } - - self.validate_server_cert_type_extension(hello, config, cx)?; - self.validate_client_cert_type_extension(hello, config, cx)?; - - Ok(()) - } - - #[cfg(feature = "tls12")] - pub(super) fn process_tls12( - &mut self, - config: &ServerConfig, - hello: &ClientHelloPayload, - using_ems: bool, - ) { - // Renegotiation. - // (We don't do reneg at all, but would support the secure version if we did.) - - use crate::msgs::base::PayloadU8; - let secure_reneg_offered = hello.renegotiation_info.is_some() - || hello - .cipher_suites - .contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); - - if secure_reneg_offered { - self.extensions.renegotiation_info = Some(PayloadU8::new(Vec::new())); - } - - // Tickets: - // If we get any SessionTicket extension and have tickets enabled, - // we send an ack. - if hello.session_ticket.is_some() && config.ticketer.enabled() { - self.send_ticket = true; - self.extensions.session_ticket_ack = Some(()); - } - - // Confirm use of EMS if offered. - if using_ems { - self.extensions - .extended_master_secret_ack = Some(()); - } - } - - fn validate_server_cert_type_extension( - &mut self, - hello: &ClientHelloPayload, - config: &ServerConfig, - cx: &mut ServerContext<'_>, - ) -> Result<(), Error> { - let client_supports = hello - .server_certificate_types - .as_deref() - .unwrap_or_default(); - - self.process_cert_type_extension( - client_supports, - config - .cert_resolver - .only_raw_public_keys(), - ExtensionType::ServerCertificateType, - cx, - ) - } - - fn validate_client_cert_type_extension( - &mut self, - hello: &ClientHelloPayload, - config: &ServerConfig, - cx: &mut ServerContext<'_>, - ) -> Result<(), Error> { - let client_supports = hello - .client_certificate_types - .as_deref() - .unwrap_or_default(); - - self.process_cert_type_extension( - client_supports, - config - .verifier - .requires_raw_public_keys(), - ExtensionType::ClientCertificateType, - cx, - ) - } - - fn process_cert_type_extension( - &mut self, - client_supports: &[CertificateType], - requires_raw_keys: bool, - extension_type: ExtensionType, - cx: &mut ServerContext<'_>, - ) -> Result<(), Error> { - debug_assert!( - extension_type == ExtensionType::ClientCertificateType - || extension_type == ExtensionType::ServerCertificateType - ); - let raw_key_negotation_result = match ( - requires_raw_keys, - client_supports.contains(&CertificateType::RawPublicKey), - client_supports.contains(&CertificateType::X509), - ) { - (true, true, _) => Ok((extension_type, CertificateType::RawPublicKey)), - (false, _, true) => Ok((extension_type, CertificateType::X509)), - (false, true, false) => Err(Error::PeerIncompatible( - PeerIncompatible::IncorrectCertificateTypeExtension, - )), - (true, false, _) => Err(Error::PeerIncompatible( - PeerIncompatible::IncorrectCertificateTypeExtension, - )), - (false, false, false) => return Ok(()), - }; - - match raw_key_negotation_result { - Ok((ExtensionType::ClientCertificateType, cert_type)) => { - self.extensions.client_certificate_type = Some(cert_type); - } - Ok((ExtensionType::ServerCertificateType, cert_type)) => { - self.extensions.server_certificate_type = Some(cert_type); - } - Err(err) => { - return Err(cx - .common - .send_fatal_alert(AlertDescription::HandshakeFailure, err)); - } - Ok((_, _)) => unreachable!(), - } - Ok(()) - } -} - -pub(super) struct ExpectClientHello { - pub(super) config: Arc<ServerConfig>, - pub(super) extra_exts: ServerExtensionsInput<'static>, - pub(super) transcript: HandshakeHashOrBuffer, - #[cfg(feature = "tls12")] - pub(super) session_id: SessionId, - #[cfg(feature = "tls12")] - pub(super) using_ems: bool, - pub(super) done_retry: bool, - pub(super) send_tickets: usize, -} - -impl ExpectClientHello { - pub(super) fn new( - config: Arc<ServerConfig>, - extra_exts: ServerExtensionsInput<'static>, - ) -> Self { - let mut transcript_buffer = HandshakeHashBuffer::new(); - - if config.verifier.offer_client_auth() { - transcript_buffer.set_client_auth_enabled(); - } - - Self { - config, - extra_exts, - transcript: HandshakeHashOrBuffer::Buffer(transcript_buffer), - #[cfg(feature = "tls12")] - session_id: SessionId::empty(), - #[cfg(feature = "tls12")] - using_ems: false, - done_retry: false, - send_tickets: 0, - } - } - - /// Continues handling of a `ClientHello` message once config and certificate are available. - pub(super) fn with_certified_key( - self, - mut sig_schemes: Vec<SignatureScheme>, - client_hello: &ClientHelloPayload, - m: &Message<'_>, - cx: &mut ServerContext<'_>, - ) -> NextStateOrError<'static> { - let tls13_enabled = self - .config - .supports_version(ProtocolVersion::TLSv1_3); - let tls12_enabled = self - .config - .supports_version(ProtocolVersion::TLSv1_2); - - // Are we doing TLS1.3? - let version = if let Some(versions) = &client_hello.supported_versions { - if versions.tls13 && tls13_enabled { - ProtocolVersion::TLSv1_3 - } else if !versions.tls12 || !tls12_enabled { - return Err(cx.common.send_fatal_alert( - AlertDescription::ProtocolVersion, - PeerIncompatible::Tls12NotOfferedOrEnabled, - )); - } else if cx.common.is_quic() { - return Err(cx.common.send_fatal_alert( - AlertDescription::ProtocolVersion, - PeerIncompatible::Tls13RequiredForQuic, - )); - } else { - ProtocolVersion::TLSv1_2 - } - } else if u16::from(client_hello.client_version) < u16::from(ProtocolVersion::TLSv1_2) { - return Err(cx.common.send_fatal_alert( - AlertDescription::ProtocolVersion, - PeerIncompatible::Tls12NotOffered, - )); - } else if !tls12_enabled && tls13_enabled { - return Err(cx.common.send_fatal_alert( - AlertDescription::ProtocolVersion, - PeerIncompatible::SupportedVersionsExtensionRequired, - )); - } else if cx.common.is_quic() { - return Err(cx.common.send_fatal_alert( - AlertDescription::ProtocolVersion, - PeerIncompatible::Tls13RequiredForQuic, - )); - } else { - ProtocolVersion::TLSv1_2 - }; - - cx.common.negotiated_version = Some(version); - - // We communicate to the upper layer what kind of key they should choose - // via the sigschemes value. Clients tend to treat this extension - // orthogonally to offered ciphersuites (even though, in TLS1.2 it is not). - // So: reduce the offered sigschemes to those compatible with the - // intersection of ciphersuites. - let client_suites = self - .config - .provider - .cipher_suites - .iter() - .copied() - .filter(|scs| { - client_hello - .cipher_suites - .contains(&scs.suite()) - }) - .collect::<Vec<_>>(); - - sig_schemes - .retain(|scheme| suites::compatible_sigscheme_for_suites(*scheme, &client_suites)); - - // We adhere to the TLS 1.2 RFC by not exposing this to the cert resolver if TLS version is 1.2 - let certificate_authorities = match version { - ProtocolVersion::TLSv1_2 => None, - _ => client_hello - .certificate_authority_names - .as_deref(), - }; - // Choose a certificate. - let certkey = { - let client_hello = ClientHello { - server_name: &cx.data.sni, - signature_schemes: &sig_schemes, - alpn: client_hello.protocols.as_ref(), - client_cert_types: client_hello - .client_certificate_types - .as_deref(), - server_cert_types: client_hello - .server_certificate_types - .as_deref(), - cipher_suites: &client_hello.cipher_suites, - certificate_authorities, - named_groups: client_hello.named_groups.as_deref(), - }; - trace!("Resolving server certificate: {client_hello:#?}"); - - let certkey = self - .config - .cert_resolver - .resolve(client_hello); - - certkey.ok_or_else(|| { - cx.common.send_fatal_alert( - AlertDescription::AccessDenied, - Error::General("no server certificate chain resolved".to_owned()), - ) - })? - }; - let certkey = ActiveCertifiedKey::from_certified_key(&certkey); - - let (suite, skxg) = self - .choose_suite_and_kx_group( - version, - certkey.get_key().algorithm(), - cx.common.protocol, - client_hello - .named_groups - .as_deref() - .unwrap_or_default(), - &client_hello.cipher_suites, - ) - .map_err(|incompat| { - cx.common - .send_fatal_alert(AlertDescription::HandshakeFailure, incompat) - })?; - - debug!("decided upon suite {suite:?}"); - cx.common.suite = Some(suite); - cx.common.kx_state = KxState::Start(skxg); - - // Start handshake hash. - let starting_hash = suite.hash_provider(); - let transcript = match self.transcript { - HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash), - HandshakeHashOrBuffer::Hash(inner) - if inner.algorithm() == starting_hash.algorithm() => - { - inner - } - _ => { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::HandshakeHashVariedAfterRetry, - )); - } - }; - - // Save their Random. - let randoms = ConnectionRandoms::new( - client_hello.random, - Random::new(self.config.provider.secure_random)?, - ); - match suite { - SupportedCipherSuite::Tls13(suite) => tls13::CompleteClientHelloHandling { - config: self.config, - transcript, - suite, - randoms, - done_retry: self.done_retry, - send_tickets: self.send_tickets, - extra_exts: self.extra_exts, - } - .handle_client_hello(cx, certkey, m, client_hello, skxg, sig_schemes), - #[cfg(feature = "tls12")] - SupportedCipherSuite::Tls12(suite) => tls12::CompleteClientHelloHandling { - config: self.config, - transcript, - session_id: self.session_id, - suite, - using_ems: self.using_ems, - randoms, - send_ticket: self.send_tickets > 0, - extra_exts: self.extra_exts, - } - .handle_client_hello( - cx, - certkey, - m, - client_hello, - skxg, - sig_schemes, - tls13_enabled, - ), - } - } - - fn choose_suite_and_kx_group( - &self, - selected_version: ProtocolVersion, - sig_key_algorithm: SignatureAlgorithm, - protocol: Protocol, - client_groups: &[NamedGroup], - client_suites: &[CipherSuite], - ) -> Result<(SupportedCipherSuite, &'static dyn SupportedKxGroup), PeerIncompatible> { - // Determine which `KeyExchangeAlgorithm`s are theoretically possible, based - // on the offered and supported groups. - let mut ecdhe_possible = false; - let mut ffdhe_possible = false; - let mut ffdhe_offered = false; - let mut supported_groups = Vec::with_capacity(client_groups.len()); - - for offered_group in client_groups { - let supported = self - .config - .provider - .kx_groups - .iter() - .find(|skxg| { - skxg.usable_for_version(selected_version) && skxg.name() == *offered_group - }); - - match offered_group.key_exchange_algorithm() { - KeyExchangeAlgorithm::DHE => { - ffdhe_possible |= supported.is_some(); - ffdhe_offered = true; - } - KeyExchangeAlgorithm::ECDHE => { - ecdhe_possible |= supported.is_some(); - } - } - - supported_groups.push(supported); - } - - let first_supported_dhe_kxg = if selected_version == ProtocolVersion::TLSv1_2 { - // https://datatracker.ietf.org/doc/html/rfc7919#section-4 (paragraph 2) - let first_supported_dhe_kxg = self - .config - .provider - .kx_groups - .iter() - .find(|skxg| skxg.name().key_exchange_algorithm() == KeyExchangeAlgorithm::DHE); - ffdhe_possible |= !ffdhe_offered && first_supported_dhe_kxg.is_some(); - first_supported_dhe_kxg - } else { - // In TLS1.3, the server may only directly negotiate a group. - None - }; - - if !ecdhe_possible && !ffdhe_possible { - return Err(PeerIncompatible::NoKxGroupsInCommon); - } - - let mut suitable_suites_iter = self - .config - .provider - .cipher_suites - .iter() - .filter(|suite| { - // Reduce our supported ciphersuites by the certified key's algorithm. - suite.usable_for_signature_algorithm(sig_key_algorithm) - // And version - && suite.version().version == selected_version - // And protocol - && suite.usable_for_protocol(protocol) - // And support one of key exchange groups - && (ecdhe_possible && suite.usable_for_kx_algorithm(KeyExchangeAlgorithm::ECDHE) - || ffdhe_possible && suite.usable_for_kx_algorithm(KeyExchangeAlgorithm::DHE)) - }); - - // RFC 7919 (https://datatracker.ietf.org/doc/html/rfc7919#section-4) requires us to send - // the InsufficientSecurity alert in case we don't recognize client's FFDHE groups (i.e., - // `suitable_suites` becomes empty). But that does not make a lot of sense (e.g., client - // proposes FFDHE4096 and we only support FFDHE2048), so we ignore that requirement here, - // and continue to send HandshakeFailure. - - let suite = if self.config.ignore_client_order { - suitable_suites_iter.find(|suite| client_suites.contains(&suite.suite())) - } else { - let suitable_suites = suitable_suites_iter.collect::<Vec<_>>(); - client_suites - .iter() - .find_map(|client_suite| { - suitable_suites - .iter() - .find(|x| *client_suite == x.suite()) - }) - .copied() - } - .ok_or(PeerIncompatible::NoCipherSuitesInCommon)?; - - // Finally, choose a key exchange group that is compatible with the selected cipher - // suite. - let maybe_skxg = supported_groups - .iter() - .find_map(|maybe_skxg| match maybe_skxg { - Some(skxg) => suite - .usable_for_kx_algorithm(skxg.name().key_exchange_algorithm()) - .then_some(*skxg), - None => None, - }); - - if selected_version == ProtocolVersion::TLSv1_3 { - // This unwrap is structurally guaranteed by the early return for `!ffdhe_possible && !ecdhe_possible` - return Ok((*suite, *maybe_skxg.unwrap())); - } - - // For TLS1.2, the server can unilaterally choose a DHE group if it has one and - // there was no better option. - match maybe_skxg { - Some(skxg) => Ok((*suite, *skxg)), - None if suite.usable_for_kx_algorithm(KeyExchangeAlgorithm::DHE) => { - // If kx for the selected cipher suite is DHE and no DHE groups are specified in the extension, - // the server is free to choose DHE params, we choose the first DHE kx group of the provider. - if let Some(server_selected_ffdhe_skxg) = first_supported_dhe_kxg { - Ok((*suite, *server_selected_ffdhe_skxg)) - } else { - Err(PeerIncompatible::NoKxGroupsInCommon) - } - } - None => Err(PeerIncompatible::NoKxGroupsInCommon), - } - } -} - -impl State<ServerConnectionData> for ExpectClientHello { - fn handle<'m>( - self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> NextStateOrError<'m> - where - Self: 'm, - { - let (client_hello, sig_schemes) = process_client_hello(&m, self.done_retry, cx)?; - self.with_certified_key(sig_schemes, client_hello, &m, cx) - } - - fn into_owned(self: Box<Self>) -> NextState<'static> { - self - } -} - -/// Configuration-independent validation of a `ClientHello` message. -/// -/// This represents the first part of the `ClientHello` handling, where we do all validation that -/// doesn't depend on a `ServerConfig` being available and extract everything needed to build a -/// [`ClientHello`] value for a [`ResolvesServerCert`]. -/// -/// Note that this will modify `data.sni` even if config or certificate resolution fail. -/// -/// [`ResolvesServerCert`]: crate::server::ResolvesServerCert -pub(super) fn process_client_hello<'m>( - m: &'m Message<'m>, - done_retry: bool, - cx: &mut ServerContext<'_>, -) -> Result<(&'m ClientHelloPayload, Vec<SignatureScheme>), Error> { - let client_hello = - require_handshake_msg!(m, HandshakeType::ClientHello, HandshakePayload::ClientHello)?; - trace!("we got a clienthello {client_hello:?}"); - - if !client_hello - .compression_methods - .contains(&Compression::Null) - { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerIncompatible::NullCompressionRequired, - )); - } - - // No handshake messages should follow this one in this flight. - cx.common.check_aligned_handshake()?; - - // Extract and validate the SNI DNS name, if any, before giving it to - // the cert resolver. In particular, if it is invalid then we should - // send an Illegal Parameter alert instead of the Internal Error alert - // (or whatever) that we'd send if this were checked later or in a - // different way. - // - // [RFC6066][] specifies that literal IP addresses are illegal in - // `ServerName`s with a `name_type` of `host_name`. - // - // Some clients incorrectly send such extensions: we choose to - // successfully parse these (into `ServerNamePayload::IpAddress`) - // but then act like the client sent no `server_name` extension. - // - // [RFC6066]: https://datatracker.ietf.org/doc/html/rfc6066#section-3 - let sni = match &client_hello.server_name { - Some(ServerNamePayload::SingleDnsName(dns_name)) => Some(dns_name.to_lowercase_owned()), - Some(ServerNamePayload::IpAddress) => None, - Some(ServerNamePayload::Invalid) => { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::ServerNameMustContainOneHostName, - )); - } - None => None, - }; - - // save only the first SNI - if let (Some(sni), false) = (&sni, done_retry) { - // Save the SNI into the session. - // The SNI hostname is immutable once set. - assert!(cx.data.sni.is_none()); - cx.data.sni = Some(sni.clone()); - } else if cx.data.sni != sni { - return Err(PeerMisbehaved::ServerNameDifferedOnRetry.into()); - } - - let sig_schemes = client_hello - .signature_schemes - .as_ref() - .ok_or_else(|| { - cx.common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerIncompatible::SignatureAlgorithmsExtensionRequired, - ) - })?; - - Ok((client_hello, sig_schemes.to_owned())) -} - -pub(crate) enum HandshakeHashOrBuffer { - Buffer(HandshakeHashBuffer), - Hash(HandshakeHash), -} diff --git a/vendor/rustls/src/server/server_conn.rs b/vendor/rustls/src/server/server_conn.rs deleted file mode 100644 index d1024b14..00000000 --- a/vendor/rustls/src/server/server_conn.rs +++ /dev/null @@ -1,1288 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::fmt; -use core::fmt::{Debug, Formatter}; -use core::marker::PhantomData; -use core::ops::{Deref, DerefMut}; -#[cfg(feature = "std")] -use std::io; - -use pki_types::{DnsName, UnixTime}; - -use super::hs; -#[cfg(feature = "std")] -use crate::WantsVerifier; -use crate::builder::ConfigBuilder; -use crate::common_state::{CommonState, Side}; -#[cfg(feature = "std")] -use crate::common_state::{Protocol, State}; -use crate::conn::{ConnectionCommon, ConnectionCore, UnbufferedConnectionCommon}; -#[cfg(doc)] -use crate::crypto; -use crate::crypto::CryptoProvider; -use crate::enums::{CertificateType, CipherSuite, ProtocolVersion, SignatureScheme}; -use crate::error::Error; -use crate::kernel::KernelConnection; -use crate::log::trace; -use crate::msgs::base::Payload; -use crate::msgs::handshake::{ClientHelloPayload, ProtocolName, ServerExtensionsInput}; -use crate::msgs::message::Message; -use crate::suites::ExtractedSecrets; -use crate::sync::Arc; -#[cfg(feature = "std")] -use crate::time_provider::DefaultTimeProvider; -use crate::time_provider::TimeProvider; -use crate::vecbuf::ChunkVecBuffer; -use crate::{ - DistinguishedName, KeyLog, NamedGroup, WantsVersions, compress, sign, verify, versions, -}; - -/// A trait for the ability to store server session data. -/// -/// The keys and values are opaque. -/// -/// Inserted keys are randomly chosen by the library and have -/// no internal structure (in other words, you may rely on all -/// bits being uniformly random). Queried keys are untrusted data. -/// -/// Both the keys and values should be treated as -/// **highly sensitive data**, containing enough key material -/// to break all security of the corresponding sessions. -/// -/// Implementations can be lossy (in other words, forgetting -/// key/value pairs) without any negative security consequences. -/// -/// However, note that `take` **must** reliably delete a returned -/// value. If it does not, there may be security consequences. -/// -/// `put` and `take` are mutating operations; this isn't expressed -/// in the type system to allow implementations freedom in -/// how to achieve interior mutability. `Mutex` is a common -/// choice. -pub trait StoresServerSessions: Debug + Send + Sync { - /// Store session secrets encoded in `value` against `key`, - /// overwrites any existing value against `key`. Returns `true` - /// if the value was stored. - fn put(&self, key: Vec<u8>, value: Vec<u8>) -> bool; - - /// Find a value with the given `key`. Return it, or None - /// if it doesn't exist. - fn get(&self, key: &[u8]) -> Option<Vec<u8>>; - - /// Find a value with the given `key`. Return it and delete it; - /// or None if it doesn't exist. - fn take(&self, key: &[u8]) -> Option<Vec<u8>>; - - /// Whether the store can cache another session. This is used to indicate to clients - /// whether their session can be resumed; the implementation is not required to remember - /// a session even if it returns `true` here. - fn can_cache(&self) -> bool; -} - -/// A trait for the ability to encrypt and decrypt tickets. -pub trait ProducesTickets: Debug + Send + Sync { - /// Returns true if this implementation will encrypt/decrypt - /// tickets. Should return false if this is a dummy - /// implementation: the server will not send the SessionTicket - /// extension and will not call the other functions. - fn enabled(&self) -> bool; - - /// Returns the lifetime in seconds of tickets produced now. - /// The lifetime is provided as a hint to clients that the - /// ticket will not be useful after the given time. - /// - /// This lifetime must be implemented by key rolling and - /// erasure, *not* by storing a lifetime in the ticket. - /// - /// The objective is to limit damage to forward secrecy caused - /// by tickets, not just limiting their lifetime. - fn lifetime(&self) -> u32; - - /// Encrypt and authenticate `plain`, returning the resulting - /// ticket. Return None if `plain` cannot be encrypted for - /// some reason: an empty ticket will be sent and the connection - /// will continue. - fn encrypt(&self, plain: &[u8]) -> Option<Vec<u8>>; - - /// Decrypt `cipher`, validating its authenticity protection - /// and recovering the plaintext. `cipher` is fully attacker - /// controlled, so this decryption must be side-channel free, - /// panic-proof, and otherwise bullet-proof. If the decryption - /// fails, return None. - fn decrypt(&self, cipher: &[u8]) -> Option<Vec<u8>>; -} - -/// How to choose a certificate chain and signing key for use -/// in server authentication. -/// -/// This is suitable when selecting a certificate does not require -/// I/O or when the application is using blocking I/O anyhow. -/// -/// For applications that use async I/O and need to do I/O to choose -/// a certificate (for instance, fetching a certificate from a data store), -/// the [`Acceptor`] interface is more suitable. -pub trait ResolvesServerCert: Debug + Send + Sync { - /// Choose a certificate chain and matching key given simplified - /// ClientHello information. - /// - /// Return `None` to abort the handshake. - fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<sign::CertifiedKey>>; - - /// Return true when the server only supports raw public keys. - fn only_raw_public_keys(&self) -> bool { - false - } -} - -/// A struct representing the received Client Hello -#[derive(Debug)] -pub struct ClientHello<'a> { - pub(super) server_name: &'a Option<DnsName<'a>>, - pub(super) signature_schemes: &'a [SignatureScheme], - pub(super) alpn: Option<&'a Vec<ProtocolName>>, - pub(super) server_cert_types: Option<&'a [CertificateType]>, - pub(super) client_cert_types: Option<&'a [CertificateType]>, - pub(super) cipher_suites: &'a [CipherSuite], - /// The [certificate_authorities] extension, if it was sent by the client. - /// - /// [certificate_authorities]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.4 - pub(super) certificate_authorities: Option<&'a [DistinguishedName]>, - pub(super) named_groups: Option<&'a [NamedGroup]>, -} - -impl<'a> ClientHello<'a> { - /// Get the server name indicator. - /// - /// Returns `None` if the client did not supply a SNI. - pub fn server_name(&self) -> Option<&str> { - self.server_name - .as_ref() - .map(<DnsName<'_> as AsRef<str>>::as_ref) - } - - /// Get the compatible signature schemes. - /// - /// Returns standard-specified default if the client omitted this extension. - pub fn signature_schemes(&self) -> &[SignatureScheme] { - self.signature_schemes - } - - /// Get the ALPN protocol identifiers submitted by the client. - /// - /// Returns `None` if the client did not include an ALPN extension. - /// - /// Application Layer Protocol Negotiation (ALPN) is a TLS extension that lets a client - /// submit a set of identifiers that each a represent an application-layer protocol. - /// The server will then pick its preferred protocol from the set submitted by the client. - /// Each identifier is represented as a byte array, although common values are often ASCII-encoded. - /// See the official RFC-7301 specifications at <https://datatracker.ietf.org/doc/html/rfc7301> - /// for more information on ALPN. - /// - /// For example, a HTTP client might specify "http/1.1" and/or "h2". Other well-known values - /// are listed in the at IANA registry at - /// <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>. - /// - /// The server can specify supported ALPN protocols by setting [`ServerConfig::alpn_protocols`]. - /// During the handshake, the server will select the first protocol configured that the client supports. - pub fn alpn(&self) -> Option<impl Iterator<Item = &'a [u8]>> { - self.alpn.map(|protocols| { - protocols - .iter() - .map(|proto| proto.as_ref()) - }) - } - - /// Get cipher suites. - pub fn cipher_suites(&self) -> &[CipherSuite] { - self.cipher_suites - } - - /// Get the server certificate types offered in the ClientHello. - /// - /// Returns `None` if the client did not include a certificate type extension. - pub fn server_cert_types(&self) -> Option<&'a [CertificateType]> { - self.server_cert_types - } - - /// Get the client certificate types offered in the ClientHello. - /// - /// Returns `None` if the client did not include a certificate type extension. - pub fn client_cert_types(&self) -> Option<&'a [CertificateType]> { - self.client_cert_types - } - - /// Get the [certificate_authorities] extension sent by the client. - /// - /// Returns `None` if the client did not send this extension. - /// - /// [certificate_authorities]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.4 - pub fn certificate_authorities(&self) -> Option<&'a [DistinguishedName]> { - self.certificate_authorities - } - - /// Get the [`named_groups`] extension sent by the client. - /// - /// This means different things in different versions of TLS: - /// - /// Originally it was introduced as the "[`elliptic_curves`]" extension for TLS1.2. - /// It described the elliptic curves supported by a client for all purposes: key - /// exchange, signature verification (for server authentication), and signing (for - /// client auth). Later [RFC7919] extended this to include FFDHE "named groups", - /// but FFDHE groups in this context only relate to key exchange. - /// - /// In TLS1.3 it was renamed to "[`named_groups`]" and now describes all types - /// of key exchange mechanisms, and does not relate at all to elliptic curves - /// used for signatures. - /// - /// [`elliptic_curves`]: https://datatracker.ietf.org/doc/html/rfc4492#section-5.1.1 - /// [RFC7919]: https://datatracker.ietf.org/doc/html/rfc7919#section-2 - /// [`named_groups`]:https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.7 - pub fn named_groups(&self) -> Option<&'a [NamedGroup]> { - self.named_groups - } -} - -/// Common configuration for a set of server sessions. -/// -/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots -/// from the operating system to add to the [`RootCertStore`] passed to a `ClientCertVerifier` -/// builder may take on the order of a few hundred milliseconds. -/// -/// These must be created via the [`ServerConfig::builder()`] or [`ServerConfig::builder_with_provider()`] -/// function. -/// -/// # Defaults -/// -/// * [`ServerConfig::max_fragment_size`]: the default is `None` (meaning 16kB). -/// * [`ServerConfig::session_storage`]: if the `std` feature is enabled, the default stores 256 -/// sessions in memory. If the `std` feature is not enabled, the default is to not store any -/// sessions. In a no-std context, by enabling the `hashbrown` feature you may provide your -/// own `session_storage` using [`ServerSessionMemoryCache`] and a `crate::lock::MakeMutex` -/// implementation. -/// * [`ServerConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. -/// * [`ServerConfig::key_log`]: key material is not logged. -/// * [`ServerConfig::send_tls13_tickets`]: 2 tickets are sent. -/// * [`ServerConfig::cert_compressors`]: depends on the crate features, see [`compress::default_cert_compressors()`]. -/// * [`ServerConfig::cert_compression_cache`]: caches the most recently used 4 compressions -/// * [`ServerConfig::cert_decompressors`]: depends on the crate features, see [`compress::default_cert_decompressors()`]. -/// -/// # Sharing resumption storage between `ServerConfig`s -/// -/// In a program using many `ServerConfig`s it may improve resumption rates -/// (which has a significant impact on connection performance) if those -/// configs share [`ServerConfig::session_storage`] or [`ServerConfig::ticketer`]. -/// -/// However, caution is needed: other fields influence the security of a session -/// and resumption between them can be surprising. If sharing -/// [`ServerConfig::session_storage`] or [`ServerConfig::ticketer`] between two -/// `ServerConfig`s, you should also evaluate the following fields and ensure -/// they are equivalent: -/// -/// * `ServerConfig::verifier` -- client authentication requirements, -/// * [`ServerConfig::cert_resolver`] -- server identities. -/// -/// To illustrate, imagine two `ServerConfig`s `A` and `B`. `A` requires -/// client authentication, `B` does not. If `A` and `B` shared a resumption store, -/// it would be possible for a session originated by `B` (that is, an unauthenticated client) -/// to be inserted into the store, and then resumed by `A`. This would give a false -/// impression to the user of `A` that the client was authenticated. This is possible -/// whether the resumption is performed statefully (via [`ServerConfig::session_storage`]) -/// or statelessly (via [`ServerConfig::ticketer`]). -/// -/// _Unlike_ `ClientConfig`, rustls does not enforce any policy here. -/// -/// [`RootCertStore`]: crate::RootCertStore -/// [`ServerSessionMemoryCache`]: crate::server::handy::ServerSessionMemoryCache -#[derive(Clone, Debug)] -pub struct ServerConfig { - /// Source of randomness and other crypto. - pub(super) provider: Arc<CryptoProvider>, - - /// Ignore the client's ciphersuite order. Instead, - /// choose the top ciphersuite in the server list - /// which is supported by the client. - pub ignore_client_order: bool, - - /// The maximum size of plaintext input to be emitted in a single TLS record. - /// A value of None is equivalent to the [TLS maximum] of 16 kB. - /// - /// rustls enforces an arbitrary minimum of 32 bytes for this field. - /// Out of range values are reported as errors from [ServerConnection::new]. - /// - /// Setting this value to a little less than the TCP MSS may improve latency - /// for stream-y workloads. - /// - /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1 - /// [ServerConnection::new]: crate::server::ServerConnection::new - pub max_fragment_size: Option<usize>, - - /// How to store client sessions. - /// - /// See [ServerConfig#sharing-resumption-storage-between-serverconfigs] - /// for a warning related to this field. - pub session_storage: Arc<dyn StoresServerSessions>, - - /// How to produce tickets. - /// - /// See [ServerConfig#sharing-resumption-storage-between-serverconfigs] - /// for a warning related to this field. - pub ticketer: Arc<dyn ProducesTickets>, - - /// How to choose a server cert and key. This is usually set by - /// [ConfigBuilder::with_single_cert] or [ConfigBuilder::with_cert_resolver]. - /// For async applications, see also [Acceptor]. - pub cert_resolver: Arc<dyn ResolvesServerCert>, - - /// Protocol names we support, most preferred first. - /// If empty we don't do ALPN at all. - pub alpn_protocols: Vec<Vec<u8>>, - - /// Supported protocol versions, in no particular order. - /// The default is all supported versions. - pub(super) versions: versions::EnabledVersions, - - /// How to verify client certificates. - pub(super) verifier: Arc<dyn verify::ClientCertVerifier>, - - /// How to output key material for debugging. The default - /// does nothing. - pub key_log: Arc<dyn KeyLog>, - - /// Allows traffic secrets to be extracted after the handshake, - /// e.g. for kTLS setup. - pub enable_secret_extraction: bool, - - /// Amount of early data to accept for sessions created by - /// this config. Specify 0 to disable early data. The - /// default is 0. - /// - /// Read the early data via [`ServerConnection::early_data`]. - /// - /// The units for this are _both_ plaintext bytes, _and_ ciphertext - /// bytes, depending on whether the server accepts a client's early_data - /// or not. It is therefore recommended to include some slop in - /// this value to account for the unknown amount of ciphertext - /// expansion in the latter case. - pub max_early_data_size: u32, - - /// Whether the server should send "0.5RTT" data. This means the server - /// sends data after its first flight of handshake messages, without - /// waiting for the client to complete the handshake. - /// - /// This can improve TTFB latency for either server-speaks-first protocols, - /// or client-speaks-first protocols when paired with "0RTT" data. This - /// comes at the cost of a subtle weakening of the normal handshake - /// integrity guarantees that TLS provides. Note that the initial - /// `ClientHello` is indirectly authenticated because it is included - /// in the transcript used to derive the keys used to encrypt the data. - /// - /// This only applies to TLS1.3 connections. TLS1.2 connections cannot - /// do this optimisation and this setting is ignored for them. It is - /// also ignored for TLS1.3 connections that even attempt client - /// authentication. - /// - /// This defaults to false. This means the first application data - /// sent by the server comes after receiving and validating the client's - /// handshake up to the `Finished` message. This is the safest option. - pub send_half_rtt_data: bool, - - /// How many TLS1.3 tickets to send immediately after a successful - /// handshake. - /// - /// Because TLS1.3 tickets are single-use, this allows - /// a client to perform multiple resumptions. - /// - /// The default is 2. - /// - /// If this is 0, no tickets are sent and clients will not be able to - /// do any resumption. - pub send_tls13_tickets: usize, - - /// If set to `true`, requires the client to support the extended - /// master secret extraction method defined in [RFC 7627]. - /// - /// The default is `true` if the "fips" crate feature is enabled, - /// `false` otherwise. - /// - /// It must be set to `true` to meet FIPS requirement mentioned in section - /// **D.Q Transition of the TLS 1.2 KDF to Support the Extended Master - /// Secret** from [FIPS 140-3 IG.pdf]. - /// - /// [RFC 7627]: https://datatracker.ietf.org/doc/html/rfc7627 - /// [FIPS 140-3 IG.pdf]: https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf - #[cfg(feature = "tls12")] - pub require_ems: bool, - - /// Provides the current system time - pub time_provider: Arc<dyn TimeProvider>, - - /// How to compress the server's certificate chain. - /// - /// If a client supports this extension, and advertises support - /// for one of the compression algorithms included here, the - /// server certificate will be compressed according to [RFC8779]. - /// - /// This only applies to TLS1.3 connections. It is ignored for - /// TLS1.2 connections. - /// - /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/ - pub cert_compressors: Vec<&'static dyn compress::CertCompressor>, - - /// Caching for compressed certificates. - /// - /// This is optional: [`compress::CompressionCache::Disabled`] gives - /// a cache that does no caching. - pub cert_compression_cache: Arc<compress::CompressionCache>, - - /// How to decompress the clients's certificate chain. - /// - /// If this is non-empty, the [RFC8779] certificate compression - /// extension is offered when requesting client authentication, - /// and any compressed certificates are transparently decompressed - /// during the handshake. - /// - /// This only applies to TLS1.3 connections. It is ignored for - /// TLS1.2 connections. - /// - /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/ - pub cert_decompressors: Vec<&'static dyn compress::CertDecompressor>, -} - -impl ServerConfig { - /// Create a builder for a server configuration with - /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider] - /// and safe protocol version defaults. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - #[cfg(feature = "std")] - pub fn builder() -> ConfigBuilder<Self, WantsVerifier> { - Self::builder_with_protocol_versions(versions::DEFAULT_VERSIONS) - } - - /// Create a builder for a server configuration with - /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider] - /// and the provided protocol versions. - /// - /// Panics if - /// - the supported versions are not compatible with the provider (eg. - /// the combination of ciphersuites supported by the provider and supported - /// versions lead to zero cipher suites being usable), - /// - if a `CryptoProvider` cannot be resolved using a combination of - /// the crate features and process default. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - #[cfg(feature = "std")] - pub fn builder_with_protocol_versions( - versions: &[&'static versions::SupportedProtocolVersion], - ) -> ConfigBuilder<Self, WantsVerifier> { - // Safety assumptions: - // 1. that the provider has been installed (explicitly or implicitly) - // 2. that the process-level default provider is usable with the supplied protocol versions. - Self::builder_with_provider( - CryptoProvider::get_default_or_install_from_crate_features().clone(), - ) - .with_protocol_versions(versions) - .unwrap() - } - - /// Create a builder for a server configuration with a specific [`CryptoProvider`]. - /// - /// This will use the provider's configured ciphersuites. You must additionally choose - /// which protocol versions to enable, using `with_protocol_versions` or - /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol - /// version is not supported by the provider's ciphersuites. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - #[cfg(feature = "std")] - pub fn builder_with_provider( - provider: Arc<CryptoProvider>, - ) -> ConfigBuilder<Self, WantsVersions> { - ConfigBuilder { - state: WantsVersions {}, - provider, - time_provider: Arc::new(DefaultTimeProvider), - side: PhantomData, - } - } - - /// Create a builder for a server configuration with no default implementation details. - /// - /// This API must be used by `no_std` users. - /// - /// You must provide a specific [`TimeProvider`]. - /// - /// You must provide a specific [`CryptoProvider`]. - /// - /// This will use the provider's configured ciphersuites. You must additionally choose - /// which protocol versions to enable, using `with_protocol_versions` or - /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol - /// version is not supported by the provider's ciphersuites. - /// - /// For more information, see the [`ConfigBuilder`] documentation. - pub fn builder_with_details( - provider: Arc<CryptoProvider>, - time_provider: Arc<dyn TimeProvider>, - ) -> ConfigBuilder<Self, WantsVersions> { - ConfigBuilder { - state: WantsVersions {}, - provider, - time_provider, - side: PhantomData, - } - } - - /// Return `true` if connections made with this `ServerConfig` will - /// operate in FIPS mode. - /// - /// This is different from [`CryptoProvider::fips()`]: [`CryptoProvider::fips()`] - /// is concerned only with cryptography, whereas this _also_ covers TLS-level - /// configuration that NIST recommends. - pub fn fips(&self) -> bool { - #[cfg(feature = "tls12")] - { - self.provider.fips() && self.require_ems - } - - #[cfg(not(feature = "tls12"))] - { - self.provider.fips() - } - } - - /// Return the crypto provider used to construct this client configuration. - pub fn crypto_provider(&self) -> &Arc<CryptoProvider> { - &self.provider - } - - /// We support a given TLS version if it's quoted in the configured - /// versions *and* at least one ciphersuite for this version is - /// also configured. - pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool { - self.versions.contains(v) - && self - .provider - .cipher_suites - .iter() - .any(|cs| cs.version().version == v) - } - - #[cfg(feature = "std")] - pub(crate) fn supports_protocol(&self, proto: Protocol) -> bool { - self.provider - .cipher_suites - .iter() - .any(|cs| cs.usable_for_protocol(proto)) - } - - pub(super) fn current_time(&self) -> Result<UnixTime, Error> { - self.time_provider - .current_time() - .ok_or(Error::FailedToGetCurrentTime) - } -} - -#[cfg(feature = "std")] -mod connection { - use alloc::boxed::Box; - use core::fmt; - use core::fmt::{Debug, Formatter}; - use core::ops::{Deref, DerefMut}; - use std::io; - - use super::{ - Accepted, Accepting, EarlyDataState, ServerConfig, ServerConnectionData, - ServerExtensionsInput, - }; - use crate::common_state::{CommonState, Context, Side}; - use crate::conn::{ConnectionCommon, ConnectionCore}; - use crate::error::Error; - use crate::server::hs; - use crate::suites::ExtractedSecrets; - use crate::sync::Arc; - use crate::vecbuf::ChunkVecBuffer; - - /// Allows reading of early data in resumed TLS1.3 connections. - /// - /// "Early data" is also known as "0-RTT data". - /// - /// This structure implements [`std::io::Read`]. - pub struct ReadEarlyData<'a> { - early_data: &'a mut EarlyDataState, - } - - impl<'a> ReadEarlyData<'a> { - fn new(early_data: &'a mut EarlyDataState) -> Self { - ReadEarlyData { early_data } - } - } - - impl io::Read for ReadEarlyData<'_> { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - self.early_data.read(buf) - } - - #[cfg(read_buf)] - fn read_buf(&mut self, cursor: core::io::BorrowedCursor<'_>) -> io::Result<()> { - self.early_data.read_buf(cursor) - } - } - - /// This represents a single TLS server connection. - /// - /// Send TLS-protected data to the peer using the `io::Write` trait implementation. - /// Read data from the peer using the `io::Read` trait implementation. - pub struct ServerConnection { - pub(super) inner: ConnectionCommon<ServerConnectionData>, - } - - impl ServerConnection { - /// Make a new ServerConnection. `config` controls how - /// we behave in the TLS protocol. - pub fn new(config: Arc<ServerConfig>) -> Result<Self, Error> { - Ok(Self { - inner: ConnectionCommon::from(ConnectionCore::for_server( - config, - ServerExtensionsInput::default(), - )?), - }) - } - - /// Retrieves the server name, if any, used to select the certificate and - /// private key. - /// - /// This returns `None` until some time after the client's server name indication - /// (SNI) extension value is processed during the handshake. It will never be - /// `None` when the connection is ready to send or process application data, - /// unless the client does not support SNI. - /// - /// This is useful for application protocols that need to enforce that the - /// server name matches an application layer protocol hostname. For - /// example, HTTP/1.1 servers commonly expect the `Host:` header field of - /// every request on a connection to match the hostname in the SNI extension - /// when the client provides the SNI extension. - /// - /// The server name is also used to match sessions during session resumption. - pub fn server_name(&self) -> Option<&str> { - self.inner.core.get_sni_str() - } - - /// Application-controlled portion of the resumption ticket supplied by the client, if any. - /// - /// Recovered from the prior session's `set_resumption_data`. Integrity is guaranteed by rustls. - /// - /// Returns `Some` if and only if a valid resumption ticket has been received from the client. - pub fn received_resumption_data(&self) -> Option<&[u8]> { - self.inner - .core - .data - .received_resumption_data - .as_ref() - .map(|x| &x[..]) - } - - /// Set the resumption data to embed in future resumption tickets supplied to the client. - /// - /// Defaults to the empty byte string. Must be less than 2^15 bytes to allow room for other - /// data. Should be called while `is_handshaking` returns true to ensure all transmitted - /// resumption tickets are affected. - /// - /// Integrity will be assured by rustls, but the data will be visible to the client. If secrecy - /// from the client is desired, encrypt the data separately. - pub fn set_resumption_data(&mut self, data: &[u8]) { - assert!(data.len() < 2usize.pow(15)); - self.inner.core.data.resumption_data = data.into(); - } - - /// Explicitly discard early data, notifying the client - /// - /// Useful if invariants encoded in `received_resumption_data()` cannot be respected. - /// - /// Must be called while `is_handshaking` is true. - pub fn reject_early_data(&mut self) { - self.inner.core.reject_early_data() - } - - /// Returns an `io::Read` implementer you can read bytes from that are - /// received from a client as TLS1.3 0RTT/"early" data, during the handshake. - /// - /// This returns `None` in many circumstances, such as : - /// - /// - Early data is disabled if [`ServerConfig::max_early_data_size`] is zero (the default). - /// - The session negotiated with the client is not TLS1.3. - /// - The client just doesn't support early data. - /// - The connection doesn't resume an existing session. - /// - The client hasn't sent a full ClientHello yet. - pub fn early_data(&mut self) -> Option<ReadEarlyData<'_>> { - let data = &mut self.inner.core.data; - if data.early_data.was_accepted() { - Some(ReadEarlyData::new(&mut data.early_data)) - } else { - None - } - } - - /// Return true if the connection was made with a `ServerConfig` that is FIPS compatible. - /// - /// This is different from [`crate::crypto::CryptoProvider::fips()`]: - /// it is concerned only with cryptography, whereas this _also_ covers TLS-level - /// configuration that NIST recommends, as well as ECH HPKE suites if applicable. - pub fn fips(&self) -> bool { - self.inner.core.common_state.fips - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - /// Should be used with care as it exposes secret key material. - pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { - self.inner.dangerous_extract_secrets() - } - } - - impl Debug for ServerConnection { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("ServerConnection") - .finish() - } - } - - impl Deref for ServerConnection { - type Target = ConnectionCommon<ServerConnectionData>; - - fn deref(&self) -> &Self::Target { - &self.inner - } - } - - impl DerefMut for ServerConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } - } - - impl From<ServerConnection> for crate::Connection { - fn from(conn: ServerConnection) -> Self { - Self::Server(conn) - } - } - - /// Handle a server-side connection before configuration is available. - /// - /// `Acceptor` allows the caller to choose a [`ServerConfig`] after reading - /// the [`super::ClientHello`] of an incoming connection. This is useful for servers - /// that choose different certificates or cipher suites based on the - /// characteristics of the `ClientHello`. In particular it is useful for - /// servers that need to do some I/O to load a certificate and its private key - /// and don't want to use the blocking interface provided by - /// [`super::ResolvesServerCert`]. - /// - /// Create an Acceptor with [`Acceptor::default()`]. - /// - /// # Example - /// - /// ```no_run - /// # #[cfg(feature = "aws_lc_rs")] { - /// # fn choose_server_config( - /// # _: rustls::server::ClientHello, - /// # ) -> std::sync::Arc<rustls::ServerConfig> { - /// # unimplemented!(); - /// # } - /// # #[allow(unused_variables)] - /// # fn main() { - /// use rustls::server::{Acceptor, ServerConfig}; - /// let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); - /// for stream in listener.incoming() { - /// let mut stream = stream.unwrap(); - /// let mut acceptor = Acceptor::default(); - /// let accepted = loop { - /// acceptor.read_tls(&mut stream).unwrap(); - /// if let Some(accepted) = acceptor.accept().unwrap() { - /// break accepted; - /// } - /// }; - /// - /// // For some user-defined choose_server_config: - /// let config = choose_server_config(accepted.client_hello()); - /// let conn = accepted - /// .into_connection(config) - /// .unwrap(); - /// - /// // Proceed with handling the ServerConnection. - /// } - /// # } - /// # } - /// ``` - pub struct Acceptor { - inner: Option<ConnectionCommon<ServerConnectionData>>, - } - - impl Default for Acceptor { - /// Return an empty Acceptor, ready to receive bytes from a new client connection. - fn default() -> Self { - Self { - inner: Some( - ConnectionCore::new( - Box::new(Accepting), - ServerConnectionData::default(), - CommonState::new(Side::Server), - ) - .into(), - ), - } - } - } - - impl Acceptor { - /// Read TLS content from `rd`. - /// - /// Returns an error if this `Acceptor` has already yielded an [`Accepted`]. For more details, - /// refer to [`Connection::read_tls()`]. - /// - /// [`Connection::read_tls()`]: crate::Connection::read_tls - pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result<usize, io::Error> { - match &mut self.inner { - Some(conn) => conn.read_tls(rd), - None => Err(io::Error::new( - io::ErrorKind::Other, - "acceptor cannot read after successful acceptance", - )), - } - } - - /// Check if a `ClientHello` message has been received. - /// - /// Returns `Ok(None)` if the complete `ClientHello` has not yet been received. - /// Do more I/O and then call this function again. - /// - /// Returns `Ok(Some(accepted))` if the connection has been accepted. Call - /// `accepted.into_connection()` to continue. Do not call this function again. - /// - /// Returns `Err((err, alert))` if an error occurred. If an alert is returned, the - /// application should call `alert.write()` to send the alert to the client. It should - /// not call `accept()` again. - pub fn accept(&mut self) -> Result<Option<Accepted>, (Error, AcceptedAlert)> { - let Some(mut connection) = self.inner.take() else { - return Err(( - Error::General("Acceptor polled after completion".into()), - AcceptedAlert::empty(), - )); - }; - - let message = match connection.first_handshake_message() { - Ok(Some(msg)) => msg, - Ok(None) => { - self.inner = Some(connection); - return Ok(None); - } - Err(err) => return Err((err, AcceptedAlert::from(connection))), - }; - - let mut cx = Context::from(&mut connection); - let sig_schemes = match hs::process_client_hello(&message, false, &mut cx) { - Ok((_, sig_schemes)) => sig_schemes, - Err(err) => { - return Err((err, AcceptedAlert::from(connection))); - } - }; - - Ok(Some(Accepted { - connection, - message, - sig_schemes, - })) - } - } - - /// Represents a TLS alert resulting from handling the client's `ClientHello` message. - /// - /// When [`Acceptor::accept()`] returns an error, it yields an `AcceptedAlert` such that the - /// application can communicate failure to the client via [`AcceptedAlert::write()`]. - pub struct AcceptedAlert(ChunkVecBuffer); - - impl AcceptedAlert { - pub(super) fn empty() -> Self { - Self(ChunkVecBuffer::new(None)) - } - - /// Send the alert to the client. - /// - /// To account for short writes this function should be called repeatedly until it - /// returns `Ok(0)` or an error. - pub fn write(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error> { - self.0.write_to(wr) - } - - /// Send the alert to the client. - /// - /// This function will invoke the writer until the buffer is empty. - pub fn write_all(&mut self, wr: &mut dyn io::Write) -> Result<(), io::Error> { - while self.write(wr)? != 0 {} - Ok(()) - } - } - - impl From<ConnectionCommon<ServerConnectionData>> for AcceptedAlert { - fn from(conn: ConnectionCommon<ServerConnectionData>) -> Self { - Self(conn.core.common_state.sendable_tls) - } - } - - impl Debug for AcceptedAlert { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("AcceptedAlert").finish() - } - } -} - -#[cfg(feature = "std")] -pub use connection::{AcceptedAlert, Acceptor, ReadEarlyData, ServerConnection}; - -/// Unbuffered version of `ServerConnection` -/// -/// See the [`crate::unbuffered`] module docs for more details -pub struct UnbufferedServerConnection { - inner: UnbufferedConnectionCommon<ServerConnectionData>, -} - -impl UnbufferedServerConnection { - /// Make a new ServerConnection. `config` controls how we behave in the TLS protocol. - pub fn new(config: Arc<ServerConfig>) -> Result<Self, Error> { - Ok(Self { - inner: UnbufferedConnectionCommon::from(ConnectionCore::for_server( - config, - ServerExtensionsInput::default(), - )?), - }) - } - - /// Extract secrets, so they can be used when configuring kTLS, for example. - /// Should be used with care as it exposes secret key material. - #[deprecated = "dangerous_extract_secrets() does not support session tickets or \ - key updates, use dangerous_into_kernel_connection() instead"] - pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { - self.inner.dangerous_extract_secrets() - } - - /// Extract secrets and an [`KernelConnection`] object. - /// - /// This allows you use rustls to manage keys and then manage encryption and - /// decryption yourself (e.g. for kTLS). - /// - /// Should be used with care as it exposes secret key material. - /// - /// See the [`crate::kernel`] documentations for details on prerequisites - /// for calling this method. - pub fn dangerous_into_kernel_connection( - self, - ) -> Result<(ExtractedSecrets, KernelConnection<ServerConnectionData>), Error> { - self.inner - .core - .dangerous_into_kernel_connection() - } -} - -impl Deref for UnbufferedServerConnection { - type Target = UnbufferedConnectionCommon<ServerConnectionData>; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -impl DerefMut for UnbufferedServerConnection { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.inner - } -} - -impl UnbufferedConnectionCommon<ServerConnectionData> { - pub(crate) fn pop_early_data(&mut self) -> Option<Vec<u8>> { - self.core.data.early_data.pop() - } - - pub(crate) fn peek_early_data(&self) -> Option<&[u8]> { - self.core.data.early_data.peek() - } -} - -/// Represents a `ClientHello` message received through the [`Acceptor`]. -/// -/// Contains the state required to resume the connection through [`Accepted::into_connection()`]. -pub struct Accepted { - connection: ConnectionCommon<ServerConnectionData>, - message: Message<'static>, - sig_schemes: Vec<SignatureScheme>, -} - -impl Accepted { - /// Get the [`ClientHello`] for this connection. - pub fn client_hello(&self) -> ClientHello<'_> { - let payload = Self::client_hello_payload(&self.message); - let ch = ClientHello { - server_name: &self.connection.core.data.sni, - signature_schemes: &self.sig_schemes, - alpn: payload.protocols.as_ref(), - server_cert_types: payload - .server_certificate_types - .as_deref(), - client_cert_types: payload - .client_certificate_types - .as_deref(), - cipher_suites: &payload.cipher_suites, - certificate_authorities: payload - .certificate_authority_names - .as_deref(), - named_groups: payload.named_groups.as_deref(), - }; - - trace!("Accepted::client_hello(): {ch:#?}"); - ch - } - - /// Convert the [`Accepted`] into a [`ServerConnection`]. - /// - /// Takes the state returned from [`Acceptor::accept()`] as well as the [`ServerConfig`] and - /// [`sign::CertifiedKey`] that should be used for the session. Returns an error if - /// configuration-dependent validation of the received `ClientHello` message fails. - #[cfg(feature = "std")] - pub fn into_connection( - mut self, - config: Arc<ServerConfig>, - ) -> Result<ServerConnection, (Error, AcceptedAlert)> { - if let Err(err) = self - .connection - .set_max_fragment_size(config.max_fragment_size) - { - // We have a connection here, but it won't contain an alert since the error - // is with the fragment size configured in the `ServerConfig`. - return Err((err, AcceptedAlert::empty())); - } - - self.connection.enable_secret_extraction = config.enable_secret_extraction; - - let state = hs::ExpectClientHello::new(config, ServerExtensionsInput::default()); - let mut cx = hs::ServerContext::from(&mut self.connection); - - let ch = Self::client_hello_payload(&self.message); - let new = match state.with_certified_key(self.sig_schemes, ch, &self.message, &mut cx) { - Ok(new) => new, - Err(err) => return Err((err, AcceptedAlert::from(self.connection))), - }; - - self.connection.replace_state(new); - Ok(ServerConnection { - inner: self.connection, - }) - } - - fn client_hello_payload<'a>(message: &'a Message<'_>) -> &'a ClientHelloPayload { - match &message.payload { - crate::msgs::message::MessagePayload::Handshake { parsed, .. } => match &parsed.0 { - crate::msgs::handshake::HandshakePayload::ClientHello(ch) => ch, - _ => unreachable!(), - }, - _ => unreachable!(), - } - } -} - -impl Debug for Accepted { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - f.debug_struct("Accepted").finish() - } -} - -#[cfg(feature = "std")] -struct Accepting; - -#[cfg(feature = "std")] -impl State<ServerConnectionData> for Accepting { - fn handle<'m>( - self: Box<Self>, - _cx: &mut hs::ServerContext<'_>, - _m: Message<'m>, - ) -> Result<Box<dyn State<ServerConnectionData> + 'm>, Error> - where - Self: 'm, - { - Err(Error::General("unreachable state".into())) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -pub(super) enum EarlyDataState { - New, - Accepted { - received: ChunkVecBuffer, - left: usize, - }, - Rejected, -} - -impl Default for EarlyDataState { - fn default() -> Self { - Self::New - } -} - -impl EarlyDataState { - pub(super) fn reject(&mut self) { - *self = Self::Rejected; - } - - pub(super) fn accept(&mut self, max_size: usize) { - *self = Self::Accepted { - received: ChunkVecBuffer::new(Some(max_size)), - left: max_size, - }; - } - - #[cfg(feature = "std")] - fn was_accepted(&self) -> bool { - matches!(self, Self::Accepted { .. }) - } - - pub(super) fn was_rejected(&self) -> bool { - matches!(self, Self::Rejected) - } - - fn peek(&self) -> Option<&[u8]> { - match self { - Self::Accepted { received, .. } => received.peek(), - _ => None, - } - } - - fn pop(&mut self) -> Option<Vec<u8>> { - match self { - Self::Accepted { received, .. } => received.pop(), - _ => None, - } - } - - #[cfg(feature = "std")] - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - match self { - Self::Accepted { received, .. } => received.read(buf), - _ => Err(io::Error::from(io::ErrorKind::BrokenPipe)), - } - } - - #[cfg(read_buf)] - fn read_buf(&mut self, cursor: core::io::BorrowedCursor<'_>) -> io::Result<()> { - match self { - Self::Accepted { received, .. } => received.read_buf(cursor), - _ => Err(io::Error::from(io::ErrorKind::BrokenPipe)), - } - } - - pub(super) fn take_received_plaintext(&mut self, bytes: Payload<'_>) -> bool { - let available = bytes.bytes().len(); - let Self::Accepted { received, left } = self else { - return false; - }; - - if received.apply_limit(available) != available || available > *left { - return false; - } - - received.append(bytes.into_vec()); - *left -= available; - true - } -} - -impl Debug for EarlyDataState { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match self { - Self::New => write!(f, "EarlyDataState::New"), - Self::Accepted { received, left } => write!( - f, - "EarlyDataState::Accepted {{ received: {}, left: {} }}", - received.len(), - left - ), - Self::Rejected => write!(f, "EarlyDataState::Rejected"), - } - } -} - -impl ConnectionCore<ServerConnectionData> { - pub(crate) fn for_server( - config: Arc<ServerConfig>, - extra_exts: ServerExtensionsInput<'static>, - ) -> Result<Self, Error> { - let mut common = CommonState::new(Side::Server); - common.set_max_fragment_size(config.max_fragment_size)?; - common.enable_secret_extraction = config.enable_secret_extraction; - common.fips = config.fips(); - Ok(Self::new( - Box::new(hs::ExpectClientHello::new(config, extra_exts)), - ServerConnectionData::default(), - common, - )) - } - - #[cfg(feature = "std")] - pub(crate) fn reject_early_data(&mut self) { - assert!( - self.common_state.is_handshaking(), - "cannot retroactively reject early data" - ); - self.data.early_data.reject(); - } - - #[cfg(feature = "std")] - pub(crate) fn get_sni_str(&self) -> Option<&str> { - self.data.get_sni_str() - } -} - -/// State associated with a server connection. -#[derive(Default, Debug)] -pub struct ServerConnectionData { - pub(super) sni: Option<DnsName<'static>>, - pub(super) received_resumption_data: Option<Vec<u8>>, - pub(super) resumption_data: Vec<u8>, - pub(super) early_data: EarlyDataState, -} - -impl ServerConnectionData { - #[cfg(feature = "std")] - pub(super) fn get_sni_str(&self) -> Option<&str> { - self.sni.as_ref().map(AsRef::as_ref) - } -} - -impl crate::conn::SideData for ServerConnectionData {} - -#[cfg(feature = "std")] -#[cfg(test)] -mod tests { - use std::format; - - use super::*; - - // these branches not reachable externally, unless something else goes wrong. - #[test] - fn test_read_in_new_state() { - assert_eq!( - format!("{:?}", EarlyDataState::default().read(&mut [0u8; 5])), - "Err(Kind(BrokenPipe))" - ); - } - - #[cfg(read_buf)] - #[test] - fn test_read_buf_in_new_state() { - use core::io::BorrowedBuf; - - let mut buf = [0u8; 5]; - let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); - assert_eq!( - format!("{:?}", EarlyDataState::default().read_buf(buf.unfilled())), - "Err(Kind(BrokenPipe))" - ); - } -} diff --git a/vendor/rustls/src/server/test.rs b/vendor/rustls/src/server/test.rs deleted file mode 100644 index 9254dbc6..00000000 --- a/vendor/rustls/src/server/test.rs +++ /dev/null @@ -1,369 +0,0 @@ -use std::prelude::v1::*; -use std::vec; - -use super::ServerConnectionData; -use crate::common_state::Context; -use crate::enums::{CipherSuite, SignatureScheme}; -use crate::msgs::base::PayloadU16; -use crate::msgs::enums::{Compression, NamedGroup}; -use crate::msgs::handshake::{ - ClientExtensions, ClientHelloPayload, HandshakeMessagePayload, HandshakePayload, KeyShareEntry, - Random, ServerNamePayload, SessionId, SupportedProtocolVersions, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::{CommonState, Error, PeerIncompatible, PeerMisbehaved, ProtocolVersion, Side}; - -#[test] -fn null_compression_required() { - assert_eq!( - test_process_client_hello(ClientHelloPayload { - compression_methods: vec![], - ..minimal_client_hello() - }), - Err(PeerIncompatible::NullCompressionRequired.into()), - ); -} - -#[test] -fn server_ignores_sni_with_ip_address() { - let mut ch = minimal_client_hello(); - ch.extensions.server_name = Some(ServerNamePayload::IpAddress); - std::println!("{:?}", ch.extensions); - assert_eq!(test_process_client_hello(ch), Ok(())); -} - -#[test] -fn server_rejects_sni_with_illegal_dns_name() { - let mut ch = minimal_client_hello(); - ch.extensions.server_name = Some(ServerNamePayload::Invalid); - std::println!("{:?}", ch.extensions); - assert_eq!( - test_process_client_hello(ch), - Err(PeerMisbehaved::ServerNameMustContainOneHostName.into()) - ); -} - -fn test_process_client_hello(hello: ClientHelloPayload) -> Result<(), Error> { - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload(HandshakePayload::ClientHello( - hello, - ))), - }; - super::hs::process_client_hello( - &m, - false, - &mut Context { - common: &mut CommonState::new(Side::Server), - data: &mut ServerConnectionData::default(), - sendable_plaintext: None, - }, - ) - .map(|_| ()) -} - -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use super::super::*; - use crate::common_state::KxState; - use crate::crypto::{ - ActiveKeyExchange, CryptoProvider, KeyExchangeAlgorithm, SupportedKxGroup, - }; - use crate::enums::CertificateType; - use crate::pki_types::pem::PemObject; - use crate::pki_types::{CertificateDer, PrivateKeyDer}; - use crate::server::{AlwaysResolvesServerRawPublicKeys, ServerConfig, ServerConnection}; - use crate::sign::CertifiedKey; - use crate::sync::Arc; - use crate::{CipherSuiteCommon, SupportedCipherSuite, Tls12CipherSuite, version}; - - #[cfg(feature = "tls12")] - #[test] - fn test_server_rejects_no_extended_master_secret_extension_when_require_ems_or_fips() { - let provider = super::provider::default_provider(); - let mut config = ServerConfig::builder_with_provider(provider.into()) - .with_protocol_versions(&[&version::TLS12]) - .unwrap() - .with_no_client_auth() - .with_single_cert(server_cert(), server_key()) - .unwrap(); - - if config.provider.fips() { - assert!(config.require_ems); - } else { - config.require_ems = true; - } - let mut conn = ServerConnection::new(config.into()).unwrap(); - - let mut ch = minimal_client_hello(); - ch.extensions - .extended_master_secret_request - .take(); - let ch = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ClientHello(ch), - )), - }; - conn.read_tls(&mut ch.into_wire_bytes().as_slice()) - .unwrap(); - - assert_eq!( - conn.process_new_packets(), - Err(Error::PeerIncompatible( - PeerIncompatible::ExtendedMasterSecretExtensionRequired - )) - ); - } - - #[cfg(feature = "tls12")] - #[test] - fn server_picks_ffdhe_group_when_clienthello_has_no_ffdhe_group_in_groups_ext() { - let config = ServerConfig::builder_with_provider(ffdhe_provider().into()) - .with_protocol_versions(&[&version::TLS12]) - .unwrap() - .with_no_client_auth() - .with_single_cert(server_cert(), server_key()) - .unwrap(); - - let mut ch = minimal_client_hello(); - ch.cipher_suites - .push(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256.suite()); - - server_chooses_ffdhe_group_for_client_hello( - ServerConnection::new(config.into()).unwrap(), - ch, - ); - } - - #[cfg(feature = "tls12")] - #[test] - fn server_picks_ffdhe_group_when_clienthello_has_no_groups_ext() { - let config = ServerConfig::builder_with_provider(ffdhe_provider().into()) - .with_protocol_versions(&[&version::TLS12]) - .unwrap() - .with_no_client_auth() - .with_single_cert(server_cert(), server_key()) - .unwrap(); - - let mut ch = minimal_client_hello(); - ch.cipher_suites - .push(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256.suite()); - ch.extensions.named_groups.take(); - - server_chooses_ffdhe_group_for_client_hello( - ServerConnection::new(config.into()).unwrap(), - ch, - ); - } - - #[cfg(feature = "tls12")] - #[test] - fn server_accepts_client_with_no_ecpoints_extension_and_only_ffdhe_cipher_suites() { - let config = ServerConfig::builder_with_provider(ffdhe_provider().into()) - .with_protocol_versions(&[&version::TLS12]) - .unwrap() - .with_no_client_auth() - .with_single_cert(server_cert(), server_key()) - .unwrap(); - - let mut ch = minimal_client_hello(); - ch.cipher_suites - .push(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256.suite()); - ch.extensions.ec_point_formats.take(); - - server_chooses_ffdhe_group_for_client_hello( - ServerConnection::new(config.into()).unwrap(), - ch, - ); - } - - fn server_chooses_ffdhe_group_for_client_hello( - mut conn: ServerConnection, - client_hello: ClientHelloPayload, - ) { - let ch = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ClientHello(client_hello), - )), - }; - conn.read_tls(&mut ch.into_wire_bytes().as_slice()) - .unwrap(); - conn.process_new_packets().unwrap(); - - let KxState::Start(skxg) = &conn.kx_state else { - panic!("unexpected kx_state"); - }; - assert_eq!(skxg.name(), FAKE_FFDHE_GROUP.name()); - } - - #[test] - fn test_server_requiring_rpk_client_rejects_x509_client() { - let mut ch = minimal_client_hello(); - ch.extensions.client_certificate_types = Some(vec![CertificateType::X509]); - let ch = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ClientHello(ch), - )), - }; - - let mut conn = ServerConnection::new(server_config_for_rpk().into()).unwrap(); - conn.read_tls(&mut ch.into_wire_bytes().as_slice()) - .unwrap(); - assert_eq!( - conn.process_new_packets().unwrap_err(), - PeerIncompatible::IncorrectCertificateTypeExtension.into(), - ); - } - - #[test] - fn test_rpk_only_server_rejects_x509_only_client() { - let mut ch = minimal_client_hello(); - ch.extensions.server_certificate_types = Some(vec![CertificateType::X509]); - let ch = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ClientHello(ch), - )), - }; - - let mut conn = ServerConnection::new(server_config_for_rpk().into()).unwrap(); - conn.read_tls(&mut ch.into_wire_bytes().as_slice()) - .unwrap(); - assert_eq!( - conn.process_new_packets().unwrap_err(), - PeerIncompatible::IncorrectCertificateTypeExtension.into(), - ); - } - - fn server_config_for_rpk() -> ServerConfig { - let x25519_provider = CryptoProvider { - kx_groups: vec![super::provider::kx_group::X25519], - ..super::provider::default_provider() - }; - ServerConfig::builder_with_provider(x25519_provider.into()) - .with_protocol_versions(&[&version::TLS13]) - .unwrap() - .with_no_client_auth() - .with_cert_resolver(Arc::new(AlwaysResolvesServerRawPublicKeys::new(Arc::new( - server_certified_key(), - )))) - } - - fn server_certified_key() -> CertifiedKey { - let key = super::provider::default_provider() - .key_provider - .load_private_key(server_key()) - .unwrap(); - let public_key_as_cert = vec![CertificateDer::from( - key.public_key() - .unwrap() - .as_ref() - .to_vec(), - )]; - CertifiedKey::new(public_key_as_cert, key) - } - - fn server_key() -> PrivateKeyDer<'static> { - PrivateKeyDer::from_pem_reader( - &mut include_bytes!("../../../test-ca/rsa-2048/end.key").as_slice(), - ) - .unwrap() - } - - fn server_cert() -> Vec<CertificateDer<'static>> { - vec![ - CertificateDer::from(&include_bytes!("../../../test-ca/rsa-2048/end.der")[..]), - CertificateDer::from(&include_bytes!("../../../test-ca/rsa-2048/inter.der")[..]), - ] - } - - fn ffdhe_provider() -> CryptoProvider { - CryptoProvider { - kx_groups: vec![FAKE_FFDHE_GROUP], - cipher_suites: vec![TLS_DHE_RSA_WITH_AES_128_GCM_SHA256], - ..super::provider::default_provider() - } - } - - static FAKE_FFDHE_GROUP: &'static dyn SupportedKxGroup = &FakeFfdheGroup; - - #[derive(Debug)] - struct FakeFfdheGroup; - - impl SupportedKxGroup for FakeFfdheGroup { - fn name(&self) -> NamedGroup { - NamedGroup::FFDHE2048 - } - - fn start(&self) -> Result<Box<dyn ActiveKeyExchange>, Error> { - Ok(Box::new(ActiveFakeFfdhe)) - } - } - - #[derive(Debug)] - struct ActiveFakeFfdhe; - - impl ActiveKeyExchange for ActiveFakeFfdhe { - #[cfg_attr(coverage_nightly, coverage(off))] - fn complete( - self: Box<Self>, - _peer_pub_key: &[u8], - ) -> Result<crate::crypto::SharedSecret, Error> { - todo!() - } - - fn pub_key(&self) -> &[u8] { - b"ActiveFakeFfdhe pub key" - } - - fn group(&self) -> NamedGroup { - NamedGroup::FFDHE2048 - } - } - - static TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite = - SupportedCipherSuite::Tls12(&TLS12_DHE_RSA_WITH_AES_128_GCM_SHA256); - - static TLS12_DHE_RSA_WITH_AES_128_GCM_SHA256: Tls12CipherSuite = - match &super::provider::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 { - SupportedCipherSuite::Tls12(provider) => Tls12CipherSuite { - common: CipherSuiteCommon { - suite: CipherSuite::TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - ..provider.common - }, - kx: KeyExchangeAlgorithm::DHE, - ..**provider - }, - _ => unreachable!(), - }; -} - -fn minimal_client_hello() -> ClientHelloPayload { - ClientHelloPayload { - client_version: ProtocolVersion::TLSv1_3, - random: Random::from([0u8; 32]), - session_id: SessionId::empty(), - cipher_suites: vec![ - CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - CipherSuite::TLS13_AES_128_GCM_SHA256, - ], - compression_methods: vec![Compression::Null], - extensions: Box::new(ClientExtensions { - signature_schemes: Some(vec![SignatureScheme::RSA_PSS_SHA256]), - named_groups: Some(vec![NamedGroup::X25519, NamedGroup::secp256r1]), - supported_versions: Some(SupportedProtocolVersions { - tls12: true, - tls13: true, - }), - key_shares: Some(vec![KeyShareEntry { - group: NamedGroup::X25519, - payload: PayloadU16::new(vec![0xab; 32]), - }]), - extended_master_secret_request: Some(()), - ..ClientExtensions::default() - }), - } -} diff --git a/vendor/rustls/src/server/tls12.rs b/vendor/rustls/src/server/tls12.rs deleted file mode 100644 index d3dfa5c8..00000000 --- a/vendor/rustls/src/server/tls12.rs +++ /dev/null @@ -1,1003 +0,0 @@ -use alloc::boxed::Box; -use alloc::string::ToString; -use alloc::vec; -use alloc::vec::Vec; - -pub(super) use client_hello::CompleteClientHelloHandling; -use pki_types::UnixTime; -use subtle::ConstantTimeEq; - -use super::common::ActiveCertifiedKey; -use super::hs::{self, ServerContext}; -use super::server_conn::{ProducesTickets, ServerConfig, ServerConnectionData}; -use crate::check::inappropriate_message; -use crate::common_state::{CommonState, HandshakeFlightTls12, HandshakeKind, Side, State}; -use crate::conn::ConnectionRandoms; -use crate::conn::kernel::{Direction, KernelContext, KernelState}; -use crate::crypto::ActiveKeyExchange; -use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion}; -use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; -use crate::hash_hs::HandshakeHash; -use crate::log::{debug, trace}; -use crate::msgs::base::Payload; -use crate::msgs::ccs::ChangeCipherSpecPayload; -use crate::msgs::codec::Codec; -use crate::msgs::handshake::{ - CertificateChain, ClientKeyExchangeParams, HandshakeMessagePayload, HandshakePayload, - NewSessionTicketPayload, NewSessionTicketPayloadTls13, SessionId, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::suites::PartiallyExtractedSecrets; -use crate::sync::Arc; -use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite}; -use crate::{ConnectionTrafficSecrets, verify}; - -mod client_hello { - use pki_types::CertificateDer; - - use super::*; - use crate::common_state::KxState; - use crate::crypto::SupportedKxGroup; - use crate::enums::SignatureScheme; - use crate::msgs::enums::{ClientCertificateType, Compression}; - use crate::msgs::handshake::{ - CertificateRequestPayload, CertificateStatus, ClientHelloPayload, ClientSessionTicket, - Random, ServerExtensionsInput, ServerHelloPayload, ServerKeyExchange, - ServerKeyExchangeParams, ServerKeyExchangePayload, - }; - use crate::sign; - use crate::verify::DigitallySignedStruct; - - pub(in crate::server) struct CompleteClientHelloHandling { - pub(in crate::server) config: Arc<ServerConfig>, - pub(in crate::server) transcript: HandshakeHash, - pub(in crate::server) session_id: SessionId, - pub(in crate::server) suite: &'static Tls12CipherSuite, - pub(in crate::server) using_ems: bool, - pub(in crate::server) randoms: ConnectionRandoms, - pub(in crate::server) send_ticket: bool, - pub(in crate::server) extra_exts: ServerExtensionsInput<'static>, - } - - impl CompleteClientHelloHandling { - pub(in crate::server) fn handle_client_hello( - mut self, - cx: &mut ServerContext<'_>, - server_key: ActiveCertifiedKey<'_>, - chm: &Message<'_>, - client_hello: &ClientHelloPayload, - selected_kxg: &'static dyn SupportedKxGroup, - sigschemes_ext: Vec<SignatureScheme>, - tls13_enabled: bool, - ) -> hs::NextStateOrError<'static> { - // -- TLS1.2 only from hereon in -- - self.transcript.add_message(chm); - - if client_hello - .extended_master_secret_request - .is_some() - { - self.using_ems = true; - } else if self.config.require_ems { - return Err(cx.common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerIncompatible::ExtendedMasterSecretExtensionRequired, - )); - } - - // "RFC 4492 specified that if this extension is missing, - // it means that only the uncompressed point format is - // supported" - // - <https://datatracker.ietf.org/doc/html/rfc8422#section-5.1.2> - let supported_ec_point_formats = client_hello - .ec_point_formats - .unwrap_or_default(); - - trace!("ecpoints {supported_ec_point_formats:?}"); - - if !supported_ec_point_formats.uncompressed { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerIncompatible::UncompressedEcPointsRequired, - )); - } - - // -- If TLS1.3 is enabled, signal the downgrade in the server random - if tls13_enabled { - self.randoms.server[24..].copy_from_slice(&tls12::DOWNGRADE_SENTINEL); - } - - // -- Check for resumption -- - // We can do this either by (in order of preference): - // 1. receiving a ticket that decrypts - // 2. receiving a sessionid that is in our cache - // - // If we receive a ticket, the sessionid won't be in our - // cache, so don't check. - // - // If either works, we end up with a ServerConnectionValue - // which is passed to start_resumption and concludes - // our handling of the ClientHello. - // - let mut ticket_received = false; - let resume_data = client_hello - .session_ticket - .as_ref() - .and_then(|ticket_ext| match ticket_ext { - ClientSessionTicket::Offer(ticket) => Some(ticket), - _ => None, - }) - .and_then(|ticket| { - ticket_received = true; - debug!("Ticket received"); - let data = self - .config - .ticketer - .decrypt(ticket.bytes()); - if data.is_none() { - debug!("Ticket didn't decrypt"); - } - data - }) - .or_else(|| { - // Perhaps resume? If we received a ticket, the sessionid - // does not correspond to a real session. - if client_hello.session_id.is_empty() || ticket_received { - return None; - } - - self.config - .session_storage - .get(client_hello.session_id.as_ref()) - }) - .and_then(|x| persist::ServerSessionValue::read_bytes(&x).ok()) - .filter(|resumedata| { - hs::can_resume(self.suite.into(), &cx.data.sni, self.using_ems, resumedata) - }); - - if let Some(data) = resume_data { - return self.start_resumption(cx, client_hello, &client_hello.session_id, data); - } - - // Now we have chosen a ciphersuite, we can make kx decisions. - let sigschemes = self - .suite - .resolve_sig_schemes(&sigschemes_ext); - - if sigschemes.is_empty() { - return Err(cx.common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerIncompatible::NoSignatureSchemesInCommon, - )); - } - - let mut ocsp_response = server_key.get_ocsp(); - - // If we're not offered a ticket or a potential session ID, allocate a session ID. - if !self.config.session_storage.can_cache() { - self.session_id = SessionId::empty(); - } else if self.session_id.is_empty() && !ticket_received { - self.session_id = SessionId::random(self.config.provider.secure_random)?; - } - - cx.common.kx_state = KxState::Start(selected_kxg); - cx.common.handshake_kind = Some(HandshakeKind::Full); - - let mut flight = HandshakeFlightTls12::new(&mut self.transcript); - - self.send_ticket = emit_server_hello( - &mut flight, - &self.config, - cx, - self.session_id, - self.suite, - self.using_ems, - &mut ocsp_response, - client_hello, - None, - &self.randoms, - self.extra_exts, - )?; - emit_certificate(&mut flight, server_key.get_cert()); - if let Some(ocsp_response) = ocsp_response { - emit_cert_status(&mut flight, ocsp_response); - } - let server_kx = emit_server_kx( - &mut flight, - sigschemes, - selected_kxg, - server_key.get_key(), - &self.randoms, - )?; - let doing_client_auth = emit_certificate_req(&mut flight, &self.config)?; - emit_server_hello_done(&mut flight); - - flight.finish(cx.common); - - if doing_client_auth { - Ok(Box::new(ExpectCertificate { - config: self.config, - transcript: self.transcript, - randoms: self.randoms, - session_id: self.session_id, - suite: self.suite, - using_ems: self.using_ems, - server_kx, - send_ticket: self.send_ticket, - })) - } else { - Ok(Box::new(ExpectClientKx { - config: self.config, - transcript: self.transcript, - randoms: self.randoms, - session_id: self.session_id, - suite: self.suite, - using_ems: self.using_ems, - server_kx, - client_cert: None, - send_ticket: self.send_ticket, - })) - } - } - - fn start_resumption( - mut self, - cx: &mut ServerContext<'_>, - client_hello: &ClientHelloPayload, - id: &SessionId, - resumedata: persist::ServerSessionValue, - ) -> hs::NextStateOrError<'static> { - debug!("Resuming connection"); - - if resumedata.extended_ms && !self.using_ems { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::ResumptionAttemptedWithVariedEms, - )); - } - - self.session_id = *id; - let mut flight = HandshakeFlightTls12::new(&mut self.transcript); - self.send_ticket = emit_server_hello( - &mut flight, - &self.config, - cx, - self.session_id, - self.suite, - self.using_ems, - &mut None, - client_hello, - Some(&resumedata), - &self.randoms, - self.extra_exts, - )?; - flight.finish(cx.common); - - let secrets = ConnectionSecrets::new_resume( - self.randoms, - self.suite, - &resumedata.master_secret.0, - ); - self.config.key_log.log( - "CLIENT_RANDOM", - &secrets.randoms.client, - &secrets.master_secret, - ); - cx.common - .start_encryption_tls12(&secrets, Side::Server); - cx.common.peer_certificates = resumedata.client_cert_chain; - cx.common.handshake_kind = Some(HandshakeKind::Resumed); - - if self.send_ticket { - let now = self.config.current_time()?; - - emit_ticket( - &secrets, - &mut self.transcript, - self.using_ems, - cx, - &*self.config.ticketer, - now, - )?; - } - emit_ccs(cx.common); - cx.common - .record_layer - .start_encrypting(); - emit_finished(&secrets, &mut self.transcript, cx.common); - - Ok(Box::new(ExpectCcs { - config: self.config, - secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - resuming: true, - send_ticket: self.send_ticket, - })) - } - } - - fn emit_server_hello( - flight: &mut HandshakeFlightTls12<'_>, - config: &ServerConfig, - cx: &mut ServerContext<'_>, - session_id: SessionId, - suite: &'static Tls12CipherSuite, - using_ems: bool, - ocsp_response: &mut Option<&[u8]>, - hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>, - randoms: &ConnectionRandoms, - extra_exts: ServerExtensionsInput<'static>, - ) -> Result<bool, Error> { - let mut ep = hs::ExtensionProcessing::new(extra_exts); - ep.process_common(config, cx, ocsp_response, hello, resumedata)?; - ep.process_tls12(config, hello, using_ems); - - let sh = HandshakeMessagePayload(HandshakePayload::ServerHello(ServerHelloPayload { - legacy_version: ProtocolVersion::TLSv1_2, - random: Random::from(randoms.server), - session_id, - cipher_suite: suite.common.suite, - compression_method: Compression::Null, - extensions: ep.extensions, - })); - trace!("sending server hello {sh:?}"); - flight.add(sh); - - Ok(ep.send_ticket) - } - - fn emit_certificate( - flight: &mut HandshakeFlightTls12<'_>, - cert_chain: &[CertificateDer<'static>], - ) { - flight.add(HandshakeMessagePayload(HandshakePayload::Certificate( - CertificateChain(cert_chain.to_vec()), - ))); - } - - fn emit_cert_status(flight: &mut HandshakeFlightTls12<'_>, ocsp: &[u8]) { - flight.add(HandshakeMessagePayload( - HandshakePayload::CertificateStatus(CertificateStatus::new(ocsp)), - )); - } - - fn emit_server_kx( - flight: &mut HandshakeFlightTls12<'_>, - sigschemes: Vec<SignatureScheme>, - selected_group: &'static dyn SupportedKxGroup, - signing_key: &dyn sign::SigningKey, - randoms: &ConnectionRandoms, - ) -> Result<Box<dyn ActiveKeyExchange>, Error> { - let kx = selected_group.start()?; - let kx_params = ServerKeyExchangeParams::new(&*kx); - - let mut msg = Vec::new(); - msg.extend(randoms.client); - msg.extend(randoms.server); - kx_params.encode(&mut msg); - - let signer = signing_key - .choose_scheme(&sigschemes) - .ok_or_else(|| Error::General("incompatible signing key".to_string()))?; - let sigscheme = signer.scheme(); - let sig = signer.sign(&msg)?; - - let skx = ServerKeyExchangePayload::from(ServerKeyExchange { - params: kx_params, - dss: DigitallySignedStruct::new(sigscheme, sig), - }); - - flight.add(HandshakeMessagePayload( - HandshakePayload::ServerKeyExchange(skx), - )); - Ok(kx) - } - - fn emit_certificate_req( - flight: &mut HandshakeFlightTls12<'_>, - config: &ServerConfig, - ) -> Result<bool, Error> { - let client_auth = &config.verifier; - - if !client_auth.offer_client_auth() { - return Ok(false); - } - - let verify_schemes = client_auth.supported_verify_schemes(); - - let names = config - .verifier - .root_hint_subjects() - .to_vec(); - - let cr = CertificateRequestPayload { - certtypes: vec![ - ClientCertificateType::RSASign, - ClientCertificateType::ECDSASign, - ], - sigschemes: verify_schemes, - canames: names, - }; - - let creq = HandshakeMessagePayload(HandshakePayload::CertificateRequest(cr)); - - trace!("Sending CertificateRequest {creq:?}"); - flight.add(creq); - Ok(true) - } - - fn emit_server_hello_done(flight: &mut HandshakeFlightTls12<'_>) { - flight.add(HandshakeMessagePayload(HandshakePayload::ServerHelloDone)); - } -} - -// --- Process client's Certificate for client auth --- -struct ExpectCertificate { - config: Arc<ServerConfig>, - transcript: HandshakeHash, - randoms: ConnectionRandoms, - session_id: SessionId, - suite: &'static Tls12CipherSuite, - using_ems: bool, - server_kx: Box<dyn ActiveKeyExchange>, - send_ticket: bool, -} - -impl State<ServerConnectionData> for ExpectCertificate { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - self.transcript.add_message(&m); - let cert_chain = require_handshake_msg_move!( - m, - HandshakeType::Certificate, - HandshakePayload::Certificate - )?; - - // If we can't determine if the auth is mandatory, abort - let mandatory = self - .config - .verifier - .client_auth_mandatory(); - - trace!("certs {cert_chain:?}"); - - let client_cert = match cert_chain.split_first() { - None if mandatory => { - return Err(cx.common.send_fatal_alert( - AlertDescription::CertificateRequired, - Error::NoCertificatesPresented, - )); - } - None => { - debug!("client auth requested but no certificate supplied"); - self.transcript.abandon_client_auth(); - None - } - Some((end_entity, intermediates)) => { - let now = self.config.current_time()?; - - self.config - .verifier - .verify_client_cert(end_entity, intermediates, now) - .map_err(|err| { - cx.common - .send_cert_verify_error_alert(err) - })?; - - Some(cert_chain) - } - }; - - Ok(Box::new(ExpectClientKx { - config: self.config, - transcript: self.transcript, - randoms: self.randoms, - session_id: self.session_id, - suite: self.suite, - using_ems: self.using_ems, - server_kx: self.server_kx, - client_cert, - send_ticket: self.send_ticket, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// --- Process client's KeyExchange --- -struct ExpectClientKx<'a> { - config: Arc<ServerConfig>, - transcript: HandshakeHash, - randoms: ConnectionRandoms, - session_id: SessionId, - suite: &'static Tls12CipherSuite, - using_ems: bool, - server_kx: Box<dyn ActiveKeyExchange>, - client_cert: Option<CertificateChain<'a>>, - send_ticket: bool, -} - -impl State<ServerConnectionData> for ExpectClientKx<'_> { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let client_kx = require_handshake_msg!( - m, - HandshakeType::ClientKeyExchange, - HandshakePayload::ClientKeyExchange - )?; - self.transcript.add_message(&m); - let ems_seed = self - .using_ems - .then(|| self.transcript.current_hash()); - - // Complete key agreement, and set up encryption with the - // resulting premaster secret. - let peer_kx_params = tls12::decode_kx_params::<ClientKeyExchangeParams>( - self.suite.kx, - cx.common, - client_kx.bytes(), - )?; - let secrets = ConnectionSecrets::from_key_exchange( - self.server_kx, - peer_kx_params.pub_key(), - ems_seed, - self.randoms, - self.suite, - ) - .map_err(|err| { - cx.common - .send_fatal_alert(AlertDescription::IllegalParameter, err) - })?; - cx.common.kx_state.complete(); - - self.config.key_log.log( - "CLIENT_RANDOM", - &secrets.randoms.client, - &secrets.master_secret, - ); - cx.common - .start_encryption_tls12(&secrets, Side::Server); - - match self.client_cert { - Some(client_cert) => Ok(Box::new(ExpectCertificateVerify { - config: self.config, - secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - client_cert, - send_ticket: self.send_ticket, - })), - _ => Ok(Box::new(ExpectCcs { - config: self.config, - secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - resuming: false, - send_ticket: self.send_ticket, - })), - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectClientKx { - config: self.config, - transcript: self.transcript, - randoms: self.randoms, - session_id: self.session_id, - suite: self.suite, - using_ems: self.using_ems, - server_kx: self.server_kx, - client_cert: self - .client_cert - .map(|cert| cert.into_owned()), - send_ticket: self.send_ticket, - }) - } -} - -// --- Process client's certificate proof --- -struct ExpectCertificateVerify<'a> { - config: Arc<ServerConfig>, - secrets: ConnectionSecrets, - transcript: HandshakeHash, - session_id: SessionId, - using_ems: bool, - client_cert: CertificateChain<'a>, - send_ticket: bool, -} - -impl State<ServerConnectionData> for ExpectCertificateVerify<'_> { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let rc = { - let sig = require_handshake_msg!( - m, - HandshakeType::CertificateVerify, - HandshakePayload::CertificateVerify - )?; - - match self.transcript.take_handshake_buf() { - Some(msgs) => { - let certs = &self.client_cert; - self.config - .verifier - .verify_tls12_signature(&msgs, &certs[0], sig) - } - None => { - // This should be unreachable; the handshake buffer was initialized with - // client authentication if the verifier wants to offer it. - // `transcript.abandon_client_auth()` can extract it, but its only caller in - // this flow will also set `ExpectClientKx::client_cert` to `None`, making it - // impossible to reach this state. - return Err(cx.common.send_fatal_alert( - AlertDescription::AccessDenied, - Error::General("client authentication not set up".into()), - )); - } - } - }; - - if let Err(e) = rc { - return Err(cx - .common - .send_cert_verify_error_alert(e)); - } - - trace!("client CertificateVerify OK"); - cx.common.peer_certificates = Some(self.client_cert.into_owned()); - - self.transcript.add_message(&m); - Ok(Box::new(ExpectCcs { - config: self.config, - secrets: self.secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - resuming: false, - send_ticket: self.send_ticket, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - Box::new(ExpectCertificateVerify { - config: self.config, - secrets: self.secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - client_cert: self.client_cert.into_owned(), - send_ticket: self.send_ticket, - }) - } -} - -// --- Process client's ChangeCipherSpec --- -struct ExpectCcs { - config: Arc<ServerConfig>, - secrets: ConnectionSecrets, - transcript: HandshakeHash, - session_id: SessionId, - using_ems: bool, - resuming: bool, - send_ticket: bool, -} - -impl State<ServerConnectionData> for ExpectCcs { - fn handle<'m>( - self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::ChangeCipherSpec(..) => {} - payload => { - return Err(inappropriate_message( - &payload, - &[ContentType::ChangeCipherSpec], - )); - } - } - - // CCS should not be received interleaved with fragmented handshake-level - // message. - cx.common.check_aligned_handshake()?; - - cx.common - .record_layer - .start_decrypting(); - Ok(Box::new(ExpectFinished { - config: self.config, - secrets: self.secrets, - transcript: self.transcript, - session_id: self.session_id, - using_ems: self.using_ems, - resuming: self.resuming, - send_ticket: self.send_ticket, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// --- Process client's Finished --- -fn get_server_connection_value_tls12( - secrets: &ConnectionSecrets, - using_ems: bool, - cx: &ServerContext<'_>, - time_now: UnixTime, -) -> persist::ServerSessionValue { - let version = ProtocolVersion::TLSv1_2; - - let mut v = persist::ServerSessionValue::new( - cx.data.sni.as_ref(), - version, - secrets.suite().common.suite, - secrets.master_secret(), - cx.common.peer_certificates.clone(), - cx.common.alpn_protocol.clone(), - cx.data.resumption_data.clone(), - time_now, - 0, - ); - - if using_ems { - v.set_extended_ms_used(); - } - - v -} - -fn emit_ticket( - secrets: &ConnectionSecrets, - transcript: &mut HandshakeHash, - using_ems: bool, - cx: &mut ServerContext<'_>, - ticketer: &dyn ProducesTickets, - now: UnixTime, -) -> Result<(), Error> { - let plain = get_server_connection_value_tls12(secrets, using_ems, cx, now).get_encoding(); - - // If we can't produce a ticket for some reason, we can't - // report an error. Send an empty one. - let ticket = ticketer - .encrypt(&plain) - .unwrap_or_default(); - let ticket_lifetime = ticketer.lifetime(); - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::NewSessionTicket(NewSessionTicketPayload::new( - ticket_lifetime, - ticket, - )), - )), - }; - - transcript.add_message(&m); - cx.common.send_msg(m, false); - Ok(()) -} - -fn emit_ccs(common: &mut CommonState) { - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), - }; - - common.send_msg(m, false); -} - -fn emit_finished( - secrets: &ConnectionSecrets, - transcript: &mut HandshakeHash, - common: &mut CommonState, -) { - let vh = transcript.current_hash(); - let verify_data = secrets.server_verify_data(&vh); - let verify_data_payload = Payload::new(verify_data); - - let f = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload(HandshakePayload::Finished( - verify_data_payload, - ))), - }; - - transcript.add_message(&f); - common.send_msg(f, true); -} - -struct ExpectFinished { - config: Arc<ServerConfig>, - secrets: ConnectionSecrets, - transcript: HandshakeHash, - session_id: SessionId, - using_ems: bool, - resuming: bool, - send_ticket: bool, -} - -impl State<ServerConnectionData> for ExpectFinished { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let finished = - require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; - - cx.common.check_aligned_handshake()?; - - let vh = self.transcript.current_hash(); - let expect_verify_data = self.secrets.client_verify_data(&vh); - - let _fin_verified = - match ConstantTimeEq::ct_eq(&expect_verify_data[..], finished.bytes()).into() { - true => verify::FinishedMessageVerified::assertion(), - false => { - return Err(cx - .common - .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError)); - } - }; - - // Save connection, perhaps - if !self.resuming && !self.session_id.is_empty() { - let now = self.config.current_time()?; - - let value = get_server_connection_value_tls12(&self.secrets, self.using_ems, cx, now); - - let worked = self - .config - .session_storage - .put(self.session_id.as_ref().to_vec(), value.get_encoding()); - #[cfg_attr(not(feature = "logging"), allow(clippy::if_same_then_else))] - if worked { - debug!("Session saved"); - } else { - debug!("Session not saved"); - } - } - - // Send our CCS and Finished. - self.transcript.add_message(&m); - if !self.resuming { - if self.send_ticket { - let now = self.config.current_time()?; - emit_ticket( - &self.secrets, - &mut self.transcript, - self.using_ems, - cx, - &*self.config.ticketer, - now, - )?; - } - emit_ccs(cx.common); - cx.common - .record_layer - .start_encrypting(); - emit_finished(&self.secrets, &mut self.transcript, cx.common); - } - - cx.common - .start_traffic(&mut cx.sendable_plaintext); - Ok(Box::new(ExpectTraffic { - secrets: self.secrets, - _fin_verified, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// --- Process traffic --- -struct ExpectTraffic { - secrets: ConnectionSecrets, - _fin_verified: verify::FinishedMessageVerified, -} - -impl ExpectTraffic {} - -impl State<ServerConnectionData> for ExpectTraffic { - fn handle<'m>( - self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::ApplicationData(payload) => cx - .common - .take_received_plaintext(payload), - payload => { - return Err(inappropriate_message( - &payload, - &[ContentType::ApplicationData], - )); - } - } - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.secrets - .export_keying_material(output, label, context); - Ok(()) - } - - fn extract_secrets(&self) -> Result<PartiallyExtractedSecrets, Error> { - self.secrets - .extract_secrets(Side::Server) - } - - fn into_external_state(self: Box<Self>) -> Result<Box<dyn KernelState + 'static>, Error> { - Ok(self) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -impl KernelState for ExpectTraffic { - fn update_secrets(&mut self, _: Direction) -> Result<ConnectionTrafficSecrets, Error> { - Err(Error::General( - "TLS 1.2 connections do not support traffic secret updates".into(), - )) - } - - fn handle_new_session_ticket( - &mut self, - _cx: &mut KernelContext<'_>, - _message: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error> { - unreachable!( - "server connections should never have handle_new_session_ticket called on them" - ) - } -} diff --git a/vendor/rustls/src/server/tls13.rs b/vendor/rustls/src/server/tls13.rs deleted file mode 100644 index b8b70e72..00000000 --- a/vendor/rustls/src/server/tls13.rs +++ /dev/null @@ -1,1535 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; - -pub(super) use client_hello::CompleteClientHelloHandling; -use pki_types::{CertificateDer, UnixTime}; -use subtle::ConstantTimeEq; - -use super::hs::{self, HandshakeHashOrBuffer, ServerContext}; -use super::server_conn::ServerConnectionData; -use crate::check::{inappropriate_handshake_message, inappropriate_message}; -use crate::common_state::{ - CommonState, HandshakeFlightTls13, HandshakeKind, Protocol, Side, State, -}; -use crate::conn::ConnectionRandoms; -use crate::conn::kernel::{Direction, KernelContext, KernelState}; -use crate::enums::{AlertDescription, ContentType, HandshakeType, ProtocolVersion}; -use crate::error::{Error, InvalidMessage, PeerIncompatible, PeerMisbehaved}; -use crate::hash_hs::HandshakeHash; -use crate::log::{debug, trace, warn}; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::enums::KeyUpdateRequest; -use crate::msgs::handshake::{ - CERTIFICATE_MAX_SIZE_LIMIT, CertificateChain, CertificatePayloadTls13, HandshakeMessagePayload, - HandshakePayload, NewSessionTicketPayloadTls13, -}; -use crate::msgs::message::{Message, MessagePayload}; -use crate::msgs::persist; -use crate::server::ServerConfig; -use crate::suites::PartiallyExtractedSecrets; -use crate::sync::Arc; -use crate::tls13::key_schedule::{ - KeyScheduleResumption, KeyScheduleTraffic, KeyScheduleTrafficWithClientFinishedPending, -}; -use crate::tls13::{ - Tls13CipherSuite, construct_client_verify_message, construct_server_verify_message, -}; -use crate::{ConnectionTrafficSecrets, compress, rand, verify}; - -mod client_hello { - use super::*; - use crate::compress::CertCompressor; - use crate::crypto::SupportedKxGroup; - use crate::enums::SignatureScheme; - use crate::msgs::base::{Payload, PayloadU8}; - use crate::msgs::ccs::ChangeCipherSpecPayload; - use crate::msgs::enums::{Compression, NamedGroup}; - use crate::msgs::handshake::{ - CertificatePayloadTls13, CertificateRequestExtensions, CertificateRequestPayloadTls13, - ClientHelloPayload, HelloRetryRequest, HelloRetryRequestExtensions, KeyShareEntry, Random, - ServerExtensions, ServerExtensionsInput, ServerHelloPayload, SessionId, - }; - use crate::server::common::ActiveCertifiedKey; - use crate::sign; - use crate::tls13::key_schedule::{ - KeyScheduleEarly, KeyScheduleHandshake, KeySchedulePreHandshake, - }; - use crate::verify::DigitallySignedStruct; - - #[derive(PartialEq)] - pub(super) enum EarlyDataDecision { - Disabled, - RequestedButRejected, - Accepted, - } - - pub(in crate::server) struct CompleteClientHelloHandling { - pub(in crate::server) config: Arc<ServerConfig>, - pub(in crate::server) transcript: HandshakeHash, - pub(in crate::server) suite: &'static Tls13CipherSuite, - pub(in crate::server) randoms: ConnectionRandoms, - pub(in crate::server) done_retry: bool, - pub(in crate::server) send_tickets: usize, - pub(in crate::server) extra_exts: ServerExtensionsInput<'static>, - } - - fn max_early_data_size(configured: u32) -> usize { - if configured != 0 { - configured as usize - } else { - // The relevant max_early_data_size may in fact be unknowable: if - // we (the server) have turned off early_data but the client has - // a stale ticket from when we allowed early_data: we'll naturally - // reject early_data but need an upper bound on the amount of data - // to drop. - // - // Use a single maximum-sized message. - 16384 - } - } - - impl CompleteClientHelloHandling { - fn check_binder( - &self, - suite: &'static Tls13CipherSuite, - client_hello: &Message<'_>, - psk: &[u8], - binder: &[u8], - ) -> bool { - let binder_plaintext = match &client_hello.payload { - MessagePayload::Handshake { parsed, encoded } => { - &encoded.bytes()[..encoded.bytes().len() - parsed.total_binder_length()] - } - _ => unreachable!(), - }; - - let handshake_hash = self - .transcript - .hash_given(binder_plaintext); - - let key_schedule = KeyScheduleEarly::new(suite, psk); - let real_binder = - key_schedule.resumption_psk_binder_key_and_sign_verify_data(&handshake_hash); - - ConstantTimeEq::ct_eq(real_binder.as_ref(), binder).into() - } - - fn attempt_tls13_ticket_decryption( - &mut self, - ticket: &[u8], - ) -> Option<persist::ServerSessionValue> { - if self.config.ticketer.enabled() { - self.config - .ticketer - .decrypt(ticket) - .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain).ok()) - } else { - self.config - .session_storage - .take(ticket) - .and_then(|plain| persist::ServerSessionValue::read_bytes(&plain).ok()) - } - } - - pub(in crate::server) fn handle_client_hello( - mut self, - cx: &mut ServerContext<'_>, - server_key: ActiveCertifiedKey<'_>, - chm: &Message<'_>, - client_hello: &ClientHelloPayload, - selected_kxg: &'static dyn SupportedKxGroup, - mut sigschemes_ext: Vec<SignatureScheme>, - ) -> hs::NextStateOrError<'static> { - if client_hello.compression_methods.len() != 1 { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::OfferedIncorrectCompressions, - )); - } - - sigschemes_ext.retain(SignatureScheme::supported_in_tls13); - - let shares_ext = client_hello - .key_shares - .as_ref() - .ok_or_else(|| { - cx.common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerIncompatible::KeyShareExtensionRequired, - ) - })?; - - if client_hello.has_keyshare_extension_with_duplicates() { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::OfferedDuplicateKeyShares, - )); - } - - if client_hello.has_certificate_compression_extension_with_duplicates() { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::OfferedDuplicateCertificateCompressions, - )); - } - - let cert_compressor = client_hello - .certificate_compression_algorithms - .as_ref() - .and_then(|offered| - // prefer server order when choosing a compression: the client's - // extension here does not denote any preference. - self.config - .cert_compressors - .iter() - .find(|compressor| offered.contains(&compressor.algorithm())) - .cloned()); - - let early_data_requested = client_hello - .early_data_request - .is_some(); - - // EarlyData extension is illegal in second ClientHello - if self.done_retry && early_data_requested { - return Err({ - cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::EarlyDataAttemptedInSecondClientHello, - ) - }); - } - - // See if there is a KeyShare for the selected kx group. - let chosen_share_and_kxg = shares_ext.iter().find_map(|share| { - (share.group == selected_kxg.name()).then_some((share, selected_kxg)) - }); - - let Some(chosen_share_and_kxg) = chosen_share_and_kxg else { - // We don't have a suitable key share. Send a HelloRetryRequest - // for the mutually_preferred_group. - self.transcript.add_message(chm); - - if self.done_retry { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::RefusedToFollowHelloRetryRequest, - )); - } - - emit_hello_retry_request( - &mut self.transcript, - self.suite, - client_hello.session_id, - cx.common, - selected_kxg.name(), - ); - emit_fake_ccs(cx.common); - - let skip_early_data = max_early_data_size(self.config.max_early_data_size); - - let next = Box::new(hs::ExpectClientHello { - config: self.config, - transcript: HandshakeHashOrBuffer::Hash(self.transcript), - #[cfg(feature = "tls12")] - session_id: SessionId::empty(), - #[cfg(feature = "tls12")] - using_ems: false, - done_retry: true, - send_tickets: self.send_tickets, - extra_exts: self.extra_exts, - }); - - return if early_data_requested { - Ok(Box::new(ExpectAndSkipRejectedEarlyData { - skip_data_left: skip_early_data, - next, - })) - } else { - Ok(next) - }; - }; - - let mut chosen_psk_index = None; - let mut resumedata = None; - - if let Some(psk_offer) = &client_hello.preshared_key_offer { - // "A client MUST provide a "psk_key_exchange_modes" extension if it - // offers a "pre_shared_key" extension. If clients offer - // "pre_shared_key" without a "psk_key_exchange_modes" extension, - // servers MUST abort the handshake." - RFC8446 4.2.9 - if client_hello - .preshared_key_modes - .is_none() - { - return Err(cx.common.send_fatal_alert( - AlertDescription::MissingExtension, - PeerMisbehaved::MissingPskModesExtension, - )); - } - - if psk_offer.binders.is_empty() { - return Err(cx.common.send_fatal_alert( - AlertDescription::DecodeError, - PeerMisbehaved::MissingBinderInPskExtension, - )); - } - - if psk_offer.binders.len() != psk_offer.identities.len() { - return Err(cx.common.send_fatal_alert( - AlertDescription::IllegalParameter, - PeerMisbehaved::PskExtensionWithMismatchedIdsAndBinders, - )); - } - - let now = self.config.current_time()?; - - for (i, psk_id) in psk_offer.identities.iter().enumerate() { - let maybe_resume_data = self - .attempt_tls13_ticket_decryption(&psk_id.identity.0) - .map(|resumedata| { - resumedata.set_freshness(psk_id.obfuscated_ticket_age, now) - }) - .filter(|resumedata| { - hs::can_resume(self.suite.into(), &cx.data.sni, false, resumedata) - }); - - let Some(resume) = maybe_resume_data else { - continue; - }; - - if !self.check_binder( - self.suite, - chm, - &resume.master_secret.0, - psk_offer.binders[i].as_ref(), - ) { - return Err(cx.common.send_fatal_alert( - AlertDescription::DecryptError, - PeerMisbehaved::IncorrectBinder, - )); - } - - chosen_psk_index = Some(i); - resumedata = Some(resume); - break; - } - } - - if !client_hello - .preshared_key_modes - .as_ref() - .map(|offer| offer.psk_dhe) - .unwrap_or_default() - { - debug!("Client unwilling to resume, PSK_DHE_KE not offered"); - self.send_tickets = 0; - chosen_psk_index = None; - resumedata = None; - } else { - self.send_tickets = self.config.send_tls13_tickets; - } - - if let Some(resume) = &resumedata { - cx.data.received_resumption_data = Some(resume.application_data.0.clone()); - cx.common - .peer_certificates - .clone_from(&resume.client_cert_chain); - } - - let full_handshake = resumedata.is_none(); - self.transcript.add_message(chm); - let key_schedule = emit_server_hello( - &mut self.transcript, - &self.randoms, - self.suite, - cx, - &client_hello.session_id, - chosen_share_and_kxg, - chosen_psk_index, - resumedata - .as_ref() - .map(|x| &x.master_secret.0[..]), - &self.config, - )?; - if !self.done_retry { - emit_fake_ccs(cx.common); - } - - if full_handshake { - cx.common - .handshake_kind - .get_or_insert(HandshakeKind::Full); - } else { - cx.common.handshake_kind = Some(HandshakeKind::Resumed); - } - - let mut ocsp_response = server_key.get_ocsp(); - let mut flight = HandshakeFlightTls13::new(&mut self.transcript); - let doing_early_data = emit_encrypted_extensions( - &mut flight, - self.suite, - cx, - &mut ocsp_response, - client_hello, - resumedata.as_ref(), - self.extra_exts, - &self.config, - )?; - - let doing_client_auth = if full_handshake { - let client_auth = emit_certificate_req_tls13(&mut flight, &self.config)?; - - if let Some(compressor) = cert_compressor { - emit_compressed_certificate_tls13( - &mut flight, - &self.config, - server_key.get_cert(), - ocsp_response, - compressor, - ); - } else { - emit_certificate_tls13(&mut flight, server_key.get_cert(), ocsp_response); - } - emit_certificate_verify_tls13( - &mut flight, - cx.common, - server_key.get_key(), - &sigschemes_ext, - )?; - client_auth - } else { - false - }; - - // If we're not doing early data, then the next messages we receive - // are encrypted with the handshake keys. - match doing_early_data { - EarlyDataDecision::Disabled => { - key_schedule.set_handshake_decrypter(None, cx.common); - cx.data.early_data.reject(); - } - EarlyDataDecision::RequestedButRejected => { - debug!( - "Client requested early_data, but not accepted: switching to handshake keys with trial decryption" - ); - key_schedule.set_handshake_decrypter( - Some(max_early_data_size(self.config.max_early_data_size)), - cx.common, - ); - cx.data.early_data.reject(); - } - EarlyDataDecision::Accepted => { - cx.data - .early_data - .accept(self.config.max_early_data_size as usize); - } - } - - cx.common.check_aligned_handshake()?; - let key_schedule_traffic = - emit_finished_tls13(flight, &self.randoms, cx, key_schedule, &self.config); - - if !doing_client_auth && self.config.send_half_rtt_data { - // Application data can be sent immediately after Finished, in one - // flight. However, if client auth is enabled, we don't want to send - // application data to an unauthenticated peer. - cx.common - .start_outgoing_traffic(&mut cx.sendable_plaintext); - } - - if doing_client_auth { - if self - .config - .cert_decompressors - .is_empty() - { - Ok(Box::new(ExpectCertificate { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: key_schedule_traffic, - send_tickets: self.send_tickets, - message_already_in_transcript: false, - })) - } else { - Ok(Box::new(ExpectCertificateOrCompressedCertificate { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: key_schedule_traffic, - send_tickets: self.send_tickets, - })) - } - } else if doing_early_data == EarlyDataDecision::Accepted && !cx.common.is_quic() { - // Not used for QUIC: RFC 9001 §8.3: Clients MUST NOT send the EndOfEarlyData - // message. A server MUST treat receipt of a CRYPTO frame in a 0-RTT packet as a - // connection error of type PROTOCOL_VIOLATION. - Ok(Box::new(ExpectEarlyData { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: key_schedule_traffic, - send_tickets: self.send_tickets, - })) - } else { - Ok(Box::new(ExpectFinished { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: key_schedule_traffic, - send_tickets: self.send_tickets, - })) - } - } - } - - fn emit_server_hello( - transcript: &mut HandshakeHash, - randoms: &ConnectionRandoms, - suite: &'static Tls13CipherSuite, - cx: &mut ServerContext<'_>, - session_id: &SessionId, - share_and_kxgroup: (&KeyShareEntry, &'static dyn SupportedKxGroup), - chosen_psk_idx: Option<usize>, - resuming_psk: Option<&[u8]>, - config: &ServerConfig, - ) -> Result<KeyScheduleHandshake, Error> { - // Prepare key exchange; the caller already found the matching SupportedKxGroup - let (share, kxgroup) = share_and_kxgroup; - debug_assert_eq!(kxgroup.name(), share.group); - let ckx = kxgroup - .start_and_complete(&share.payload.0) - .map_err(|err| { - cx.common - .send_fatal_alert(AlertDescription::IllegalParameter, err) - })?; - cx.common.kx_state.complete(); - - let extensions = Box::new(ServerExtensions { - key_share: Some(KeyShareEntry::new(ckx.group, ckx.pub_key)), - selected_version: Some(ProtocolVersion::TLSv1_3), - preshared_key: chosen_psk_idx.map(|idx| idx as u16), - ..Default::default() - }); - - let sh = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::ServerHello(ServerHelloPayload { - legacy_version: ProtocolVersion::TLSv1_2, - random: Random::from(randoms.server), - session_id: *session_id, - cipher_suite: suite.common.suite, - compression_method: Compression::Null, - extensions, - }), - )), - }; - - cx.common.check_aligned_handshake()?; - - let client_hello_hash = transcript.hash_given(&[]); - - trace!("sending server hello {sh:?}"); - transcript.add_message(&sh); - cx.common.send_msg(sh, false); - - // Start key schedule - let key_schedule_pre_handshake = if let Some(psk) = resuming_psk { - let early_key_schedule = KeyScheduleEarly::new(suite, psk); - early_key_schedule.client_early_traffic_secret( - &client_hello_hash, - &*config.key_log, - &randoms.client, - cx.common, - ); - - KeySchedulePreHandshake::from(early_key_schedule) - } else { - KeySchedulePreHandshake::new(suite) - }; - - // Do key exchange - let key_schedule = key_schedule_pre_handshake.into_handshake(ckx.secret); - - let handshake_hash = transcript.current_hash(); - let key_schedule = key_schedule.derive_server_handshake_secrets( - handshake_hash, - &*config.key_log, - &randoms.client, - cx.common, - ); - - Ok(key_schedule) - } - - fn emit_fake_ccs(common: &mut CommonState) { - if common.is_quic() { - return; - } - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::ChangeCipherSpec(ChangeCipherSpecPayload {}), - }; - common.send_msg(m, false); - } - - fn emit_hello_retry_request( - transcript: &mut HandshakeHash, - suite: &'static Tls13CipherSuite, - session_id: SessionId, - common: &mut CommonState, - group: NamedGroup, - ) { - let req = HelloRetryRequest { - legacy_version: ProtocolVersion::TLSv1_2, - session_id, - cipher_suite: suite.common.suite, - extensions: HelloRetryRequestExtensions { - key_share: Some(group), - supported_versions: Some(ProtocolVersion::TLSv1_3), - ..Default::default() - }, - }; - - let m = Message { - version: ProtocolVersion::TLSv1_2, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::HelloRetryRequest(req), - )), - }; - - trace!("Requesting retry {m:?}"); - transcript.rollup_for_hrr(); - transcript.add_message(&m); - common.send_msg(m, false); - common.handshake_kind = Some(HandshakeKind::FullWithHelloRetryRequest); - } - - fn decide_if_early_data_allowed( - cx: &mut ServerContext<'_>, - client_hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>, - suite: &'static Tls13CipherSuite, - config: &ServerConfig, - ) -> EarlyDataDecision { - let early_data_requested = client_hello - .early_data_request - .is_some(); - let rejected_or_disabled = match early_data_requested { - true => EarlyDataDecision::RequestedButRejected, - false => EarlyDataDecision::Disabled, - }; - - let Some(resume) = resumedata else { - // never any early data if not resuming. - return rejected_or_disabled; - }; - - /* Non-zero max_early_data_size controls whether early_data is allowed at all. - * We also require stateful resumption. */ - let early_data_configured = config.max_early_data_size > 0 && !config.ticketer.enabled(); - - /* "For PSKs provisioned via NewSessionTicket, a server MUST validate - * that the ticket age for the selected PSK identity (computed by - * subtracting ticket_age_add from PskIdentity.obfuscated_ticket_age - * modulo 2^32) is within a small tolerance of the time since the ticket - * was issued (see Section 8)." -- this is implemented in ServerSessionValue::set_freshness() - * and related. - * - * "In order to accept early data, the server [...] MUST verify that the - * following values are the same as those associated with the - * selected PSK: - * - * - The TLS version number - * - The selected cipher suite - * - The selected ALPN [RFC7301] protocol, if any" - * - * (RFC8446, 4.2.10) */ - let early_data_possible = early_data_requested - && resume.is_fresh() - && Some(resume.version) == cx.common.negotiated_version - && resume.cipher_suite == suite.common.suite - && resume.alpn.as_ref().map(|p| &p.0[..]) == cx.common.alpn_protocol.as_deref(); - - if early_data_configured && early_data_possible && !cx.data.early_data.was_rejected() { - EarlyDataDecision::Accepted - } else { - if cx.common.is_quic() { - // Clobber value set in tls13::emit_server_hello - cx.common.quic.early_secret = None; - } - - rejected_or_disabled - } - } - - fn emit_encrypted_extensions( - flight: &mut HandshakeFlightTls13<'_>, - suite: &'static Tls13CipherSuite, - cx: &mut ServerContext<'_>, - ocsp_response: &mut Option<&[u8]>, - hello: &ClientHelloPayload, - resumedata: Option<&persist::ServerSessionValue>, - extra_exts: ServerExtensionsInput<'static>, - config: &ServerConfig, - ) -> Result<EarlyDataDecision, Error> { - let mut ep = hs::ExtensionProcessing::new(extra_exts); - ep.process_common(config, cx, ocsp_response, hello, resumedata)?; - - let early_data = decide_if_early_data_allowed(cx, hello, resumedata, suite, config); - if early_data == EarlyDataDecision::Accepted { - ep.extensions.early_data_ack = Some(()); - } - - let ee = HandshakeMessagePayload(HandshakePayload::EncryptedExtensions(ep.extensions)); - - trace!("sending encrypted extensions {ee:?}"); - flight.add(ee); - Ok(early_data) - } - - fn emit_certificate_req_tls13( - flight: &mut HandshakeFlightTls13<'_>, - config: &ServerConfig, - ) -> Result<bool, Error> { - if !config.verifier.offer_client_auth() { - return Ok(false); - } - - let cr = CertificateRequestPayloadTls13 { - context: PayloadU8::empty(), - extensions: CertificateRequestExtensions { - signature_algorithms: Some( - config - .verifier - .supported_verify_schemes(), - ), - certificate_compression_algorithms: match config.cert_decompressors.as_slice() { - &[] => None, - decomps => Some( - decomps - .iter() - .map(|decomp| decomp.algorithm()) - .collect(), - ), - }, - authority_names: match config.verifier.root_hint_subjects() { - &[] => None, - authorities => Some(authorities.to_vec()), - }, - }, - }; - - let creq = HandshakeMessagePayload(HandshakePayload::CertificateRequestTls13(cr)); - - trace!("Sending CertificateRequest {creq:?}"); - flight.add(creq); - Ok(true) - } - - fn emit_certificate_tls13( - flight: &mut HandshakeFlightTls13<'_>, - cert_chain: &[CertificateDer<'static>], - ocsp_response: Option<&[u8]>, - ) { - let cert = HandshakeMessagePayload(HandshakePayload::CertificateTls13( - CertificatePayloadTls13::new(cert_chain.iter(), ocsp_response), - )); - - trace!("sending certificate {cert:?}"); - flight.add(cert); - } - - fn emit_compressed_certificate_tls13( - flight: &mut HandshakeFlightTls13<'_>, - config: &ServerConfig, - cert_chain: &[CertificateDer<'static>], - ocsp_response: Option<&[u8]>, - cert_compressor: &'static dyn CertCompressor, - ) { - let payload = CertificatePayloadTls13::new(cert_chain.iter(), ocsp_response); - - let Ok(entry) = config - .cert_compression_cache - .compression_for(cert_compressor, &payload) - else { - return emit_certificate_tls13(flight, cert_chain, ocsp_response); - }; - - let c = HandshakeMessagePayload(HandshakePayload::CompressedCertificate( - entry.compressed_cert_payload(), - )); - - trace!("sending compressed certificate {c:?}"); - flight.add(c); - } - - fn emit_certificate_verify_tls13( - flight: &mut HandshakeFlightTls13<'_>, - common: &mut CommonState, - signing_key: &dyn sign::SigningKey, - schemes: &[SignatureScheme], - ) -> Result<(), Error> { - let message = construct_server_verify_message(&flight.transcript.current_hash()); - - let signer = signing_key - .choose_scheme(schemes) - .ok_or_else(|| { - common.send_fatal_alert( - AlertDescription::HandshakeFailure, - PeerIncompatible::NoSignatureSchemesInCommon, - ) - })?; - - let scheme = signer.scheme(); - let sig = signer.sign(message.as_ref())?; - - let cv = DigitallySignedStruct::new(scheme, sig); - - let cv = HandshakeMessagePayload(HandshakePayload::CertificateVerify(cv)); - - trace!("sending certificate-verify {cv:?}"); - flight.add(cv); - Ok(()) - } - - fn emit_finished_tls13( - mut flight: HandshakeFlightTls13<'_>, - randoms: &ConnectionRandoms, - cx: &mut ServerContext<'_>, - key_schedule: KeyScheduleHandshake, - config: &ServerConfig, - ) -> KeyScheduleTrafficWithClientFinishedPending { - let handshake_hash = flight.transcript.current_hash(); - let verify_data = key_schedule.sign_server_finish(&handshake_hash); - let verify_data_payload = Payload::new(verify_data.as_ref()); - - let fin = HandshakeMessagePayload(HandshakePayload::Finished(verify_data_payload)); - - trace!("sending finished {fin:?}"); - flight.add(fin); - let hash_at_server_fin = flight.transcript.current_hash(); - flight.finish(cx.common); - - // Now move to application data keys. Read key change is deferred until - // the Finish message is received & validated. - key_schedule.into_traffic_with_client_finished_pending( - hash_at_server_fin, - &*config.key_log, - &randoms.client, - cx.common, - ) - } -} - -struct ExpectAndSkipRejectedEarlyData { - skip_data_left: usize, - next: Box<hs::ExpectClientHello>, -} - -impl State<ServerConnectionData> for ExpectAndSkipRejectedEarlyData { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - /* "The server then ignores early data by skipping all records with an external - * content type of "application_data" (indicating that they are encrypted), - * up to the configured max_early_data_size." - * (RFC8446, 14.2.10) */ - if let MessagePayload::ApplicationData(skip_data) = &m.payload { - if skip_data.bytes().len() <= self.skip_data_left { - self.skip_data_left -= skip_data.bytes().len(); - return Ok(self); - } - } - - self.next.handle(cx, m) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCertificateOrCompressedCertificate { - config: Arc<ServerConfig>, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - send_tickets: usize, -} - -impl State<ServerConnectionData> for ExpectCertificateOrCompressedCertificate { - fn handle<'m>( - self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CertificateTls13(..)), - .. - } => Box::new(ExpectCertificate { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: self.key_schedule, - send_tickets: self.send_tickets, - message_already_in_transcript: false, - }) - .handle(cx, m), - - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::CompressedCertificate(..)), - .. - } => Box::new(ExpectCompressedCertificate { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: self.key_schedule, - send_tickets: self.send_tickets, - }) - .handle(cx, m), - - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::Handshake], - &[ - HandshakeType::Certificate, - HandshakeType::CompressedCertificate, - ], - )), - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCompressedCertificate { - config: Arc<ServerConfig>, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - send_tickets: usize, -} - -impl State<ServerConnectionData> for ExpectCompressedCertificate { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - self.transcript.add_message(&m); - let compressed_cert = require_handshake_msg_move!( - m, - HandshakeType::CompressedCertificate, - HandshakePayload::CompressedCertificate - )?; - - let selected_decompressor = self - .config - .cert_decompressors - .iter() - .find(|item| item.algorithm() == compressed_cert.alg); - - let Some(decompressor) = selected_decompressor else { - return Err(cx.common.send_fatal_alert( - AlertDescription::BadCertificate, - PeerMisbehaved::SelectedUnofferedCertCompression, - )); - }; - - if compressed_cert.uncompressed_len as usize > CERTIFICATE_MAX_SIZE_LIMIT { - return Err(cx.common.send_fatal_alert( - AlertDescription::BadCertificate, - InvalidMessage::MessageTooLarge, - )); - } - - let mut decompress_buffer = vec![0u8; compressed_cert.uncompressed_len as usize]; - if let Err(compress::DecompressionFailed) = - decompressor.decompress(compressed_cert.compressed.0.bytes(), &mut decompress_buffer) - { - return Err(cx.common.send_fatal_alert( - AlertDescription::BadCertificate, - PeerMisbehaved::InvalidCertCompression, - )); - } - - let cert_payload = - match CertificatePayloadTls13::read(&mut Reader::init(&decompress_buffer)) { - Ok(cm) => cm, - Err(err) => { - return Err(cx - .common - .send_fatal_alert(AlertDescription::BadCertificate, err)); - } - }; - trace!( - "Client certificate decompressed using {:?} ({} bytes -> {})", - compressed_cert.alg, - compressed_cert - .compressed - .0 - .bytes() - .len(), - compressed_cert.uncompressed_len, - ); - - let m = Message { - version: ProtocolVersion::TLSv1_3, - payload: MessagePayload::handshake(HandshakeMessagePayload( - HandshakePayload::CertificateTls13(cert_payload.into_owned()), - )), - }; - - Box::new(ExpectCertificate { - config: self.config, - transcript: self.transcript, - suite: self.suite, - key_schedule: self.key_schedule, - send_tickets: self.send_tickets, - message_already_in_transcript: true, - }) - .handle(cx, m) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCertificate { - config: Arc<ServerConfig>, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - send_tickets: usize, - message_already_in_transcript: bool, -} - -impl State<ServerConnectionData> for ExpectCertificate { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - if !self.message_already_in_transcript { - self.transcript.add_message(&m); - } - let certp = require_handshake_msg_move!( - m, - HandshakeType::Certificate, - HandshakePayload::CertificateTls13 - )?; - - // We don't send any CertificateRequest extensions, so any extensions - // here are illegal. - if certp - .entries - .iter() - .any(|e| !e.extensions.only_contains(&[])) - { - return Err(PeerMisbehaved::UnsolicitedCertExtension.into()); - } - - let client_cert = certp.into_certificate_chain(); - - let mandatory = self - .config - .verifier - .client_auth_mandatory(); - - let Some((end_entity, intermediates)) = client_cert.split_first() else { - if !mandatory { - debug!("client auth requested but no certificate supplied"); - self.transcript.abandon_client_auth(); - return Ok(Box::new(ExpectFinished { - config: self.config, - suite: self.suite, - key_schedule: self.key_schedule, - transcript: self.transcript, - send_tickets: self.send_tickets, - })); - } - - return Err(cx.common.send_fatal_alert( - AlertDescription::CertificateRequired, - Error::NoCertificatesPresented, - )); - }; - - let now = self.config.current_time()?; - - self.config - .verifier - .verify_client_cert(end_entity, intermediates, now) - .map_err(|err| { - cx.common - .send_cert_verify_error_alert(err) - })?; - - Ok(Box::new(ExpectCertificateVerify { - config: self.config, - suite: self.suite, - transcript: self.transcript, - key_schedule: self.key_schedule, - client_cert: client_cert.into_owned(), - send_tickets: self.send_tickets, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -struct ExpectCertificateVerify { - config: Arc<ServerConfig>, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - client_cert: CertificateChain<'static>, - send_tickets: usize, -} - -impl State<ServerConnectionData> for ExpectCertificateVerify { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let rc = { - let sig = require_handshake_msg!( - m, - HandshakeType::CertificateVerify, - HandshakePayload::CertificateVerify - )?; - let handshake_hash = self.transcript.current_hash(); - self.transcript.abandon_client_auth(); - let certs = &self.client_cert; - let msg = construct_client_verify_message(&handshake_hash); - - self.config - .verifier - .verify_tls13_signature(msg.as_ref(), &certs[0], sig) - }; - - if let Err(e) = rc { - return Err(cx - .common - .send_cert_verify_error_alert(e)); - } - - trace!("client CertificateVerify OK"); - cx.common.peer_certificates = Some(self.client_cert); - - self.transcript.add_message(&m); - Ok(Box::new(ExpectFinished { - config: self.config, - suite: self.suite, - key_schedule: self.key_schedule, - transcript: self.transcript, - send_tickets: self.send_tickets, - })) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// --- Process (any number of) early ApplicationData messages, -// followed by a terminating handshake EndOfEarlyData message --- - -struct ExpectEarlyData { - config: Arc<ServerConfig>, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - send_tickets: usize, -} - -impl State<ServerConnectionData> for ExpectEarlyData { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::ApplicationData(payload) => { - match cx - .data - .early_data - .take_received_plaintext(payload) - { - true => Ok(self), - false => Err(cx.common.send_fatal_alert( - AlertDescription::UnexpectedMessage, - PeerMisbehaved::TooMuchEarlyDataReceived, - )), - } - } - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::EndOfEarlyData), - .. - } => { - self.key_schedule - .update_decrypter(cx.common); - self.transcript.add_message(&m); - Ok(Box::new(ExpectFinished { - config: self.config, - suite: self.suite, - key_schedule: self.key_schedule, - transcript: self.transcript, - send_tickets: self.send_tickets, - })) - } - payload => Err(inappropriate_handshake_message( - &payload, - &[ContentType::ApplicationData, ContentType::Handshake], - &[HandshakeType::EndOfEarlyData], - )), - } - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// --- Process client's Finished --- -fn get_server_session_value( - suite: &'static Tls13CipherSuite, - resumption: &KeyScheduleResumption, - cx: &ServerContext<'_>, - nonce: &[u8], - time_now: UnixTime, - age_obfuscation_offset: u32, -) -> persist::ServerSessionValue { - let version = ProtocolVersion::TLSv1_3; - - let secret = resumption.derive_ticket_psk(nonce); - - persist::ServerSessionValue::new( - cx.data.sni.as_ref(), - version, - suite.common.suite, - secret.as_ref(), - cx.common.peer_certificates.clone(), - cx.common.alpn_protocol.clone(), - cx.data.resumption_data.clone(), - time_now, - age_obfuscation_offset, - ) -} - -struct ExpectFinished { - config: Arc<ServerConfig>, - transcript: HandshakeHash, - suite: &'static Tls13CipherSuite, - key_schedule: KeyScheduleTrafficWithClientFinishedPending, - send_tickets: usize, -} - -impl ExpectFinished { - fn emit_ticket( - flight: &mut HandshakeFlightTls13<'_>, - suite: &'static Tls13CipherSuite, - cx: &ServerContext<'_>, - resumption: &KeyScheduleResumption, - config: &ServerConfig, - ) -> Result<(), Error> { - let secure_random = config.provider.secure_random; - let nonce = rand::random_vec(secure_random, 32)?; - let age_add = rand::random_u32(secure_random)?; - - let now = config.current_time()?; - - let plain = - get_server_session_value(suite, resumption, cx, &nonce, now, age_add).get_encoding(); - - let stateless = config.ticketer.enabled(); - let (ticket, lifetime) = if stateless { - let Some(ticket) = config.ticketer.encrypt(&plain) else { - return Ok(()); - }; - (ticket, config.ticketer.lifetime()) - } else { - let id = rand::random_vec(secure_random, 32)?; - let stored = config - .session_storage - .put(id.clone(), plain); - if !stored { - trace!("resumption not available; not issuing ticket"); - return Ok(()); - } - let stateful_lifetime = 24 * 60 * 60; // this is a bit of a punt - (id, stateful_lifetime) - }; - - let mut payload = NewSessionTicketPayloadTls13::new(lifetime, age_add, nonce, ticket); - - if config.max_early_data_size > 0 { - if !stateless { - payload.extensions.max_early_data_size = Some(config.max_early_data_size); - } else { - // We implement RFC8446 section 8.1: by enforcing that 0-RTT is - // only possible if using stateful resumption - warn!("early_data with stateless resumption is not allowed"); - } - } - - let t = HandshakeMessagePayload(HandshakePayload::NewSessionTicketTls13(payload)); - trace!("sending new ticket {t:?} (stateless: {stateless})"); - flight.add(t); - - Ok(()) - } -} - -impl State<ServerConnectionData> for ExpectFinished { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - let finished = - require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; - - let handshake_hash = self.transcript.current_hash(); - let (key_schedule_before_finished, expect_verify_data) = self - .key_schedule - .sign_client_finish(&handshake_hash, cx.common); - - let fin = match ConstantTimeEq::ct_eq(expect_verify_data.as_ref(), finished.bytes()).into() - { - true => verify::FinishedMessageVerified::assertion(), - false => { - return Err(cx - .common - .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError)); - } - }; - - // Note: future derivations include Client Finished, but not the - // main application data keying. - self.transcript.add_message(&m); - - cx.common.check_aligned_handshake()?; - - let (key_schedule_traffic, resumption) = - key_schedule_before_finished.into_traffic(self.transcript.current_hash()); - - let mut flight = HandshakeFlightTls13::new(&mut self.transcript); - for _ in 0..self.send_tickets { - Self::emit_ticket(&mut flight, self.suite, cx, &resumption, &self.config)?; - } - flight.finish(cx.common); - - // Application data may now flow, even if we have client auth enabled. - cx.common - .start_traffic(&mut cx.sendable_plaintext); - - Ok(match cx.common.is_quic() { - true => Box::new(ExpectQuicTraffic { - key_schedule: key_schedule_traffic, - _fin_verified: fin, - }), - false => Box::new(ExpectTraffic { - key_schedule: key_schedule_traffic, - _fin_verified: fin, - }), - }) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -// --- Process traffic --- -struct ExpectTraffic { - key_schedule: KeyScheduleTraffic, - _fin_verified: verify::FinishedMessageVerified, -} - -impl ExpectTraffic { - fn handle_key_update( - &mut self, - common: &mut CommonState, - key_update_request: &KeyUpdateRequest, - ) -> Result<(), Error> { - if let Protocol::Quic = common.protocol { - return Err(common.send_fatal_alert( - AlertDescription::UnexpectedMessage, - PeerMisbehaved::KeyUpdateReceivedInQuicConnection, - )); - } - - common.check_aligned_handshake()?; - - if common.should_update_key(key_update_request)? { - self.key_schedule - .update_encrypter_and_notify(common); - } - - // Update our read-side keys. - self.key_schedule - .update_decrypter(common); - Ok(()) - } -} - -impl State<ServerConnectionData> for ExpectTraffic { - fn handle<'m>( - mut self: Box<Self>, - cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - match m.payload { - MessagePayload::ApplicationData(payload) => cx - .common - .take_received_plaintext(payload), - MessagePayload::Handshake { - parsed: HandshakeMessagePayload(HandshakePayload::KeyUpdate(key_update)), - .. - } => self.handle_key_update(cx.common, &key_update)?, - payload => { - return Err(inappropriate_handshake_message( - &payload, - &[ContentType::ApplicationData, ContentType::Handshake], - &[HandshakeType::KeyUpdate], - )); - } - } - - Ok(self) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.key_schedule - .export_keying_material(output, label, context) - } - - fn extract_secrets(&self) -> Result<PartiallyExtractedSecrets, Error> { - self.key_schedule - .extract_secrets(Side::Server) - } - - fn send_key_update_request(&mut self, common: &mut CommonState) -> Result<(), Error> { - self.key_schedule - .request_key_update_and_update_encrypter(common) - } - - fn into_external_state(self: Box<Self>) -> Result<Box<dyn KernelState + 'static>, Error> { - Ok(self) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -impl KernelState for ExpectTraffic { - fn update_secrets(&mut self, dir: Direction) -> Result<ConnectionTrafficSecrets, Error> { - self.key_schedule - .refresh_traffic_secret(match dir { - Direction::Transmit => Side::Server, - Direction::Receive => Side::Client, - }) - } - - fn handle_new_session_ticket( - &mut self, - _cx: &mut KernelContext<'_>, - _message: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error> { - unreachable!( - "server connections should never have handle_new_session_ticket called on them" - ) - } -} - -struct ExpectQuicTraffic { - key_schedule: KeyScheduleTraffic, - _fin_verified: verify::FinishedMessageVerified, -} - -impl State<ServerConnectionData> for ExpectQuicTraffic { - fn handle<'m>( - self: Box<Self>, - _cx: &mut ServerContext<'_>, - m: Message<'m>, - ) -> hs::NextStateOrError<'m> - where - Self: 'm, - { - // reject all messages - Err(inappropriate_message(&m.payload, &[])) - } - - fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.key_schedule - .export_keying_material(output, label, context) - } - - fn into_owned(self: Box<Self>) -> hs::NextState<'static> { - self - } -} - -impl KernelState for ExpectQuicTraffic { - fn update_secrets(&mut self, _: Direction) -> Result<ConnectionTrafficSecrets, Error> { - Err(Error::General( - "QUIC connections do not support key updates".into(), - )) - } - - fn handle_new_session_ticket( - &mut self, - _cx: &mut KernelContext<'_>, - _message: &NewSessionTicketPayloadTls13, - ) -> Result<(), Error> { - unreachable!("handle_new_session_ticket should not be called for server-side connections") - } -} diff --git a/vendor/rustls/src/stream.rs b/vendor/rustls/src/stream.rs deleted file mode 100644 index d92d05e3..00000000 --- a/vendor/rustls/src/stream.rs +++ /dev/null @@ -1,282 +0,0 @@ -use core::ops::{Deref, DerefMut}; -use std::io::{BufRead, IoSlice, Read, Result, Write}; - -use crate::conn::{ConnectionCommon, SideData}; - -/// This type implements `io::Read` and `io::Write`, encapsulating -/// a Connection `C` and an underlying transport `T`, such as a socket. -/// -/// This allows you to use a rustls Connection like a normal stream. -#[derive(Debug)] -pub struct Stream<'a, C: 'a + ?Sized, T: 'a + Read + Write + ?Sized> { - /// Our TLS connection - pub conn: &'a mut C, - - /// The underlying transport, like a socket - pub sock: &'a mut T, -} - -impl<'a, C, T, S> Stream<'a, C, T> -where - C: 'a + DerefMut + Deref<Target = ConnectionCommon<S>>, - T: 'a + Read + Write, - S: SideData, -{ - /// Make a new Stream using the Connection `conn` and socket-like object - /// `sock`. This does not fail and does no IO. - pub fn new(conn: &'a mut C, sock: &'a mut T) -> Self { - Self { conn, sock } - } - - /// If we're handshaking, complete all the IO for that. - /// If we have data to write, write it all. - fn complete_prior_io(&mut self) -> Result<()> { - if self.conn.is_handshaking() { - self.conn.complete_io(self.sock)?; - } - - if self.conn.wants_write() { - self.conn.complete_io(self.sock)?; - } - - Ok(()) - } - - fn prepare_read(&mut self) -> Result<()> { - self.complete_prior_io()?; - - // We call complete_io() in a loop since a single call may read only - // a partial packet from the underlying transport. A full packet is - // needed to get more plaintext, which we must do if EOF has not been - // hit. - while self.conn.wants_read() { - if self.conn.complete_io(self.sock)?.0 == 0 { - break; - } - } - - Ok(()) - } - - // Implements `BufRead::fill_buf` but with more flexible lifetimes, so StreamOwned can reuse it - fn fill_buf(mut self) -> Result<&'a [u8]> - where - S: 'a, - { - self.prepare_read()?; - self.conn.reader().into_first_chunk() - } -} - -impl<'a, C, T, S> Read for Stream<'a, C, T> -where - C: 'a + DerefMut + Deref<Target = ConnectionCommon<S>>, - T: 'a + Read + Write, - S: SideData, -{ - fn read(&mut self, buf: &mut [u8]) -> Result<usize> { - self.prepare_read()?; - self.conn.reader().read(buf) - } - - #[cfg(read_buf)] - fn read_buf(&mut self, cursor: core::io::BorrowedCursor<'_>) -> Result<()> { - self.prepare_read()?; - self.conn.reader().read_buf(cursor) - } -} - -impl<'a, C, T, S> BufRead for Stream<'a, C, T> -where - C: 'a + DerefMut + Deref<Target = ConnectionCommon<S>>, - T: 'a + Read + Write, - S: 'a + SideData, -{ - fn fill_buf(&mut self) -> Result<&[u8]> { - // reborrow to get an owned `Stream` - Stream { - conn: self.conn, - sock: self.sock, - } - .fill_buf() - } - - fn consume(&mut self, amt: usize) { - self.conn.reader().consume(amt) - } -} - -impl<'a, C, T, S> Write for Stream<'a, C, T> -where - C: 'a + DerefMut + Deref<Target = ConnectionCommon<S>>, - T: 'a + Read + Write, - S: SideData, -{ - fn write(&mut self, buf: &[u8]) -> Result<usize> { - self.complete_prior_io()?; - - let len = self.conn.writer().write(buf)?; - - // Try to write the underlying transport here, but don't let - // any errors mask the fact we've consumed `len` bytes. - // Callers will learn of permanent errors on the next call. - let _ = self.conn.complete_io(self.sock); - - Ok(len) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> Result<usize> { - self.complete_prior_io()?; - - let len = self - .conn - .writer() - .write_vectored(bufs)?; - - // Try to write the underlying transport here, but don't let - // any errors mask the fact we've consumed `len` bytes. - // Callers will learn of permanent errors on the next call. - let _ = self.conn.complete_io(self.sock); - - Ok(len) - } - - fn flush(&mut self) -> Result<()> { - self.complete_prior_io()?; - - self.conn.writer().flush()?; - if self.conn.wants_write() { - self.conn.complete_io(self.sock)?; - } - Ok(()) - } -} - -/// This type implements `io::Read` and `io::Write`, encapsulating -/// and owning a Connection `C` and an underlying blocking transport -/// `T`, such as a socket. -/// -/// This allows you to use a rustls Connection like a normal stream. -#[derive(Debug)] -pub struct StreamOwned<C: Sized, T: Read + Write + Sized> { - /// Our connection - pub conn: C, - - /// The underlying transport, like a socket - pub sock: T, -} - -impl<C, T, S> StreamOwned<C, T> -where - C: DerefMut + Deref<Target = ConnectionCommon<S>>, - T: Read + Write, - S: SideData, -{ - /// Make a new StreamOwned taking the Connection `conn` and socket-like - /// object `sock`. This does not fail and does no IO. - /// - /// This is the same as `Stream::new` except `conn` and `sock` are - /// moved into the StreamOwned. - pub fn new(conn: C, sock: T) -> Self { - Self { conn, sock } - } - - /// Get a reference to the underlying socket - pub fn get_ref(&self) -> &T { - &self.sock - } - - /// Get a mutable reference to the underlying socket - pub fn get_mut(&mut self) -> &mut T { - &mut self.sock - } - - /// Extract the `conn` and `sock` parts from the `StreamOwned` - pub fn into_parts(self) -> (C, T) { - (self.conn, self.sock) - } -} - -impl<'a, C, T, S> StreamOwned<C, T> -where - C: DerefMut + Deref<Target = ConnectionCommon<S>>, - T: Read + Write, - S: SideData, -{ - fn as_stream(&'a mut self) -> Stream<'a, C, T> { - Stream { - conn: &mut self.conn, - sock: &mut self.sock, - } - } -} - -impl<C, T, S> Read for StreamOwned<C, T> -where - C: DerefMut + Deref<Target = ConnectionCommon<S>>, - T: Read + Write, - S: SideData, -{ - fn read(&mut self, buf: &mut [u8]) -> Result<usize> { - self.as_stream().read(buf) - } - - #[cfg(read_buf)] - fn read_buf(&mut self, cursor: core::io::BorrowedCursor<'_>) -> Result<()> { - self.as_stream().read_buf(cursor) - } -} - -impl<C, T, S> BufRead for StreamOwned<C, T> -where - C: DerefMut + Deref<Target = ConnectionCommon<S>>, - T: Read + Write, - S: 'static + SideData, -{ - fn fill_buf(&mut self) -> Result<&[u8]> { - self.as_stream().fill_buf() - } - - fn consume(&mut self, amt: usize) { - self.as_stream().consume(amt) - } -} - -impl<C, T, S> Write for StreamOwned<C, T> -where - C: DerefMut + Deref<Target = ConnectionCommon<S>>, - T: Read + Write, - S: SideData, -{ - fn write(&mut self, buf: &[u8]) -> Result<usize> { - self.as_stream().write(buf) - } - - fn flush(&mut self) -> Result<()> { - self.as_stream().flush() - } -} - -#[cfg(test)] -mod tests { - use std::net::TcpStream; - - use super::{Stream, StreamOwned}; - use crate::client::ClientConnection; - use crate::server::ServerConnection; - - #[test] - fn stream_can_be_created_for_connection_and_tcpstream() { - type _Test<'a> = Stream<'a, ClientConnection, TcpStream>; - } - - #[test] - fn streamowned_can_be_created_for_client_and_tcpstream() { - type _Test = StreamOwned<ClientConnection, TcpStream>; - } - - #[test] - fn streamowned_can_be_created_for_server_and_tcpstream() { - type _Test = StreamOwned<ServerConnection, TcpStream>; - } -} diff --git a/vendor/rustls/src/suites.rs b/vendor/rustls/src/suites.rs deleted file mode 100644 index c40b88df..00000000 --- a/vendor/rustls/src/suites.rs +++ /dev/null @@ -1,272 +0,0 @@ -use core::fmt; - -use crate::common_state::Protocol; -use crate::crypto::cipher::{AeadKey, Iv}; -use crate::crypto::{self, KeyExchangeAlgorithm}; -use crate::enums::{CipherSuite, SignatureAlgorithm, SignatureScheme}; -use crate::msgs::handshake::ALL_KEY_EXCHANGE_ALGORITHMS; -#[cfg(feature = "tls12")] -use crate::tls12::Tls12CipherSuite; -use crate::tls13::Tls13CipherSuite; -#[cfg(feature = "tls12")] -use crate::versions::TLS12; -use crate::versions::{SupportedProtocolVersion, TLS13}; - -/// Common state for cipher suites (both for TLS 1.2 and TLS 1.3) -pub struct CipherSuiteCommon { - /// The TLS enumeration naming this cipher suite. - pub suite: CipherSuite, - - /// Which hash function the suite uses. - pub hash_provider: &'static dyn crypto::hash::Hash, - - /// Number of TCP-TLS messages that can be safely encrypted with a single key of this type - /// - /// Once a `MessageEncrypter` produced for this suite has encrypted more than - /// `confidentiality_limit` messages, an attacker gains an advantage in distinguishing it - /// from an ideal pseudorandom permutation (PRP). - /// - /// This is to be set on the assumption that messages are maximally sized -- - /// each is 2<sup>14</sup> bytes. It **does not** consider confidentiality limits for - /// QUIC connections - see the [`quic::KeyBuilder.confidentiality_limit`] field for - /// this context. - /// - /// For AES-GCM implementations, this should be set to 2<sup>24</sup> to limit attack - /// probability to one in 2<sup>60</sup>. See [AEBounds] (Table 1) and [draft-irtf-aead-limits-08]: - /// - /// ```python - /// >>> p = 2 ** -60 - /// >>> L = (2 ** 14 // 16) + 1 - /// >>> qlim = (math.sqrt(p) * (2 ** (129 // 2)) - 1) / (L + 1) - /// >>> print(int(qlim).bit_length()) - /// 24 - /// ``` - /// [AEBounds]: https://eprint.iacr.org/2024/051.pdf - /// [draft-irtf-aead-limits-08]: https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.1.1 - /// - /// For chacha20-poly1305 implementations, this should be set to `u64::MAX`: - /// see <https://www.ietf.org/archive/id/draft-irtf-cfrg-aead-limits-08.html#section-5.2.1> - pub confidentiality_limit: u64, -} - -impl CipherSuiteCommon { - /// Return `true` if this is backed by a FIPS-approved implementation. - /// - /// This means all the constituent parts that do cryptography return `true` for `fips()`. - pub fn fips(&self) -> bool { - self.hash_provider.fips() - } -} - -/// A cipher suite supported by rustls. -/// -/// This type carries both configuration and implementation. Compare with -/// [`CipherSuite`], which carries solely a cipher suite identifier. -#[derive(Clone, Copy, PartialEq)] -pub enum SupportedCipherSuite { - /// A TLS 1.2 cipher suite - #[cfg(feature = "tls12")] - Tls12(&'static Tls12CipherSuite), - /// A TLS 1.3 cipher suite - Tls13(&'static Tls13CipherSuite), -} - -impl SupportedCipherSuite { - /// The cipher suite's identifier - pub fn suite(&self) -> CipherSuite { - self.common().suite - } - - /// The hash function the ciphersuite uses. - pub(crate) fn hash_provider(&self) -> &'static dyn crypto::hash::Hash { - self.common().hash_provider - } - - pub(crate) fn common(&self) -> &CipherSuiteCommon { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(inner) => &inner.common, - Self::Tls13(inner) => &inner.common, - } - } - - /// Return the inner `Tls13CipherSuite` for this suite, if it is a TLS1.3 suite. - pub fn tls13(&self) -> Option<&'static Tls13CipherSuite> { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(_) => None, - Self::Tls13(inner) => Some(inner), - } - } - - /// Return supported protocol version for the cipher suite. - pub fn version(&self) -> &'static SupportedProtocolVersion { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(_) => &TLS12, - Self::Tls13(_) => &TLS13, - } - } - - /// Return true if this suite is usable for a key only offering `sig_alg` - /// signatures. This resolves to true for all TLS1.3 suites. - pub fn usable_for_signature_algorithm(&self, _sig_alg: SignatureAlgorithm) -> bool { - match self { - Self::Tls13(_) => true, // no constraint expressed by ciphersuite (e.g., TLS1.3) - #[cfg(feature = "tls12")] - Self::Tls12(inner) => inner - .sign - .iter() - .any(|scheme| scheme.algorithm() == _sig_alg), - } - } - - /// Return true if this suite is usable for the given [`Protocol`]. - /// - /// All cipher suites are usable for TCP-TLS. Only TLS1.3 suites - /// with `Tls13CipherSuite::quic` provided are usable for QUIC. - pub(crate) fn usable_for_protocol(&self, proto: Protocol) -> bool { - match proto { - Protocol::Tcp => true, - Protocol::Quic => self - .tls13() - .and_then(|cs| cs.quic) - .is_some(), - } - } - - /// Return `true` if this is backed by a FIPS-approved implementation. - pub fn fips(&self) -> bool { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(cs) => cs.fips(), - Self::Tls13(cs) => cs.fips(), - } - } - - /// Return the list of `KeyExchangeAlgorithm`s supported by this cipher suite. - /// - /// TLS 1.3 cipher suites support both ECDHE and DHE key exchange, but TLS 1.2 suites - /// support one or the other. - pub(crate) fn key_exchange_algorithms(&self) -> &[KeyExchangeAlgorithm] { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(tls12) => core::slice::from_ref(&tls12.kx), - Self::Tls13(_) => ALL_KEY_EXCHANGE_ALGORITHMS, - } - } - - /// Say if the given `KeyExchangeAlgorithm` is supported by this cipher suite. - /// - /// TLS 1.3 cipher suites support all key exchange types, but TLS 1.2 suites - /// support only one. - pub(crate) fn usable_for_kx_algorithm(&self, _kxa: KeyExchangeAlgorithm) -> bool { - match self { - #[cfg(feature = "tls12")] - Self::Tls12(tls12) => tls12.kx == _kxa, - Self::Tls13(_) => true, - } - } -} - -impl fmt::Debug for SupportedCipherSuite { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.suite().fmt(f) - } -} - -/// Return true if `sigscheme` is usable by any of the given suites. -pub(crate) fn compatible_sigscheme_for_suites( - sigscheme: SignatureScheme, - common_suites: &[SupportedCipherSuite], -) -> bool { - let sigalg = sigscheme.algorithm(); - common_suites - .iter() - .any(|&suite| suite.usable_for_signature_algorithm(sigalg)) -} - -/// Secrets for transmitting/receiving data over a TLS session. -/// -/// After performing a handshake with rustls, these secrets can be extracted -/// to configure kTLS for a socket, and have the kernel take over encryption -/// and/or decryption. -pub struct ExtractedSecrets { - /// sequence number and secrets for the "tx" (transmit) direction - pub tx: (u64, ConnectionTrafficSecrets), - - /// sequence number and secrets for the "rx" (receive) direction - pub rx: (u64, ConnectionTrafficSecrets), -} - -/// [ExtractedSecrets] minus the sequence numbers -pub(crate) struct PartiallyExtractedSecrets { - /// secrets for the "tx" (transmit) direction - pub(crate) tx: ConnectionTrafficSecrets, - - /// secrets for the "rx" (receive) direction - pub(crate) rx: ConnectionTrafficSecrets, -} - -/// Secrets used to encrypt/decrypt data in a TLS session. -/// -/// These can be used to configure kTLS for a socket in one direction. -/// The only other piece of information needed is the sequence number, -/// which is in [ExtractedSecrets]. -#[non_exhaustive] -pub enum ConnectionTrafficSecrets { - /// Secrets for the AES_128_GCM AEAD algorithm - Aes128Gcm { - /// AEAD Key - key: AeadKey, - /// Initialization vector - iv: Iv, - }, - - /// Secrets for the AES_256_GCM AEAD algorithm - Aes256Gcm { - /// AEAD Key - key: AeadKey, - /// Initialization vector - iv: Iv, - }, - - /// Secrets for the CHACHA20_POLY1305 AEAD algorithm - Chacha20Poly1305 { - /// AEAD Key - key: AeadKey, - /// Initialization vector - iv: Iv, - }, -} - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use std::println; - - use super::provider::tls13::*; - - #[test] - fn test_scs_is_debug() { - println!("{:?}", super::provider::ALL_CIPHER_SUITES); - } - - #[test] - fn test_can_resume_to() { - assert!( - TLS13_AES_128_GCM_SHA256 - .tls13() - .unwrap() - .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL) - .is_some() - ); - assert!( - TLS13_AES_256_GCM_SHA384 - .tls13() - .unwrap() - .can_resume_from(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL) - .is_none() - ); - } -} diff --git a/vendor/rustls/src/test_macros.rs b/vendor/rustls/src/test_macros.rs deleted file mode 100644 index 237578e0..00000000 --- a/vendor/rustls/src/test_macros.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! Macros used for unit testing. - -/// Instantiate the given test functions once for each built-in provider. -/// -/// The selected provider module is bound as `provider`; you can rely on this -/// having the union of the items common to the `crypto::ring` and -/// `crypto::aws_lc_rs` modules. -#[cfg(test)] -macro_rules! test_for_each_provider { - ($($tt:tt)+) => { - #[cfg(feature = "ring")] - mod test_with_ring { - use crate::crypto::ring as provider; - #[allow(unused_imports)] - use super::*; - $($tt)+ - } - - #[cfg(feature = "aws_lc_rs")] - mod test_with_aws_lc_rs { - use crate::crypto::aws_lc_rs as provider; - #[allow(unused_imports)] - use super::*; - $($tt)+ - } - }; -} - -/// Instantiate the given benchmark functions once for each built-in provider. -/// -/// The selected provider module is bound as `provider`; you can rely on this -/// having the union of the items common to the `crypto::ring` and -/// `crypto::aws_lc_rs` modules. -#[cfg(bench)] -macro_rules! bench_for_each_provider { - ($($tt:tt)+) => { - #[cfg(feature = "ring")] - mod bench_with_ring { - use crate::crypto::ring as provider; - #[allow(unused_imports)] - use super::*; - $($tt)+ - } - - #[cfg(feature = "aws_lc_rs")] - mod bench_with_aws_lc_rs { - use crate::crypto::aws_lc_rs as provider; - #[allow(unused_imports)] - use super::*; - $($tt)+ - } - }; -} - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - #[test] - fn test_each_provider() { - std::println!("provider is {:?}", super::provider::default_provider()); - } -} - -#[cfg(all(test, bench))] -#[macro_rules_attribute::apply(bench_for_each_provider)] -mod benchmarks { - #[bench] - fn bench_each_provider(b: &mut test::Bencher) { - b.iter(|| super::provider::default_provider()); - } -} diff --git a/vendor/rustls/src/ticketer.rs b/vendor/rustls/src/ticketer.rs deleted file mode 100644 index d1b5e143..00000000 --- a/vendor/rustls/src/ticketer.rs +++ /dev/null @@ -1,365 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec::Vec; -use core::mem; -#[cfg(feature = "std")] -use std::sync::{RwLock, RwLockReadGuard}; - -use pki_types::UnixTime; - -use crate::lock::{Mutex, MutexGuard}; -use crate::server::ProducesTickets; -#[cfg(not(feature = "std"))] -use crate::time_provider::TimeProvider; -use crate::{Error, rand}; - -#[derive(Debug)] -pub(crate) struct TicketSwitcherState { - next: Option<Box<dyn ProducesTickets>>, - current: Box<dyn ProducesTickets>, - previous: Option<Box<dyn ProducesTickets>>, - next_switch_time: u64, -} - -/// A ticketer that has a 'current' sub-ticketer and a single -/// 'previous' ticketer. It creates a new ticketer every so -/// often, demoting the current ticketer. -#[cfg_attr(feature = "std", derive(Debug))] -pub struct TicketSwitcher { - pub(crate) generator: fn() -> Result<Box<dyn ProducesTickets>, rand::GetRandomFailed>, - lifetime: u32, - state: Mutex<TicketSwitcherState>, - #[cfg(not(feature = "std"))] - time_provider: &'static dyn TimeProvider, -} - -impl TicketSwitcher { - /// Creates a new `TicketSwitcher`, which rotates through sub-ticketers - /// based on the passage of time. - /// - /// `lifetime` is in seconds, and is how long the current ticketer - /// is used to generate new tickets. Tickets are accepted for no - /// longer than twice this duration. `generator` produces a new - /// `ProducesTickets` implementation. - #[cfg(feature = "std")] - #[deprecated(note = "use TicketRotator instead")] - pub fn new( - lifetime: u32, - generator: fn() -> Result<Box<dyn ProducesTickets>, rand::GetRandomFailed>, - ) -> Result<Self, Error> { - Ok(Self { - generator, - lifetime, - state: Mutex::new(TicketSwitcherState { - next: Some(generator()?), - current: generator()?, - previous: None, - next_switch_time: UnixTime::now() - .as_secs() - .saturating_add(u64::from(lifetime)), - }), - }) - } - - /// Creates a new `TicketSwitcher`, which rotates through sub-ticketers - /// based on the passage of time. - /// - /// `lifetime` is in seconds, and is how long the current ticketer - /// is used to generate new tickets. Tickets are accepted for no - /// longer than twice this duration. `generator` produces a new - /// `ProducesTickets` implementation. - #[cfg(not(feature = "std"))] - pub fn new<M: crate::lock::MakeMutex>( - lifetime: u32, - generator: fn() -> Result<Box<dyn ProducesTickets>, rand::GetRandomFailed>, - time_provider: &'static dyn TimeProvider, - ) -> Result<Self, Error> { - Ok(Self { - generator, - lifetime, - state: Mutex::new::<M>(TicketSwitcherState { - next: Some(generator()?), - current: generator()?, - previous: None, - next_switch_time: time_provider - .current_time() - .unwrap() - .as_secs() - .saturating_add(u64::from(lifetime)), - }), - time_provider, - }) - } - - /// If it's time, demote the `current` ticketer to `previous` (so it - /// does no new encryptions but can do decryption) and use next for a - /// new `current` ticketer. - /// - /// Calling this regularly will ensure timely key erasure. Otherwise, - /// key erasure will be delayed until the next encrypt/decrypt call. - /// - /// For efficiency, this is also responsible for locking the state mutex - /// and returning the mutexguard. - pub(crate) fn maybe_roll(&self, now: UnixTime) -> Option<MutexGuard<'_, TicketSwitcherState>> { - // The code below aims to make switching as efficient as possible - // in the common case that the generator never fails. To achieve this - // we run the following steps: - // 1. If no switch is necessary, just return the mutexguard - // 2. Shift over all of the ticketers (so current becomes previous, - // and next becomes current). After this, other threads can - // start using the new current ticketer. - // 3. unlock mutex and generate new ticketer. - // 4. Place new ticketer in next and return current - // - // There are a few things to note here. First, we don't check whether - // a new switch might be needed in step 4, even though, due to locking - // and entropy collection, significant amounts of time may have passed. - // This is to guarantee that the thread doing the switch will eventually - // make progress. - // - // Second, because next may be None, step 2 can fail. In that case - // we enter a recovery mode where we generate 2 new ticketers, one for - // next and one for the current ticketer. We then take the mutex a - // second time and redo the time check to see if a switch is still - // necessary. - // - // This somewhat convoluted approach ensures good availability of the - // mutex, by ensuring that the state is usable and the mutex not held - // during generation. It also ensures that, so long as the inner - // ticketer never generates panics during encryption/decryption, - // we are guaranteed to never panic when holding the mutex. - - let now = now.as_secs(); - let mut are_recovering = false; // Are we recovering from previous failure? - { - // Scope the mutex so we only take it for as long as needed - let mut state = self.state.lock()?; - - // Fast path in case we do not need to switch to the next ticketer yet - if now <= state.next_switch_time { - return Some(state); - } - - // Make the switch, or mark for recovery if not possible - match state.next.take() { - Some(next) => { - state.previous = Some(mem::replace(&mut state.current, next)); - state.next_switch_time = now.saturating_add(u64::from(self.lifetime)); - } - _ => are_recovering = true, - } - } - - // We always need a next, so generate it now - let next = (self.generator)().ok()?; - if !are_recovering { - // Normal path, generate new next and place it in the state - let mut state = self.state.lock()?; - state.next = Some(next); - Some(state) - } else { - // Recovering, generate also a new current ticketer, and modify state - // as needed. (we need to redo the time check, otherwise this might - // result in very rapid switching of ticketers) - let new_current = (self.generator)().ok()?; - let mut state = self.state.lock()?; - state.next = Some(next); - if now > state.next_switch_time { - state.previous = Some(mem::replace(&mut state.current, new_current)); - state.next_switch_time = now.saturating_add(u64::from(self.lifetime)); - } - Some(state) - } - } -} - -impl ProducesTickets for TicketSwitcher { - fn lifetime(&self) -> u32 { - self.lifetime * 2 - } - - fn enabled(&self) -> bool { - true - } - - fn encrypt(&self, message: &[u8]) -> Option<Vec<u8>> { - #[cfg(feature = "std")] - let now = UnixTime::now(); - #[cfg(not(feature = "std"))] - let now = self - .time_provider - .current_time() - .unwrap(); - - self.maybe_roll(now)? - .current - .encrypt(message) - } - - fn decrypt(&self, ciphertext: &[u8]) -> Option<Vec<u8>> { - #[cfg(feature = "std")] - let now = UnixTime::now(); - #[cfg(not(feature = "std"))] - let now = self - .time_provider - .current_time() - .unwrap(); - - let state = self.maybe_roll(now)?; - - // Decrypt with the current key; if that fails, try with the previous. - state - .current - .decrypt(ciphertext) - .or_else(|| { - state - .previous - .as_ref() - .and_then(|previous| previous.decrypt(ciphertext)) - }) - } -} - -#[cfg(not(feature = "std"))] -impl core::fmt::Debug for TicketSwitcher { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("TicketSwitcher") - .field("generator", &self.generator) - .field("lifetime", &self.lifetime) - .field("state", &**self.state.lock().unwrap()) - .finish() - } -} - -#[cfg(feature = "std")] -#[derive(Debug)] -pub(crate) struct TicketRotatorState { - current: Box<dyn ProducesTickets>, - previous: Option<Box<dyn ProducesTickets>>, - next_switch_time: u64, -} - -/// A ticketer that has a 'current' sub-ticketer and a single -/// 'previous' ticketer. It creates a new ticketer every so -/// often, demoting the current ticketer. -#[cfg(feature = "std")] -pub struct TicketRotator { - pub(crate) generator: fn() -> Result<Box<dyn ProducesTickets>, rand::GetRandomFailed>, - lifetime: u32, - state: RwLock<TicketRotatorState>, -} - -#[cfg(feature = "std")] -impl TicketRotator { - /// Creates a new `TicketRotator`, which rotates through sub-ticketers - /// based on the passage of time. - /// - /// `lifetime` is in seconds, and is how long the current ticketer - /// is used to generate new tickets. Tickets are accepted for no - /// longer than twice this duration. `generator` produces a new - /// `ProducesTickets` implementation. - pub fn new( - lifetime: u32, - generator: fn() -> Result<Box<dyn ProducesTickets>, rand::GetRandomFailed>, - ) -> Result<Self, Error> { - Ok(Self { - generator, - lifetime, - state: RwLock::new(TicketRotatorState { - current: generator()?, - previous: None, - next_switch_time: UnixTime::now() - .as_secs() - .saturating_add(u64::from(lifetime)), - }), - }) - } - - /// If it's time, demote the `current` ticketer to `previous` (so it - /// does no new encryptions but can do decryption) and replace it - /// with a new one. - /// - /// Calling this regularly will ensure timely key erasure. Otherwise, - /// key erasure will be delayed until the next encrypt/decrypt call. - /// - /// For efficiency, this is also responsible for locking the state rwlock - /// and returning it for read. - pub(crate) fn maybe_roll( - &self, - now: UnixTime, - ) -> Option<RwLockReadGuard<'_, TicketRotatorState>> { - let now = now.as_secs(); - - // Fast, common, & read-only path in case we do not need to switch - // to the next ticketer yet - { - let read = self.state.read().ok()?; - - if now <= read.next_switch_time { - return Some(read); - } - } - - // We need to switch ticketers, and make a new one. - // Generate a potential "next" ticketer outside the lock. - let next = (self.generator)().ok()?; - - let mut write = self.state.write().ok()?; - - if now <= write.next_switch_time { - // Another thread beat us to it. Nothing to do. - drop(write); - - return self.state.read().ok(); - } - - // Now we have: - // - confirmed we need rotation - // - confirmed we are the thread that will do it - // - successfully made the replacement ticketer - write.previous = Some(mem::replace(&mut write.current, next)); - write.next_switch_time = now.saturating_add(u64::from(self.lifetime)); - drop(write); - - self.state.read().ok() - } -} - -#[cfg(feature = "std")] -impl ProducesTickets for TicketRotator { - fn lifetime(&self) -> u32 { - self.lifetime * 2 - } - - fn enabled(&self) -> bool { - true - } - - fn encrypt(&self, message: &[u8]) -> Option<Vec<u8>> { - self.maybe_roll(UnixTime::now())? - .current - .encrypt(message) - } - - fn decrypt(&self, ciphertext: &[u8]) -> Option<Vec<u8>> { - let state = self.maybe_roll(UnixTime::now())?; - - // Decrypt with the current key; if that fails, try with the previous. - state - .current - .decrypt(ciphertext) - .or_else(|| { - state - .previous - .as_ref() - .and_then(|previous| previous.decrypt(ciphertext)) - }) - } -} - -#[cfg(feature = "std")] -impl core::fmt::Debug for TicketRotator { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("TicketRotator") - .finish_non_exhaustive() - } -} diff --git a/vendor/rustls/src/time_provider.rs b/vendor/rustls/src/time_provider.rs deleted file mode 100644 index e43f4d6d..00000000 --- a/vendor/rustls/src/time_provider.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! The library's source of time. - -use core::fmt::Debug; - -use pki_types::UnixTime; - -/// An object that provides the current time. -/// -/// This is used to, for example, check if a certificate has expired during -/// certificate validation, or to check the age of a ticket. -pub trait TimeProvider: Debug + Send + Sync { - /// Returns the current wall time. - /// - /// This is not required to be monotonic. - /// - /// Return `None` if unable to retrieve the time. - fn current_time(&self) -> Option<UnixTime>; -} - -#[derive(Debug)] -#[cfg(feature = "std")] -/// Default `TimeProvider` implementation that uses `std` -pub struct DefaultTimeProvider; - -#[cfg(feature = "std")] -impl TimeProvider for DefaultTimeProvider { - fn current_time(&self) -> Option<UnixTime> { - Some(UnixTime::now()) - } -} diff --git a/vendor/rustls/src/tls12/mod.rs b/vendor/rustls/src/tls12/mod.rs deleted file mode 100644 index c9271850..00000000 --- a/vendor/rustls/src/tls12/mod.rs +++ /dev/null @@ -1,380 +0,0 @@ -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; -use core::fmt; - -use zeroize::Zeroize; - -use crate::common_state::{CommonState, Side}; -use crate::conn::ConnectionRandoms; -use crate::crypto; -use crate::crypto::cipher::{AeadKey, MessageDecrypter, MessageEncrypter, Tls12AeadAlgorithm}; -use crate::crypto::hash; -use crate::enums::{AlertDescription, SignatureScheme}; -use crate::error::{Error, InvalidMessage}; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::handshake::{KeyExchangeAlgorithm, KxDecode}; -use crate::suites::{CipherSuiteCommon, PartiallyExtractedSecrets, SupportedCipherSuite}; - -/// A TLS 1.2 cipher suite supported by rustls. -pub struct Tls12CipherSuite { - /// Common cipher suite fields. - pub common: CipherSuiteCommon, - - /// How to compute the TLS1.2 PRF for the suite's hash function. - /// - /// If you have a TLS1.2 PRF implementation, you should directly implement the [`crypto::tls12::Prf`] trait. - /// - /// If not, you can implement the [`crypto::hmac::Hmac`] trait (and associated), and then use - /// [`crypto::tls12::PrfUsingHmac`]. - pub prf_provider: &'static dyn crypto::tls12::Prf, - - /// How to exchange/agree keys. - /// - /// In TLS1.2, the key exchange method (eg, Elliptic Curve Diffie-Hellman with Ephemeral keys -- ECDHE) - /// is baked into the cipher suite, but the details to achieve it are negotiated separately. - /// - /// This controls how protocol messages (like the `ClientKeyExchange` message) are interpreted - /// once this cipher suite has been negotiated. - pub kx: KeyExchangeAlgorithm, - - /// How to sign messages for authentication. - /// - /// This is a set of [`SignatureScheme`]s that are usable once this cipher suite has been - /// negotiated. - /// - /// The precise scheme used is then chosen from this set by the selected authentication key. - pub sign: &'static [SignatureScheme], - - /// How to produce a [`MessageDecrypter`] or [`MessageEncrypter`] - /// from raw key material. - pub aead_alg: &'static dyn Tls12AeadAlgorithm, -} - -impl Tls12CipherSuite { - /// Resolve the set of supported [`SignatureScheme`]s from the - /// offered signature schemes. If we return an empty - /// set, the handshake terminates. - pub fn resolve_sig_schemes(&self, offered: &[SignatureScheme]) -> Vec<SignatureScheme> { - self.sign - .iter() - .filter(|pref| offered.contains(pref)) - .cloned() - .collect() - } - - /// Return `true` if this is backed by a FIPS-approved implementation. - /// - /// This means all the constituent parts that do cryptography return `true` for `fips()`. - pub fn fips(&self) -> bool { - self.common.fips() && self.prf_provider.fips() && self.aead_alg.fips() - } -} - -impl From<&'static Tls12CipherSuite> for SupportedCipherSuite { - fn from(s: &'static Tls12CipherSuite) -> Self { - Self::Tls12(s) - } -} - -impl PartialEq for Tls12CipherSuite { - fn eq(&self, other: &Self) -> bool { - self.common.suite == other.common.suite - } -} - -impl fmt::Debug for Tls12CipherSuite { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Tls12CipherSuite") - .field("suite", &self.common.suite) - .finish() - } -} - -/// TLS1.2 per-connection keying material -pub(crate) struct ConnectionSecrets { - pub(crate) randoms: ConnectionRandoms, - suite: &'static Tls12CipherSuite, - pub(crate) master_secret: [u8; 48], -} - -impl ConnectionSecrets { - pub(crate) fn from_key_exchange( - kx: Box<dyn crypto::ActiveKeyExchange>, - peer_pub_key: &[u8], - ems_seed: Option<hash::Output>, - randoms: ConnectionRandoms, - suite: &'static Tls12CipherSuite, - ) -> Result<Self, Error> { - let mut ret = Self { - randoms, - suite, - master_secret: [0u8; 48], - }; - - let (label, seed) = match ems_seed { - Some(seed) => ("extended master secret", Seed::Ems(seed)), - None => ( - "master secret", - Seed::Randoms(join_randoms(&ret.randoms.client, &ret.randoms.server)), - ), - }; - - // The API contract for for_key_exchange is that the caller guarantees `label` and `seed` - // slice parameters are non-empty. - // `label` is guaranteed non-empty because it's assigned from a `&str` above. - // `seed.as_ref()` is guaranteed non-empty by documentation on the AsRef impl. - ret.suite - .prf_provider - .for_key_exchange( - &mut ret.master_secret, - kx, - peer_pub_key, - label.as_bytes(), - seed.as_ref(), - )?; - - Ok(ret) - } - - pub(crate) fn new_resume( - randoms: ConnectionRandoms, - suite: &'static Tls12CipherSuite, - master_secret: &[u8], - ) -> Self { - let mut ret = Self { - randoms, - suite, - master_secret: [0u8; 48], - }; - ret.master_secret - .copy_from_slice(master_secret); - ret - } - - /// Make a `MessageCipherPair` based on the given supported ciphersuite `self.suite`, - /// and the session's `secrets`. - pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair { - // Make a key block, and chop it up. - // Note: we don't implement any ciphersuites with nonzero mac_key_len. - let key_block = self.make_key_block(); - let shape = self.suite.aead_alg.key_block_shape(); - - let (client_write_key, key_block) = key_block.split_at(shape.enc_key_len); - let (server_write_key, key_block) = key_block.split_at(shape.enc_key_len); - let (client_write_iv, key_block) = key_block.split_at(shape.fixed_iv_len); - let (server_write_iv, extra) = key_block.split_at(shape.fixed_iv_len); - - let (write_key, write_iv, read_key, read_iv) = match side { - Side::Client => ( - client_write_key, - client_write_iv, - server_write_key, - server_write_iv, - ), - Side::Server => ( - server_write_key, - server_write_iv, - client_write_key, - client_write_iv, - ), - }; - - ( - self.suite - .aead_alg - .decrypter(AeadKey::new(read_key), read_iv), - self.suite - .aead_alg - .encrypter(AeadKey::new(write_key), write_iv, extra), - ) - } - - fn make_key_block(&self) -> Vec<u8> { - let shape = self.suite.aead_alg.key_block_shape(); - - let len = (shape.enc_key_len + shape.fixed_iv_len) * 2 + shape.explicit_nonce_len; - - let mut out = vec![0u8; len]; - - // NOTE: opposite order to above for no good reason. - // Don't design security protocols on drugs, kids. - let randoms = join_randoms(&self.randoms.server, &self.randoms.client); - self.suite.prf_provider.for_secret( - &mut out, - &self.master_secret, - b"key expansion", - &randoms, - ); - - out - } - - pub(crate) fn suite(&self) -> &'static Tls12CipherSuite { - self.suite - } - - pub(crate) fn master_secret(&self) -> &[u8] { - &self.master_secret[..] - } - - fn make_verify_data(&self, handshake_hash: &hash::Output, label: &[u8]) -> Vec<u8> { - let mut out = vec![0u8; 12]; - - self.suite.prf_provider.for_secret( - &mut out, - &self.master_secret, - label, - handshake_hash.as_ref(), - ); - - out - } - - pub(crate) fn client_verify_data(&self, handshake_hash: &hash::Output) -> Vec<u8> { - self.make_verify_data(handshake_hash, b"client finished") - } - - pub(crate) fn server_verify_data(&self, handshake_hash: &hash::Output) -> Vec<u8> { - self.make_verify_data(handshake_hash, b"server finished") - } - - pub(crate) fn export_keying_material( - &self, - output: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) { - let mut randoms = Vec::new(); - randoms.extend_from_slice(&self.randoms.client); - randoms.extend_from_slice(&self.randoms.server); - if let Some(context) = context { - assert!(context.len() <= 0xffff); - (context.len() as u16).encode(&mut randoms); - randoms.extend_from_slice(context); - } - - self.suite - .prf_provider - .for_secret(output, &self.master_secret, label, &randoms); - } - - pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> { - // Make a key block, and chop it up - let key_block = self.make_key_block(); - let shape = self.suite.aead_alg.key_block_shape(); - - let (client_key, key_block) = key_block.split_at(shape.enc_key_len); - let (server_key, key_block) = key_block.split_at(shape.enc_key_len); - let (client_iv, key_block) = key_block.split_at(shape.fixed_iv_len); - let (server_iv, explicit_nonce) = key_block.split_at(shape.fixed_iv_len); - - let client_secrets = self.suite.aead_alg.extract_keys( - AeadKey::new(client_key), - client_iv, - explicit_nonce, - )?; - let server_secrets = self.suite.aead_alg.extract_keys( - AeadKey::new(server_key), - server_iv, - explicit_nonce, - )?; - - let (tx, rx) = match side { - Side::Client => (client_secrets, server_secrets), - Side::Server => (server_secrets, client_secrets), - }; - Ok(PartiallyExtractedSecrets { tx, rx }) - } -} - -impl Drop for ConnectionSecrets { - fn drop(&mut self) { - self.master_secret.zeroize(); - } -} - -enum Seed { - Ems(hash::Output), - Randoms([u8; 64]), -} - -impl AsRef<[u8]> for Seed { - /// This is guaranteed to return a non-empty slice. - fn as_ref(&self) -> &[u8] { - match self { - // seed is a hash::Output, which is a fixed, non-zero length array. - Self::Ems(seed) => seed.as_ref(), - // randoms is a fixed, non-zero length array. - Self::Randoms(randoms) => randoms.as_ref(), - } - } -} - -fn join_randoms(first: &[u8; 32], second: &[u8; 32]) -> [u8; 64] { - let mut randoms = [0u8; 64]; - randoms[..32].copy_from_slice(first); - randoms[32..].copy_from_slice(second); - randoms -} - -type MessageCipherPair = (Box<dyn MessageDecrypter>, Box<dyn MessageEncrypter>); - -pub(crate) fn decode_kx_params<'a, T: KxDecode<'a>>( - kx_algorithm: KeyExchangeAlgorithm, - common: &mut CommonState, - kx_params: &'a [u8], -) -> Result<T, Error> { - let mut rd = Reader::init(kx_params); - let kx_params = T::decode(&mut rd, kx_algorithm)?; - match rd.any_left() { - false => Ok(kx_params), - true => Err(common.send_fatal_alert( - AlertDescription::DecodeError, - InvalidMessage::InvalidDhParams, - )), - } -} - -pub(crate) const DOWNGRADE_SENTINEL: [u8; 8] = [0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01]; - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use super::provider::kx_group::X25519; - use super::*; - use crate::common_state::{CommonState, Side}; - use crate::msgs::handshake::{ServerEcdhParams, ServerKeyExchangeParams}; - - #[test] - fn server_ecdhe_remaining_bytes() { - let key = X25519.start().unwrap(); - let server_params = ServerEcdhParams::new(&*key); - let mut server_buf = Vec::new(); - server_params.encode(&mut server_buf); - server_buf.push(34); - - let mut common = CommonState::new(Side::Client); - assert!( - decode_kx_params::<ServerKeyExchangeParams>( - KeyExchangeAlgorithm::ECDHE, - &mut common, - &server_buf - ) - .is_err() - ); - } - - #[test] - fn client_ecdhe_invalid() { - let mut common = CommonState::new(Side::Server); - assert!( - decode_kx_params::<ServerKeyExchangeParams>( - KeyExchangeAlgorithm::ECDHE, - &mut common, - &[34], - ) - .is_err() - ); - } -} diff --git a/vendor/rustls/src/tls13/key_schedule.rs b/vendor/rustls/src/tls13/key_schedule.rs deleted file mode 100644 index 4bf04214..00000000 --- a/vendor/rustls/src/tls13/key_schedule.rs +++ /dev/null @@ -1,1308 +0,0 @@ -//! Key schedule maintenance for TLS1.3 - -use alloc::boxed::Box; -use alloc::string::ToString; -use core::ops::Deref; - -use crate::common_state::{CommonState, Side}; -use crate::crypto::cipher::{AeadKey, Iv, MessageDecrypter, Tls13AeadAlgorithm}; -use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock, OutputLengthError, expand}; -use crate::crypto::{SharedSecret, hash, hmac}; -use crate::error::Error; -use crate::msgs::message::Message; -use crate::suites::PartiallyExtractedSecrets; -use crate::{ConnectionTrafficSecrets, KeyLog, Tls13CipherSuite, quic}; - -// We express the state of a contained KeySchedule using these -// typestates. This means we can write code that cannot accidentally -// (e.g.) encrypt application data using a KeySchedule solely constructed -// with an empty or trivial secret, or extract the wrong kind of secrets -// at a given point. - -/// The "early secret" stage of the key schedule WITH a PSK. -/// -/// This is only useful when you need to use one of the binder -/// keys, the "client_early_traffic_secret", or -/// "early_exporter_master_secret". -/// -/// See [`KeySchedulePreHandshake`] for more information. -pub(crate) struct KeyScheduleEarly { - ks: KeySchedule, -} - -impl KeyScheduleEarly { - pub(crate) fn new(suite: &'static Tls13CipherSuite, secret: &[u8]) -> Self { - Self { - ks: KeySchedule::new(suite, secret), - } - } - - /// Computes the `client_early_traffic_secret` and writes it - /// to `common`. - /// - /// `hs_hash` is `Transcript-Hash(ClientHello)`. - /// - /// ```text - /// Derive-Secret(., "c e traffic", ClientHello) - /// = client_early_traffic_secret - /// ``` - pub(crate) fn client_early_traffic_secret( - &self, - hs_hash: &hash::Output, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - common: &mut CommonState, - ) { - let client_early_traffic_secret = self.ks.derive_logged_secret( - SecretKind::ClientEarlyTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - match common.side { - Side::Client => self - .ks - .set_encrypter(&client_early_traffic_secret, common), - Side::Server => self - .ks - .set_decrypter(&client_early_traffic_secret, common), - } - - if common.is_quic() { - // If 0-RTT should be rejected, this will be clobbered by ExtensionProcessing - // before the application can see. - common.quic.early_secret = Some(client_early_traffic_secret); - } - } - - pub(crate) fn resumption_psk_binder_key_and_sign_verify_data( - &self, - hs_hash: &hash::Output, - ) -> hmac::Tag { - let resumption_psk_binder_key = self - .ks - .derive_for_empty_hash(SecretKind::ResumptionPskBinderKey); - self.ks - .sign_verify_data(&resumption_psk_binder_key, hs_hash) - } -} - -/// The "early secret" stage of the key schedule. -/// -/// Call [`KeySchedulePreHandshake::new`] to create it without -/// a PSK, or use [`From<KeyScheduleEarly>`] to create it with -/// a PSK. -/// -/// ```text -/// 0 -/// | -/// v -/// PSK -> HKDF-Extract = Early Secret -/// | -/// +-----> Derive-Secret(., "ext binder" | "res binder", "") -/// | = binder_key -/// | -/// +-----> Derive-Secret(., "c e traffic", ClientHello) -/// | = client_early_traffic_secret -/// | -/// +-----> Derive-Secret(., "e exp master", ClientHello) -/// | = early_exporter_master_secret -/// v -/// Derive-Secret(., "derived", "") -/// ``` -pub(crate) struct KeySchedulePreHandshake { - ks: KeySchedule, -} - -impl KeySchedulePreHandshake { - /// Creates a key schedule without a PSK. - pub(crate) fn new(suite: &'static Tls13CipherSuite) -> Self { - Self { - ks: KeySchedule::new_with_empty_secret(suite), - } - } - - /// `shared_secret` is the "(EC)DHE" secret input to - /// "HKDF-Extract": - /// - /// ```text - /// (EC)DHE -> HKDF-Extract = Handshake Secret - /// ``` - pub(crate) fn into_handshake( - mut self, - shared_secret: SharedSecret, - ) -> KeyScheduleHandshakeStart { - self.ks - .input_secret(shared_secret.secret_bytes()); - KeyScheduleHandshakeStart { ks: self.ks } - } -} - -/// Creates a key schedule with a PSK. -impl From<KeyScheduleEarly> for KeySchedulePreHandshake { - fn from(KeyScheduleEarly { ks }: KeyScheduleEarly) -> Self { - Self { ks } - } -} - -/// KeySchedule during handshake. -/// -/// Created by [`KeySchedulePreHandshake`]. -pub(crate) struct KeyScheduleHandshakeStart { - ks: KeySchedule, -} - -impl KeyScheduleHandshakeStart { - pub(crate) fn derive_client_handshake_secrets( - mut self, - early_data_enabled: bool, - hs_hash: hash::Output, - suite: &'static Tls13CipherSuite, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - common: &mut CommonState, - ) -> KeyScheduleHandshake { - debug_assert_eq!(common.side, Side::Client); - // Suite might have changed due to resumption - self.ks.inner = suite.into(); - let new = self.into_handshake(hs_hash, key_log, client_random, common); - - // Decrypt with the peer's key, encrypt with our own key - new.ks - .set_decrypter(&new.server_handshake_traffic_secret, common); - - if !early_data_enabled { - // Set the client encryption key for handshakes if early data is not used - new.ks - .set_encrypter(&new.client_handshake_traffic_secret, common); - } - - new - } - - pub(crate) fn derive_server_handshake_secrets( - self, - hs_hash: hash::Output, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - common: &mut CommonState, - ) -> KeyScheduleHandshake { - debug_assert_eq!(common.side, Side::Server); - let new = self.into_handshake(hs_hash, key_log, client_random, common); - - // Set up to encrypt with handshake secrets, but decrypt with early_data keys. - // If not doing early_data after all, this is corrected later to the handshake - // keys (now stored in key_schedule). - new.ks - .set_encrypter(&new.server_handshake_traffic_secret, common); - new - } - - pub(crate) fn server_ech_confirmation_secret( - &mut self, - client_hello_inner_random: &[u8], - hs_hash: hash::Output, - ) -> [u8; 8] { - /* - Per ietf-tls-esni-17 section 7.2: - <https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#section-7.2> - accept_confirmation = HKDF-Expand-Label( - HKDF-Extract(0, ClientHelloInner.random), - "ech accept confirmation", - transcript_ech_conf,8) - */ - hkdf_expand_label( - self.ks - .suite - .hkdf_provider - .extract_from_secret(None, client_hello_inner_random) - .as_ref(), - SecretKind::ServerEchConfirmationSecret.to_bytes(), - hs_hash.as_ref(), - ) - } - - fn into_handshake( - self, - hs_hash: hash::Output, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - common: &mut CommonState, - ) -> KeyScheduleHandshake { - // Use an empty handshake hash for the initial handshake. - let client_secret = self.ks.derive_logged_secret( - SecretKind::ClientHandshakeTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - let server_secret = self.ks.derive_logged_secret( - SecretKind::ServerHandshakeTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - if common.is_quic() { - common.quic.hs_secrets = Some(quic::Secrets::new( - client_secret.clone(), - server_secret.clone(), - self.ks.suite, - self.ks.suite.quic.unwrap(), - common.side, - common.quic.version, - )); - } - - KeyScheduleHandshake { - ks: self.ks, - client_handshake_traffic_secret: client_secret, - server_handshake_traffic_secret: server_secret, - } - } -} - -pub(crate) struct KeyScheduleHandshake { - ks: KeySchedule, - client_handshake_traffic_secret: OkmBlock, - server_handshake_traffic_secret: OkmBlock, -} - -impl KeyScheduleHandshake { - pub(crate) fn sign_server_finish(&self, hs_hash: &hash::Output) -> hmac::Tag { - self.ks - .sign_finish(&self.server_handshake_traffic_secret, hs_hash) - } - - pub(crate) fn set_handshake_encrypter(&self, common: &mut CommonState) { - debug_assert_eq!(common.side, Side::Client); - self.ks - .set_encrypter(&self.client_handshake_traffic_secret, common); - } - - pub(crate) fn set_handshake_decrypter( - &self, - skip_requested: Option<usize>, - common: &mut CommonState, - ) { - debug_assert_eq!(common.side, Side::Server); - let secret = &self.client_handshake_traffic_secret; - match skip_requested { - None => self.ks.set_decrypter(secret, common), - Some(max_early_data_size) => common - .record_layer - .set_message_decrypter_with_trial_decryption( - self.ks - .derive_decrypter(&self.client_handshake_traffic_secret), - max_early_data_size, - ), - } - } - - pub(crate) fn into_traffic_with_client_finished_pending( - self, - hs_hash: hash::Output, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - common: &mut CommonState, - ) -> KeyScheduleTrafficWithClientFinishedPending { - debug_assert_eq!(common.side, Side::Server); - - let before_finished = - KeyScheduleBeforeFinished::new(self.ks, hs_hash, key_log, client_random); - let (_client_secret, server_secret) = ( - &before_finished.current_client_traffic_secret, - &before_finished.current_server_traffic_secret, - ); - - before_finished - .ks - .set_encrypter(server_secret, common); - - if common.is_quic() { - common.quic.traffic_secrets = Some(quic::Secrets::new( - _client_secret.clone(), - server_secret.clone(), - before_finished.ks.suite, - before_finished.ks.suite.quic.unwrap(), - common.side, - common.quic.version, - )); - } - - KeyScheduleTrafficWithClientFinishedPending { - handshake_client_traffic_secret: self.client_handshake_traffic_secret, - before_finished, - } - } - - pub(crate) fn into_pre_finished_client_traffic( - self, - pre_finished_hash: hash::Output, - handshake_hash: hash::Output, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - ) -> (KeyScheduleClientBeforeFinished, hmac::Tag) { - let before_finished = - KeyScheduleBeforeFinished::new(self.ks, pre_finished_hash, key_log, client_random); - let tag = before_finished - .ks - .sign_finish(&self.client_handshake_traffic_secret, &handshake_hash); - (KeyScheduleClientBeforeFinished(before_finished), tag) - } -} - -/// Keys derived (but not installed) before client's Finished message. -pub(crate) struct KeyScheduleBeforeFinished { - ks: KeySchedule, - current_client_traffic_secret: OkmBlock, - current_server_traffic_secret: OkmBlock, - current_exporter_secret: OkmBlock, -} - -impl KeyScheduleBeforeFinished { - fn new( - mut ks: KeySchedule, - hs_hash: hash::Output, - key_log: &dyn KeyLog, - client_random: &[u8; 32], - ) -> Self { - ks.input_empty(); - - let current_client_traffic_secret = ks.derive_logged_secret( - SecretKind::ClientApplicationTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - let current_server_traffic_secret = ks.derive_logged_secret( - SecretKind::ServerApplicationTrafficSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - let current_exporter_secret = ks.derive_logged_secret( - SecretKind::ExporterMasterSecret, - hs_hash.as_ref(), - key_log, - client_random, - ); - - Self { - ks, - current_client_traffic_secret, - current_server_traffic_secret, - current_exporter_secret, - } - } - - pub(crate) fn into_traffic( - self, - hs_hash: hash::Output, - ) -> (KeyScheduleTraffic, KeyScheduleResumption) { - let Self { - ks, - current_client_traffic_secret, - current_server_traffic_secret, - current_exporter_secret, - } = self; - - let resumption_master_secret = - ks.derive(SecretKind::ResumptionMasterSecret, hs_hash.as_ref()); - - ( - KeyScheduleTraffic { - ks: ks.inner, - current_client_traffic_secret, - current_server_traffic_secret, - current_exporter_secret, - }, - KeyScheduleResumption { - ks: ks.inner, - resumption_master_secret, - }, - ) - } -} - -/// Client-side key schedule before the finished message is sent. -/// -/// This differs from `KeyScheduleTrafficWithClientFinishedPending` because -/// none of the final traffic secrets are installed yet. After the finished -/// message is sent, `into_traffic()` does that. -pub(crate) struct KeyScheduleClientBeforeFinished(KeyScheduleBeforeFinished); - -impl KeyScheduleClientBeforeFinished { - pub(crate) fn into_traffic( - self, - common: &mut CommonState, - hs_hash: hash::Output, - ) -> (KeyScheduleTraffic, KeyScheduleResumption) { - let next = self.0; - - debug_assert_eq!(common.side, Side::Client); - let (client_secret, server_secret) = ( - &next.current_client_traffic_secret, - &next.current_server_traffic_secret, - ); - - next.ks - .set_decrypter(server_secret, common); - next.ks - .set_encrypter(client_secret, common); - - if common.is_quic() { - common.quic.traffic_secrets = Some(quic::Secrets::new( - client_secret.clone(), - server_secret.clone(), - next.ks.suite, - next.ks.suite.quic.unwrap(), - common.side, - common.quic.version, - )); - } - - next.into_traffic(hs_hash) - } -} - -/// KeySchedule during traffic stage, retaining the ability to calculate the client's -/// finished verify_data. The traffic stage key schedule can be extracted from it -/// through signing the client finished hash. -pub(crate) struct KeyScheduleTrafficWithClientFinishedPending { - handshake_client_traffic_secret: OkmBlock, - before_finished: KeyScheduleBeforeFinished, -} - -impl KeyScheduleTrafficWithClientFinishedPending { - pub(crate) fn update_decrypter(&self, common: &mut CommonState) { - debug_assert_eq!(common.side, Side::Server); - self.before_finished - .ks - .set_decrypter(&self.handshake_client_traffic_secret, common); - } - - pub(crate) fn sign_client_finish( - self, - hs_hash: &hash::Output, - common: &mut CommonState, - ) -> (KeyScheduleBeforeFinished, hmac::Tag) { - debug_assert_eq!(common.side, Side::Server); - let tag = self - .before_finished - .ks - .sign_finish(&self.handshake_client_traffic_secret, hs_hash); - - // Install keying to read future messages. - self.before_finished.ks.set_decrypter( - &self - .before_finished - .current_client_traffic_secret, - common, - ); - - (self.before_finished, tag) - } -} - -/// KeySchedule during traffic stage. All traffic & exporter keys are guaranteed -/// to be available. -pub(crate) struct KeyScheduleTraffic { - ks: KeyScheduleSuite, - current_client_traffic_secret: OkmBlock, - current_server_traffic_secret: OkmBlock, - current_exporter_secret: OkmBlock, -} - -impl KeyScheduleTraffic { - pub(crate) fn update_encrypter_and_notify(&mut self, common: &mut CommonState) { - let secret = self.next_application_traffic_secret(common.side); - common.enqueue_key_update_notification(); - self.ks.set_encrypter(&secret, common); - } - - pub(crate) fn request_key_update_and_update_encrypter( - &mut self, - common: &mut CommonState, - ) -> Result<(), Error> { - common.check_aligned_handshake()?; - common.send_msg_encrypt(Message::build_key_update_request().into()); - let secret = self.next_application_traffic_secret(common.side); - self.ks.set_encrypter(&secret, common); - Ok(()) - } - - pub(crate) fn update_decrypter(&mut self, common: &mut CommonState) { - let secret = self.next_application_traffic_secret(common.side.peer()); - self.ks.set_decrypter(&secret, common); - } - - pub(crate) fn next_application_traffic_secret(&mut self, side: Side) -> OkmBlock { - let current = match side { - Side::Client => &mut self.current_client_traffic_secret, - Side::Server => &mut self.current_server_traffic_secret, - }; - - let secret = self.ks.derive_next(current); - *current = secret.clone(); - secret - } - - pub(crate) fn export_keying_material( - &self, - out: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - self.ks - .export_keying_material(&self.current_exporter_secret, out, label, context) - } - - pub(crate) fn refresh_traffic_secret( - &mut self, - side: Side, - ) -> Result<ConnectionTrafficSecrets, Error> { - let secret = self.next_application_traffic_secret(side); - let (key, iv) = expand_secret( - &secret, - self.ks.suite.hkdf_provider, - self.ks.suite.aead_alg.key_len(), - ); - Ok(self - .ks - .suite - .aead_alg - .extract_keys(key, iv)?) - } - - pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> { - let (client_key, client_iv) = expand_secret( - &self.current_client_traffic_secret, - self.ks.suite.hkdf_provider, - self.ks.suite.aead_alg.key_len(), - ); - let (server_key, server_iv) = expand_secret( - &self.current_server_traffic_secret, - self.ks.suite.hkdf_provider, - self.ks.suite.aead_alg.key_len(), - ); - let client_secrets = self - .ks - .suite - .aead_alg - .extract_keys(client_key, client_iv)?; - let server_secrets = self - .ks - .suite - .aead_alg - .extract_keys(server_key, server_iv)?; - - let (tx, rx) = match side { - Side::Client => (client_secrets, server_secrets), - Side::Server => (server_secrets, client_secrets), - }; - Ok(PartiallyExtractedSecrets { tx, rx }) - } -} - -pub(crate) struct KeyScheduleResumption { - ks: KeyScheduleSuite, - resumption_master_secret: OkmBlock, -} - -impl KeyScheduleResumption { - pub(crate) fn derive_ticket_psk(&self, nonce: &[u8]) -> OkmBlock { - self.ks - .derive_ticket_psk(&self.resumption_master_secret, nonce) - } -} - -fn expand_secret(secret: &OkmBlock, hkdf: &'static dyn Hkdf, aead_key_len: usize) -> (AeadKey, Iv) { - let expander = hkdf.expander_for_okm(secret); - - ( - hkdf_expand_label_aead_key(expander.as_ref(), aead_key_len, b"key", &[]), - hkdf_expand_label(expander.as_ref(), b"iv", &[]), - ) -} - -/// This is the TLS1.3 key schedule. It stores the current secret and -/// the type of hash. This isn't used directly; but only through the -/// typestates. -struct KeySchedule { - current: Box<dyn HkdfExpander>, - inner: KeyScheduleSuite, -} - -impl KeySchedule { - fn new(suite: &'static Tls13CipherSuite, secret: &[u8]) -> Self { - Self { - current: suite - .hkdf_provider - .extract_from_secret(None, secret), - inner: suite.into(), - } - } - - /// Creates a key schedule without a PSK. - fn new_with_empty_secret(suite: &'static Tls13CipherSuite) -> Self { - Self { - current: suite - .hkdf_provider - .extract_from_zero_ikm(None), - inner: suite.into(), - } - } - - /// Input the empty secret. - /// - /// RFC 8446: "If a given secret is not available, then the - /// 0-value consisting of a string of Hash.length bytes set - /// to zeros is used." - fn input_empty(&mut self) { - let salt = self.derive_for_empty_hash(SecretKind::DerivedSecret); - self.current = self - .suite - .hkdf_provider - .extract_from_zero_ikm(Some(salt.as_ref())); - } - - /// Input the given secret. - fn input_secret(&mut self, secret: &[u8]) { - let salt = self.derive_for_empty_hash(SecretKind::DerivedSecret); - self.current = self - .suite - .hkdf_provider - .extract_from_secret(Some(salt.as_ref()), secret); - } - - /// Derive a secret of given `kind`, using current handshake hash `hs_hash`. - /// - /// More specifically - /// ```text - /// Derive-Secret(., "derived", Messages) - /// ``` - /// where `hs_hash` is `Messages`. - fn derive(&self, kind: SecretKind, hs_hash: &[u8]) -> OkmBlock { - hkdf_expand_label_block(self.current.as_ref(), kind.to_bytes(), hs_hash) - } - - fn derive_logged_secret( - &self, - kind: SecretKind, - hs_hash: &[u8], - key_log: &dyn KeyLog, - client_random: &[u8; 32], - ) -> OkmBlock { - let output = self.derive(kind, hs_hash); - - let log_label = kind - .log_label() - .expect("not a loggable secret"); - if key_log.will_log(log_label) { - key_log.log(log_label, client_random, output.as_ref()); - } - output - } - - /// Derive a secret of given `kind` using the hash of the empty string - /// for the handshake hash. - /// - /// More specifically: - /// ```text - /// Derive-Secret(., Label, "") - /// ``` - /// where `kind` is `Label`. - /// - /// Useful only for the following `SecretKind`s: - /// - `SecretKind::ExternalPskBinderKey` - /// - `SecretKind::ResumptionPSKBinderKey` - /// - `SecretKind::DerivedSecret` - fn derive_for_empty_hash(&self, kind: SecretKind) -> OkmBlock { - let hp = self.suite.common.hash_provider; - let empty_hash = hp - .algorithm() - .hash_for_empty_input() - .unwrap_or_else(|| hp.start().finish()); - self.derive(kind, empty_hash.as_ref()) - } -} - -impl Deref for KeySchedule { - type Target = KeyScheduleSuite; - - fn deref(&self) -> &Self::Target { - &self.inner - } -} - -/// This is a component part of `KeySchedule`, and groups operations -/// that do not depend on the root key schedule secret. -#[derive(Clone, Copy)] -struct KeyScheduleSuite { - suite: &'static Tls13CipherSuite, -} - -impl KeyScheduleSuite { - fn set_encrypter(&self, secret: &OkmBlock, common: &mut CommonState) { - let expander = self - .suite - .hkdf_provider - .expander_for_okm(secret); - let key = derive_traffic_key(expander.as_ref(), self.suite.aead_alg); - let iv = derive_traffic_iv(expander.as_ref()); - - common - .record_layer - .set_message_encrypter( - self.suite.aead_alg.encrypter(key, iv), - self.suite.common.confidentiality_limit, - ); - } - - fn set_decrypter(&self, secret: &OkmBlock, common: &mut CommonState) { - common - .record_layer - .set_message_decrypter(self.derive_decrypter(secret)); - } - - fn derive_decrypter(&self, secret: &OkmBlock) -> Box<dyn MessageDecrypter> { - let expander = self - .suite - .hkdf_provider - .expander_for_okm(secret); - let key = derive_traffic_key(expander.as_ref(), self.suite.aead_alg); - let iv = derive_traffic_iv(expander.as_ref()); - self.suite.aead_alg.decrypter(key, iv) - } - - /// Sign the finished message consisting of `hs_hash` using a current - /// traffic secret. - /// - /// See RFC 8446 section 4.4.4. - fn sign_finish(&self, base_key: &OkmBlock, hs_hash: &hash::Output) -> hmac::Tag { - self.sign_verify_data(base_key, hs_hash) - } - - /// Sign the finished message consisting of `hs_hash` using the key material - /// `base_key`. - /// - /// See RFC 8446 section 4.4.4. - fn sign_verify_data(&self, base_key: &OkmBlock, hs_hash: &hash::Output) -> hmac::Tag { - let expander = self - .suite - .hkdf_provider - .expander_for_okm(base_key); - let hmac_key = hkdf_expand_label_block(expander.as_ref(), b"finished", &[]); - - self.suite - .hkdf_provider - .hmac_sign(&hmac_key, hs_hash.as_ref()) - } - - /// Derive the next application traffic secret, returning it. - fn derive_next(&self, base_key: &OkmBlock) -> OkmBlock { - let expander = self - .suite - .hkdf_provider - .expander_for_okm(base_key); - hkdf_expand_label_block(expander.as_ref(), b"traffic upd", &[]) - } - - /// Derive the PSK to use given a resumption_master_secret and - /// ticket_nonce. - fn derive_ticket_psk(&self, rms: &OkmBlock, nonce: &[u8]) -> OkmBlock { - let expander = self - .suite - .hkdf_provider - .expander_for_okm(rms); - hkdf_expand_label_block(expander.as_ref(), b"resumption", nonce) - } - - fn export_keying_material( - &self, - current_exporter_secret: &OkmBlock, - out: &mut [u8], - label: &[u8], - context: Option<&[u8]>, - ) -> Result<(), Error> { - let secret = { - let h_empty = self - .suite - .common - .hash_provider - .hash(&[]); - - let expander = self - .suite - .hkdf_provider - .expander_for_okm(current_exporter_secret); - hkdf_expand_label_block(expander.as_ref(), label, h_empty.as_ref()) - }; - - let h_context = self - .suite - .common - .hash_provider - .hash(context.unwrap_or(&[])); - - let expander = self - .suite - .hkdf_provider - .expander_for_okm(&secret); - hkdf_expand_label_slice(expander.as_ref(), b"exporter", h_context.as_ref(), out) - .map_err(|_| Error::General("exporting too much".to_string())) - } -} - -impl From<&'static Tls13CipherSuite> for KeyScheduleSuite { - fn from(suite: &'static Tls13CipherSuite) -> Self { - Self { suite } - } -} - -/// [HKDF-Expand-Label] where the output is an AEAD key. -/// -/// [HKDF-Expand-Label]: <https://www.rfc-editor.org/rfc/rfc8446#section-7.1> -pub fn derive_traffic_key( - expander: &dyn HkdfExpander, - aead_alg: &dyn Tls13AeadAlgorithm, -) -> AeadKey { - hkdf_expand_label_aead_key(expander, aead_alg.key_len(), b"key", &[]) -} - -/// [HKDF-Expand-Label] where the output is an IV. -/// -/// [HKDF-Expand-Label]: <https://www.rfc-editor.org/rfc/rfc8446#section-7.1> -pub fn derive_traffic_iv(expander: &dyn HkdfExpander) -> Iv { - hkdf_expand_label(expander, b"iv", &[]) -} - -/// [HKDF-Expand-Label] where the output length is a compile-time constant, and therefore -/// it is infallible. -/// -/// [HKDF-Expand-Label]: <https://www.rfc-editor.org/rfc/rfc8446#section-7.1> -pub(crate) fn hkdf_expand_label<T: From<[u8; N]>, const N: usize>( - expander: &dyn HkdfExpander, - label: &[u8], - context: &[u8], -) -> T { - hkdf_expand_label_inner(expander, label, context, N, |e, info| expand(e, info)) -} - -/// [HKDF-Expand-Label] where the output is one block in size. -pub(crate) fn hkdf_expand_label_block( - expander: &dyn HkdfExpander, - label: &[u8], - context: &[u8], -) -> OkmBlock { - hkdf_expand_label_inner(expander, label, context, expander.hash_len(), |e, info| { - e.expand_block(info) - }) -} - -/// [HKDF-Expand-Label] where the output is an AEAD key. -pub(crate) fn hkdf_expand_label_aead_key( - expander: &dyn HkdfExpander, - key_len: usize, - label: &[u8], - context: &[u8], -) -> AeadKey { - hkdf_expand_label_inner(expander, label, context, key_len, |e, info| { - let key: AeadKey = expand(e, info); - key.with_length(key_len) - }) -} - -/// [HKDF-Expand-Label] where the output is a slice. -/// -/// This can fail because HKDF-Expand is limited in its maximum output length. -fn hkdf_expand_label_slice( - expander: &dyn HkdfExpander, - label: &[u8], - context: &[u8], - output: &mut [u8], -) -> Result<(), OutputLengthError> { - hkdf_expand_label_inner(expander, label, context, output.len(), |e, info| { - e.expand_slice(info, output) - }) -} - -pub(crate) fn server_ech_hrr_confirmation_secret( - hkdf_provider: &'static dyn Hkdf, - client_hello_inner_random: &[u8], - hs_hash: hash::Output, -) -> [u8; 8] { - /* - Per ietf-tls-esni-17 section 7.2.1: - <https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-17#section-7.2.1> - hrr_accept_confirmation = HKDF-Expand-Label( - HKDF-Extract(0, ClientHelloInner1.random), - "hrr ech accept confirmation", - transcript_hrr_ech_conf, - 8) - */ - hkdf_expand_label( - hkdf_provider - .extract_from_secret(None, client_hello_inner_random) - .as_ref(), - SecretKind::ServerEchHrrConfirmationSecret.to_bytes(), - hs_hash.as_ref(), - ) -} - -fn hkdf_expand_label_inner<F, T>( - expander: &dyn HkdfExpander, - label: &[u8], - context: &[u8], - n: usize, - f: F, -) -> T -where - F: FnOnce(&dyn HkdfExpander, &[&[u8]]) -> T, -{ - const LABEL_PREFIX: &[u8] = b"tls13 "; - - let output_len = u16::to_be_bytes(n as u16); - let label_len = u8::to_be_bytes((LABEL_PREFIX.len() + label.len()) as u8); - let context_len = u8::to_be_bytes(context.len() as u8); - - let info = &[ - &output_len[..], - &label_len[..], - LABEL_PREFIX, - label, - &context_len[..], - context, - ]; - - f(expander, info) -} - -/// The kinds of secret we can extract from `KeySchedule`. -#[derive(Debug, Clone, Copy, PartialEq)] -enum SecretKind { - ResumptionPskBinderKey, - ClientEarlyTrafficSecret, - ClientHandshakeTrafficSecret, - ServerHandshakeTrafficSecret, - ClientApplicationTrafficSecret, - ServerApplicationTrafficSecret, - ExporterMasterSecret, - ResumptionMasterSecret, - DerivedSecret, - ServerEchConfirmationSecret, - ServerEchHrrConfirmationSecret, -} - -impl SecretKind { - fn to_bytes(self) -> &'static [u8] { - use self::SecretKind::*; - match self { - ResumptionPskBinderKey => b"res binder", - ClientEarlyTrafficSecret => b"c e traffic", - ClientHandshakeTrafficSecret => b"c hs traffic", - ServerHandshakeTrafficSecret => b"s hs traffic", - ClientApplicationTrafficSecret => b"c ap traffic", - ServerApplicationTrafficSecret => b"s ap traffic", - ExporterMasterSecret => b"exp master", - ResumptionMasterSecret => b"res master", - DerivedSecret => b"derived", - // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-7.2 - ServerEchConfirmationSecret => b"ech accept confirmation", - // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-7.2.1 - ServerEchHrrConfirmationSecret => b"hrr ech accept confirmation", - } - } - - fn log_label(self) -> Option<&'static str> { - use self::SecretKind::*; - Some(match self { - ClientEarlyTrafficSecret => "CLIENT_EARLY_TRAFFIC_SECRET", - ClientHandshakeTrafficSecret => "CLIENT_HANDSHAKE_TRAFFIC_SECRET", - ServerHandshakeTrafficSecret => "SERVER_HANDSHAKE_TRAFFIC_SECRET", - ClientApplicationTrafficSecret => "CLIENT_TRAFFIC_SECRET_0", - ServerApplicationTrafficSecret => "SERVER_TRAFFIC_SECRET_0", - ExporterMasterSecret => "EXPORTER_SECRET", - _ => { - return None; - } - }) - } -} - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use core::fmt::Debug; - use std::prelude::v1::*; - use std::vec; - - use super::provider::ring_like::aead; - use super::provider::tls13::{ - TLS13_AES_128_GCM_SHA256_INTERNAL, TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, - }; - use super::{KeySchedule, SecretKind, derive_traffic_iv, derive_traffic_key}; - use crate::KeyLog; - use crate::msgs::enums::HashAlgorithm; - - #[test] - fn empty_hash() { - let sha256 = super::provider::tls13::TLS13_AES_128_GCM_SHA256 - .tls13() - .unwrap() - .common - .hash_provider; - let sha384 = super::provider::tls13::TLS13_AES_256_GCM_SHA384 - .tls13() - .unwrap() - .common - .hash_provider; - - assert!( - sha256.start().finish().as_ref() - == HashAlgorithm::SHA256 - .hash_for_empty_input() - .unwrap() - .as_ref() - ); - assert!( - sha384.start().finish().as_ref() - == HashAlgorithm::SHA384 - .hash_for_empty_input() - .unwrap() - .as_ref() - ); - - // a theoretical example of unsupported hash - assert!( - HashAlgorithm::SHA1 - .hash_for_empty_input() - .is_none() - ); - } - - #[test] - fn test_vectors() { - /* These test vectors generated with OpenSSL. */ - let hs_start_hash = [ - 0xec, 0x14, 0x7a, 0x06, 0xde, 0xa3, 0xc8, 0x84, 0x6c, 0x02, 0xb2, 0x23, 0x8e, 0x41, - 0xbd, 0xdc, 0x9d, 0x89, 0xf9, 0xae, 0xa1, 0x7b, 0x5e, 0xfd, 0x4d, 0x74, 0x82, 0xaf, - 0x75, 0x88, 0x1c, 0x0a, - ]; - - let hs_full_hash = [ - 0x75, 0x1a, 0x3d, 0x4a, 0x14, 0xdf, 0xab, 0xeb, 0x68, 0xe9, 0x2c, 0xa5, 0x91, 0x8e, - 0x24, 0x08, 0xb9, 0xbc, 0xb0, 0x74, 0x89, 0x82, 0xec, 0x9c, 0x32, 0x30, 0xac, 0x30, - 0xbb, 0xeb, 0x23, 0xe2, - ]; - - let ecdhe_secret = [ - 0xe7, 0xb8, 0xfe, 0xf8, 0x90, 0x3b, 0x52, 0x0c, 0xb9, 0xa1, 0x89, 0x71, 0xb6, 0x9d, - 0xd4, 0x5d, 0xca, 0x53, 0xce, 0x2f, 0x12, 0xbf, 0x3b, 0xef, 0x93, 0x15, 0xe3, 0x12, - 0x71, 0xdf, 0x4b, 0x40, - ]; - - let client_hts = [ - 0x61, 0x7b, 0x35, 0x07, 0x6b, 0x9d, 0x0e, 0x08, 0xcf, 0x73, 0x1d, 0x94, 0xa8, 0x66, - 0x14, 0x78, 0x41, 0x09, 0xef, 0x25, 0x55, 0x51, 0x92, 0x1d, 0xd4, 0x6e, 0x04, 0x01, - 0x35, 0xcf, 0x46, 0xab, - ]; - - let client_hts_key = [ - 0x62, 0xd0, 0xdd, 0x00, 0xf6, 0x96, 0x19, 0xd3, 0xb8, 0x19, 0x3a, 0xb4, 0xa0, 0x95, - 0x85, 0xa7, - ]; - - let client_hts_iv = [ - 0xff, 0xf7, 0x5d, 0xf5, 0xad, 0x35, 0xd5, 0xcb, 0x3c, 0x53, 0xf3, 0xa9, - ]; - - let server_hts = [ - 0xfc, 0xf7, 0xdf, 0xe6, 0x4f, 0xa2, 0xc0, 0x4f, 0x62, 0x35, 0x38, 0x7f, 0x43, 0x4e, - 0x01, 0x42, 0x23, 0x36, 0xd9, 0xc0, 0x39, 0xde, 0x68, 0x47, 0xa0, 0xb9, 0xdd, 0xcf, - 0x29, 0xa8, 0x87, 0x59, - ]; - - let server_hts_key = [ - 0x04, 0x67, 0xf3, 0x16, 0xa8, 0x05, 0xb8, 0xc4, 0x97, 0xee, 0x67, 0x04, 0x7b, 0xbc, - 0xbc, 0x54, - ]; - - let server_hts_iv = [ - 0xde, 0x83, 0xa7, 0x3e, 0x9d, 0x81, 0x4b, 0x04, 0xc4, 0x8b, 0x78, 0x09, - ]; - - let client_ats = [ - 0xc1, 0x4a, 0x6d, 0x79, 0x76, 0xd8, 0x10, 0x2b, 0x5a, 0x0c, 0x99, 0x51, 0x49, 0x3f, - 0xee, 0x87, 0xdc, 0xaf, 0xf8, 0x2c, 0x24, 0xca, 0xb2, 0x14, 0xe8, 0xbe, 0x71, 0xa8, - 0x20, 0x6d, 0xbd, 0xa5, - ]; - - let client_ats_key = [ - 0xcc, 0x9f, 0x5f, 0x98, 0x0b, 0x5f, 0x10, 0x30, 0x6c, 0xba, 0xd7, 0xbe, 0x98, 0xd7, - 0x57, 0x2e, - ]; - - let client_ats_iv = [ - 0xb8, 0x09, 0x29, 0xe8, 0xd0, 0x2c, 0x70, 0xf6, 0x11, 0x62, 0xed, 0x6b, - ]; - - let server_ats = [ - 0x2c, 0x90, 0x77, 0x38, 0xd3, 0xf8, 0x37, 0x02, 0xd1, 0xe4, 0x59, 0x8f, 0x48, 0x48, - 0x53, 0x1d, 0x9f, 0x93, 0x65, 0x49, 0x1b, 0x9f, 0x7f, 0x52, 0xc8, 0x22, 0x29, 0x0d, - 0x4c, 0x23, 0x21, 0x92, - ]; - - let server_ats_key = [ - 0x0c, 0xb2, 0x95, 0x62, 0xd8, 0xd8, 0x8f, 0x48, 0xb0, 0x2c, 0xbf, 0xbe, 0xd7, 0xe6, - 0x2b, 0xb3, - ]; - - let server_ats_iv = [ - 0x0d, 0xb2, 0x8f, 0x98, 0x85, 0x86, 0xa1, 0xb7, 0xe4, 0xd5, 0xc6, 0x9c, - ]; - - let mut ks = KeySchedule::new_with_empty_secret(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); - ks.input_secret(&ecdhe_secret); - - assert_traffic_secret( - &ks, - SecretKind::ClientHandshakeTrafficSecret, - &hs_start_hash, - &client_hts, - &client_hts_key, - &client_hts_iv, - ); - - assert_traffic_secret( - &ks, - SecretKind::ServerHandshakeTrafficSecret, - &hs_start_hash, - &server_hts, - &server_hts_key, - &server_hts_iv, - ); - - ks.input_empty(); - - assert_traffic_secret( - &ks, - SecretKind::ClientApplicationTrafficSecret, - &hs_full_hash, - &client_ats, - &client_ats_key, - &client_ats_iv, - ); - - assert_traffic_secret( - &ks, - SecretKind::ServerApplicationTrafficSecret, - &hs_full_hash, - &server_ats, - &server_ats_key, - &server_ats_iv, - ); - } - - fn assert_traffic_secret( - ks: &KeySchedule, - kind: SecretKind, - hash: &[u8], - expected_traffic_secret: &[u8], - expected_key: &[u8], - expected_iv: &[u8], - ) { - #[derive(Debug)] - struct Log<'a>(&'a [u8]); - impl KeyLog for Log<'_> { - fn log(&self, _label: &str, _client_random: &[u8], secret: &[u8]) { - assert_eq!(self.0, secret); - } - } - let log = Log(expected_traffic_secret); - let traffic_secret = ks.derive_logged_secret(kind, hash, &log, &[0; 32]); - - // Since we can't test key equality, we test the output of sealing with the key instead. - let aead_alg = &aead::AES_128_GCM; - let expander = TLS13_AES_128_GCM_SHA256_INTERNAL - .hkdf_provider - .expander_for_okm(&traffic_secret); - let key = derive_traffic_key( - expander.as_ref(), - TLS13_AES_128_GCM_SHA256_INTERNAL.aead_alg, - ); - let key = aead::UnboundKey::new(aead_alg, key.as_ref()).unwrap(); - let seal_output = seal_zeroes(key); - let expected_key = aead::UnboundKey::new(aead_alg, expected_key).unwrap(); - let expected_seal_output = seal_zeroes(expected_key); - assert_eq!(seal_output, expected_seal_output); - assert!(seal_output.len() >= 48); // Sanity check. - - let iv = derive_traffic_iv(expander.as_ref()); - assert_eq!(iv.as_ref(), expected_iv); - } - - fn seal_zeroes(key: aead::UnboundKey) -> Vec<u8> { - let key = aead::LessSafeKey::new(key); - let mut seal_output = vec![0; 32]; - key.seal_in_place_append_tag( - aead::Nonce::assume_unique_for_key([0; aead::NONCE_LEN]), - aead::Aad::empty(), - &mut seal_output, - ) - .unwrap(); - seal_output - } -} - -#[cfg(all(test, bench))] -#[macro_rules_attribute::apply(bench_for_each_provider)] -mod benchmarks { - #[bench] - fn bench_sha256(b: &mut test::Bencher) { - use core::fmt::Debug; - - use super::provider::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; - use super::{KeySchedule, SecretKind, derive_traffic_iv, derive_traffic_key}; - use crate::KeyLog; - - fn extract_traffic_secret(ks: &KeySchedule, kind: SecretKind) { - #[derive(Debug)] - struct Log; - - impl KeyLog for Log { - fn log(&self, _label: &str, _client_random: &[u8], _secret: &[u8]) {} - } - - let hash = [0u8; 32]; - let traffic_secret = ks.derive_logged_secret(kind, &hash, &Log, &[0u8; 32]); - let traffic_secret_expander = TLS13_CHACHA20_POLY1305_SHA256_INTERNAL - .hkdf_provider - .expander_for_okm(&traffic_secret); - test::black_box(derive_traffic_key( - traffic_secret_expander.as_ref(), - TLS13_CHACHA20_POLY1305_SHA256_INTERNAL.aead_alg, - )); - test::black_box(derive_traffic_iv(traffic_secret_expander.as_ref())); - } - - b.iter(|| { - let mut ks = - KeySchedule::new_with_empty_secret(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); - ks.input_secret(&[0u8; 32]); - - extract_traffic_secret(&ks, SecretKind::ClientHandshakeTrafficSecret); - extract_traffic_secret(&ks, SecretKind::ServerHandshakeTrafficSecret); - - ks.input_empty(); - - extract_traffic_secret(&ks, SecretKind::ClientApplicationTrafficSecret); - extract_traffic_secret(&ks, SecretKind::ServerApplicationTrafficSecret); - }); - } -} diff --git a/vendor/rustls/src/tls13/mod.rs b/vendor/rustls/src/tls13/mod.rs deleted file mode 100644 index ab55c889..00000000 --- a/vendor/rustls/src/tls13/mod.rs +++ /dev/null @@ -1,125 +0,0 @@ -use core::fmt; - -use crate::crypto; -use crate::crypto::hash; -use crate::suites::{CipherSuiteCommon, SupportedCipherSuite}; - -pub(crate) mod key_schedule; - -/// A TLS 1.3 cipher suite supported by rustls. -pub struct Tls13CipherSuite { - /// Common cipher suite fields. - pub common: CipherSuiteCommon, - - /// How to complete HKDF with the suite's hash function. - /// - /// If you have a HKDF implementation, you should directly implement the `crypto::tls13::Hkdf` - /// trait (and associated). - /// - /// If not, you can implement the [`crypto::hmac::Hmac`] trait (and associated), and then use - /// [`crypto::tls13::HkdfUsingHmac`]. - pub hkdf_provider: &'static dyn crypto::tls13::Hkdf, - - /// How to produce a [MessageDecrypter] or [MessageEncrypter] - /// from raw key material. - /// - /// [MessageDecrypter]: crate::crypto::cipher::MessageDecrypter - /// [MessageEncrypter]: crate::crypto::cipher::MessageEncrypter - pub aead_alg: &'static dyn crypto::cipher::Tls13AeadAlgorithm, - - /// How to create QUIC header and record protection algorithms - /// for this suite. - /// - /// Provide `None` to opt out of QUIC support for this suite. It will - /// not be offered in QUIC handshakes. - pub quic: Option<&'static dyn crate::quic::Algorithm>, -} - -impl Tls13CipherSuite { - /// Can a session using suite self resume from suite prev? - pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> { - (prev.common.hash_provider.algorithm() == self.common.hash_provider.algorithm()) - .then_some(prev) - } - - /// Return `true` if this is backed by a FIPS-approved implementation. - /// - /// This means all the constituent parts that do cryptography return `true` for `fips()`. - pub fn fips(&self) -> bool { - let Self { - common, - hkdf_provider, - aead_alg, - quic, - } = self; - common.fips() - && hkdf_provider.fips() - && aead_alg.fips() - && quic.map(|q| q.fips()).unwrap_or(true) - } - - /// Returns a `quic::Suite` for the ciphersuite, if supported. - pub fn quic_suite(&'static self) -> Option<crate::quic::Suite> { - self.quic - .map(|quic| crate::quic::Suite { quic, suite: self }) - } -} - -impl From<&'static Tls13CipherSuite> for SupportedCipherSuite { - fn from(s: &'static Tls13CipherSuite) -> Self { - Self::Tls13(s) - } -} - -impl PartialEq for Tls13CipherSuite { - fn eq(&self, other: &Self) -> bool { - self.common.suite == other.common.suite - } -} - -impl fmt::Debug for Tls13CipherSuite { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Tls13CipherSuite") - .field("suite", &self.common.suite) - .finish() - } -} - -/// Constructs the signature message specified in section 4.4.3 of RFC8446. -pub(crate) fn construct_client_verify_message(handshake_hash: &hash::Output) -> VerifyMessage { - VerifyMessage::new(handshake_hash, CLIENT_CONSTANT) -} - -/// Constructs the signature message specified in section 4.4.3 of RFC8446. -pub(crate) fn construct_server_verify_message(handshake_hash: &hash::Output) -> VerifyMessage { - VerifyMessage::new(handshake_hash, SERVER_CONSTANT) -} - -pub(crate) struct VerifyMessage { - buf: [u8; MAX_VERIFY_MSG], - used: usize, -} - -impl VerifyMessage { - fn new(handshake_hash: &hash::Output, context_string_with_0: &[u8; 34]) -> Self { - let used = 64 + context_string_with_0.len() + handshake_hash.as_ref().len(); - let mut buf = [0x20u8; MAX_VERIFY_MSG]; - - let (_spaces, context) = buf.split_at_mut(64); - let (context, hash) = context.split_at_mut(34); - context.copy_from_slice(context_string_with_0); - hash[..handshake_hash.as_ref().len()].copy_from_slice(handshake_hash.as_ref()); - - Self { buf, used } - } -} - -impl AsRef<[u8]> for VerifyMessage { - fn as_ref(&self) -> &[u8] { - &self.buf[..self.used] - } -} - -const SERVER_CONSTANT: &[u8; 34] = b"TLS 1.3, server CertificateVerify\x00"; -const CLIENT_CONSTANT: &[u8; 34] = b"TLS 1.3, client CertificateVerify\x00"; -const MAX_VERIFY_MSG: usize = 64 + CLIENT_CONSTANT.len() + hash::Output::MAX_LEN; diff --git a/vendor/rustls/src/vecbuf.rs b/vendor/rustls/src/vecbuf.rs deleted file mode 100644 index 8a4a1f3e..00000000 --- a/vendor/rustls/src/vecbuf.rs +++ /dev/null @@ -1,374 +0,0 @@ -use alloc::collections::VecDeque; -use alloc::vec::Vec; -use core::{cmp, mem}; -#[cfg(feature = "std")] -use std::io; -#[cfg(feature = "std")] -use std::io::Read; - -#[cfg(feature = "std")] -use crate::msgs::message::OutboundChunks; - -/// This is a byte buffer that is built from a deque of byte vectors. -/// -/// This avoids extra copies when appending a new byte vector, -/// at the expense of more complexity when reading out. -pub(crate) struct ChunkVecBuffer { - /// How many bytes have been consumed in the first chunk. - /// - /// Invariant: zero if `chunks.is_empty()` - /// Invariant: 0 <= `prefix_used` < `chunks[0].len()` - prefix_used: usize, - - chunks: VecDeque<Vec<u8>>, - - /// The total upper limit (in bytes) of this object. - limit: Option<usize>, -} - -impl ChunkVecBuffer { - pub(crate) fn new(limit: Option<usize>) -> Self { - Self { - prefix_used: 0, - chunks: VecDeque::new(), - limit, - } - } - - /// Sets the upper limit on how many bytes this - /// object can store. - /// - /// Setting a lower limit than the currently stored - /// data is not an error. - /// - /// A [`None`] limit is interpreted as no limit. - pub(crate) fn set_limit(&mut self, new_limit: Option<usize>) { - self.limit = new_limit; - } - - /// If we're empty - pub(crate) fn is_empty(&self) -> bool { - self.chunks.is_empty() - } - - /// How many bytes we're storing - pub(crate) fn len(&self) -> usize { - self.chunks - .iter() - .fold(0usize, |acc, chunk| acc + chunk.len()) - - self.prefix_used - } - - /// For a proposed append of `len` bytes, how many - /// bytes should we actually append to adhere to the - /// currently set `limit`? - pub(crate) fn apply_limit(&self, len: usize) -> usize { - if let Some(limit) = self.limit { - let space = limit.saturating_sub(self.len()); - cmp::min(len, space) - } else { - len - } - } - - /// Take and append the given `bytes`. - pub(crate) fn append(&mut self, bytes: Vec<u8>) -> usize { - let len = bytes.len(); - - if !bytes.is_empty() { - if self.chunks.is_empty() { - debug_assert_eq!(self.prefix_used, 0); - } - - self.chunks.push_back(bytes); - } - - len - } - - /// Take one of the chunks from this object. - /// - /// This function returns `None` if the object `is_empty`. - pub(crate) fn pop(&mut self) -> Option<Vec<u8>> { - let mut first = self.chunks.pop_front(); - - if let Some(first) = &mut first { - // slice off `prefix_used` if needed (uncommon) - let prefix = mem::take(&mut self.prefix_used); - first.drain(0..prefix); - } - - first - } - - #[cfg(read_buf)] - /// Read data out of this object, writing it into `cursor`. - pub(crate) fn read_buf(&mut self, mut cursor: core::io::BorrowedCursor<'_>) -> io::Result<()> { - while !self.is_empty() && cursor.capacity() > 0 { - let chunk = &self.chunks[0][self.prefix_used..]; - let used = cmp::min(chunk.len(), cursor.capacity()); - cursor.append(&chunk[..used]); - self.consume(used); - } - - Ok(()) - } - - /// Inspect the first chunk from this object. - pub(crate) fn peek(&self) -> Option<&[u8]> { - self.chunks - .front() - .map(|ch| ch.as_slice()) - } -} - -#[cfg(feature = "std")] -impl ChunkVecBuffer { - pub(crate) fn is_full(&self) -> bool { - self.limit - .map(|limit| self.len() > limit) - .unwrap_or_default() - } - - /// Append a copy of `bytes`, perhaps a prefix if - /// we're near the limit. - pub(crate) fn append_limited_copy(&mut self, payload: OutboundChunks<'_>) -> usize { - let take = self.apply_limit(payload.len()); - self.append(payload.split_at(take).0.to_vec()); - take - } - - /// Read data out of this object, writing it into `buf` - /// and returning how many bytes were written there. - pub(crate) fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - let mut offs = 0; - - while offs < buf.len() && !self.is_empty() { - let used = (&self.chunks[0][self.prefix_used..]).read(&mut buf[offs..])?; - - self.consume(used); - offs += used; - } - - Ok(offs) - } - - pub(crate) fn consume_first_chunk(&mut self, used: usize) { - // this backs (infallible) `BufRead::consume`, where `used` is - // user-supplied. - assert!( - used <= self - .chunk() - .map(|ch| ch.len()) - .unwrap_or_default(), - "illegal `BufRead::consume` usage", - ); - self.consume(used); - } - - fn consume(&mut self, used: usize) { - // first, mark the rightmost extent of the used buffer - self.prefix_used += used; - - // then reduce `prefix_used` by discarding wholly-covered - // buffers - while let Some(buf) = self.chunks.front() { - if self.prefix_used < buf.len() { - return; - } else { - self.prefix_used -= buf.len(); - self.chunks.pop_front(); - } - } - - debug_assert_eq!( - self.prefix_used, 0, - "attempted to `ChunkVecBuffer::consume` more than available" - ); - } - - /// Read data out of this object, passing it `wr` - pub(crate) fn write_to(&mut self, wr: &mut dyn io::Write) -> io::Result<usize> { - if self.is_empty() { - return Ok(0); - } - - let mut prefix = self.prefix_used; - let mut bufs = [io::IoSlice::new(&[]); 64]; - for (iov, chunk) in bufs.iter_mut().zip(self.chunks.iter()) { - *iov = io::IoSlice::new(&chunk[prefix..]); - prefix = 0; - } - let len = cmp::min(bufs.len(), self.chunks.len()); - let bufs = &bufs[..len]; - let used = wr.write_vectored(bufs)?; - let available_bytes = bufs.iter().map(|ch| ch.len()).sum(); - - if used > available_bytes { - // This is really unrecoverable, since the amount of data written - // is now unknown. Consume all the potentially-written data in - // case the caller ignores the error. - // See <https://github.com/rustls/rustls/issues/2316> for background. - self.consume(available_bytes); - return Err(io::Error::new( - io::ErrorKind::Other, - std::format!("illegal write_vectored return value ({used} > {available_bytes})"), - )); - } - self.consume(used); - Ok(used) - } - - /// Returns the first contiguous chunk of data, or None if empty. - pub(crate) fn chunk(&self) -> Option<&[u8]> { - self.chunks - .front() - .map(|chunk| &chunk[self.prefix_used..]) - } -} - -#[cfg(all(test, feature = "std"))] -mod tests { - use alloc::vec; - use alloc::vec::Vec; - - use super::ChunkVecBuffer; - - #[test] - fn short_append_copy_with_limit() { - let mut cvb = ChunkVecBuffer::new(Some(12)); - assert_eq!(cvb.append_limited_copy(b"hello"[..].into()), 5); - assert_eq!(cvb.append_limited_copy(b"world"[..].into()), 5); - assert_eq!(cvb.append_limited_copy(b"hello"[..].into()), 2); - assert_eq!(cvb.append_limited_copy(b"world"[..].into()), 0); - - let mut buf = [0u8; 12]; - assert_eq!(cvb.read(&mut buf).unwrap(), 12); - assert_eq!(buf.to_vec(), b"helloworldhe".to_vec()); - } - - #[test] - fn read_byte_by_byte() { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(b"test fixture data".to_vec()); - assert!(!cvb.is_empty()); - for expect in b"test fixture data" { - let mut byte = [0]; - assert_eq!(cvb.read(&mut byte).unwrap(), 1); - assert_eq!(byte[0], *expect); - } - - assert_eq!(cvb.read(&mut [0]).unwrap(), 0); - } - - #[test] - fn every_possible_chunk_interleaving() { - let input = (0..=0xffu8) - .cycle() - .take(4096) - .collect::<Vec<u8>>(); - - for input_chunk_len in 1..64usize { - for output_chunk_len in 1..65usize { - std::println!("check input={input_chunk_len} output={output_chunk_len}"); - let mut cvb = ChunkVecBuffer::new(None); - for chunk in input.chunks(input_chunk_len) { - cvb.append(chunk.to_vec()); - } - - assert_eq!(cvb.len(), input.len()); - let mut buf = vec![0u8; output_chunk_len]; - - for expect in input.chunks(output_chunk_len) { - assert_eq!(expect.len(), cvb.read(&mut buf).unwrap()); - assert_eq!(expect, &buf[..expect.len()]); - } - - assert_eq!(cvb.read(&mut [0]).unwrap(), 0); - } - } - } - - #[cfg(read_buf)] - #[test] - fn read_buf() { - use core::io::BorrowedBuf; - use core::mem::MaybeUninit; - - { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(b"test ".to_vec()); - cvb.append(b"fixture ".to_vec()); - cvb.append(b"data".to_vec()); - - let mut buf = [MaybeUninit::<u8>::uninit(); 8]; - let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); - cvb.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled(), b"test fix"); - buf.clear(); - cvb.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled(), b"ture dat"); - buf.clear(); - cvb.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled(), b"a"); - } - - { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(b"short message".to_vec()); - - let mut buf = [MaybeUninit::<u8>::uninit(); 1024]; - let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); - cvb.read_buf(buf.unfilled()).unwrap(); - assert_eq!(buf.filled(), b"short message"); - } - } -} - -#[cfg(bench)] -mod benchmarks { - use alloc::vec; - - use super::ChunkVecBuffer; - - #[bench] - fn read_one_byte_from_large_message(b: &mut test::Bencher) { - b.iter(|| { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(vec![0u8; 16_384]); - assert_eq!(1, cvb.read(&mut [0u8]).unwrap()); - }); - } - - #[bench] - fn read_all_individual_from_large_message(b: &mut test::Bencher) { - b.iter(|| { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(vec![0u8; 16_384]); - loop { - if let Ok(0) = cvb.read(&mut [0u8]) { - break; - } - } - }); - } - - #[bench] - fn read_half_bytes_from_large_message(b: &mut test::Bencher) { - b.iter(|| { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(vec![0u8; 16_384]); - assert_eq!(8192, cvb.read(&mut [0u8; 8192]).unwrap()); - assert_eq!(8192, cvb.read(&mut [0u8; 8192]).unwrap()); - }); - } - - #[bench] - fn read_entire_large_message(b: &mut test::Bencher) { - b.iter(|| { - let mut cvb = ChunkVecBuffer::new(None); - cvb.append(vec![0u8; 16_384]); - assert_eq!(16_384, cvb.read(&mut [0u8; 16_384]).unwrap()); - }); - } -} diff --git a/vendor/rustls/src/verify.rs b/vendor/rustls/src/verify.rs deleted file mode 100644 index ce07e3a0..00000000 --- a/vendor/rustls/src/verify.rs +++ /dev/null @@ -1,382 +0,0 @@ -use alloc::vec::Vec; -use core::fmt::Debug; - -use pki_types::{CertificateDer, ServerName, UnixTime}; - -use crate::enums::SignatureScheme; -use crate::error::{Error, InvalidMessage}; -use crate::msgs::base::PayloadU16; -use crate::msgs::codec::{Codec, Reader}; -use crate::msgs::handshake::DistinguishedName; - -// Marker types. These are used to bind the fact some verification -// (certificate chain or handshake signature) has taken place into -// protocol states. We use this to have the compiler check that there -// are no 'goto fail'-style elisions of important checks before we -// reach the traffic stage. -// -// These types are public, but cannot be directly constructed. This -// means their origins can be precisely determined by looking -// for their `assertion` constructors. - -/// Zero-sized marker type representing verification of a signature. -#[derive(Debug)] -pub struct HandshakeSignatureValid(()); - -impl HandshakeSignatureValid { - /// Make a `HandshakeSignatureValid` - pub fn assertion() -> Self { - Self(()) - } -} - -#[derive(Debug)] -pub(crate) struct FinishedMessageVerified(()); - -impl FinishedMessageVerified { - pub(crate) fn assertion() -> Self { - Self(()) - } -} - -/// Zero-sized marker type representing verification of a server cert chain. -#[allow(unreachable_pub)] -#[derive(Debug)] -pub struct ServerCertVerified(()); - -#[allow(unreachable_pub)] -impl ServerCertVerified { - /// Make a `ServerCertVerified` - pub fn assertion() -> Self { - Self(()) - } -} - -/// Zero-sized marker type representing verification of a client cert chain. -#[derive(Debug)] -pub struct ClientCertVerified(()); - -impl ClientCertVerified { - /// Make a `ClientCertVerified` - pub fn assertion() -> Self { - Self(()) - } -} - -/// Something that can verify a server certificate chain, and verify -/// signatures made by certificates. -#[allow(unreachable_pub)] -pub trait ServerCertVerifier: Debug + Send + Sync { - /// Verify the end-entity certificate `end_entity` is valid for the - /// hostname `dns_name` and chains to at least one trust anchor. - /// - /// `intermediates` contains all certificates other than `end_entity` that - /// were sent as part of the server's [Certificate] message. It is in the - /// same order that the server sent them and may be empty. - /// - /// Note that none of the certificates have been parsed yet, so it is the responsibility of - /// the implementer to handle invalid data. It is recommended that the implementer returns - /// [`Error::InvalidCertificate(CertificateError::BadEncoding)`] when these cases are encountered. - /// - /// [Certificate]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2 - fn verify_server_cert( - &self, - end_entity: &CertificateDer<'_>, - intermediates: &[CertificateDer<'_>], - server_name: &ServerName<'_>, - ocsp_response: &[u8], - now: UnixTime, - ) -> Result<ServerCertVerified, Error>; - - /// Verify a signature allegedly by the given server certificate. - /// - /// `message` is not hashed, and needs hashing during the verification. - /// The signature and algorithm are within `dss`. `cert` contains the - /// public key to use. - /// - /// `cert` has already been validated by [`ServerCertVerifier::verify_server_cert`]. - /// - /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. - /// Otherwise, return an error -- rustls will send an alert and abort the - /// connection. - /// - /// This method is only called for TLS1.2 handshakes. Note that, in TLS1.2, - /// SignatureSchemes such as `SignatureScheme::ECDSA_NISTP256_SHA256` are not - /// in fact bound to the specific curve implied in their name. - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error>; - - /// Verify a signature allegedly by the given server certificate. - /// - /// This method is only called for TLS1.3 handshakes. - /// - /// This method is very similar to `verify_tls12_signature`: but note the - /// tighter ECDSA SignatureScheme semantics -- e.g. `SignatureScheme::ECDSA_NISTP256_SHA256` - /// must only validate signatures using public keys on the right curve -- - /// rustls does not enforce this requirement for you. - /// - /// `cert` has already been validated by [`ServerCertVerifier::verify_server_cert`]. - /// - /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. - /// Otherwise, return an error -- rustls will send an alert and abort the - /// connection. - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error>; - - /// Return the list of SignatureSchemes that this verifier will handle, - /// in `verify_tls12_signature` and `verify_tls13_signature` calls. - /// - /// This should be in priority order, with the most preferred first. - fn supported_verify_schemes(&self) -> Vec<SignatureScheme>; - - /// Returns whether this verifier requires raw public keys as defined - /// in [RFC 7250](https://tools.ietf.org/html/rfc7250). - fn requires_raw_public_keys(&self) -> bool { - false - } - - /// Return the [`DistinguishedName`]s of certificate authorities that this verifier trusts. - /// - /// If specified, will be sent as the [`certificate_authorities`] extension in ClientHello. - /// Note that this is only applicable to TLS 1.3. - /// - /// [`certificate_authorities`]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.4 - fn root_hint_subjects(&self) -> Option<&[DistinguishedName]> { - None - } -} - -/// Something that can verify a client certificate chain -#[allow(unreachable_pub)] -pub trait ClientCertVerifier: Debug + Send + Sync { - /// Returns `true` to enable the server to request a client certificate and - /// `false` to skip requesting a client certificate. Defaults to `true`. - fn offer_client_auth(&self) -> bool { - true - } - - /// Return `true` to require a client certificate and `false` to make - /// client authentication optional. - /// Defaults to `self.offer_client_auth()`. - fn client_auth_mandatory(&self) -> bool { - self.offer_client_auth() - } - - /// Returns the [`DistinguishedName`] [subjects] that the server will hint to clients to - /// identify acceptable authentication trust anchors. - /// - /// These hint values help the client pick a client certificate it believes the server will - /// accept. The hints must be DER-encoded X.500 distinguished names, per [RFC 5280 A.1]. They - /// are sent in the [`certificate_authorities`] extension of a [`CertificateRequest`] message - /// when [ClientCertVerifier::offer_client_auth] is true. When an empty list is sent the client - /// should always provide a client certificate if it has one. - /// - /// Generally this list should contain the [`DistinguishedName`] of each root trust - /// anchor in the root cert store that the server is configured to use for authenticating - /// presented client certificates. - /// - /// In some circumstances this list may be customized to include [`DistinguishedName`] entries - /// that do not correspond to a trust anchor in the server's root cert store. For example, - /// the server may be configured to trust a root CA that cross-signed an issuer certificate - /// that the client considers a trust anchor. From the server's perspective the cross-signed - /// certificate is an intermediate, and not present in the server's root cert store. The client - /// may have the cross-signed certificate configured as a trust anchor, and be unaware of the - /// root CA that cross-signed it. If the server's hints list only contained the subjects of the - /// server's root store the client would consider a client certificate issued by the cross-signed - /// issuer unacceptable, since its subject was not hinted. To avoid this circumstance the server - /// should customize the hints list to include the subject of the cross-signed issuer in addition - /// to the subjects from the root cert store. - /// - /// [subjects]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 - /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1 - /// [`CertificateRequest`]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.3.2 - /// [`certificate_authorities`]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.4 - fn root_hint_subjects(&self) -> &[DistinguishedName]; - - /// Verify the end-entity certificate `end_entity` is valid, acceptable, - /// and chains to at least one of the trust anchors trusted by - /// this verifier. - /// - /// `intermediates` contains the intermediate certificates the - /// client sent along with the end-entity certificate; it is in the same - /// order that the peer sent them and may be empty. - /// - /// Note that none of the certificates have been parsed yet, so it is the responsibility of - /// the implementer to handle invalid data. It is recommended that the implementer returns - /// an [InvalidCertificate] error with the [BadEncoding] variant when these cases are encountered. - /// - /// [InvalidCertificate]: Error#variant.InvalidCertificate - /// [BadEncoding]: crate::CertificateError#variant.BadEncoding - fn verify_client_cert( - &self, - end_entity: &CertificateDer<'_>, - intermediates: &[CertificateDer<'_>], - now: UnixTime, - ) -> Result<ClientCertVerified, Error>; - - /// Verify a signature allegedly by the given client certificate. - /// - /// `message` is not hashed, and needs hashing during the verification. - /// The signature and algorithm are within `dss`. `cert` contains the - /// public key to use. - /// - /// `cert` has already been validated by [`ClientCertVerifier::verify_client_cert`]. - /// - /// If and only if the signature is valid, return `Ok(HandshakeSignatureValid)`. - /// Otherwise, return an error -- rustls will send an alert and abort the - /// connection. - /// - /// This method is only called for TLS1.2 handshakes. Note that, in TLS1.2, - /// SignatureSchemes such as `SignatureScheme::ECDSA_NISTP256_SHA256` are not - /// in fact bound to the specific curve implied in their name. - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error>; - - /// Verify a signature allegedly by the given client certificate. - /// - /// This method is only called for TLS1.3 handshakes. - /// - /// This method is very similar to `verify_tls12_signature`, but note the - /// tighter ECDSA SignatureScheme semantics in TLS 1.3. For example, - /// `SignatureScheme::ECDSA_NISTP256_SHA256` - /// must only validate signatures using public keys on the right curve -- - /// rustls does not enforce this requirement for you. - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error>; - - /// Return the list of SignatureSchemes that this verifier will handle, - /// in `verify_tls12_signature` and `verify_tls13_signature` calls. - /// - /// This should be in priority order, with the most preferred first. - fn supported_verify_schemes(&self) -> Vec<SignatureScheme>; - - /// Returns whether this verifier requires raw public keys as defined - /// in [RFC 7250](https://tools.ietf.org/html/rfc7250). - fn requires_raw_public_keys(&self) -> bool { - false - } -} - -/// Turns off client authentication. -/// -/// In contrast to using -/// `WebPkiClientVerifier::builder(roots).allow_unauthenticated().build()`, the `NoClientAuth` -/// `ClientCertVerifier` will not offer client authentication at all, vs offering but not -/// requiring it. -#[derive(Debug)] -pub struct NoClientAuth; - -impl ClientCertVerifier for NoClientAuth { - fn offer_client_auth(&self) -> bool { - false - } - - fn root_hint_subjects(&self) -> &[DistinguishedName] { - unimplemented!(); - } - - fn verify_client_cert( - &self, - _end_entity: &CertificateDer<'_>, - _intermediates: &[CertificateDer<'_>], - _now: UnixTime, - ) -> Result<ClientCertVerified, Error> { - unimplemented!(); - } - - fn verify_tls12_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - unimplemented!(); - } - - fn verify_tls13_signature( - &self, - _message: &[u8], - _cert: &CertificateDer<'_>, - _dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - unimplemented!(); - } - - fn supported_verify_schemes(&self) -> Vec<SignatureScheme> { - unimplemented!(); - } -} - -/// This type combines a [`SignatureScheme`] and a signature payload produced with that scheme. -#[derive(Debug, Clone)] -pub struct DigitallySignedStruct { - /// The [`SignatureScheme`] used to produce the signature. - pub scheme: SignatureScheme, - sig: PayloadU16, -} - -impl DigitallySignedStruct { - pub(crate) fn new(scheme: SignatureScheme, sig: Vec<u8>) -> Self { - Self { - scheme, - sig: PayloadU16::new(sig), - } - } - - /// Get the signature. - pub fn signature(&self) -> &[u8] { - &self.sig.0 - } -} - -impl Codec<'_> for DigitallySignedStruct { - fn encode(&self, bytes: &mut Vec<u8>) { - self.scheme.encode(bytes); - self.sig.encode(bytes); - } - - fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> { - let scheme = SignatureScheme::read(r)?; - let sig = PayloadU16::read(r)?; - - Ok(Self { scheme, sig }) - } -} - -#[test] -fn assertions_are_debug() { - use std::format; - - assert_eq!( - format!("{:?}", ClientCertVerified::assertion()), - "ClientCertVerified(())" - ); - assert_eq!( - format!("{:?}", HandshakeSignatureValid::assertion()), - "HandshakeSignatureValid(())" - ); - assert_eq!( - format!("{:?}", FinishedMessageVerified::assertion()), - "FinishedMessageVerified(())" - ); - assert_eq!( - format!("{:?}", ServerCertVerified::assertion()), - "ServerCertVerified(())" - ); -} diff --git a/vendor/rustls/src/verifybench.rs b/vendor/rustls/src/verifybench.rs deleted file mode 100644 index 06213e7b..00000000 --- a/vendor/rustls/src/verifybench.rs +++ /dev/null @@ -1,244 +0,0 @@ -//! This program does benchmarking of the functions in verify.rs, -//! that do certificate chain validation and signature verification. -//! -//! This uses captured certificate chains for a selection of websites, -//! saved in `testdata/cert-{SITE}.{I}.der`. -//! -//! To update that data: -//! -//! - delete all `testdata/cert-*.der`. -//! - run the `admin/capture-certdata` script. -//! - update the verification timestamp near the bottom of this file -//! to the current time. -//! - where a website's chain length changed, reflect that in the list -//! of certificate files below. -//! -//! This does not need to be done regularly; because the verification -//! time is fixed, it only needs doing if a root certificate is -//! distrusted. - -#![cfg(bench)] - -use core::time::Duration; -use std::prelude::v1::*; - -use pki_types::{CertificateDer, ServerName, UnixTime}; -use webpki_roots; - -use crate::crypto::CryptoProvider; -use crate::verify::ServerCertVerifier; -use crate::webpki::{RootCertStore, WebPkiServerVerifier}; - -#[macro_rules_attribute::apply(bench_for_each_provider)] -mod benchmarks { - use super::{Context, provider}; - - #[bench] - fn reddit_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "reddit.com", - &[ - include_bytes!("testdata/cert-reddit.0.der"), - include_bytes!("testdata/cert-reddit.1.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn github_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "github.com", - &[ - include_bytes!("testdata/cert-github.0.der"), - include_bytes!("testdata/cert-github.1.der"), - include_bytes!("testdata/cert-github.2.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn arstechnica_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "arstechnica.com", - &[ - include_bytes!("testdata/cert-arstechnica.0.der"), - include_bytes!("testdata/cert-arstechnica.1.der"), - include_bytes!("testdata/cert-arstechnica.2.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn servo_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "servo.org", - &[ - include_bytes!("testdata/cert-servo.0.der"), - include_bytes!("testdata/cert-servo.1.der"), - include_bytes!("testdata/cert-servo.2.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn twitter_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "twitter.com", - &[ - include_bytes!("testdata/cert-twitter.0.der"), - include_bytes!("testdata/cert-twitter.1.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn wikipedia_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "wikipedia.org", - &[ - include_bytes!("testdata/cert-wikipedia.0.der"), - include_bytes!("testdata/cert-wikipedia.1.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn google_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "www.google.com", - &[ - include_bytes!("testdata/cert-google.0.der"), - include_bytes!("testdata/cert-google.1.der"), - include_bytes!("testdata/cert-google.2.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn hn_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "news.ycombinator.com", - &[ - include_bytes!("testdata/cert-hn.0.der"), - include_bytes!("testdata/cert-hn.1.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn stackoverflow_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "stackoverflow.com", - &[ - include_bytes!("testdata/cert-stackoverflow.0.der"), - include_bytes!("testdata/cert-stackoverflow.1.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn duckduckgo_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "duckduckgo.com", - &[ - include_bytes!("testdata/cert-duckduckgo.0.der"), - include_bytes!("testdata/cert-duckduckgo.1.der"), - include_bytes!("testdata/cert-duckduckgo.2.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn rustlang_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "www.rust-lang.org", - &[ - include_bytes!("testdata/cert-rustlang.0.der"), - include_bytes!("testdata/cert-rustlang.1.der"), - include_bytes!("testdata/cert-rustlang.2.der"), - include_bytes!("testdata/cert-rustlang.3.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } - - #[bench] - fn wapo_cert(b: &mut test::Bencher) { - let ctx = Context::new( - provider::default_provider(), - "www.washingtonpost.com", - &[ - include_bytes!("testdata/cert-wapo.0.der"), - include_bytes!("testdata/cert-wapo.1.der"), - ], - ); - b.iter(|| ctx.verify_once()); - } -} - -struct Context { - server_name: ServerName<'static>, - chain: Vec<CertificateDer<'static>>, - now: UnixTime, - verifier: WebPkiServerVerifier, -} - -impl Context { - fn new(provider: CryptoProvider, domain: &'static str, certs: &[&'static [u8]]) -> Self { - let mut roots = RootCertStore::empty(); - roots.extend( - webpki_roots::TLS_SERVER_ROOTS - .iter() - .cloned(), - ); - Self { - server_name: domain.try_into().unwrap(), - chain: certs - .iter() - .copied() - .map(|bytes| CertificateDer::from(bytes.to_vec())) - .collect(), - now: UnixTime::since_unix_epoch(Duration::from_secs(1_746_605_469)), - verifier: WebPkiServerVerifier::new_without_revocation( - roots, - provider.signature_verification_algorithms, - ), - } - } - - fn verify_once(&self) { - const OCSP_RESPONSE: &[u8] = &[]; - - let (end_entity, intermediates) = self.chain.split_first().unwrap(); - self.verifier - .verify_server_cert( - end_entity, - intermediates, - &self.server_name, - OCSP_RESPONSE, - self.now, - ) - .unwrap(); - } -} diff --git a/vendor/rustls/src/versions.rs b/vendor/rustls/src/versions.rs deleted file mode 100644 index 4acdf99a..00000000 --- a/vendor/rustls/src/versions.rs +++ /dev/null @@ -1,97 +0,0 @@ -use core::fmt; - -use crate::enums::ProtocolVersion; - -/// A TLS protocol version supported by rustls. -/// -/// All possible instances of this class are provided by the library in -/// the [`ALL_VERSIONS`] array, as well as individually as [`TLS12`] -/// and [`TLS13`]. -#[non_exhaustive] -#[derive(Eq, PartialEq)] -pub struct SupportedProtocolVersion { - /// The TLS enumeration naming this version. - pub version: ProtocolVersion, -} - -impl fmt::Debug for SupportedProtocolVersion { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.version.fmt(f) - } -} - -/// TLS1.2 -#[cfg(feature = "tls12")] -pub static TLS12: SupportedProtocolVersion = SupportedProtocolVersion { - version: ProtocolVersion::TLSv1_2, -}; - -/// TLS1.3 -pub static TLS13: SupportedProtocolVersion = SupportedProtocolVersion { - version: ProtocolVersion::TLSv1_3, -}; - -/// A list of all the protocol versions supported by rustls. -pub static ALL_VERSIONS: &[&SupportedProtocolVersion] = &[ - &TLS13, - #[cfg(feature = "tls12")] - &TLS12, -]; - -/// The version configuration that an application should use by default. -/// -/// This will be [`ALL_VERSIONS`] for now, but gives space in the future -/// to remove a version from here and require users to opt-in to older -/// versions. -pub static DEFAULT_VERSIONS: &[&SupportedProtocolVersion] = ALL_VERSIONS; - -#[derive(Clone, Copy)] -pub(crate) struct EnabledVersions { - #[cfg(feature = "tls12")] - tls12: Option<&'static SupportedProtocolVersion>, - tls13: Option<&'static SupportedProtocolVersion>, -} - -impl fmt::Debug for EnabledVersions { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut list = &mut f.debug_list(); - #[cfg(feature = "tls12")] - if let Some(v) = self.tls12 { - list = list.entry(v); - } - if let Some(v) = self.tls13 { - list = list.entry(v); - } - list.finish() - } -} - -impl EnabledVersions { - pub(crate) fn new(versions: &[&'static SupportedProtocolVersion]) -> Self { - let mut ev = Self { - #[cfg(feature = "tls12")] - tls12: None, - tls13: None, - }; - - for v in versions { - match v.version { - #[cfg(feature = "tls12")] - ProtocolVersion::TLSv1_2 => ev.tls12 = Some(v), - ProtocolVersion::TLSv1_3 => ev.tls13 = Some(v), - _ => {} - } - } - - ev - } - - pub(crate) fn contains(&self, version: ProtocolVersion) -> bool { - match version { - #[cfg(feature = "tls12")] - ProtocolVersion::TLSv1_2 => self.tls12.is_some(), - ProtocolVersion::TLSv1_3 => self.tls13.is_some(), - _ => false, - } - } -} diff --git a/vendor/rustls/src/webpki/anchors.rs b/vendor/rustls/src/webpki/anchors.rs deleted file mode 100644 index b526ed25..00000000 --- a/vendor/rustls/src/webpki/anchors.rs +++ /dev/null @@ -1,143 +0,0 @@ -use alloc::vec::Vec; -use alloc::{fmt, format}; - -use pki_types::{CertificateDer, TrustAnchor}; -use webpki::anchor_from_trusted_cert; - -use super::pki_error; -use crate::log::{debug, trace}; -use crate::{DistinguishedName, Error}; - -/// A container for root certificates able to provide a root-of-trust -/// for connection authentication. -#[derive(Clone)] -pub struct RootCertStore { - /// The list of roots. - pub roots: Vec<TrustAnchor<'static>>, -} - -impl RootCertStore { - /// Make a new, empty `RootCertStore`. - pub fn empty() -> Self { - Self { roots: Vec::new() } - } - - /// Parse the given DER-encoded certificates and add all that can be parsed - /// in a best-effort fashion. - /// - /// This is because large collections of root certificates often - /// include ancient or syntactically invalid certificates. - /// - /// Returns the number of certificates added, and the number that were ignored. - pub fn add_parsable_certificates<'a>( - &mut self, - der_certs: impl IntoIterator<Item = CertificateDer<'a>>, - ) -> (usize, usize) { - let mut valid_count = 0; - let mut invalid_count = 0; - - for der_cert in der_certs { - #[cfg_attr(not(feature = "logging"), allow(unused_variables))] - match anchor_from_trusted_cert(&der_cert) { - Ok(anchor) => { - self.roots.push(anchor.to_owned()); - valid_count += 1; - } - Err(err) => { - trace!("invalid cert der {:?}", der_cert.as_ref()); - debug!("certificate parsing failed: {err:?}"); - invalid_count += 1; - } - }; - } - - debug!( - "add_parsable_certificates processed {valid_count} valid and {invalid_count} invalid certs" - ); - - (valid_count, invalid_count) - } - - /// Add a single DER-encoded certificate to the store. - /// - /// This is suitable for a small set of root certificates that are expected to parse - /// successfully. For large collections of roots (for example from a system store) it - /// is expected that some of them might not be valid according to the rules rustls - /// implements. As long as a relatively limited number of certificates are affected, - /// this should not be a cause for concern. Use [`RootCertStore::add_parsable_certificates`] - /// in order to add as many valid roots as possible and to understand how many certificates - /// have been diagnosed as malformed. - pub fn add(&mut self, der: CertificateDer<'_>) -> Result<(), Error> { - self.roots.push( - anchor_from_trusted_cert(&der) - .map_err(pki_error)? - .to_owned(), - ); - Ok(()) - } - - /// Return the DER encoded [`DistinguishedName`] of each trust anchor subject in the root - /// cert store. - /// - /// Each [`DistinguishedName`] will be a DER-encoded X.500 distinguished name, per - /// [RFC 5280 A.1], including the outer `SEQUENCE`. - /// - /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1 - pub fn subjects(&self) -> Vec<DistinguishedName> { - self.roots - .iter() - .map(|ta| DistinguishedName::in_sequence(ta.subject.as_ref())) - .collect() - } - - /// Return true if there are no certificates. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Say how many certificates are in the container. - pub fn len(&self) -> usize { - self.roots.len() - } -} - -impl FromIterator<TrustAnchor<'static>> for RootCertStore { - fn from_iter<T: IntoIterator<Item = TrustAnchor<'static>>>(iter: T) -> Self { - Self { - roots: iter.into_iter().collect(), - } - } -} - -impl Extend<TrustAnchor<'static>> for RootCertStore { - fn extend<T: IntoIterator<Item = TrustAnchor<'static>>>(&mut self, iter: T) { - self.roots.extend(iter); - } -} - -impl fmt::Debug for RootCertStore { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RootCertStore") - .field("roots", &format!("({} roots)", &self.roots.len())) - .finish() - } -} - -#[test] -fn root_cert_store_debug() { - use core::iter; - - use pki_types::Der; - - let ta = TrustAnchor { - subject: Der::from_slice(&[]), - subject_public_key_info: Der::from_slice(&[]), - name_constraints: None, - }; - let store = RootCertStore::from_iter(iter::repeat(ta).take(138)); - - assert_eq!( - format!("{store:?}"), - "RootCertStore { roots: \"(138 roots)\" }" - ); -} diff --git a/vendor/rustls/src/webpki/client_verifier.rs b/vendor/rustls/src/webpki/client_verifier.rs deleted file mode 100644 index 060f0f77..00000000 --- a/vendor/rustls/src/webpki/client_verifier.rs +++ /dev/null @@ -1,665 +0,0 @@ -use alloc::vec::Vec; - -use pki_types::{CertificateDer, CertificateRevocationListDer, UnixTime}; -use webpki::{CertRevocationList, ExpirationPolicy, RevocationCheckDepth, UnknownStatusPolicy}; - -use super::{VerifierBuilderError, pki_error}; -#[cfg(doc)] -use crate::ConfigBuilder; -#[cfg(doc)] -use crate::crypto; -use crate::crypto::{CryptoProvider, WebPkiSupportedAlgorithms}; -#[cfg(doc)] -use crate::server::ServerConfig; -use crate::sync::Arc; -use crate::verify::{ - ClientCertVerified, ClientCertVerifier, DigitallySignedStruct, HandshakeSignatureValid, - NoClientAuth, -}; -use crate::webpki::parse_crls; -use crate::webpki::verify::{ParsedCertificate, verify_tls12_signature, verify_tls13_signature}; -use crate::{DistinguishedName, Error, RootCertStore, SignatureScheme}; - -/// A builder for configuring a `webpki` client certificate verifier. -/// -/// For more information, see the [`WebPkiClientVerifier`] documentation. -#[derive(Debug, Clone)] -pub struct ClientCertVerifierBuilder { - roots: Arc<RootCertStore>, - root_hint_subjects: Vec<DistinguishedName>, - crls: Vec<CertificateRevocationListDer<'static>>, - revocation_check_depth: RevocationCheckDepth, - unknown_revocation_policy: UnknownStatusPolicy, - revocation_expiration_policy: ExpirationPolicy, - anon_policy: AnonymousClientPolicy, - supported_algs: WebPkiSupportedAlgorithms, -} - -impl ClientCertVerifierBuilder { - pub(crate) fn new( - roots: Arc<RootCertStore>, - supported_algs: WebPkiSupportedAlgorithms, - ) -> Self { - Self { - root_hint_subjects: roots.subjects(), - roots, - crls: Vec::new(), - anon_policy: AnonymousClientPolicy::Deny, - revocation_check_depth: RevocationCheckDepth::Chain, - unknown_revocation_policy: UnknownStatusPolicy::Deny, - revocation_expiration_policy: ExpirationPolicy::Ignore, - supported_algs, - } - } - - /// Clear the list of trust anchor hint subjects. - /// - /// By default, the client cert verifier will use the subjects provided by the root cert - /// store configured for client authentication. Calling this function will remove these - /// hint subjects, indicating the client should make a free choice of which certificate - /// to send. - /// - /// See [`ClientCertVerifier::root_hint_subjects`] for more information on - /// circumstances where you may want to clear the default hint subjects. - pub fn clear_root_hint_subjects(mut self) -> Self { - self.root_hint_subjects = Vec::default(); - self - } - - /// Add additional [`DistinguishedName`]s to the list of trust anchor hint subjects. - /// - /// By default, the client cert verifier will use the subjects provided by the root cert - /// store configured for client authentication. Calling this function will add to these - /// existing hint subjects. Calling this function with empty `subjects` will have no - /// effect. - /// - /// See [`ClientCertVerifier::root_hint_subjects`] for more information on - /// circumstances where you may want to override the default hint subjects. - pub fn add_root_hint_subjects( - mut self, - subjects: impl IntoIterator<Item = DistinguishedName>, - ) -> Self { - self.root_hint_subjects.extend(subjects); - self - } - - /// Verify the revocation state of presented client certificates against the provided - /// certificate revocation lists (CRLs). Calling `with_crls` multiple times appends the - /// given CRLs to the existing collection. - /// - /// By default all certificates in the verified chain built from the presented client - /// certificate to a trust anchor will have their revocation status checked. Calling - /// [`only_check_end_entity_revocation`][Self::only_check_end_entity_revocation] will - /// change this behavior to only check the end entity client certificate. - /// - /// By default if a certificate's revocation status can not be determined using the - /// configured CRLs, it will be treated as an error. Calling - /// [`allow_unknown_revocation_status`][Self::allow_unknown_revocation_status] will change - /// this behavior to allow unknown revocation status. - pub fn with_crls( - mut self, - crls: impl IntoIterator<Item = CertificateRevocationListDer<'static>>, - ) -> Self { - self.crls.extend(crls); - self - } - - /// Only check the end entity certificate revocation status when using CRLs. - /// - /// If CRLs are provided using [`with_crls`][Self::with_crls] only check the end entity - /// certificate's revocation status. Overrides the default behavior of checking revocation - /// status for each certificate in the verified chain built to a trust anchor - /// (excluding the trust anchor itself). - /// - /// If no CRLs are provided then this setting has no effect. Neither the end entity certificate - /// or any intermediates will have revocation status checked. - pub fn only_check_end_entity_revocation(mut self) -> Self { - self.revocation_check_depth = RevocationCheckDepth::EndEntity; - self - } - - /// Allow unauthenticated clients to connect. - /// - /// Clients that offer a client certificate issued by a trusted root, and clients that offer no - /// client certificate will be allowed to connect. - pub fn allow_unauthenticated(mut self) -> Self { - self.anon_policy = AnonymousClientPolicy::Allow; - self - } - - /// Allow unknown certificate revocation status when using CRLs. - /// - /// If CRLs are provided with [`with_crls`][Self::with_crls] and it isn't possible to - /// determine the revocation status of a certificate, do not treat it as an error condition. - /// Overrides the default behavior where unknown revocation status is considered an error. - /// - /// If no CRLs are provided then this setting has no effect as revocation status checks - /// are not performed. - pub fn allow_unknown_revocation_status(mut self) -> Self { - self.unknown_revocation_policy = UnknownStatusPolicy::Allow; - self - } - - /// Enforce the CRL nextUpdate field (i.e. expiration) - /// - /// If CRLs are provided with [`with_crls`][Self::with_crls] and the verification time is - /// beyond the time in the CRL nextUpdate field, it is expired and treated as an error condition. - /// Overrides the default behavior where expired CRLs are not treated as an error condition. - /// - /// If no CRLs are provided then this setting has no effect as revocation status checks - /// are not performed. - pub fn enforce_revocation_expiration(mut self) -> Self { - self.revocation_expiration_policy = ExpirationPolicy::Enforce; - self - } - - /// Build a client certificate verifier. The built verifier will be used for the server to offer - /// client certificate authentication, to control how offered client certificates are validated, - /// and to determine what to do with anonymous clients that do not respond to the client - /// certificate authentication offer with a client certificate. - /// - /// If `with_signature_verification_algorithms` was not called on the builder, a default set of - /// signature verification algorithms is used, controlled by the selected [`CryptoProvider`]. - /// - /// Once built, the provided `Arc<dyn ClientCertVerifier>` can be used with a Rustls - /// [`ServerConfig`] to configure client certificate validation using - /// [`with_client_cert_verifier`][ConfigBuilder<ClientConfig, WantsVerifier>::with_client_cert_verifier]. - /// - /// # Errors - /// This function will return a [`VerifierBuilderError`] if: - /// 1. No trust anchors have been provided. - /// 2. DER encoded CRLs have been provided that can not be parsed successfully. - pub fn build(self) -> Result<Arc<dyn ClientCertVerifier>, VerifierBuilderError> { - if self.roots.is_empty() { - return Err(VerifierBuilderError::NoRootAnchors); - } - - Ok(Arc::new(WebPkiClientVerifier::new( - self.roots, - self.root_hint_subjects, - parse_crls(self.crls)?, - self.revocation_check_depth, - self.unknown_revocation_policy, - self.revocation_expiration_policy, - self.anon_policy, - self.supported_algs, - ))) - } -} - -/// A client certificate verifier that uses the `webpki` crate[^1] to perform client certificate -/// validation. -/// -/// It must be created via the [`WebPkiClientVerifier::builder()`] or -/// [`WebPkiClientVerifier::builder_with_provider()`] functions. -/// -/// Once built, the provided `Arc<dyn ClientCertVerifier>` can be used with a Rustls [`ServerConfig`] -/// to configure client certificate validation using [`with_client_cert_verifier`][ConfigBuilder<ClientConfig, WantsVerifier>::with_client_cert_verifier]. -/// -/// Example: -/// -/// To require all clients present a client certificate issued by a trusted CA: -/// ```no_run -/// # #[cfg(any(feature = "ring", feature = "aws_lc_rs"))] { -/// # use rustls::RootCertStore; -/// # use rustls::server::WebPkiClientVerifier; -/// # let roots = RootCertStore::empty(); -/// let client_verifier = WebPkiClientVerifier::builder(roots.into()) -/// .build() -/// .unwrap(); -/// # } -/// ``` -/// -/// Or, to allow clients presenting a client certificate authenticated by a trusted CA, or -/// anonymous clients that present no client certificate: -/// ```no_run -/// # #[cfg(any(feature = "ring", feature = "aws_lc_rs"))] { -/// # use rustls::RootCertStore; -/// # use rustls::server::WebPkiClientVerifier; -/// # let roots = RootCertStore::empty(); -/// let client_verifier = WebPkiClientVerifier::builder(roots.into()) -/// .allow_unauthenticated() -/// .build() -/// .unwrap(); -/// # } -/// ``` -/// -/// If you wish to disable advertising client authentication: -/// ```no_run -/// # use rustls::RootCertStore; -/// # use rustls::server::WebPkiClientVerifier; -/// # let roots = RootCertStore::empty(); -/// let client_verifier = WebPkiClientVerifier::no_client_auth(); -/// ``` -/// -/// You can also configure the client verifier to check for certificate revocation with -/// client certificate revocation lists (CRLs): -/// ```no_run -/// # #[cfg(any(feature = "ring", feature = "aws_lc_rs"))] { -/// # use rustls::RootCertStore; -/// # use rustls::server::{WebPkiClientVerifier}; -/// # let roots = RootCertStore::empty(); -/// # let crls = Vec::new(); -/// let client_verifier = WebPkiClientVerifier::builder(roots.into()) -/// .with_crls(crls) -/// .build() -/// .unwrap(); -/// # } -/// ``` -/// -/// [^1]: <https://github.com/rustls/webpki> -#[derive(Debug)] -pub struct WebPkiClientVerifier { - roots: Arc<RootCertStore>, - root_hint_subjects: Vec<DistinguishedName>, - crls: Vec<CertRevocationList<'static>>, - revocation_check_depth: RevocationCheckDepth, - unknown_revocation_policy: UnknownStatusPolicy, - revocation_expiration_policy: ExpirationPolicy, - anonymous_policy: AnonymousClientPolicy, - supported_algs: WebPkiSupportedAlgorithms, -} - -impl WebPkiClientVerifier { - /// Create a builder for the `webpki` client certificate verifier configuration using - /// the [process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider]. - /// - /// Client certificate authentication will be offered by the server, and client certificates - /// will be verified using the trust anchors found in the provided `roots`. If you - /// wish to disable client authentication use [`WebPkiClientVerifier::no_client_auth()`] instead. - /// - /// Use [`Self::builder_with_provider`] if you wish to specify an explicit provider. - /// - /// For more information, see the [`ClientCertVerifierBuilder`] documentation. - pub fn builder(roots: Arc<RootCertStore>) -> ClientCertVerifierBuilder { - Self::builder_with_provider( - roots, - CryptoProvider::get_default_or_install_from_crate_features().clone(), - ) - } - - /// Create a builder for the `webpki` client certificate verifier configuration using - /// a specified [`CryptoProvider`]. - /// - /// Client certificate authentication will be offered by the server, and client certificates - /// will be verified using the trust anchors found in the provided `roots`. If you - /// wish to disable client authentication use [WebPkiClientVerifier::no_client_auth()] instead. - /// - /// The cryptography used comes from the specified [`CryptoProvider`]. - /// - /// For more information, see the [`ClientCertVerifierBuilder`] documentation. - pub fn builder_with_provider( - roots: Arc<RootCertStore>, - provider: Arc<CryptoProvider>, - ) -> ClientCertVerifierBuilder { - ClientCertVerifierBuilder::new(roots, provider.signature_verification_algorithms) - } - - /// Create a new `WebPkiClientVerifier` that disables client authentication. The server will - /// not offer client authentication and anonymous clients will be accepted. - /// - /// This is in contrast to using `WebPkiClientVerifier::builder().allow_unauthenticated().build()`, - /// which will produce a verifier that will offer client authentication, but not require it. - pub fn no_client_auth() -> Arc<dyn ClientCertVerifier> { - Arc::new(NoClientAuth {}) - } - - /// Construct a new `WebpkiClientVerifier`. - /// - /// * `roots` is a list of trust anchors to use for certificate validation. - /// * `root_hint_subjects` is a list of distinguished names to use for hinting acceptable - /// certificate authority subjects to a client. - /// * `crls` is a `Vec` of owned certificate revocation lists (CRLs) to use for - /// client certificate validation. - /// * `revocation_check_depth` controls which certificates have their revocation status checked - /// when `crls` are provided. - /// * `unknown_revocation_policy` controls how certificates with an unknown revocation status - /// are handled when `crls` are provided. - /// * `anonymous_policy` controls whether client authentication is required, or if anonymous - /// clients can connect. - /// * `supported_algs` specifies which signature verification algorithms should be used. - pub(crate) fn new( - roots: Arc<RootCertStore>, - root_hint_subjects: Vec<DistinguishedName>, - crls: Vec<CertRevocationList<'static>>, - revocation_check_depth: RevocationCheckDepth, - unknown_revocation_policy: UnknownStatusPolicy, - revocation_expiration_policy: ExpirationPolicy, - anonymous_policy: AnonymousClientPolicy, - supported_algs: WebPkiSupportedAlgorithms, - ) -> Self { - Self { - roots, - root_hint_subjects, - crls, - revocation_check_depth, - unknown_revocation_policy, - revocation_expiration_policy, - anonymous_policy, - supported_algs, - } - } -} - -impl ClientCertVerifier for WebPkiClientVerifier { - fn offer_client_auth(&self) -> bool { - true - } - - fn client_auth_mandatory(&self) -> bool { - match self.anonymous_policy { - AnonymousClientPolicy::Allow => false, - AnonymousClientPolicy::Deny => true, - } - } - - fn root_hint_subjects(&self) -> &[DistinguishedName] { - &self.root_hint_subjects - } - - fn verify_client_cert( - &self, - end_entity: &CertificateDer<'_>, - intermediates: &[CertificateDer<'_>], - now: UnixTime, - ) -> Result<ClientCertVerified, Error> { - let cert = ParsedCertificate::try_from(end_entity)?; - - let crl_refs = self.crls.iter().collect::<Vec<_>>(); - - let revocation = if self.crls.is_empty() { - None - } else { - Some( - webpki::RevocationOptionsBuilder::new(&crl_refs) - // Note: safe to unwrap here - new is only fallible if no CRLs are provided - // and we verify this above. - .unwrap() - .with_depth(self.revocation_check_depth) - .with_status_policy(self.unknown_revocation_policy) - .with_expiration_policy(self.revocation_expiration_policy) - .build(), - ) - }; - - cert.0 - .verify_for_usage( - self.supported_algs.all, - &self.roots.roots, - intermediates, - now, - webpki::KeyUsage::client_auth(), - revocation, - None, - ) - .map_err(pki_error) - .map(|_| ClientCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - verify_tls12_signature(message, cert, dss, &self.supported_algs) - } - - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - verify_tls13_signature(message, cert, dss, &self.supported_algs) - } - - fn supported_verify_schemes(&self) -> Vec<SignatureScheme> { - self.supported_algs.supported_schemes() - } -} - -/// Controls how the [WebPkiClientVerifier] handles anonymous clients. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) enum AnonymousClientPolicy { - /// Clients that do not present a client certificate are allowed. - Allow, - /// Clients that do not present a client certificate are denied. - Deny, -} - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use std::prelude::v1::*; - use std::{format, println, vec}; - - use pki_types::pem::PemObject; - use pki_types::{CertificateDer, CertificateRevocationListDer}; - - use super::{WebPkiClientVerifier, provider}; - use crate::RootCertStore; - use crate::server::VerifierBuilderError; - use crate::sync::Arc; - - fn load_crls(crls_der: &[&[u8]]) -> Vec<CertificateRevocationListDer<'static>> { - crls_der - .iter() - .map(|pem_bytes| CertificateRevocationListDer::from_pem_slice(pem_bytes).unwrap()) - .collect() - } - - fn test_crls() -> Vec<CertificateRevocationListDer<'static>> { - load_crls(&[ - include_bytes!("../../../test-ca/ecdsa-p256/client.revoked.crl.pem").as_slice(), - include_bytes!("../../../test-ca/rsa-2048/client.revoked.crl.pem").as_slice(), - ]) - } - - fn load_roots(roots_der: &[&[u8]]) -> Arc<RootCertStore> { - let mut roots = RootCertStore::empty(); - roots_der.iter().for_each(|der| { - roots - .add(CertificateDer::from(der.to_vec())) - .unwrap() - }); - roots.into() - } - - fn test_roots() -> Arc<RootCertStore> { - load_roots(&[ - include_bytes!("../../../test-ca/ecdsa-p256/ca.der").as_slice(), - include_bytes!("../../../test-ca/rsa-2048/ca.der").as_slice(), - ]) - } - - #[test] - fn test_client_verifier_no_auth() { - // We should be able to build a verifier that turns off client authentication. - WebPkiClientVerifier::no_client_auth(); - } - - #[test] - fn test_client_verifier_required_auth() { - // We should be able to build a verifier that requires client authentication, and does - // no revocation checking. - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_client_verifier_optional_auth() { - // We should be able to build a verifier that allows client authentication, and anonymous - // access, and does no revocation checking. - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .allow_unauthenticated(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_client_verifier_without_crls_required_auth() { - // We should be able to build a verifier that requires client authentication, and does - // no revocation checking, that hasn't been configured to determine how to handle - // unauthenticated clients yet. - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_client_verifier_without_crls_opptional_auth() { - // We should be able to build a verifier that allows client authentication, - // and anonymous access, that does no revocation checking. - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .allow_unauthenticated(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_with_invalid_crls() { - // Trying to build a client verifier with invalid CRLs should error at build time. - let result = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(vec![CertificateRevocationListDer::from(vec![0xFF])]) - .build(); - assert!(matches!(result, Err(VerifierBuilderError::InvalidCrl(_)))); - } - - #[test] - fn test_with_crls_multiple_calls() { - // We should be able to call `with_crls` on a client verifier multiple times. - let initial_crls = test_crls(); - let extra_crls = - load_crls(&[ - include_bytes!("../../../test-ca/eddsa/client.revoked.crl.pem").as_slice(), - ]); - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(initial_crls.clone()) - .with_crls(extra_crls.clone()); - - // There should be the expected number of crls. - assert_eq!(builder.crls.len(), initial_crls.len() + extra_crls.len()); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_client_verifier_with_crls_required_auth_implicit() { - // We should be able to build a verifier that requires client authentication, and that does - // revocation checking with CRLs, and that does not allow any anonymous access. - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(test_crls()); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_client_verifier_with_crls_optional_auth() { - // We should be able to build a verifier that supports client authentication, that does - // revocation checking with CRLs, and that allows anonymous access. - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(test_crls()) - .allow_unauthenticated(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_client_verifier_ee_only() { - // We should be able to build a client verifier that only checks EE revocation status. - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(test_crls()) - .only_check_end_entity_revocation(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_client_verifier_allow_unknown() { - // We should be able to build a client verifier that allows unknown revocation status - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(test_crls()) - .allow_unknown_revocation_status(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_client_verifier_enforce_expiration() { - // We should be able to build a client verifier that allows unknown revocation status - let builder = WebPkiClientVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(test_crls()) - .enforce_revocation_expiration(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_builder_no_roots() { - // Trying to create a client verifier builder with no trust anchors should fail at build time - let result = WebPkiClientVerifier::builder_with_provider( - RootCertStore::empty().into(), - provider::default_provider().into(), - ) - .build(); - assert!(matches!(result, Err(VerifierBuilderError::NoRootAnchors))); - } - - #[test] - fn smoke() { - let all = vec![ - VerifierBuilderError::NoRootAnchors, - VerifierBuilderError::InvalidCrl(crate::CertRevocationListError::ParseError), - ]; - - for err in all { - let _ = format!("{err:?}"); - let _ = format!("{err}"); - } - } -} diff --git a/vendor/rustls/src/webpki/mod.rs b/vendor/rustls/src/webpki/mod.rs deleted file mode 100644 index 24960a1e..00000000 --- a/vendor/rustls/src/webpki/mod.rs +++ /dev/null @@ -1,313 +0,0 @@ -use alloc::vec::Vec; -use core::fmt; - -use pki_types::CertificateRevocationListDer; -use webpki::{CertRevocationList, InvalidNameContext, OwnedCertRevocationList}; - -use crate::error::{ - CertRevocationListError, CertificateError, Error, ExtendedKeyPurpose, OtherError, -}; -#[cfg(feature = "std")] -use crate::sync::Arc; - -mod anchors; -mod client_verifier; -mod server_verifier; -mod verify; - -pub use anchors::RootCertStore; -pub use client_verifier::{ClientCertVerifierBuilder, WebPkiClientVerifier}; -pub use server_verifier::{ServerCertVerifierBuilder, WebPkiServerVerifier}; -// Conditionally exported from crate. -#[allow(unreachable_pub)] -pub use verify::{ - ParsedCertificate, verify_server_cert_signed_by_trust_anchor, verify_server_name, -}; -pub use verify::{ - WebPkiSupportedAlgorithms, verify_tls12_signature, verify_tls13_signature, - verify_tls13_signature_with_raw_key, -}; - -/// An error that can occur when building a certificate verifier. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum VerifierBuilderError { - /// No root trust anchors were provided. - NoRootAnchors, - /// A provided CRL could not be parsed. - InvalidCrl(CertRevocationListError), -} - -impl From<CertRevocationListError> for VerifierBuilderError { - fn from(value: CertRevocationListError) -> Self { - Self::InvalidCrl(value) - } -} - -impl fmt::Display for VerifierBuilderError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::NoRootAnchors => write!(f, "no root trust anchors were provided"), - Self::InvalidCrl(e) => write!(f, "provided CRL could not be parsed: {e:?}"), - } - } -} - -#[cfg(feature = "std")] -impl std::error::Error for VerifierBuilderError {} - -fn pki_error(error: webpki::Error) -> Error { - use webpki::Error::*; - match error { - BadDer | BadDerTime | TrailingData(_) => CertificateError::BadEncoding.into(), - CertNotValidYet { time, not_before } => { - CertificateError::NotValidYetContext { time, not_before }.into() - } - CertExpired { time, not_after } => { - CertificateError::ExpiredContext { time, not_after }.into() - } - InvalidCertValidity => CertificateError::Expired.into(), - UnknownIssuer => CertificateError::UnknownIssuer.into(), - CertNotValidForName(InvalidNameContext { - expected, - presented, - }) => CertificateError::NotValidForNameContext { - expected, - presented, - } - .into(), - CertRevoked => CertificateError::Revoked.into(), - UnknownRevocationStatus => CertificateError::UnknownRevocationStatus.into(), - CrlExpired { time, next_update } => { - CertificateError::ExpiredRevocationListContext { time, next_update }.into() - } - IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl.into(), - - InvalidSignatureForPublicKey => CertificateError::BadSignature.into(), - #[allow(deprecated)] - UnsupportedSignatureAlgorithm | UnsupportedSignatureAlgorithmForPublicKey => { - CertificateError::UnsupportedSignatureAlgorithm.into() - } - UnsupportedSignatureAlgorithmContext(cx) => { - CertificateError::UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: cx.signature_algorithm_id, - supported_algorithms: cx.supported_algorithms, - } - .into() - } - UnsupportedSignatureAlgorithmForPublicKeyContext(cx) => { - CertificateError::UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: cx.signature_algorithm_id, - public_key_algorithm_id: cx.public_key_algorithm_id, - } - .into() - } - - InvalidCrlSignatureForPublicKey => CertRevocationListError::BadSignature.into(), - #[allow(deprecated)] - UnsupportedCrlSignatureAlgorithm | UnsupportedCrlSignatureAlgorithmForPublicKey => { - CertRevocationListError::UnsupportedSignatureAlgorithm.into() - } - UnsupportedCrlSignatureAlgorithmContext(cx) => { - CertRevocationListError::UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: cx.signature_algorithm_id, - supported_algorithms: cx.supported_algorithms, - } - .into() - } - UnsupportedCrlSignatureAlgorithmForPublicKeyContext(cx) => { - CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: cx.signature_algorithm_id, - public_key_algorithm_id: cx.public_key_algorithm_id, - } - .into() - } - - #[allow(deprecated)] - RequiredEkuNotFound => CertificateError::InvalidPurpose.into(), - RequiredEkuNotFoundContext(webpki::RequiredEkuNotFoundContext { required, present }) => { - CertificateError::InvalidPurposeContext { - required: ExtendedKeyPurpose::for_values(required.oid_values()), - presented: present - .into_iter() - .map(|eku| ExtendedKeyPurpose::for_values(eku.into_iter())) - .collect(), - } - .into() - } - - _ => CertificateError::Other(OtherError( - #[cfg(feature = "std")] - Arc::new(error), - )) - .into(), - } -} - -fn crl_error(e: webpki::Error) -> CertRevocationListError { - use webpki::Error::*; - match e { - InvalidCrlSignatureForPublicKey => CertRevocationListError::BadSignature, - #[allow(deprecated)] - UnsupportedCrlSignatureAlgorithm | UnsupportedCrlSignatureAlgorithmForPublicKey => { - CertRevocationListError::UnsupportedSignatureAlgorithm - } - UnsupportedCrlSignatureAlgorithmContext(cx) => { - CertRevocationListError::UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: cx.signature_algorithm_id, - supported_algorithms: cx.supported_algorithms, - } - } - UnsupportedSignatureAlgorithmForPublicKeyContext(cx) => { - CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: cx.signature_algorithm_id, - public_key_algorithm_id: cx.public_key_algorithm_id, - } - } - InvalidCrlNumber => CertRevocationListError::InvalidCrlNumber, - InvalidSerialNumber => CertRevocationListError::InvalidRevokedCertSerialNumber, - IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl, - MalformedExtensions | BadDer | BadDerTime => CertRevocationListError::ParseError, - UnsupportedCriticalExtension => CertRevocationListError::UnsupportedCriticalExtension, - UnsupportedCrlVersion => CertRevocationListError::UnsupportedCrlVersion, - UnsupportedDeltaCrl => CertRevocationListError::UnsupportedDeltaCrl, - UnsupportedIndirectCrl => CertRevocationListError::UnsupportedIndirectCrl, - UnsupportedRevocationReason => CertRevocationListError::UnsupportedRevocationReason, - - _ => CertRevocationListError::Other(OtherError( - #[cfg(feature = "std")] - Arc::new(e), - )), - } -} - -fn parse_crls( - crls: Vec<CertificateRevocationListDer<'_>>, -) -> Result<Vec<CertRevocationList<'_>>, CertRevocationListError> { - crls.iter() - .map(|der| OwnedCertRevocationList::from_der(der.as_ref()).map(Into::into)) - .collect::<Result<Vec<_>, _>>() - .map_err(crl_error) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloc::vec; - - #[test] - fn pki_crl_errors() { - // CRL signature errors should be turned into BadSignature. - assert_eq!( - pki_error(webpki::Error::InvalidCrlSignatureForPublicKey), - Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), - ); - - #[allow(deprecated)] - { - assert_eq!( - pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithm), - Error::InvalidCertRevocationList( - CertRevocationListError::UnsupportedSignatureAlgorithm - ), - ); - assert_eq!( - pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey), - Error::InvalidCertRevocationList( - CertRevocationListError::UnsupportedSignatureAlgorithm - ), - ); - } - - assert_eq!( - pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmContext( - webpki::UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: vec![], - supported_algorithms: vec![], - } - )), - Error::InvalidCertRevocationList( - CertRevocationListError::UnsupportedSignatureAlgorithmContext { - signature_algorithm_id: vec![], - supported_algorithms: vec![], - } - ) - ); - assert_eq!( - pki_error( - webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKeyContext( - webpki::UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: vec![], - public_key_algorithm_id: vec![], - } - ) - ), - Error::InvalidCertRevocationList( - CertRevocationListError::UnsupportedSignatureAlgorithmForPublicKeyContext { - signature_algorithm_id: vec![], - public_key_algorithm_id: vec![], - } - ) - ); - - // Revoked cert errors should be turned into Revoked. - assert_eq!( - pki_error(webpki::Error::CertRevoked), - Error::InvalidCertificate(CertificateError::Revoked), - ); - - // Issuer not CRL signer errors should be turned into IssuerInvalidForCrl - assert_eq!( - pki_error(webpki::Error::IssuerNotCrlSigner), - Error::InvalidCertRevocationList(CertRevocationListError::IssuerInvalidForCrl) - ); - } - - #[test] - fn crl_error_from_webpki() { - use CertRevocationListError::*; - #[allow(deprecated)] - let testcases = &[ - (webpki::Error::InvalidCrlSignatureForPublicKey, BadSignature), - ( - webpki::Error::UnsupportedCrlSignatureAlgorithm, - UnsupportedSignatureAlgorithm, - ), - ( - webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey, - UnsupportedSignatureAlgorithm, - ), - (webpki::Error::InvalidCrlNumber, InvalidCrlNumber), - ( - webpki::Error::InvalidSerialNumber, - InvalidRevokedCertSerialNumber, - ), - (webpki::Error::IssuerNotCrlSigner, IssuerInvalidForCrl), - (webpki::Error::MalformedExtensions, ParseError), - (webpki::Error::BadDer, ParseError), - (webpki::Error::BadDerTime, ParseError), - ( - webpki::Error::UnsupportedCriticalExtension, - UnsupportedCriticalExtension, - ), - (webpki::Error::UnsupportedCrlVersion, UnsupportedCrlVersion), - (webpki::Error::UnsupportedDeltaCrl, UnsupportedDeltaCrl), - ( - webpki::Error::UnsupportedIndirectCrl, - UnsupportedIndirectCrl, - ), - ( - webpki::Error::UnsupportedRevocationReason, - UnsupportedRevocationReason, - ), - ]; - for t in testcases { - assert_eq!(crl_error(t.0.clone()), t.1); - } - - assert!(matches!( - crl_error(webpki::Error::NameConstraintViolation), - Other(..) - )); - } -} diff --git a/vendor/rustls/src/webpki/server_verifier.rs b/vendor/rustls/src/webpki/server_verifier.rs deleted file mode 100644 index 5aa92350..00000000 --- a/vendor/rustls/src/webpki/server_verifier.rs +++ /dev/null @@ -1,448 +0,0 @@ -use alloc::vec::Vec; - -use pki_types::{CertificateDer, CertificateRevocationListDer, ServerName, UnixTime}; -use webpki::{CertRevocationList, ExpirationPolicy, RevocationCheckDepth, UnknownStatusPolicy}; - -use crate::crypto::{CryptoProvider, WebPkiSupportedAlgorithms}; -use crate::log::trace; -use crate::sync::Arc; -use crate::verify::{ - DigitallySignedStruct, HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, -}; -use crate::webpki::verify::{ - ParsedCertificate, verify_server_cert_signed_by_trust_anchor_impl, verify_tls12_signature, - verify_tls13_signature, -}; -use crate::webpki::{VerifierBuilderError, parse_crls, verify_server_name}; -#[cfg(doc)] -use crate::{ConfigBuilder, ServerConfig, crypto}; -use crate::{Error, RootCertStore, SignatureScheme}; - -/// A builder for configuring a `webpki` server certificate verifier. -/// -/// For more information, see the [`WebPkiServerVerifier`] documentation. -#[derive(Debug, Clone)] -pub struct ServerCertVerifierBuilder { - roots: Arc<RootCertStore>, - crls: Vec<CertificateRevocationListDer<'static>>, - revocation_check_depth: RevocationCheckDepth, - unknown_revocation_policy: UnknownStatusPolicy, - revocation_expiration_policy: ExpirationPolicy, - supported_algs: WebPkiSupportedAlgorithms, -} - -impl ServerCertVerifierBuilder { - pub(crate) fn new( - roots: Arc<RootCertStore>, - supported_algs: WebPkiSupportedAlgorithms, - ) -> Self { - Self { - roots, - crls: Vec::new(), - revocation_check_depth: RevocationCheckDepth::Chain, - unknown_revocation_policy: UnknownStatusPolicy::Deny, - revocation_expiration_policy: ExpirationPolicy::Ignore, - supported_algs, - } - } - - /// Verify the revocation state of presented client certificates against the provided - /// certificate revocation lists (CRLs). Calling `with_crls` multiple times appends the - /// given CRLs to the existing collection. - pub fn with_crls( - mut self, - crls: impl IntoIterator<Item = CertificateRevocationListDer<'static>>, - ) -> Self { - self.crls.extend(crls); - self - } - - /// Only check the end entity certificate revocation status when using CRLs. - /// - /// If CRLs are provided using [`with_crls`][Self::with_crls] only check the end entity - /// certificate's revocation status. Overrides the default behavior of checking revocation - /// status for each certificate in the verified chain built to a trust anchor - /// (excluding the trust anchor itself). - /// - /// If no CRLs are provided then this setting has no effect. Neither the end entity certificate - /// or any intermediates will have revocation status checked. - pub fn only_check_end_entity_revocation(mut self) -> Self { - self.revocation_check_depth = RevocationCheckDepth::EndEntity; - self - } - - /// Allow unknown certificate revocation status when using CRLs. - /// - /// If CRLs are provided with [`with_crls`][Self::with_crls] and it isn't possible to - /// determine the revocation status of a certificate, do not treat it as an error condition. - /// Overrides the default behavior where unknown revocation status is considered an error. - /// - /// If no CRLs are provided then this setting has no effect as revocation status checks - /// are not performed. - pub fn allow_unknown_revocation_status(mut self) -> Self { - self.unknown_revocation_policy = UnknownStatusPolicy::Allow; - self - } - - /// Enforce the CRL nextUpdate field (i.e. expiration) - /// - /// If CRLs are provided with [`with_crls`][Self::with_crls] and the verification time is - /// beyond the time in the CRL nextUpdate field, it is expired and treated as an error condition. - /// Overrides the default behavior where expired CRLs are not treated as an error condition. - /// - /// If no CRLs are provided then this setting has no effect as revocation status checks - /// are not performed. - pub fn enforce_revocation_expiration(mut self) -> Self { - self.revocation_expiration_policy = ExpirationPolicy::Enforce; - self - } - - /// Build a server certificate verifier, allowing control over the root certificates to use as - /// trust anchors, and to control how server certificate revocation checking is performed. - /// - /// If `with_signature_verification_algorithms` was not called on the builder, a default set of - /// signature verification algorithms is used, controlled by the selected [`crypto::CryptoProvider`]. - /// - /// Once built, the provided `Arc<dyn ServerCertVerifier>` can be used with a Rustls - /// [`ServerConfig`] to configure client certificate validation using - /// [`with_client_cert_verifier`][ConfigBuilder<ClientConfig, WantsVerifier>::with_client_cert_verifier]. - /// - /// # Errors - /// This function will return a [`VerifierBuilderError`] if: - /// 1. No trust anchors have been provided. - /// 2. DER encoded CRLs have been provided that can not be parsed successfully. - pub fn build(self) -> Result<Arc<WebPkiServerVerifier>, VerifierBuilderError> { - if self.roots.is_empty() { - return Err(VerifierBuilderError::NoRootAnchors); - } - - Ok(WebPkiServerVerifier::new( - self.roots, - parse_crls(self.crls)?, - self.revocation_check_depth, - self.unknown_revocation_policy, - self.revocation_expiration_policy, - self.supported_algs, - ) - .into()) - } -} - -/// Default `ServerCertVerifier`, see the trait impl for more information. -#[allow(unreachable_pub)] -#[derive(Debug)] -pub struct WebPkiServerVerifier { - roots: Arc<RootCertStore>, - crls: Vec<CertRevocationList<'static>>, - revocation_check_depth: RevocationCheckDepth, - unknown_revocation_policy: UnknownStatusPolicy, - revocation_expiration_policy: ExpirationPolicy, - supported: WebPkiSupportedAlgorithms, -} - -#[allow(unreachable_pub)] -impl WebPkiServerVerifier { - /// Create a builder for the `webpki` server certificate verifier configuration using - /// the [process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider]. - /// - /// Server certificates will be verified using the trust anchors found in the provided `roots`. - /// - /// Use [`Self::builder_with_provider`] if you wish to specify an explicit provider. - /// - /// For more information, see the [`ServerCertVerifierBuilder`] documentation. - pub fn builder(roots: Arc<RootCertStore>) -> ServerCertVerifierBuilder { - Self::builder_with_provider( - roots, - CryptoProvider::get_default_or_install_from_crate_features().clone(), - ) - } - - /// Create a builder for the `webpki` server certificate verifier configuration using - /// a specified [`CryptoProvider`]. - /// - /// Server certificates will be verified using the trust anchors found in the provided `roots`. - /// - /// The cryptography used comes from the specified [`CryptoProvider`]. - /// - /// For more information, see the [`ServerCertVerifierBuilder`] documentation. - pub fn builder_with_provider( - roots: Arc<RootCertStore>, - provider: Arc<CryptoProvider>, - ) -> ServerCertVerifierBuilder { - ServerCertVerifierBuilder::new(roots, provider.signature_verification_algorithms) - } - - /// Short-cut for creating a `WebPkiServerVerifier` that does not perform certificate revocation - /// checking, avoiding the need to use a builder. - pub(crate) fn new_without_revocation( - roots: impl Into<Arc<RootCertStore>>, - supported_algs: WebPkiSupportedAlgorithms, - ) -> Self { - Self::new( - roots, - Vec::default(), - RevocationCheckDepth::Chain, - UnknownStatusPolicy::Allow, - ExpirationPolicy::Ignore, - supported_algs, - ) - } - - /// Constructs a new `WebPkiServerVerifier`. - /// - /// * `roots` is the set of trust anchors to trust for issuing server certs. - /// * `crls` are a vec of owned certificate revocation lists (CRLs) to use for - /// client certificate validation. - /// * `revocation_check_depth` controls which certificates have their revocation status checked - /// when `crls` are provided. - /// * `unknown_revocation_policy` controls how certificates with an unknown revocation status - /// are handled when `crls` are provided. - /// * `supported` is the set of supported algorithms that will be used for - /// certificate verification and TLS handshake signature verification. - pub(crate) fn new( - roots: impl Into<Arc<RootCertStore>>, - crls: Vec<CertRevocationList<'static>>, - revocation_check_depth: RevocationCheckDepth, - unknown_revocation_policy: UnknownStatusPolicy, - revocation_expiration_policy: ExpirationPolicy, - supported: WebPkiSupportedAlgorithms, - ) -> Self { - Self { - roots: roots.into(), - crls, - revocation_check_depth, - unknown_revocation_policy, - revocation_expiration_policy, - supported, - } - } -} - -impl ServerCertVerifier for WebPkiServerVerifier { - /// Will verify the certificate is valid in the following ways: - /// - Signed by a trusted `RootCertStore` CA - /// - Not Expired - /// - Valid for DNS entry - /// - Valid revocation status (if applicable). - /// - /// Depending on the verifier's configuration revocation status checking may be performed for - /// each certificate in the chain to a root CA (excluding the root itself), or only the - /// end entity certificate. Similarly, unknown revocation status may be treated as an error - /// or allowed based on configuration. - fn verify_server_cert( - &self, - end_entity: &CertificateDer<'_>, - intermediates: &[CertificateDer<'_>], - server_name: &ServerName<'_>, - ocsp_response: &[u8], - now: UnixTime, - ) -> Result<ServerCertVerified, Error> { - let cert = ParsedCertificate::try_from(end_entity)?; - - let crl_refs = self.crls.iter().collect::<Vec<_>>(); - - let revocation = if self.crls.is_empty() { - None - } else { - // Note: unwrap here is safe because RevocationOptionsBuilder only errors when given - // empty CRLs. - Some( - webpki::RevocationOptionsBuilder::new(crl_refs.as_slice()) - // Note: safe to unwrap here - new is only fallible if no CRLs are provided - // and we verify this above. - .unwrap() - .with_depth(self.revocation_check_depth) - .with_status_policy(self.unknown_revocation_policy) - .with_expiration_policy(self.revocation_expiration_policy) - .build(), - ) - }; - - // Note: we use the crate-internal `_impl` fn here in order to provide revocation - // checking information, if applicable. - verify_server_cert_signed_by_trust_anchor_impl( - &cert, - &self.roots, - intermediates, - revocation, - now, - self.supported.all, - )?; - - if !ocsp_response.is_empty() { - trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec()); - } - - verify_server_name(&cert, server_name)?; - Ok(ServerCertVerified::assertion()) - } - - fn verify_tls12_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - verify_tls12_signature(message, cert, dss, &self.supported) - } - - fn verify_tls13_signature( - &self, - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - ) -> Result<HandshakeSignatureValid, Error> { - verify_tls13_signature(message, cert, dss, &self.supported) - } - - fn supported_verify_schemes(&self) -> Vec<SignatureScheme> { - self.supported.supported_schemes() - } -} - -#[cfg(test)] -#[macro_rules_attribute::apply(test_for_each_provider)] -mod tests { - use std::prelude::v1::*; - use std::{println, vec}; - - use pki_types::pem::PemObject; - use pki_types::{CertificateDer, CertificateRevocationListDer}; - - use super::{VerifierBuilderError, WebPkiServerVerifier, provider}; - use crate::RootCertStore; - use crate::sync::Arc; - - fn load_crls(crls_der: &[&[u8]]) -> Vec<CertificateRevocationListDer<'static>> { - crls_der - .iter() - .map(|pem_bytes| CertificateRevocationListDer::from_pem_slice(pem_bytes).unwrap()) - .collect() - } - - fn test_crls() -> Vec<CertificateRevocationListDer<'static>> { - load_crls(&[ - include_bytes!("../../../test-ca/ecdsa-p256/client.revoked.crl.pem").as_slice(), - include_bytes!("../../../test-ca/rsa-2048/client.revoked.crl.pem").as_slice(), - ]) - } - - fn load_roots(roots_der: &[&[u8]]) -> Arc<RootCertStore> { - let mut roots = RootCertStore::empty(); - roots_der.iter().for_each(|der| { - roots - .add(CertificateDer::from(der.to_vec())) - .unwrap() - }); - roots.into() - } - - fn test_roots() -> Arc<RootCertStore> { - load_roots(&[ - include_bytes!("../../../test-ca/ecdsa-p256/ca.der").as_slice(), - include_bytes!("../../../test-ca/rsa-2048/ca.der").as_slice(), - ]) - } - - #[test] - fn test_with_invalid_crls() { - // Trying to build a server verifier with invalid CRLs should error at build time. - let result = WebPkiServerVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(vec![CertificateRevocationListDer::from(vec![0xFF])]) - .build(); - assert!(matches!(result, Err(VerifierBuilderError::InvalidCrl(_)))); - } - - #[test] - fn test_with_crls_multiple_calls() { - // We should be able to call `with_crls` on a server verifier multiple times. - let initial_crls = test_crls(); - let extra_crls = - load_crls(&[ - include_bytes!("../../../test-ca/eddsa/client.revoked.crl.pem").as_slice(), - ]); - - let builder = WebPkiServerVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .with_crls(initial_crls.clone()) - .with_crls(extra_crls.clone()); - - // There should be the expected number of crls. - assert_eq!(builder.crls.len(), initial_crls.len() + extra_crls.len()); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_builder_no_roots() { - // Trying to create a server verifier builder with no trust anchors should fail at build time - let result = WebPkiServerVerifier::builder_with_provider( - RootCertStore::empty().into(), - provider::default_provider().into(), - ) - .build(); - assert!(matches!(result, Err(VerifierBuilderError::NoRootAnchors))); - } - - #[test] - fn test_server_verifier_ee_only() { - // We should be able to build a server cert. verifier that only checks the EE cert. - let builder = WebPkiServerVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .only_check_end_entity_revocation(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_server_verifier_allow_unknown() { - // We should be able to build a server cert. verifier that allows unknown revocation - // status. - let builder = WebPkiServerVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .allow_unknown_revocation_status(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_server_verifier_allow_unknown_ee_only() { - // We should be able to build a server cert. verifier that allows unknown revocation - // status and only checks the EE cert. - let builder = WebPkiServerVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .allow_unknown_revocation_status() - .only_check_end_entity_revocation(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } - - #[test] - fn test_server_verifier_enforce_expiration() { - // We should be able to build a server cert. verifier that allows unknown revocation - // status. - let builder = WebPkiServerVerifier::builder_with_provider( - test_roots(), - provider::default_provider().into(), - ) - .enforce_revocation_expiration(); - // The builder should be Debug. - println!("{builder:?}"); - builder.build().unwrap(); - } -} diff --git a/vendor/rustls/src/webpki/verify.rs b/vendor/rustls/src/webpki/verify.rs deleted file mode 100644 index 5c3e79be..00000000 --- a/vendor/rustls/src/webpki/verify.rs +++ /dev/null @@ -1,289 +0,0 @@ -use alloc::vec::Vec; -use core::fmt; - -use pki_types::{ - CertificateDer, ServerName, SignatureVerificationAlgorithm, SubjectPublicKeyInfoDer, UnixTime, -}; - -use super::anchors::RootCertStore; -use super::pki_error; -use crate::enums::SignatureScheme; -use crate::error::{Error, PeerMisbehaved}; -use crate::verify::{DigitallySignedStruct, HandshakeSignatureValid}; - -/// Verify that the end-entity certificate `end_entity` is a valid server cert -/// and chains to at least one of the trust anchors in the `roots` [RootCertStore]. -/// -/// This function is primarily useful when building a custom certificate verifier. It -/// performs **no revocation checking**. Implementers must handle this themselves, -/// along with checking that the server certificate is valid for the subject name -/// being used (see [`verify_server_name`]). -/// -/// `intermediates` contains all certificates other than `end_entity` that -/// were sent as part of the server's `Certificate` message. It is in the -/// same order that the server sent them and may be empty. -#[allow(dead_code)] -pub fn verify_server_cert_signed_by_trust_anchor( - cert: &ParsedCertificate<'_>, - roots: &RootCertStore, - intermediates: &[CertificateDer<'_>], - now: UnixTime, - supported_algs: &[&dyn SignatureVerificationAlgorithm], -) -> Result<(), Error> { - verify_server_cert_signed_by_trust_anchor_impl( - cert, - roots, - intermediates, - None, // No revocation checking supported with this API. - now, - supported_algs, - ) -} - -/// Verify that the `end_entity` has an alternative name matching the `server_name`. -/// -/// Note: this only verifies the name and should be used in conjunction with more verification -/// like [verify_server_cert_signed_by_trust_anchor] -pub fn verify_server_name( - cert: &ParsedCertificate<'_>, - server_name: &ServerName<'_>, -) -> Result<(), Error> { - cert.0 - .verify_is_valid_for_subject_name(server_name) - .map_err(pki_error) -} - -/// Describes which `webpki` signature verification algorithms are supported and -/// how they map to TLS [`SignatureScheme`]s. -#[derive(Clone, Copy)] -#[allow(unreachable_pub)] -pub struct WebPkiSupportedAlgorithms { - /// A list of all supported signature verification algorithms. - /// - /// Used for verifying certificate chains. - /// - /// The order of this list is not significant. - pub all: &'static [&'static dyn SignatureVerificationAlgorithm], - - /// A mapping from TLS `SignatureScheme`s to matching webpki signature verification algorithms. - /// - /// This is one (`SignatureScheme`) to many ([`SignatureVerificationAlgorithm`]) because - /// (depending on the protocol version) there is not necessary a 1-to-1 mapping. - /// - /// For TLS1.2, all `SignatureVerificationAlgorithm`s are tried in sequence. - /// - /// For TLS1.3, only the first is tried. - /// - /// The supported schemes in this mapping is communicated to the peer and the order is significant. - /// The first mapping is our highest preference. - pub mapping: &'static [( - SignatureScheme, - &'static [&'static dyn SignatureVerificationAlgorithm], - )], -} - -impl WebPkiSupportedAlgorithms { - /// Return all the `scheme` items in `mapping`, maintaining order. - pub fn supported_schemes(&self) -> Vec<SignatureScheme> { - self.mapping - .iter() - .map(|item| item.0) - .collect() - } - - /// Return the first item in `mapping` that matches `scheme`. - fn convert_scheme( - &self, - scheme: SignatureScheme, - ) -> Result<&[&'static dyn SignatureVerificationAlgorithm], Error> { - self.mapping - .iter() - .filter_map(|item| if item.0 == scheme { Some(item.1) } else { None }) - .next() - .ok_or_else(|| PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into()) - } - - /// Return `true` if all cryptography is FIPS-approved. - pub fn fips(&self) -> bool { - self.all.iter().all(|alg| alg.fips()) - && self - .mapping - .iter() - .all(|item| item.1.iter().all(|alg| alg.fips())) - } -} - -impl fmt::Debug for WebPkiSupportedAlgorithms { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "WebPkiSupportedAlgorithms {{ all: [ .. ], mapping: ")?; - f.debug_list() - .entries(self.mapping.iter().map(|item| item.0)) - .finish()?; - write!(f, " }}") - } -} - -/// Wrapper around internal representation of a parsed certificate. -/// -/// This is used in order to avoid parsing twice when specifying custom verification -pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>); - -impl ParsedCertificate<'_> { - /// Get the parsed certificate's SubjectPublicKeyInfo (SPKI) - pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> { - self.0.subject_public_key_info() - } -} - -impl<'a> TryFrom<&'a CertificateDer<'a>> for ParsedCertificate<'a> { - type Error = Error; - fn try_from(value: &'a CertificateDer<'a>) -> Result<Self, Self::Error> { - webpki::EndEntityCert::try_from(value) - .map_err(pki_error) - .map(ParsedCertificate) - } -} - -/// Verify a message signature using the `cert` public key and any supported scheme. -/// -/// This function verifies the `dss` signature over `message` using the subject public key from -/// `cert`. Since TLS 1.2 doesn't provide enough information to map the `dss.scheme` into a single -/// [`SignatureVerificationAlgorithm`], this function will map to several candidates and try each in -/// succession until one succeeds or we exhaust all candidates. -/// -/// See [WebPkiSupportedAlgorithms::mapping] for more information. -pub fn verify_tls12_signature( - message: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - supported_schemes: &WebPkiSupportedAlgorithms, -) -> Result<HandshakeSignatureValid, Error> { - let possible_algs = supported_schemes.convert_scheme(dss.scheme)?; - let cert = webpki::EndEntityCert::try_from(cert).map_err(pki_error)?; - - let mut error = None; - for alg in possible_algs { - match cert.verify_signature(*alg, message, dss.signature()) { - Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKeyContext(_)) => { - error = Some(err); - continue; - } - Err(e) => return Err(pki_error(e)), - Ok(()) => return Ok(HandshakeSignatureValid::assertion()), - } - } - - #[allow(deprecated)] // The `unwrap_or()` should be statically unreachable - Err(pki_error(error.unwrap_or( - webpki::Error::UnsupportedSignatureAlgorithmForPublicKey, - ))) -} - -/// Verify a message signature using the `cert` public key and the first TLS 1.3 compatible -/// supported scheme. -/// -/// This function verifies the `dss` signature over `message` using the subject public key from -/// `cert`. Unlike [verify_tls12_signature], this function only tries the first matching scheme. See -/// [WebPkiSupportedAlgorithms::mapping] for more information. -pub fn verify_tls13_signature( - msg: &[u8], - cert: &CertificateDer<'_>, - dss: &DigitallySignedStruct, - supported_schemes: &WebPkiSupportedAlgorithms, -) -> Result<HandshakeSignatureValid, Error> { - if !dss.scheme.supported_in_tls13() { - return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into()); - } - - let alg = supported_schemes.convert_scheme(dss.scheme)?[0]; - - let cert = webpki::EndEntityCert::try_from(cert).map_err(pki_error)?; - - cert.verify_signature(alg, msg, dss.signature()) - .map_err(pki_error) - .map(|_| HandshakeSignatureValid::assertion()) -} - -/// Verify a message signature using a raw public key and the first TLS 1.3 compatible -/// supported scheme. -pub fn verify_tls13_signature_with_raw_key( - msg: &[u8], - spki: &SubjectPublicKeyInfoDer<'_>, - dss: &DigitallySignedStruct, - supported_schemes: &WebPkiSupportedAlgorithms, -) -> Result<HandshakeSignatureValid, Error> { - if !dss.scheme.supported_in_tls13() { - return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into()); - } - - let raw_key = webpki::RawPublicKeyEntity::try_from(spki).map_err(pki_error)?; - let alg = supported_schemes.convert_scheme(dss.scheme)?[0]; - - raw_key - .verify_signature(alg, msg, dss.signature()) - .map_err(pki_error) - .map(|_| HandshakeSignatureValid::assertion()) -} - -/// Verify that the end-entity certificate `end_entity` is a valid server cert -/// and chains to at least one of the trust anchors in the `roots` [RootCertStore]. -/// -/// `intermediates` contains all certificates other than `end_entity` that -/// were sent as part of the server's `Certificate` message. It is in the -/// same order that the server sent them and may be empty. -/// -/// `revocation` controls how revocation checking is performed, if at all. -/// -/// This function exists to be used by [`verify_server_cert_signed_by_trust_anchor`], -/// and differs only in providing a `Option<webpki::RevocationOptions>` argument. We -/// can't include this argument in `verify_server_cert_signed_by_trust_anchor` because -/// it will leak the webpki types into Rustls' public API. -pub(crate) fn verify_server_cert_signed_by_trust_anchor_impl( - cert: &ParsedCertificate<'_>, - roots: &RootCertStore, - intermediates: &[CertificateDer<'_>], - revocation: Option<webpki::RevocationOptions<'_>>, - now: UnixTime, - supported_algs: &[&dyn SignatureVerificationAlgorithm], -) -> Result<(), Error> { - let result = cert.0.verify_for_usage( - supported_algs, - &roots.roots, - intermediates, - now, - webpki::KeyUsage::server_auth(), - revocation, - None, - ); - match result { - Ok(_) => Ok(()), - Err(e) => Err(pki_error(e)), - } -} - -#[cfg(test)] -mod tests { - use std::format; - - use super::*; - - #[test] - fn certificate_debug() { - assert_eq!( - "CertificateDer(0x6162)", - format!("{:?}", CertificateDer::from(b"ab".to_vec())) - ); - } - - #[cfg(feature = "ring")] - #[test] - fn webpki_supported_algorithms_is_debug() { - assert_eq!( - "WebPkiSupportedAlgorithms { all: [ .. ], mapping: [ECDSA_NISTP384_SHA384, ECDSA_NISTP256_SHA256, ED25519, RSA_PSS_SHA512, RSA_PSS_SHA384, RSA_PSS_SHA256, RSA_PKCS1_SHA512, RSA_PKCS1_SHA384, RSA_PKCS1_SHA256] }", - format!( - "{:?}", - crate::crypto::ring::default_provider().signature_verification_algorithms - ) - ); - } -} diff --git a/vendor/rustls/src/x509.rs b/vendor/rustls/src/x509.rs deleted file mode 100644 index 2620fe8a..00000000 --- a/vendor/rustls/src/x509.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Additional x509/asn1 functions to those provided in webpki/ring. - -use alloc::vec::Vec; - -/// Prepend stuff to `bytes` to put it in a DER SEQUENCE. -pub(crate) fn wrap_in_sequence(bytes: &[u8]) -> Vec<u8> { - asn1_wrap(DER_SEQUENCE_TAG, bytes, &[]) -} - -/// Prepend stuff to `bytes_a` + `bytes_b` to put it in a DER SEQUENCE. -#[cfg_attr(not(feature = "ring"), allow(dead_code))] -pub(crate) fn wrap_concat_in_sequence(bytes_a: &[u8], bytes_b: &[u8]) -> Vec<u8> { - asn1_wrap(DER_SEQUENCE_TAG, bytes_a, bytes_b) -} - -/// Prepend stuff to `bytes` to put it in a DER BIT STRING. -pub(crate) fn wrap_in_bit_string(bytes: &[u8]) -> Vec<u8> { - asn1_wrap(DER_BIT_STRING_TAG, &[0u8], bytes) -} - -/// Prepend stuff to `bytes` to put it in a DER OCTET STRING. -#[cfg_attr(not(feature = "ring"), allow(dead_code))] -pub(crate) fn wrap_in_octet_string(bytes: &[u8]) -> Vec<u8> { - asn1_wrap(DER_OCTET_STRING_TAG, bytes, &[]) -} - -fn asn1_wrap(tag: u8, bytes_a: &[u8], bytes_b: &[u8]) -> Vec<u8> { - let len = bytes_a.len() + bytes_b.len(); - - if len <= 0x7f { - // Short form - let mut ret = Vec::with_capacity(2 + len); - ret.push(tag); - ret.push(len as u8); - ret.extend_from_slice(bytes_a); - ret.extend_from_slice(bytes_b); - ret - } else { - // Long form - let size = len.to_be_bytes(); - let leading_zero_bytes = size - .iter() - .position(|&x| x != 0) - .unwrap_or(size.len()); - assert!(leading_zero_bytes < size.len()); - let encoded_bytes = size.len() - leading_zero_bytes; - - let mut ret = Vec::with_capacity(2 + encoded_bytes + len); - ret.push(tag); - - ret.push(0x80 + encoded_bytes as u8); - ret.extend_from_slice(&size[leading_zero_bytes..]); - - ret.extend_from_slice(bytes_a); - ret.extend_from_slice(bytes_b); - ret - } -} - -const DER_SEQUENCE_TAG: u8 = 0x30; -const DER_BIT_STRING_TAG: u8 = 0x03; -const DER_OCTET_STRING_TAG: u8 = 0x04; - -#[cfg(test)] -mod tests { - use std::vec; - - use super::*; - - #[test] - fn test_empty() { - assert_eq!(vec![0x30, 0x00], wrap_in_sequence(&[])); - } - - #[test] - fn test_small() { - assert_eq!( - vec![0x30, 0x04, 0x00, 0x11, 0x22, 0x33], - wrap_in_sequence(&[0x00, 0x11, 0x22, 0x33]) - ); - } - - #[test] - fn test_medium() { - let mut val = Vec::new(); - val.resize(255, 0x12); - assert_eq!( - vec![0x30, 0x81, 0xff, 0x12, 0x12, 0x12], - wrap_in_sequence(&val)[..6] - ); - } - - #[test] - fn test_large() { - let mut val = Vec::new(); - val.resize(4660, 0x12); - wrap_in_sequence(&val); - assert_eq!( - vec![0x30, 0x82, 0x12, 0x34, 0x12, 0x12], - wrap_in_sequence(&val)[..6] - ); - } - - #[test] - fn test_huge() { - let mut val = Vec::new(); - val.resize(0xffff, 0x12); - let result = wrap_in_sequence(&val); - assert_eq!(vec![0x30, 0x82, 0xff, 0xff, 0x12, 0x12], result[..6]); - assert_eq!(result.len(), 0xffff + 4); - } - - #[test] - fn test_gigantic() { - let mut val = Vec::new(); - val.resize(0x100000, 0x12); - let result = wrap_in_sequence(&val); - assert_eq!(vec![0x30, 0x83, 0x10, 0x00, 0x00, 0x12, 0x12], result[..7]); - assert_eq!(result.len(), 0x100000 + 5); - } - - #[test] - fn test_ludicrous() { - let mut val = Vec::new(); - val.resize(0x1000000, 0x12); - let result = wrap_in_sequence(&val); - assert_eq!( - vec![0x30, 0x84, 0x01, 0x00, 0x00, 0x00, 0x12, 0x12], - result[..8] - ); - assert_eq!(result.len(), 0x1000000 + 6); - } - - #[test] - fn test_wrap_in_bit_string() { - // The BIT STRING encoding starts with a single octet on - // the front saying how many bits to disregard from the - // last octet. So this zero means "no bits" unused, which - // is correct because our input is an string of octets. - // - // So if we encode &[0x55u8] with this function, we should get: - // - // 0x03 0x02 0x00 0x55 - // ^ tag ^ len ^ no unused bits ^ value - assert_eq!(wrap_in_bit_string(&[0x55u8]), vec![0x03, 0x02, 0x00, 0x55]); - } -} |
