pax_global_header00006660000000000000000000000064145346171000014513gustar00rootroot0000000000000052 comment=cf6aa80cbfb1f18e308138fdd59ac8255ac931ce rustls-v-0.21.10/000077500000000000000000000000001453461710000134535ustar00rootroot00000000000000rustls-v-0.21.10/.github/000077500000000000000000000000001453461710000150135ustar00rootroot00000000000000rustls-v-0.21.10/.github/codecov.yml000066400000000000000000000001741453461710000171620ustar00rootroot00000000000000coverage: status: patch: default: threshold: 0.05% project: default: threshold: 0.05% rustls-v-0.21.10/.github/dependabot.yml000066400000000000000000000003251453461710000176430ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: cargo directory: "/" schedule: interval: daily open-pull-requests-limit: 10 - package-ecosystem: github-actions directory: "/" schedule: interval: weekly rustls-v-0.21.10/.github/workflows/000077500000000000000000000000001453461710000170505ustar00rootroot00000000000000rustls-v-0.21.10/.github/workflows/build.yml000066400000000000000000000174561453461710000207070ustar00rootroot00000000000000name: rustls permissions: contents: read on: push: pull_request: schedule: - cron: '0 18 * * *' jobs: build: name: Build+test runs-on: ${{ matrix.os }} strategy: matrix: # test a bunch of toolchains on ubuntu rust: - stable - beta - nightly os: [ubuntu-20.04] # but only stable on macos/windows (slower platforms) include: - os: macos-latest rust: stable - os: windows-latest rust: stable steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install ${{ matrix.rust }} toolchain uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - name: cargo build (debug; default features) run: cargo build - name: cargo test (debug; all features) run: cargo test --all-features env: RUST_BACKTRACE: 1 msrv: name: MSRV runs-on: ubuntu-20.04 steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - uses: dtolnay/rust-toolchain@master with: toolchain: "1.61" - run: cargo check --lib --all-features -p rustls features: name: Features runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable - name: cargo build (debug; default features) run: cargo build - name: cargo test (debug; default features) run: cargo test env: RUST_BACKTRACE: 1 - name: cargo build (debug; no default features) run: cargo test --no-default-features - name: cargo test (debug; no default features; tls12) run: cargo test --no-default-features --features tls12 - name: cargo test (release; no run) run: cargo test --release --no-run bogo: name: BoGo test suite runs-on: ubuntu-20.04 steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install stable toolchain uses: dtolnay/rust-toolchain@stable - name: Install golang toolchain uses: actions/setup-go@v4 with: go-version: "1.20" - name: Run test suite working-directory: bogo run: ./runme fuzz: name: Smoke-test fuzzing targets runs-on: ubuntu-20.04 steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install nightly toolchain uses: dtolnay/rust-toolchain@nightly - name: Install cargo fuzz run: cargo install cargo-fuzz - name: Smoke-test fuzz targets run: | cargo fuzz build for target in $(cargo fuzz list) ; do cargo fuzz run $target -- -max_total_time=10 done benchmarks: name: Run benchmarks runs-on: ubuntu-20.04 steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install stable toolchain uses: dtolnay/rust-toolchain@nightly - name: Smoke-test benchmark program run: cargo run --release --example bench - name: Run micro-benchmarks run: cargo bench env: RUSTFLAGS: --cfg=bench docs: name: Check for documentation errors runs-on: ubuntu-20.04 steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install rust toolchain uses: dtolnay/rust-toolchain@nightly - name: cargo doc (all features) run: cargo doc --all-features --no-deps --workspace env: RUSTDOCFLAGS: -Dwarnings coverage: name: Measure coverage runs-on: ubuntu-20.04 steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install rust toolchain uses: dtolnay/rust-toolchain@nightly with: components: llvm-tools - name: Install cargo-llvm-cov run: cargo install cargo-llvm-cov - name: Install golang toolchain uses: actions/setup-go@v4 with: go-version: "1.20" - name: Measure coverage run: ./admin/coverage --lcov --output-path final.info - name: Report to codecov.io uses: codecov/codecov-action@v3 with: file: final.info fail_ci_if_error: false minver: name: Check minimum versions runs-on: ubuntu-20.04 steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install rust toolchain uses: dtolnay/rust-toolchain@nightly - name: cargo test (debug; all features; -Z minimal-versions) run: cargo -Z minimal-versions test --all-features cross: name: Check cross compilation targets runs-on: ubuntu-20.04 steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install cross uses: taiki-e/install-action@cross - run: cross build --target i686-unknown-linux-gnu semver: name: Check semver compatibility runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Check semver uses: obi1kenobi/cargo-semver-checks-action@v2 format: name: Format runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable with: components: rustfmt - name: Check formatting run: cargo fmt --all -- --check - name: Check formatting (connect-tests workspace) run: cargo fmt --all --manifest-path=connect-tests/Cargo.toml -- --check - name: Check formatting (fuzz workspace) run: cargo fmt --all --manifest-path=fuzz/Cargo.toml -- --check clippy: name: Clippy runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install rust toolchain uses: dtolnay/rust-toolchain@stable with: components: clippy - run: cargo clippy --package rustls --all-features -- --deny warnings --allow unknown-lints - run: cargo clippy --package rustls --no-default-features -- --deny warnings --allow unknown-lints - run: cargo clippy --manifest-path=connect-tests/Cargo.toml --all-features -- --deny warnings --allow unknown-lints - run: cargo clippy --manifest-path=fuzz/Cargo.toml --all-features -- --deny warnings --allow unknown-lints clippy-nightly: name: Clippy (Nightly) runs-on: ubuntu-latest steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install rust toolchain uses: dtolnay/rust-toolchain@nightly with: components: clippy - run: cargo clippy --package rustls --all-features - run: cargo clippy --package rustls --no-default-features -- --deny warnings - run: cargo clippy --manifest-path=connect-tests/Cargo.toml --all-features -- --deny warnings - run: cargo clippy --manifest-path=fuzz/Cargo.toml --all-features -- --deny warnings rustls-v-0.21.10/.github/workflows/cifuzz.yml000066400000000000000000000012731453461710000211100ustar00rootroot00000000000000name: CIFuzz on: [pull_request] jobs: Fuzzing: runs-on: ubuntu-latest steps: - name: Build Fuzzers id: build uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master with: oss-fuzz-project-name: 'rustls' dry-run: false language: rust - name: Run Fuzzers uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master with: oss-fuzz-project-name: 'rustls' fuzz-seconds: 150 dry-run: false language: rust - name: Upload Crash uses: actions/upload-artifact@v3 if: failure() && steps.build.outcome == 'success' with: name: artifacts path: ./out/artifacts rustls-v-0.21.10/.github/workflows/connect-tests.yml000066400000000000000000000023241453461710000223650ustar00rootroot00000000000000name: connect-tests permissions: contents: read on: schedule: # We only run connectivity tests on a weekly basis, choosing a weekday and # a time slightly offset from the top of the hour. - cron: '15 12 * * 3' jobs: build: name: Connectivity Tests runs-on: ${{ matrix.os }} strategy: matrix: # test a bunch of toolchains on ubuntu rust: - stable - beta - nightly - "1.60" # MSRV os: [ubuntu-20.04] # but only stable on macos/windows (slower platforms) include: - os: macos-latest rust: stable - os: windows-latest rust: stable steps: - name: Checkout sources uses: actions/checkout@v3 with: persist-credentials: false - name: Install ${{ matrix.rust }} toolchain uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - run: cargo build - run: cargo test --manifest-path=connect-tests/Cargo.toml env: RUST_BACKTRACE: 1 - run: cargo run --bin simpleclient - run: cargo run --bin limitedclient - run: cargo run --bin simple_0rtt_client rustls-v-0.21.10/.gitignore000066400000000000000000000002221453461710000154370ustar00rootroot00000000000000Cargo.lock target/ *.gcda *.gcno *.info sslkeylogfile.txt admin/rustfmt .DS_Store ._.DS_Store **/.DS_Store **/._.DS_Store /.idea /default.profraw rustls-v-0.21.10/.rustfmt.toml000066400000000000000000000000171453461710000161300ustar00rootroot00000000000000chain_width=40 rustls-v-0.21.10/CODE_OF_CONDUCT.md000066400000000000000000000004071453461710000162530ustar00rootroot00000000000000# 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. rustls-v-0.21.10/CONTRIBUTING.md000066400000000000000000000041751453461710000157130ustar00rootroot00000000000000# Contributing Thanks for considering helping this project. There are many ways you can help: using the library and reporting bugs, reporting usability issues, making additions and improvements to the library, documentation and finding security bugs. ## Reporting bugs Please file a github issue. Include as much information as possible. Suspected protocol bugs are easier debugged with a pcap or reproduction steps. Feel free to file github issues to get help, or ask a question. ## Code changes Some ideas and guidelines for contributions: - For large features, file an issue prior to starting work. This means everyone can see what is in progress prior to a PR. - Feel free to submit a PR even if the work is not totally finished, for feedback or to hand-over. - Prefer not to reference github issue or PR numbers in commits. - Try to keep code formatting commits separate from functional commits. - See [`.github/workflows/build.yml`](.github/workflows/build.yml) for how to run the various test suites, and how to make coverage measurements. - I run `cargo outdated` prior to major releases; but PRs to update specific dependencies are welcome. ## Security bugs Please report security bugs by filing a github issue, or by email to jbp@jbp.io if you want to disclose privately. I'll then: - Prepare a fix and regression tests. - Backport the fix and make a patch release for most recent release. - Submit an advisory to [rustsec/advisory-db](https://github.com/RustSec/advisory-db). - Refer to the advisory on the main README.md and release notes. If you're *looking* for security bugs, this crate is set up for `cargo fuzz` but would benefit from more runtime, targets and corpora. ## Testing - Features involving additions to the public API should have (at least) API-level tests (see [`rustls/tests/api.rs`](rustls/tests/api.rs)). - Protocol additions should have some coverage -- consider enabling corresponding tests in the bogo suite, or writing some ad hoc tests. PRs which cause test failures or a significant coverage decrease are unlikely to be accepted. ## Licensing Contributions are made under [rustls's licenses](LICENSE). rustls-v-0.21.10/Cargo.toml000066400000000000000000000002311453461710000153770ustar00rootroot00000000000000[workspace] members = [ # tests and example code "examples", # the main library and tests "rustls", ] exclude = ["admin/rustfmt"] resolver = "2" rustls-v-0.21.10/LICENSE000066400000000000000000000004361453461710000144630ustar00rootroot00000000000000Rustls 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. rustls-v-0.21.10/LICENSE-APACHE000066400000000000000000000251371453461710000154070ustar00rootroot00000000000000 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. rustls-v-0.21.10/LICENSE-ISC000066400000000000000000000014071453461710000150760ustar00rootroot00000000000000ISC License (ISC) Copyright (c) 2016, Joseph Birr-Pixton 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. rustls-v-0.21.10/LICENSE-MIT000066400000000000000000000020721453461710000151100ustar00rootroot00000000000000Copyright (c) 2016 Joseph Birr-Pixton 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. rustls-v-0.21.10/README.md000066400000000000000000000231651453461710000147410ustar00rootroot00000000000000

Rustls is a modern TLS library written in Rust. It uses ring for cryptography and webpki for certificate verification.

# Status Rustls is mature and widely used. While most of the API surface is stable, we expect the next few releases will make further changes as needed to accomodate new features or performance improvements. If you'd like to help out, please see [CONTRIBUTING.md](CONTRIBUTING.md). [![Build Status](https://github.com/rustls/rustls/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/rustls/rustls/actions/workflows/build.yml?query=branch%3Amain) [![Coverage Status (codecov.io)](https://codecov.io/gh/rustls/rustls/branch/main/graph/badge.svg)](https://codecov.io/gh/rustls/rustls/) [![Documentation](https://docs.rs/rustls/badge.svg)](https://docs.rs/rustls/) [![Chat](https://img.shields.io/discord/976380008299917365?logo=discord)](https://discord.gg/MCSB76RU96) ## Release history Release history can be found [on GitHub](https://github.com/rustls/rustls/releases). # Documentation Lives here: 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. ## Current features * TLS1.2 and TLS1.3. * ECDSA, Ed25519 or RSA server authentication by clients. * ECDSA, Ed25519 or RSA server authentication by servers. * Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. * 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 for clients. * TLS1.3 0-RTT data for servers. * Client authentication by clients. * Client authentication by servers. * Extended master secret support ([RFC7627](https://tools.ietf.org/html/rfc7627)). * Exporters ([RFC5705](https://tools.ietf.org/html/rfc5705)). * OCSP stapling by servers. * SCT stapling by servers. * SCT verification by clients. ## Possible future features * PSK support. * OCSP verification by clients. * Certificate pinning. ## Non-features For reasons [explained in the manual](https://docs.rs/rustls/latest/rustls/manual/_02_tls_vulnerabilities/index.html), 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. * Compression. * Discrete-log Diffie-Hellman. * Automatic protocol version downgrade. There are plenty of other libraries that provide these features should you need them. ### Platform support While Rustls itself is platform independent it uses [`ring`](https://crates.io/crates/ring) for implementing the cryptography in TLS. As a result, rustls only runs on platforms supported by `ring`. At the time of writing, this means 32-bit ARM, Aarch64 (64-bit ARM), x86, x86-64, LoongArch64, 32-bit & 64-bit Little Endian MIPS, 32-bit PowerPC (Big Endian), 64-bit PowerPC (Big and Little Endian), 64-bit RISC-V, and s390x. We do not presently support WebAssembly. For more information, see [the supported `ring` target platforms][ring-target-platforms]. Rustls requires Rust 1.61 or later. [ring-target-platforms]: https://github.com/briansmith/ring/blob/2e8363b433fa3b3962c877d9ed2e9145612f3160/include/ring-core/target.h#L18-L64 # Example code There are two example programs which use [mio](https://github.com/carllerche/mio) to do asynchronous IO. ## Client example program The client example program is named `tlsclient-mio`. The interface looks like: ```tlsclient-mio Connects to the TLS server at hostname:PORT. The default PORT is 443. By default, this reads a request from stdin (to EOF) before making the connection. --http replaces this with a basic HTTP GET request for /. If --cafile is not supplied, a built-in set of CA certificates are used from the webpki-roots crate. Usage: tlsclient-mio [options] [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] tlsclient-mio (--version | -v) tlsclient-mio (--help | -h) Options: -p, --port PORT Connect to PORT [default: 443]. --http Send a basic HTTP GET request for /. --cafile CAFILE Read root certificates from CAFILE. --auth-key KEY Read client authentication key from KEY. --auth-certs CERTS Read client authentication certificates from CERTS. CERTS must match up with KEY. --protover VERSION Disable default TLS version list, and use VERSION instead. May be used multiple times. --suite SUITE Disable default cipher suite list, and use SUITE instead. May be used multiple times. --proto PROTOCOL Send ALPN extension containing PROTOCOL. May be used multiple times to offer several protocols. --no-tickets Disable session ticket support. --no-sni Disable server name indication support. --insecure Disable certificate verification. --verbose Emit log output. --max-frag-size M Limit outgoing messages to M bytes. --version, -v Show tool version. --help, -h Show this screen. ``` 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 ``` ## Server example program The server example program is named `tlsserver-mio`. The interface looks like: ```tlsserver-mio Runs a TLS server on :PORT. The default PORT is 443. `echo' mode means the server echoes received data on each connection. `http' mode means the server blindly sends a HTTP response on each connection. `forward' means the server forwards plaintext to a connection made to localhost:fport. `--certs' names the full certificate chain, `--key' provides the RSA private key. Usage: tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] echo tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] http tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] [options] forward tlsserver-mio (--version | -v) tlsserver-mio (--help | -h) Options: -p, --port PORT Listen on PORT [default: 443]. --certs CERTFILE Read server certificates from CERTFILE. This should contain PEM-format certificates in the right order (the first certificate should certify KEYFILE, the last should be a root CA). --key KEYFILE Read private key from KEYFILE. This should be a RSA private key or PKCS8-encoded private key, in PEM format. --ocsp OCSPFILE Read DER-encoded OCSP response from OCSPFILE and staple to certificate. Optional. --auth CERTFILE Enable client authentication, and accept certificates signed by those roots provided in CERTFILE. --require-auth Send a fatal alert if the client does not complete client authentication. --resumption Support session resumption. --tickets Support tickets. --protover VERSION Disable default TLS version list, and use VERSION instead. May be used multiple times. --suite SUITE Disable default cipher suite list, and use SUITE instead. May be used multiple times. --proto PROTOCOL Negotiate PROTOCOL using ALPN. May be used multiple times. --verbose Emit log output. --version, -v Show tool version. --help, -h Show this screen. ``` 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/end.fullchain --key test-ca/rsa/end.rsa -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/ca.cert -p 8443 localhost hello world ^C ``` # 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. # 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. rustls-v-0.21.10/RELEASING.md000066400000000000000000000051071453461710000153110ustar00rootroot00000000000000## Before making a release 1. Run `cargo update` followed by `cargo outdated`, to check if we have any dependency updates which are not already automatically taken by their semver specs. - If we do, take them if possible. There should be dependabot PRs submitted for these already, but if not make separate commits for these and land those first. 2. Update `rustls/Cargo.toml` to set the correct version. 3. Make a commit with the new version number, something like 'Prepare $VERSION'. This should not contain functional changes: just version numbers, and perhaps markdown changes. 4. Do a dry run: in `rustls/` check `cargo publish --dry-run`. - Do not use `--allow-dirty`; use a separate working tree if needed. 5. Come up with text detailing headline changes for this release. General guidelines: * :green_heart: include any breaking changes. * :green_heart: include any major new headline features. * :green_heart: include any major, user-visible bug fixes. * :green_heart: include any new API deprecations. * :green_heart: emphasise contributions from outside the maintainer team. * :x: omit any internal build, process or test improvements. * :x: omit any minor or user-invisible bug fixes. * :x: omit any changes to dependency versions (unless these cause breaking changes). 5. Open a PR with the above commit and include the release notes in the description. Wait for review and CI to confirm it as green. - Any red _should_ naturally block the release. - If rustc nightly is broken, this _may_ be acceptable if the reason is understood and does not point to a defect in rustls. eg, at the time of writing in releasing 0.20: - `cargo fuzz` is broken: https://github.com/rust-fuzz/cargo-fuzz/issues/276 - oss fuzz is broken: https://github.com/google/oss-fuzz/issues/6268 (Both of these share the same root cause of LLVM13 breaking changes; which are unfortunately common when rustc nightly takes a new LLVM.) ## Making a release 1. Tag the released version: eg. `git tag -m '0.20.0' v/0.20.0` 2. Push the tag: eg. `git push origin v/0.20.0` 3. Do the release: `cargo publish` when sat in `rustls/`. - Do not use `--allow-dirty`; use a separate working tree if needed. ## After making a release 1. Create a new GitHub release for that tag. Use "Generate release notes" (against the tag for the previous release) as a starting point for the release description. Then add the "headlines" produced earlier at the top. 2. Update dependent crates (eg, hyper-rustls, rustls-native-certs, etc.) if this was a semver-incompatible release. rustls-v-0.21.10/SECURITY.md000066400000000000000000000017011453461710000152430ustar00rootroot00000000000000# Security Policy ## Supported Versions Security fixes will be backported only to the rustls versions for which the original semver-compatible release was published less than 2 years ago. For example, as of 2023-06-13 the latest release is 0.21.1. * 0.21.0 was released in March of 2023 * 0.20.0 was released in September of 2021 * 0.19.0 was released in November of 2020 Therefore 0.20.x and 0.21.x will be updated, while 0.19.x will not be. ## Reporting a Vulnerability Please report security bugs by email to rustls-security@googlegroups.com. We'll then: - Prepare a fix and regression tests. - Backport the fix and make a patch release for most recent release. - Submit an advisory to [rustsec/advisory-db](https://github.com/RustSec/advisory-db). - Refer to the advisory on the main README.md and release notes. If you're *looking* for security bugs, this crate is set up for `cargo fuzz` but would benefit from more runtime, targets and corpora. rustls-v-0.21.10/admin/000077500000000000000000000000001453461710000145435ustar00rootroot00000000000000rustls-v-0.21.10/admin/bench-measure.mk000066400000000000000000000040571453461710000176200ustar00rootroot00000000000000RECORD=perf record -F2000 --call-graph dwarf,16000 -- FLAMEGRAPH=perf script | ~/FlameGraph/stackcollapse-perf.pl | ~/FlameGraph/flamegraph.pl > MEMUSAGE=/usr/bin/env time -f %M perf: ./target/release/examples/bench $(RECORD) ./target/release/examples/bench bulk TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 $(FLAMEGRAPH) perf-aes128-rustls.svg perffull: ./target/release/examples/bench $(RECORD) ./target/release/examples/bench bulk TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 $(FLAMEGRAPH) perf-aes256-rustls.svg $(RECORD) ./target/release/examples/bench bulk TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 $(FLAMEGRAPH) perf-chacha-rustls.svg $(RECORD) ./target/release/examples/bench handshake TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 $(FLAMEGRAPH) perf-fullhs-rustls.svg $(RECORD) ./target/release/examples/bench handshake-resume TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 $(FLAMEGRAPH) perf-resume-rustls.svg $(RECORD) ./target/release/examples/bench handshake-ticket TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 $(FLAMEGRAPH) perf-ticket-rustls.svg perf13: $(RECORD) ./target/release/examples/bench handshake-ticket TLS13_AES_256_GCM_SHA384 $(FLAMEGRAPH) perf-ticket13-rustls.svg measure: ./target/release/examples/bench $^ bulk TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 $^ bulk TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 $^ bulk TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 $^ bulk TLS13_AES_256_GCM_SHA384 $^ handshake TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 $^ handshake-resume TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 $^ handshake-ticket TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 $^ handshake TLS13_AES_256_GCM_SHA384 $^ handshake-resume TLS13_AES_256_GCM_SHA384 $^ handshake-ticket TLS13_AES_256_GCM_SHA384 memory: ./target/release/examples/bench $(MEMUSAGE) $^ memory TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 100 $(MEMUSAGE) $^ memory TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 1000 $(MEMUSAGE) $^ memory TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 5000 $(MEMUSAGE) $^ memory TLS13_AES_256_GCM_SHA384 100 $(MEMUSAGE) $^ memory TLS13_AES_256_GCM_SHA384 1000 $(MEMUSAGE) $^ memory TLS13_AES_256_GCM_SHA384 5000 rustls-v-0.21.10/admin/bench-range000077500000000000000000000010661453461710000166450ustar00rootroot00000000000000#!/usr/bin/env python3 import subprocess suite = 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256' print('len,send,recv') for len in [16, 32, 64, 128, 512, 1024, 4096, 8192, 32768, 65536, 131072, 262144, 1048576]: out = subprocess.check_output(['./target/release/examples/bench', 'bulk', suite, str(len)]) lines = out.splitlines() for l in out.splitlines(): items = l.split() if items[3] == 'send': send = float(items[4]) if items[3] == 'recv': recv = float(items[4]) print('%d,%g,%g' % (len, send, recv)) rustls-v-0.21.10/admin/capture-certdata000077500000000000000000000031021453461710000177150ustar00rootroot00000000000000#!/usr/bin/env python3 import subprocess import base64 from os import path SITES = dict( google = 'www.google.com', duckduckgo = 'duckduckgo.com', github = 'github.com', wikipedia = 'wikipedia.org', arstechnica = 'arstechnica.com', reddit = 'reddit.com', hn = 'news.ycombinator.com', servo = 'servo.org', rustlang = 'www.rust-lang.org', wapo = 'www.washingtonpost.com', twitter = 'twitter.com', stackoverflow = 'stackoverflow.com', ) def extract_certs(lines): buffer = None for l in lines: if b'-----BEGIN CERT' in l: buffer = b'' elif b'-----END CERT' in l and buffer is not None: yield base64.b64decode(buffer) buffer = None elif buffer is not None: buffer += l def collect(hostname): subp = subprocess.Popen([ 'openssl', 's_client', '-showcerts', '-connect', hostname + ':443', ], stderr = subprocess.PIPE, stdout = subprocess.PIPE, stdin = subprocess.PIPE) stdout, stderr = subp.communicate('') stdout = stdout.splitlines() certs = list(extract_certs(stdout)) return certs if __name__ == '__main__': certfile = lambda name, i: 'rustls/src/testdata/cert-%s.%d.der' % (name, i) for name, hostname in SITES.items(): if path.exists(certfile(name, 0)): continue certchain = collect(hostname) for i, cert in enumerate(certchain): open(certfile(name, i), 'wb').write(cert) print('wrote', certfile(name, i)) rustls-v-0.21.10/admin/coverage000077500000000000000000000003171453461710000162650ustar00rootroot00000000000000#!/usr/bin/env bash set -e source <(cargo llvm-cov show-env --export-prefix) cargo llvm-cov clean --workspace cargo build --all-targets --all-features cargo test --all-features cargo llvm-cov report "$@" rustls-v-0.21.10/admin/pull-readme000077500000000000000000000010641453461710000167010ustar00rootroot00000000000000#!/usr/bin/env sh # Extract the introductory documentation into the README.md set -e awk 'BEGIN { take=1 }/# Approach/{take=0;print}take' < README.md > README.md.new grep '^//!' rustls/src/lib.rs | \ sed -e 's@^\/\/\! *@@g' | \ sed -e 's@manual](manual)@manual](https://docs.rs/rustls/latest/rustls/manual/_02_tls_vulnerabilities/index.html)@' | \ awk '/# Rustls - a modern TLS library/{take=1;next}/## Design Overview/{take=0}take' >> README.md.new awk '/# Example code/{take=1}take' < README.md >> README.md.new mv README.md.new README.md rustls-v-0.21.10/admin/pull-usage000077500000000000000000000012661453461710000165540ustar00rootroot00000000000000#!/usr/bin/env sh # Extract the example usage into README.md set -e awk 'BEGIN { take=1 }/```tlsclient-mio/{take=0;print}take' < README.md > README.md.new ./target/debug/tlsclient-mio --help >> README.md.new awk '/^```tlsclient-mio$/ {start=1;} start' < README.md > README.md.tmp awk '/^```$/ {start=1;} start' < README.md.tmp >> README.md.new mv README.md.new README.md awk 'BEGIN { take=1 }/```tlsserver-mio/{take=0;print}take' < README.md > README.md.new ./target/debug/tlsserver-mio --help >> README.md.new awk '/^```tlsserver-mio$/ {start=1;} start' < README.md > README.md.tmp awk '/^```$/ {start=1;} start' < README.md.tmp >> README.md.new mv README.md.new README.md rm README.md.tmp rustls-v-0.21.10/admin/rustls-logo-web.png000077500000000000000000002477231453461710000203400ustar00rootroot00000000000000PNG  IHDRx"AsBIT|d pHYs--JtEXtSoftwareAdobe Fireworks CS5q6tEXtCreation Time05/21/18YE IDATxw$Uqfv60s`]%. ɊHIV=9CEQ>Ĝ'H$Ȳeaatǩ}ﭪٙ{>p8^]v8M:=en]I?m , >"B`]RJD?*(юGPFIr8p4K'0mjOXf2NiBD觃,Z0goR"U@e VtIwCʀSXW_=^x*נ3>Ѕ؀8F۱;".&!8%poբ¿-.ig+ |1W [ѝB8>MFRLtawob+Dcl~OJjpԏS5i`6p ]떂7] "J8MOg `DZm-}ͅ7/ +* kW& E# X\GZo S~w55 6ӿY  "x n;揂ba Tx^Wm#p qt C1 Ӏ׸7 U@3.1 #p8zF] qw-A?";`HAN e^c%ƵMFUp.5DAFY#Kb9?HL:Bs95S3cp$o4V3n%Y~ MQp7 nY ]y-"dpMyDIdFM3ޠ- ǷU-!o^m2#lgp8jIe%f}J)Ack{̻<8L%@X~ MH:J<As "@o'aS~MqJNvb1m6C[o[{?p3J@ ([cWWرG\= OC%5!ǔխyje#ap|t |o?8}/"o kH́yEX:5X} Z&TǸ4Vh}aL:|sqQpolHT1X*3xfy/c5Ex\y]J>QJaT#j1f>Ig JE>pxc*$_)=.N d3[}sq q _`r=H }=vRB|D["J(&bcT`Q5kKпǸ~/8Np yj @` R !@j qjyq8l Nt ( yX;V [ PurQSp &Ԉ%h{{Po[&o ^ 5b -7cmEL3 ^7N*=P56[%fw',h[\u}HCrT1]֓ŶkGQcBDVgPCsD=3QcTcPCwVG!fÀRmv'H޽J!gT$z}3bz%W%4gG);4漣݃aH@{3bG AFf{G HdބT4<r8jr?_ȕ$:0N]Dx'wdiGb><3_G)!G ?n};h0H5b[U'>rSo*P3 hĥIp=ka`i(>v&b8*q)dGNJ qR`[}WK9ꄧM}| . ځ! ދk%-/W-1fDp\Då D-VYNOT'LzpTry%|~ 6 GTVp F\ cp_7OF o oUKpϝ}dvw2zYݟw3yHZl?.ߍƦ UF+s,j4e{ƦOױZyTq䋢@LBl58'_&JALk\Vl÷V-zIF`Gp cHQzK??Y 'C.y6aK@?ދ *JIIstnm|]ll V#R}#`mh]X-ҜTդHT n | pv;|a)Ӫ 7 μik} pAs8"qUH@ 'L )h#Sť2X|8p]U!&OR?^cG6U>#i!7 `ѿ3(E$5}9]CW'1#T1p c( S?^{HPYW9tThCLoCL 3 +&F%[Nsg.;(y8oZ ?__K(;ż`$3ˤ"—sgA./J*=j4ML5Bcp eN0Mx01vC?r= N#A@f3(V*{+Lm YR7(tl<;0g~zB&8 z 3ēBJ&z2,nd=lœ' 1p c(U/^vBF{`z]Ht}0$`zC<\m=GoQJ| @5?WQ!a0R?_$}4`,T;csRy3NCO\ȴ8x"p jCz{:jfYԹ*ƺ&W#vK N()W`Եv$Ȱ zsD/Y %?f|I6lu&#+pp,IKMчqh"QnC/G$Np4kJhWm}e{=q a%{Fw X^V# h)oo^gVMU@}9"%qoL ffm `_~/N)pp4 BzC_{?8;V3,5@VD{BGAn\ KM$Lm''X?")%)̄RM`n+$*L#  yn%8t,Pժ]5]UvNh aWzEsba4=p;`ȗ`HI9#eNQ=a0Ɉa[B5'ߋ^)NpoM/v[HD̖t ZY P%j yH^11S.{ )#>k3$SpAz1j[*ϭ%mE.WQ8%k 'bW{@͘nohpUK%D 6Kv#Q.ff1?%(I|IcaW ? f_- BJ }p*hmk-@N|̖å`Jփy 8zM>kb p`GY26 yWw͡2KՒN<*#$k&e1};*g")Q)a[QUI83)q /2(DHO@j@x )3[$Jۮ(|܎QJ`Sax f4 ,F^|0I=M/!TS%* ?o#S{D1H th(?~ l:NjjuQefs~HJ^nZ({p[I HY٘qZ ׁǐC@ 2jQ 8zK_NnTiX,on 1$U+¶44#uƤ:`=kS翀<_i}3p388&a^N;jGs~iaʍG* ,a>*e#I+f8`@UaM`ư, dR] VEJ =sZ8[i4M%IΔ&Q _|8p,s່v7=XG&ӛ1GPxmD)qBY?3$qy<_|(| p+fLCGO ,``iʸ ܺ T›r_/<?9i/nƌP4F =>L6: I'`K/+?(BY#11aR:9KjNTd߶N U_D-Hpm>xoe5+; #gp(RN$7-¿3g!vX8hܻXRG5p_MW@ff4 X1Q:5`+ӿzW".yZp4x X:Z, Ip^{+[&GCt  UtZpd?AnQ}5pL)c p(N|Y"@sո@2)4ڑgRu$<KIås5սa鈠b1Sahck/g"6ZkYŮė@¨`ƾ^.uOæ`y^6Z =s+HH,\MptOmBRQH1-3;LDYroհbL.8z]7AuV^㩊nӛSKgڧ%Jc!.1X¸6Κ[/H%D#QGJFu0gp.GoD: }u'f?k Kk[-8c(aD8mJ>KFW g(N hzR-!`q 8l7RtUrDJ{(|}xUn`0* A[;^ 0!n;֌no4ܸ/s\8 ZiCv3#J۝Nkv7e}G54W\J1{B yirLi!dא1x=kác[HS@2B>z#.YzID8%V&UNctOUh$vgEyo R@guU|Roڌ[PߞW4X8Gg?(:9z.sa~sc\'( {7QŠ/ P5W| ] t8*v8$o6%,N=8jQ(Ts}䀫Aq*xwR=u:J?sXhʦqB? CzHi1R1f8YY8(,!MB'=~p8^Dz%a<X'1gv "OG?;J:nSeDNCpPaܵu ߷z9҂PYz tSPQDŽ݀QqGSfuT u%Rcߝ' ͂7L06LӬ زhL{T @̗F6aJU:LS}ndoo73~;OpkIy/^1vh_ٮ;Pd8 AtQЅ~Z E`(=%V̨̾Q{h\EQa ~Xۢg([Լ;c5O{ZK*ίBsC غ1[fEJ@7&%[_M"mf̓~#d OI#ѝehKOdu}5BqQ&qWnIBs`?~ tb wǺj;6)~\+h^Wrp4cʄ@~e 9Yk1Y?xp~$wGfs>BzIkta&zT%Va m#VǃuW`Rv[@[ ;@U (RUtuOu D aR`r?C (zI!_1wN&; e:2j وq4ʦί=ĸ?m_ݼ{1NjO,TG?n1}L fƕaSL<O! }+5=BVW_jF;"?@yPګ )?V=DCW& 0o!k=07i±@R9sp8 C~zno[g#An{#fu_ۉ75 9Q~ 0/<ӛ3i@Ѝ \7mjR|&üaG+ K\POCgt+7^6|x%E`ODiHki< <>C IDATu'êdto|p }#+rrt$~$Ԏe6S:ReȽsyW >nPr-4DK"LR[W4اvμ؉?ws2C3Te P% E G0TԖ@9/t׌V8a Pg;E!s,nipXhI8Q|FG;vLFFWE K`r.{a2 s@-uFBx|m7^@ڢۂ?9nip,Mi<8ꯕsLB@ +|@ڋ} iv)42{;6:ㆆ<p1um;@:Dq/I(`x4tJ`JL,7tpf:.386^&օ`{KV ;> 5tLj"% #r>p+#h~MZJ7 e4_ |{8j2r_{}>Xf?JGM{qhH$*&ªpW5tfLB >5P"|!_]SV//'|qFd UʠZ\@yڸh8ftuDk ,kd9qܹEKy/_"8*8 e&c&{Fx|T\gS|i | Gպoa6pZe#0wD_,@@ R\3z2%3 `paѵ(*RHUȗwo/sߴj3bIxf%&U f4÷VS# Xũ؀Ry)ꁚ6v<Dk >$7uA!۪w8>|t!;R 36Ql*B۔|ȤEh ,VTuO-_GX;BbW$=U ݝ `%VEMkUH wTwcwW` Ay@0TdfTE:Ң֩rbzN:KqT}Tr8\cSp" wwcQ( T AgQ,/GO9Rvd8bk:[~Hjy1ߖ?YDI1ètsIO/_<W)-fgчM4E⾢Jdlki_J^|W@1fx.@6P e`~+[ 0n Vl-\_1NM%b(=.8YSng?MMgЄ9QjƒD4ǽWnHF>j'ʖ[h`?.R#_/釀Y{ ʋSmD{wwTwgM Hᄕ[J@ *k;}z}lO>G`M:iŒȃ^hG2׺3GGn'|3a`| _C .Vj[jFT3 18LF*'taxKIc-M$P$0Am RǠ#r^} 3jsZ'W:m. ^6#8M6%Wת W۫|HEAXu޾Y̷Tj$7́-igc 8#x2.ԅDwC׳mF#bff _]N27;nU+?8>#ճr*҈iՒء}JKYbj)˵sGtaVql/}4eb .ml4I`.ڏj> G*)53T~!҈HuiS3! u㇚"Kg|LچXbAtn j)>PTJ˅;hzW(ˬep,cx$d @-ѕ(7@xq,u=8Z$bqjʇS;eo4i T]$V e/u v<+r126S+K܃Hn @F: )^J,8_F*jRUPsۍM3/  @Bk Geq8$"J+8\~b\_p|),'oIj&8}S2|i嬥7#QAZj | iC g1Sj7W(`(mF+D|тCԊޤvGї~>RcYc??A u+D&=#'c (Xb(9Ff?t,.i5yM@1[re5F5_T:-.L#"Dx;HAE)9qwZ0YSjYWS}HeJS48S+ PP;=6\&g;1s NhBsՎ\ wur9=#3tzyb.BDqaP*L @BիOޫv-<źxpDcR`"l!3R; syJК4n(H4L @0Z 1{W ܜGvB)#/0@%XA-]zV`c'@!ڐUd(GBOF{8Yfgh\Nn NAV^v+{㲕<?8AP)!#F#ǩZj%i-'Z5Z*v _.=R`: 9-{aR!ŽKdD >Hf=V? `Ca+>XiK3#5\f)F j)j[].^]m0 u@"]PP\n<-&.oϠg uLQ&D)3OlBmS?G)ꂗ aZ7% (oe$y/G+O+`Oɗ5_\blĶ +@7b+'IL;b~ǫdjrD&P\kOrrCD~ULߗ>LMhcx3EQk ZYx笞E)0Nn3V,l%_Sm M=X-p ޷p8LH-ӛ1D%N+7䖺%4">Xz22N7 9ؘFf>Q!A*h(mPaT@˒j͘ TQ5kKu(;`@uUwl6<BLǟZc=N` $N`0_?:rp:p,C2VkyTfE& Ԏ<)>6Z*ª+է?k;JRwD({m7\L+"/!B5\o M{4Ȉ!"sn .#):Lr}5 og(6*pIzR{*</nW| 0#2B%~Ě[DƩSړٿ.;YZ ]<K$=؞-p&c(% VI0Ua/e(-օF(pzs+~= lBSF*L\![=}j{#殦:/OBtPADfVU#')%UJ1ܭ2 w*nPձvT"4aPȲ$P>'Վ`Ά{M=eXT37b 7^E`ShضP0MB+u%x>׿:,'eC~逄׸PeV;hE~ CNˆp(pli"I(M3 x 1KrE ZaxF9H|}9נ ɊnN$ pИtGчT>0X=5J PzZ*`#օ盱 mD^t i lhӛ{(ئDSY>ZqǞ4Fr)6 IS2F5ɘ5UưCGYCDLU&kvUQUzU'|j!>m=xqlݜD˹v2@7"ןD>>'\z4rόxӛ…: BBїcḻ+#kQu6 )R `)МOTVF]Dg(% *@*ZU6 ½h)O~bcrE0h`C\mME;Dצ~iOSVPoYd$}0d -GP Yp2;kB ?(_I^1S-V\^>G]z&pxc; *Gti]6¬jh4 ܫj>~h.Y$¿3'?’_-8QfYH,RpG7x85T} ơ\j,eǰ:v<-W"(wj ,z ۍD*ʍ24p^^i55~7q (7h)!\OtNvJ_,i[(IfcJLDY֨7ùPlop8>Pw̄cD[P>d##AAߋKd$ܾP*:@+" @W]g nFZHW*८֯}F{PE42lp8C|F5+@c.YT?@_ݒLB~p|tW/_4}jiC $fYҦA RAb`+@U8"W0PRfRMzx,A@# ߖp 1iCA ˳|`8a tvO͢L^?b?20JlBvњ0<_YfnA"DuWV:x_0DߝmCKk|٥9Wc^Y. VDK-wDʃ͇? CG?fl5+Qb2mwb3;GNfRu䁗Ɓh d0TjMuj%f ]1Ф5wm1VДU݈\CVGN],;t2"n|X(  pwrg D] ŰĜa+7@/[gJe -pYxjEHcp8=T ~t+ bUHJjw[ff6-C0@WtmEp8ehNw W LGn XB2#,OUKG=G|iY;X]$=iu2nOsᎃ)RFs^  JugPi8p,_ ^|. k6}m[kdEԆ? }cHI^2|}eNO"1Z:: ל0M1Xow-l,ڽଙ{ 2TSxmj Qn>ssi pqjs)^ SOsR^xw5e} Vw?P[W&3/5v>PHH0 2<MּI¾8Ebp4l  zX}5Wjo"<1F(Jg @TTRBA BPB{~z&Zݒ {X\:KI87؃pP庛KH@TzJ_ '5uAבRp:ݑ b}ЈvE|98\W2 xqW(uHZ^ZAĀˣM6 óvD)jTzݳsQIYH IDATP@ Pr0w"w6깠:/VxCn p uiYf>aQm+<27<@H\5 mW7G* n{7@6vAE,#;_^'7kۓ&;.M52Q*;2PĻ(()j(C>|l!lCWۍGr/=|Xℓ[ynt{x"2$cwMS/La֢tQǁYxyPړ`j)i3;?MEgpEe;!mv-})90n5V?AXRϢpe kw!zhfĜ>VՉ;_._$Rg$L8 *b ME,Ỉ.Bkϩ!=~D-Jۙ ?vpМnhQLBr4-Ne+׿nP;t&>h|WS 9!;\?tRlEk$;EhnYͧ!,Czf2g[|4F o_f0K-I)B,pIu.l+~e;bԤQ'aT'o/wNd t| A5h˟-C[@sԉd _aܪz Q<R5o7k `1OQn D;92ɣImmz:vNjr8݀An3<3!ş4nan7K ,"4u/O ʩ>ВFIo'[,Y7ZL 4˷~LtZ3C$V/By[i ǒBH xAp 0;ܖڟgd7|)&N2edl^բp/b IΣ[y*~Wl_ jWlӟ!BЬ@!\Yhgܳ$- ʏ:ׅPg*"09@yNHj_Sه&̧ƒԄ}p8`/D xXfRB܏ ͗kKBu*F@`،;E.]eaY;T,>В:a_Ncw|]Gdհf"tvEvӜwgTz8y/FfI@;x?", Y9% %G`g)ᝈx߿Qpp JD#b9$DHxO{vK!!G*=<xq*bU4p!p:g~9K]pĝ[`z(v5cUJ@p2 u܈|8h4~ؓH{QS-ge2 JFxV,\gpt xi(?$+_x.!.9; x u{pL1XV"#Z2V$F5?Q723tYD1X YF50E Fc2o 06j}:kB@Ջ}_to خfc`,"WpT~ y L︞?4t fKD}ؔG ޥ7E _xs.xg"vNDc20EmpdtwCE8(qp1Uᯖ~P!%@E_J 4O,\"`ft_Gz[|?Ξ(A_(w;;Wx0otwpU nsn: ؛j 3u ɱ͙?@2AqV ;K!n d*B1\Gwµ;`VUnk]Vi%O҃LξOh܂L s3U3)"5P ~ g9_Cmٔ7n4V|QJ҃ ׮Uaxr% Cg:KR!> ]<ʊ"mMC''Jw:U=p8}0ӊSoLh"*Am^.HGJt13?s% ˌ2,Zpݰ ZH\&θ7$CV߿߄?ԩho+* Q'ƒ j ZC $./BTM3!ɅZY]M9`B0ˇ_Fpo@\*@ Z 9zJrO')†mx DBLDEzME1(BW?.e첒g*~Ι5ْN )A""  Vr/WHQDzIi=93nvvvwk0sL;m+D'6 ug"$@!hkpC~Bey20^'+l x!&_oC;?zـ +] {L e ң,ʽ!W@t{G`c D9401 &k8] <vu)؞(GAė¤ےC 93hA8o΁tIS! [O4o>Pʟ vK{Wv[H뢱L㟗Ї)l>Ыgܿx`t`` @Õ|ww!M"}y,J8Jt߉8tM.DOfV< h剏a c(bĐ}|dXj,:ЛϵM?lAYFGS0{+? 쉪yFH%a7_&w_&}l=m-a6x?#L-!0b>o~񺽏A}BU/!x8¿(E?p1ycn`Cfy%@={ w;5?H4ri7J8ɰo5Ćx+ b is^Etb^'w?cpzb HK%fF 7 dA[ znZ%ޚIʑb$f.⥟ `aTJoz5ֺ rS͘0  s[ITRY KڌҚ{{ >o@l&FbBGu,ځF!?hg3MZDvG*дQ/u# o 7}"raP?EZ|Gy_ m>9Usz:s%p=B3 ly!3J} *dyd8IJJ@ACD3&W[0h_@9X\h]趲 N{>=TB21DH&-? yD~4,>Dz.C :觮@[ zp8`L8iABV7;<  r[6`MVayHǠmՈ,İHW%5}*!RrlA%NX ϴ][Tcѭ 0nqJA?eBkGF{;l,y5`?P{ ̚bȷ9vW߁y i$ zώ_B@:_,ȫhnA2fl y\av^>[{"j%A&D},!Iɍ!J.Ͱ9dx?<6uĒ4o)9`~(ᴉ,/tfd@0>gM*M2)Q )>F%dgً?' {`gjd|u"όY$(cD]U#j^qS&7v`\ț>''p*eIN̓N$(hd/x n]{5f L l< =!z>Sn;QB dl(j\(: m8 0g.,.|q~o a ΝW΅Cx 1qpL!:Ck7}w8'QyBwyҝggW_"]k3/bK 9X[I`8.nƹ6)~0)P膍㦲?sa<4LreqM7KU'{3Ee4EAKT:^GUO͛7O}^xc2_ܲX=z!_8`x@ޗ+S0u)'qZdIʏGpJϷ}w !.obV|D|D_, <b|20 =q@l@#/ XyΓ'a52c/j7MӮ$-k![GD2e>4)ygZCxFLJys\qo"G-c$#TE)^z;΀KihV wHmGVvvvrᇳt~V'14/qЎ ylDK cZ`3xVJ^.V!)! \'\>oѿD@虭p{RK!!<1+FC%/7 3Y<;gN+7Hߺ,RK2SM-7 o!͓cP%àŻ KZ lExDTI,RM]P^!SHwt('nx9^~~'8n< Sf3 +̕OX}ݗ{W[4"ҳW5ZH9_A%rψwGen|7oV5s8m;ǐ:s7O|Rp㚜 %2x[aOg"ϺL~hs tī=}̗aIADV> 8qfL|g<~Db[:$_|Fomˑ `ז@!CkL9vN >=`_f85-4G4oEOô]> 0o< x~>#;;2ܛwn @^ZAr(Sry>>+ 2 4 Nz7Oxr/ skoh4{ѻƓ]ˎ>>>y'&_ ݶ"^e18F}bZvq.+ B{a2FH4/zMPߝ D~l²v89_ 3 L~9埉m@7| xP[ /*?4djS~+͂6wDS%ґ7$S4] ׁ?~w#$o& +^i5XaۿP5]aG6~$H<2555|;ܫߗFڷͨ8ؓJ}VD )=#;w =78h K $1 "C) /Iw&{|%YPk;Är9毡݈ mJS !R  ÐP:f&2[咾2(PVP@RuKNѨMpj}A끏aP$9cP8#2o6|qЙMt$ d. SNvx*N]&Vk= a wރw:>{wvnG>!jYNDs%EI`X=gf6#ʀ;׉7 a/?'`*p3p9$wLix&QJ.a>9 IDATx@)J8u&t, rVYdV;- V+X;'f¬fcUG%eq | ,wt[)}[ qS:lW ͨGEĂzuS=6takMN#'sc+s|ytw i^G+}TD^ kL`.G ?{؝B HJxp:y]`2^'A( oJ!To='j:X60zI)+$/'öaisФ>>378[ x :kkkk6mڠ9uT&Lر[aY!gCfj"`7$]Gk'3̣a5nϊl?;3?n_&֚_z#>bD$, :q2֜cs .,;?޼`޽|]ogn3&, *H }mHuIllNZ sIKtxML)ы+[ﱉL~?.]I}:Vn^n깦ÖR]]CMh{#EKGAoke0,t"E|mI蝄{+[U}ǧS‰S䚏m)S?~d6(G^#  6kD7PO, 9^>>ZuرH] @ xH$Ow*P!H"lҨ 6*`oCqrcmUF0^^ee'n]+吐Q-Qm}p8?u0o 9ȚV-tX }b8vOيS@MGb^:/q< idz珀jᢐ7ށ}=d22'1ALG[{o<] K[kw\d{V!ACᏈ.KiG1=ny)*sV l.nMjwQܾyH-2;# ec SC2 Ϗ@`γ.&8|Lzr5u_(RrH|؀ӝe*Y |(]G@J4oe?0TJy{0a \[ؘ~^&#0 -/h xzdMB,oKۑ|di4!@6Do !HmLۀup02"EDdk?/l&ͭ8F~}?R*Q` sH*c(I'lݲei2vAË6B06|/6ohh`ӦB-[lm Fq/B‘0b¢rS&4VЦ@ꭘA$A^ ܾ ~$R͗/ . c;dk8IňvL@.'z<|ē s̑nepx(qJ_= DqCz9Ν%Ld^S#bw N{6ۜo =:0*. '8mMׅZ$#w8K+fC]$-g]f}/Vew{:=]E fL$ 8qF5/AW6~o۠N= /0_9PȺx,hY=Ȃo$5+b6"MuSʐ^?N2M>e,> h dzkߋ(q<+ `b<wnϻCQJ D[9|xn/'2 []({[Lvk:GE,0N: CO7 Zt~nƅģ,:uI`RrL6o"#1Pjz;X5_ 7H\$*LSOmW^ɋ p.Z /.k!.H N}c***xw>}zϻqFc-Ae.MPoTW@@)6܅2d䀜O?H(p7oFF:so1Em T \jgҡAJ˸ў(W C.`5biW &Ck ^VK\3{m z YZP1`]h|衇X?@*!m|#1@ ʐ!5.|Q `Œ5&|M BʐV~Sf2GvhG$j`dSpܚf)PεrPMʴu!ec3_ӷ1`yܒ=D?)y sZ(  ,  p\jC-ӥ¶N ){Iw  $65?WpP V6"ᡠ(tQDpSĝޣ| G9U>UJ!Y2Yva xdo#pDry.o#@=hbE1hr ҡ_t܊}b+͹~Rw摑&, mXH[xQ X%K;(ʒN@L [@#hnuPNNc=9 ??16J<3ZTJpx+H’\u> RHГĘD|a:Ԕ>op`\Ύ†a5w#F I'+@m ͩCEB~XZHفmͮr}Z@F ZJOON=l7" T@B!bSը*̓ȯX|'5ޫ'$&x+ wb@ۛ\EQkdrFZe.uX. G w-Dr-Aՠh?e $W 2fs0 8L  ef?P]haR7 p8&K[p#LX i' jEQuiA5M$P!,?*V ⛰<;lK|I NV@o`_1΀kn4d ՝$k΀d,6jv ҍFldyP@45FpX5|uLn( Ypr N-? D?_]WН`U3! zH3 #nj)$ph t$|nC.@" rl6ј)t7) ׸gO/H1-B;Fe (I'h!y[+zSgep$f`r/&Xs,_??cBx،r'S=\1[RJaƻ |NU$4} d d UF3U8wk PaK&7B DdKY|@їtrDF G2׫F I>IVe`jʀ C9A huBso)XP%jfgN9 3JlP6l'x{3%~ĂqA%{WJnQ5:NR1 uby2a9FI^\N7*h7C5^}#b](Z47GR[DG)EKҀdYCXb1IgZGBphA$‹q2X+E۪)ƿ.X4?dj%."lCk ^ .e0jKdQ {V x |4A4Q<?[LtWCUEf! LB\5#;\DH8C__Û[ai{=-&Ka ؍K5!!TZq*PT05 c#"mKH" c :4pȏ!ZfMPSБ 5M1Xv&ĘgNK3AK!X*Ϊ ME6; j@CB#`kNXڰ8!HI;} 1ޒ*rY z|/R@mq=)7}k!\$8LI oęGtasMߝm:Hto) \0VhYhÚj#0\H`d8۱ *A9P3e؈ /j 4 ך`u,̅YXInL+@M,Ђl$y*D;˰c| !A6hG e4v-AZ@~0(j G&LSd>FзH nu}8 Q)o PYKj,e{\3NA_$5,=%(7uN̮UI8$f`}׌7G ,ڋZ'=<<I_1+)|HRxr#s#,kB2pCnr55 RӺI=6Hk+ M6)bH@hGDSn4ol :2]>/Mᐸ=菧P'7= P1!Kl7e b%27`&*u%Fxb="d8BVoE6Cf2K,.!E7wkwq1(VbO55*L*ĈD` P_Ai'`ėzOaY'>%SuU4$Zs:W;c0n`D^wI{ k:R>S#ZW3SO:P n@TذnR̾fkzKob!Y}wKzٙ 09]7BM}umCx kM;|!%0\!Kp*пu{1v>.N@" {| Z0H'V&Bh5s&vbĐ!=ǢxC!zW1  'ّ9?"7MxF[B 7|Կl  _ x pp>ptl(Ͱԟx9lvkZ.*d1]3p|5 RRrlgmmB$Z.q! hdz܀(v /A6TJ5QS[H=tƐ78C sr` 8khm3 uծ+IJ1OO ZB@^!L~ /L̆e];9_8mwryo06nϲ/8bvt <t$\R$@؆՝˴ƴIlpfXP.~|7`Ri1hD)Pv'p7/*IQҿPJa+K;!*h$ַ yd9eoŎfFLn;U"yBWTc+]"DsIq Wo{6}7PHtߚp b`Cc+`vCym=+P;F,Ȅ֛jH d@.#Ւ[ӥ<#W3R mV&q" 9+%x}#2BeiNq`Vp<:WCcre4̽yYp4$0 )y N,#B{O}L=$FHא=xunRJ"t0wJ]K,MJ O–** Ăp WPo`0?!3u3RRDama7bH/ߛI(L Updxԟ8SJEJ-0gU_:8AWiUXC`8К 0 R#Q~.w y ;  k,+,ΔdМ84Ƹ8p뾢7,]56);K4@d,%p Z7-|=)Xvz&XX m32-l=hZy7Demo#֜Aj}9^%قm&Zi;@a]|݆H8ahy%1C"H@AK!"`CvW_x88y8bKUTpxX8)-Q^fIi.*PgD_.P_GR"4+T u6"kt !䩢ssw|]fIaXvlCIĸ iƺ"b@O)Uw 8j.7{*^Y*=C+!xuޝL;J\auk[rnQ=s7^ ZC^CV"X,|#lÖq]Chm(ޭ1`$D%Ა !s`z0# 8>Q -pP8 Vw$4< jEUհGm+rIhs{#.o`bD rZ2-h҃h6Y+SIiB+9ݙB}٤b`OUdu"jiW{lWB#ƹG!5ȵ o&4U̮##/xN m{~4) PNw`@xE\ѕQGs({@O)% J[6j ٫{%cH"5X6|]1򫙉@v 8I{.5U=.s& Y!*>أL2SZP؜ rۻ>:{Rk?&%5Ơ[*CPmGo)FBuuXS$ȎaR`YO$0JvLo[Df(3 oJiF; [s Y[A+(ݖsHsY+SAnjkpG=|j=O#ٱ6=}=<Ƕ?i 0C2K_ >ΞQvg᝴7j_@]~:GI4%%?Z MbjXd;30uIJdrA} CȯE:!N%[ÑM{6l2`!Ni 'Oɛ9 y:Ӏ}HOxπN Nƪ*7UmGIllƉP֋RB79\#{9:,J2yIxh f5ŷGsvOB*j_J°)A擸Eqg`}ZӡIדN+: vB.HmEpĄlPf|-A3UU3g xIi-g.01Kzv{'ގe)ԕw2I+٠9kQ 9EVRoP޺l9s=l2 (k~e\GP"uRww# GNFm^ʁ-m$]>H=>#[{$oJgc ݋mRߐ;jFTL 5j I#'l۫`M:OW Ļ'Ë[W@I:o)m8霐*ZE/ uL8'?3ϩ sUНZ' h zZ&/\Z jh \wpf]’XXòQDՎMǀbCR&P{T])on;/c؀:8Fwr][=wD7$-}OVˬU iLص@m\xBMx1T-i3II|~`9X~,mq7wjg4)Tz]3z=[4fA~` WM`ug*?wTޑiRT YEE*4((A!J$Mپ;;sgK ɜgg޹=s|p|Y g]o p{G3dj,Lo@L?x `Q/@_}"AAx1֒A~Z88@*0`t *W"= l iX3p ג6EUR=Y3%\=vT].inGw'N'T G#:[\.CQ9(g0H^S5`Dr,`| 9`& 7E/ekLhz7ۑE7 iC? ]T!?AH$iCadG¦Ms89G**ev-U\ 7 ];=0dJl29@]l?;JĄ jb?m$#p4J0D: FCldb;Dv8w} YǕ !P,5,`#%8c-焀87;{ w ᗟn?<> "dvW8"eE@D@K7H%('Ӑs*)(BHx jMؘ_b;%2%=@֊|$iZH~/Ik7f.Fc<bq𠀟. hi3`Hvu  >I_|/i۟$(*|MwJx@qz;rEƅsw [A:ROMPב|yY#} rZAkHV7a^00   l0 e{Hx`wBft& 3ԁ1 U\+EѽDA2G;}8 KL'"-FiKG:2qـ}/AQ:@,{m7W):!@[ުrC= Fڱ0 pRxmR\4R, mHmzn |EvQ倶@ 1"CS{E$h#eV/ -wZ IDAT <86>0 R_o9򡞘CB&X6u7 x~ sVB iNA!Sϵlw#3 Ź*BCfK vBy Rk^c&i)+۔%QucaKɦIE4·a`iS(4W.LRd8~wS";7a2:2Uۊuu~uB;:XI~be6PY p Sɖ;O?I`ApHmOGRf3%ֳr;8=L@Z RLogL sd-%onP/Ɂ) ]~i TW}ұp0Tk3#@H8PCp lԠhnӮeb5PC|C.0h, 4Cr4},J"CfVѶv+ 6ߝ'z}fI0.AξZ3FFB`φă^ HEEY.!@s°S嘧uBry|"Da A67&K&/jiWT(&R:DǢ|oį;ȭ+ ȁ~Vg!C2W/P kZ}Jd`۶Md߁ѯ@#mmQwqrHS Kp3ߞ&*=#Jp/,|!R"duiuj!iB4ZMDDD7 }ebaϰL64 hp78s!H'L=+ (Ν ~@LJ 0~d־ vBIL:1( hֲ` 18V.dD eUn8k0bTJH j0\3 "Rʔ!uC2NiIjX5!?oٷ{cw2(@GÁ}ia4HAw WBc!Y+%Vsjb*%[Z:Nri {͐E ŰUX>6 gF  o1kh AeZ @!dn'*p$m$b/Ȧ k`o!ԣ (j0 T,NXiHe10?of;LCqK"->mU.Aj3Cgם:^  ^(޶ 7(ٯ?&TB|+6r.idc֩e{,6A {mA@,sjatW$?9nBR\N蒟h#mI/bޮ3/((F#'C6_iz0 ߼wDkD֡ighKJghKl@r,@QȲހuio2#08s?i-e>Ti`g Z,5{;# Ue N젴qOz}/dO?\< s-51 'jp=Ht_W#K"Qßl!oiN4u;__ͣg8徵97"?d,zk }$g|vG-?qO!ݭm(skx0qmR=#HcƾmNu2pzaePH]C[K0p@-`e, |Ud 3 `HY*0%$dCncNjM2-?QK'M >^ 'P)%@=Ӂ $h`AOA 8B'鏙M =өݥ"*zW"7VJA6nerOa?T E=()&ؽ#H2w|GQlp3R{bX,[}m'aU\붤p5K#-s:D^w9>9N_YSTpd> crTMp[XdșT]E&|r8 (PY̮gJ++Ҥ^cR  ZAOM@Q.zD*Sh]LAY~% ȮY d *Jjέ"8ۂ `˰-iU y+̛>̶ XP]ABޘlnvGt9#͢ Brmx?ch'I?e@> Zh_qIW'y #5N[N#uiڧHa}F5dX T8'9YRN7~`NBȋ[cR @9 ?lGsڈMO!Ջ'WU}o}*Meg zzˌe5s_~@AǣzSн5lC& i,v @0gx[ث ?Ɯ]!H7g{y(&`b< !L\=BC$(*[gk`lJi%BF.4ɰz62 }ܵ~ۆHb1>l &' iq[8}Usr_s~׀[NHaA멋]oB}c|֏Esᖥ['n6淣V$dZAχ !vRXSሷ]OLJ]j QY=VE[?}~Ffp* `[^.t p/s f]K ,PA ֬0`: b[FN|DV=b`Dc`Z#b$3  tkvFuw a"c]l2MT]GbS> HqGX z?e=bѶ_DtG|+v t+D:_IH|2V¦Axr<O!H}_vuQXx9L1i~s^7#N^?ecm9 ڡ'` }zB`\mkOqMC*;BX"Jo}p7m ̹XڻP@=<#_`CЭR""ES?ueV4ض8_+%}I+&. _(%ZՉts4 ud#`]1 AOQG&@"Ϝ/owt^Ӣ{Ӂߪ_H?6U\ .sB?||>v)4a*,ϖ6F-{D_Y] D..^$'L@|A 7 ]~\V#ݚ.,@+ Jz&@nHm/r\HWݪ`+P^I'ue\zY)CX7m>eE.;dAHp)l xY-6V< ȱR`!dh>r `#<~2 f:L^Cif[1M@8HGbdNԟ!̖Fl+O9ƖZ: ~@y+ȵ Iw4Uߖ9y$=pOTBT}nAv-&B > 㷢_L~Ϳ#WVmX; ;Ep .> ?>v=|2@UBiV/r{ s2$q MqlN@ xumJD' $m_  3L- 2\iWSbTWÀnX 56!J1=n$yFD9 $!wÐZ?%0CWO#rFq;{͉PNY?y_8"W"(ݳFAtuQ8e˃`!;cUUp{t8ٺnז@;]@vgևr^AYC W"\p'[Z/܄ߐ%zfF _6o[ K_EKURn }iZ&o'.2=~# 7B0g BiUݹ0CxcX!;c&́DR ܷFqʂ?6ɓgpZ[SJNGO¸Odix!<<]_u#rx17?׷J3`0t,]{xdJnvϩw&M0FS2o8@_ݬò|ׯp},\3])ls==g*y2[ W^j1Hcrx?`F@38 FvMS/ki;xHg`'R7q#5Е`< "4"~('p5!k?#k.72$x{O"jGzAG#D3WM"A8-xm+'qeAVtbrүCع"SߠJ w 6!E3 ȓȗwLʜC> .АKFb>-o+ʤkUmΐic5isӠX؆"; 6% >8tޝq1rHzE,ömjkkYr%g޼y~=}FArsnξ.ޚ Oi y&/EX8 7c'-bpe[O!W&i?Xtu@8-A?Cu0@b ;u~O,->q=+#t IbhT_7Y"`eL:ɤiii!NcpX,F0dƍL:˗тx0l5![_xExgB۝0xuvd-3ZȬn+ם?>_7-WNYo!CupFol;HϿZ+Sk. 4`d]qʌΩj#f졃~:bIVpp˘ ./gzҽh {ayܸ7q> I]E|opҾ)WODn?9~p Xl̍T̒O5 13zl=,Tm:ma56i$3PU,iJ Z3!ѝUF0clO$ԘC TVVҿ <ě7|ۢ(.b(z]V`)]tsU$oC rh͐oA"8 I{O%CYik43H9Qc ~w YQt=sw 2UO'i;S=z|uHE&>D~* 1asJ2 Z$ YG4G:?9΂v_Д4Us6i{ضoXll`W j~?*aCʃ"D&-Mt1iwƢ  13&r4\t&yO4D/9Bt٫-*3pZNtn3S|`< =- 0ALKG 6z^eNCK2ByY&b7`utrZ ]**ˠL@Ri1 PYT7lc5o ̊iBC>xeXJ{'u=V G0yu -N'b8 ~[EL=W>;.g"]*^sݧەDgS@O7#ԧ$z/p7vҶ\6+րH6&`T6"-vط /Ѿ bæ_x  ?F \ 9_oG/;#2he@E1EoX46Oap-:hze;.S?`EW)1M۶k0 .ޡ"J 02U.Ns}9.0cg7wGG@&H¼(±G0.D2 w_C· c! )VjOi|-}~z?&Çm;`h ?L3 g^:+p 0pو*:8]SQ_\:+fvL]O>r=" OrS]Uo:zem5L{4 tēJg#2LdAro'B>@?aZR3,+"ԫpGouF|*7^Y1o#Ak 8PZ!Nz4@UU%=z=)z۽6 IDAT²%a(Mm3[2n&8lLy$ cE00F$;j0:7'(vѥɓ X (fC8 T@[-}~=9 O;M)La)6aYY >GZr+)VnFOu HyiAڢ jހ/ٶmkZ6|Ȩ[^.=d!Lۋ-E' eML6q]rI[VۺT"0&[wW}aoySkNGJ 7 CIHhUTTUkdD9"` # $!|*`h1%(_Bk5؍4KJCI_swJr[;XcyM:SZҪ,xɏ~r`Dwps hjaг/x n{WlKg6L^X] Y dĮ$OY_L 纜?N=riB`;X'3SawDe ;6g/6!)j5zp}#1 ":sk|ш[Vfgk|:&zBH3 +M$Y1lFc3y}zg7Qm 1lVi84Z 31#!'`DCrΗ|ځQ28i}_o8 wl_1 G7 KW^wrAv_YN pmm-0 cg^d>C-&& HiAp N>%Kn" #K|-}>@*қli$P*)9j= m:'2|pVXA()-/eƌ׹W1fS"t~wgoa:y$ fA>BMS9LTpQ/f>lj`slzQE ]UF)9^UvY m"tYG*PH@lHb ͆_k!;?6n5U( #$AAIޯq ;ۯE|o~ aQ-\߄z99@o7?NI *Ɍ>a` |G|`:hիWi>Zk@r.X gVG;-5p-Q)$tړ71^5x?]8bٍiqv*Hqm_M\q7^({>i,׬]CZg~Z}ց]m`M+'=5rYA3pZg$ /ֿC9^0J,hylht~~ i6lOEn`/щ'(}`^=,Ll}" ÀQ 5iaN[? Es@+x3~@  &CqǣmYC 0N1eCC΂zXJdޛ+2d0ͨxgH&eTe[ C"#ol4Ə`8}.8T=`ƺUz(Tޟ8"ydr~9dRdX v*C>\Zܜ֏TztqϿ>]؈S"^[E , ;H[1~vS|)9 n#!_̇wQ(y{n̝9'lK>Eax_q/4ON\n@jnʱ)M]#TÜF[,8<[EQ =Nif;F1j$ɶ/ŵ[ ~;m) ~^D]2-Zg  >yc?`4 Y>@J* L.oTG@j~ `db1w_R.t"A@1-HǙv=[^Q_L];g P0 j~rE7N~W/>οU-Db ȿs-G&67d\ TE'diKN#)rkDOD }`lUl iŮ! Xw `,B6^ Y2*i?` cϣ9OU}> X-EqSuǿKetS @&: 0܋Jdz b،=%H N;h6^*d "ρҡ@h r^g9p\P-8T (3DgZ`@F5H&̛7>T*id2Ȼﺛ>(5sַK M&!l4'X-Iey^}Mn\q F%{Le& }(DEЏ!שFTM?msuU  ;B1.)R2nncݦ ?N0u>c K4Ɩ X:[V /O@ϮRvFK,hM)ISQw\vfka Kҭ4Cl:?MӦ&xo2>Ӻ:EHOdҲվ_d}KEv "FA@QflCryO QWԶ'/ˆ)ËBtĹ z1BWwE rR< g!Qo <&a/O+LƶML#ʢMYHB!t-TZz?M+ŋaZhG6cLD]S> Ԓmƒ򅭓lQ3p7mwvkm%/?'-wA!_U7W3~1]DW[prOxa;oI#L& mAy'u>< vHh^jdDmށf ՊpHS#ҡ(RK/$z/ԛܾZ&|r݄/Yӝ߱k:ӏ $l` f?lj]/q'P,O9 N(76ށ 4$z5*_%P A0:#*\^H;2<_fli[f§Gˁ_!% z/$Rjt> ̸PV?  Qa%okӣ856p)9ppҩx"iX=lh53w>MS&x#z\kx [ mb z > wkq/ Ai1!5$떻^G:a$ge9Tp@%L&@- LN;mSסp;fZ't@?@dGL Ǽ /A@ʖ4_3[Yac $`jho։]*%'n0@@kVA.F 1L"YLLSYǖ1c l;{LːmÙW|dY$m ^^]VcBT 5?C}#6Zxe<(jVs)B2sFPY=u%e;g~oe,jYA/VK {)= [~lHBg+@I?b`ºmե_. GL@Ȕc,q@qUQNf\}<3eZ|Hjyx:VRTQ'R|8ѹPRy$f[_hac߱`pk&_K:l \kii ܈Hti@7/Dhں%ro;꘨"Ő>?7?D<iv3?_[a Ny "xJ:8-x@T~$ g>\ =پwB"EH`}YۚǘO@OVB=]\ya6)՘F }Ӧx3'S6.`ŻZ̞oxEem}90 )Y 7v'Br|ܡ; ?f]Vjs] (v^`Yѿqh?vfi{,Sp[i-Ժ24qv+ >pROx>{~Jn- !` Nm5!Djխuъrq q L#`bLHXaTp` p:el|bGϱXbK= Yf4RC@&nǶMh@/8`WuNǁiH1q_?3*uz0>*-zj WΉq̊`/Ei#A%A qV-}Ju9_d7#z  jRY&Qc7f,쌕}i`L2F 4:`ho@zO>y9dXR݇`YL3a. HHxր{[G2Cjj_q _XEX~m^`sWDܖ_!m.`F jG8}JxKR;d/pwyӴ6M SNiB(5ˁ^6v*Lk@e g(aL4,^aАh;-2,XʿB4)[[_#}ppӏq3t'p@ED㺋Bp]nߓ_Xk.b(2$-RxUII8#Cus7R`}!ute@}G#}ON[e,A4l0fl1V*DcڦXWӗ 6֏5ӐgpoD ]XpPy;+UxR_p\ZoEa~n[t.`+(BQ T)vU86̮ ϒt)v=<8`%~k)\96 ۸˼0Ò,ݒjLihjlHMlJa!JbxJ2Qt!ɶ.)!7}uڶm\4__I $9Քډ ϶[b ?շaf$\8!Y߃;:K. eZ$Gi0/dݶoW7[v"Քjih!Ӕ llji28 ~b]΂:{^>`[i>hˡL?}z["ꖺsaVD?0 sqꋮ#oN1̍ mCq8' 0(M":y4ѿkF 5)HW.;K$VcLCtC66$(f q%0kMz[_8eU RZqF^ONt!}AVi&\$nFzMq^-|oN@.fo@!1:Nm@91(ranR- +]|Rt:x@cN~$rG Spn_\d@o&`WqU[  Fg@320qSKޅ0AS2=kǕVl 6+];Ź `%0o ;-6iˋ"OYPw}a#~łZЀ{mG-`BS#,Xz%=^pH0#hm&_5op!$?u0op~_fτp*K߆iV0fI&E;h KW^`\Gr35JZy`]DȐԖBtxr \5Ba028뫎' X(tIhI 0v?@1-BO5s_?GL[n# ,t}J\ٮ5{]CqHd>wvό(kA2w|182L׀MIG6q IfVjG~SO~_U O4UJ IDAT^퀠0S{JIK7YY)SJG qrޭհBD65F \_n84R^0Ac)ԽHb Cj6ـh~c^-۝UMvʝKRWz5(Њ4 Xlq`Ojk@!%=bDǝSy9f&_9eY~4n58wԜ=u{l Wxfq1Qc(%p  7Ҏ Cixk:سc qVDn6?VŸl1.'km"%t\zu+ ;- aC9YU3}f:d^Z{TМӭ~Po JWG}ظA՗[w;()Y#%p&Ck2u'fA]ɂ[{!`dsRtuܰb<g™>8iz0 z.y[sŸs/t]YA˲ pdJOL$z] 94g3R]p}ӣô dX\+BPDBnQ Ri$oY]#F%yʿ! )RYAu:Ї 6hPu%H!TЩQr-#"7o \~DB^  Hːڪ|Kr/g``ػ:4YwIdD B^BcL* Xd,A:A?vϫIKLeD3]P~§>#_R"wν!;{C!|wkD\ B0sWL0QZa7rۅHx ?@ZcX81{:yg ŤڑyFpJCl_&CW Qǁo>Ǫ3~>ܗ": ;E T ?XAP ~)X^C2ouB=iGʌwi=௑~?*yD[ ܒA@9ھHw[(J{5Q0'֒_]BoD|hs! I MތTҕA;{-9ޯTƠ"U<ۆ@ +QBMQ)_%Hgoe3v_3Gzޕ>Q ,D{#BAuoNOz&R~}p%x2dn|Ӕd yx7$[*;K*K4u;^Ik `3BV[,rAc)%T(x{ W}1~V6R^}-t+Kȕ8i)|É.V85] +<% xrCzuLj S9_LAg}c a!4˛+Yr+y5ܧ끛zX26x{THJ"@E@Wk: X7sTDa^W*XX MqhqACkVSqu04x(T -Q+* ͢8N 3:Az=,/ u ,l*2NC&?'HEV˹{GN %<:X6AF3R֧'_-> irH$EŠ,`rhY </z eAƆ/xE 󏗛U;3|O0n*}(EE0tVT zze̩$MmP ʲDIU%TơZ@uDT8x. =p pup{`BQM Rp,=V'KWxe\"KZ xmL\ZvF^Gק{tN;JJpqJr|UOhk·TҞFqF?EQJ8)!Oj|H O- {W/Ͻ"8ɉǎ6s;FX\ Yx}ÑbKaFZ:e]65Up V0Xkȕɺ ;{ʇlA!lW}KsVJm *#Gqoߋ_KFfl'{D?_R`S/Z/}1b \_:uy60襒8܉% J \\2pҲZsfݝnT.;lOn=y{ ֜ҹ|,5D9 +Ԏ8c[Ųi-Z_=|P_ M0^WXuAQ}PQ.[,!ay345g ĥep4'ݿ>Fq.?um~'kdS]@,h c87*;7S>6l3YIy-(7W/XXhX}xEt;©x`q3p\G55L$ NvO"ntE{u^Ixߵp} Ccpp:Ǡ+ ii2=IYkꁶpcTGds=nNQ`Ao%@JDR掞4n' D$r6ǿ#9gGVmD?7$OHnf "ě-}fan-ģp %H$agqH8" ' G> cp|R0Pw! FMP-y@]lG+ʫ'\ml4I~މ?q B~]P!ޑYp,_ ɎBrv| q x..MC`Y5rH+ъ\LJ& :䨱WهZ)z( @(fMOB#v-;OY$ Ƨ]m22x\|6 pAAgΤ p>\U' +$)-RgoLzڮ޽Ԯ-3@/ *GFhk}!\4I cj`qR p.нp]ʶ护`S#lHҫE_fZ՝jdžF GaBjC?q n\z,iXyAOWj9g:#`4#`&&?TȦ mvɊyfd`^o_U֯QQ{zWP/]O7>)^_l#pVX@*?2Tf g)7T"K ̯j}] x|kԹf e`Y@rmh|[?SGUutXB&J[d gXgoJX"d ׯtjcM(T3PU6%z8J,Dz,!Y~YF=oqn(( 6cw;6P_$fU`FTp/]dRBR7CL-,$oW: z"^do˸)feX^Z+a+V%_ vآvB`@;k7㚏^n84THDF@ i>U(֥;G8kK6r rR$ Ȉ3uzZ( (tNc*r߁xkє?3# (R  ?1$bg+\]%o̻OZ)bç\)G&JŖW*v ZBph#fPiC̍_> 3qNsoOvN $v*2O UzUUDf^s@qnCⰱv!2.,C*,t5 i)H X.ZʔvTǃ~?C> 7MAY!l `Ku3ģ!??\ \}ɏO~ 3eC(ta)%}rynx[*|l`LՒ\@)C&JlA\1\X= _?cr J2[MeUxx:qGl(5.l04W^\ZޖFBR-Ȏ_;K Uk, g࿶CE@/m45Hĸxi23.jڏHʊ|l~6gPW+ (Qn;LFB"N!i=Xqxf#*ėBXYQ$^y/ɷs0 g͝{:PΞ#''x)$3QfImEԷ\@)G rrX\IQ8+ R"8Sckjpu=\sGZqigB"pd!bux2no7p$$dxM@+ ?yͥ4wbNawddD"` ꄃ`n5{,J H \d+vJ8)biIF#:ʐKV@cMT׾{_^OG#@@WWg!.Dl öӈHV7Y:~I%a>cA߄QS-TQCۖ[[- c`:OHM!,zkV~bΜ]˿|=gꞑܗBYė3Y @U+4k|Z5g&q:z`}#,̃ Kp(- !XW'!Tx&exZ&mx^Xxh > @e( G'Ơ'u'w/a*e+` X4M Ɖ@b;1>sn:ㅈ<x+Ԏ:Hx%1ym߫n+5 ; _1*%s` OvKV$Ҏ44yA!@Rf, =ßmIt?XZ~" <M|FhqՋ`"ƹ%'KCg`{>Q98p azqqKqFV~jZ} K1[I݀I[ pn)_TXjWU#B@;lvO ]TB,jW_$xԯX)ZyPW }PI:FRkO!,0@I_@)C s5B^,%k"Xpf v>,!9uJbe@c벥5'h jM Tg"*yȂBA@U Z~9O4ElP?Bj32tNH^=םrU"M[qpuz7e-ؒD`]ԉeE!9IbuA%P0<*)GOḮI$B*x<-,2I lp۴%v1c!(Q@6Rf= fYؕUZ3Mѓ>#htJ³-O!a}L~B$&^]y4*Pg{k 08x;q' ؆̇GܿρWPI.!~o#jm5 l7ӤGy`u=$oMwv|~uR wZA"d:џ7&UímfQF-)\dZ {@ Y>+="Q~N_u"ߵL 'ÄqlHU;O?A8[R-Y LnǼOj `R`ix0$/nw>f!Dg:t$(b?GB:=aU<h ~Kk3O"̖a5~9G`lMӂI7:p~͵v[ie~k *`U< :c!%<H«)Y/ݭO.[l߿7uwt0 XLxUY]JܔX6&t*ﰽ؝T=w; +#H 5ygM9}C߅R(0GrZ^ \f M4"i`fx)RP$'ӗ-+ kȂ)/jeec,2DJ-E(jax<+^kxȐÁAϷ 1:M& xj(5Uk侪njA[A~eǸBc7/E "ŮPaW5\e ,otH@^H;^YM]pÍdR3Uq/ 4b'ܱ9ޟPȵCے⟥bOFVz`ͫ`,Q^v^ nixNYNasi~t'Ќ&!p׃#(tEs: urW왩lY3r 4-'uYH[':ti@q@_U?(T5j9TVKYǙ 'Ck՗6a`GĂo?bA_(7(tI 0c)R 7>!m5Yxl͉ɀ)-{횳W#9x@mJ6\ -R/l*l83 oIf"(&5YUT\(:PK9ɹ,wޣe%S|ml no[_<qȏ:MMzr%*`a㚆OyǶū fJBMh^7]V2iļs+2O|s>L4ϖۢ[5k䴩#m@w\Q7§O-wXJt]nIB47]_@+i IiPה&pRj3fz҆•pp=#'/\=ގ[0~}~EPfYIo.$MQ"j\h|6ړmfA2Ix-_ GKcz9kzs> ܀w#k8\甔ܕ ׿Zh#.^UQEn9eO!ct6W1'!h)/][-9aN4`c Vl%=13aB@yX-G%ke\\2^G `2 Mh ִgE-CfN[vD\`lS#݌qǡ+|?q.fp! $F${G :~kd>«u{J2Ǥ"p_JYPX$m |"fq[%8F38у9&3 B7+k%Āqk ru5HRIgˬ6:.oor~@RnGa1w {opIP!C(HDМ8m03ƒs/YUScE 5"es\i:#vb)^(?N H3+2.o苾 P]!Tn^^5r_BYv^?ȼgS 8l{5aȑwwl<(g)KցW+߃*jο'Gh/̯|M!i K9(%0%h526UqnUk}yH'1bc7r#adzT<`ZKponh%9%̍->2\ o]@^.p HEDF7h.]OhnRh1QFw bw^(~ r7Jo/ϸ2zz@ 0GRbmeHo; .j@} HpefB\Hf R%nTG圙RY"gH CM>7` k_] 5f Sw㿅6y}y{HAQc4@y뾷$Ę .WNP:=Id 79 mPU_6|P^!܉ K|ݫK5R8L$ZY %07e"U <ˇ:` >v>|p`0 W@܌) ql1E͸QdaR]!98w8)onA] qVُI-X'"^ou+|- F Ɠc:,jK#QQ־1%~ m+C;ðCRU2[eB|ݫݯ1o+R0RsW ljq9,-wy۲qd޼셆tJ[#nФ)m7U[82nWUb4r!ĩbݣ>8{S#*"_@-xBB)7"hnʈaub>oc*$.Uw@A@;Z@1xdU wB%oPr{}_2׿2Mυ#RsS )c\%y\ mNVR?< T>R?AKHccS4xc#zat}Ƚq$ͱ¹H-qxaHA, TXoP̳0= spmR[8ræąH9uz8BK.3ߍxw7 qqR8!I kHF`fxKk}{O y(fܔBVVZ* +ceP;$=lO qACp\60]&#!➯ m3EQNۧ]Z7w/f prƃl=?I| *QLHX䢎glZYKpm#Ɠ W_8mP2j#Лw<%ޅ Q >U[/ ; 7U@;1ڏK7Xm} +̫f!C$"1/Rq9qxC|x.7}o* w]D-W>۸ާ7#T\J`nJ!*S(0eew Bo)o)kmWUIqLSc8q.δ"0 tO hy }9 m<Zld <p=JC")j^;pDͫ RNxIvţ`r?S:BJ3 <25_?|zAuu\Ѹ'RsH&(^sJaid;}Xc6%k#G Z B޺rB5d,r{Eꃭ8So#C&o׋ ~^ ܧ8*40nA ?' zCZeAO0bI 6wֿolh;4|xcn̫?{ڡ)ɂ]7_g\å QRXJ`I!`]*-t(g%: s-_אſ m1n8) QF 1-SD ЂB1KۇOƁHЬS'g$x6WBWvjSlXv1\6ts!_,$4n Bw!E$a A$JAx?~TRp1x`;T05,ǫT $TJ`nAȅL_MñqawE;cX`Y_tM9@ n.Yoi3 =6a:mx_F9o8 ɲ.?uF< ( čHa?(ZaK1JDiPЊ*BTx0ư|_}5NuQB#ARhs3gNE( IDAT%C L'KLɍU "(@{d+sHp# 8*(?N*#鵹R><+A֣?h-F;\QF%~Gk:2ܰ6+T닾[/~qģљ s^."1כVbмlF+䴱ַJwk7k!YuǓ saaR Sxd@XxMjD#îPSDN@: aE<r/,(%pk1+ gtfDZa[bCM_sw Ki@$FfH׉HsJb gBN:Ǡ}L>-ϭK֔gS0^R$Jet!JR5K!$-GL Ɛl!~ t  (KuLvCo?$៾ݽP wՖ@YsdIf@rD Rv7Zo3*`@{U QK7c%2^h\_u\ rL6ˑ>;Ldco ohZنe =w@,{w+\AQ,6wT<nÿm+ޕ:A M!.#YEH}@\QRkC"1g_W={$" wr\NIsH&q)~9`iTJs}6b1T޴ }p8up{B!BYS~@eyk׷E_XJ`nI!K%J_# ٬>@P̎7*^Q[0-4#Xy<,;b3-Ξ -6]-[ː[_2 Զxzqv ؜dhxW˧a]n!OL{R"Dk!]C?c QG̓(үB~b@wߑIwl!~'nJq9(%0wďm%b`MYQA}=fYYxYP w~E`q4#Fez,rp}.G;M0xoTxp_sP@tO A:'ǡcN/`hbZ~oB/]8i!VWѢ7/pCh?z2<{ tX< sijUĭ{t 4~d};{E"FPJ|(,[єײ,JÛ;p2G}5`0<4El1ʾg’̳] A,]])ߟqЕ}fQdq"WqaZ(px:XGO3kQ[h+3,*t&nP\R.N]q8e-7d!B_PE&x6%ɚu[0M L&-FX@6N=0 -ya ,L r/LίN85",5:1=r),[⬛-W@cfz{Cx.\2w9@oB((IÙ/ܧY/W;Y/3ނv+PN/~ %LkQ@ hHY!( iTW;:8,}#ԾDiڱay02 fv/t)ITw/7 g?TW@m<|p]^))#A !/mulNvt ]Hea~n5{? q}L\5!!uڵ{T7z,d3mE Mhqw4§BO}'vLgV~?#dbq;+ [21a hш=eZRk20D_R49Bʿ x 5G^o6[A:%@st| Yީ$sDJ`n J$KcBtiv`(ycDNɪ3s2:#%y WU4',}.O ~6ĹҰP=Hr7JK$PW!%PIDž#9L' {LwEz4/ΦV2#1[ |Gͬ@5}U[ O>;{*0 x58-+ m8 n qa0? +PY+%0wOR[a$*dv|hOB۸fz4l-埅-vD\~HBDNQm-qr |M f~ nu.OϖyD\Ձ TbIVGSk8p6 LPӋҕst{oF^ eY Xhxx_q"1xp/̐7{g-YU95ܩfFHbg.[!&`@L4>͋A4DyLg 2Mw36MMÝ[y|gunu]>UD>BdgI.A83ỏjwPF_nzjxoꃓrT]9kฬHt}3 Obn*/'ԧ(vWam~~4|ez@߅ [rp{z%z٩f֩ywI@v< -R^Glg`s1TIP BiE{rHAeRT7}; ]ȣ5ޝ3ݾ;gP*-ƾ\za.EJM\pXV9T^6U`i޷>?\;|.{׬YKS@ qvSZ{Mfj{Jy/| WتxÒ3Ka^J?Rሩ*,dR$Z d4:)mkxNb3NA %+{z-Nwi/:ae;^OpWȀ$;ΟAl wo #\ 1R,p ̩')G®a$췛뱫 \gy/ԈDz';>yhJH؃` odor~66^CFI(pw%\n ~4au. ոB `ȃa}ԌX/Qg%->*֒8ې5p;g^F|]؄dXz LxOa.<~ o^y |=p01\8g@.7ޥ8"'M;F ukb%&iXR?|3F": P?;",)9= /RPG!k('W+TQi-^-=X^q+N`fpĒ_m,c5: %U0P#'kjcRo8 x'gIL@wo-YU@tIMA )X=0 N,s˗ s Zfm}v y8=D։GysW.@`}2\۴=`&3G\ۿxѶr< ׎<z%0<4XR3b < !Eaqs,ny"o}~Nㄣ/֭F|_7 WE9L`HH @wY 8 /8ۼФO= |܃!wbJbNםcyy0虹`<|i1|n&5^o cc=g)%,/+NM9pqao :pZ!V"4I$6,Ҡ\%pv;%N~G_<Q\~ Ο` Vg4QGʇ5\yvᩰz "e̸y p^^J]%0^ 95*Bus \>o %)5']o_;W~|Xh2\> c41 |4u@. /={Z=n4MDYUt<=sJB W[s '}=\u:6xH= i%.E Y˛"@0*>>k3S_$b' Q tϒhV?(SPኗ\nF*6 e|k L7'KC_ H @Q`ʙ9ewғ襶/x XbJD}By 4[ yO㰷 QR {?[J /hȷ/P5bzXFdsJ KBxzp!!gӎ0>Q6 ax)ǞU F S#%ݍf kvN=veRVN_g+)|>JqATqPƗ-L>::g9PO woTػ:$ l;]"Uˤ烄!;7ŋD-Lm/*x$]N(o~Mx|M;zHS|b_LmirG~y40F1arP>%!{Z+ч-@Jr7VwT]1-9RCeḾBI~,,1ϋl`oZjxH[j @CO7 89TawLX^P<_inoMFa)%!O{Jp硔*R?(er6H€W_Oj`wh oRCd.0GB7±^kE>NѣV_穈OӮ N9C:ϮTVh8:ptw x%PUSlJ=a_ELj[!Pj/QnIk"7U#QWVYoĽh(N@.Ɇ"yVE,f} YSE$\#{ V.Sq V;Z}-F`, QCe!Ev\?LREc!ֈk`w ۉ-Sp$e{7W/RIOސ-&p\3rooPT ؛^Q?kmejs0Rнh4 pw lsAӴUY|2}juy=<+ /p#dWt'gpf3p̔.b_M%e+Ʋ,Щ@Jϸ'5CUܗܞ7n%R`ܭFOWԎE_wM~sJp&x2>O G.Ythw~xVU\|V""ve3e>k\ӟ$k¡C;.)ss= ˨XKem-aZ=}g[9 f1+׻;3'['2O}c0` \>&EWߏ~aZIDATl-.r;Fg6%x5Q9 vJ|KdzgXOn[~.֯[6ÁwzDVLX*|ǥ_>pקJ3֦2z>[ɊmMM02EF&ce~ B KKt7pVZ{UN,uEPVw*`c}FB- E@xҗs<^:  AORc(&ʬbF>"WSeEplFNܰ3FA&Q<&y EG%YQo@kKpJVG6%eهQ6d@UJ'//W{Xy_Ђ:AʋfC\iZXs7*+s^Y[w'by>+g!U1mvg#xGkW}=Yۓ;4ڔoeUoU oٽSecqs/V pF8%pѫmh"64\b\a+{o1+7e)0>y>RYc>&LWd@6)^OJ*[*>D}+d}ӞJcࣘmO+p0RD\H0fEzŠ'p 3~xG/ޅf#ڞ2aߢu bw kە79I̪7#­hnU.MccYT8VbOqįO6VʇX$eRW )*Ic-S' S w ^[P\tt-"%J}GD`!jKJsv،[3%b VOI/nشt z+J[>cnMW*FW/9 \Ȕ.ۦ1/Г>o|V"J]ٿ@.BJUS^&#bT(os?=LnE[x&2D,Ft#a?k a@Ԃ.D *dCI1$/ԅ~766>*LɎ:'l# {MnARr|K<)Q~~^ɰ\,Fr<&_]^3}G, u؛fR)0`'=_TΨZvMw\ ?:jPlպE_6+ԭ><+M}m$E(YѤI7FУǩI}-Uӳޔ %}/g<5" j<˳lB?!> e*)B$x+r4d\{ыp?\!r{7UQb4ޭi%{w (#m,sY̋H]% k߫/r&LR~⣖rR?\O .""7 `,iZ^ 䭹h&]2fyG Dٺ5ߦx@cyb$/O3—(qD |89- z"$V?Iʶ3ec3J@g^0}y6Gs.y{?w)j x*ԟ0h}ȃbwT7S59* )Bk $( CBm# fǒ&DhuZ+96₾]CVȃad-K%P/~-srLRͶYL{^hإ'&DdQVRQpRt5I$RCޢy>aьl4R,FDw z?]k﯏ IV]cxGl0B+^ %]UVغw4Oo&| =+4w#yoźrD2ֲ/G/@@р a"bc &+}Kz~5K¾$t?ƇthkTH @"`35$~nUy QH9ߨq?/EޑQͲDCkbQ+9knMLYBXGݿcE39HZKQ%I O;ImiJfg|"]P7wϟDoZ")KD3L% ;(kFЈ4% MBr3˹ٽid5۶Vmj^Ot[^µqmw3t=lG< kte{cCR_פ5RCJ -.f%wnL׊g> stream x\K$9n篈U%Q@? 6v>,|J{02 ^[|SٹRP$ERC9k~6:=uk5n-n)?Ҿ=MZy-[kޮ lG4^]-:{]5W4u˟N>u.hv_g*ﱊ{!wERTہcTc\ &Raz2Zܕ0I\%Ga>@qMfbDj q/ v|oLn+j!L#Nn6A1weDe)"bnj&bCb$fDT+/#4Ӏiet)DV'@#A&^М{H|aW/9!ͽFu#gLsH',g)f;H2gщl]~4|.*uA-k})+FœQH"QZP Vz‚$tW(Z63h$%}i%;i.t 䭸,4zLGNqUq L:a1;uSCTꁼ#y-`: H W`i.MhOvz`$Z`|R"OIe}Ё$"3HLw9{pEX ፫S_ldT{bS { ޿Ng ā$&;.>D<4Ota"Y~l5Hw,H Z /0d\̞q{4CܲO:0 pۈ<d%:Oްa7 &$Ɂٱ<.Q 9|}8Gx0mb) #L<$W1L̉8ӝcU]T Ƒ5ikv(lyJY&N>: jtLf)Z~,e9(63UvV43ݩPl`@e O"(<5b9XL»S_=&lv i\ s 1;t2ԡEGSa,.FD8<G..s5̃ JpHD9CfAlŵe&Al04LEmɨ)i9Jd$j|rf3Bp]Ya-J{V^`ԐnJK~CS QprPdԔhGqrTCCڌ/jLDQ[*HW'W%wؔB \AyK ;Y l+> Sh5DTСk #Wq(-19KZ.7К|]U*(::.OhP-K FH۔`3 "'a}sds5^HRBc2$5Y>nF4qE)veZ "F6z:(3ovU^$)#`[Ҝ͟vZs@y>ғUC&z;˩JGc94;ߠzD4W)~)F_t=nP6K%ITw&U%E$u"ʮ:O]h;/pud ͎š  KOtJ/ .r)CyEe Kw:68UtsKՏW`0.LhÈ+MPGZ%Ur &ZY%}yKEȐw_ph&KWAT*RE&n:ut]e{+ڭT4'j71 r>MF Cז4 \aznѽb VhO<4qvsBEml87gq|hߐ^S բk?´pk4Ѫ/1+,ƃC sݓC>>eӔp8Όn.sl?w; 2^#K /z]vCiZe'ͻ$#A*I>ܥzDtuD,*ѫt]0y4z2bBB vHZ\ [x-fE!5 xkq̓N1}OFW9 ʽMӹprUhXՖ4uݫ%NNTQ }xR)m%8#᪈cwfOaxrwZһX᫼Xa+:z74 n \-FrƟC*:!? kcBC*:z\TtFYΐ/Qi VrއI&AG/ aj,ǧԎHű05ajԁn:,܂p7I<-eVT]?:[L8aTu,wM;LNb[ m ndkBV\/?O :LG/BQ2>{iOo!3<(o^j^"72~~ ޛy~Uim+Sm!;?~o};gyø[' ŃK>o%U0hDT~0*sohΈO3Ɔ {M8Qe?;$нLsYXGd=-dz3HH TI#7@!ٞ'Hp_F> $d^o7fȅj5 ]MU TY ~yK!B|h7/:?Q-sBhKe:ѷsͿy\CyŴ*xf i`)4y;RgϷ0gw`ȟ"&@8Ds1u3SI#Fqz6巼 Z8GE7g,M9Sb#^Nz ̴5bcwzA-Yn|Pb\pmKLOO/.\Eg:J"Dq.яBF4VӍY$VygqCт.O)̸ťH8Lط0WEp}b ][2hyf ^h]D?H!tPEKca"糗mXb%f1S= o-}^nwW%eZ 9ݩ)NVOUEWL UY/6I_@ٜLDcVIny9A%x[=҅I!Bɝh|:)hw'%6|\<`Pb*d5[Y% '%=Dz9)5<~B#ךgJ+~ J8[24QK IqZzzRy7$ufzbCr'˸Ms,^u&;g^^LǦ;9Ci]@n'X-϶ 2,MueF- N?hx2~pNNlG8U];: X^C ׸-KvvVכSg]t$zj< :sl4LID=x{cX&o/zd d&B5fzdX/(){nc-{ *q"Fѝ߲N4?:81HPrr9~.MMOnnN+TSsIeZ3n)Wuƅ6Ŀ$puG)o)}kO@Y$x~9Z>,y(G/q7`G/ W endstream endobj 3 0 obj 5485 endobj 5 0 obj <> stream x]K,;rׯ@S 0^}}0Ն}+!eVu_'L=BP(=.nx^OkZ~ e{.הy=-r֮_PZ]WԟBޤK_c\&DLe|_Gq$lm ƿa<@Hq{N&bD*q'qG€өATz{nXfTC a8ZctÁ>ˍ<gD>lksWh);!xJCnFzhO +8M"æB< 3$hCcFΐ¦ZrAKƏ@3=Ӟ.X NR'H9FBӧQyW'H/:nf߼]1*d挪GbIP"z0!q0ݕzgLjp-eh H44FS.t褭,*pJV-ptBAV(MI_ q8H:4bwF q\ƂPĵm^߮-0sHb-0MsЀ$"723S"$ ̓.,0g5x`0krK,HLJs3ٳD&7.jنx}ak$Y%:'m6t6*$Łw8侱b7XX5Gx0dbYAzPc:(: `^4G21jn4@Hq${Mհ0>S; 'ihRd*{K.]Fn(tN&-w(N63E "+SlAdHwDǾ)@b@6oWوļ* hjy6ML"y}dHo#MlأCC ވv]eޮ]hc(B6 :Pꛄ3J-{z0U3F`[ԦYk*ESl]ݮQT36&m $,M?8H2 HЕ ܻϠ 1GQd).eUȐqT' ^VəLxC A33_;#EiF骴jl{BxFCQUq'E5ts("-K Q7Ke㫐:\B TAU<]9Nih/v}-4ͻа XC7.0*֟E]i>drsqD(SqE@! "t~#hf4JHyܻ>-JQ7G}!m-NBoAA/sFTFgYyBߔ!~\!+Ql6Z~G4Jʒ^P+2K9? OѴ}sn,lbT2A#J,߮+ϗ4>uECwswUkݰv Idjд(}gpϣo*n[%@<;ˬ(L'ɑӦF '=,8Ihb(L%"tB% l9 @ѽɎ;ts(bmy䂙TI@:nH\g}~;ElhOYH '^Il^~A ~%'Ȣ Js (Nf!ee͇"1 O&L!w͗xqT' מId*Tu>!h126in`ݶ2Jztczc*8:SU=| :*sMoa|p#kk#:VTz$( "#vio.$+%y;>Q|Aw݊kE.HJFCCa*91]fƖw:R͡vre;(Z㍖zU L7ް,9 ;#1fD7!4,oҙm?DX)p3 dٹK|<@{oa9aɪ> 9k\>r~h|>pPR'5Ji&l/c??+OW+{Q[vEd}ꮓv͖t)Bك{CW} zgmB7EuÈ3MwPCZÒ"x-YvsLsHM};ɌD\OU84*aʒ8جr*-UQdaCk/nׇ[E_*fgW&&נ)Q2TwSnDWre͇"WX:hXej"ڴCďKMPpܜD%QQ%G[ ws@>kQzQ}.S wjC:תI=ZuxyM`#ZD*ϰf ݮQxmdZDlo"K5F*ʎEZDs)f*q:$TzlGnw"ך$*ъ>!hhUcFbFi(<$t)D|?%s9]nXet<8$DBh]2:z{1rFoAWo-tF9KHg'L\޽uiOV- fOۧ+uOlLuZaj- twDii(3n]eMYzWNQ6/D;4ٓ}mtC܋.͡\OD˾-a .WI( 8V66mO""YkzW t zXl3=p8t>FNg7WNwy8ȷ+%τv)BFZھM膜ɩ肬=|3bkșʱ1ҙpk[4'*Mk /wtIJ&9/ֶY P~r端]~:SLoqڮo_OؕƗ}K_ e+@U|^"(%t7oXyU◰ޅu˿O]w X8oHX?c6vS "=ŇOK~IFħ$ =/O -għdc]|߱]Ѥ._ǿw0?l G*4?pL1&Ǽbumydz$NO Α `}{?e>|'JA y`~f;]M= f+% QT]A?DwyW;߼\crq v!1} Ǐ@."6)0Q{:Uf &Sډ><^4 !?=X#0 L0À3%m;nB]0u>f;Kdm ) F/j-CE[4$0|%>ƢucښT0q 8Zam.$ðwowp)# 汅8hKn\Tm"ޞ}1E}Zb'FT2y=jSScqӼC/?Xfh9t':!p˳gi ;n'{"ɺ24R5"Z](L_t󌄽kGf+Ny ,,h.FZX8߾C'7M6.Sv4mR7)ck&F9O*SëstN5.#݋O6\w*iNwDþlIZWů~7otIԄ93^OSU{]F,*_-*.0} <4> b\8n~)eƍ$厫צ)z GΊ^k Uc+dz= ͬs9H[9wzm6*ŬW& /OP S ~{P,wcAZ0gbX9vȐlkG?Y:w~.q;ӻDM.n?$cvq2–m/a:uL]sNgUHaԝINܤفͽ/k>Tw֌ԋc1sG9:㘩8Vy&;tҋYe9XRG>ڬn(2e^L-6ujg \@3 Ϡ 'My۪7'sY00O]UwkeZ奫%4co1+Mלì[>)R2&aD\He[v* in5Zrh)1$PX-jDp2pMFmW7&`r8YԢq$ya;Fcsl?)Mh`x5l>*l,SCrQr7CsY6T YEebxƂ|>3U뱾-N1BB$m'5#ey d!G|]om=UބbByG{ ?;(a1i" mEk꫋# ~鉜Wf8GKl n]J,"Iv0i:n~9fwPK%~0qVy]Y2[]aǍKɥ.Bxdy]Q-7~ʒtu6jz"Z9;|VԲY|KMXoGnߤZgw1kMк /2ȘJKXn_1 ~+덕jx!dUdBY.Rhn%G;^6 \./Y\kTJ0EcQO=P;d'S V|`Eޖzr~[&_Ŷg'M{S# FEqʜ iFv Gg; 715q·ڻ,xެ #f ޻ wÙyw:.K9) ۼ$4I<{.K[|=Sʶ rjG1ɇEuI^w{txgB.)kvro1_z;-_hVbنs]>`/^f`9q5D{)YN(nѺdY-ĺ Ql?ktv.<4,WyD.}v`}/3]w.=/S.;CF)\$ǭ߮x0].%yMBZaaV&-$W/z3O~ы?i#LoyBIom^F~qϩf8?A$}WkJIvbn> stream x]K$9n篈U=B@UMnç #e73؃jEHIPa:WB\jZKq)m[BY˒#纆^"ou u{ޖ\'tY?= eH/w}~{5gT48OP\'43~$P$E8cB0Q%l&e(z:Pݘ8KC  @s2#RS͈6؋Qa>ͨ0j81ZpCʈ2SV#pF6[3MbPH@-wA )XFTiȁr iOC (8O"jS#GA&^И#$V8#pgt8҉Yʣ)㸍ct"ĩ/1}ȏϛwtE:|6O3Q0gT=HbwB`xz„$tW(Z62h$%}i&iS.t䭸,XT@z {NqUp L:a2;5SCT&aWf$xCWFh;0v4͆swШ%Ӻ|.-pH-0yR"OI1h@'H u"f!0 6| = ~-#QEnM5'jl-<>q">C`$\ 1p!hPL!Ȑ'ȍ ~7x^m'9y91e/:ExdVGzP |,Vg33Nb'Mxlü>#GvIjN 0WD89p7Wvav@ q6vm]R^a\+A&DʉB6Ƒ5isvˌ@Bol墱KY&N>8ujhtL&-whNl63E*+Ql$@ː?n<}Q7()@j@o@mbU`6`4@W/fJhW;LiEs%J {ԹbvdeɏCTPEil2*֬:!1%@'0¶hL5jz]ˣ8c7O9<,Q36&(m $"M? oHJ /C.4gICôk,Q75%2GVE DuPpZl2ܭP4\'lf$vFx-UҪC~S MUTQܞšG'KQ7[e;,JcM <]%NHh˝h/v8}-4էаj iC.0*ڟLMi>drsqH> BTyB6 uDx:tml6incE="tYB$}AMd9Z2;Y-F );b:Ӣt'!:Rh-<& ;i&F \к?ihDI; - }Q\3Bf p:!`:eG\hr UeuCaj´تƚCn MMSePޣJ]J>%{#ǰLsRZ]P"ҋɫ: 96MP#T. nEaHvbw~ \TX(m*i:% .2K%?''OѴ:]0Ĩ(D9J>Iryj.]O\b.!MUɮqsjm]*VD9 BEG+wx 5|a6*ٹ^f G1d l=Y VoP8@Aeq8E|uHZFC'Caje(IАIMvfءCyN#-i3)u Ygs V!h5wڬHjOYJ '^l~ey3_dgQlsμ$ExH+- ]ܻ4&KI"sMKzQw$|g3F=Un\'l#ߘ붕Q F  T9ՙOUn,Q7;qW=EuvENALKjx "cQ7Qю݁DZ)f)γK(u E|N܆#QT͍/cbKָ}jc~h9dPFJK(7V'7J&^vQv4Q[vE}ꮓvA͖7Bق{CW}zcsBEu<: @›$%؜dwB9tLWy= |'U[jFSoY넀[-x~*”ɕ&$lZd=&m$lUlbl˴cD>.'mtwK[ D? IY+uT~zF/ fBc:tqq!0S,r\46M|;;=q*v=Tu[ `0.L4A i-KLe̲YgK.DfdQCO <49);m%?q?Fݝ"ՙ=t;~ );.wMRz':<>U^һr{O[厣Qv]{t2ɍDv73ڝtEҵzoӊg'5k`lu: o6 |ᙋ81G)z,-UkݹjI+mr3G.?Nh[D+nC;DuP#-܉z?6QW1`ݛJ@bBo8z_$eǁ[Bwe{W'_c|EH] ]P2*CG_ƌ-Jvtuf*:)WM;LNb[u}ڇ/ֶ ЅV8')|)Ogj)?|-op'lJG9tۚvnTW1:_C`sww 8x ӟwn+ 3aܰr[' ŝK> 㒍 OI4{XO iow4/UG+8<СyE,:&Dzauy^d r !'pv~T'ugy=A4?i] ^ DGrcF f?FWSoDB7UiV^@s:]C4Dty߼#_MNU9A jO!hD9_c6ھ{+P :8,T3g-$ZvcsfL. X*G(Tz?:p-b6},'E{U1`#!+hJ^v0Jl3`\iyVd380$Z?pg E4VCxFIpTpGT0s%=1cLח8ͽn2Kݵ}a,/\"d[%c|szo]CJdJCqEv<;im i7u笺8T'J:RHg"bmnUˇ]䶑 ӑ+dq#K32FLӝ-Gn$qzkB^5!{5 虌l[wٙ#k"Z쭕q<Iӈ M$.5tZ=vvvyPpi*޵~K+\EUVZ_;7ϟ*<-/e'$ǻSPɓߤq]ijn3&\%!N/LW,i'5?}+Vh1wpX/(j22S]6}c%g}>3kSU y\M#@Unm_xӃzy'וjW.Usv{E0 M]||H淀3#+6'VMռ1acYQSf1݆Fײ]5Gh<楛)pW262^=ȉ =$_|224J[miSNՓIɄx\}sSW7\ nx V&jѽ0.xlǾURLN8}bomg>BhDv+üPHuURf1sޞh >le`O0ٍ^dzCEֿ //.AXE}/o^͵%p+^sf %iS dzIXsiw4۴4 qkm%=~]?3{-[kJv$ al/Z }_Ԏ8ُd,\$ #6RqNt*x˼EI*Joph=oOw8E&(f$ʂOC4n닾d=Fr~sP*@7Ytc򡼂]/*ՋU\6VvFMVq[HcP!Z+fAS~riXk՛c 8C>xoNc{bQ敔l ʮw;i,a=ɇr8ptXt>nHa5Nw)nO7W RDPHдh1uDx38>gx4%7ժ LXZiZG77=t"50uww>˒αW"kGiVZ 6Y?W|)Dw{?mm+nX86 ?lɭs>Z X}# v/iOc1+ B^t)c ňtp۸ly #Fpx׏u5"H>$e82&?my ; &0s$`0?792u~gw9>6 `޵Z6_Óz}=5%~91~쉁Q_r}z~G½fzk'5w!>)砛#P@e?m]ޑ:NmK@Uu^_yv*ë*m<#~TݑJ}r /m%Nbnc"hcx5R$BJ d[ +^EYAj8=q;t,a߻<TuHw 7`@y_q; endstream endobj 9 0 obj 6570 endobj 11 0 obj <> stream x]I$;nȳ.4 ^l?OeFe;Pf\TBQER|K?_ Z{?.w5ki5\S>n+v׺՗|:Rg&wǀ!hqDuKǰBS_?%v | (>"8(CXԉ^tjq\&DLe|\֣X2đ-]o8 $$1"ՈG€ *4׏FTC8> пNG,7CH;5F؊teJNҁt;58 ؈]@iJ-N఩#W} &Z1#+$\R#Əs{D˞.X NRH1s.eS=QyW>H/:ffbTh3Jbw8AmO ]wDòZD.dԄ:i+n  /f=3ЖNpt9P5%E~1|x u`[k ?<8*NMW0";_6~Z $l~Q&Oݣ>5h@ ;pS"$ ݃.(0g5`krK,y©ƻSۿ.0Xn 1p#hPL,7&4Y6e;؂ Y:~J֣IWpaw;J a9`%I&ZC}`k$Y%:'mcmn&`ƊwNlT,eXLt凑G5LRݡҋ;Bs]YV]dJqI}-U#b>`oU6"1YUÃ~b2,ti s6YujF4.~GCTЁR$]2lYǀǨ*:1plE5@Z#JhE^]ݮQTs&m $V Tq2d'+-mwɟAA6X~4lt9&HitWVE GuPpe2Vh5| a.JKW/0HWT;Ѵ|/8 S0ei4UEQGqyRTC7.BZD0E}STF8 U)T I՜;Ɉbˀh!lބMLj:ͽ =QnWZddrsqDǀ(SqE@!P^Р0`6[!~-bv5 ӣ{/QQ},t+j> G"9f+i"#jw}Z6> #DC>mZ⣍zTa壑 ^o'Zs.4Ζd }S([ͼDjk66W/] FG -Y\=.BDQuHJV? CIȌ.hZv]U-&T5MCyFkGUV(<4%U)\JDyz 1 j5KI=7 z\t{: ߓCj>+dՋpѿĐ2RԊRt?:qv4l@hܢߪ ('i*kk%!&Mh~ vDq87 |Wź k7zb.ILmo8 <j&*٩^f E1dk=H6>t?@hAdqN|uHJFCCa(Yz}hز$E&;z7K͡<6fsfRP%"ksU 8hg'pCP9;ElўĞO콒 ͽ|%'Ȣ J#WQے5lTxu-C7.;n d&G|ȮVnVuI`͖#tCك{CW}zg}@7Elu`)nk@!7B[CYQ`ظ̓F1HL$'r+jǘ9_*HA*K:xbFGIKd4ZV3:AHWewYľ9n]Liܝ7IgtU^0Gn7/z#9d. ˹GgtZݾQKFG/xS}NH>S} &NtZ 'I4T\Qq0.1DW%r0Kj |!ݡi=ٷ ЖKG;Ľ(3XD;r5ot" 黍s٦!$!w]7۝.A/z_xfǡ_nQnf*.#wEԎG7.3BA4qm2*nCQJ:g(OLD]PQ A3QW6`ݛ %m`B8z/^eǁ[BwnbW'_c"dnșNQ>#Ϝ;+#,J MNsҴ rII,oC;"loU~Za ?_%35׿-\?^# [z ھnȯ(:;߱+|-7|W_8x^Ox xC{߰ßr5N'(>|_3K2* >%Qa}R!P4lPֻ+!Hq \eg1[xEN2_n=uRp g'_ Α `}?e~#q 2_(/'1`~f;]M= f 5QT]A +o^Nc_+\\=@80ONh(tB=z;E>:MjlbX75 3b_a~ax_%m@`,d h1kǒc m66XoYBjFx~ "KDQs(X B`/uS>cHYYnG4]:rYY+$'Bщ.5=xixwAik:qܘXǙU&Y\ 㮵8Bm 79`iH7b5C썍%q &= ^֍YRMm֜iqZ(aROedqQ=ԕ_;Ba2yUQ%4)<5z^V57QGǶo$)tR^D~,fOǒ79NdasZ7,4U9tf뀷/Cus`E`O/qxJN#Zi2 %aԛNm`7XWjPƾ\bתo Uk"$ LXm,&@Xc ık 3% 4#^p_)&6NU2[Ѡ3qlð%ic}+6rijP 6.85APK[ 2׃go-%q)b"JYEGe;(-=C# ]-ϓ txߑa.OX^1l:- 4lH~r܋+خ 8kB ,hYxLH-r4\k !b 3x&໨;)ꖤ'W8kv:6DhcEˑ9ЪqOJ꓏6{ϗ0.Uxp}TSJ5_a%C9A6^aXg2j1=>{t;+IX"`=cީg=f7qA9Avya?vܝ]0wí{wZ ?a|.ocB\yyءFG+2GaRƶgr.o&fo}u#q{7޿psڹ,u8.fL^p}{l4w]]f꨽^}EL_'Ӑ{ۓafɴuv-1[ -s.{nX̷a7cZFgNf0M>ɪڊ_EpfƵ#O0>|"VJucCNϜD*./t'mZ%A-+/8t6GW ~ęTE M&VoGHyn,_Ssę:|N4'aPF,ڡqwit3t:1:xu  z|Zrg+z{9;kчG{ONy.c6$WP2H7>I> v0vw&QŒE51kx^:zb+~7Y*vэKOĸJX"|ߦM]@bϟLpi:R-RNc!Cm.νPˋVfa Пwo{HVqF{ͧԾpGo') :|Iv3-߲3?6N@FhDG!.#VR,[O‘]Xv_ HU^Ϥ]'㟼e83U+wJ3a~[Gp -d׉%|~M #Bwf␥vU$qTάO.߸-'8^ZS\,SMqA|8XKB?e/<ӎnzyŸ>ι7=%ZJM9y;an88 T:˘@N=uhyrY32fZ`Gnf|'M~_ЕYqE73՛qDoL,w}*km]ف$Gtα;Z1rohr[CP5Iw=4jԧ#״¬ dVddS8AX3~^$܁ Pl!L-p5VFaϛЉizLoPq)%U#V.!/˽|7/{XZ9{S.BԧG81g 7k&Iۑ/䡴r;W{w6M>.͗>Kd2Tӏ?<<_񱫋4i\+nwQ9qto0͚V|-ޞwVJ40.x{|ul(Lϳ(ltp F8G BB+SNfL<€ן{ NW$s0q9fY9_2eb!o~ϛVGھHHYq ;>X"-}S:~yvgi~wx jU}7Ggأ8\}]f{{(j~u=U2'{ 9,mpZ7<\/p v開X>eGjFku?w: Дiwr+ Z= f琙ЭbЙ-:C0ӎ_(pT inN7᣹;T<\tIr~~N$03tqK}-g"Ow/;kBc-쯐8O9xEi JausRo6L; w=ks#ul2] QRS.he7GONTatb*=lӨ!ĕܮ@{`w݊e_ᔏ~K2>/:eҡfzδoӯ

H_gB$ ;o)Kqg{VSҾW!Sr~B 5^ο܉ğo3{voe {C#Z endstream endobj 12 0 obj 8285 endobj 14 0 obj <> stream x]K$qׯn'0h`fvրoAmy`T.f̬^KCPO|If0 Af_opPrMyn+v׺|Ov]Q+ z^e>!k8Ψnit[[ F}BFхl)?j>*}BiZ웟W MsF#IT](T=<0!q0ݕOjp-eX h44zS.td,*pFVNptV)ʜ*?bw;:̀ohP|`X0"VQC#I&[_Swp+< H!|)3!=.BBw= `Z C}፻C_ˬdT[bU k w#?/g ā HL6\m2,rcyh@u3ۉ@F.LfiCH# \@ #=QS(C>HLj3'чiY^vX#)G6IN5\q5t~UH7+8侱a7/Xj `{ggAfS`8L0q8=\3=1+X]{H45vÌ@jY9HEc"CٳM|`b;py˻9LSܡҫ;YBcY6]dk'jqA{M5=b9H o7јLF}`0_{pWqdjW;LiMs$sP˒EFCa@;Jmr&WɰeuO QYtblΩEu@FDG]ݮQT36&(m$f RT~1dVHЕ^n,43"DQK2zyfUȐIT' /L! ͆͌sQZtUZjMsȷ{BzL**q'C5ts("Dptqr2RhD)Ꟈ9 Qw.²'ACؼ Ρ4:͕FI+-sOsOn98Bs"}Bx"hQ``6!zb1;tÉ͕l>&5Dv{"9вSf3iԐ"#:jmsw}Z69#DCʟ-NB%J*l|3AJ@S#*MYBߔC.yaHCЦIkr>!`:aG\h"NUfuCaiUCn UMCeP^xJ]J%+ch9(VJT"܋hU,+M,a$﹮vhGBt0q %K'ޏLW keb|m?h#eNu.Rt?Ir4l@ܢߪ :('i* %֋o̕KCLмOv]܄wnub!ILmo8 yt1԰$Uϳ3&@b4 Lz):m/'4P8AAfqNԌ.T!H'4Q!gI$;z7O͡HW㍴y䂙H@;nH\94bV!1w-HbOYH '^ImV~Qwv}S_d9g(yɜN6C*<͕e'͇"1 O& w͗xIT' 4g:zݸO#3YKQY%;0o} 嫆?xKS[Rv@j(;bId,pT7DEBFBFh6NZ3 }B6ךŽ# ] C0Oh4lw9ﮤ:R͡HW\8DJde^tc>7,ENsvN:}i}@^/W;ϲ] Qiu2L%ɍd{Qte A5eWD3O=B0kfAw:wUޙ~M{.& zG v'Y❦lvӅy*w}iuΒHW3f5OX}p۱k0'ݣZ>A[]]5%>d؜[&y0&L0VC_yg'ntwK{ D,:{u]~КW]Q>' wϑU]i2BO"~Ш|@eE4I{?kt-DW/:[T(.*D4$y`sAq}/&q+񵊸΋G7-!~+ gH6љl*р0tHG8 \"2gO!t!,ӌS@WUu)zxU(4ugҁ<855,)KЉҙe74$ ǽH5TCO L=TYUNuS*41lwhm4bOv}+,U4;b71 rCu>UFtC7W4 \aA{jˣb w8"y\j zsDEm6YK!#-wm'tCTtAGm_ڌ-%S=v6:FX;3tiqmDimnXW]KC;"lmM~Z')~KOgj!?ko-Ev%㳇-l_-Ã} PK"b^Fݯo{7|!_oE~Ų%lC^o?,7N GX{8`-.?,Q|4ehtT@}JRPj(̡:#>͠k;T{v懍!+hq摄t&KsY1YȺEF#/ )8B6cDz 8N?] 8/ȼP*_j;m 3j걛ؿЭ4*_ҹ^PE=TkCEp˥̀/Lu,`-K[,( #—؄ j̵+h0ɎQD]i};XKCw-T)u cbL_JŁUJ^'Q_7 %%_*+1$/*_a_R![ NtAܵ}R->r?ɟI6!eG;iau.s-qpO}_>$D|nxz1Y0=+DkDf$T jU&ӽ\AWTp|I"S;:Fvn"*qΞco9KGy->IOx7_NoĚ̮[&7YHU[ZväLM)!Lr[E )rQw0/h}zqvzZZיƇ=Qݲ!GaLng⮞̍&,i 5+?SL,vݾHLϬGE.f).OhRNXVuۗN|yNV{@?sGPqKT᠗tOAnZ0 gzݫ[Ud)cI;Y"1~i<|.cxML$ ekaJ}d|y8dYG*ȚR%Yz%ٴ/1mossZ2['Қ|6~`w<~UČo}SG$Dw=U9CNVd5iOTg `o|ͧI+t}:z?gI.>R.[0ߓ34ʃ3~_w|O$|vʺ?4㖔F`dK~Mͥ>ꋏ+~>Kj\uaV_4ip7sv>yRMmkhPKZee깧Y$#M/䏋CďKM>fSJx$±;EiC6{\uȌRS\5vaU ޺gsHy. ZmoN)6闬'4/.M2{P B ;.y{1o|7HV׭9cRI뙉HMtlf&2-D;-2˫5>ݳ{ 6}>d SַNvkNl4 A<K~D%lw= ףP)|a[w^}O*ͤc9ֵMdKPT'|bˮ'*os><3x>^Xٰ;ȝ]I|`.oMzmC|JʿxlX;Yjs-p$f<d_p߲m9fEeepG5'qPVQvTôķDdt]:k&q3qٌ9Z!w4Wܚ[stس>cܲHsE݅]΂˸e|Ɯdla'ޘz8ux,Fȣ+>pn@ jPcț]8S(.Ы F껄>{i2A礏ӧMf 2YfQGItɐWW,Jfi͙$X~w ȫⴑ|.j'焬8Q8 v$ib>bX*?|81g,6%<{6sja\T#GN4 fL3O;(*<1O7 oup}eTοX?R:GÄy8CbMiG YP( JZ(^#g5ğQPnoO; endstream endobj 15 0 obj 7329 endobj 17 0 obj <> stream x\K$9nU=B@uMOeF}ߔ"2zgb{E((")R?l+!ktӯ翞k|s(k9#׺^ߵ)u=ץm@kQ(|~Wz H#Kچ=q˟Nm6ChXԇfZiCW.0*_LUi>drsqԅDۀRqE@! < `6su@jXa `cztuCTTāgFn}E!Hd9Z26vz1R$z@=tOR&gtdHӢ%>Zy^M7H6> %rutS׈J̵"K4PҕGI>/5 | 4Ԏxm/vU eMUͳɗDIpühc@WlϚ{d.=bNmJAI쀋%m[Qi,2mJ IJ i\2;iϼ.m'Э,xIhd( -y@9`vyuo-]3:t6ShYjNN6ZFY)p  naZ,rbFw?F:Wc.5oV賌Jgv Yrͦ4(2gQ.-u E| ܆#䷒W/}b ؐqclYG$+ǀ9rTZb@i(+=ӛfP(0l<]6 h>s]'-ҹK e ]]q$< o@`u%i f1]+r3 |'V,t5׬m@9mǪ~wj@moEVԄĐUssڛL]00Ha򷺝&.[XW2- "z'ntwKk @,:kuC~ZW\]Q>' oUUiθ2D"qxʌdi.RDϻ~(z]t=nP\Ul$y`1@ }/& {[ 'SH4 \ DgBa:tu~D!0C,rL4:LҝNV]KëB(+?T_aĕ;!iIXAV,}9%qHd>tF**>C%qʩ .*~RE&ͽ/͘n"14+U0ML\GPݱO]iսN$WX:hXUj"C$+MPpToNRR- wC?kCGŸRS&xV5MٝhKlr}dТw'=Ui~6ha z~Cm lŌ#T{h$J !kU4OIzDs%f*I6ܤT{Dnw5#fhEE F!.իj:]Nr\XWfr޺I&A a3Շɺ؇T6Sm@Mt0p '$Q>\Qqp7]a2,+( Mde^+G;tu(d|Z/og B۩!Q?R 3 saBҬX^ұ^PE^*uT]E|rѡo3[ġhb%4[1tKlwߩ;ť@O"LG֨»*M`F>FsczUfC'ep1S 6n/RPb(&_$%p&4JEWQ!unnZ (|/o.$/3zW,HGx|MXq5HN2lltA 8+D3@*Bo- >)AVǯӿ4[kSUT|4*4)TC,o/tې6%_Uև&uPH8E JIfe3 lK,~kT)SQ-@hBV1y#]C(^@0X*<8ӛ0 ͘M2F_ퟂd/~-"S4DZHs'KU;,$MjlڤH`Gi1h,0@cyՐ7LQ":_3&6K^WbL>)$Ю1ͬN9[4wq!wᾊpo.M<AHAf^!ѫl: OQrE8٦ު듩VQ/-'ӏUu`zQ_ IHoy뱠xZ< V;; T} §)>\3?`X%M]@*^2BUdc37]eSDVRe׸Awd1#K ?*`!-\YhSӡ!Rqm}y 9ě&+'[aBc( "g %1յB˩cI*Ua /&WҲ/~O9)ȼn^lbR^;~yBCyHaDƷ͂-ב5m/euH2sUmn3NplYgSc|pwbo%9$SJE^EחvWF/%$PX}[/ ':_%@OH +ݶ&nd;ʘ%}Ee<(orooqltz<5.GSھA0Y?xF٫ endstream endobj 18 0 obj 7384 endobj 20 0 obj <> stream x]Kdmׯ%`@LO\ #NAPG|SNUzaH(Gp/mxn#_O_t9xn{"޵eu k8mi[{ k?BsTẠY}E:(mC\\}ƜLT DխLer_Oǣ8e$lo ! u9VĝĭL"éATGnLn+j!L0FpCʈe<$8o4C}*#Q!8jNHe!0`#rrt)DV%aS%GA Mơ9#GHlaS+9!͵FuG OǙ^aO',)fc3DC_6cuw]4E}mֹ3e~Ũ3j'1JKFPB 0>vgLjp-eZ h4F.t d,8+hpF /ptBAcvDŧO8FZu^Y#X̆;w`i.MK_ ׀$}OJ^+;=<H!|)3)=ծBp=`Z C}#39UXU{©'3H$&;. >D<4Ota"Y:liCW;Hau5IdP[Yf8>LK4C̲O:0 p?$H#IR=ujOpFck~MH+w䱱aw/\x5p`#S@FPc:d: `^621'L_7U  jhQ>Gul0͸UGaD -]LR7qv`i(FJd2MrKd( AYT6BU\N uI!{,<`T)@r@vo@bU71qF}`2[_{pgqĵ҃Gq49ć=1;t2ԡD,p*~GCTЁRߤU2lYuA cKN,`mU [` tMˣ}?s7Oٻ<gnLPچH4y RTq1dVH0^.,43$|a,QԒ#e2"e՜7d[!o.جHb,JkV.0jH7Vɇ|/8aktTUCUQ>CyN!/ѪLDQK*HW'W%s8+A4{tu8="=.v2iAXV8|-4͇аi9@.,06LX|r,aظBDuAtRqE@! < `6su}Gjx:tG!*[S[_Qσ]!Hd9Z26v*F )=bת|w9!:Rh-<\G#^ohݟ54:s-#t:tR+s " c"BꋝuAtEY,pКյ"T>(jIR! 4iUO5LšG'є#JV"LwRZ;+D4t s\A}nF u@+8wO[=q`QCuAp1wSab8.RQT삸,ED﨨,G -[sc`hk(-Iz-uDb;%!&=м.r#١;۹aYV:Q$Im/8\AdcIT)U߳3&@b4 ,z):m/]4ߠp0jqNԌNR!H4Q#g;]IvtHšG'i%3)v 89+>4b3XV!1w*El䧁,q&g6C^~Qwr~S_d9g^lsμħyxHh(- ]\Yv|Nhd$dRo2"LQOM쮻7i (%AJD?5qD <|I:KDv󦧿 `|t#ߵwv{T{$.X8*͛EFޟݑB#\\2iY#.;Э֬]PxIhd(,5y@9`vȹnKCG:z)vQ,5@''-#ӝ7ް[,rbFw?F:wƘ]PgIKk!4,%Qގ݁D\+r3مK9E tzn+չOy:O\c'ϲ]-*QiFdFYwJA9EygeAueWD;:ix-l;8~{HJ @ta}AEu<: @›$%(N;M:+rǫ~LeK"]h5.X}pQ4,wKT:h};|W!ȓ.$͹go2ិe4ac_q;[M\xQyKǓX7;(n=oU^$!#`NinvZ;oT1ҝU!_^eZ%oP#Yv?kt=DW/: {P]Um^$y`sCc">L:eWkU '.Z)]$4 |:@΄ftPuC:aYi!L\қNLO=K˫J( 4ÈO%Ub Z8 LsJEȐ}޻T܂?ph6£&Kɭ m**;ML4c.r~+iv^br rCs>MF CW4 \aA{:ˣb vѧ"y iT*VA?[ٮ|!֢˅50mnMMzv7z\?8"`mk@ĝ!w;^Yx5ظ˃N}Tv4'rjjs\.sZ49 F%MxjAUG%du]Nnlß8#N?ϔƝАsT':Ot}EFa/H."9OܙCNt?xǡ}/?OQ.Ƚ*]34EGA+kr3GWYO MaQjLg(LD}]P hQWM %m`B d/ yqսЃyޕeX..[}_%[2~=jgDnV2`c3SIw׶mNT6A^06;u5$9/ֶ ЄV8'+|o?i<ӏp/[x'%㣏%l_-ÇҿlE)r1/OKn~a=T)eoI6!@Y/O&orzxxC{@o( Cnq=Ň_K~IGԧ$*}l/O?L 3 .AjҐ_;7Chq\egxX{dݳ.ϋN2?n$N*٤Α `پ_O|Og| DGv\h~fhfaCYy~}IzxBETrWQ!\UDᗗ1#_Kn:Έ%@RdU@4LWr :n⑙D@UNqZJ IէX]RuAE:H8<6jL]0K.)Fx9DL|~z#`-?& !5S2,a:CPa怜BX~E $mɥf)bSD#2 @5bIM_|kO {j[lݏ8 i? lXj7&Rc^.jU3%-cmgtBMDtӆ[B=Lk]j2ev6}NͿ7fTHX& .Og̸<$7?*ڊЛh˖cFќKm%K{Y[Wfv?_mf'qݜնuK胲?)y}|n6?g!)BES_mz/yScZ>FU׏;%3/Wpmʡ^E`H/Z %ُv Kaxny&Gq yf $Ɗ6ӻadqqU+E!~>3㋻3:!Y^_VY\M|Qx4+\I|c#ϐFcuP U4 ?Ҡ; ?ۏ| 9[ iF;Ch8QօO#WsG8iSߤ2 :RjWJu9^~fU31?ȳ8@5^DN䫯;&~!5ͪ/;ǞoҤ5XNXmH^6JOiѝVe]ksJSe Ζt@ ^E!e92me\ѵBwvɛ&f/4-dWO>fEwdXLTK{ɝɎMbוT\Cqo`n1TųeˌF\9 KJpEnmZ_}7"&"A`*89n#"cu9.(WnK-y^]ٴB̠r4Sk;-z'$ O-F;POVsxmeߡ*GdLy6WG=E]N(ۘ3B]PzT7XNKX }j@w\3U߽A9.;j?{9Bߎ?lw_v4{ B -]*HәFWx3# endstream endobj 21 0 obj 6650 endobj 23 0 obj <> stream x]I$;nȳ*4 Հoc?O7,3w*2"o WBQER|c82WB<ߧ?r1K[ϡ,#Ǻ^Y_RkBǺE/R M<~MHgT4=y?BkcTkB|qsbk%EnnZa DԖi(vy33KoK:ÿ9oG\jFI\Ѽ0 hwj룵c=pEFyHi3fckkcWQSvB:ƿ34̀ȁH= & 4 9rZ!Dk3DՒ\7~X8C3D$(Ḏct"Ħ/1uWkBPiZ̬_W -sF#YIP"zy 5aBb`+`Ldjp/eh H44FSnt褭-8+pJ B[;[Nm^ *7@BQ֔mM>M# */`T܀C\mNcÈXl(wG _~Zϟ $lyR"OJ}Ѐ$"O23S"$ Ӄ.,0g[5`0vr@Fe%xpi'jg0 āHL6(m02rc~hBe3,ۉ]j$&^YoYݑ()d~)$s&չYK"'MxlC6X# GVI*NIθX:/*$Ɂ r_XgslMV5`Ȉ-j3)uP&IuRidbN2=]0+h*UGH41v݌c K,٢T,eXlZy2/#G}2hCGw 6`)ɳ)N+p9)7. ʓW[<G| jlDb* hjy4EvE4nF_9{ra:{ 5x#u|G"9b+i"#jW}Z6>$#D'C>mZ⣍zTa壑 ^oW@7]Qi--#t:tR y |N$ʋd_Q^VM.|MQV7#.dqxE!)Y]`(L%"3C2-bXtm1i ][t6`yTn%cH9(VJR"̋ɫ: _<6MPsC E׺Z=Y:0Ĩ&kB`BVX( h"i:%Vd3yOTigB%VXĨ(DImueN2)!p0YIr$质5Q TKWp Wd4t2EڡQ [dGf8dmY䜙TI@:nHڜ54b3P!(~aV"R6f,'{$6C^~B >Pwr_dّg(YpmɚNC*Җ{7wIMc2,MB/qqT' מId*zn|Mk>0M [(4 J7:?:#s;Uճ2GIHt8a^49 gu=.=Nm˕JA*I쀋9m [QiN{{t)$)\l.sgA7 xӭ,^Prꮓv`͖W:w䡬>29": @6q 'r:GB9On˥W- |'T,d5iY AS:kUZdr%I[bCV͹g*oBou&.XWyW'l4:X]w-* LO`ZPvZ7*}礁Rwi|J/6(,F+TH"I|U臨]ѕuO{T(΍*Ed$Kɹ@1}/&1{K1'.]C$mih/pvx ͊š  SItLO.R)CPxF4rKw:wq*v=BW\Q~&>È3M!nI[F,}%qHxdF"*0PeKlV9E(iжB`QkBMĭ/RL+vkД(P;r7+m9tq.: G1?+`8Z5RW(TnN-;Bn}b'^r]JԢɁ50u:UUzv'969p~dE;hTyE8gfׄ.(?f-f+IJ["K5F*ʎ$WDs)f*q:$Tz&"\tE5ITVD+ׄ[ZNUM-"$Vjw5 C君})׬("أm56nxAwLi6Ө*]U1ftnQ -klʒޭkDEAD&-Dm,b_CS.}4FB]ћ3:?ft*/ft挎#MBBėZ S2u\F#l3:NrOTn(%W#gt"4{)RNInTs:ݝQtQtvT[HxR>S} P"LM0]0]Sk@w7Ij23*F%*D7]f]E1_n4'rh]:ڡCyNFr=.z1@\M[$]Ȯ7Hj#, :~i>d]fvSЋ|qh(NCmtv3twъ|ۻ"_rLhjǣ{o Md7ߡ(AFΎGQ37LD]PQ A3QW6`ݛ %m`B8z/^eǁ[BwnbW'_c"d.șnϣ/}Fl-^srttf*>)9͉J&&f' nxmT!i\oS#?" Kz ǒ~,CW@zeBz >~rV|*߽*GXB|z:o?lƻ.,7$l +)Gp°aͧ)C$S֧PC3 .^;MEqy9Ğ?@ v$Th~2,cL'g+(-zrM܌=Bhp<4+ޡyMuX;kj͓ۺƦQGe)X+O]5WRA ڙXd:ۥd\+$LժSЏ^EK*}ŦY_۝)ͼ-dCdԾvX3ɴYdhM"}$73ް>|߲6GfO!un7dz4̱ekZoõJ ⏺ Napz!pZG@JT,e NzOǦw !gޅF5퓺0Vn9 X9AEJ1*X\D3s+ݘQ:O쬹`~󈆡᥌&3v:#{+E7N.eqBymxKUljג]Cd. m^8>j[(rFVl>jJa !cyS\## c,بG4Kޒ'?#.j}sܱWaME(0-Y(ܼAXM>LIyuX@vǓ%OmA}.T^n?9' j +Ҭ$-jAW)_iSB"wvԍ dn^O m-䘵9씘1۰̐[`ք vPh}`Z'T}R6ObKr;F&8lq Hd_̉p5ss J:'> ?ɹ֕8"vk>ʭb r[l3ϐV6 mynjhMH F[`Gk^5W-4anAݎjd^jy@j#JK\[2GB.v1:.nU9@haNF-a^~bv>|&-oûIV4<7ZFsccW%Zwk{ڣ$u )cbN 7з,W1ל<9 OmRǰϴ<í?o;%,Gr0:ϛ 稨yj2 `U%SU0zWFYܨ}Ýl"|ۊiT|U_zR[Uy#p9XR#I}p;2)l"5swbԜKٴG&+Y#vqqcgv1޼/ d#{Xk`4:7qU~+y?3%;;Y=V-AInm\v1Eכ ޺{Ԫ\p,rX0{ÿ0beVJ)YIkn|CY>qKDɜtxaͥ6 ґ$=+;ӽ9ilw='c.jMbNr\tM ~#Ộ~ .¤+~Vs ZoYҖ><_myQ]>إs$-Pe޿7qy J,c"bxe^ uFcLUX3`c;`?8]R!~ {9<>z,z.B~YeMz`) 9?\A(M tX /yBl]Lo7{hC1sxAE)2mL cJ?@1}P瘁xtY:a0Iw!_HvM9o%>B ha zKS[o]Iν 7Qx%oMYdkM|mzhAژwqe׳LǜݯglmU,Aw+FZ2wT5ǦFr0>|[n'Þ6a}O?mnd!{Ug_|QI gAণ_ן(=JrPa~{[;4gε7 ^yt%u}g Z,C䯧-qp#}ȝ =ckGΔPl-ʡx6N 54 $!Yy2Zkd{ɐp< 1o*1ҽqdz/Tci*v I&+iH H_8ܷ?Z`8Z`pN.t%*$zGÕnY&%ۚb=~ƅ;6 9%E CTX> stream x]Ko$9rׯoh-= 7}3fgK2`0 2kp/mWC<p9ϵsc="+Dse/c}fӨ!EGt~}Z69Ǣ#D'Cʟ-NB%Jl|3AJ9]FTzgS-Ds(ݸ\3O1R}M œhrcAtEY,pКսE(jIR!r4Mj.fMšG'ӣ)Uu)yGDZ;+Shr/BG |,2@FpVpt-DW/: [t`Q]ǂ 9 YabL\o'7qL֩.qQG9QQcY [[s}Ag%5$Mdڣz1r{I HvvnAXĻU̻NT-$ BEG;`"/Y}4l'G$+1rTZ|@:QV][FP(exβAueWD3w,zB0kfA DPJp%tB? (bIx$P(Aq%i f1]Kr{O2,te旬ǂE~D|ַ"tYEu%>hl-S} %, ğ# jhRl˴Ǯ/|8?u*N.j;^A~B<n!5X\Q>' wU4GrmG/*~Ь|\%\k!zqtX'BuaT%z^'Qλ+T"`׉(_È3M7PGZÒ*x-άŜ>8tQ$2d.:#S͗0dIb69Mİݡ}+ǂ.终RLvߠ!^14wnPy9tqeI): G<+`xs!ǥ&PpToNh;Bn~j']GO)ܩEkar<ܚ&N4ZKr!>RC~Bww>%iJphΜ6 `Pl'4[1#]MxɌ.%J %jU4 ݥū$pt_Pp$r=rLoQH &PFoZTH>SրI!w%׬(DFou6xpLiz}Tv4'rjj\,sZ4!F% xjNUG&iKdlgtᲈcsjOaҸrwJқp᫼a3:z74n \-FrO\Nס sgtZhþQ}HFG/x#gt&4{.RNgInTs:ÝQvрttLН6$hodBcLetɺ8mL mG[-90M5OEUWw%*nRY=Dx=_7hO-rh]:ڡCyN#vg-a .W3(r QN+nOmO""YkЉF7Xl3=[yb8t9GN0Wpy8ȷ%τ&>]\Yf)Nh[W4b!;DmP#.9܉z?6P1`ݛ %cB d勗8r^l2@},)BFZھ/肒ɩ?|}i3"x-q1ڙHk[4'*Mk wtĺZdkjhB G?@O՗_N ?i<[8/" Exa| ۷-=m%Qa{z`*5T0PfЍ5 {7U|Qog~bo G^ҙ,}L@#S&{B`N%'i4-N-NG/ 2m@yglj% +%h Nqg !"wz N$t ϳIg{ f)NP[D{ra1Do {EhDķRhxd80Y4i,)87ZbG-Fk:ְھ'!J&І-#l| ULFފT\jd%oPZHdU_̸WX'$R5LjS} bJbjwh&J+L>\>lt01}ߤB%[I\ $yQnF͗ TC,2<@L"NK3T"~l^ o<Ti>v12ըs/򆺄9: ,j${=N\ S9^KcbʒAwUb]:6enp”DIٺZp͵U7hgX;7݀:oFO:uz$NC [6b"sv`E(1Y䧨0m>{ 9~{u_v\9cz tKi{m\?a[SζLA?)b!f(aS&/uL_f v'AikOC ʞ=RqCX v lRhƫܪDAaJ9j_ T"\8&>dg#s Z6羍?Ѷbr(渻(xW~0r4=*k K&މqc⏞9,j*:5Nz)Rq%Pa kmH!I;h<+\^]kN[w h$q.j!Bc;~[-d+@=V"dOE% A([bҬxG׋ > X U0z{8{?o]ڇVշAFLMriZE5 4lW;4h_ŷr S6z{b@zCq7tgl8IV8ČqGaU[̉;s{9n& F /sH;yWTyw'qΞ.QGm=y3N3׮+g#l={]1 [VAJ4֟[d?_2 D37t- Eu?Yay vsr[m* vE Y,<0 B)ܿ~옰O_f9[8|gy|Pljd/,-|!n'g&oav1rl*j[ǜ#~1_58Tas0; :XK+_gX7l8}?nή NG [/KDm9/pPB[E v⒮ , S1˝j.y{!x>W{N]½\ծs6UI+"ҮQЭh 'b*s9]RL2(HB[d8q AD]=۳ҋm0ތS[dGZW8{wb0m"or<"ȓ6|-ɲnП B^;[m{/򆤽%[9~ef$q{/p"S軇W疟jnE՛"A惵b;=< °aG1lLӒg~?RB:4/z.0|3k U~gIԙ_)P+=ݡDim4Xso$/zXNNlCwK_\X0$2=3]@Q<:h4oO-6A hӯO[/P ?GKF'TC^>Ί{I,4NUV7}c1 gg9{g9U蕪W1_IHͭuo< fu\ ]kPߑb/F2d&w~<5Je3TVn.d9ary|뻟Nsp%nGCھB0_<= endstream endobj 27 0 obj 7306 endobj 29 0 obj <> stream x\K;nׯc;@v71EU'3Ơ;f~ħl~%ER$%od^O,[kiuy{k/iZ^T*Y\Ii-[yuBu{#׋_ܖ[_'$}3*[jvZէ 3g=Vqz$P$E8}+0Q٥ R#MԐkq(ñI%Z F?@~{ĈT3A:{@ ʭW|un3*uwnVAЇ2̔UHLXb13P"AT3:Ui`hde´.D'@!ƠtT1_KWF"xn`KYԻ eS9F !N}qӇhT[2i&m6e sF"$FajCSO4[ c].wtTkY,kyÊ8HmcǮVs_D5 aAgWbiNݦ)up&uRodbLO7NYuR-TCr֤y^f-q<#SLe7p6`D {c2 Kr d( A35igE3ٝupY1-Cx[nY#S9-௶IxuB@}߂,ޯ^އ&]n>2 /wrİEw-Uhlʜ&K:d!+M(Mƙ]%5=]'>FSn,NGh?N?G..c5 J[pHDCrȆ$4@Y ZAl04v%QS.rdh!Q~Q-7lzV(63\;#Eils EiUoh!; NE)FM *h*j1'GbPܣE8u%ZkK^lRD+?OW5"ڢfr'#:-¶hɠm6MchOK4u 6(C[{%%&mJZJ}9GG' ^΍@w^3rV{ӢiK(lO4@cyIQY΁НZyL1QN4+E=φrF?-Z\⣅[ H3A09UC+Mڍ2,Ѭ khТHg9" c"BQuBtFQYr=y PT ŜrSO(yX54>7K+lj.=ZT֥(YhA:˺GrB7s¶"'Vٵ<$^*NhZ_sbo+g2PQ >"9@"'ˑæzfP{M|1Hz H4QCEΣ&țh42A-GXoG&f3: XǬ6RLc.Vz?#< CަDx'^lGAݠc>ϦqJFFQs%1F9kiFhDF M LZ/Aݠ!Q~rærPE hYpLC3qQ F[ҕP8՘OQ,feQX-r:q7't~qE,2kgnJ AJ1sYK<pPCM݊0klsL-A0ht25rN Aq#w0hYjF6ZFʪӕ8-1p ca:Sc&5-ɼ!4,-^юMA"^*)ΣI(:e `?s`%2&怎d^X);ǑHV^iFQ鳎L-̠T{Q4넠=+mST7{n軋JryBEu,Z MuF ,IShv;̼LyG#w}°j%f4E~NX=GxHLwWiQ<+”JP^Cyd?d3or6n9_2'[Շ&.|82- "F6z:Hb3oī4=7HREaluR1{5h+&SoTc'g+);nrmGO,yeP|Ҝo\~p9;\6ۨ<虞=OI"wvcrnhLPYRNjAR'hZl,smEߞ~$LhvL.e3X@z3fzJYvK gɐt lӊS3.FUst* FԅyqH$K.$(g4>Ӽ%1Hdv;ٌL\-U_~aȒ,U(F"IG_lcN>Ds|T4'[+BDZڞ'tA ~2GnV2ccc#SAHkkW6A0cv۪i3s8>|Lcm]krW\t8ҟNrII?N.~"D=$H$֛A\pFh-OV|] c_y7H/ȼQ)nԏj򊚉ު6TY]±Y ]C$yt#_MΑ߻Cߐo0ɠAw?v=B ZCv7$+ҼCV^{> /lymW×-ϭm-m?6Nv?`\87\ џT5,-oVF#?Əħ^ ^샃H*XP%JxҘ$&D^>x~8š+)L5sW⌿9-N&^=P}煃)r7?I} ?}4'9dw >j^Ծټ#֏g8E]#CŹw]vR E; 3NCøs;O a-0 #~%b˿/gyyVaE$qO"ms3TO#~ţx-^'y󒃭[گyrf"w#(u!~yD C׺(p.Cc8|VauQJdQmn=E:($8Q^rhf2f^ 2N }Y{R:`-U$!NiFMN0 X)ܛ;2!,L.߁6mu_2 ZP2Tn;nxbeԴ^>a]|LU]߈(RfGmd :Ux| l_!iQv*@M&" "=TK 'WwnM\2DMh =LLC-oJ)1rۤUM==-=Z$r@@<>Mty.{Pt_0Ձo_XS$< O?$ Ttz~ w7}tpHdžK.;&{#~[ e< endstream endobj 30 0 obj 5832 endobj 32 0 obj <> stream x]K$9nU=B`P@WMOeF}"2zz5"((El׿]k|k(ss]B/+%y֥>CsQ(T;+=o?ⲊF%mÖM_Khm>ph+mJ]C:Zal3BUZD|\Gq$zޖt!l`"$:˺5 0:@֚G5m=n2Î>KҐ,=fclV [X XrB8*;"xJ=:p=m<9b4   4̐Xk f.,%T/fp6q{tHʢ "r}YU {$ݗ[7.֮4sB"$Bɽ!8Dh5&8ƺR ] egٴfH4" Ɇ ::j+, -X=63-`4B@ Z(Mqa8pЖ}42@y h&p6 -bY D~}yJ1hD L`K&p-1 Xx< G 6~- j{`4 1<< HD6XP("O$D$y hAۅ?$V %҆, )`~SV&=-j U&A.MC )v̾oac>@ 6 =lcP"Quy0=\e|c,2֡LV!k<(mj_I8qꋶ] Oe\6mKQ~(:&J ;_z6z`^pV"L!uZE@? @2+MǾɀc@2o {/ayWQ  } .(Ye6 thX sa:E]5*~GCaT(b(*,á9d%N`"6(rЫԈRhXlylˢE=0H1BGQ*C&7$t-E7.73hLCG׈(o2Gɲ*pH9?EEr*wڐnáьGk=\,^ TBsцl/0ai4UQCQyTTE7.BjH0EyST U(P QOՌIbJsACX L5m4fBZ3r 6ٝMv疛^a> [1=` <نвh,dGHn`̻-Yk_QAnG/0^{;Y b9:{E(,nh;(qѢ.4& )%re>&ѩiEi!7+Р y^L&J#ʾȈVI.|84(Ke,Rz\Bjf(=L57<7KL$j*E7.0*TP7xli+LիP`JH{az *q57AMF\ G8)M`{t`Q\܇C# sYab#.ķQ-vDԱ,³&3[ -rQPBxrj(\Td,_bCxnmwk\ͰV*Dq}&I2EE DQUJlT/ (R 0[;ɡ"҇C[ <,(qɨ(G:A Z֜@ѼɆ^t3(m zdDIt ( 5lhB3BڭAcj6[{ERP>QbS4}`7ݮ(EMyB`EI7tR u-E7.n #Ƥ.`CF-W+gޮo-@^NFYw$3~tFqݲ BΪL=4ol;1]"F(k0oMy.@6r;p4&3.ԖIR3 t'TWwY%ph4c`pMvFA) wAVԸ-!3W`ϻ78~ [Vƃ_yKƓH6;X^{޵Ww]E ujZnנAK^q5Fo5#9 _q󭷉v~eVxʌxi.Dϻzߥhz\4[:ւP0ig9bv%hpP]_]'lR]Ţ.fz(;̘&4fP1W i _BR4 {_iSffR`h0ԍLԀ/'^VMgU>tE(ӄݠ"ӇC)VǗ I5pe Tх wp] ;뮌?+֠h6mcR;L{"7#QNTT`쐱ZqW먶\R)9h|`M!LuõjbDkc`#X H%A7s>8BE4YD C9 EwDh[D3ihrQly."I4W# #092Tn*QVF#gjNUI0"D^ks5C䐛}G[.,(Ecm1# 1AU&4$ǫr+jۘҙXg4KC"K:nE\C%*Jjg4ZRn3:H,b_CS&}&4:ߝ7IftU^MG7/r#9çd&k ʙEetj]QsFG.x4F3:=HꝹŜN(4t9"$ɻ.;mѬBm>Pmf3jDZ=&УGŔD7!̻m=]nwh'aeQ/BtA7.F2=!m.*z6hcmr5nt" 髎ⲐAtlS$ZӻfMWKf.ϣ}Fh-99vR:BP:dgnam Dqmcd>&]g' f yҵki\o0ӷpm_ǟ ƗYx_2 SW@y~y }7(m ~ }U/a8.ėQ'orxe  gu)Z#Akq!G(2'$}`X~]J3-0ʅ5n-[,)\r)pu_VjeLaaꂰ1 61v{{ؑZ\eyw١>Z4羵/?#{zJEa|#QmRB}h8I5t2,$P[ W/7]MC'AfY ;yl d7y{=;?h8ׁwNl0-g}F/LE_~d7st`oc2fL?}s~ ,Czqz2\Y\Dmr6~vOR[: c;gud7MNiꞝc!6@l'Gca֠)!t/+_ojσ⴯8WZdJb0 B@' i:LDľ4)aYw,I@.j&OV{d,zW+'4.AW;jL!'9]nD]{ ,r(lYFw)yhr+Lqmͳ+ڤ˿Bu!z[`tm햝%ҒZ}= Q2+ jX_% 0qٳv1[F̯đ.R8[\2 s t 0ZQlD]Lˎ1= Sϳ &|켮aIȬpIRCIȇ^, d\5liv_VX8ͶM.lX8AI[(p\Mڲ˵xd ҆8m$'^C)#цiXF̔^F)YPL0tVm+*ڥH~ ᐹD; Ix yol|^ᓯ794?Pt;^ws$uԨ$5pXKejg.[R7:ø?)]# 09! muwDss]Ÿ;!7a0kpbOiTxBwvqT'l|4=fU=4A)()nR ^ ~etyxFXyMϋYZ<:_ 5bGiQR@|y{`:/?eۇKP%~C@]pp;qZƝ}32?aGHjHRTdXM%iW9k.qրL5E.lVkm\)ڞE?ty1)^Av&ᲫfF^3㝰Zю;s5v2iX~}uV&5k xLy:jF)if,{ 2.+ÅnO3}p#$>7kӽ#쳻$ SNGǬ@ Ĕ1|aoqwODS$/!ݣB$;EQ]ac6KkdP 5)+] [&̧tt#o0>WG< uǸDPveTVXgY"G|'o*ϵsw-Lʩ<_ڪ'58: NsW _>s%igE#Ehw |ڥ wLQ }QAdbvho 1ɟm a>y՚)|6Ӛ\(Wsr/7N{I1,mH|btx,G#ݛmaj}mπyCn5հf5˒Z|fBy;`͢M=Wq?=u6f'\ ;YcZf\N }2|_)Rj.Y3i e*n \/)[\T_kQ_jwɧ5 L!O ME{gwv9E@sI} (K#_im`ʓ}lP.juG̈́x_27[*^\o\ᵣiv#ܭIε~`ȋY+މ;Wl̖ϻ QPV9G/4|gܭ$oSuǀG[eT{p*0OXNߩE;oS/OwOL1l0@NMna]7FLb٭ޜѸKQnw0/PjfiÂdB ~.?qw쏲(hWp ntO0LEoSn*;L}Jӆ~X#pKԖ>Z# p1UYsl|XvQ+$c[W\-:~!C7Qá } ˌjy_f>s6//G t#Xݠ?o9q@\3Ex'6a2O4TZdi9](/:qLl.M^%̿_O-[6 ߼|s(=|'ٝos 6bB^\D_?ق.ཽD%Mf oN/%6T]Xx}_ KT*TqO%s=~*:I__*"#zz8Ɠ! o!0~h8Jow+a^pԏ;w{ײ|?y endstream endobj 33 0 obj 8098 endobj 35 0 obj <> stream x\K$9nǯU=BP@uOnç #e7Ճ_HH(Edoau\O,Yk|kiZ֔i^zY{kuyMQGzQ@{5gT4\%6ԧ 3gt89 q;IQĠX*,T {*[m-Zrdg ޶sa<@q{MfbDj$q{@ *6C7F SQYf*yΈ>bkIkW 9;!U<ˈ*4`9p]0i4IPmȳ9(0Ck+r6iՋ>g{F3-$X R'H}l)?>*mB0>웏+FœQH"QP' I:Qld5`HK$L6Ҧ&&[q[ *pN /ptBAevD%O#yM> H 7h0`Fnù;Zhki]/k ,\D L^%\Z$ L^@`HOŃ6.l0g۱F<}Zf;G jdrsqމۄ1 BTyB6 u gXa`a`ztum)**[ijO@\Q]I_P΁N-Eh!EbGL:Cgw}ZG}ŐMh#u@-Hv>Lx|tЈJvZn%5te Z\3eBdv^Ch}E{qzp0Q2#.gqx/Cҳ0t MaZl[cMӡsńʦ2tu(b< yjav;*ٹ^f G1d l=Y 6nP8AAgq8E|uHzFC0t2 ~|h$Eג[&vP>xx#m8b&u!6RLc.V"?;?GxNU)[m3i"K\Ia+qQrl40ΙtpukNO"1Y OvMCz_*ヺC&Q3?Tq6!`M4uXҸ_0jnlt/x~,SGTg>UݳŗDI[t80oz{Uu,2k]\i$mۛyw 66aמō # -!J'4cvdwRlpP>xx'7+.Q%@Vtr6RW 4n'8}aȉcc!cvI ?HڲBc2j]Hd5Y^nFmݝU\r݋x'I8XWj]{7*}2Yڕ!_z;өHGc94:ߡrD5Dw~*f_t=&nP2=S)Iw.U$E0ID]U$u.]KHivd ͎ա  SOtLO ȧ]Ri1/}S3NUwt)Pi#DyMԐֲH.$^v,%}$qHdȾlF&_U84«*[[ATn*~"'M,:شbM>Es|ivU4'b_bZr>UJ3/-;i>E aznZOk7c\~]zO)[&/ SõkF->:Ĭ`WϑwK-nD*q ](X=6; 2^#mo^]5FkZe'ͧhAz$RnrzDtuD,*ъt0yiDGoM6NQ`94titɮ܊9[{\5NQmIKޭXkD呠 k "Y݋&7-D7:AH[ľ9nO3$9jIJoFot7ݾ"4[Jtb?wnormNtnQˍ~ཱི|7Ao."-ty;Quсtu\ݻ'mI ȅt#}O~8Luwugr1ݗ$J0Oˇ23*&Ot,S?Mde^:!Eiwա|DHn&ݻ˾-e W$]Ȯ_OZq8 :l$)w ЛNKj~iqo͉J&V'dmt!z?_cIә`I-Gv%㳇=lo[zm`oo[bS{D :yim6!@[/0&ZX~?oP,8y#nl=\0?,Q|4glT|JR0j(̡9#>`+t =4M*gVpz$a@2YtLeˊG#]y1I[& )8B>k&8EX=mie[_ V@慮 y@PE͝>MW TU]s;!_}h7(.b//:?́)%Aw$PX -nc%0KFcŷ`N.!Z>hC1A]"pH1yX)HK4.Ʒ.@$Mxt^U(10Mc*)?HMHYxEe'#^7#3XCy5W/,d¾}a^P:V8y[(g Lq-͓p:j&v0+CVbUk 6%) EA(E3O_YpqpKu8]FAOԉ_(V[}2 O[9s~hqRbԠuo4@G;)8%1c*$Q;wp 9iAN&ybtʎ̓H:lTn=BRqV1%kFڊoaM{495ىwd?HR]k 2YQ-Z~* (b]Vrl,+-%ji"=6}wKuܲ4&mT垯3~0r(;/2㜘E;ͷ7'$eESg'9aI2:{]c{7 3knӑ (AW7J!5_/-~9/e'ٝȚZ!7o;er(V+lV,g򒓫B@6Q*M>Wk):T\=[W~Lzyj짩1io/~g6f)w?lã&BvF:RL9 ]:?NaaJ%JN my~U6P1"oDfgȱt:O|6.%PގE/qMN> stream xݼ xǵ(\{UHjI32ImFFЂ$@HIH Al`c8+vCb8H&}&_FON[{FUէN:u,U5>HdpD^ u;&g\˄ܡ[Pi߄~ҿ)zJawbz*j݊-O$#7ykdL^7mcdlWZNsJپٗ0>O/b^~5Ry<+ Jvt#R| xBlo[ܴ|% š`"bayYiIqA?oA';+3Ýr$Z-f J9 $sF"|;^~,WqbQzOs^)# rRT.uֻ7γwչ+Jz泔3.p'nsFY 0UWΈ;8[KDLxܣgS JzDc`FHsKg}ru-mu+TPFTZAfC35}>{MgǺS\qErv=#>ukMBD4SʻחJT KSS!347vfrivOFäky 6XgC՝rnָ]e5 ^dyr:+LtFNVz~_W7g$7oq4WtNĔw=Pdr-F6nsrOY.։T5 ;#BkͯªL㊄ dYnDԻbsAn$}[gDÄ3~߇C4\ _XݵsȪ^ѩTUXҷ.V+⯯c-;$0\I`"L:l \eOu E}δ!g]8].&hȡ؜Ki1Bm+܍-:bD_0t|f hܝR \DqvRB@38CpV=eF+LTk+ Yh$#uH&N,6"`Xru_;c c cjx(Q/;;݃.gDnd}cQcX],dq cf$37Xe7n}ҸWL1B7Da")gw'1he>Oe67i;nrTQ"fmőFhl]ʬh9#+VuhF7뎶Χ)`_mי |Y)eVhxEI-(ug(e2 hyb-2QJ܀h I7tw8WaMZ(,).r8^΁lxjO~t}6\}Asw9cwto,X9s_t6dɶ5Siu47՘L{MGLpv|AhYzF.I$ If!Y4*jD$B$^/(¢C3͞S#ßeipg gd9''uӖ`4k5W,qr䩯{,'(c|6 f0wP$3B(ȩEt9wzVqQIi"Lla|p$!6k[۶FlǠd @\|vEѢ&SMj/j n0ܤ֯===Ѫh@Pq0>&<)J0.kk!SZS> 0RǮi`E-\ۆY 8l? S_~ͼ/ |  Iq8n=-dʢPN5e*29\G3* *P[e]BZ"I˵yQ=rf& (H2qCfQF'5QRjV8\ fB打(96ޑtvr7]|{߲e?ƞ`t|z DA59ӟY̕(5ZR˖ G-;ڊe$YWwKrro^Ȟ>`˳ffh[XS dDG>;Ax+ <_gR(@~|Cl;{k&04Vp!.|>lf6PuQJy`EG T>)p% P׫ C@ ԫJSf_AIPADIl@Cz/+G1R }A SN)ߣG~; Sޟ 2;k>c>=ל|,AAǂ >%\cyj/z犯fg7uui]+=ת+׷Vw<3IvW[1(>ScSr+vn+lq+95[~%Q'nH"'%?Lx{5B(q ,O ɗ9 }ţ4{A֙Gs9YccBѵbCnfq Sjs>0ӣi =4RZ}3Ekʋ77K1+dI2E_( /m}&>YtOwGT7u%0Qt.@~4\ȹÑ)p!6R(Hs k̪fKTԘG,R1Zv% 8g{\5D͹baa?pp5SIM6 <7nbNU4vMYf;5B0*hloZm~93^;c+(*Ԣx[<%|9<yS.Y D@gL6DmMKL[ V5.1bbSؘ:KLtXμ/gZF,{-\,sPvtp]Ifaơk8 [8Yy=%lJt$DsZD fAへn @o[Trm UfA߫Gԋ`኎BiiKFokwէ9,>K!/z-9ZCjN>l[8VM7+sb䝇;"덉)GA*D=2([Cd9FWSL}'OeA[Rf$3pEÄ+N|Ș)xh\`W'8ԢF5XjHA64R6[ [+{X=bV]P]+s];\2[i.ƙc^(6x 酷aJ!/%$~/D~k^61Y1Q7ySS\6:K]6)ٜɄ`Lx */ y!"/|@MyU «^J *Q<, MAfQE@<9^V}C}Z򽐡4Ur&/wZ /T4[ ~oϾ:ksQ)dכyaB Ԭ@_/\v`^νEm:F8}=l \CeCljqV}fg9vçGф ;+0L$'~|&ܟe83ӯ]\(&A{YGK`AnV~UܐNT2Tz)5㭚M14a'ϡCQP7^߂.t< TL7̞',0 39+ OZ }em|Oi3WNM '4~L~a $'#@]5g7ІOdK+!qW6iuf87鬂 Ng?Zu*z_)C*QN\#T3 I'J%On%=z(ʟ <3vܺSUv«d,(1=Ͼsw8[c'l89ީY;RRbU Hc"0qq9/;wNgr3G؂tY"'Yd(~ϬC-v|Oj|QY/VJJic~V߾nxKqb XRP:A[U^TиmAU#n_m_`IqgսFGYǸl!i%*ߴ|Ur. m_ tG1gfߞyAMBh-i4X0j%56gU*9)ALkd(9w+HѸX#a^}_zRUd%WNX9[0=[e@xkSY *MinB_ LF=ʑI%OO:WmG=Ǘ=HWI2$:hOi#ZB 9ga# &ENC҅t+uC:hYЈREҪuԪzФQ/Z"ӛzuKt3:ί;;;u:c؋}JVփ;RPVgR yv(;YQ,- b/`F0GΏlv Q[3n?: ꟡>y^i۵1yD.Z23iF VJAJZuMa}f0qr\sdOkFp>oS-s&-8>}Erʔ@N| |._>ANraUtd[M]MBBMm~YQ,w +5$h@P ^ ~G$8*k%hV""C<*Q6I~GQϧ稂T'jCQzU841kxCB;8z@CF))GΜS:xm3+XF<~J![퉽v, 8L^-p-I}ɻzߟ~P9Gɽ¿_;w\كaHod6?i5fo @;*QO|K=p)˜1.ӓl&%5ꏩNt '@G`}[ͼF1}%P#m;]3kcyD`\{<_Ѿp=ϽuӾO?kwn-ZUnY- 9O{n|把kK9;}傖2&S*QIF-nHk4jz)P+UC^":_D 4ShiX\/~]|M7񯢚m ?V6p%z}XьQ s-R:Ch`u3I/ua+EX,B"4O`*`EP<"hDYpDHo"Jpvz/7^Sp-V|SWDxVEna\u"!(B-"v@wDT ,zCcSG#ǂ|uKԂK+qW.qeҧB.eڒNc=Y+'ܩ[-.m6l:l%l<;Gc1`"QxB&ef* (l10@{øB٦gwgH\;ӿ}_}d?~ֽBEʧ;iBlޥ1ͭ[)gb{?Q20 ;GXo"D*dU"EieZW\-. H֗//LǶ0Y$_GU{TJҲ-wj4Zg.>)u$N i@AWmc7,-('gEIi>ɥ}^4aCӕ_Nx䑙wUm ;5& R22gҌTؕp]a0`Vj]UM^?WХq̾e{ݱS[uyWFP)?|I39Vϸ'Mե7bxXՔm:v%i 7I87' ot|7t#{W67[0YL+Kh2_eY]J8K0-B,'ߑ+CV.1oΉ>iTZCXzN. 35n n}` ([TNs&yZRD>,b2qߗx54?""H Zn&DYT#1mc1ՙeh_h$5.)+ EPTkCt5=w\:tHs$$m`(7喹=)ˇf6fs :ѿ~a6lh,0gVvwc Q5賫ekAiG5(y8X$ ˡY`_|s0},&00')&0sx]'7 7g>7pp/-e_ zuVN|qG?*c9iwT˻5ؘ;[l LZUm1T6U+KJ*͜oR}9&w'ka_jD[/ϕss'sXsUf%4b&~<^1G{9v|n'^˲c/FDa5SPK2fٟђ-KS[Kv~# ~@p}5| c- KFC7q&S&wIqK,S!_Dݢ {V/i\rVs2N5Y*k8߀fYrNQP x(_FOTsg~Q|QO:|wq|G?Rt0.ĸ@T9;ZajNU@!DaFVL-4VhEe Z}R57(׬4kb0N..ia5skjt< D9N$ N @ P. bS-ή_re;oÏ{y~^sod{*ʍ-cgNn-lzk߾=;u4W׮~pc>Ώb>NC+ =Dk%Z/B jq!NˡQU짘.:;rYgCun7+ޥP{swnL4gzqaէhy'ߜ6 Ft6 S # HliA2$sm6&Yk k&qǢάu3r].m[CM_΍RyAxh¾{Wm=kշX2Ђo(l>xz m1HxR=`F.M>y%gx6].ȏxSǭ/ D'eMl/?guԱOnql*.Zu,hd0&Z-,o37a0iѸIAkV J^68 , Qkf@^cNj]vl% $PΨ0azZe<$Xޤ6Lu=5R^~Nw-¾OsWQ(ߢk-rx545SA A'4{[8 L9$'/H"riJMI?Χ;΂FdR[~yE9r=0gc ٯAb&c@;xjWI^=mXԵ!Yɪ8|פ۞~'lXI߭\N TokSrݞÃoTT.=fszKqR6_j/:jo|hK}WEoxӒ哫 r}"¾w~>O]upUpUVנ*rܷ";.Z͚̅t*AL7BF<{=Gݡz Q#']hi?wI}^#58Y@ˑ9> {byI ^|:,>kd!>Sy2sq afZ 1?>euy,WEI@D3>/Co~0XvO'[ asaH?8GU_P}~RSyLݡ}R' ~js6טjYjV7IlN|4oIIIs#ɗGWS&S1ii8v8>pwe^UưM ژBL2KGH_t sx1戋ly O*bi5M.tjbi-1DEañ df`Lӵ44.=Dɱ4Gj4Orcip/*ފ?$EHER&zF JFr讱&u9Rg3?lغ.Ϲhf018\P[ߺisx?92t}k'G:WooS {~x|bp :V9'N88*6 T M#$~u>GFGbM t.럘ٺabbt߿sμ:[7M^abHq$|"R38X0A'C?ѱ&FwoG o]ᅥaVu%&2AE#9,$WV2I¤!r1@"T眇a\ s; r)֪%mjDcߏB# ق1 F?l)_ #V|s[o#urB-PhGa_]A ysbY?Ǣc^2B+bլdPZ۪@}NMBFy1<3kuxȲ';Kx!(F>|TW8c8[+YZͶ'aL6z9GAޯO/¹` # |q%q9w=o佽~{ynN4ǿ.0߅lr|˜|9PJtK/܌K0rtpM+kr<˜|YHl\aB ,=qLrs35ϼ 틌F=SH=ߤ& 8dIb jz鉓O\zO9ZKfbtȀf(<^f0%;Od8Cx5Že8.|2;,Cё^:ʛ:=zQU:!>>dz=y{޽3{S2CDG.|#..:y z쎴l%ʟ9mqL"//l{ab1LȖ/a,T؆<rm+ۓ׮B_9[`3z/^!' g JBNV *t 8V#3V30] L\ GuA|V6ϴ.( 1noE2BⲐܒ ]hHܑ.KZF:jmp|$.XJ\ _R*u40vf1^Cp)^NVnSNTc55&d11]2͘5XC|{δϪgZ##UҾjun.R)\Kj `BfILSHmv@4A|>)IȈ%{nh+&QM_V: }DރYqĊMG ƕV| QPz=RPHc; endstream endobj 98 0 obj 15976 endobj 99 0 obj <> endobj 100 0 obj <> stream x]n0E -E qF0xdvĒ }y-ЅCq<ra{91 ߆/]8Iۮk=&Y=>n\&0wGndߧO]I~ma|㧿~NdJ[|og|ht7?CʿSJ36֍e~J|7WL9z .J68Vj. ^ pi\Zne,9_d^7!ۚ[^]`pp%r]􇏋bkҿп¹\D_/#9k:Ř 5C>Bj p %/P[ ,;+SYA_18_ᬱ Wܵ_qJY!>l<}柖J4v>Bu0"~3 endstream endobj 101 0 obj <> endobj 102 0 obj <> stream xս xE0\}{M^N^BtK@V$$ٔP2 :FPT23^G\3E\oIW yorԩSΩ:2ؿE!Dz}k߇B]@zӠiB׹>_"GHwa(TiGj&uфcꈣ߱*4.Ru[wʉ>}FPWzZ׷\)ľށ(cu,/oOKh4 ?ApLPH&sT%&6.>j':SR3LǛ/(,*/)g) VΫB[ȄH7|"dD 49]X.,z F'oڋnOߐv=%p:pkϣOk>~@%|ֵOߎ F'(%{r6Wt/^zNt;GxA ߂F>+Q; 0AtN4~@)GFhÌOWAg RΩLy/b<~܃:>tEfr^+jk.Y\hU*ssf%YEyY^;ӕH[:AQ pZl)-\#dqG+Mh2jIaFm-FHBv) iHlЬLa}a; hrGm^ )UDwFV15\RNQ8洫2]JMjMs8 F v$WV/(3]r) ͑P%nF:o;>pN@Zmu&wꜣFӖNjt=U׫Q>Yp؆hs?15"KX0@wx8[[Mr𙈈 è:7BKXR5jXX7VBJX~ e#;hωh- mhUsH8Gq 1ղ-:UKG6GC(?aCF#;:[^Q*ۺm| Zjf)Ȱ E" =. Rtz[ax*-M]-5tnT,5U E iTuh;sGJhʩl۰Qt!w"Jy(b,,b#J'1|>#l.wi;lv,%AS rkVVUAUMY 3ػ{6Խ,PjoMs𜖲3I4e]+TRY"XaZB# >e!)s4Tp(MJ4 RQ}LwzL{(8Jh8JEejGK/e饡tKS3d EgrR Xgyf='_z`DgKYsrڬ瀥tv]]g/Ƕ$S{li:Du.3#7:&;T4mp_&lܝ& '=DxI&2l)<zXߦ߯'8MCQhM$ӉKo@2A&ʈ\Okqqr,ӣ˥ rv 1,yYWԔmjBMAM4(O "%`Cܟj~k 6c>:_8kY+vVOmp#.~gjΆZVUp ._5Qf/}Yq\6:䧚*QCy刂;79&fPN*.*aT9'ЧRbJJKL.RM絜 -FRhܰ?ѱX仜5LD;{,o{\⊾~3'?碹(%Ɓ$ZNR+Za$S\tԱ $QcHp U''jWGƇ˿FGM=r3A=Ze \̅Kb#Z!j˜-axZvv Hc6Ɨ㆜\:4nbDm&~l{?=4&{\IK))ZD] `hװJd(_RJU77Nvzݝo8ď{)͊J45aaeK/yAK^k%+dnl؋K &_ 1L&݌' ΢BsZM(YCJEEK1/Xo8AMT?J=K/=y+ );v?`c]EВ&ؤt&G `=lP dȭ6oa~)6@ιɫ&ݒsgΑRܛP H"[D TTꣃ{Ym}'V]%4#- 25n>7,n"&c{''#VQ{wGaiC-ŷo -y-z52wٶv/vzM󝰻zgf'j.XVbXEH_΋sZ)]̚~_Wq,Ai%r_$I@ff瀳)5uv84XD׼Ì3JA/6^99? ZYuD TJ!4Jc2|!gдAAL(L>Cg433k ]S_iLVBڅ ^?O v6rETFC>NRa!j cy.tz'|BqK*RغT*zm ta97`9_÷ZqD&S $BE'I,5ڗkT1ΉÂaQnG5CiɗhBpT{e[7 mM=fbSoTUmSzdV }ƌX/A^70A-A4td!%>&; sz*00XjlMd&<2ˉSPhH_l bTX~RGu0]C6:l}J>K9C֤z܍z&ټnlfA7Xs^Ҟ+v/h٩}Q9Pzfu5)j^^)ĦJEپpّ6#:ں\-ba1 {X"G}PϫzRMԩCt% $!ɛt5S$ԫx2cacLl0E ԀuZ2=$IEGq=csݔ~;CuSh|Ԩk<#_Y;PO -thhH-nǸ!ĵ8俉IAeX&}I'aRnFsj*&N L$krfS\P1iiBҠ]& PN5E%˓ ;:l]3ۼyC?LD !9@frnIc.^mω|QV /vePI9vnԨ~bi0U;5[^%%G'f' Bw*OѿJ ވwchw==xfoMNƍ: 71THɳd5[z-8ՒjQl=YY#  ?<`LpW HY=RbRpc%vazz@Mtiѭ_ٓmԹ-zս=&aZFacPG8e԰a3YJQ<^p"U+*cUُO1![&q.9~~H@im@~*?2[8Ϳ?+U?#HuTP)_BWX;aBk"#&| 9HR#h_f.\T1VQ[#}(T l3y/}l_:SX K$̦l +tNHb2?'O\✚٫c=NN/qWhѪh؜՛fYCam Y%ϯȰxfA-2,C!~AG{sanG .L1bt'\J &6 +njCxRdD$B*_9k-Xm h8isw?2O/K=>h;SJ.\_ݹ+_+?}}wK7=+496$_1Hbi}ۗg6+#\y%#h΢λnͩXY^vc Z辄!~@>;Ӊˮe~f%&U-TKEψؖ^Hۖ?II$Xrh &5QW&ꘖ|:| ŀ6bLI B-9@Vi-jEmvH;ifafb@>L\! xꇴö vS#|NʾFSb4h0=l"-)sBy9:ͶiOܷĪ wC!^{%FܟG!裃>5l_;&i@#Є = xHO "4CZr~t aa nx gݠvO! 67݀. 72]Gݤ 5n%8 \ep&'!7vC,;ɍ)K C7q.767 &Tne׸q}'W0°~V_~J|qRX6W *Feh Cn&lnʼnqX'3IJ}o'UI4I$N(|N/rƠMY\ }LȦQ4oeH$5%L]A*!0$Rj'8(hr@y?5"7굄&Fqlgk5i2=Qk5kciY *+1DKy_5 :NC!QfLsAsIiX%GRM'90*$Z9(r%O8&ղK}d٦y9oY#OǵΟ8w?k$S.hg Z5OU81I r9.8.91h0D̩ԸEx-,W-,jWB(S[&F-[xi+ڽ . k 0c\5~;mT }m@oTtF8ґ:P:*Dx{Paj`& 4tK0@BpH (S +B0&\dh4f`dBOO%_aE+@Jwu$jHA9|҉lsc^d[G2,ozZ`VVLr|&JÊxXI;qD mCGLTPQjIvRZ\*W8]9ּR>*$P^m*mЅw_gaSds_O`iKǏ_]eWTvgm[`eC-W$N8 XRIm6e zSGs4R\/QT+m+Pl8gdP ΞQD_er/ՓoXt۾'gyNIM;VT+pWx9fS &a*:E='OvR$2{ eK1m&ˢ`xI_'[##p}Dw^C` d45XTJ*h[=C6OgCLymyW!1iN7ͼW-S92tJ c6xLaޟBݍ1kϵ`g=s#mc* _vv,=aYD#xյM|y%xeβqq''bR%nTC*mʯ%T*[\1;3(J8|[n%?*;JxQ @7-pT*A2]qTyb"Ɵ(+L%Z G*)+RkFISbFJU$)a{;)ث:W^TQfU%PVtO J%N*OЌ+J9RB% M%UB<_%Vˆz;XPڔZɅ\I3-JqJId EB5e}Q9ɇXԆ0]f~q]*-,4vZueWNombaJn4rd'=ᅫ~<|~S[W}>a8*aw  . ['`${ osÀ3)f (ZAQ+BVXAfUu2;)<{adcMg/o_lg]5o؁e]72fTXF(Y} ;\ÏY;{x-v(/;z;Kڱfc 0ɞc  pB#$Ìv)Xq MIe?d->;.رcnKvC;n|0 aDT۹j}>fI.გo\!m',3Sr-OVH{'ڣ;glٙLIek|^)2 >"eѪ j[קX:j$*>A-wi2!TϮ^9C3n%?ۣy(t"<-~@ -}Zi'$3*pl/JM` 0#a5>p= f(&ո ꥟*}~'zŤ'KH[Pc8Qߺt%L( LY,˄O(cPoz ws}IT\LJU+U,˟ITQ 4ݜ\07I6%Lrf|L&oLÚbd8yjˁn7hc&˶r▱ FLf0_h.-/5JJ!=uVWa߱G ۍ+=ˠ6 R!HcҰU1y yXl,LwM!O Xk, f̛ fPIΤ$'䚨+,𦶺snKNi`I#9wg<`;:<Ԁ BNp/@ &>aHH&2C oPyuE7;DۈXfl'ca;-ł7|SSr6eX_&Ig3=4ķv`a̸t`މo+KF<[yA2ߙux-&+KO ]##şwMx&M= [`n>#!2RfŅq#HvGB8rxk dɲ\3ٗ2gEz!OݿЯ4~@JS%(jj`a9gY"+ VAJA5ĬFL`juj ;$8#ן3F=)8₍l nOeɐnwI`1*#Q!dET"cHcg )1bĚDBN]OT=kuS8Cf$|Ohæfx rKeM&:}=rbhQRysQ^sCG][j@9sf>N1}RѐD"p} IZo[f[G\$W{u.!YW\ + N29!jvqDuE肙'iݝMN`?voڃ'3\l7ܰsg&7C.f; Qlv|͡ п&Q뚸!5%U:'=npNR*U KH\P*?zM.аB!ϏV<%yFGͱ%$YEqKLY|(P斋tNm6J "p & 'ʄѺۊZ[;Lh\-Mp` 9\'iԆHUY"ak$TE6Fd$"YIȯIjL5SQP@ DŽ`MZ YbknKA.36SS,ʤP&!87Wp p F7,r^>>&nnu {o~QxSH DPh {kieZQxx%yހwDySX|o/yy)^{(yf'\Ҽ^X { OPJh/// ?ҼA^/^ +_pk'?^m,Bh*/|?I 缰{{"$ҘOqXf 1ij&##4 >>BmQEDh"/?h}k\gUkZAdZm\Ђ-#˓_XH ;KgT̉+E_/*$nNkK1eNH>$ ^S#$?%:RixuզEx^5S6_C+x1 .ڽ$jMz`tٶ]{`lo=`a3w˥kt[ m8Rؖ8Hr*lfPJ111c8s zF#zO$&i|Դh36l9Q6i9kϾ&vH2ow fނNi Eqo)xw۹_saq\@^KI5ž5e;)ޚ3;<zKœjk46lA_妥_xg[QfV6hs\('lAď O:-}oC۳ \5H9LlCF?l _BES+A-.|?bp9|CN.+&Nf%}(T&D Dbj~D1nkڊΪaH jhQCD5m]jNU. `TRCi(Q5ǩ$0 y_IP[STR>5'51(#՜l 6t5ɹRr 8d/iݗ ,H>ߵ/XQDM?0pAޢe&H[nQ8lͰ.J~*sR)Hx(敼 .TcNm5?S&oy& S5K{B(^O媨VPBU*(C?7iM4P< $i.}|1 <]CG5>GxC/jQv/Y٣9y\#gaW+/w1DMBh4":,q͋UX56 Y7$IB S$*ԄhQ|ږZ &;$zy`5 ]A_~bN4#2 0PPI RZZӧa2@BE4qĥ3V17l[rM}eS?U٦JǹOA9;|2co&>1윸-'=D9vȉFxlɟO,, |yt)AL$8m@ib?edXsI ?b9)9r8,oX`2f`!E,pP"f_`u`vq,lhj- ^2UB1S-#E ֋5V7Gn֐]whiɽ8rdيc&z+2Zڒf.˞WhنmJע27%jVvv/'.XQ6P\S^qEֆ83%WީVs[g9:w^t϶zu7M7$0TE"~"Y@qXud9yZV#c*!)l&q|9INv|Sg!޸_Uzrޜʹ} I~03MjV5V A =E|4Oo dgӉ%HsfќU9f3:~~W:q^c2$2djb Q`tEs.11}Ȗ>OΫMZPf-h S7We 7%{ĵǞdzu/_Ǻ_Vow2["NࠒbRPfCp98a$Nb;@2p+(V`¢Kd0G$E'rY G|")Oi`DCC:WRwA:! I rH$uKPr:VK:'U KfS irz{H 0@JM _i\íaJ1EDZ"o~J6s o"H+ԐDHd~DIj0^t5SNY-cꐣ<5 ::QktDl%y>H?g[J]JaWRHؓ`ƍRx*Jt:5]ҝoQ_ /Aw/&wߏN_5/W~s.tGyqƴix}K.:vѻ֨(0l[#`bXʇ;tj++pmU{nf61eXIE&0YMV%l-(!#%Pt(^3JXX1F`c-pҫ2 s K:֥%iax0jfJ 7ߒ:*S_г=^Sy&k뷱%msWƙ:k;uez+l@%}HOI# 6/Ur%ϻcua],GpܺR.7.vƿk̜ך3{킌%*Ǧ|Pt#[TQ.;ٚݥllH t\dgjo:_O~gDݟ_Ҭ7d c& fiPKg8HK&9?RI =o}ZN4-'^DV}_z>鷛~[w/rMKw! 'åi.~mX:y"nd.=er3-x+}a0}Ҕ!q]He40,&am eؗEn_}~  %kL&wyP"[qAyYuKDDvͻ-'#_*t>k4&_7WF|'6)Cqj,a$=qamI'C\n>%gQR3=t`օ`\vC?@wQ{״twzn^ \GðV^ԇ~ԍ:QD6VSm˧%gR U 妡hga@g;}n2Tf^n ~)t+mGi;O˯a9.D)} lHuSLݹˤ,J17֒ߍYOS2(AvKk)R Z*zaPG;hyg!WKi~}7nT)}P%%P]i<韛܈yu[ w ҙ'c4ʝ64n zY=#;롍3e1nF=Y)wHz~oz-vJmcMC3c#N)ZnluoQ]=x7q@Z5ؾUYHw z56_qk,|Wx?M?V?._x%"^._^Rk2iK,? cxmlG)W_ON #ҥsҗҎNt%ys'}h`о _y ѱ s4>3x `ӥOOؓċN<=zO?5y;~,Z} zp8oޡ(CM"{{=wp 9c/ċ4=@&'vî;ڂޞY֞@5k-Zh[h^3dY4dky'\6%%_Y<s bM5Tl 9~ObJmՁVb@jՖj;V.jj/j'RvEK8dșNg9䒪Qyu(M^~ Wf/mmh@?cFeW@(΁bBÀͦ`42 8a`NA>+ix`%-Az"^IП ?@D|` endstream endobj 103 0 obj 20160 endobj 104 0 obj <> endobj 105 0 obj <> stream x]ˎ0E|˞E "<:RФ8i B뙑f`Ueb{~)~c{ K~n>!?K?dJ].Ik3eE{|ܖp= qʊmӺOKV|0%=}>5 K^fuw|mo52xS?kyVTi.ܦ s3\B*:_uwӹhbhY겎a \`Gv`Oa/y^+^s\b6 ޑ%>{SdCNQW_H 7nۃoŇV_?ZSߡEN'a[Kn賦NZOM/>GM wRj[We?no05hcoV~_&}?X%/1/CKN.K+ץF~8ZO>Z[Ե_j?.4FW'sґS4f77 endstream endobj 106 0 obj <> endobj 107 0 obj <> stream xVog>4qҤMp#8kFEYIq^\;[b_lwv&D lf P'4DF~(EL#BLU$^&_А`)%s]\Zѡ™V ~@3UxU"_.JwNo 1+-uԼ׵dwHĶo^D'_^q}m_hwq[ҮG7ЦVK|wy̲Yv{ͼZrW?8&A?v8|^ 7!8(4a 5~ ߃/7 mxyFn@sG𬫍H}&.UL ȑ # k 2K92R,W, 2I9~LQ~⿛UjJ\H0K9L f/-.`RTxjR {H/$09ʔI'՚^()MXzF<D; gEsv4uyfLMk\mBk&t2¨8:7ЧEdzr+ӭX͂][@Zneƒ#) ELkњq _oC;j|Kp# 6Q2TVy#xCy$<:Jb  *?'Ty Gy'N@a,3A( ֏T8<SgYLHwCu/#NB;9}?#CmGmq!o] x\CLiSaLb6W^$'Nd$s$5 A:R,Ֆ7EQ8|j#06 ݢZhrLD'm|h|ARы%0|A8:#eTr/ r"_E&EZUyU[6edWn`>_A|F` a0BUXZ;8x^ "/TS_h;>ogju endstream endobj 108 0 obj 1964 endobj 109 0 obj <> endobj 110 0 obj <> stream x]Pn {L6Q{|Cu.R  I[Ќvf4ԝ;g^`D\5€u`NwV~=8ymI8wnM;͖7صg5M<5+TLJ08Rγ /jF^\ئ@?D4F&dMUIh.Й1KER֤1cm[2꜖i zju{Cv rG endstream endobj 111 0 obj <> endobj 112 0 obj <> stream x9kTיߝ=x͌x C $a 10M 2e$8M֤mꄄmmOnnM`'-I{t$mړ#n6a׻MrN71_Is=g숙+_@&, \iV cGk@"zdnbpeԉ#{]oȨ;s2_}Gݎ6M"2 >xt]GM͎y< o ;m.W2gӑ_!Xe"mHHs󑹯_^Be!^)ΰNo0K9Sw y3 x=q>)>7n˜zJbCbb< *p_"\ )%ë< yEQ?"fW{8|~.{ !,⸗5Oc2BX& J O8by\: ,i[ػswa&+sKA'wY||o`JhPk F_znMe0?`0v2riC2;ZDá@_`ޞ]yWou95ʊ2*Mge z2jJǨV\堸FB¨*#zU%}(yI_RwEr49jd"Ϸ+*Bx]u ޣ\d!bϟlU2*ՎKvަE5`BM[!fͿccVeq?oXÎnW5i&U}jLQ:'Ԭ-ݿ*Q{2>R0.SɮV)j#jWjqzIT]KoNGYzJ8Eїo;0KKܱ4^M,VdQYZ\c/Z'ﳨ$ّl@@He;0RϫX[M? cj҉߷È$.ay*3J9k!Y\QU0=Вʕw+~}au0Q ET,Ve)$75YʪÂZ*`P%QCu Paʖ4Chd>5j=kGNȿRB((ڮOu)sYiO? i*)5ܦXJKuȲi=OJl:n¹mXWUcC+0-4PEΪ2mӿ?=HAq(!K j,7! ܈רT[›Z%#)9_gTG˩kӚhb&/G l950jiP6Yl9HcЌF̧5/2Lʪ/DFãE9 -\ ^], X`v˵U;5 u{-/5 zޭ-avE~JG;Z$m%{|I 4i\ANʆ3ŬuE!='D<~3:mux y'd+4*CH""FM`QrAV h4&*4i\h,Obq4?w O.\(y0L5]J+{)ݛ)݀Ar%ѯ{$ ixݽ< +,%(A_NyBTn5Yy|zcR7_n瞧 31{;$Zz Ȁț;h̯d|=Sm'@ID'IpAȀhMBh2&$xR<-&DNlZ_hsrpbۛ]75W27W9Z#gpF70LFh*R̟A-9d_Ҍ^2ot!:cK?jĞd[Ϊ,omwwl֠ii޽]RQ_aJظ[xw4Wc2,ELzua5Slkm]fw+<~gAy .^dk3%/\,a]%ޒ@ [.>ܼ\]-PVĴ~`I=k=Ƭ?kтm.v`b)hOZ;2BJLey 񸛙fҰAYu TWi>m>g֛dsfm:Hwv g[´`}ErWK}]QwrQ\'q[pOqpڷ .}9agي@=WWY9/C׷nRBJWx cpUS 4tso±7zO7 ̍?]񇏾hduB_q mŝ&S V~pN5/$lYl,nڦT>ƃJ10et98XXfvM;%^=aYxqO\)|%y(i9[=ufIxW\%{j=V>˄:XuFgsBZȋ-S<|鹲#kv`J|:;%)l?9!K*ZNʓG2mL\3Z75ӊw;wM\=slz~Kr?)Sߖhf_NFz捽v'~Lg^vNCFbKȣW Kdf>Hʷtd@ BEdl8ҠO1ʀBܞ9C)X<|=%P)fr0ORpWW~vϤ,%N<`脣_1 )@ [e)^69>uPľ )op)6#A]w,gAݗRpLK<ܡe܉d\Uy 2.w5r̘Sn5<EGƝrowe;WGȳĠ9NTt%6!a(}YwU9ܻ, _qX<2< :p<23#ѱF(<ĩ]ƣct ffS##p<Ls;\[oN slv~x$8'SL _FDoj o*)S#"#qtmn~hd,p%JڋLVReڸyLBd n<8BBeF.D B0RNZ` ?5bw5]*ًZGk-0p"5ɇte#0yixf{{Q6DQ~Afn+Sf7rGQ9c35\Y?Ok"gB#턺iqޟ/k2f;)lDP4i,h3{hFlӹ$-"bÁK{#M^LLdm{,I`^#~U~.s_%C?to\-$&HO*( T-lhBZ},WWg!׈qvc3+lJ̾ģnI}$!.x/./߅܃8s;||žHH_7TJ{\,`IHY,#+|LUH﯐>,-3gO.'9~rw[zC鄴s9u{"p=6+Is4Y"OQI4B( !|uIwgtTn<}"HHx8Zt,K2=L/hKJ%c&> Uf8 0$$Ɂ.o/yhgm,@=xD7it! $ם3d"C0stR/ѷ "-2g$+N 0+^!Ic! DGVə޳jH *G-ҧGB+|teh-Q:Z<ܣ#"bJ.B,nO^bMr 5^̞dFCb,rR\̀ƏSXCZifmaSNI^(Ǟx6 endstream endobj 113 0 obj 5608 endobj 114 0 obj <> endobj 115 0 obj <> stream x]MO  aEwkĬn҃0${X5yf}afȩ{[C6bW/0i*[!;3ڶE=֖7{PvD^̈́wS~u f0S9V0w{3w*u'`㪴" ^ PK)0OᣲJJk#&mwć?$>h%O7ͽ\M]L}46~K| endstream endobj 116 0 obj <> endobj 117 0 obj <> stream xz tS׵+ɒlYueٖmْmAƒG]?2aK$!D.lؼc Q vytx`h{qXq2,`9cṱX~6O [XyĽׅeq|`/[ Q MNLϼA"''iXqzFPʔ\T5Z>`4,֔4hOwddf9sr]yÏ:I# DVJ>2b$VYX(;X  <LFM$o37'e>Mٳ|jȔw5r3EWp_{.,2 FKXɗPGއ?' !:."^#G8C sB´_#tB _CfcL?^&7#Դy/Yr|%Qz'.|_B  !'ʾMҗ m7@lANɛd A"}"9tuA $PjYټ.X[S]<௬(/[[vfef8$^īq L9 $Ya>Q_ʎ?,bU>a_&3=G>3tb9)kb8=]qt,|Tǂݎ#ڤ1 bm8}t;RV;yR pc)] @kDϖ sCPkWmnkk5R ˪riJqN睞;#]!ڮ07cڹ=a+ ~|8稩 جMmidI :8wvps@FBDbpn`~azsW&k$ԅ^GaYluMWfa_jf@r Mvd=»[e ;LYS'kٽr}x53H»ף+s3 ̆UU:KR]'!9r?fTymd8!#ᾇ1o!vRTjHTϨ@6NUa|/#A":#]_@PĊiOLJ`<0鹥Ԕ9[fۜtӾۧk;K%yפo#믵"~;Pf~e@l-vZL\(FѦW*6jcx#޶" eL-דKss3tS*R (K >ەsQ(`9^0j(:qޢJ/ܢ% 廞;LUVWvN/k4P>͉nm]QiP􅭵PrjOZxkf4Z[hKjs':wtW&;i*oyf^Is5mG?H1P*xMx򜖷~OԁpxpZޭ4ZâCx k<5={_NE^ $) +^)I2Ⅲf`4Xψ]TxAfQ Ԅ+FC9<+?/ar&`U@-5@q9Uˆ ZG%,*zD_d9#DJ{ݹ"Enϟ.C!>{"RUE_ýІHS|2X(i:fJ3זi)T/x$5Gu)EIVPygCel+rAKVQ8Yts.Rj=i//Жd^RQ[p(H' ^%! TT䠤ɔAff WSuuQ La:C}ʌ_5E3s[ ѽb^ŘɅFL5ҮLQSTYN35h[s;0pYS֒t[qVb?Mgr#ELdgmVR]|J,jme/)k)2iem<ܚUc=$Sᢖ%4Qknr72>#:^"jMX%jզSR9 XCVj&ERp0j %RG)qIe&];;;ǾAkB!YY[oV,k}㑹{Յ G wkyuG Ots?m=ETړ3hH" Iٞâ햤tQ` c+h,F.hjJvm5|Z݂2S/ G6}x ݗ#~TT0mNhFrCI]QH33{/"cbġǍ4gg0D͉yTظB*_覾iN`{ wSIXɟ).5mx;`1D,*bti_={s ݟD#KExF=AYRU*&(M!W4)qʳJP8;:qEG)<+Ih逢 DsFΏ&u- sV^wkUݓstJ$9>]h~(?Hϵ1>j%?H(<> _(숅^[S.Dq^/<EDL"G.&R0&_uD#p+-!.Q/Ό22tw6zOEGq>b"7UȅFg]P5Oc]:yp! 8*Q4`MprpHFQ8ݿI 87,}еCWpGq,a!gs=|iy/ǡbYz}(IR"F +Bы\{;!di@CzDmjG Y(7q& 7$m $g!^/=}ٝw>t۸k|[]$C-HoVd55x''28 !+JM8buF(KD!i&d2JZ$F(iiu):әc2Q6^H34GYfV.XYe"EW ,8hY f+)`$4!RXbr2'PoJ $74zc|}0r%ڟTՍ*wy}U$Eu@)8fdI z u猗lfL ̔:QYJKHh>s .I<ɍ!kbu;{]/Y|ז-=>+MۅVwqmO}g/~, =>X^{ LqpY,L9༆40.%&KdyNE|FސP>}^zO,BhVFTNYk23d^ Tz̽&5nͬb?&_TVoUjSn!g}z yEDw1E0nHtcjLO]!DhH"* 7>\HM|`&?}g*gC>Όk{MEc%]㕯nKBvuAim~6ޖWֶv/Ykq-I+jVOœꀓPrDJٮ"B{9U*vTU鳪L o[~Fzx}ip@zI  p\_Ԃ0]v즷y\&ՁezQF~>8 e؆QzI(Q\e:&IѬH+LyPEH6t%E,,C  fwolM@GbO+:Qޅ(~r8,2,d|"SSdᨁ+ ݠ4s].xrB9vY9X,4kRZrr'rr܂s@&X i19wJ;ںJ&:]P @y-o,2qpv͝iE<_?eܞFOJq{դ"z՝Xweí=G}U[5Y X YK-Z=mvMIVe*7VecŘzS/ $ $.+˻rV1^LYSɕ,IIw1bYܳʅwg&~W ?=^A+cNrp散/pmVgT$3p,&-l46z!I!H/&ޘ1wykR ȇ pu[0ǚrYJk>x:vs20P=-bLo!Yd)iG`40eN=0N@ӳvkr^dCh?u?{=JY %h6; £T,6BY,Lyliqe:gu_1Φ}=3V}AmXl(7{G*UNGet<'7se^+a@]&[\,u` {"A)F>W&@Iw(%lNkr2XDj EB{>d8+z\=BKgU]tg;K"pYǺ1re..n]CBfC&M2YhϤ V3 ^<#z)iVJQQf}L'l{ hR]GoB79RK-vKiSYҐo8Ý,5yQ@sԱ 2䦷c<ȧ 28RZcȇqN& dLz! {;A1=:PG"/D^z@܋~571 G."4c @V1PјޓN=Vv'%ݛĹʒ8!ɔD[d} \/k)+`YF#h.z CXF#mI18Mh9,FHzNx=86!,JsWS7<}yKqhIY{Iշ49OEƆBhUȇߟ{v<==vxVGWϘЦ䓞qB [~,x? } (ZJb"+z /fYܫ15.#%Kvt j0vKsXY\Y&9{iM}\L[׼Y9:ypJvo䭍N1{Y<y" JzDuS- =!ȴ}q3ܘK]$zNf\|_v@R'رsѯG^@7~{"_|&hvmbf,o*J̏S4DkO'p5U ǰ@jF2p'I1tZS܃>n-}{wY8s9 R^ދ2WH=>yd­TAiN}B%BeC>*Ubwq^R\A~jHH=~-4~fFsYN5b;r.Qo#(¹DcHUad TL`t 扑<!_2GO`9|7+8Bc 18L1XC*i |NӞ $K(1#\ $,k1XFWb|] ͿH`Y*1XM ]18#<5dScFg`6<$ nq͢aZ><W4Tն-hhY)M𖁩MW''&6-OV OMBww'=XO O]lʱqC33q}`T98<53'fFۦƦj뻩>3}Xl\r-XAfvL OmݻGgl^O#ۤ)G&mE64?2H~ Ԇehfˆ/c/7Bf70-9Xs"8rҁp aoǤx`;Lslº 2ǯa-c[6 z{놤"ZM?+^ogzBďM?skb4ˌ4w4w'hzF3jRXW񌢟rt GcވjJ`Hi\ )ʉ.a]ZYdJI "}c%h ?73)qX rsEB0 maQ{2QM|<.b?DZ'JIO ݇%j ǐc݈؆XݧY\;{A>H]?m 6K}O_ܧ;W!rN!(Bmr!N ?r;F^z!;{Og=llيw:Uu{l~zco!9wm`?Jm@r)eԓ6Ixd%K/d[sQI #x!| O >DͶ<R/JZއ^:.ᵀ %`JuOГO{|`N NCj6?Ĺ'.?NDIuc dq㓏GͶ_:d =Jw>pa`2p ‹CHY~ T=pm"L:s!!ؽ , h,^HS}76fNA=ڃtP6 ԽN?>}kKͳ^^zB9mBe}Y0ܒg>m6m5JI`>g=x}NXR@A06,M5B IoRuPzeǫ/dMJu [<Xz6CQB\'_u΃"`6-U^4`mEmm&9ٶ;٤)K 4 A_ROf[]`g A>ei.2uA۩+vR PD:mZO;ZE;ݯ=]XwIaB`$ށ.WӼ|)Z{™h Ξ5]{>R.j v70`7fR==3=%}`qME\3RմTRa333۶mV ۰ !':i&TѴYf%fb㥵45?Ϳm endstream endobj 118 0 obj 10111 endobj 119 0 obj <> endobj 120 0 obj <> stream x]͎0y /Q⛿ Eb BbhD&,xܓR=&m[[yCpzgN2Ċ~YW_9Ic-ziIqﶄy}Jүapa=>ϿdIӘcTSχ!n9F|c/?,/%bWW0+8X[0 ҿ/o_ip/ԁ99#+B_YU^qBR_}_BYc93GS_ILef~j endstream endobj 121 0 obj <> endobj 122 0 obj <> stream x{ X[י9ޫ}$!$}e`#0؀F,v$6qY4gkM^i&e^g6N4qIX\ o]y {t b0ehot !BX?mZC"5oiIw{˻RBmo3#T0GxʳPڰeꖏiʛ7 k>[Ɵe~ TeЖpM2 (#$�m_C-a"տA@i*K#yK-lmD@/}7qd8Ӫu4!+4/(2#>zFZբf˜ֶ|NnO`DYXЙDl Dm QGIvlu0" [!5z/%^ pA9@4 n!d)*<洔MX|J}Ps!S hi$Ә{tVݪ6K4 =wck͌֜AB\O>0IHFEd&G GDuDg&eX콨JAǥx\"7rbMg-OqI62L IViz)XR:1BZ?eyHJd1Yg08%0Wolv%JWgng^0Qw|u;ѝk{~1Y=,F蛂w. ̘ #;jgk{YiI{HI@^+gCA fϤ FGKqvdkfq9:a uJ*}\/q\[um{C"- x\"c/.+7h-fC9(yqil$.1^\GjTإ MfZhd$iMKycLŝUvYEyM?x;?-ٙs|oee2SygYIw7.3cqMI 9_;- tJ>kݫڻB۹OMB[Sfwf(i+^U1)U`NjNKIYdX6z|L$TJo b"z)(b8!:Z)q8Ju; B,YSwk͛Zvf!|{dX_&dkr6*otC{[+\'rRe2e9QiJi@F H\[ޠG୊v!4- L -tqF&4fLMy!͔7k&GRJ>qls`NzBuGI hER]m+ALl>;'ox$42/fJWnkҬ)y8:1Zq5+xvYJtR_'&/eB)^9s+>I+#i&t+:Vԇb~ៅΏ29$PTdWj)C,f%/~d$%RbClib1Pb`aM% Q+Sa3DK?_j+4ާҽ͉Vm8淹fG}B%a#2c-<$ kxy2NfI& IHx+UJ,T*-%KVLp[Bf{\َxXCjܣ;d2C:+%;YJRZ4 ZłFpџufg+Gp)5EYdj*p&$'() ])Wr)ð5&")+,DNN )2sQp8l QCڼ;NOyiJ̹dK[]U^Vn}o3=ֱ%]w;ĪCef[uvh/M:Rݸ}f`nUAE+-+YQԝxEt%s+ xe3seHL蚛q!^tEh [};\p7>m[ɗǎwuG|q㖢ZԁqrٝȎNˌ,Ǖvl}"4C[ ]%$=Zu]ZݛX9i[J86enXSWNl^7NqV2ٯ 0 `.PR*m=m6-ѝ[ؙD qŀހ.E},|%Wx G9CYUg0d$ב=X /Iu K4MYwn{cURZˊ[YWTlSdP9Wk޶4q2s]Ӓ5 3f[DaMY4)؇fH͘$%TH{]Ƅ'n1~.ŹQ$x/_˙umW/ܜ5;D&52vW r!$B! yyȅn脎YQĮ\NK&zˣol_و N/4%%s?E؇9-~Aw&A9;2ԥ駟bg猖頭m`rѓBA%/}Etf].c6GlY~ETF jB1A00CK]J샩K*+, 7D έQ`V' uE9@p.'mX$ۍ(͡\ U9w; 'Һ^w׻ꅽ? }liڒ֡]̝?:w/[WV7"1y)O*P_۔tbr88򢈰o)m&UxnoBmM55d[r27bBVY))ŇAp^n.F9\/-;*#~d\YyyYfr (H;a0-Zܬ1,:n2ݽǿ]q_S5]χڔxVl 567\>'zn>TVtҶpcpveNn׎(KV.+i+5ʮQ/ѸC eb_LJþidd1y>3( {^r JrdZc oրB_bh ȔG5_koqǿYu,bt%PAa)T}+&'nu9đ`KZEsqnn'CC=2xVg(Xt&t~m`,<- 9-hLh.*ړ3l7uΫ K MkSHߓ+&ªh,Γ3Ԓ?=t|S}ʫ}<&wg(=xe@a#,ͫ#*[@M: )i` 3hZC(O#i4)yAnI ,ZRvRҙ4;y*]bNq:ܠ-+/+_̴2َ Lϵ/:F:ƪyr)F ^<#O?Q)31!|OQyiA]uk%#s䥎"Ӿ,?_/lĔEvd7zTaVjSSj\ĄsɬWcG5DImW.#059%Q$5G[4  -! 78įh ij7p,1?n>9I31ܠK$|d}pz^uuzI^>_wl9ѭ*`h9YƵBFwt](hY[֙vˊWܵdd(<;kZǿcp~7N_ > >Ai1e2Y]肇2<;T:4.Mt^syysc_~K1ݟ "S-BA b¥V^FG2bW" waZM&" FV\"1,Fb{~79z*k]6\xK|cR9.ņ)zчkލ6iAe0gPh)OӮ6-,Jx :fy6~%Q|A[IL?byQ6²,OI7i,Dҥ$6) %c,΋:*<΁pܐӊmp1LI.ba^7onyq{uvUDߏ^[{\ghneݭ۵Wc0؏n ]ˉtD $@. 3%W2&-a$$F n:MyW F cK?~?Pk]hPJ%k%'=" i{CwXbfNl~;{5v.̖|}qEXCHbY)_a)D"EnP`;/A嚿\)AyihjHV0 )jNM6n(ǎ!9;y|!DTW#$quVǙWB ǣE=a0dF>y䠄MIL!f5ISY1ح8 sӕZ9=E7\XJ;qeS뻌ƺƦϡR|} ~W۴dDFP 1B,HeL.*Xs^Vt9+Ъ:Tc*ꤊT/UK+R Lc*T|RЊ:뭆؋ƓF˜e2M b r:V<2?0ք+R,I-_QC%eѧ*W7+i*͍}_j!a'# y6*&S4̙ i>3 ^[eNI%$G 50۫<-Gm ijszzקuezz7z5;а5'u$3'+֦ZY0Ylb/2)5yd0i fSPwI+èi>=ӚޗNzRV2I A~U4ڇCd#1Cqĸ8kd}DM { #Dzǹeazvjj9b‚I?d×xf>п:dRPoܟIFrw2iεremv;yR:8J$)_h.{}HA/)zrkRzu,hl]FeU9]ܮļc*%PFjD~J_p(c}nEWVz5cH=9<#hoc3 11$`r%<3k]Nx=%DK9npQ[JE@.EMs^J{ߏJҨUU暿Y0vs׺,Zԉ#ٗC- !dGl&EPO6F8kp gQy4 4*aTw}^ (xqr5*rd$=83G+i504iE> f%{s(*_W:e^kS[&+zjk7,uTj {ӒV+Қ&Wt5[,cMxgݛkk7ݽeDjCM+JBݵ*VQڽx\]56[M\Pu嵂|:$/m=rХ蒀,ا[#> 5iII+>ϒG@A8/7/7H$('&d0ޑ;rsHNn-eR+p-ٻ׎yh%v7oRXuOֶS{_Y>Ց12~Jx3?liy+|N‰ٮ]?=Of**f~?dl uJtFoa1=&x6N "22\g98)"Rd wK$Q.o q(G,(r^9Gcjc pezA LLQcpϟKv^)[&$׿OD'㼷I|6D& W~w *xnT"Q1G*^EeѯBI3.7OQfDA TRN7[|nO3s}u.O?8k_Y@Ӓ}RiS&" vٞt (&KGY救12"hB fgd1YYQF]o^=i#؋E \,v מ:щJcǞ얡_t^.=q[u+CB${ x[Q܁w "jq,>R. VSv#n(FAj^ k=Lf--K\m 9,3ɟXT)嫪/gտh|.ޣ_V7{V^Ī$^6lߴ &DWL uCiV^ FZ(()mq>0"K~!KNZ+rqX {Xy dV1X֠:ꘕC7'q6 +9)M݀k.D^m8KBſBsy Eh ?71.1,Ry=QPs pV{C"S M_15.ϘlaJYcw?:q>x.k׋84QݼŽ>/׎(jC/|a/9՗g+5x̦K..'/aӥU6]bϚ>#O} [֚ ǿ񙕿o|I.̯]х_^` 2|':{pez>Uϯk?y^E{.p'JYqiLYi6ϒz-֢bek.p0/pxqfޟɻ_}ʹ`w7cҋ|}I&>{ҽU V r]c|u}QQk9jLYqîÌpOo`%lVp1@ d ;a]Rc>x|`oy}k˸Ļ`a\2o•=)cHAh,=mvD@0'ͫ}EUgBL[c˦gp 6.5 Hc` &΅N"tVN{m>90MB?^(oj#3>Tlam_!xaYjwkY֥Ўij?.h^e@$y|Trm^VE}9 _{ #} 5EF}mfO%ɩɩi'80Ω)x.\`Zɩx ҔsZ;''ŁX`z4* rNO0.#13}''ŕ5fR\dl#5/m endstream endobj 123 0 obj 12216 endobj 124 0 obj <> endobj 125 0 obj <> stream x]n0E .E # ^ dvԔ@ }x2-Ѕtf07ޏKuuީ;>F cnX{_wӴZexw]]=e00z96EY۪s޺{wqT=x=.X/>;e䬩O]B.[EV]9?wWO.TSȆ ¦?+ܐ7'r~vpӀ_Ra3xKW x|u!lo%NOїN[0i8k5<3 ӿF/%5Jӿw%oooc?fn_0- +п8KbH-пx8ߊ8J-ɡy4&nH0slopfT( endstream endobj 126 0 obj <> endobj 127 0 obj <> stream xݼ tSǵ0<{9da[ٖd|~` @IH &"inon&mHz i4Iss&)Onۀoϑl M{}ZZљǞ={{c#H'Ql @yYy̱kY@]6nc?mز•e݄ )ywg;(؞c]ZBO8v[O Ckzfy }cmm{}.,D5Nrjm6%f=L.\FD*:I^GнX6E#oj(9FVb{o z\{"L7y|Ov2Ag]?~\i~R[B_t!<@#^nLh(y)>\d)6'FqUv,mnj\xQuښ*sfWUV*+-) 23]iN{Bl2FNxɯu 骯/`yWPt`f[s /@*aHe̎*RUu9oָ'{k\%5XMj&3N'p&8 6Ov #|>}A>97`Ҁ`+p瀚ٵG(En\FmOotv/]5j j*J#q?=q 3YݝYzW;1+h j9_L]5#8ץ\)d?#,CNL\DDω.5q$*j"P&MK{lA}Asw?TD[m^>Gjsi阆i{@:l{N(d5fἃ%;#HYkiBi6OZjO0QAۜݡ:lV76šLՌïK6 (w!U?8 yaѷL(=EO7hF_ \fȪhiWDIH쨝 pOԅ#^RL:j4UfD{ڠ֋+m *(W{_hȡ ؝S1H緶7;gE W0t|Fиma48傺 ڸ4cÇ ׼*j3tj)`#HF0QWc l:ͯƦaY3p?1~@MeѨE l;]}W#41\0CyDV7n`8z:ØndnNdP`1s5L0B/6YzvzpVEak- ׂ WK{  Q;{(poKgI{[ۏRuIǺj)ee,0-ŌNTWky@ͯ9D-MYsepJ)y䳭q"!G5s&*w \Xy5+kXgHPYBWІ[K qWi#UG9Irc+>ոUV8-N:BX_hMnED 5a1QO%X)ґ&fĶbqD(Nk8&T_U]ͿT!yq.$A+ϡ-'>0CͿ}>xt }vlc3Ϗm ^E]Hxo$)dIbXzb괒,F[vzn~Eb3x>=h$MQ1f }j/ҝuIxyvirrV+KBpi}Q Q9ޚ[TXm+UԕGGUj]s]7'/1weA q_@ yPRT MUڎGL/`{q]-qZDnGP0.  l,j>#.$LÙvEgBxGPAdݐ%|l^$ J&⢮2h@}3d3 1w6#aoŨN4cML:ru%xG̿RǕfVIWN"nQ\oK3 *έweR@CnAhz%Q%"m ('h -;q,^RKZow nt@9u&SO2$ӝ湍Vh4Ć͗pnyK2@"!BI3u%s(o^|9`ih$րhH4i[*Y=aówpҒ[RmZx✻0y`srEBr}?ظr̛Mگ6~ޥi:|2g'3]b-> L:m<1eJ33S 5dG~]Ȱ]JA^/snl2\ "=( yG A"y_Fn CY]L_?`t e3((V;0 H)C2Nwh 9:}a#&#Nʺp?b4RCctC!nJEF ^!O 4} F4rWemOd&mLY)y̸zL!Fy!S#>e#ՓJS5v.,W{хf(r ßgZ8. mT Y)xEf4pIiFN˹B.+3KO؝/ŗbQZcu1&Ӑd$|ssMo25QQQ_`7̻DnKUc-RR+fynɺ흹E%k~nKdʍRxE bYd?1uE@5 ȢRK;s6NR]J` }wLWYv J'+dGjbvvA-}zͬ?_<;}vZ\^KnQ]ƺM̪1^H)z; V{P|KxCeR|8M"=$E]n"\a NgE^0Vh]a8CA"D~̙_q5 /SWG234Nh2)\ {/Z:NBq&3*WPډvn{ߚxg۶t)szmo=Ҳ3wly@k#osS=uuGzTz@+^tsC)8ࢅFu:tF Y`O,ѷB]WkZ]澖O Զ~=UIIc1v; }9%L9GD 7Ę`;h9e rOQF4Z+-DŽJs 6/oQI͉ BW#t1ܵ=} I&3@,fnKgAj FP*u:ǣC 3ق02jWA-t|Q^&"ayWC'COާwsed>z`]qMNQƻ֚'ܹun{-C zGx]!>;C 4paB ; aklLE hET}("hw`i9WPh GtppYu*i%^d1xN, JA2;gNzC>*U^}v?RȑN\dVb/L`S@MoZbfg,WKĤ,Hu'[(huΘT`w4Pt3&"FǑeO@  :g_OJ))ѹRh^]4̄b,JCMkauӪDIJBV (7EҨ"{)~BNo.u%K[53QTȻ>8˹Es7㽝2.(oW;;[>iD[%/AT,Q aD^iLK!$Rě$X+b7gEJ0&j $yMWq+!+|(w$zT$ewTZ- JY`Vi(}*џ1xtTKYD{8K5͔ N?1x@HpLND20Dc$°!CR&avb#d`#]?͟9^  Bl-uLym&"ܭrN ,vV71)dx@o@1vZ}ફ̤\fE+^B;o}t):IM3< ̂dl Dp.&1aLܨgg)!" 5&4ոR9u;yٽzvjs}^/[S# 84G7;}d][ZJӶ=WT.L rW6xuև߼}o[q#ԣo}$@Ew);cYgp}z>/bvlΦlpO/[wsOs! \w.EGlnVAJ:(x+;y3{iedN1_Pvy+ێ{V럣r純xZfέٯT=;mjK|9 f7<0\ UK-w6gJlEEx)~mg,o[b56~WxwBy TP&.@v. 0,*Qan:ɋAlfA;dL7x;ITO5i]l1'zXNPusl',P7-»喣uw0ȎJeMEVɳlO_Ig> ߅:wh{=MϦ0FJ%2pXqo-el=cQfN=s.t.},ޜ.'Ѧ$T7jhbFNf뻆j$?<-б$7Lzt_CZĆE?uV (8oJx3V-)ord{trwlmX864}:PBq%,_+gס2%E7L7L_u Fh1JTI:-^7-2d7{=^y&}օVt~ms}|{eUgO꒵Zsh܏Tڌj\K/NۉH2RDr:Ac"഼0p:~ΫT}t1=(w%.DCch Z=:ąCDv͑sټ]:С5$b`jy"pkлp_h?-{!$[LܧJܴ/ /]ZDǩj\SոXP_̇tXwN/S-޽>]%~?S`p^l5oun=hk\Rk7[¿Z혝j t<ƖGӘ5ʗݣ$fg7+5. ԭ~LV#;3U'CQWٔ,nY<1tj夅~hY`22͓!Q ymAsdzFaȰUc&׮d 02W.W2w,GQp'gDL2ÙxLps?.KSc.Ƚ2mTbƦ&eh\,c2cr& zcc;27\!Stx J!FOjyj5»_t9 aO.̼ѷIx ̛\녫 7hOZwYl]u4 [ޙ&MefҌM)*DQ~G /hJ2DMF1:ZxUD@X)-ʏvNq튲x/USO0PY]ꫛU彽3;Af\KFH$Qh bغm۸ NytTQ(Fg}\6/rZvW$rNS OR0s4!g{pT-^:w@<u*߾kq á9U'G:E Bq\ljn&3Z[Cr%F1,ySVyβ'7R-qZvqʺBAa9Mo]~vB{J1us%zПy$]/ª%_[xqI6|C/?eXПz~v:pq5*Cz؎na@U#I :Օ vW2}aY/:uHDh_}ٽ>ñ>~Yp<λ7(۵Fz |? Ư/Ju^!LZ>"';F@ 8З딣Jnq=Op"☸SFWŭ"mA+"#^""Lĉ:M[^(\kϊ+D&+$׮2TwD+E0x=X."M:GWT#".~kU,`;ESVH+iOī"=+Dx\ DZM{EeuQ!ODg `,"L@g"GD"%G.ܼVMAM&K 7r5Cyoq3WrBP9"5/XK H$ɟSaWǑUZѬMsVxgqZNGv{"O GB0C"зZϽˡ?="vUNfqE,E/{qb)l 1mAʇlHQ22PT( QqWxl`mԖwzRARC.fᨎ0Bj*+]aVJ[ʴznŕ4T> l~uoIXcD=nk}ͯlYNJ|J0jR ʳ*]9^I"1GvFW.z5ML--_.{Y)|wۈzkF ?Rw EY |.?aۣIY[Bc`d/nYk?yX.\@ᜰ'YXx*SfdJ` +d6(M Wad*nu CNj GSkC?dj+<]1Yޔwmvr۾?o-8yUqmB+4(%⮠)&pplA8d;m㵝& \LihX 'a#ǔȥ;C꽧m#FJt~rdGq _{cGKVβ+kO>ΞdFT)1qHWՋ bg6}yaJ'I;yvgX=dQ|뵷I3 YzbhHV@`)Pʠ35ZX7r׏T`g C|0QPt-VZA;g _6Ya#յK0?!s-ĭ>4Cw3vL's\{ '4%6i8.=/r-|8B| ;>걽 &3_=39',!XxC_`81 "mi|4_0fm> N8NLD(JeW g192˫jfpz>-滓bH3ޠ7mFܲZ*07 vƒe*&k XǭaXYO[y=P+[vp\;7Z-"M}xR9ㄙ+ؐUqBshC,~v~~f{WP>/f9Qvsg' YՕsP8,Q׏!\4%# :8q #V,No }B"t$Yha!wۅ9- ;O'^hN9*HC$|_mnߵsIKYEɐ.LD?X>Y_C~SgnaD\6G4ScԫxGI3> cduڽ"nY)'X}ZF3ąϫXqoe>Y~1FyA+Ch_Bp,5?.ɺIgzE߫p ZƟcJc&b~+?Y/{* Ib q&7u]x7b&n҉3v?aZ2,Q0V<9h$͓8`$-z:=IkǑHZ$Fh HÚmGdI~?!ig$ $KHq"iH'ܝ@#i ~IkɧǑd?E,𑴁tY)G±HHi?22̑&!{, p*g 8q\o'ǁwWwkǯNCG_^8_0}9TӈG7 Jvf~}ü0(|7r{gJ4eO pHNҋ`6߃xEVeWSdzOu||~Mϴ?@}}eM{{{x>P3|+{.]t3 1|F -\>  t=ԡzO'AB[7M4(l~|ꬷeWtfc66^چ80qҒSZR+69ܘlo'1v44Rv9Ǘa_K:_|dkLmfFQ/2fDm&`jߴěLnSiȴt4e҆K/xt%?ڒpB;!mZ{-[i j Gg^2/!(S:PXb#1:6:it,~pLnb!4Z<::66FMFFIh&`FZ2p-77卩cHgD-dh0X endstream endobj 128 0 obj 13688 endobj 129 0 obj <> endobj 130 0 obj <> stream x]n0; c{ :Cm6SCv^䷽6S6a8uLns|M7—,ᢞ~mxp ìUΩf\C.Uχ.s*xLAyTi.ܦ .![E}[tn?:Eub#\`+ d ;p +ɼ=xŌ7\Wn{xO.L yMӿ =h[a[ ˷p&cF_bl-J} -k_CJ8;C C#/q{4wػY'_?ӿu;]0KIgb烙%jKf\w1R=4B22;~z'To@; endstream endobj 131 0 obj <> endobj 132 0 obj <> endobj 133 0 obj <> endobj 1 0 obj <>/Contents 2 0 R>> endobj 4 0 obj <>/Contents 5 0 R>> endobj 7 0 obj <>/Contents 8 0 R>> endobj 10 0 obj <>/Contents 11 0 R>> endobj 13 0 obj <>/Contents 14 0 R>> endobj 16 0 obj <>/Contents 17 0 R>> endobj 19 0 obj <>/Contents 20 0 R>> endobj 22 0 obj <>/Contents 23 0 R>> endobj 25 0 obj <>/Contents 26 0 R>> endobj 28 0 obj <>/Contents 29 0 R>> endobj 31 0 obj <>/Contents 32 0 R>> endobj 34 0 obj <>/Contents 35 0 R>> endobj 134 0 obj <> endobj 135 0 obj < /Dest[1 0 R/XYZ 72 628.4 0]/Parent 134 0 R>> endobj 136 0 obj < /Dest[1 0 R/XYZ 72 567.2 0]/Parent 135 0 R/Next 137 0 R>> endobj 137 0 obj < /Dest[4 0 R/XYZ 72 652.4 0]/Parent 135 0 R/Prev 136 0 R/Next 138 0 R>> endobj 138 0 obj < /Dest[7 0 R/XYZ 72 465.2 0]/Parent 135 0 R/Prev 137 0 R/Next 139 0 R>> endobj 139 0 obj < /Dest[10 0 R/XYZ 72 652.4 0]/Parent 135 0 R/Prev 138 0 R/Next 143 0 R>> endobj 140 0 obj < /Dest[10 0 R/XYZ 72 531.8 0]/Parent 139 0 R/Next 141 0 R>> endobj 141 0 obj < /Dest[13 0 R/XYZ 72 596.1 0]/Parent 139 0 R/Prev 140 0 R/Next 142 0 R>> endobj 142 0 obj < /Dest[16 0 R/XYZ 72 652.4 0]/Parent 139 0 R/Prev 141 0 R>> endobj 143 0 obj < /Dest[22 0 R/XYZ 72 652.4 0]/Parent 135 0 R/Prev 139 0 R/Next 148 0 R>> endobj 144 0 obj < /Dest[22 0 R/XYZ 72 560 0]/Parent 143 0 R/Next 145 0 R>> endobj 145 0 obj < /Dest[22 0 R/XYZ 72 357.4 0]/Parent 143 0 R/Prev 144 0 R/Next 146 0 R>> endobj 146 0 obj < /Dest[25 0 R/XYZ 72 567.9 0]/Parent 143 0 R/Prev 145 0 R/Next 147 0 R>> endobj 147 0 obj < /Dest[25 0 R/XYZ 72 210.8 0]/Parent 143 0 R/Prev 146 0 R>> endobj 148 0 obj < /Dest[31 0 R/XYZ 72 652.4 0]/Parent 135 0 R/Prev 143 0 R>> endobj 96 0 obj <> endobj 37 0 obj <> >> endobj 38 0 obj <> >> endobj 39 0 obj <> >> endobj 40 0 obj <> >> endobj 41 0 obj <> >> endobj 42 0 obj <> >> endobj 43 0 obj <> >> endobj 44 0 obj <> >> endobj 45 0 obj <> >> endobj 46 0 obj <> >> endobj 47 0 obj <> >> endobj 48 0 obj <> >> endobj 49 0 obj <> endobj 50 0 obj <> endobj 51 0 obj <> endobj 52 0 obj <> >> endobj 53 0 obj <> >> endobj 54 0 obj <> endobj 55 0 obj <> >> endobj 56 0 obj <> endobj 57 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <> >> endobj 60 0 obj <> >> endobj 61 0 obj <> >> endobj 62 0 obj <> >> endobj 63 0 obj <> >> endobj 64 0 obj <> >> endobj 65 0 obj <> >> endobj 66 0 obj <> >> endobj 67 0 obj <> endobj 68 0 obj <> endobj 69 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 72 0 obj <> endobj 73 0 obj <> endobj 74 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 77 0 obj <> endobj 78 0 obj <> endobj 79 0 obj <> >> endobj 80 0 obj <> >> endobj 81 0 obj <> >> endobj 82 0 obj <> >> endobj 83 0 obj <> >> endobj 84 0 obj <> >> endobj 85 0 obj <> >> endobj 86 0 obj <> >> endobj 87 0 obj <> >> endobj 88 0 obj <> >> endobj 89 0 obj <> >> endobj 90 0 obj <> >> endobj 91 0 obj <> endobj 92 0 obj <> endobj 93 0 obj <> endobj 94 0 obj <> endobj 95 0 obj <> endobj 149 0 obj <> endobj 150 0 obj < /Producer /CreationDate(D:20200615114251+02'00')>> endobj xref 0 151 0000000000 65535 f 0000174509 00000 n 0000000019 00000 n 0000005575 00000 n 0000174789 00000 n 0000005596 00000 n 0000013841 00000 n 0000175006 00000 n 0000013862 00000 n 0000020503 00000 n 0000175237 00000 n 0000020524 00000 n 0000028882 00000 n 0000175449 00000 n 0000028904 00000 n 0000036306 00000 n 0000175689 00000 n 0000036328 00000 n 0000043785 00000 n 0000175887 00000 n 0000043807 00000 n 0000050530 00000 n 0000176099 00000 n 0000050552 00000 n 0000058831 00000 n 0000176311 00000 n 0000058853 00000 n 0000066232 00000 n 0000176509 00000 n 0000066254 00000 n 0000072159 00000 n 0000176707 00000 n 0000072181 00000 n 0000080352 00000 n 0000176926 00000 n 0000080374 00000 n 0000086629 00000 n 0000180898 00000 n 0000181037 00000 n 0000181176 00000 n 0000181315 00000 n 0000181454 00000 n 0000181593 00000 n 0000181732 00000 n 0000181871 00000 n 0000182010 00000 n 0000182149 00000 n 0000182288 00000 n 0000182427 00000 n 0000182566 00000 n 0000182682 00000 n 0000182800 00000 n 0000182916 00000 n 0000183158 00000 n 0000183308 00000 n 0000183424 00000 n 0000183582 00000 n 0000183698 00000 n 0000183816 00000 n 0000183934 00000 n 0000184092 00000 n 0000184249 00000 n 0000184404 00000 n 0000184554 00000 n 0000184717 00000 n 0000184865 00000 n 0000185098 00000 n 0000185248 00000 n 0000185365 00000 n 0000185483 00000 n 0000185597 00000 n 0000185715 00000 n 0000185831 00000 n 0000185948 00000 n 0000186066 00000 n 0000186184 00000 n 0000186302 00000 n 0000186417 00000 n 0000186531 00000 n 0000186647 00000 n 0000186790 00000 n 0000186933 00000 n 0000187076 00000 n 0000187219 00000 n 0000187362 00000 n 0000187505 00000 n 0000187648 00000 n 0000187791 00000 n 0000187934 00000 n 0000188077 00000 n 0000188220 00000 n 0000188363 00000 n 0000188481 00000 n 0000188596 00000 n 0000188713 00000 n 0000188832 00000 n 0000180721 00000 n 0000086651 00000 n 0000102714 00000 n 0000102737 00000 n 0000102945 00000 n 0000103503 00000 n 0000103915 00000 n 0000124164 00000 n 0000124188 00000 n 0000124386 00000 n 0000125004 00000 n 0000125470 00000 n 0000127522 00000 n 0000127545 00000 n 0000127739 00000 n 0000128046 00000 n 0000128218 00000 n 0000133914 00000 n 0000133937 00000 n 0000134151 00000 n 0000134486 00000 n 0000134697 00000 n 0000144897 00000 n 0000144921 00000 n 0000145122 00000 n 0000145619 00000 n 0000145969 00000 n 0000158274 00000 n 0000158298 00000 n 0000158494 00000 n 0000159015 00000 n 0000159388 00000 n 0000173165 00000 n 0000173189 00000 n 0000173394 00000 n 0000173945 00000 n 0000174351 00000 n 0000174452 00000 n 0000177124 00000 n 0000177184 00000 n 0000177495 00000 n 0000177614 00000 n 0000177774 00000 n 0000177906 00000 n 0000178163 00000 n 0000178371 00000 n 0000178580 00000 n 0000178900 00000 n 0000179121 00000 n 0000179507 00000 n 0000179824 00000 n 0000180193 00000 n 0000180577 00000 n 0000188951 00000 n 0000189068 00000 n trailer < <228A53982A989028C46CC7B64EFBCE04> ] /DocChecksum /D45B3CCD8084747D34BAC79EF11CED74 >> startxref 189244 %%EOF rustls-v-0.21.10/bogo/000077500000000000000000000000001453461710000144015ustar00rootroot00000000000000rustls-v-0.21.10/bogo/.gitignore000066400000000000000000000000461453461710000163710ustar00rootroot00000000000000runner.tar.gz testresult.tar.gz bogo/ rustls-v-0.21.10/bogo/README.md000066400000000000000000000027621453461710000156670ustar00rootroot00000000000000# BoGo [BoGo](https://github.com/google/boringssl/tree/master/ssl/test) is the TLS test suite for boringssl, which we run against rustls as well. ## System requirements You will need golang installed ## Running tests ```bash $ cd bogo # from rustls repo root $ ./runme ``` ## Running a single test ```bash $ cd bogo # from rustls repo root $ ./runme -test "Foo;Bar" # where Foo and Bar are test names like EarlyData-Server-BadFinished-TLS13 ``` ## Diagnosing failures When updating the BoGo suite it's expected that new failures will emerge. There are often two major categories to diagnose: ### Unexpected error outputs Often the upstream will change expected error outputs (e.g. changing from `:DECODE_ERROR:` to `:NO_CERTS:`). The [`bogo_shim`][bogo_shim] `handle_err` function is responsible for mapping errors in combination with the `ErrorMap` and `TestErrorMap` data in [`config.json`][config.json]. These will typically need updating for new error outputs or changes in error outputs. [bogo_shim]: ../rustls/examples/internal/bogo_shim.rs [config.json]: ./config.json ### Unhandled options When the upstream test suite adds new options that aren't handled by Rustls the [`bogo_shim`][bogo_shim]'s `main` fn can be updated to signal `NYI` (not-yet-implemented) for the unhandled options. See the `// Not implemented things` switch near the end of the function definition. Use your best judgement to decide whether there should be a Rustls issue filed to consider implementing the option in question. rustls-v-0.21.10/bogo/check.py000066400000000000000000000025261453461710000160350ustar00rootroot00000000000000import re import json import fnmatch import sys config = json.load(open('config.json')) test_error_set = set(config['TestErrorMap'].keys()) obsolete_disabled_tests = set() all_tests = set() failing_tests = set() unimpl_tests = set() disabled_tests = set() passed_tests = set() for line in sys.stdin: m = re.match('^(PASSED|UNIMPLEMENTED|FAILED|DISABLED) \((.*)\)$', line.strip()) if m: status, name = m.groups() if name in test_error_set: test_error_set.remove(name) all_tests.add(name) if status == 'FAILED': failing_tests.add(name) elif status == 'UNIMPLEMENTED': unimpl_tests.add(name) elif status == 'DISABLED': disabled_tests.add(name) elif status == 'PASSED': passed_tests.add(name) if disabled_tests: for disabled_glob in sorted(config['DisabledTests'].keys()): tests_matching_glob = fnmatch.filter(disabled_tests, disabled_glob) if not tests_matching_glob: print 'DisabledTests glob', disabled_glob, 'matches no tests' else: print '(DisabledTests unchecked)' print len(all_tests), 'total tests' print len(passed_tests), 'passed' print len(failing_tests), 'tests failing' print len(unimpl_tests), 'tests not supported' if test_error_set: print 'unknown TestErrorMap keys', test_error_set rustls-v-0.21.10/bogo/config.json000066400000000000000000000552641453461710000165550ustar00rootroot00000000000000{ "DisabledTests": { "SendV2ClientHello-*": "only support TLS1.2", "*SSL3*": "", "*SSLv3*": "", "*TLS1-*": "", "*-TLS1": "", "*TLS11-*": "", "*-TLS11": "", "ConflictingVersionNegotiation": "", "SendFallbackSCSV": "fallback scsv not implemented", "PointFormat-Server-Missing": "we require ecc", "ECDSAKeyUsage-*": "TODO: we don't do anything with key usages", "CheckRecordVersion-*": "we don't look at record version", "TLS13-WrongOuterRecord": "we're lax on this", "*DTLS*": "not supported", "*Draft23*": "old draft", "TokenBinding-*": "not supported", "DummyPQPadding-*": "not supported", "MTU*": "dtls only", "DisableEverything": "not useful", "SendEmptyRecords": "non-standard openssl/boringssl behaviour", "SendEmptyRecords-Async": "", "CheckLeafCurve": "", "SendWarningAlerts": "", "SendWarningAlerts-*": "", "Peek-*": "", "*-Split": "", "EchoTLS13CompatibilitySessionID": "", "ClientOCSPCallback*": "ocsp not supported yet", "ServerOCSPCallback*": "", "CertCompression*": "not implemented", "DuplicateCertCompressionExt*": "", "TLS-ECH-*": "", "ALPS-*": "", "*Kyber*": "", "ExtraClientEncryptedExtension-TLS-TLS13": "uses ALPS", "SendHelloRetryRequest-2-TLS13": "we accept any supported keyshare", "OmitExtensions-ServerHello-TLS12": "bug in bogo if sct offered", "EmptyExtensions-ServerHello-TLS12": "", "Server-JDK11*": "workarounds for oracle engineering quality", "Client-RejectJDK11DowngradeRandom": "", "CBCRecordSplitting*": "insane ciphersuites", "*CBCPadding*": "", "RSAEphemeralKey": "", "BadRSAClientKeyExchange-*": "", "SendClientVersion-RSA": "", "Basic-Server-RSA-*": "", "RSAKeyUsage-*": "", "*-3DES-*": "", "*-RSA_WITH_3DES_EDE_CBC_SHA-*": "", "*-AES128-SHA*": "", "*-AES256-SHA*": "", "*_WITH_AES_128_CBC_*": "", "*_WITH_AES_256_CBC_*": "", "*-ECDSA_SHA1-*": "no ecdsa-sha1", "*-Sign-RSA_PKCS1_SHA1-*": "no sha1", "*-VerifyDefault-RSA_PKCS1_SHA1-*": "no sha1", "*_P224_*": "no p224", "*-P-224-*": "", "*_P521_*": "no p521", "CurveTest-Client-P-521-TLS12": "", "CurveTest-Server-P-521-TLS12": "", "CurveTest-Client-Compressed-P-521-TLS12": "", "CurveTest-Server-Compressed-P-521-TLS12": "", "CurveTest-Client-P-521-TLS13": "", "CurveTest-Server-P-521-TLS13": "", "CurveTest-Client-Compressed-P-521-TLS13": "", "CurveTest-Server-Compressed-P-521-TLS13": "", "GREASE-*": "not implemented", "LargeMessage-Reject": "", "DelegatedCredentials-*": "not implemented", "CECPQ2*": "no PQC experiments", "*CECPQ2*": "", "KeyUpdate-FromClient": "not implemented (no API yet)", "KeyUpdate-FromServer": "", "ExportTrafficSecrets-*": "", "*-InvalidSignature-*-SHA1-*": "no sha1", "NoCommonCurves": "nothing to fall back to", "ClientHelloPadding": "hello padding extension not implemented", "Resume-Client-CipherMismatch": "tries to vary to unimplemented CBC-mode cs", "*Auth-SHA1-Fallback*": "", "RSA-PSS-Large": "", "TLS12-AES128-GCM-*": "no pfs", "TLS12-AES256-GCM-*": "", "*-RSA_WITH_AES_128_GCM_SHA256-*": "", "*-RSA_WITH_AES_256_GCM_SHA384-*": "", "*-RSA_WITH_AES_128_CBC_SHA-*": "", "*-RSA_WITH_AES_256_CBC_SHA-*": "", "OmitExtensions-ClientHello-TLS12": "", "EmptyExtensions-ClientHello-TLS12": "", "Resume-Server-OmitPSKsOnSecondClientHello": "not required by RFC", "FallbackSCSV*": "fallback countermeasure not yet implemented", "RequireAnyClientCertificate-TLS12": "we don't send an alert in this case", "TooManyKeyUpdates": "no limit implemented", "SendUserCanceledAlerts-TooMany-TLS13": "", "ServerBogusVersion": "we ignore legacy_version if there's an extension", "Renegotiate-Client-*": "no reneg", "Shutdown-Shim-Renegotiate-*": "", "Shutdown-Shim-HelloRequest-*": "", "Shutdown-Shim-ApplicationData*": "tests boringssl/openssl-specific behaviour, we don't let application data overtake connection shutdown", "Renegotiate-Server-*": "", "Renegotiate-ForbidAfterHandshake": "", "SendHalfHelloRequest-*": "", "RetainOnlySHA256-*": "", "ExtendedMasterSecret-Renego-*": "", "ALPN*SelectEmpty-*": "", "Draft-Downgrade-Server": "not implemented; TODO", "EarlyData-*ALPN*-*": "no alpn change in resumed sessions", "*EarlyKeyingMaterial-Client-*": "early exporter NYI", "QUICTransportParams-*": "Bogo assumes this can be tested over TLS1.3 framing -- could make this work with some effort", "QUICCompatibilityMode": "", "Ed25519DefaultDisable-NoAccept": "not implemented (ed25519 accepted by default)", "Ed25519DefaultDisable-NoAdvertise": "not implemented (ed25519 advertised by default)", "Server-VerifyDefault-Ed25519-TLS13": "ed25519 accepted by default", "Server-VerifyDefault-Ed25519-TLS12": "", "Client-VerifyDefault-Ed25519-TLS13": "", "Client-VerifyDefault-Ed25519-TLS12": "", "*-HintMismatch-*": "hints are a boringssl-specific feature", "*-QUIC-*" :"", "QUIC-*": "", "*-QUIC": "" }, "ErrorMap": { ":HTTP_REQUEST:": ":GARBAGE:", ":HTTPS_PROXY_REQUEST:": ":GARBAGE:", ":WRONG_VERSION_NUMBER:": ":GARBAGE:", ":PEER_DID_NOT_RETURN_A_CERTIFICATE:": ":NO_CERTS:", ":UNEXPECTED_RECORD:": ":UNEXPECTED_MESSAGE:", ":NO_RENEGOTIATION:": ":UNEXPECTED_MESSAGE:", ":DIGEST_CHECK_FAILED:": ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", ":APPLICATION_DATA_INSTEAD_OF_HANDSHAKE:": ":UNEXPECTED_MESSAGE:", ":ENCRYPTED_LENGTH_TOO_LONG:": ":GARBAGE:" }, "TestErrorMap": { "EmptyCertificateList": ":NO_CERTS:", "SendInvalidRecordType": ":GARBAGE:", "NoSharedCipher": ":HANDSHAKE_FAILURE:", "NoSharedCipher-TLS13": ":HANDSHAKE_FAILURE:", "InvalidECDHPoint-Client": ":PEER_MISBEHAVIOUR:", "InvalidECDHPoint-Server": ":PEER_MISBEHAVIOUR:", "TrailingMessageData-ClientHello-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-ServerHello-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-ServerCertificate-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-CertificateRequest-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-ClientCertificate-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-CertificateVerify-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-NewSessionTicket-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-ServerHelloDone-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-ServerKeyExchange-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-ClientKeyExchange-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-CertificateStatus-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-ClientHello-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-ServerHello-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-EncryptedExtensions-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-CertificateRequest-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-ServerCertificate-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-ServerCertificateVerify-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-ServerFinished-TLS": ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", "TrailingMessageData-TLS13-ClientCertificate-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-ClientCertificateVerify-TLS": ":BAD_HANDSHAKE_MSG:", "TrailingMessageData-TLS13-EndOfEarlyData-TLS": ":BAD_HANDSHAKE_MSG:", "Server-NonEmptyEndOfEarlyData-TLS13": ":BAD_HANDSHAKE_MSG:", "MissingKeyShare-Client-TLS13": ":PEER_MISBEHAVIOUR:", "MissingKeyShare-Server-TLS13": ":INCOMPATIBLE:", "EmptyEncryptedExtensions-TLS13": ":BAD_HANDSHAKE_MSG:", "NoSupportedCurves": ":INCOMPATIBLE:", "BadECDHECurve": ":PEER_MISBEHAVIOUR:", "VersionTooLow": ":INCOMPATIBLE:", "ServerHelloBogusCipher": ":PEER_MISBEHAVIOUR:", "ServerHelloBogusCipher-TLS13": ":PEER_MISBEHAVIOUR:", "ALPNClient-RejectUnknown-TLS-TLS12": ":PEER_MISBEHAVIOUR:", "ALPNClient-RejectUnknown-TLS-TLS13": ":PEER_MISBEHAVIOUR:", "ALPNClient-EmptyProtocolName-TLS-TLS12": ":PEER_MISBEHAVIOUR:", "ALPNClient-EmptyProtocolName-TLS-TLS13": ":PEER_MISBEHAVIOUR:", "ALPNServer-EmptyProtocolName-TLS-TLS12": ":PEER_MISBEHAVIOUR:", "ALPNServer-EmptyProtocolName-TLS-TLS13": ":PEER_MISBEHAVIOUR:", "Verify-ServerAuth-SignatureType": ":PEER_MISBEHAVIOUR:", "Verify-ClientAuth-SignatureType": ":BAD_SIGNATURE:", "Verify-ServerAuth-SignatureType-TLS13": ":BAD_SIGNATURE:", "Verify-ClientAuth-SignatureType-TLS13": ":BAD_SIGNATURE:", "ClientAuth-Enforced": ":PEER_MISBEHAVIOUR:", "ServerAuth-Enforced": ":PEER_MISBEHAVIOUR:", "UnofferedExtension-Client": ":PEER_MISBEHAVIOUR:", "UnknownExtension-Client": ":PEER_MISBEHAVIOUR:", "KeyUpdate-InvalidRequestMode": ":BAD_HANDSHAKE_MSG:", "ExtraCompressionMethods-TLS13": ":PEER_MISBEHAVIOUR:", "NoNullCompression-TLS12": ":INCOMPATIBLE:", "NoNullCompression-TLS13": ":INCOMPATIBLE:", "InvalidCompressionMethod": ":PEER_MISBEHAVIOUR:", "TLS13-InvalidCompressionMethod": ":PEER_MISBEHAVIOUR:", "TLS13-AES128-GCM-server": ":INCOMPATIBLE:", "TLS13-AES128-GCM-client": ":PEER_MISBEHAVIOUR:", "TLS13-AES256-GCM-server": ":INCOMPATIBLE:", "TLS13-AES256-GCM-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS13-ECDHE_ECDSA_WITH_AES_128_GCM_SHA256-server": ":INCOMPATIBLE:", "TLS-TLS13-ECDHE_ECDSA_WITH_AES_128_GCM_SHA256-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS13-ECDHE_ECDSA_WITH_AES_256_GCM_SHA384-server": ":INCOMPATIBLE:", "TLS-TLS13-ECDHE_ECDSA_WITH_AES_256_GCM_SHA384-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS13-ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256-server": ":INCOMPATIBLE:", "TLS-TLS13-ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS13-ECDHE_RSA_WITH_AES_128_GCM_SHA256-server": ":INCOMPATIBLE:", "TLS-TLS13-ECDHE_RSA_WITH_AES_128_GCM_SHA256-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS13-ECDHE_RSA_WITH_AES_256_GCM_SHA384-server": ":INCOMPATIBLE:", "TLS-TLS13-ECDHE_RSA_WITH_AES_256_GCM_SHA384-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS13-ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256-server": ":INCOMPATIBLE:", "TLS-TLS13-ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS12-CHACHA20_POLY1305_SHA256-server": ":INCOMPATIBLE:", "TLS-TLS12-CHACHA20_POLY1305_SHA256-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS12-AES_128_GCM_SHA256-server": ":INCOMPATIBLE:", "TLS-TLS12-AES_128_GCM_SHA256-client": ":PEER_MISBEHAVIOUR:", "TLS-TLS12-AES_256_GCM_SHA384-server": ":INCOMPATIBLE:", "TLS-TLS12-AES_256_GCM_SHA384-client": ":PEER_MISBEHAVIOUR:", "SkipHelloRetryRequest-TLS13": ":PEER_MISBEHAVIOUR:", "NoSupportedVersions": ":INCOMPATIBLE:", "Client-VerifyDefault-RSA_PKCS1_SHA1-TLS12": ":PEER_ALERT_INTERNAL_ERROR:", "Server-VerifyDefault-RSA_PKCS1_SHA1-TLS12": ":HANDSHAKE_FAILURE:", "Client-VerifyDefault-RSA_PKCS1_SHA1-TLS13": ":PEER_MISBEHAVIOUR:", "Server-VerifyDefault-RSA_PKCS1_SHA1-TLS13": ":PEER_MISBEHAVIOUR:", "Client-VerifyDefault-RSA_PKCS1_SHA256-TLS13": ":PEER_MISBEHAVIOUR:", "Server-VerifyDefault-RSA_PKCS1_SHA256-TLS13": ":PEER_MISBEHAVIOUR:", "Client-VerifyDefault-RSA_PKCS1_SHA384-TLS13": ":PEER_MISBEHAVIOUR:", "Server-VerifyDefault-RSA_PKCS1_SHA384-TLS13": ":PEER_MISBEHAVIOUR:", "Client-VerifyDefault-RSA_PKCS1_SHA512-TLS13": ":PEER_MISBEHAVIOUR:", "Server-VerifyDefault-RSA_PKCS1_SHA512-TLS13": ":PEER_MISBEHAVIOUR:", "ClientAuth-InvalidSignature-RSA-PKCS1-SHA1-TLS12": ":PEER_MISBEHAVIOUR:", "ServerAuth-InvalidSignature-RSA-PKCS1-SHA1-TLS12": ":PEER_MISBEHAVIOUR:", "Server-Sign-RSA_PKCS1_SHA256-TLS13": ":INCOMPATIBLE:", "Server-Sign-RSA_PKCS1_SHA384-TLS13": ":INCOMPATIBLE:", "Server-Sign-RSA_PKCS1_SHA512-TLS13": ":INCOMPATIBLE:", "Client-Sign-RSA_PKCS1_SHA256-TLS13": ":INCOMPATIBLE:", "Client-Sign-RSA_PKCS1_SHA384-TLS13": ":INCOMPATIBLE:", "Client-Sign-RSA_PKCS1_SHA512-TLS13": ":INCOMPATIBLE:", "Client-TLS13-NoSign-RSA_PKCS1_MD5_SHA1": ":INCOMPATIBLE:", "Server-TLS12-NoSign-RSA_PKCS1_MD5_SHA1": ":INCOMPATIBLE:", "Server-TLS13-NoSign-RSA_PKCS1_MD5_SHA1": ":INCOMPATIBLE:", "ALPNClient-EmptyProtocolName-TLS13": ":PEER_MISBEHAVIOUR:", "ALPNServer-EmptyProtocolName-TLS13": ":PEER_MISBEHAVIOUR:", "ALPNClient-RejectUnknown-TLS13": ":PEER_MISBEHAVIOUR:", "ClientAuth-NoFallback-RSA": ":BAD_HANDSHAKE_MSG:", "ClientAuth-NoFallback-ECDSA": ":BAD_HANDSHAKE_MSG:", "ClientAuth-NoFallback-TLS13": ":BAD_HANDSHAKE_MSG:", "ServerAuth-NoFallback-TLS13": ":INCOMPATIBLE:", "ClientAuth-Enforced-TLS13": ":PEER_MISBEHAVIOUR:", "ServerAuth-Enforced-TLS13": ":PEER_MISBEHAVIOUR:", "SecondClientHelloWrongCurve-TLS13": ":PEER_MISBEHAVIOUR:", "SecondClientHelloMissingKeyShare-TLS13": ":INCOMPATIBLE:", "Resume-Server-BinderWrongLength-SecondBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-NoPSKBinder-SecondBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-ExtraPSKBinder-SecondBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-ExtraIdentityNoBinder-SecondBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-InvalidPSKBinder-SecondBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-PSKBinderFirstExtension-SecondBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-OmitPSKsOnSecondClientHello": ":PEER_MISBEHAVIOUR:", "Resume-Server-BinderWrongLength": ":PEER_MISBEHAVIOUR:", "Resume-Server-NoPSKBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-ExtraPSKBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-ExtraIdentityNoBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-InvalidPSKBinder": ":PEER_MISBEHAVIOUR:", "Resume-Server-PSKBinderFirstExtension": ":PEER_MISBEHAVIOUR:", "Resume-Client-PRFMismatch-TLS13": ":PEER_MISBEHAVIOUR:", "Resume-Client-Mismatch-TLS12-TLS13-TLS": ":PEER_MISBEHAVIOUR:", "Resume-Client-Mismatch-TLS13-TLS12-TLS": ":PEER_MISBEHAVIOUR:", "NoSupportedCurves-TLS13": ":INCOMPATIBLE:", "BadECDHECurve-TLS13": ":PEER_MISBEHAVIOUR:", "InvalidECDHPoint-Client-TLS13": ":PEER_MISBEHAVIOUR:", "InvalidECDHPoint-Server-TLS13": ":PEER_MISBEHAVIOUR:", "InvalidPSKIdentity-TLS13": ":PEER_MISBEHAVIOUR:", "AlwaysSelectPSKIdentity-TLS13": ":PEER_MISBEHAVIOUR:", "TrailingKeyShareData-TLS13": ":BAD_HANDSHAKE_MSG:", "HelloRetryRequestCurveMismatch-TLS13": ":PEER_MISBEHAVIOUR:", "HelloRetryRequestVersionMismatch-TLS13": ":INCOMPATIBLE:", "HelloRetryRequest-DuplicateCookie-TLS13": ":PEER_MISBEHAVIOUR:", "HelloRetryRequest-DuplicateCurve-TLS13": ":PEER_MISBEHAVIOUR:", "UnknownUnencryptedExtension-Client-TLS13": ":PEER_MISBEHAVIOUR:", "UnexpectedUnencryptedExtension-Client-TLS13": ":PEER_MISBEHAVIOUR:", "UnofferedExtension-Client-TLS13": ":PEER_MISBEHAVIOUR:", "RenegotiationInfo-Forbidden-TLS13": ":PEER_MISBEHAVIOUR:", "UnknownExtension-Client-TLS13": ":PEER_MISBEHAVIOUR:", "RequestContextInHandshake-TLS13": ":BAD_HANDSHAKE_MSG:", "UnnecessaryHelloRetryRequest-TLS13": ":PEER_MISBEHAVIOUR:", "UnknownCurve-HelloRetryRequest-TLS13": ":PEER_MISBEHAVIOUR:", "DisabledCurve-HelloRetryRequest-TLS13": ":PEER_MISBEHAVIOUR:", "HelloRetryRequest-Empty-TLS13": ":PEER_MISBEHAVIOUR:", "HelloRetryRequest-EmptyCookie-TLS13": ":PEER_MISBEHAVIOUR:", "TrailingDataWithFinished-Client-TLS12": ":PEER_MISBEHAVIOUR:", "TrailingDataWithFinished-Resume-Client-TLS12": ":PEER_MISBEHAVIOUR:", "TrailingDataWithFinished-Server-TLS12": ":PEER_MISBEHAVIOUR:", "TrailingDataWithFinished-Resume-Server-TLS12": ":PEER_MISBEHAVIOUR:", "TrailingDataWithFinished-Client-TLS13": ":PEER_MISBEHAVIOUR:", "TrailingDataWithFinished-Server-TLS13": ":PEER_MISBEHAVIOUR:", "TrailingDataWithFinished-Resume-Client-TLS13": ":PEER_MISBEHAVIOUR:", "TrailingDataWithFinished-Resume-Server-TLS13": ":PEER_MISBEHAVIOUR:", "PartialSecondClientHelloAfterFirst": ":PEER_MISBEHAVIOUR:", "PartialClientFinishedWithSecondClientHello": ":PEER_MISBEHAVIOUR:", "PartialClientFinishedWithClientHello-TLS12-Resume": ":PEER_MISBEHAVIOUR:", "PartialServerHelloWithHelloRetryRequest": ":PEER_MISBEHAVIOUR:", "PartialNewSessionTicketWithServerHelloDone": ":PEER_MISBEHAVIOUR:", "PartialEndOfEarlyDataWithClientHello": ":PEER_MISBEHAVIOUR:", "FragmentAcrossChangeCipherSpec-Client": ":PEER_MISBEHAVIOUR:", "FragmentAcrossChangeCipherSpec-Server-Packed": ":PEER_MISBEHAVIOUR:", "FragmentAcrossChangeCipherSpec-Client-Resume-Packed": ":PEER_MISBEHAVIOUR:", "FragmentAcrossChangeCipherSpec-Client-Resume": ":PEER_MISBEHAVIOUR:", "FragmentAcrossChangeCipherSpec-Server-Resume": ":PEER_MISBEHAVIOUR:", "FragmentAcrossChangeCipherSpec-Server": ":PEER_MISBEHAVIOUR:", "FragmentAcrossChangeCipherSpec-Client-Packed": ":PEER_MISBEHAVIOUR:", "FragmentAcrossChangeCipherSpec-Server-Resume-Packed": ":PEER_MISBEHAVIOUR:", "PartialFinishedWithServerHelloDone": ":PEER_MISBEHAVIOUR:", "UnsupportedCurve-ServerHello-TLS13": ":PEER_MISBEHAVIOUR:", "PartialClientKeyExchangeWithClientHello": ":PEER_MISBEHAVIOUR:", "MinimumVersion-Client-TLS13-TLS12-TLS": ":INCOMPATIBLE:", "MinimumVersion-Client2-TLS13-TLS12-TLS": ":INCOMPATIBLE:", "MinimumVersion-Server-TLS13-TLS12-TLS": ":INCOMPATIBLE:", "MinimumVersion-Server2-TLS13-TLS12-TLS": ":INCOMPATIBLE:", "DuplicateKeyShares-TLS13": ":PEER_MISBEHAVIOUR:", "PartialEncryptedExtensionsWithServerHello": ":PEER_MISBEHAVIOUR:", "PartialClientFinishedWithClientHello": ":PEER_MISBEHAVIOUR:", "PointFormat-EncryptedExtensions-TLS13": ":PEER_MISBEHAVIOUR:", "Ticket-Forbidden-TLS13": ":PEER_MISBEHAVIOUR:", "PointFormat-Server-MissingUncompressed": ":INCOMPATIBLE:", "MissingSignatureAlgorithmsInCertificateRequest-TLS13": ":INCOMPATIBLE:", "NegotiatePSKResumption-TLS13": ":PEER_MISBEHAVIOUR:", "PointFormat-Client-MissingUncompressed": ":PEER_MISBEHAVIOUR:", "SendUnsolicitedOCSPOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:", "SendUnsolicitedSCTOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:", "UnsolicitedServerNameAck-TLS-TLS12": ":PEER_MISBEHAVIOUR:", "UnsolicitedServerNameAck-TLS-TLS13": ":PEER_MISBEHAVIOUR:", "TicketSessionIDLength-33-TLS-TLS12": ":BAD_HANDSHAKE_MSG:", "Server-TooLongSessionID-TLS13": ":BAD_HANDSHAKE_MSG:", "Server-TooLongSessionID-TLS12": ":BAD_HANDSHAKE_MSG:", "Client-TooLongSessionID": ":BAD_HANDSHAKE_MSG:", "Ed25519DefaultDisable-NoAccept": ":PEER_MISBEHAVIOUR:", "SendUnknownExtensionOnCertificate-TLS13": ":PEER_MISBEHAVIOUR:", "SendDuplicateExtensionsOnCerts-TLS13": ":PEER_MISBEHAVIOUR:", "SignedCertificateTimestampListEmpty-Client-TLS-TLS12": ":PEER_MISBEHAVIOUR:", "SignedCertificateTimestampListEmpty-Client-TLS-TLS13": ":PEER_MISBEHAVIOUR:", "SignedCertificateTimestampListEmptySCT-Client-TLS-TLS12": ":PEER_MISBEHAVIOUR:", "SignedCertificateTimestampListEmptySCT-Client-TLS-TLS13": ":PEER_MISBEHAVIOUR:", "EMS-Forbidden-TLS13": ":PEER_MISBEHAVIOUR:", "Unclean-Shutdown": ":CLOSE_WITHOUT_CLOSE_NOTIFY:", "SendExtensionOnClientCertificate-TLS13": ":PEER_MISBEHAVIOUR:", "SendBogusAlertType": ":BAD_ALERT:", "TLS13-HRR-InvalidCompressionMethod": ":BAD_HANDSHAKE_MSG:", "CertificateCipherMismatch-RSA": ":PEER_MISBEHAVIOUR:", "CertificateCipherMismatch-ECDSA": ":PEER_MISBEHAVIOUR:", "CertificateCipherMismatch-Ed25519": ":PEER_MISBEHAVIOUR:", "ServerCipherFilter-RSA": ":INCOMPATIBLE:", "ServerCipherFilter-ECDSA": ":INCOMPATIBLE:", "ServerCipherFilter-Ed25519": ":INCOMPATIBLE:", "SendServerHelloAsHelloRetryRequest": ":BAD_HANDSHAKE_MSG:", "TLS13-OnlyPadding": ":PEER_MISBEHAVIOUR:", "TLS13-EmptyRecords": ":PEER_MISBEHAVIOUR:", "TLS13-DuplicateTicketEarlyDataSupport": ":PEER_MISBEHAVIOUR:", "SupportedVersionSelection-TLS12": ":PEER_MISBEHAVIOUR:", "HelloRetryRequest-CipherChange-TLS13": ":PEER_MISBEHAVIOUR:", "CurveTest-Client-Compressed-P-256-TLS12": ":PEER_MISBEHAVIOUR:", "CurveTest-Server-Compressed-P-256-TLS12": ":PEER_MISBEHAVIOUR:", "CurveTest-Client-Compressed-P-256-TLS13": ":PEER_MISBEHAVIOUR:", "CurveTest-Server-Compressed-P-256-TLS13": ":PEER_MISBEHAVIOUR:", "CurveTest-Client-Compressed-P-384-TLS12": ":PEER_MISBEHAVIOUR:", "CurveTest-Server-Compressed-P-384-TLS12": ":PEER_MISBEHAVIOUR:", "CurveTest-Client-Compressed-P-384-TLS13": ":PEER_MISBEHAVIOUR:", "CurveTest-Server-Compressed-P-384-TLS13": ":PEER_MISBEHAVIOUR:", "ExtendedMasterSecret-NoToYes-Client": ":PEER_MISBEHAVIOUR:", "ExtendedMasterSecret-YesToNo-Server": ":PEER_MISBEHAVIOUR:", "ExtendedMasterSecret-YesToNo-Client": ":PEER_MISBEHAVIOUR:", "ServerAcceptsEarlyDataOnHRR-Client-TLS13": ":PEER_MISBEHAVIOUR:", "Downgrade-TLS12-Client": ":PEER_MISBEHAVIOUR:", "Downgrade-TLS10-Client": ":HANDSHAKE_FAILURE:", "Downgrade-TLS10-Server": ":INCOMPATIBLE:", "UnsupportedCurve": ":PEER_MISBEHAVIOUR:", "ECDSACurveMismatch-Verify-TLS13": ":BAD_SIGNATURE:", "SecondServerHelloNoVersion-TLS13": ":PEER_MISBEHAVIOUR:", "SecondServerHelloWrongVersion-TLS13": ":INCOMPATIBLE:", "TooManyChangeCipherSpec-Client-TLS13": ":PEER_MISBEHAVIOUR:", "TooManyChangeCipherSpec-Server-TLS13": ":PEER_MISBEHAVIOUR:", "EarlyData-CipherMismatch-Client-TLS13": ":PEER_MISBEHAVIOUR:", "EarlyDataWithoutResume-Client-TLS13": ":PEER_MISBEHAVIOUR:", "EarlyDataVersionDowngrade-Client-TLS13": ":PEER_MISBEHAVIOUR:", "EarlyData-SkipEndOfEarlyData-TLS13": ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", "SkipEarlyData-Interleaved-TLS13": ":PEER_MISBEHAVIOUR:", "SkipEarlyData-TooMuchData-TLS13": ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", "SkipEarlyData-HRR-FatalAlert-TLS13": ":HANDSHAKE_FAILURE:", "SkipEarlyData-HRR-Interleaved-TLS13": ":PEER_MISBEHAVIOUR:", "SkipEarlyData-HRR-TooMuchData-TLS13": ":UNEXPECTED_MESSAGE:", "SkipEarlyData-SecondClientHelloEarlyData-TLS13": ":PEER_MISBEHAVIOUR:" }, "TestLocalErrorMap": { "SendServerHelloAsHelloRetryRequest": "remote error: error decoding message", "GarbageCertificate-Server-TLS12": "remote error: bad certificate", "GarbageCertificate-Server-TLS13": "remote error: bad certificate", "GarbageCertificate-Client-TLS12": "remote error: bad certificate", "GarbageCertificate-Client-TLS13": "remote error: bad certificate", "Client-VerifyDefault-RSA_PKCS1_SHA1-TLS12": "tls: no common signature algorithms", "Server-VerifyDefault-RSA_PKCS1_SHA1-TLS12": "tls: no common signature algorithms", "Downgrade-TLS10-Client": "tls: no cipher suite supported by both client and server", "Downgrade-TLS10-Server": "remote error: protocol version not supported", "TrailingDataWithFinished-Client-TLS13": "local error: bad record MAC", "TrailingDataWithFinished-Resume-Client-TLS13": "local error: bad record MAC", "SkipEarlyData-SecondClientHelloEarlyData-TLS13": "remote error: illegal parameter" }, "HalfRTTTickets": 0 } rustls-v-0.21.10/bogo/fetch-and-build000077500000000000000000000006651453461710000172640ustar00rootroot00000000000000#!/usr/bin/env bash set -ex mkdir -p bogo pushd bogo git init --initial-branch main git config core.sparsecheckout 1 cat << EOF > .git/info/sparse-checkout go.mod go.sum ssl/test/runner util/testresult EOF # fix on a tested point of rustls-testing branch COMMIT=b81c2d26009b6cc5159b7a9cbdddfa4ae79defea git fetch --depth=1 https://github.com/rustls/boringssl.git $COMMIT git checkout $COMMIT (cd ssl/test/runner && go test -c) popd rustls-v-0.21.10/bogo/keys/000077500000000000000000000000001453461710000153545ustar00rootroot00000000000000rustls-v-0.21.10/bogo/keys/cert.pem000066400000000000000000000017711453461710000170220ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICwTCCAamgAwIBAgIJAOvk/cOYx7QRMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV BAoMBGJvZ28wHhcNMTcwODI4MTQzNTIzWhcNMjcwODI2MTQzNTIzWjAPMQ0wCwYD VQQKDARib2dvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzZ9e9VGd jJ4z1B7D8RcBhiBCU9qSfYrP2hFLBEEPBGXfFx6PGTLbKoNz8SpX4qvsZSF5pLV8 f2/MU42YSv28KfSpYVP38ewWeY/J3mwe/6kGyDIRrRaIsjCEOXm7grUSOgVaqEmI 5gZ28Za5j9hOWU6RPLCgVZzvesRxcS7bh+DTcdJ74A+dED7EV39VqSmu9H5/B0Xq AD7bgFHN4DFURU9J01F0f2KPxVLFHa+PbyjQzZXhDmw+Zl6hesJCvFFc4raFt5b0 aRsEepoWwUb8KgApI5/cOEwmGhpLugTC8LALW6ZTWimpN5D92GvPdN1w9w9VPc3C ZDfD7PLK9MjRFQIDAQABoyAwHjAcBgNVHREEFTATggR0ZXN0ggtleGFtcGxlLmNv bTANBgkqhkiG9w0BAQsFAAOCAQEANDSklYrPCpv3Tr5sT2nr09LlwRivGUCLgIVv fqpfVE/ij3h33QthhJ/CR6x9e9q2WXB+UfNq6fIS5Kw6bE6dx4AljTUocng9IqNA y+CPxfq7Xl2uq6RqUFFnaVDZUmZGt0EofHvzpQKU29vGOjKoalIujoOj0sVyH7qK k26z9teDlU/wHHOElLHZaGwRPv7M5pWo5x2y5EnfTxwpi5Ic5mu0gaE3Xa6qlcu5 WcFVEd8NVFDYfxN1A52JRjyfpYrjcaPCOAzFrJERGMPtHSkyfd0djihvW75cpf64 CWeNQYqqf13rr1sg727cTXd65BRkhKFSb7A8QNf2e1m2vips2Q== -----END CERTIFICATE----- rustls-v-0.21.10/bogo/keys/ecdsa_p256_cert.pem000066400000000000000000000007311453461710000207300ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBLzCB16ADAgECAgkAvS1W/y9FJJ0wCQYHKoZIzj0EATAUMRIwEAYDVQQKDAli b2dvLXAyNTYwHhcNMTcwODI4MTQzNTIzWhcNMjcwODI2MTQzNTIzWjAUMRIwEAYD VQQKDAlib2dvLXAyNTYwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQingxZkEmP ALGMBDvXwpATjzihD74sAJTOX6IfHwjy7iIdm5bsP+ME9zyU6qnu6fv0Zu7f7o6U Bxz235vAOxASoxMwETAPBgNVHREECDAGggR0ZXN0MAkGByqGSM49BAEDSAAwRQIg dNB2V/WHlr5L3YiCN+c1odtvg+stq0nz5LB4NOueWhACIQDLWeMG/MXGjM9hr3JO izH3GbWkFN58KFzqoalfRhYwCQ== -----END CERTIFICATE----- rustls-v-0.21.10/bogo/keys/ecdsa_p256_key.pem000066400000000000000000000003611453461710000205620ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgPNtjq6YsYC9qgqXR AZevfVt61zK8lkkM+gx9Vh/CPH2hRANCAAQingxZkEmPALGMBDvXwpATjzihD74s AJTOX6IfHwjy7iIdm5bsP+ME9zyU6qnu6fv0Zu7f7o6UBxz235vAOxAS -----END PRIVATE KEY----- rustls-v-0.21.10/bogo/keys/ecdsa_p384_cert.pem000066400000000000000000000010521453461710000207270ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBbTCB9KADAgECAgkAnarogxZe7cYwCQYHKoZIzj0EATAUMRIwEAYDVQQKDAli b2dvLXAzODQwHhcNMTcwODI4MTQzNTIzWhcNMjcwODI2MTQzNTIzWjAUMRIwEAYD VQQKDAlib2dvLXAzODQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQb5S/671ocYzgV uGdFEo75AWUjwgPEwxFtrwgXn5SQEqPGGuJ4V7AB04kQ2BRhO+koTyq/QEtTIV5S KNhc9gH15ThkFUCLJTxurshRt8fIleWHDXqf7+kT12zfxsXOvGCjEzARMA8GA1Ud EQQIMAaCBHRlc3QwCQYHKoZIzj0EAQNpADBmAjEAl32GlN7wdF6LIjtSoe13yj/n Au7ENi5fNj6qczKXU9a7Hy0mmZCD4au7K7kwh8YcAjEAuv6Jo8BUuyCzY0U+zSxX bUM6/ZBxn04uMLe1+NC2RoyhNp4HugQP+4KXVuFyFyu0 -----END CERTIFICATE----- rustls-v-0.21.10/bogo/keys/ecdsa_p384_key.pem000066400000000000000000000004621453461710000205660ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAqYnznQtyoRmf+knoM h9AwVqbeeXdBHUrxXgDg5gYqRUCOEea2rUchjnEOZtLyVmChZANiAAQb5S/671oc YzgVuGdFEo75AWUjwgPEwxFtrwgXn5SQEqPGGuJ4V7AB04kQ2BRhO+koTyq/QEtT IV5SKNhc9gH15ThkFUCLJTxurshRt8fIleWHDXqf7+kT12zfxsXOvGA= -----END PRIVATE KEY----- rustls-v-0.21.10/bogo/keys/key.pem000066400000000000000000000032501453461710000166470ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDNn171UZ2MnjPU HsPxFwGGIEJT2pJ9is/aEUsEQQ8EZd8XHo8ZMtsqg3PxKlfiq+xlIXmktXx/b8xT jZhK/bwp9KlhU/fx7BZ5j8nebB7/qQbIMhGtFoiyMIQ5ebuCtRI6BVqoSYjmBnbx lrmP2E5ZTpE8sKBVnO96xHFxLtuH4NNx0nvgD50QPsRXf1WpKa70fn8HReoAPtuA Uc3gMVRFT0nTUXR/Yo/FUsUdr49vKNDNleEObD5mXqF6wkK8UVzitoW3lvRpGwR6 mhbBRvwqACkjn9w4TCYaGku6BMLwsAtbplNaKak3kP3Ya8903XD3D1U9zcJkN8Ps 8sr0yNEVAgMBAAECggEAFLuNB49DI3qQH0M63oRDUxLNnUbcnmvwqTw1JCirKvZa mCoso43NK2w1tItgcSqEm23UphbmhrLvFz2frXAIGPLiYT3mMi5r1bX51MNyHLUe SfFCdwFepxjdPC5aCcPYIqGHkpBXjVn5hEJ+U1KsE7UoT8Y/ZGJ+gxJrnc3rtLd4 TFxF5p6KKX3qluFnsjwjlcP7tMXd+fY3YWecAt+nUuz1eoQ5btieYW37/HV/LUhU Ew1aQ65nWx2Tb3XIRiEOB+KadI6BYYgfiNQuEfvDHy0MUToTTxl/P+Z/RIpuMWQz PysCGY8REM4+5bD+R8PUw2BszR6+3mIhpxROc3J5wQKBgQDu3i0kJ3XgkgSQjHYD ev2TzLP4U1GVITIOPm2si5rsuL3OP4fEBgurnY++L/SQzAztyV0ZYhrXpi1OzkJQ 4HKdOux9L21FBgpZuIW3FVAJ45nTgicrIxPG/4fXsepXA/+YVFCZE/6YcBHbMaAj ZNRgd6/oPUkEqA7d0z2+39lOFwKBgQDcXsf3iBRv8JZnDiLKSol6ig4IiIDumhVt gSfLYmRrycSa5nj0if76s1618WRiU3oNWHd9QCCgB0ju/faoQSo1s4q3rGMaACPX WczSudci0dxID47UrdQE3F0tj3nF9yJSqmyc9sgY16O34k5OvsCtCqOaWLXddXUj uqN6HZPhswKBgQDXDYpAoZI709puNTdOnN1Nwp9I8+JgTBmfv07IaIvbkdu4o3Pc 5MB/CoTOaqhZ8Iu3TXIXFz8pZcAm0gXcgKZPriwZ7KgI245YBovEMFj1/kaQqP4Q lS0KHSa058Yd/0iPYWGK3/h4T3WUDVKqau3VyAvEH+DsY023IqbVgP1IkwKBgDfs GYS4VK9fd1tpm+yH48Fj/VGvCkECewOR7f5P1rn/ttO0PueXiUwnbpZvTpEhK+zt EU2Ik37oulpjuk9SUhrUmBQqO+/iLzY8BJ1JKc4dQXBL+mwAPLiLD147daSGJYCi 3PMsMPUU6+gDFuomwBBpjcDiWCx93R8XAts/XEK/AoGAJrh0wA4SEkFV//FcS0k8 7J3ussV0xJf7QK156oZ0vTtgGQtKgJV7RQ6YoqlNoypTEcYy9pe1ygoab9PlGMDr h9oW2/ULzcdvFhQrN9LIZYtZUftbFOsnbC0VCUxM9X3jKqveuWdSUkanVxzhIm1o 5jNe8cr8Wy4nn6BCc0CShyE= -----END PRIVATE KEY----- rustls-v-0.21.10/bogo/keys/rsa_1024_cert.pem000066400000000000000000000012341453461710000203270ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBvzCCASigAwIBAgIJAPdX5ohr7khiMA0GCSqGSIb3DQEBBQUAMBcxFTATBgNV BAoMDGJvZ28tcnNhMTAyNDAeFw0xNzA4MjgxNDM1MjNaFw0yNzA4MjYxNDM1MjNa MBcxFTATBgNVBAoMDGJvZ28tcnNhMTAyNDCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEA65t1vhJG/nqeoNc21C6cfHJp1kTTx6kyOo5A/Ky5OEyGF+a3sDxdwQi0 w/kOr0Vk2EeSmbAaUv3RTGNAMDZgyFRULWQxOXZHHuKDxtKdMkDcWd/0eiI1wrXM u/0TpbHQZ13yLaj5Zj8/C3e9hcGefDTnu8cFzF1mNdGF9UOvUJECAwEAAaMTMBEw DwYDVR0RBAgwBoIEdGVzdDANBgkqhkiG9w0BAQUFAAOBgQCiQZyZwmeNBD1t5Hqb 5CtqSlRYRAqCOqJSoKoAFPwrvUo9q4oHnziqhmVNlzH+0/4YEDqzx/eNy+2nzaLs 5RSMG3bDRBW1azUtb9UX9XvErlswnrRhluoFBgpz7f/OgwGi7eenO9voVR/SzFHC nwSEnrKyp3TECXBSB0E57W8+AA== -----END CERTIFICATE----- rustls-v-0.21.10/bogo/keys/rsa_1024_key.pem000066400000000000000000000016241453461710000201650ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAOubdb4SRv56nqDX NtQunHxyadZE08epMjqOQPysuThMhhfmt7A8XcEItMP5Dq9FZNhHkpmwGlL90Uxj QDA2YMhUVC1kMTl2Rx7ig8bSnTJA3Fnf9HoiNcK1zLv9E6Wx0Gdd8i2o+WY/Pwt3 vYXBnnw057vHBcxdZjXRhfVDr1CRAgMBAAECgYAmX5GTvYJWnD4N0D+b22OdWT0n qtobYNFPfC/Vd4RLSRtl9SvhxlM2x2Y5rOzZWyILn8yev3HqJnDaUif4MkMcza8m OFLWUcklLF4tXFYKPIHlmEuX4BV1TwTlraxFSSNT9cK1jKgUtVu9tIMaqRRguq64 3pGG/LLVR8SYiF1YiQJBAPZQby60gA+At+P/aSdUhdRbQKMtg+99F3cuF+OcS6HT LxG+Gjy7GSH6W4RXrkhpjFDTAYzsmPhMHFYiMupmSscCQQD03z4NvsJngeHlu9KB Ip84Q9edKZPr49qTnMDp+ucA9fNXy57IQMNFQxQyHojZ4iaMRDm9hMDkaSZSnuUy oHHnAkADiGvP067yifoZPxSXB9NTlGt86640xSqM/xBAp4E+NPU73+oobNaTci/V 2hwZ1cm5bw1apBodlZnicmMgkY8JAkEAjSZV7bRk+Sc8IKHYoIllgBhTJAvAcXwB FY+JABaZq8saPyRnXYU/SiB1dsJ1HisnDzmQkvb//WnDJmLjOQCVRwJBAJKZ+EHy WNc8TWnnE1ZFO8ifBB0Nw21u0DjAwp7YeltufqCkkmgdrvWu9LNMmzAJY70Z6rd/ iAxe1vcHuPJ0R5k= -----END PRIVATE KEY----- rustls-v-0.21.10/bogo/keys/rsa_chain_cert.pem000066400000000000000000000043061453461710000210260ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICwDCCAaigAwIBAgIJAMxop1TANOUXMA0GCSqGSIb3DQEBCwUAMBUxEzARBgNV BAoMCmJvZ28tY2hhaW4wHhcNMTcwODI4MTQzNTIzWhcNMjcwODI2MTQzNTIzWjAV MRMwEQYDVQQKDApib2dvLWNoYWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA5Rmy9d0TK2CYkabdcLWP2t18G/VTI3tqQ248uLPHsu0Qwd1jnpvy+iSM 6wvj7HF28vRp7bH45LZYr0n3xBKO2Unq0FjGYrpd69f/RKSa7YiZOwRNcnvjH2sK /V8kpQVVWtFbifNwiyTKGTsI2B3itDuAofIobSV1q18QruEDOkZDqK98zxmlFctM IaZGCg+qVHSwoMOVSPvEffe4AApB+Y5BbBuPlx1TOLpD+chnfQxAC/SstrKgSP8W TipezQZ707p0XO3TvEMEZg474ZBmCdxDHgOAkxJWAHh+7/G7hyzK9OiknUH6m6Rj BEgKQM8Ts3UwjjVukXjpX04Y5e4NkwIDAQABoxMwETAPBgNVHREECDAGggR0ZXN0 MA0GCSqGSIb3DQEBCwUAA4IBAQDdlYbBnfLp87GTzA3EoflWccTKmqQXzz+cV7Ys Y8lyFkeNkI5bjdlA2OEvpC8qwP7t5ynWlGCaRLhu8DL5xYg/phdebnoDziExq4sx 8KDs94F8o5OrTLvhF5/54XXBmlQ5CBCrij/Yh5rEZYHp0WKeGeusJoAdNYsAsWBP ic9Kz5f1KGwVZRVwerFRHxn0d3TRApdr8Z08BEeFgf85GJ/NzgXgeVUPeY1zP29N d2YMjQkoftv8rDyPajzkRrA8m95kqBnBq7zS1RIJsOgyVj7euxBR3KImGveGv77E 60Md73BJ+G5PmEvMvA8ISpGwIKECUoPrF78nEnNzDebkMSL4 -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDYDCCAkigAwIBAgIJAMzVAHp+DLMaMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQwHhcNMTcwODI4MTQzNTIzWhcNMjcwODI2MTQzNTIzWjBF MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA2I/TeZbcYE4dtFHumC2BnklgZ58eoYO+GXQITbHauYmw3Zk2q6p73mfM P8zCA7ftEOQRA9rTKC4UsWY+Q8S4HML6Z/CtYgR8ZTx+tkO2NVmf9uP0xS6rxZAJ gcZFemnWM5nMk+4AXSR23nfVbHJ/mW1MpDOFP8wvSr1BrIrJojWVy7/9k6SuRWYK rK7FpwaSCk+X5U9R2i/RkVvtg58NLuGqpkxSMszpb0NbaG/sw0/s1a9sPEliBPOE HaiGOKB5xSIDXcIfoFx+3G4TwX97bT4wUP4OfwbyHZTXCWfXFGVtHq+038OrhEkc p4WjJm54oi5FOuNy9egspDKohbfw4wIDAQABo1MwUTAdBgNVHQ4EFgQUK+qMsG3P TWsWrsjmRtpSICfCFhEwHwYDVR0jBBgwFoAUK+qMsG3PTWsWrsjmRtpSICfCFhEw DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEALVCboVd/Kf3ofoqS 03S9aa2hXscDcvqPxhEhRosiunM3/qnXn3+SHJGvOKciXV+A/YCvwsvX4AeMxxH3 tSg55g+2hylFfk9hyTmNRKUMxQNZSbUpGtOz6vM9o8HgBP3KzS0mvHxRI5VNN8n3 wDcmjx/GCBbUOgRPzAIKIqpzKX7PNHF2imgf2HeDhWGIowNWE/GbuRg+tCxQY5ZZ vN9XxIttvrzTHh57sHntwUvAkc+EI5TJiD/VbUiBEfHt0vojU2lzEKuGmzKpuT/g vSu8+pGvI3lD1bNg26zniPOUxzGW93ZKS87af+bcicVvpVxsZ+OEgxyJhGdqZDjY IdjRtA== -----END CERTIFICATE----- rustls-v-0.21.10/bogo/keys/rsa_chain_key.pem000066400000000000000000000032501453461710000206560ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDlGbL13RMrYJiR pt1wtY/a3Xwb9VMje2pDbjy4s8ey7RDB3WOem/L6JIzrC+PscXby9Gntsfjktliv SffEEo7ZSerQWMZiul3r1/9EpJrtiJk7BE1ye+Mfawr9XySlBVVa0VuJ83CLJMoZ OwjYHeK0O4Ch8ihtJXWrXxCu4QM6RkOor3zPGaUVy0whpkYKD6pUdLCgw5VI+8R9 97gACkH5jkFsG4+XHVM4ukP5yGd9DEAL9Ky2sqBI/xZOKl7NBnvTunRc7dO8QwRm DjvhkGYJ3EMeA4CTElYAeH7v8buHLMr06KSdQfqbpGMESApAzxOzdTCONW6ReOlf Thjl7g2TAgMBAAECggEAWAI/VWPP8WHyOkG334xf7twWyUa84WyPrcezW+D0Xi/j uBWsJ0oRVTalS8YNkM8lur9Z0g4EZxgFiZEItTHL3n0ez1rLGzIs0mTvkxcIzSck dh95APnGjlM4rYzXLu2VlIXIfH4gRdOkL30WMK+KX2JcT9oO3Z7+TQ8AAa4+5ytM sPD5R4IIhbWcgd+yoGqRN44qBvaHrLUfX5xE9dH3HpgrRqKtJlmUlJBqQKsjPglE VQbpibh5cvJaEw3C9eiNi5CTd+ZFa8wlQgUtOJ8xjDl6a194u+qKu/UbcwcQv/aL 1pX8cYAfmFIABYaP5kRhFJ4kKN02XVlpMU4Zn/JEAQKBgQD7Rqtoxc+dEUabsvc8 vlrQl3GrqGapMGzpxaXQbtVc9up+EsNzmQwfkbm/RLaGhGSHG8FXODnObN1W4Mw/ j/X3DoCtFV/9gX49fOCP8iNFaBlCOVhYO9JS4XttW124CVBbBc4xpQn3VI42u5MF mwegk0FiRZjGfVqAncM1rV2GwQKBgQDpaE2szTifaFm3G6qt3DUzMuPtu+qP0K34 Ccr79tIB4gbTOVBsmOJQ3/nHUdpHYCoZG7A3eG6Jq4dhf1jaycJ4sGt90WuJF13c pjRuYLK9G/74Yj/makCDlW6N4LGV7TuTL8GBdGPEOp/PJWqxYVKPbK0/2sdz/YGq 8fONQbedUwKBgBaSR412z2p9hckwr1LOipvYLsbLrsUd63qoXXe2rQXXzEKc7t+w bM1dKsFKq9azh9A3Jwvtqgun7c4DDXXcOa0CqX5iwCemfS+KyyVDC/YNHs+7FPuA DCmTxaGSJn4EoCo9AEOnXpjQCKJUASXswiejcqkgNVQHKJ0LDuEAfLlBAoGBANxO 8jov/skf8saN2719Q83OtCs6Gz2hyAN+ItVO9IyIbs7Co3HNoJibwCTt0q1aTIIk i2DgUN2rRP62+ASTOfc29k7s86aToqnZS1X/+dXb7f8+pXf0RG6vBonuU1Djej8E bY6mcGDQwPUCKUHCTe5IswK5m1eVKeZTuAJVzF03AoGAGaKqUOlr108TV4hAU+/c VPQ/px4JWGFiXLfr83qBuGpOCwseMHNxIBfX4ByaFnQHS2hITt0CnqBmEjwrg5Er XFg7rlP1pNzKi/xDG7dJhf8BG0s2oaWDU9/ueM1Ub6G2hU8opv+8XTKxYTksRPLC E5B6+WXrANVFwnOw30zZKn4= -----END PRIVATE KEY----- rustls-v-0.21.10/bogo/regen-certs000077500000000000000000000053751453461710000165570ustar00rootroot00000000000000#!/usr/bin/env bash set -e rm -rf keys/ && mkdir -p keys/ # cert.pem/key.pem: rsa2048/sha256 self signed openssl req -batch -x509 \ -utf8 \ -newkey rsa:2048 \ -sha256 \ -days 3650 \ -nodes -keyout keys/key.pem \ -out keys/cert.pem \ -reqexts SAN \ -extensions SAN \ -config <(cat <> keys/rsa_chain_cert.pem # ecdsa_p256_cert.pem/ecdsa_p256_key.pem: ecdsap256/sha1(?) openssl req -batch -x509 \ -utf8 \ -newkey ec \ -pkeyopt ec_paramgen_curve:prime256v1 \ -sha1 \ -days 3650 \ -nodes -keyout keys/ecdsa_p256_key.pem \ -out keys/ecdsa_p256_cert.pem \ -reqexts SAN \ -extensions SAN \ -config <(cat < TlsClient { TlsClient::new(hostname) } #[test] fn no_cbc() { connect("cbc.badssl.com") .fails() .expect(r"TLS error: AlertReceived\(HandshakeFailure\)") .go() .unwrap(); } #[test] fn no_rc4() { connect("rc4.badssl.com") .fails() .expect(r"TLS error: AlertReceived\(HandshakeFailure\)") .go() .unwrap(); } #[test] fn expired() { connect("expired.badssl.com") .fails() .expect(r#"TLS error: InvalidCertificate\(Expired\)"#) .go() .unwrap(); } #[test] fn wrong_host() { connect("wrong.host.badssl.com") .fails() .expect(r#"TLS error: InvalidCertificate\(NotValidForName\)"#) .go() .unwrap(); } #[test] fn self_signed() { connect("self-signed.badssl.com") .fails() .expect(r#"TLS error: InvalidCertificate\(UnknownIssuer\)"#) .go() .unwrap(); } #[test] fn no_dh() { connect("dh2048.badssl.com") .fails() .expect(r"TLS error: AlertReceived\(HandshakeFailure\)") .go() .unwrap(); } #[test] fn mozilla_old() { connect("mozilla-old.badssl.com") .expect("mozilla-old.badssl.com") .go() .unwrap(); } #[test] fn mozilla_inter() { connect("mozilla-intermediate.badssl.com") .expect("mozilla-intermediate.badssl.com") .go() .unwrap(); } #[test] fn mozilla_modern() { connect("mozilla-modern.badssl.com") .expect("mozilla-modern.badssl.com") .go() .unwrap(); } #[test] fn sha256() { connect("sha256.badssl.com") .expect("sha256.badssl.com") .go() .unwrap(); } #[test] fn too_many_sans() { connect("10000-sans.badssl.com") .fails() .expect(r"TLS error: InvalidMessage\(HandshakePayloadTooLarge\)") .go() .unwrap(); } #[test] fn rsa8192() { connect("rsa8192.badssl.com") .expect("rsa8192.badssl.com") .go() .unwrap(); } #[test] fn sha1_2016() { connect("sha1-2016.badssl.com") .fails() .expect(r#"TLS error: InvalidCertificate\(Expired\)"#) .go() .unwrap(); } #[cfg(feature = "dangerous_configuration")] mod danger { #[test] fn self_signed() { super::connect("self-signed.badssl.com") .insecure() .expect("self-signed.badssl.com") .go() .unwrap(); } } } rustls-v-0.21.10/connect-tests/tests/common/000077500000000000000000000000001453461710000206765ustar00rootroot00000000000000rustls-v-0.21.10/connect-tests/tests/common/mod.rs000066400000000000000000000231451453461710000220300ustar00rootroot00000000000000use std::env; use std::net; use std::fs::{self, File}; use std::io::Write; use std::path::{Path, PathBuf}; use std::process; use std::str; use std::thread; use std::time; use self::regex::Regex; use regex; use ring::rand::SecureRandom; pub struct DeleteFilesOnDrop { path: PathBuf, } impl DeleteFilesOnDrop { pub fn path(&self) -> &PathBuf { &self.path } } impl Drop for DeleteFilesOnDrop { fn drop(&mut self) { fs::remove_dir_all(&self.path).unwrap(); } } macro_rules! embed_files { ( $( ($name:ident, $keytype:expr, $path:expr); )+ ) => { $( const $name: &'static [u8] = include_bytes!( concat!("../../../test-ca/", $keytype, "/", $path)); )+ pub fn bytes_for(keytype: &str, path: &str) -> &'static [u8] { match (keytype, path) { $( ($keytype, $path) => $name, )+ _ => panic!("unknown keytype {} with path {}", keytype, path), } } pub fn new_test_ca() -> DeleteFilesOnDrop { let mut rand = [0u8; 4]; ring::rand::SystemRandom::new() .fill(&mut rand) .unwrap(); let dir = env::temp_dir() .join(format!("rustls-{:02x}{:02x}{:02x}{:02x}", rand[0], rand[1], rand[2], rand[3])); let deleter = DeleteFilesOnDrop { path: dir, }; fs::create_dir(&deleter.path).unwrap(); fs::create_dir(deleter.path.join("ecdsa")).unwrap(); fs::create_dir(deleter.path.join("eddsa")).unwrap(); fs::create_dir(deleter.path.join("rsa")).unwrap(); $( let filename = deleter.path.join($keytype).join($path); let mut f = File::create(&filename).unwrap(); f.write_all($name).unwrap(); )+ deleter } } } embed_files! { (ECDSA_CA_CERT, "ecdsa", "ca.cert"); (ECDSA_CA_DER, "ecdsa", "ca.der"); (ECDSA_CA_KEY, "ecdsa", "ca.key"); (ECDSA_CLIENT_CERT, "ecdsa", "client.cert"); (ECDSA_CLIENT_CHAIN, "ecdsa", "client.chain"); (ECDSA_CLIENT_FULLCHAIN, "ecdsa", "client.fullchain"); (ECDSA_CLIENT_KEY, "ecdsa", "client.key"); (ECDSA_CLIENT_REQ, "ecdsa", "client.req"); (ECDSA_END_CERT, "ecdsa", "end.cert"); (ECDSA_END_CHAIN, "ecdsa", "end.chain"); (ECDSA_END_FULLCHAIN, "ecdsa", "end.fullchain"); (ECDSA_END_KEY, "ecdsa", "end.key"); (ECDSA_END_REQ, "ecdsa", "end.req"); (ECDSA_INTER_CERT, "ecdsa", "inter.cert"); (ECDSA_INTER_KEY, "ecdsa", "inter.key"); (ECDSA_INTER_REQ, "ecdsa", "inter.req"); (ECDSA_NISTP256_PEM, "ecdsa", "nistp256.pem"); (ECDSA_NISTP384_PEM, "ecdsa", "nistp384.pem"); (EDDSA_CA_CERT, "eddsa", "ca.cert"); (EDDSA_CA_DER, "eddsa", "ca.der"); (EDDSA_CA_KEY, "eddsa", "ca.key"); (EDDSA_CLIENT_CERT, "eddsa", "client.cert"); (EDDSA_CLIENT_CHAIN, "eddsa", "client.chain"); (EDDSA_CLIENT_FULLCHAIN, "eddsa", "client.fullchain"); (EDDSA_CLIENT_KEY, "eddsa", "client.key"); (EDDSA_CLIENT_REQ, "eddsa", "client.req"); (EDDSA_END_CERT, "eddsa", "end.cert"); (EDDSA_END_CHAIN, "eddsa", "end.chain"); (EDDSA_END_FULLCHAIN, "eddsa", "end.fullchain"); (EDDSA_END_KEY, "eddsa", "end.key"); (EDDSA_END_REQ, "eddsa", "end.req"); (EDDSA_INTER_CERT, "eddsa", "inter.cert"); (EDDSA_INTER_KEY, "eddsa", "inter.key"); (EDDSA_INTER_REQ, "eddsa", "inter.req"); (RSA_CA_CERT, "rsa", "ca.cert"); (RSA_CA_DER, "rsa", "ca.der"); (RSA_CA_KEY, "rsa", "ca.key"); (RSA_CLIENT_CERT, "rsa", "client.cert"); (RSA_CLIENT_CHAIN, "rsa", "client.chain"); (RSA_CLIENT_FULLCHAIN, "rsa", "client.fullchain"); (RSA_CLIENT_KEY, "rsa", "client.key"); (RSA_CLIENT_REQ, "rsa", "client.req"); (RSA_CLIENT_RSA, "rsa", "client.rsa"); (RSA_END_CERT, "rsa", "end.cert"); (RSA_END_CHAIN, "rsa", "end.chain"); (RSA_END_FULLCHAIN, "rsa", "end.fullchain"); (RSA_END_KEY, "rsa", "end.key"); (RSA_END_REQ, "rsa", "end.req"); (RSA_END_RSA, "rsa", "end.rsa"); (RSA_INTER_CERT, "rsa", "inter.cert"); (RSA_INTER_KEY, "rsa", "inter.key"); (RSA_INTER_REQ, "rsa", "inter.req"); } // Wait until we can connect to localhost:port. fn wait_for_port(port: u16) -> Option<()> { let mut count = 0; loop { thread::sleep(time::Duration::from_millis(500)); if net::TcpStream::connect(("127.0.0.1", port)).is_ok() { return Some(()); } count += 1; if count == 10 { return None; } } } // Find an unused port fn unused_port(mut port: u16) -> u16 { loop { if net::TcpStream::connect(("127.0.0.1", port)).is_err() { return port; } port += 1; } } pub fn tlsserver_find() -> &'static str { "../target/debug/tlsserver-mio" } pub fn tlsclient_find() -> &'static str { "../target/debug/tlsclient-mio" } pub struct TlsClient { pub hostname: String, pub port: u16, pub http: bool, pub cafile: Option, pub cache: Option, pub suites: Vec, pub no_sni: bool, pub insecure: bool, pub verbose: bool, pub max_fragment_size: Option, pub expect_fails: bool, pub expect_output: Vec, pub expect_log: Vec, } impl TlsClient { pub fn new(hostname: &str) -> Self { Self { hostname: hostname.to_string(), port: 443, http: true, cafile: None, cache: None, no_sni: false, insecure: false, verbose: false, max_fragment_size: None, suites: Vec::new(), expect_fails: false, expect_output: Vec::new(), expect_log: Vec::new(), } } pub fn cafile(&mut self, cafile: &Path) -> &mut Self { self.cafile = Some(cafile.to_path_buf()); self } pub fn cache(&mut self, cache: &str) -> &mut Self { self.cache = Some(cache.to_string()); self } pub fn no_sni(&mut self) -> &mut Self { self.no_sni = true; self } pub fn insecure(&mut self) -> &mut Self { self.insecure = true; self } pub fn verbose(&mut self) -> &mut Self { self.verbose = true; self } pub fn max_fragment_size(&mut self, max_fragment_size: usize) -> &mut Self { self.max_fragment_size = Some(max_fragment_size); self } pub fn port(&mut self, port: u16) -> &mut Self { self.port = port; self } pub fn expect(&mut self, expect: &str) -> &mut Self { self.expect_output .push(expect.to_string()); self } pub fn expect_log(&mut self, expect: &str) -> &mut Self { self.verbose = true; self.expect_log.push(expect.to_string()); self } pub fn suite(&mut self, suite: &str) -> &mut Self { self.suites.push(suite.to_string()); self } pub fn fails(&mut self) -> &mut Self { self.expect_fails = true; self } pub fn go(&mut self) -> Option<()> { let fragstring; let portstring = self.port.to_string(); let mut args = Vec::<&str>::new(); args.push(&self.hostname); args.push("--port"); args.push(&portstring); if self.http { args.push("--http"); } if self.cache.is_some() { args.push("--cache"); args.push(self.cache.as_ref().unwrap()); } if self.no_sni { args.push("--no-sni"); } if self.insecure { args.push("--insecure"); } if self.cafile.is_some() { args.push("--cafile"); args.push( self.cafile .as_ref() .unwrap() .to_str() .unwrap(), ); } for suite in &self.suites { args.push("--suite"); args.push(suite.as_ref()); } if self.verbose { args.push("--verbose"); } if self.max_fragment_size.is_some() { args.push("--max-frag-size"); fragstring = self .max_fragment_size .unwrap() .to_string(); args.push(&fragstring); } let output = process::Command::new(tlsclient_find()) .args(&args) .env("SSLKEYLOGFILE", "./sslkeylogfile.txt") .output() .unwrap_or_else(|e| panic!("failed to execute: {}", e)); let stdout_str = String::from_utf8_lossy(&output.stdout); let stderr_str = String::from_utf8_lossy(&output.stderr); for expect in &self.expect_output { let re = Regex::new(expect).unwrap(); if re.find(&stdout_str).is_none() { println!("We expected to find '{}' in the following output:", expect); println!("{:?}", output); panic!("Test failed"); } } for expect in &self.expect_log { let re = Regex::new(expect).unwrap(); if re.find(&stderr_str).is_none() { println!("We expected to find '{}' in the following output:", expect); println!("{:?}", output); panic!("Test failed"); } } if self.expect_fails { assert!(output.status.code().unwrap() != 0); } else { assert!(output.status.success()); } Some(()) } } rustls-v-0.21.10/connect-tests/tests/topsites.rs000066400000000000000000000023671453461710000216360ustar00rootroot00000000000000// These tests check we can handshake with a selection of // common hosts. // // Rules: only hosts that can really handle the traffic. #[allow(dead_code)] mod common; mod online { use super::common::TlsClient; fn check(hostname: &str) { TlsClient::new(hostname) .expect("HTTP/1.[01] ") .go() .unwrap() } #[test] fn joe() { check("jbp.io") } #[test] fn google() { check("google.com") } #[test] fn github() { check("github.com") } #[test] fn aws() { check("aws.amazon.com") } #[test] fn microsoft() { check("www.microsoft.com") } #[test] fn wikipedia() { check("www.wikipedia.org") } #[test] fn twitter() { check("twitter.com") } #[test] fn facebook() { check("www.facebook.com") } #[test] fn baidu() { check("www.baidu.com") } #[test] fn netflix() { check("www.netflix.com") } #[test] fn stackoverflow() { check("stackoverflow.com") } #[test] fn apple() { check("www.apple.com") } #[test] fn cloudflare_1_1_1_1_dns() { check("1.1.1.1") } } rustls-v-0.21.10/examples/000077500000000000000000000000001453461710000152715ustar00rootroot00000000000000rustls-v-0.21.10/examples/Cargo.toml000066400000000000000000000011351453461710000172210ustar00rootroot00000000000000[package] name = "rustls-examples" version = "0.0.1" edition = "2021" license = "Apache-2.0 OR ISC OR MIT" description = "Rustls example code and tests." publish = false [features] dangerous_configuration = ["rustls/dangerous_configuration"] quic = ["rustls/quic"] [dependencies] docopt = "~1.1" env_logger = "0.10" log = { version = "0.4.4" } mio = { version = "0.8", features = ["net", "os-poll"] } rustls = { path = "../rustls", features = [ "logging" ]} rustls-pemfile = "1.0.3" sct = "0.7" serde = "1.0" serde_derive = "1.0" webpki-roots = "0.25" [dev-dependencies] regex = "1.0" ring = "0.16.20" rustls-v-0.21.10/examples/src/000077500000000000000000000000001453461710000160605ustar00rootroot00000000000000rustls-v-0.21.10/examples/src/bin/000077500000000000000000000000001453461710000166305ustar00rootroot00000000000000rustls-v-0.21.10/examples/src/bin/limitedclient.rs000066400000000000000000000037321453461710000220310ustar00rootroot00000000000000/// limitedclient: This example demonstrates usage of ClientConfig building /// so that unused cryptography in rustls can be discarded by the linker. You can /// observe using `nm` that the binary of this program does not contain any AES code. use std::sync::Arc; use std::io::{stdout, Read, Write}; use std::net::TcpStream; use rustls::OwnedTrustAnchor; fn main() { let mut root_store = rustls::RootCertStore::empty(); root_store.add_trust_anchors( webpki_roots::TLS_SERVER_ROOTS .iter() .map(|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, ta.name_constraints, ) }), ); let config = rustls::ClientConfig::builder() .with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]) .with_kx_groups(&[&rustls::kx_group::X25519]) .with_protocol_versions(&[&rustls::version::TLS13]) .unwrap() .with_root_certificates(root_store) .with_no_client_auth(); let server_name = "www.rust-lang.org".try_into().unwrap(); let mut conn = rustls::ClientConnection::new(Arc::new(config), server_name).unwrap(); let mut sock = TcpStream::connect("www.rust-lang.org:443").unwrap(); let mut tls = rustls::Stream::new(&mut conn, &mut sock); tls.write_all( concat!( "GET / HTTP/1.1\r\n", "Host: www.rust-lang.org\r\n", "Connection: close\r\n", "Accept-Encoding: identity\r\n", "\r\n" ) .as_bytes(), ) .unwrap(); let ciphersuite = tls .conn .negotiated_cipher_suite() .unwrap(); writeln!( &mut std::io::stderr(), "Current ciphersuite: {:?}", ciphersuite.suite() ) .unwrap(); let mut plaintext = Vec::new(); tls.read_to_end(&mut plaintext).unwrap(); stdout().write_all(&plaintext).unwrap(); } rustls-v-0.21.10/examples/src/bin/simple_0rtt_client.rs000066400000000000000000000052611453461710000230020ustar00rootroot00000000000000use std::sync::Arc; use std::io::{BufRead, BufReader, Write}; use std::net::TcpStream; use rustls::{OwnedTrustAnchor, RootCertStore}; fn start_connection(config: &Arc, domain_name: &str) { let server_name = domain_name .try_into() .expect("invalid DNS name"); let mut conn = rustls::ClientConnection::new(Arc::clone(config), server_name).unwrap(); let mut sock = TcpStream::connect(format!("{}:443", domain_name)).unwrap(); sock.set_nodelay(true).unwrap(); let request = format!( "GET / HTTP/1.1\r\n\ Host: {}\r\n\ Connection: close\r\n\ Accept-Encoding: identity\r\n\ \r\n", domain_name ); // If early data is available with this server, then early_data() // will yield Some(WriteEarlyData) and WriteEarlyData implements // io::Write. Use this to send the request. if let Some(mut early_data) = conn.early_data() { early_data .write_all(request.as_bytes()) .unwrap(); println!(" * 0-RTT request sent"); } let mut stream = rustls::Stream::new(&mut conn, &mut sock); // Complete handshake. stream.flush().unwrap(); // If we didn't send early data, or the server didn't accept it, // then send the request as normal. if !stream.conn.is_early_data_accepted() { stream .write_all(request.as_bytes()) .unwrap(); println!(" * Normal request sent"); } else { println!(" * 0-RTT data accepted"); } let mut first_response_line = String::new(); BufReader::new(stream) .read_line(&mut first_response_line) .unwrap(); println!(" * Server response: {:?}", first_response_line); } fn main() { env_logger::init(); let mut root_store = RootCertStore::empty(); root_store.add_trust_anchors( webpki_roots::TLS_SERVER_ROOTS .iter() .map(|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, ta.name_constraints, ) }), ); let mut config = rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_no_client_auth(); // Enable early data. config.enable_early_data = true; let config = Arc::new(config); // Do two connections. The first will be a normal request, the // second will use early data if the server supports it. println!("* Sending first request:"); start_connection(&config, "jbp.io"); println!("* Sending second request:"); start_connection(&config, "jbp.io"); } rustls-v-0.21.10/examples/src/bin/simpleclient.rs000066400000000000000000000041331453461710000216670ustar00rootroot00000000000000/// This is the simplest possible client using rustls that does something useful: /// it accepts the default configuration, loads some root certs, and then connects /// to google.com and issues a basic HTTP request. The response is printed to stdout. /// /// It makes use of rustls::Stream to treat the underlying TLS connection as a basic /// bi-directional stream -- the underlying IO is performed transparently. /// /// Note that `unwrap()` is used to deal with networking errors; this is not something /// that is sensible outside of example code. use std::sync::Arc; use std::io::{stdout, Read, Write}; use std::net::TcpStream; use rustls::{OwnedTrustAnchor, RootCertStore}; fn main() { let mut root_store = RootCertStore::empty(); root_store.add_trust_anchors( webpki_roots::TLS_SERVER_ROOTS .iter() .map(|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, ta.name_constraints, ) }), ); let config = rustls::ClientConfig::builder() .with_safe_defaults() .with_root_certificates(root_store) .with_no_client_auth(); let server_name = "www.rust-lang.org".try_into().unwrap(); let mut conn = rustls::ClientConnection::new(Arc::new(config), server_name).unwrap(); let mut sock = TcpStream::connect("www.rust-lang.org:443").unwrap(); let mut tls = rustls::Stream::new(&mut conn, &mut sock); tls.write_all( concat!( "GET / HTTP/1.1\r\n", "Host: www.rust-lang.org\r\n", "Connection: close\r\n", "Accept-Encoding: identity\r\n", "\r\n" ) .as_bytes(), ) .unwrap(); let ciphersuite = tls .conn .negotiated_cipher_suite() .unwrap(); writeln!( &mut std::io::stderr(), "Current ciphersuite: {:?}", ciphersuite.suite() ) .unwrap(); let mut plaintext = Vec::new(); tls.read_to_end(&mut plaintext).unwrap(); stdout().write_all(&plaintext).unwrap(); } rustls-v-0.21.10/examples/src/bin/tlsclient-mio.rs000066400000000000000000000360661453461710000217740ustar00rootroot00000000000000use std::process; use std::sync::Arc; use mio::net::TcpStream; use std::fs; use std::io; use std::io::{BufReader, Read, Write}; use std::net::SocketAddr; use std::str; #[macro_use] extern crate serde_derive; use docopt::Docopt; use rustls::{OwnedTrustAnchor, RootCertStore}; const CLIENT: mio::Token = mio::Token(0); /// This encapsulates the TCP-level connection, some connection /// state, and the underlying TLS-level session. struct TlsClient { socket: TcpStream, closing: bool, clean_closure: bool, tls_conn: rustls::ClientConnection, } impl TlsClient { fn new( sock: TcpStream, server_name: rustls::ServerName, cfg: Arc, ) -> Self { Self { socket: sock, closing: false, clean_closure: false, tls_conn: rustls::ClientConnection::new(cfg, server_name).unwrap(), } } /// Handles events sent to the TlsClient by mio::Poll fn ready(&mut self, ev: &mio::event::Event) { assert_eq!(ev.token(), CLIENT); if ev.is_readable() { self.do_read(); } if ev.is_writable() { self.do_write(); } if self.is_closed() { println!("Connection closed"); process::exit(if self.clean_closure { 0 } else { 1 }); } } fn read_source_to_end(&mut self, rd: &mut dyn io::Read) -> io::Result { let mut buf = Vec::new(); let len = rd.read_to_end(&mut buf)?; self.tls_conn .writer() .write_all(&buf) .unwrap(); Ok(len) } /// We're ready to do a read. fn do_read(&mut self) { // Read TLS data. This fails if the underlying TCP connection // is broken. match self.tls_conn.read_tls(&mut self.socket) { Err(error) => { if error.kind() == io::ErrorKind::WouldBlock { return; } println!("TLS read error: {:?}", error); self.closing = true; return; } // If we're ready but there's no data: EOF. Ok(0) => { println!("EOF"); self.closing = true; self.clean_closure = true; return; } Ok(_) => {} }; // Reading some TLS data might have yielded new TLS // messages to process. Errors from this indicate // TLS protocol problems and are fatal. let io_state = match self.tls_conn.process_new_packets() { Ok(io_state) => io_state, Err(err) => { println!("TLS error: {:?}", err); self.closing = true; return; } }; // Having read some TLS data, and processed any new messages, // we might have new plaintext as a result. // // Read it and then write it to stdout. if io_state.plaintext_bytes_to_read() > 0 { let mut plaintext = vec![0u8; io_state.plaintext_bytes_to_read()]; self.tls_conn .reader() .read_exact(&mut plaintext) .unwrap(); io::stdout() .write_all(&plaintext) .unwrap(); } // If wethat fails, the peer might have started a clean TLS-level // session closure. if io_state.peer_has_closed() { self.clean_closure = true; self.closing = true; } } fn do_write(&mut self) { self.tls_conn .write_tls(&mut self.socket) .unwrap(); } /// Registers self as a 'listener' in mio::Registry fn register(&mut self, registry: &mio::Registry) { let interest = self.event_set(); registry .register(&mut self.socket, CLIENT, interest) .unwrap(); } /// Reregisters self as a 'listener' in mio::Registry. fn reregister(&mut self, registry: &mio::Registry) { let interest = self.event_set(); registry .reregister(&mut self.socket, CLIENT, interest) .unwrap(); } /// Use wants_read/wants_write to register for different mio-level /// IO readiness events. fn event_set(&self) -> mio::Interest { let rd = self.tls_conn.wants_read(); let wr = self.tls_conn.wants_write(); if rd && wr { mio::Interest::READABLE | mio::Interest::WRITABLE } else if wr { mio::Interest::WRITABLE } else { mio::Interest::READABLE } } fn is_closed(&self) -> bool { self.closing } } impl io::Write for TlsClient { fn write(&mut self, bytes: &[u8]) -> io::Result { self.tls_conn.writer().write(bytes) } fn flush(&mut self) -> io::Result<()> { self.tls_conn.writer().flush() } } impl io::Read for TlsClient { fn read(&mut self, bytes: &mut [u8]) -> io::Result { self.tls_conn.reader().read(bytes) } } const USAGE: &str = " Connects to the TLS server at hostname:PORT. The default PORT is 443. By default, this reads a request from stdin (to EOF) before making the connection. --http replaces this with a basic HTTP GET request for /. If --cafile is not supplied, a built-in set of CA certificates are used from the webpki-roots crate. Usage: tlsclient-mio [options] [--suite SUITE ...] [--proto PROTO ...] [--protover PROTOVER ...] tlsclient-mio (--version | -v) tlsclient-mio (--help | -h) Options: -p, --port PORT Connect to PORT [default: 443]. --http Send a basic HTTP GET request for /. --cafile CAFILE Read root certificates from CAFILE. --auth-key KEY Read client authentication key from KEY. --auth-certs CERTS Read client authentication certificates from CERTS. CERTS must match up with KEY. --protover VERSION Disable default TLS version list, and use VERSION instead. May be used multiple times. --suite SUITE Disable default cipher suite list, and use SUITE instead. May be used multiple times. --proto PROTOCOL Send ALPN extension containing PROTOCOL. May be used multiple times to offer several protocols. --no-tickets Disable session ticket support. --no-sni Disable server name indication support. --insecure Disable certificate verification. --verbose Emit log output. --max-frag-size M Limit outgoing messages to M bytes. --version, -v Show tool version. --help, -h Show this screen. "; #[derive(Debug, Deserialize)] struct Args { flag_port: Option, flag_http: bool, flag_verbose: bool, flag_protover: Vec, flag_suite: Vec, flag_proto: Vec, flag_max_frag_size: Option, flag_cafile: Option, flag_no_tickets: bool, flag_no_sni: bool, flag_insecure: bool, flag_auth_key: Option, flag_auth_certs: Option, arg_hostname: String, } // TODO: um, well, it turns out that openssl s_client/s_server // that we use for testing doesn't do ipv6. So we can't actually // test ipv6 and hence kill this. fn lookup_ipv4(host: &str, port: u16) -> SocketAddr { use std::net::ToSocketAddrs; let addrs = (host, port).to_socket_addrs().unwrap(); for addr in addrs { if let SocketAddr::V4(_) = addr { return addr; } } unreachable!("Cannot lookup address"); } /// Find a ciphersuite with the given name fn find_suite(name: &str) -> Option { for suite in rustls::ALL_CIPHER_SUITES { let sname = format!("{:?}", suite.suite()).to_lowercase(); if sname == name.to_string().to_lowercase() { return Some(*suite); } } None } /// Make a vector of ciphersuites named in `suites` fn lookup_suites(suites: &[String]) -> Vec { let mut out = Vec::new(); for csname in suites { let scs = find_suite(csname); match scs { Some(s) => out.push(s), None => panic!("cannot look up ciphersuite '{}'", csname), } } out } /// Make a vector of protocol versions named in `versions` fn lookup_versions(versions: &[String]) -> Vec<&'static rustls::SupportedProtocolVersion> { let mut out = Vec::new(); for vname in versions { let version = match vname.as_ref() { "1.2" => &rustls::version::TLS12, "1.3" => &rustls::version::TLS13, _ => panic!( "cannot look up version '{}', valid are '1.2' and '1.3'", vname ), }; out.push(version); } out } fn load_certs(filename: &str) -> Vec { let certfile = fs::File::open(filename).expect("cannot open certificate file"); let mut reader = BufReader::new(certfile); rustls_pemfile::certs(&mut reader) .unwrap() .iter() .map(|v| rustls::Certificate(v.clone())) .collect() } fn load_private_key(filename: &str) -> rustls::PrivateKey { let keyfile = fs::File::open(filename).expect("cannot open private key file"); let mut reader = BufReader::new(keyfile); loop { match rustls_pemfile::read_one(&mut reader).expect("cannot parse private key .pem file") { Some(rustls_pemfile::Item::RSAKey(key)) => return rustls::PrivateKey(key), Some(rustls_pemfile::Item::PKCS8Key(key)) => return rustls::PrivateKey(key), Some(rustls_pemfile::Item::ECKey(key)) => return rustls::PrivateKey(key), None => break, _ => {} } } panic!( "no keys found in {:?} (encrypted keys not supported)", filename ); } #[cfg(feature = "dangerous_configuration")] mod danger { pub struct NoCertificateVerification {} impl rustls::client::ServerCertVerifier for NoCertificateVerification { fn verify_server_cert( &self, _end_entity: &rustls::Certificate, _intermediates: &[rustls::Certificate], _server_name: &rustls::ServerName, _scts: &mut dyn Iterator, _ocsp: &[u8], _now: std::time::SystemTime, ) -> Result { Ok(rustls::client::ServerCertVerified::assertion()) } } } #[cfg(feature = "dangerous_configuration")] fn apply_dangerous_options(args: &Args, cfg: &mut rustls::ClientConfig) { if args.flag_insecure { cfg.dangerous() .set_certificate_verifier(Arc::new(danger::NoCertificateVerification {})); } } #[cfg(not(feature = "dangerous_configuration"))] fn apply_dangerous_options(args: &Args, _: &mut rustls::ClientConfig) { if args.flag_insecure { panic!("This build does not support --insecure."); } } /// Build a `ClientConfig` from our arguments fn make_config(args: &Args) -> Arc { let mut root_store = RootCertStore::empty(); if args.flag_cafile.is_some() { let cafile = args.flag_cafile.as_ref().unwrap(); let certfile = fs::File::open(cafile).expect("Cannot open CA file"); let mut reader = BufReader::new(certfile); root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut reader).unwrap()); } else { root_store.add_trust_anchors( webpki_roots::TLS_SERVER_ROOTS .iter() .map(|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, ta.name_constraints, ) }), ); } let suites = if !args.flag_suite.is_empty() { lookup_suites(&args.flag_suite) } else { rustls::DEFAULT_CIPHER_SUITES.to_vec() }; let versions = if !args.flag_protover.is_empty() { lookup_versions(&args.flag_protover) } else { rustls::DEFAULT_VERSIONS.to_vec() }; let config = rustls::ClientConfig::builder() .with_cipher_suites(&suites) .with_safe_default_kx_groups() .with_protocol_versions(&versions) .expect("inconsistent cipher-suite/versions selected") .with_root_certificates(root_store); let mut config = match (&args.flag_auth_key, &args.flag_auth_certs) { (Some(key_file), Some(certs_file)) => { let certs = load_certs(certs_file); let key = load_private_key(key_file); config .with_client_auth_cert(certs, key) .expect("invalid client auth certs/key") } (None, None) => config.with_no_client_auth(), (_, _) => { panic!("must provide --auth-certs and --auth-key together"); } }; config.key_log = Arc::new(rustls::KeyLogFile::new()); if args.flag_no_tickets { config.resumption = config .resumption .tls12_resumption(rustls::client::Tls12Resumption::SessionIdOnly); } if args.flag_no_sni { config.enable_sni = false; } config.alpn_protocols = args .flag_proto .iter() .map(|proto| proto.as_bytes().to_vec()) .collect(); config.max_fragment_size = args.flag_max_frag_size; apply_dangerous_options(args, &mut config); Arc::new(config) } /// Parse some arguments, then make a TLS client connection /// somewhere. fn main() { let version = env!("CARGO_PKG_NAME").to_string() + ", version: " + env!("CARGO_PKG_VERSION"); let args: Args = Docopt::new(USAGE) .map(|d| d.help(true)) .map(|d| d.version(Some(version))) .and_then(|d| d.deserialize()) .unwrap_or_else(|e| e.exit()); if args.flag_verbose { env_logger::Builder::new() .parse_filters("trace") .init(); } let port = args.flag_port.unwrap_or(443); let addr = lookup_ipv4(args.arg_hostname.as_str(), port); let config = make_config(&args); let sock = TcpStream::connect(addr).unwrap(); let server_name = args .arg_hostname .as_str() .try_into() .expect("invalid DNS name"); let mut tlsclient = TlsClient::new(sock, server_name, config); if args.flag_http { let httpreq = format!( "GET / HTTP/1.0\r\nHost: {}\r\nConnection: \ close\r\nAccept-Encoding: identity\r\n\r\n", args.arg_hostname ); tlsclient .write_all(httpreq.as_bytes()) .unwrap(); } else { let mut stdin = io::stdin(); tlsclient .read_source_to_end(&mut stdin) .unwrap(); } let mut poll = mio::Poll::new().unwrap(); let mut events = mio::Events::with_capacity(32); tlsclient.register(poll.registry()); loop { poll.poll(&mut events, None).unwrap(); for ev in events.iter() { tlsclient.ready(ev); tlsclient.reregister(poll.registry()); } } } rustls-v-0.21.10/examples/src/bin/tlsserver-mio.rs000066400000000000000000000506301453461710000220150ustar00rootroot00000000000000use std::sync::Arc; use mio::net::{TcpListener, TcpStream}; #[macro_use] extern crate log; use std::collections::HashMap; use std::fs; use std::io; use std::io::{BufReader, Read, Write}; use std::net; #[macro_use] extern crate serde_derive; use docopt::Docopt; use rustls::server::{ AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, NoClientAuth, UnparsedCertRevocationList, }; use rustls::{self, RootCertStore}; // Token for our listening socket. const LISTENER: mio::Token = mio::Token(0); // Which mode the server operates in. #[derive(Clone)] enum ServerMode { /// Write back received bytes Echo, /// Do one read, then write a bodged HTTP response and /// cleanly close the connection. Http, /// Forward traffic to/from given port on localhost. Forward(u16), } /// This binds together a TCP listening socket, some outstanding /// connections, and a TLS server configuration. struct TlsServer { server: TcpListener, connections: HashMap, next_id: usize, tls_config: Arc, mode: ServerMode, } impl TlsServer { fn new(server: TcpListener, mode: ServerMode, cfg: Arc) -> Self { Self { server, connections: HashMap::new(), next_id: 2, tls_config: cfg, mode, } } fn accept(&mut self, registry: &mio::Registry) -> Result<(), io::Error> { loop { match self.server.accept() { Ok((socket, addr)) => { debug!("Accepting new connection from {:?}", addr); let tls_conn = rustls::ServerConnection::new(Arc::clone(&self.tls_config)).unwrap(); let mode = self.mode.clone(); let token = mio::Token(self.next_id); self.next_id += 1; let mut connection = OpenConnection::new(socket, token, mode, tls_conn); connection.register(registry); self.connections .insert(token, connection); } Err(ref err) if err.kind() == io::ErrorKind::WouldBlock => return Ok(()), Err(err) => { println!( "encountered error while accepting connection; err={:?}", err ); return Err(err); } } } } fn conn_event(&mut self, registry: &mio::Registry, event: &mio::event::Event) { let token = event.token(); if self.connections.contains_key(&token) { self.connections .get_mut(&token) .unwrap() .ready(registry, event); if self.connections[&token].is_closed() { self.connections.remove(&token); } } } } /// This is a connection which has been accepted by the server, /// and is currently being served. /// /// It has a TCP-level stream, a TLS-level connection state, and some /// other state/metadata. struct OpenConnection { socket: TcpStream, token: mio::Token, closing: bool, closed: bool, mode: ServerMode, tls_conn: rustls::ServerConnection, back: Option, sent_http_response: bool, } /// Open a plaintext TCP-level connection for forwarded connections. fn open_back(mode: &ServerMode) -> Option { match *mode { ServerMode::Forward(ref port) => { let addr = net::SocketAddrV4::new(net::Ipv4Addr::new(127, 0, 0, 1), *port); let conn = TcpStream::connect(net::SocketAddr::V4(addr)).unwrap(); Some(conn) } _ => None, } } /// This used to be conveniently exposed by mio: map EWOULDBLOCK /// errors to something less-errory. fn try_read(r: io::Result) -> io::Result> { match r { Ok(len) => Ok(Some(len)), Err(e) => { if e.kind() == io::ErrorKind::WouldBlock { Ok(None) } else { Err(e) } } } } impl OpenConnection { fn new( socket: TcpStream, token: mio::Token, mode: ServerMode, tls_conn: rustls::ServerConnection, ) -> Self { let back = open_back(&mode); Self { socket, token, closing: false, closed: false, mode, tls_conn, back, sent_http_response: false, } } /// We're a connection, and we have something to do. fn ready(&mut self, registry: &mio::Registry, ev: &mio::event::Event) { // If we're readable: read some TLS. Then // see if that yielded new plaintext. Then // see if the backend is readable too. if ev.is_readable() { self.do_tls_read(); self.try_plain_read(); self.try_back_read(); } if ev.is_writable() { self.do_tls_write_and_handle_error(); } if self.closing { let _ = self .socket .shutdown(net::Shutdown::Both); self.close_back(); self.closed = true; self.deregister(registry); } else { self.reregister(registry); } } /// Close the backend connection for forwarded sessions. fn close_back(&mut self) { if self.back.is_some() { let back = self.back.as_mut().unwrap(); back.shutdown(net::Shutdown::Both) .unwrap(); } self.back = None; } fn do_tls_read(&mut self) { // Read some TLS data. match self.tls_conn.read_tls(&mut self.socket) { Err(err) => { if let io::ErrorKind::WouldBlock = err.kind() { return; } error!("read error {:?}", err); self.closing = true; return; } Ok(0) => { debug!("eof"); self.closing = true; return; } Ok(_) => {} }; // Process newly-received TLS messages. if let Err(err) = self.tls_conn.process_new_packets() { error!("cannot process packet: {:?}", err); // last gasp write to send any alerts self.do_tls_write_and_handle_error(); self.closing = true; } } fn try_plain_read(&mut self) { // Read and process all available plaintext. if let Ok(io_state) = self.tls_conn.process_new_packets() { if io_state.plaintext_bytes_to_read() > 0 { let mut buf = vec![0u8; io_state.plaintext_bytes_to_read()]; self.tls_conn .reader() .read_exact(&mut buf) .unwrap(); debug!("plaintext read {:?}", buf.len()); self.incoming_plaintext(&buf); } } } fn try_back_read(&mut self) { if self.back.is_none() { return; } // Try a non-blocking read. let mut buf = [0u8; 1024]; let back = self.back.as_mut().unwrap(); let rc = try_read(back.read(&mut buf)); if rc.is_err() { error!("backend read failed: {:?}", rc); self.closing = true; return; } let maybe_len = rc.unwrap(); // If we have a successful but empty read, that's an EOF. // Otherwise, we shove the data into the TLS session. match maybe_len { Some(0) => { debug!("back eof"); self.closing = true; } Some(len) => { self.tls_conn .writer() .write_all(&buf[..len]) .unwrap(); } None => {} }; } /// Process some amount of received plaintext. fn incoming_plaintext(&mut self, buf: &[u8]) { match self.mode { ServerMode::Echo => { self.tls_conn .writer() .write_all(buf) .unwrap(); } ServerMode::Http => { self.send_http_response_once(); } ServerMode::Forward(_) => { self.back .as_mut() .unwrap() .write_all(buf) .unwrap(); } } } fn send_http_response_once(&mut self) { let response = b"HTTP/1.0 200 OK\r\nConnection: close\r\n\r\nHello world from rustls tlsserver\r\n"; if !self.sent_http_response { self.tls_conn .writer() .write_all(response) .unwrap(); self.sent_http_response = true; self.tls_conn.send_close_notify(); } } fn tls_write(&mut self) -> io::Result { self.tls_conn .write_tls(&mut self.socket) } fn do_tls_write_and_handle_error(&mut self) { let rc = self.tls_write(); if rc.is_err() { error!("write failed {:?}", rc); self.closing = true; } } fn register(&mut self, registry: &mio::Registry) { let event_set = self.event_set(); registry .register(&mut self.socket, self.token, event_set) .unwrap(); if self.back.is_some() { registry .register( self.back.as_mut().unwrap(), self.token, mio::Interest::READABLE, ) .unwrap(); } } fn reregister(&mut self, registry: &mio::Registry) { let event_set = self.event_set(); registry .reregister(&mut self.socket, self.token, event_set) .unwrap(); } fn deregister(&mut self, registry: &mio::Registry) { registry .deregister(&mut self.socket) .unwrap(); if self.back.is_some() { registry .deregister(self.back.as_mut().unwrap()) .unwrap(); } } /// What IO events we're currently waiting for, /// based on wants_read/wants_write. fn event_set(&self) -> mio::Interest { let rd = self.tls_conn.wants_read(); let wr = self.tls_conn.wants_write(); if rd && wr { mio::Interest::READABLE | mio::Interest::WRITABLE } else if wr { mio::Interest::WRITABLE } else { mio::Interest::READABLE } } fn is_closed(&self) -> bool { self.closed } } const USAGE: &str = " Runs a TLS server on :PORT. The default PORT is 443. `echo' mode means the server echoes received data on each connection. `http' mode means the server blindly sends a HTTP response on each connection. `forward' means the server forwards plaintext to a connection made to localhost:fport. `--certs' names the full certificate chain, `--key' provides the RSA private key. Usage: tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] \ [--proto PROTO ...] [--protover PROTOVER ...] [options] echo tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] \ [--proto PROTO ...] [--protover PROTOVER ...] [options] http tlsserver-mio --certs CERTFILE --key KEYFILE [--suite SUITE ...] \ [--proto PROTO ...] [--protover PROTOVER ...] [options] forward tlsserver-mio (--version | -v) tlsserver-mio (--help | -h) Options: -p, --port PORT Listen on PORT [default: 443]. --certs CERTFILE Read server certificates from CERTFILE. This should contain PEM-format certificates in the right order (the first certificate should certify KEYFILE, the last should be a root CA). --key KEYFILE Read private key from KEYFILE. This should be a RSA private key or PKCS8-encoded private key, in PEM format. --ocsp OCSPFILE Read DER-encoded OCSP response from OCSPFILE and staple to certificate. Optional. --auth CERTFILE Enable client authentication, and accept certificates signed by those roots provided in CERTFILE. --crl CRLFILE ... Perform client certificate revocation checking using the DER-encoded CRLFILE. May be used multiple times. --require-auth Send a fatal alert if the client does not complete client authentication. --resumption Support session resumption. --tickets Support tickets. --protover VERSION Disable default TLS version list, and use VERSION instead. May be used multiple times. --suite SUITE Disable default cipher suite list, and use SUITE instead. May be used multiple times. --proto PROTOCOL Negotiate PROTOCOL using ALPN. May be used multiple times. --verbose Emit log output. --version, -v Show tool version. --help, -h Show this screen. "; #[derive(Debug, Deserialize)] struct Args { cmd_echo: bool, cmd_http: bool, flag_port: Option, flag_verbose: bool, flag_protover: Vec, flag_suite: Vec, flag_proto: Vec, flag_certs: Option, flag_crl: Vec, flag_key: Option, flag_ocsp: Option, flag_auth: Option, flag_require_auth: bool, flag_resumption: bool, flag_tickets: bool, arg_fport: Option, } fn find_suite(name: &str) -> Option { for suite in rustls::ALL_CIPHER_SUITES { let sname = format!("{:?}", suite.suite()).to_lowercase(); if sname == name.to_string().to_lowercase() { return Some(*suite); } } None } fn lookup_suites(suites: &[String]) -> Vec { let mut out = Vec::new(); for csname in suites { let scs = find_suite(csname); match scs { Some(s) => out.push(s), None => panic!("cannot look up ciphersuite '{}'", csname), } } out } /// Make a vector of protocol versions named in `versions` fn lookup_versions(versions: &[String]) -> Vec<&'static rustls::SupportedProtocolVersion> { let mut out = Vec::new(); for vname in versions { let version = match vname.as_ref() { "1.2" => &rustls::version::TLS12, "1.3" => &rustls::version::TLS13, _ => panic!( "cannot look up version '{}', valid are '1.2' and '1.3'", vname ), }; out.push(version); } out } fn load_certs(filename: &str) -> Vec { let certfile = fs::File::open(filename).expect("cannot open certificate file"); let mut reader = BufReader::new(certfile); rustls_pemfile::certs(&mut reader) .unwrap() .iter() .map(|v| rustls::Certificate(v.clone())) .collect() } fn load_private_key(filename: &str) -> rustls::PrivateKey { let keyfile = fs::File::open(filename).expect("cannot open private key file"); let mut reader = BufReader::new(keyfile); loop { match rustls_pemfile::read_one(&mut reader).expect("cannot parse private key .pem file") { Some(rustls_pemfile::Item::RSAKey(key)) => return rustls::PrivateKey(key), Some(rustls_pemfile::Item::PKCS8Key(key)) => return rustls::PrivateKey(key), Some(rustls_pemfile::Item::ECKey(key)) => return rustls::PrivateKey(key), None => break, _ => {} } } panic!( "no keys found in {:?} (encrypted keys not supported)", filename ); } fn load_ocsp(filename: &Option) -> Vec { let mut ret = Vec::new(); if let Some(name) = filename { fs::File::open(name) .expect("cannot open ocsp file") .read_to_end(&mut ret) .unwrap(); } ret } fn load_crls(filenames: &[String]) -> Vec { filenames .iter() .map(|filename| { let mut der = Vec::new(); fs::File::open(filename) .expect("cannot open CRL file") .read_to_end(&mut der) .unwrap(); UnparsedCertRevocationList(der) }) .collect() } fn make_config(args: &Args) -> Arc { let client_auth = if args.flag_auth.is_some() { let roots = load_certs(args.flag_auth.as_ref().unwrap()); let mut client_auth_roots = RootCertStore::empty(); for root in roots { client_auth_roots.add(&root).unwrap(); } let crls = load_crls(&args.flag_crl); if args.flag_require_auth { AllowAnyAuthenticatedClient::new(client_auth_roots) .with_crls(crls) .expect("invalid CRLs") .boxed() } else { AllowAnyAnonymousOrAuthenticatedClient::new(client_auth_roots) .with_crls(crls) .expect("invalid CRLs") .boxed() } } else { NoClientAuth::boxed() }; let suites = if !args.flag_suite.is_empty() { lookup_suites(&args.flag_suite) } else { rustls::ALL_CIPHER_SUITES.to_vec() }; let versions = if !args.flag_protover.is_empty() { lookup_versions(&args.flag_protover) } else { rustls::ALL_VERSIONS.to_vec() }; let certs = load_certs( args.flag_certs .as_ref() .expect("--certs option missing"), ); let privkey = load_private_key( args.flag_key .as_ref() .expect("--key option missing"), ); let ocsp = load_ocsp(&args.flag_ocsp); let mut config = rustls::ServerConfig::builder() .with_cipher_suites(&suites) .with_safe_default_kx_groups() .with_protocol_versions(&versions) .expect("inconsistent cipher-suites/versions specified") .with_client_cert_verifier(client_auth) .with_single_cert_with_ocsp_and_sct(certs, privkey, ocsp, vec![]) .expect("bad certificates/private key"); config.key_log = Arc::new(rustls::KeyLogFile::new()); if args.flag_resumption { config.session_storage = rustls::server::ServerSessionMemoryCache::new(256); } if args.flag_tickets { config.ticketer = rustls::Ticketer::new().unwrap(); } config.alpn_protocols = args .flag_proto .iter() .map(|proto| proto.as_bytes().to_vec()) .collect::>(); Arc::new(config) } fn main() { let version = env!("CARGO_PKG_NAME").to_string() + ", version: " + env!("CARGO_PKG_VERSION"); let args: Args = Docopt::new(USAGE) .map(|d| d.help(true)) .map(|d| d.version(Some(version))) .and_then(|d| d.deserialize()) .unwrap_or_else(|e| e.exit()); if args.flag_verbose { env_logger::Builder::new() .parse_filters("trace") .init(); } if !args.flag_crl.is_empty() && args.flag_auth.is_none() { println!("-crl can only be provided with -auth enabled"); return; } let mut addr: net::SocketAddr = "0.0.0.0:443".parse().unwrap(); addr.set_port(args.flag_port.unwrap_or(443)); let config = make_config(&args); let mut listener = TcpListener::bind(addr).expect("cannot listen on port"); let mut poll = mio::Poll::new().unwrap(); poll.registry() .register(&mut listener, LISTENER, mio::Interest::READABLE) .unwrap(); let mode = if args.cmd_echo { ServerMode::Echo } else if args.cmd_http { ServerMode::Http } else { ServerMode::Forward(args.arg_fport.expect("fport required")) }; let mut tlsserv = TlsServer::new(listener, mode, config); let mut events = mio::Events::with_capacity(256); loop { poll.poll(&mut events, None).unwrap(); for event in events.iter() { match event.token() { LISTENER => { tlsserv .accept(poll.registry()) .expect("error accepting socket"); } _ => tlsserv.conn_event(poll.registry(), event), } } } } rustls-v-0.21.10/fuzz/000077500000000000000000000000001453461710000144515ustar00rootroot00000000000000rustls-v-0.21.10/fuzz/.gitignore000066400000000000000000000000221453461710000164330ustar00rootroot00000000000000 target artifacts rustls-v-0.21.10/fuzz/Cargo.toml000066400000000000000000000013541453461710000164040ustar00rootroot00000000000000 [package] name = "rustls-fuzz" version = "0.0.1" authors = ["Automatically generated"] publish = false edition = "2021" [package.metadata] cargo-fuzz = true [dependencies.rustls] path = "../rustls" [dependencies.libfuzzer-sys] git = "https://github.com/rust-fuzz/libfuzzer-sys.git" # Prevent this from interfering with workspaces [workspace] members = ["."] [[bin]] name = "message" path = "fuzzers/message.rs" [[bin]] name = "deframer" path = "fuzzers/deframer.rs" [[bin]] name = "fragment" path = "fuzzers/fragment.rs" [[bin]] name = "persist" path = "fuzzers/persist.rs" [[bin]] name = "client" path = "fuzzers/client.rs" [[bin]] name = "server" path = "fuzzers/server.rs" [[bin]] name = "server_name" path = "fuzzers/server_name.rs" rustls-v-0.21.10/fuzz/README.md000066400000000000000000000013461453461710000157340ustar00rootroot00000000000000# Fuzz Testing Rustls supports fuzz testing using [cargo-fuzz]. Fuzz tests are automatically run during continuous integration using [oss-fuzz]. You may also run fuzz tests locally. See the [cargo-fuzz setup] instructions for requirements. ```bash # List available fuzzing targets. $ cargo fuzz list client deframer fragment message persist servert # Run the message fuzz target for a fixed period of time (expressed in seconds). $ cargo fuzz run message -- -max_total_time=120 # Clean up generated corpus files git clean --interactive -- ./corpus ``` [cargo-fuzz]: https://rust-fuzz.github.io/book/cargo-fuzz.html [oss-fuzz]: https://google.github.io/oss-fuzz/ [cargo-fuzz setup]: https://rust-fuzz.github.io/book/cargo-fuzz/setup.html rustls-v-0.21.10/fuzz/corpus/000077500000000000000000000000001453461710000157645ustar00rootroot00000000000000rustls-v-0.21.10/fuzz/corpus/client/000077500000000000000000000000001453461710000172425ustar00rootroot00000000000000rustls-v-0.21.10/fuzz/corpus/client/tls12-server.bin000066400000000000000000000136751453461710000222210ustar00rootroot00000000000000?;YZy4B7m_o8{κr̩#  `0\0DSA=xҌ'0  *H  0I1 0 UUS10U  Google Inc1%0#UGoogle Internet Authority G20 170427083000Z 170720083000Z0f1 0 UUS10U California10U Mountain View10U Google Inc10U *.google.com0Y0*H=*H=BM0FhZQR͓>!ܿ-1wGV"tǬ[LL?E55nťV^o00U%0++0 U0U0 *.google.com *.android.com*.appengine.google.com*.cloud.google.com*.gcp.gvt2.com*.google-analytics.com *.google.ca *.google.cl*.google.co.in*.google.co.jp*.google.co.uk*.google.com.ar*.google.com.au*.google.com.br*.google.com.co*.google.com.mx*.google.com.tr*.google.com.vn *.google.de *.google.es *.google.fr *.google.hu *.google.it *.google.nl *.google.pl *.google.pt*.googleadapis.com*.googleapis.cn*.googlecommerce.com*.googlevideo.com *.gstatic.cn *.gstatic.com *.gvt1.com *.gvt2.com*.metric.gstatic.com *.urchin.com*.url.google.com*.youtube-nocookie.com *.youtube.com*.youtubeeducation.com *.ytimg.comandroid.clients.google.com android.comdeveloper.android.google.cndevelopers.android.google.cng.cogoo.glgoogle-analytics.com google.comgooglecommerce.comsource.android.google.cn urchin.com www.goo.glyoutu.be youtube.comyoutubeeducation.com0h+\0Z0++0http://pki.google.com/GIAG2.crt0++0http://clients1.google.com/ocsp0UZ _MY(p#W@70 U00U#0JhvbZ/0!U 00  +y0g 00U)0'0%#!http://pki.google.com/GIAG2.crl0  *H  !ȩix3:uQ:wTpCJl:vWK>dO'ojMuy:X GFŀ9o?0Ϝ_$ Qk.i?\@~r8FՌZ!O]<-{-oֻf~ <{?we K$-݅ R@200 ыVv[|2In?B>00ؠ:0  *H  0B1 0 UUS10U  GeoTrust Inc.10UGeoTrust Global CA0 150401000000Z 171231235959Z0I1 0 UUS10U  Google Inc1%0#UGoogle Internet Authority G20"0  *H 0 *w\P:PH?pF~!Za 2Dt SOU΂bY_^?[H8S$S JT}koP(0@sQl:<7K}$1q`.JBjSKa͝>c+5ieF"SJ*캗 9az%NRu"jNF~{E3Ϻ>q%% 5y7ůri00U#0zhd }}eN0UJhvbZ/0U0.+"0 0+0http://g.symcd.com0U005U.0,0*(&$http://g.symcb.com/crls/gtglobal.crl0U 00  +y0  *H  NC^BҮ}}Iz<7 ǒ 53 (cr 2vgPX2LHcI] 7*iQKIp,$$N^mH5ei͇AP?.WQX z'}UfX__d]m9HuL)Z:+ʜUՀ&l\̸fd}I [pFNYl.6q!0}00  *H 0N1 0 UUS10U Equifax1-0+U $Equifax Secure Certificate Authority0 020521040000Z 180821040000Z0B1 0 UUS10U  GeoTrust Inc.10UGeoTrust Global CA0"0  *H 0 c0#V~[&d΃qN{U^8S\O-P#6fˎ99 8.M>o,`96S9^&+=2(Rq3=86by0_+qk00U#0Hh+ҲG# O30Uzhd }}eN0U00U0:U3010/-+)http://crl.geotrust.com/crls/secureca.crl0NU G0E0CU 0;09+-https://www.geotrust.com/resources/repository0  *H vnNK0q~f;NC80}Uj6HfmGZ\s284I6Voڼsc{>"=_8tPNa?r n K,uz0GYhH:LdaSF F0D vMIΤ:MbD3I=V.ঁc |l޲F`Ii0\轗'z|Wru#F`l,uͽ~l4s엨c{M&Ğģ'If2Pϲb'kŪ@87zrnO 12{4m@33s)酄𥨳o9gm(]t5 Hz+?"ۚYL0ƻԪcVGwtߣ(rdsq+,rL4/jK #`RjSwwdI'oV4 B]sj@f+JGyaP_4;\9,gfZtW a30M\b[#(svGp.ҕ0Ȉ&'v"ՙvTwNcll*yV~* zT p i?a-sD;w\7Qa #ڙ̌+BF%[2~8:ʻJPOe&w]Hwׇ{B 0+Sd-jqو7ʫp!EOR!(Թvtyov{b`b, Ih~>2]8ͽ޺J[6+}YW䦍5P Q3ku>k(?w57Yb36%L'\O[ki;%=D [숼?c/&\odb̫u[/d+M8F Î" N]'8&;0j@R/6WFHyMm19hr#("qKt[+{{+Rl~(l;;2pn(,&"b6G4@F0ɽuo@Uy%*k(l"B$h4 1եNQ ]uTIMϦ(xW{=gN( { /DtWTTI&߿r-_j{)[&Qi(N̓ bASc~eX# =Sԋ`٠:ua1{ʿ kE:8Gp-ߑdFh'/( zXӑ&:8Kˢ:)f;z^_!`LiZOڬ\,! n <][Xgy@㢨׿o-6yǓ0R)7AeEgc[yZ*fmxDL>d^Z 6 2 [~gX69 P3m8]<3i65P6j .rg>B+w8a<6D(şܕɊ.Fajgx%)WпB7 f{I<ɥΧsO_. /䳜5(t<{Pa;[yH$?ʽ_,hX9l 0 ibܦ=ͣكގ8[hN}&ט~Yfϼ~rvk{l3H+ x}FНtթGӅB^85L@(:);pK2$bg":z DqSԛ=lg:?ءgd~b M(`_}k|[&f+`@yH4&ȂKm5BgBJfA/q@O _i㲜&j4eV/x%d]|IM.j ܐ==L@ފB֦)'#@Hru^/ۏk8Vk+G2̐3!=rustls-v-0.21.10/fuzz/corpus/client/tls13-server.bin000066400000000000000000000111301453461710000222020ustar00rootroot00000000000000RNJ/P%D.*zOx@>RK.+'(($ HPv%kfkgvLXTު{o3a;y n,MwEƀE$!?󟺽wdi9xo#Nj 8R [SSh4~UkSQ#1I)) #h\lP7Ek*%UzN"&^Q،wաRrD[Mo4Vvw9=iY\VVu^ZH-tbsHO-yie֥ޖ4+`3eހOb=VC'qųN4a7cϚ+GBLGSޭlp Szu *sUuLb} YYrfp0A d (>/5l=%Ki9H极 H{4le5uge V!ĉ:P>u'=0T~ A+xнddS+ 2i-#46#(@ N!Xt;V/vxY HĮqg e7EYEV_P͢aE̱XswzW#A"!F+\ mp&Xے%lAw*Νٽ4sH!Mrg cy \h7P14j;f*!8sa!,62TF+ N tdЇ&gjiQ^ViciJK2َ>Y_BVoϿ<)#Fl kt( *HiKxHT #tOCCYa1@}R3`[G#3߭ P`$kvFOMlKCx13Nr+Z٣14IY ;"Aױ2BSq_GIBq DǶ> ߙXGHhۜ~FR\Җ^?(bGjGlU"yT$<w\D$+DoQ& |*/5Y 'Q[´{!]qx$oU~pd~ucW\s|vT8@O܄0}(6'Ie'-vuQU"YGxZnOD ޹T<޲@a;d&PqJɁ[DƄ6YrAˑ $x[ϊF+z\!C`6\SE棔]2!!X#xy[+V/л-3bl L>+o-y:(gȯVha<[߯M "BVdVQb:p$*GĵhL̥(sWp;k*jvN'37W8cLGԥfv"6PHEB/(qYCAT-m֩mvme2,?'+[ lRYI3%+E2 it}uY5;s:Ɏ ٷ ?B Ojza>Th/̷a$Q 3 Uip@#~Z|*E-ytv~?0vBl^}U߫7>_q"|Ums+-ez`웭ӇxZIKmݮܙ{[8 g괱1[Ck&6 hVĜ3AӮIiH-bR`L}+~9,"_Sb^U aeNJ{Vcc-ilKqխGa%XNqW@e:JbWCWx-9ӿig(BqyDM6=a~﫶aJape8څPC|D$QSCmNMW0w@;#״WRݦYh" D w߾о>b+t"CL}튐H\N=oN\e@a%ÞQ+$s'YGqs{4]y1D۟kt/3 <9mޚ+#60YXPѓKTx~PNW\)~:zX/(z{%Zϛu~jdUH$l^!oͱǡd #¦M@$707,1~|[YN4 nis>aGy/7f^WjPͷM\{pw|s+ LpO2sVAT/s۟o:`OҞB{AV B w`5}jj1N*(!÷QVS%qIB* I74{'P~'9߹3:{8ɰpJbEřxFk >;:Ҧ `$Sra./ϐB_yf@Ӫ DwcRRvf}6ؔٴe5a;;9̴'FOR&l)6$S*aC2BMlFs{kAߖ47s CK1!F Fbu5$W\ "o{vTWdM?]uCV4Iv!u"?~T )Nu5LCk]G\冈3ެZ,J͵Uv67r@֞^_"$R)U X5J[ sv?D}ٗJ#2z뾿F&LŮmt x@“x%"+R(ne!qzXw>E:tprustls-v-0.21.10/fuzz/corpus/message/000077500000000000000000000000001453461710000174105ustar00rootroot00000000000000rustls-v-0.21.10/fuzz/corpus/message/Alert.10280050250016901720.bin000066400000000000000000000000371453461710000232100ustar00rootroot00000000000000 GJ ꖶb+f+g³ɧrustls-v-0.21.10/fuzz/corpus/message/Alert.10990289312340337901.bin000066400000000000000000000000371453461710000232410ustar00rootroot00000000000000JrxMcc櫣 ՃxMrustls-v-0.21.10/fuzz/corpus/message/Alert.11416797448165465899.bin000066400000000000000000000000371453461710000233000ustar00rootroot00000000000000 0w=}J:MP)rustls-v-0.21.10/fuzz/corpus/message/Alert.11760376156357150936.bin000066400000000000000000000000371453461710000232510ustar00rootroot00000000000000ݔ%PG9 Fdxrustls-v-0.21.10/fuzz/corpus/message/Alert.12245208494696599323.bin000066400000000000000000000000371453461710000232640ustar00rootroot00000000000000NDqK˗edP/Vrustls-v-0.21.10/fuzz/corpus/message/Alert.12355157071787079801.bin000066400000000000000000000000371453461710000232530ustar00rootroot00000000000000`daOW$erustls-v-0.21.10/fuzz/corpus/message/Alert.1926005331368283096.bin000066400000000000000000000000271453461710000231610ustar00rootroot00000000000000̽C];S[Ip?rustls-v-0.21.10/fuzz/corpus/message/Alert.2519011641324364265.bin000066400000000000000000000000371453461710000231500ustar00rootroot00000000000000wT֬'+sW-brustls-v-0.21.10/fuzz/corpus/message/Alert.3043772687617154178.bin000066400000000000000000000000271453461710000231750ustar00rootroot00000000000000m'G{mdvrustls-v-0.21.10/fuzz/corpus/message/Alert.3312711214589330727.bin000066400000000000000000000000271453461710000231530ustar00rootroot00000000000000s쭦 7r arrustls-v-0.21.10/fuzz/corpus/message/Alert.3846875027962666933.bin000066400000000000000000000000071453461710000232100ustar00rootroot00000000000000(rustls-v-0.21.10/fuzz/corpus/message/Alert.3913777692829914411.bin000066400000000000000000000000371453461710000232040ustar00rootroot00000000000000}C !Iܨd/c0{jrustls-v-0.21.10/fuzz/corpus/message/Alert.4452180125344520836.bin000066400000000000000000000000271453461710000231510ustar00rootroot00000000000000[1}`MVR5rustls-v-0.21.10/fuzz/corpus/message/Alert.4742310320599043602.bin000066400000000000000000000000071453461710000231440ustar00rootroot00000000000000rustls-v-0.21.10/fuzz/corpus/message/Alert.5389179157252855041.bin000066400000000000000000000000371453461710000231760ustar00rootroot00000000000000 % MK"m\LP1=rjO"rustls-v-0.21.10/fuzz/corpus/message/Alert.5456718882703404602.bin000066400000000000000000000000371453461710000231670ustar00rootroot00000000000000LqY_tb܍6f0rustls-v-0.21.10/fuzz/corpus/message/Alert.6121018813528470199.bin000066400000000000000000000000371453461710000231630ustar00rootroot00000000000000Sq3OҎ8Ke×1Ɍvrustls-v-0.21.10/fuzz/corpus/message/Alert.6263407189670520235.bin000066400000000000000000000000371453461710000231630ustar00rootroot00000000000000](5UiBk #Pkx̀`irustls-v-0.21.10/fuzz/corpus/message/Alert.7573777073329161362.bin000066400000000000000000000000371453461710000231750ustar00rootroot00000000000000R LXҥЙGk%,-Vrustls-v-0.21.10/fuzz/corpus/message/Alert.7765214894001215959.bin000066400000000000000000000000371453461710000231740ustar00rootroot00000000000000rǬb2C_S'rustls-v-0.21.10/fuzz/corpus/message/Alert.8003974926653128830.bin000066400000000000000000000000371453461710000231730ustar00rootroot00000000000000yT&9_,w}l*msprustls-v-0.21.10/fuzz/corpus/message/Alert.8040902803342244309.bin000066400000000000000000000000371453461710000231500ustar00rootroot00000000000000]Ļ_qpbxACX$drustls-v-0.21.10/fuzz/corpus/message/Alert.9395714526513626176.bin000066400000000000000000000000371453461710000231770ustar00rootroot00000000000000\#sݝV++S=rustls-v-0.21.10/fuzz/corpus/message/Alert.9705133744397563296.bin000066400000000000000000000000371453461710000232040ustar00rootroot00000000000000yCLsѷn$ehq>7kTCrustls-v-0.21.10/fuzz/corpus/message/ApplicationData.1679947195649814466.bin000066400000000000000000000025361453461710000252150ustar00rootroot00000000000000YHTTP/1.1 200 OK Date: Mon, 08 May 2017 22:57:43 GMT Content-Type: text/html; charset=utf-8 Transfer-Encoding: chunked Connection: close Set-Cookie: __cfduid=d1755eb7822a3999117381353fbdf59c41494284263; expires=Tue, 08-May-18 22:57:43 GMT; path=/; domain=.jbp.io; HttpOnly Last-Modified: Mon, 03 Apr 2017 20:07:46 GMT Access-Control-Allow-Origin: * Expires: Mon, 08 May 2017 23:07:43 GMT Cache-Control: max-age=600 X-GitHub-Request-Id: 8857:5FC2:18DD116:208AB68:5910F7E7 Strict-Transport-Security: max-age=2592000 X-Content-Type-Options: nosniff Server: cloudflare-nginx CF-RAY: 35c00506a9303536-LHR be2 jbp.io :: 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 recommended way is to depend on the `webpki_roots` crate which contains //! the Mozilla set of root certificates. //! //! ```rust,no_run //! let mut root_store = rustls::RootCertStore::empty(); //! root_store.add_trust_anchors( //! webpki_roots::TLS_SERVER_ROOTS //! .iter() //! .map(|ta| { //! rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( //! ta.subject, //! ta.spki, //! ta.name_constraints, //! ) //! }) //! ); //! ``` //! //! 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 //! # let root_store: rustls::RootCertStore = panic!(); //! let config = rustls::ClientConfig::builder() //! .with_safe_defaults() //! .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 //! # use rustls; //! # use webpki; //! # use std::sync::Arc; //! # let mut root_store = rustls::RootCertStore::empty(); //! # root_store.add_trust_anchors( //! # webpki_roots::TLS_SERVER_ROOTS //! # .iter() //! # .map(|ta| { //! # rustls::OwnedTrustAnchor::from_subject_spki_name_constraints( //! # ta.subject, //! # ta.spki, //! # ta.name_constraints, //! # ) //! # }) //! # ); //! # let config = rustls::ClientConfig::builder() //! # .with_safe_defaults() //! # .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 //! # 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 { panic!() } //! # } //! # impl Write for Socket { //! # fn write(&mut self, buf: &[u8]) -> Result { 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 //! [`tlsserver`](https://github.com/rustls/rustls/blob/main/examples/src/bin/tlsserver-mio.rs) //! and [`tlsclient`](https://github.com/rustls/rustls/blob/main/examples/src/bin/tlsclient-mio.rs) //! are full worked examples. These both use mio. //! //! # Crate features //! Here's a list of what features are exposed by the rustls crate and what //! they mean. //! //! - `logging`: this makes 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. This feature is in the default set. //! //! - `dangerous_configuration`: this feature enables a `dangerous()` method on //! `ClientConfig` and `ServerConfig` that allows setting inadvisable options, //! such as replacing the certificate verification process. Applications //! requesting this feature should be reviewed carefully. //! //! - `quic`: this feature exposes additional constructors and functions //! for using rustls as a TLS library for QUIC. See the `quic` module for //! details of these. You will only need this if you're writing a QUIC //! implementation. //! //! - `tls12`: enables support for TLS version 1.2. This feature is in the default //! set. 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. //! //! - `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. // Require docs for public APIs, deny unsafe code, etc. #![forbid(unsafe_code, unused_must_use)] #![cfg_attr(not(any(read_buf, bench)), forbid(unstable_features))] #![deny( clippy::clone_on_ref_ptr, clippy::use_self, trivial_casts, trivial_numeric_casts, missing_docs, 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`, 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))] // 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))] // 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"))] #[macro_use] mod log { macro_rules! trace ( ($($tt:tt)*) => {{}} ); macro_rules! debug ( ($($tt:tt)*) => {{}} ); macro_rules! warn ( ($($tt:tt)*) => {{}} ); } #[macro_use] mod msgs; mod anchors; mod cipher; mod common_state; mod conn; mod dns_name; mod error; mod hash_hs; mod limited_cache; mod rand; mod record_layer; mod stream; #[cfg(feature = "tls12")] mod tls12; mod tls13; mod vecbuf; mod verify; #[cfg(test)] mod verifybench; mod x509; #[macro_use] mod check; mod bs_debug; mod builder; mod enums; mod key; mod key_log; mod key_log_file; mod kx; mod suites; mod ticketer; mod versions; /// Internal classes which may be useful outside the library. /// The contents of this section DO NOT form part of the stable interface. pub mod internal { /// Low-level TLS message parsing and encoding functions. pub mod msgs { pub use crate::msgs::*; } /// Low-level TLS message decryption functions. pub mod cipher { pub use crate::cipher::MessageDecrypter; } /// Low-level TLS record layer functions. pub mod record_layer { pub use crate::record_layer::{Decrypted, RecordLayer}; } } // The public interface is: pub use crate::anchors::{OwnedTrustAnchor, RootCertStore}; pub use crate::builder::{ ConfigBuilder, ConfigSide, WantsCipherSuites, WantsKxGroups, WantsVerifier, WantsVersions, }; pub use crate::common_state::{CommonState, IoState, Side}; pub use crate::conn::{Connection, ConnectionCommon, Reader, SideData, Writer}; pub use crate::enums::{ AlertDescription, CipherSuite, ContentType, HandshakeType, ProtocolVersion, SignatureAlgorithm, SignatureScheme, }; pub use crate::error::{ CertRevocationListError, CertificateError, Error, InvalidMessage, PeerIncompatible, PeerMisbehaved, }; pub use crate::key::{Certificate, PrivateKey}; pub use crate::key_log::{KeyLog, NoKeyLog}; pub use crate::key_log_file::KeyLogFile; pub use crate::kx::{SupportedKxGroup, ALL_KX_GROUPS}; pub use crate::msgs::enums::NamedGroup; pub use crate::msgs::handshake::DistinguishedName; pub use crate::stream::{Stream, StreamOwned}; pub use crate::suites::{ BulkAlgorithm, SupportedCipherSuite, ALL_CIPHER_SUITES, DEFAULT_CIPHER_SUITES, }; #[cfg(feature = "secret_extraction")] #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] pub use crate::suites::{ConnectionTrafficSecrets, ExtractedSecrets}; pub use crate::ticketer::Ticketer; #[cfg(feature = "tls12")] pub use crate::tls12::Tls12CipherSuite; pub use crate::tls13::Tls13CipherSuite; pub use crate::verify::DigitallySignedStruct; pub use crate::versions::{SupportedProtocolVersion, ALL_VERSIONS, DEFAULT_VERSIONS}; /// Items for use in a client. pub mod client { pub(super) mod builder; mod client_conn; mod common; pub(super) mod handy; mod hs; #[cfg(feature = "tls12")] mod tls12; mod tls13; pub use crate::dns_name::InvalidDnsNameError; pub use builder::{WantsClientCert, WantsTransparencyPolicyOrClientCert}; pub use client_conn::{ ClientConfig, ClientConnection, ClientConnectionData, ClientSessionStore, ResolvesClientCert, Resumption, ServerName, Tls12Resumption, WriteEarlyData, }; pub use handy::ClientSessionMemoryCache; #[cfg(feature = "dangerous_configuration")] pub use crate::verify::{ verify_server_cert_signed_by_trust_anchor, verify_server_name, CertificateTransparencyPolicy, HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, WebPkiVerifier, }; #[cfg(feature = "dangerous_configuration")] pub use client_conn::danger::DangerousClientConfig; pub use crate::msgs::persist::Tls12ClientSessionValue; pub use crate::msgs::persist::Tls13ClientSessionValue; } pub use client::{ClientConfig, ClientConnection, ServerName}; /// 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(feature = "tls12")] mod tls12; mod tls13; pub use crate::verify::{ AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, NoClientAuth, UnparsedCertRevocationList, }; pub use builder::WantsServerCert; pub use handy::ResolvesServerCertUsingSni; pub use handy::{NoServerSessionStorage, ServerSessionMemoryCache}; pub use server_conn::StoresServerSessions; pub use server_conn::{ Accepted, Acceptor, ReadEarlyData, ServerConfig, ServerConnection, ServerConnectionData, }; pub use server_conn::{ClientHello, ProducesTickets, ResolvesServerCert}; #[cfg(feature = "dangerous_configuration")] pub use crate::dns_name::DnsName; #[cfg(feature = "dangerous_configuration")] pub use crate::key::ParsedCertificate; #[cfg(feature = "dangerous_configuration")] pub use crate::verify::{ClientCertVerified, ClientCertVerifier}; } pub use server::{ServerConfig, ServerConnection}; /// All defined ciphersuites appear in this module. /// /// [`ALL_CIPHER_SUITES`] is provided as an array of all of these values. pub mod cipher_suite { pub use crate::suites::CipherSuiteCommon; #[cfg(feature = "tls12")] pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256; #[cfg(feature = "tls12")] pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384; #[cfg(feature = "tls12")] pub use crate::tls12::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256; #[cfg(feature = "tls12")] pub use crate::tls12::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; #[cfg(feature = "tls12")] pub use crate::tls12::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384; #[cfg(feature = "tls12")] pub use crate::tls12::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256; pub use crate::tls13::TLS13_AES_128_GCM_SHA256; pub use crate::tls13::TLS13_AES_256_GCM_SHA384; pub use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256; } /// 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; } /// All defined key exchange groups appear in this module. /// /// ALL_KX_GROUPS is provided as an array of all of these values. pub mod kx_group { pub use crate::kx::SECP256R1; pub use crate::kx::SECP384R1; pub use crate::kx::X25519; } /// Message signing interfaces and implementations. pub mod sign; #[cfg(feature = "quic")] #[cfg_attr(docsrs, doc(cfg(feature = "quic")))] /// APIs for implementing QUIC TLS pub mod quic; /// This is the rustls manual. pub mod manual; rustls-v-0.21.10/rustls/src/limited_cache.rs000066400000000000000000000156451453461710000207310ustar00rootroot00000000000000use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::collections::{HashMap, VecDeque}; use std::hash::Hash; /// 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 { map: HashMap, // first item is the oldest key oldest: VecDeque, } impl LimitedCache where K: Eq + Hash + Clone + std::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 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 insert(&mut self, k: K, v: V) { let inserted_new_item = match self.map.entry(k) { Entry::Occupied(mut old) => { // nb. 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(&self, k: &Q) -> Option<&V> where K: Borrow, Q: Hash + Eq, { self.map.get(k) } pub(crate) fn get_mut(&mut self, k: &Q) -> Option<&mut V> where K: Borrow, Q: Hash + Eq, { self.map.get_mut(k) } pub(crate) fn remove(&mut self, k: &Q) -> Option where K: Borrow, Q: Hash + Eq, { if let Some(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) } else { None } } } #[cfg(test)] mod test { type Test = super::LimitedCache; #[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)); } } rustls-v-0.21.10/rustls/src/manual/000077500000000000000000000000001453461710000170535ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/manual/defaults.rs000066400000000000000000000022051453461710000212270ustar00rootroot00000000000000/*! ## 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. */ rustls-v-0.21.10/rustls/src/manual/features.rs000066400000000000000000000026211453461710000212400ustar00rootroot00000000000000/*! ## Current features * TLS1.2 and TLS1.3. * ECDSA, Ed25519 or RSA server authentication by clients. * ECDSA, Ed25519 or RSA server authentication by servers. * Forward secrecy using ECDHE; with curve25519, nistp256 or nistp384 curves. * 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 MTU 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). * TLS1.3 resumption via tickets or session storage. * TLS1.3 0-RTT data for clients. * Client authentication by clients. * Client authentication by servers. * Extended master secret support (RFC7627). * Exporters (RFC5705). * OCSP stapling by servers. * SCT stapling by servers. * SCT verification by clients. ## Possible future features * PSK support. * OCSP verification by clients. * Certificate pinning. ## 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. * Compression. * Discrete-log Diffie-Hellman. * Automatic protocol version downgrade. */ rustls-v-0.21.10/rustls/src/manual/howto.rs000066400000000000000000000037441453461710000205710ustar00rootroot00000000000000/*! # 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` with the matching certificate chain into a [`sign::CertifiedKey`][certified_key] - making a [`ResolvesServerCertUsingSni`][cert_using_sni] and feeding in your `sign::CertifiedKey` for all SNI hostnames you want to use it for, - setting that as your `ServerConfig`'s [`cert_resolver`][cert_resolver] [signing_key]: ../../sign/trait.SigningKey.html [choose_scheme]: ../../sign/trait.SigningKey.html#tymethod.choose_scheme [sig_scheme]: ../../enum.SignatureScheme.html [signer]: ../../sign/trait.Signer.html [sign_method]: ../../sign/trait.Signer.html#tymethod.sign [certified_key]: ../../sign/struct.CertifiedKey.html [cert_using_sni]: ../../struct.ResolvesServerCertUsingSni.html [cert_resolver]: ../../struct.ServerConfig.html#structfield.cert_resolver [^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. */ rustls-v-0.21.10/rustls/src/manual/implvulns.rs000066400000000000000000000125151453461710000214560ustar00rootroot00000000000000/*! # 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` (nb. 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. */ rustls-v-0.21.10/rustls/src/manual/mod.rs000066400000000000000000000020441453461710000202000ustar00rootroot00000000000000/*! 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; rustls-v-0.21.10/rustls/src/manual/tlsvulns.rs000066400000000000000000000240601453461710000213150ustar00rootroot00000000000000/*! # 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. 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](http://netifera.com/research/crime/CRIME_ekoparty2012.pdf) ([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://www.openssl.org/~bodo/ssl-poodle.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 to earlier protocol versions. ## 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. */ rustls-v-0.21.10/rustls/src/msgs/000077500000000000000000000000001453461710000165475ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/msgs/alert.rs000066400000000000000000000012631453461710000202260ustar00rootroot00000000000000use 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) { self.level.encode(bytes); self.description.encode(bytes); } fn read(r: &mut Reader) -> Result { let level = AlertLevel::read(r)?; let description = AlertDescription::read(r)?; r.expect_empty("AlertMessagePayload") .map(|_| Self { level, description }) } } rustls-v-0.21.10/rustls/src/msgs/base.rs000066400000000000000000000075641453461710000200430ustar00rootroot00000000000000use std::fmt; use crate::error::InvalidMessage; use crate::key; use crate::msgs::codec; use crate::msgs::codec::{Codec, Reader}; /// An externally length'd payload #[derive(Clone, Eq, PartialEq)] pub struct Payload(pub Vec); impl Codec for Payload { fn encode(&self, bytes: &mut Vec) { bytes.extend_from_slice(&self.0); } fn read(r: &mut Reader) -> Result { Ok(Self::read(r)) } } impl Payload { pub fn new(bytes: impl Into>) -> Self { Self(bytes.into()) } pub fn empty() -> Self { Self::new(Vec::new()) } pub fn read(r: &mut Reader) -> Self { Self(r.rest().to_vec()) } } impl Codec for key::Certificate { fn encode(&self, bytes: &mut Vec) { codec::u24(self.0.len() as u32).encode(bytes); bytes.extend_from_slice(&self.0); } fn read(r: &mut Reader) -> Result { let len = codec::u24::read(r)?.0 as usize; let mut sub = r.sub(len)?; let body = sub.rest().to_vec(); Ok(Self(body)) } } impl fmt::Debug for Payload { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { hex(f, &self.0) } } /// An arbitrary, unknown-content, u24-length-prefixed payload #[derive(Clone, Eq, PartialEq)] pub struct PayloadU24(pub Vec); impl PayloadU24 { pub fn new(bytes: Vec) -> Self { Self(bytes) } } impl Codec for PayloadU24 { fn encode(&self, bytes: &mut Vec) { codec::u24(self.0.len() as u32).encode(bytes); bytes.extend_from_slice(&self.0); } fn read(r: &mut Reader) -> Result { let len = codec::u24::read(r)?.0 as usize; let mut sub = r.sub(len)?; let body = sub.rest().to_vec(); Ok(Self(body)) } } impl fmt::Debug for PayloadU24 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { hex(f, &self.0) } } /// An arbitrary, unknown-content, u16-length-prefixed payload #[derive(Clone, Eq, PartialEq)] pub struct PayloadU16(pub Vec); impl PayloadU16 { pub fn new(bytes: Vec) -> Self { Self(bytes) } pub fn empty() -> Self { Self::new(Vec::new()) } pub fn encode_slice(slice: &[u8], bytes: &mut Vec) { (slice.len() as u16).encode(bytes); bytes.extend_from_slice(slice); } } impl Codec for PayloadU16 { fn encode(&self, bytes: &mut Vec) { Self::encode_slice(&self.0, bytes); } fn read(r: &mut Reader) -> Result { let len = u16::read(r)? as usize; let mut sub = r.sub(len)?; let body = sub.rest().to_vec(); Ok(Self(body)) } } impl fmt::Debug for PayloadU16 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { hex(f, &self.0) } } /// An arbitrary, unknown-content, u8-length-prefixed payload #[derive(Clone, Eq, PartialEq)] pub struct PayloadU8(pub Vec); impl PayloadU8 { pub fn new(bytes: Vec) -> Self { Self(bytes) } pub fn empty() -> Self { Self(Vec::new()) } pub fn into_inner(self) -> Vec { self.0 } } impl Codec for PayloadU8 { fn encode(&self, bytes: &mut Vec) { (self.0.len() as u8).encode(bytes); bytes.extend_from_slice(&self.0); } fn read(r: &mut Reader) -> Result { let len = u8::read(r)? as usize; let mut sub = r.sub(len)?; let body = sub.rest().to_vec(); Ok(Self(body)) } } impl fmt::Debug for PayloadU8 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { hex(f, &self.0) } } // Format an iterator of u8 into a hex string pub(super) fn hex<'a>( f: &mut fmt::Formatter<'_>, payload: impl IntoIterator, ) -> fmt::Result { for b in payload { write!(f, "{:02x}", b)?; } Ok(()) } rustls-v-0.21.10/rustls/src/msgs/ccs.rs000066400000000000000000000010041453461710000176600ustar00rootroot00000000000000use crate::error::InvalidMessage; use crate::msgs::codec::{Codec, Reader}; #[derive(Debug)] pub struct ChangeCipherSpecPayload; impl Codec for ChangeCipherSpecPayload { fn encode(&self, bytes: &mut Vec) { 1u8.encode(bytes); } fn read(r: &mut Reader) -> Result { let typ = u8::read(r)?; if typ != 1 { return Err(InvalidMessage::InvalidCcs); } r.expect_empty("ChangeCipherSpecPayload") .map(|_| Self {}) } } rustls-v-0.21.10/rustls/src/msgs/codec.rs000066400000000000000000000217651453461710000202050ustar00rootroot00000000000000use std::fmt::Debug; 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 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: &[u8]) -> Reader { 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 { 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) -> &[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<&[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: Debug + Sized { /// Function for encoding itself by appending itself to /// the provided vec of bytes. fn encode(&self, bytes: &mut Vec); /// 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) -> Result; /// Convenience function for encoding the implementation /// into a vec and returning it fn get_encoding(&self) -> Vec { 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 fn read_bytes(bytes: &[u8]) -> Result { let mut reader = Reader::init(bytes); Self::read(&mut reader) } } impl Codec for u8 { fn encode(&self, bytes: &mut Vec) { bytes.push(*self); } fn read(r: &mut Reader) -> Result { match r.take(1) { Some(&[byte]) => Ok(byte), _ => Err(InvalidMessage::MissingData("u8")), } } } pub 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) { let mut b16 = [0u8; 2]; put_u16(*self, &mut b16); bytes.extend_from_slice(&b16); } fn read(r: &mut Reader) -> Result { match r.take(2) { Some(&[b1, b2]) => Ok(Self::from_be_bytes([b1, b2])), _ => Err(InvalidMessage::MissingData("u8")), } } } // 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 for usize { #[inline] fn from(v: u24) -> Self { v.0 as Self } } impl Codec for u24 { fn encode(&self, bytes: &mut Vec) { let be_bytes = u32::to_be_bytes(self.0); bytes.extend_from_slice(&be_bytes[1..]); } fn read(r: &mut Reader) -> Result { 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) { bytes.extend(Self::to_be_bytes(*self)); } fn read(r: &mut Reader) -> Result { match r.take(4) { Some(&[a, b, c, d]) => Ok(Self::from_be_bytes([a, b, c, d])), _ => Err(InvalidMessage::MissingData("u32")), } } } pub 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) { let mut b64 = [0u8; 8]; put_u64(*self, &mut b64); bytes.extend_from_slice(&b64); } fn read(r: &mut Reader) -> Result { 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 Codec for Vec { fn encode(&self, bytes: &mut Vec) { let len_offset = bytes.len(); bytes.extend(match T::SIZE_LEN { ListLength::U8 => &[0][..], ListLength::U16 => &[0, 0], ListLength::U24 { .. } => &[0, 0, 0], }); for i in self { i.encode(bytes); } match T::SIZE_LEN { ListLength::U8 => { let len = bytes.len() - len_offset - 1; debug_assert!(len <= 0xff); bytes[len_offset] = len as u8; } ListLength::U16 => { let len = bytes.len() - len_offset - 2; debug_assert!(len <= 0xffff); let out: &mut [u8; 2] = (&mut bytes[len_offset..len_offset + 2]) .try_into() .unwrap(); *out = u16::to_be_bytes(len as u16); } ListLength::U24 { .. } => { let len = bytes.len() - len_offset - 3; debug_assert!(len <= 0xff_ffff); let len_bytes = u32::to_be_bytes(len as u32); let out: &mut [u8; 3] = (&mut bytes[len_offset..len_offset + 3]) .try_into() .unwrap(); out.copy_from_slice(&len_bytes[1..]); } } } fn read(r: &mut Reader) -> Result { let len = match T::SIZE_LEN { ListLength::U8 => usize::from(u8::read(r)?), ListLength::U16 => usize::from(u16::read(r)?), ListLength::U24 { max } => Ord::min(usize::from(u24::read(r)?), max), }; let mut sub = r.sub(len)?; let mut ret = Self::new(); while sub.any_left() { ret.push(T::read(&mut sub)?); } Ok(ret) } } /// A trait for types that can be encoded and decoded in a list. /// /// This trait is used to implement `Codec` for `Vec`. 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` requires an implementation of this trait /// for its element type `T`. /// // TODO: make this `pub(crate)` once our MSRV allows it? pub 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. /// // TODO: make this `pub(crate)` once our MSRV allows it? pub enum ListLength { U8, U16, U24 { max: usize }, } rustls-v-0.21.10/rustls/src/msgs/deframer.rs000066400000000000000000000660171453461710000207140ustar00rootroot00000000000000use std::io; use std::ops::Range; use super::base::Payload; use super::codec::Codec; use super::message::PlainMessage; use crate::enums::{ContentType, ProtocolVersion}; use crate::error::{Error, InvalidMessage, PeerMisbehaved}; use crate::msgs::codec; use crate::msgs::message::{MessageError, OpaqueMessage}; use crate::record_layer::{Decrypted, RecordLayer}; /// This deframer works to reconstruct TLS messages from a stream of arbitrary-sized reads. /// /// It buffers incoming data into a `Vec` through `read()`, and returns messages through `pop()`. /// QUIC connections will call `push()` to append handshake payload data directly. #[derive(Default)] pub struct MessageDeframer { /// Set if the peer is not talking TLS, but some other /// protocol. The caller should abort the connection, because /// the deframer cannot recover. last_error: Option, /// Buffer of data read from the socket, in the process of being parsed into messages. /// /// For buffer size management, checkout out the `read()` method. buf: Vec, /// If we're in the middle of joining a handshake payload, this is the metadata. joining_hs: Option, /// What size prefix of `buf` is used. used: usize, } impl MessageDeframer { /// Return any decrypted messages that the deframer has been able to parse. /// /// Returns an `Error` if the deframer failed to parse some message contents or if decryption /// failed, `Ok(None)` if no full message is buffered or if trial decryption failed, and /// `Ok(Some(_))` if a valid message was found and decrypted successfully. pub fn pop(&mut self, record_layer: &mut RecordLayer) -> Result, Error> { if let Some(last_err) = self.last_error.clone() { return Err(last_err); } else if self.used == 0 { return Ok(None); } // We loop over records we've received but not processed yet. // For records that decrypt as `Handshake`, we keep the current state of the joined // handshake message payload in `self.joining_hs`, appending to it as we see records. let expected_len = loop { let start = match &self.joining_hs { Some(meta) => { match meta.expected_len { // We're joining a handshake payload, and we've seen the full payload. Some(len) if len <= meta.payload.len() => break len, // Not enough data, and we can't parse any more out of the buffer (QUIC). _ if meta.quic => return Ok(None), // Try parsing some more of the encrypted buffered data. _ => meta.message.end, } } None => 0, }; // Does our `buf` contain a full message? It does if it is big enough to // contain a header, and that header has a length which falls within `buf`. // If so, deframe it and place the message onto the frames output queue. let mut rd = codec::Reader::init(&self.buf[start..self.used]); let m = match OpaqueMessage::read(&mut rd) { Ok(m) => m, Err(msg_err) => { let err_kind = match msg_err { MessageError::TooShortForHeader | MessageError::TooShortForLength => { return Ok(None) } MessageError::InvalidEmptyPayload => InvalidMessage::InvalidEmptyPayload, MessageError::MessageTooLarge => InvalidMessage::MessageTooLarge, MessageError::InvalidContentType => InvalidMessage::InvalidContentType, MessageError::UnknownProtocolVersion => { InvalidMessage::UnknownProtocolVersion } }; return Err(self.set_err(err_kind)); } }; // If we're in the middle of joining a handshake payload and the next message is not of // type handshake, yield an error. Return CCS messages immediately without decrypting. let end = start + rd.used(); if m.typ == ContentType::ChangeCipherSpec && self.joining_hs.is_none() { // This is unencrypted. We check the contents later. self.discard(end); return Ok(Some(Deframed { want_close_before_decrypt: false, aligned: true, trial_decryption_finished: false, message: m.into_plain_message(), })); } // Decrypt the encrypted message (if necessary). let msg = match record_layer.decrypt_incoming(m) { Ok(Some(decrypted)) => { let Decrypted { want_close_before_decrypt, plaintext, } = decrypted; debug_assert!(!want_close_before_decrypt); plaintext } // This was rejected early data, discard it. If we currently have a handshake // payload in progress, this counts as interleaved, so we error out. Ok(None) if self.joining_hs.is_some() => { return Err(self.set_err( PeerMisbehaved::RejectedEarlyDataInterleavedWithHandshakeMessage, )); } Ok(None) => { self.discard(end); continue; } Err(e) => return Err(e), }; if self.joining_hs.is_some() && msg.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(self.set_err(PeerMisbehaved::MessageInterleavedWithHandshakeMessage)); } // If it's not a handshake message, just return it -- no joining necessary. if msg.typ != ContentType::Handshake { let end = start + rd.used(); self.discard(end); return Ok(Some(Deframed { want_close_before_decrypt: false, aligned: true, trial_decryption_finished: false, message: msg, })); } // If we don't know the payload size yet or if the payload size is larger // than the currently buffered payload, we need to wait for more data. match self.append_hs(msg.version, &msg.payload.0, end, false)? { HandshakePayloadState::Blocked => return Ok(None), HandshakePayloadState::Complete(len) => break len, HandshakePayloadState::Continue => continue, } }; let meta = self.joining_hs.as_mut().unwrap(); // safe after calling `append_hs()` // We can now wrap the complete handshake payload in a `PlainMessage`, to be returned. let message = PlainMessage { typ: ContentType::Handshake, version: meta.version, payload: Payload::new(&self.buf[meta.payload.start..meta.payload.start + expected_len]), }; // But before we return, update the `joining_hs` state to skip past this payload. if meta.payload.len() > expected_len { // If we have another (beginning of) a handshake payload left in the buffer, update // the payload start to point past the payload we're about to yield, and update the // `expected_len` to match the state of that remaining payload. meta.payload.start += expected_len; meta.expected_len = payload_size(&self.buf[meta.payload.start..meta.payload.end])?; } else { // Otherwise, we've yielded the last handshake payload in the buffer, so we can // discard all of the bytes that we're previously buffered as handshake data. let end = meta.message.end; self.joining_hs = None; self.discard(end); } Ok(Some(Deframed { want_close_before_decrypt: false, aligned: self.joining_hs.is_none(), trial_decryption_finished: true, message, })) } /// Fuses this deframer's error and returns the set value. /// /// Any future calls to `pop` will return `err` again. fn set_err(&mut self, err: impl Into) -> Error { let err = err.into(); self.last_error = Some(err.clone()); err } /// Allow pushing handshake messages directly into the buffer. #[cfg(feature = "quic")] pub fn push(&mut self, version: ProtocolVersion, payload: &[u8]) -> Result<(), Error> { if self.used > 0 && self.joining_hs.is_none() { return Err(Error::General( "cannot push QUIC messages into unrelated connection".into(), )); } else if let Err(err) = self.prepare_read() { return Err(Error::General(err.into())); } let end = self.used + payload.len(); self.append_hs(version, payload, end, true)?; self.used = end; Ok(()) } /// Write the handshake message contents into the buffer and update the metadata. /// /// Returns true if a complete message is found. fn append_hs( &mut self, version: ProtocolVersion, payload: &[u8], end: usize, quic: bool, ) -> Result { let meta = match &mut self.joining_hs { Some(meta) => { debug_assert_eq!(meta.quic, quic); // We're joining a handshake message to the previous one here. // Write it into the buffer and update the metadata. let dst = &mut self.buf[meta.payload.end..meta.payload.end + payload.len()]; dst.copy_from_slice(payload); meta.message.end = end; meta.payload.end += payload.len(); // If we haven't parsed the payload size yet, try to do so now. if meta.expected_len.is_none() { meta.expected_len = payload_size(&self.buf[meta.payload.start..meta.payload.end])?; } meta } None => { // We've found a new handshake message here. // Write it into the buffer and create the metadata. let expected_len = payload_size(payload)?; let dst = &mut self.buf[..payload.len()]; dst.copy_from_slice(payload); self.joining_hs .insert(HandshakePayloadMeta { message: Range { start: 0, end }, payload: Range { start: 0, end: payload.len(), }, version, expected_len, quic, }) } }; Ok(match meta.expected_len { Some(len) if len <= meta.payload.len() => HandshakePayloadState::Complete(len), _ => match self.used > meta.message.end { true => HandshakePayloadState::Continue, false => HandshakePayloadState::Blocked, }, }) } /// Read some bytes from `rd`, and add them to our internal buffer. #[allow(clippy::comparison_chain)] pub fn read(&mut self, rd: &mut dyn io::Read) -> io::Result { if let Err(err) = self.prepare_read() { 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) -> Result<(), &'static str> { // 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 self.joining_hs { Some(_) => MAX_HANDSHAKE_SIZE as usize, None => OpaqueMessage::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 `OpaqueMessage::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(()) } /// Returns true if we have messages for the caller /// to process, either whole messages in our output /// queue or partial messages in our buffer. pub fn has_pending(&self) -> bool { self.used > 0 } /// Discard `taken` bytes from the start of our buffer. 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; } } } enum HandshakePayloadState { /// Waiting for more data. Blocked, /// We have a complete handshake message. Complete(usize), /// More records available for processing. Continue, } struct HandshakePayloadMeta { /// The range of bytes from the deframer buffer that contains data processed so far. /// /// This will need to be discarded as the last of the handshake message is `pop()`ped. message: Range, /// The range of bytes from the deframer buffer that contains payload. payload: Range, /// The protocol version as found in the decrypted handshake message. version: ProtocolVersion, /// The expected size of the handshake payload, if available. /// /// If the received payload exceeds 4 bytes (the handshake payload header), we update /// `expected_len` to contain the payload length as advertised (at most 16_777_215 bytes). expected_len: Option, /// True if this is a QUIC handshake message. /// /// In the case of QUIC, we get a plaintext handshake data directly from the CRYPTO stream, /// so there's no need to unwrap and decrypt the outer TLS record. This is implemented /// by directly calling `MessageDeframer::push()` from the connection. quic: bool, } /// Determine the expected length of the payload as advertised in the header. /// /// Returns `Err` if the advertised length is larger than what we want to accept /// (`MAX_HANDSHAKE_SIZE`), `Ok(None)` if the buffer is too small to contain a complete header, /// and `Ok(Some(len))` otherwise. fn payload_size(buf: &[u8]) -> Result, Error> { if buf.len() < HEADER_SIZE { return Ok(None); } let (header, _) = buf.split_at(HEADER_SIZE); match codec::u24::read_bytes(&header[1..]) { Ok(len) if len.0 > MAX_HANDSHAKE_SIZE => Err(Error::InvalidMessage( InvalidMessage::HandshakePayloadTooLarge, )), Ok(len) => Ok(Some(HEADER_SIZE + usize::from(len))), _ => Ok(None), } } #[derive(Debug)] pub struct Deframed { pub want_close_before_decrypt: bool, pub aligned: bool, pub trial_decryption_finished: bool, pub message: PlainMessage, } #[derive(Debug)] pub enum DeframerError { HandshakePayloadSizeTooLarge, } const HEADER_SIZE: 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: u32 = 0xffff; const READ_SIZE: usize = 4096; #[cfg(test)] mod tests { use super::MessageDeframer; use crate::msgs::message::{Message, OpaqueMessage}; use crate::record_layer::RecordLayer; use crate::{ContentType, Error, InvalidMessage}; use std::io; const FIRST_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-test.1.bin"); const SECOND_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-test.2.bin"); const EMPTY_APPLICATIONDATA_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-empty-applicationdata.bin"); const INVALID_EMPTY_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-invalid-empty.bin"); const INVALID_CONTENTTYPE_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-invalid-contenttype.bin"); const INVALID_VERSION_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-invalid-version.bin"); const INVALID_LENGTH_MESSAGE: &[u8] = include_bytes!("../testdata/deframer-invalid-length.bin"); fn input_bytes(d: &mut MessageDeframer, bytes: &[u8]) -> io::Result { let mut rd = io::Cursor::new(bytes); d.read(&mut rd) } fn input_bytes_concat( d: &mut MessageDeframer, bytes1: &[u8], bytes2: &[u8], ) -> io::Result { let mut bytes = vec![0u8; bytes1.len() + bytes2.len()]; bytes[..bytes1.len()].clone_from_slice(bytes1); bytes[bytes1.len()..].clone_from_slice(bytes2); let mut rd = io::Cursor::new(&bytes); d.read(&mut rd) } struct ErrorRead { error: Option, } impl ErrorRead { fn new(error: io::Error) -> Self { Self { error: Some(error) } } } impl io::Read for ErrorRead { fn read(&mut self, buf: &mut [u8]) -> io::Result { for (i, b) in buf.iter_mut().enumerate() { *b = i as u8; } let error = self.error.take().unwrap(); Err(error) } } fn input_error(d: &mut MessageDeframer) { let error = io::Error::from(io::ErrorKind::TimedOut); let mut rd = ErrorRead::new(error); d.read(&mut rd) .expect_err("error not propagated"); } fn input_whole_incremental(d: &mut MessageDeframer, bytes: &[u8]) { let before = d.used; for i in 0..bytes.len() { assert_len(1, input_bytes(d, &bytes[i..i + 1])); assert!(d.has_pending()); } assert_eq!(before + bytes.len(), d.used); } fn assert_len(want: usize, got: io::Result) { if let Ok(gotval) = got { assert_eq!(gotval, want); } else { panic!("read failed, expected {:?} bytes", want); } } fn pop_first(d: &mut MessageDeframer, rl: &mut RecordLayer) { let m = d.pop(rl).unwrap().unwrap().message; assert_eq!(m.typ, ContentType::Handshake); Message::try_from(m).unwrap(); } fn pop_second(d: &mut MessageDeframer, rl: &mut RecordLayer) { let m = d.pop(rl).unwrap().unwrap().message; assert_eq!(m.typ, ContentType::Alert); Message::try_from(m).unwrap(); } #[test] fn check_incremental() { let mut d = MessageDeframer::default(); assert!(!d.has_pending()); input_whole_incremental(&mut d, FIRST_MESSAGE); assert!(d.has_pending()); let mut rl = RecordLayer::new(); pop_first(&mut d, &mut rl); assert!(!d.has_pending()); assert!(d.last_error.is_none()); } #[test] fn check_incremental_2() { let mut d = MessageDeframer::default(); assert!(!d.has_pending()); input_whole_incremental(&mut d, FIRST_MESSAGE); assert!(d.has_pending()); input_whole_incremental(&mut d, SECOND_MESSAGE); assert!(d.has_pending()); let mut rl = RecordLayer::new(); pop_first(&mut d, &mut rl); assert!(d.has_pending()); pop_second(&mut d, &mut rl); assert!(!d.has_pending()); assert!(d.last_error.is_none()); } #[test] fn check_whole() { let mut d = MessageDeframer::default(); assert!(!d.has_pending()); assert_len(FIRST_MESSAGE.len(), input_bytes(&mut d, FIRST_MESSAGE)); assert!(d.has_pending()); let mut rl = RecordLayer::new(); pop_first(&mut d, &mut rl); assert!(!d.has_pending()); assert!(d.last_error.is_none()); } #[test] fn check_whole_2() { let mut d = MessageDeframer::default(); assert!(!d.has_pending()); assert_len(FIRST_MESSAGE.len(), input_bytes(&mut d, FIRST_MESSAGE)); assert_len(SECOND_MESSAGE.len(), input_bytes(&mut d, SECOND_MESSAGE)); let mut rl = RecordLayer::new(); pop_first(&mut d, &mut rl); pop_second(&mut d, &mut rl); assert!(!d.has_pending()); assert!(d.last_error.is_none()); } #[test] fn test_two_in_one_read() { let mut d = MessageDeframer::default(); assert!(!d.has_pending()); assert_len( FIRST_MESSAGE.len() + SECOND_MESSAGE.len(), input_bytes_concat(&mut d, FIRST_MESSAGE, SECOND_MESSAGE), ); let mut rl = RecordLayer::new(); pop_first(&mut d, &mut rl); pop_second(&mut d, &mut rl); assert!(!d.has_pending()); assert!(d.last_error.is_none()); } #[test] fn test_two_in_one_read_shortest_first() { let mut d = MessageDeframer::default(); assert!(!d.has_pending()); assert_len( FIRST_MESSAGE.len() + SECOND_MESSAGE.len(), input_bytes_concat(&mut d, SECOND_MESSAGE, FIRST_MESSAGE), ); let mut rl = RecordLayer::new(); pop_second(&mut d, &mut rl); pop_first(&mut d, &mut rl); assert!(!d.has_pending()); assert!(d.last_error.is_none()); } #[test] fn test_incremental_with_nonfatal_read_error() { let mut d = MessageDeframer::default(); assert_len(3, input_bytes(&mut d, &FIRST_MESSAGE[..3])); input_error(&mut d); assert_len( FIRST_MESSAGE.len() - 3, input_bytes(&mut d, &FIRST_MESSAGE[3..]), ); let mut rl = RecordLayer::new(); pop_first(&mut d, &mut rl); assert!(!d.has_pending()); assert!(d.last_error.is_none()); } #[test] fn test_invalid_contenttype_errors() { let mut d = MessageDeframer::default(); assert_len( INVALID_CONTENTTYPE_MESSAGE.len(), input_bytes(&mut d, INVALID_CONTENTTYPE_MESSAGE), ); let mut rl = RecordLayer::new(); assert_eq!( d.pop(&mut rl).unwrap_err(), Error::InvalidMessage(InvalidMessage::InvalidContentType) ); } #[test] fn test_invalid_version_errors() { let mut d = MessageDeframer::default(); assert_len( INVALID_VERSION_MESSAGE.len(), input_bytes(&mut d, INVALID_VERSION_MESSAGE), ); let mut rl = RecordLayer::new(); assert_eq!( d.pop(&mut rl).unwrap_err(), Error::InvalidMessage(InvalidMessage::UnknownProtocolVersion) ); } #[test] fn test_invalid_length_errors() { let mut d = MessageDeframer::default(); assert_len( INVALID_LENGTH_MESSAGE.len(), input_bytes(&mut d, INVALID_LENGTH_MESSAGE), ); let mut rl = RecordLayer::new(); assert_eq!( d.pop(&mut rl).unwrap_err(), Error::InvalidMessage(InvalidMessage::MessageTooLarge) ); } #[test] fn test_empty_applicationdata() { let mut d = MessageDeframer::default(); assert_len( EMPTY_APPLICATIONDATA_MESSAGE.len(), input_bytes(&mut d, EMPTY_APPLICATIONDATA_MESSAGE), ); let mut rl = RecordLayer::new(); let m = d.pop(&mut rl).unwrap().unwrap().message; assert_eq!(m.typ, ContentType::ApplicationData); assert_eq!(m.payload.0.len(), 0); assert!(!d.has_pending()); assert!(d.last_error.is_none()); } #[test] fn test_invalid_empty_errors() { let mut d = MessageDeframer::default(); assert_len( INVALID_EMPTY_MESSAGE.len(), input_bytes(&mut d, INVALID_EMPTY_MESSAGE), ); let mut rl = RecordLayer::new(); assert_eq!( d.pop(&mut rl).unwrap_err(), Error::InvalidMessage(InvalidMessage::InvalidEmptyPayload) ); // CorruptMessage has been fused assert_eq!( d.pop(&mut rl).unwrap_err(), Error::InvalidMessage(InvalidMessage::InvalidEmptyPayload) ); } #[test] fn test_limited_buffer() { const PAYLOAD_LEN: usize = 16_384; let mut message = Vec::with_capacity(16_389); message.push(0x17); // ApplicationData message.extend(&[0x03, 0x04]); // ProtocolVersion message.extend((PAYLOAD_LEN as u16).to_be_bytes()); // payload length message.extend(&[0; PAYLOAD_LEN]); let mut d = MessageDeframer::default(); assert_len(4096, input_bytes(&mut d, &message)); assert_len(4096, input_bytes(&mut d, &message)); assert_len(4096, input_bytes(&mut d, &message)); assert_len(4096, input_bytes(&mut d, &message)); assert_len( OpaqueMessage::MAX_WIRE_SIZE - 16_384, input_bytes(&mut d, &message), ); assert!(input_bytes(&mut d, &message).is_err()); } } rustls-v-0.21.10/rustls/src/msgs/enums.rs000066400000000000000000000266041453461710000202540ustar00rootroot00000000000000#![allow(clippy::upper_case_acronyms)] #![allow(non_camel_case_types)] /// This file is autogenerated. See https://github.com/ctz/tls-hacking/ 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. @U8 EnumName: HashAlgorithm; EnumVal{ NONE => 0x00, MD5 => 0x01, SHA1 => 0x02, SHA224 => 0x03, SHA256 => 0x04, SHA384 => 0x05, SHA512 => 0x06 } } 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. @U8 EnumName: ClientCertificateType; EnumVal{ 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. @U8 EnumName: Compression; EnumVal{ 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. @U8 EnumName: AlertLevel; EnumVal{ 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. @U8 EnumName: HeartbeatMessageType; EnumVal{ 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. @U16 EnumName: ExtensionType; EnumVal{ 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, Padding => 0x0015, ExtendedMasterSecret => 0x0017, 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 } } 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. @U8 EnumName: ServerNameType; EnumVal{ 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::kx_group`] for the list of supported /// elliptic curve groups. @U16 EnumName: NamedCurve; EnumVal{ 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. @U16 EnumName: NamedGroup; EnumVal{ secp256r1 => 0x0017, secp384r1 => 0x0018, secp521r1 => 0x0019, X25519 => 0x001d, X448 => 0x001e, FFDHE2048 => 0x0100, FFDHE3072 => 0x0101, FFDHE4096 => 0x0102, FFDHE6144 => 0x0103, FFDHE8192 => 0x0104 } } 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. @U8 EnumName: ECPointFormat; EnumVal{ Uncompressed => 0x00, ANSIX962CompressedPrime => 0x01, ANSIX962CompressedChar2 => 0x02 } } impl ECPointFormat { pub const SUPPORTED: [Self; 1] = [Self::Uncompressed]; } 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. @U8 EnumName: HeartbeatMode; EnumVal{ 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. @U8 EnumName: ECCurveType; EnumVal{ 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. @U8 EnumName: PSKKeyExchangeMode; EnumVal{ 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. @U8 EnumName: KeyUpdateRequest; EnumVal{ 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. @U8 EnumName: CertificateStatusType; EnumVal{ OCSP => 0x01 } } #[cfg(test)] pub(crate) mod tests { //! These tests are intended to provide coverage and //! check panic-safety of relatively unused values. use super::*; use crate::msgs::codec::Codec; #[test] fn test_enums() { test_enum8::(HashAlgorithm::NONE, HashAlgorithm::SHA512); test_enum8::( ClientCertificateType::RSASign, ClientCertificateType::ECDSAFixedECDH, ); test_enum8::(Compression::Null, Compression::LSZ); test_enum8::(AlertLevel::Warning, AlertLevel::Fatal); test_enum8::( HeartbeatMessageType::Request, HeartbeatMessageType::Response, ); test_enum16::(ExtensionType::ServerName, ExtensionType::RenegotiationInfo); test_enum8::(ServerNameType::HostName, ServerNameType::HostName); test_enum16::( NamedCurve::sect163k1, NamedCurve::arbitrary_explicit_char2_curves, ); test_enum16::(NamedGroup::secp256r1, NamedGroup::FFDHE8192); test_enum8::( ECPointFormat::Uncompressed, ECPointFormat::ANSIX962CompressedChar2, ); test_enum8::( HeartbeatMode::PeerAllowedToSend, HeartbeatMode::PeerNotAllowedToSend, ); test_enum8::(ECCurveType::ExplicitPrime, ECCurveType::NamedCurve); test_enum8::( PSKKeyExchangeMode::PSK_KE, PSKKeyExchangeMode::PSK_DHE_KE, ); test_enum8::( KeyUpdateRequest::UpdateNotRequested, KeyUpdateRequest::UpdateRequested, ); test_enum8::( CertificateStatusType::OCSP, CertificateStatusType::OCSP, ); } pub(crate) fn test_enum8(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(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(enum_value: &T) -> u8 { let enc = enum_value.get_encoding(); assert_eq!(enc.len(), 1); enc[0] } fn get16(enum_value: &T) -> u16 { let enc = enum_value.get_encoding(); assert_eq!(enc.len(), 2); (enc[0] as u16 >> 8) | (enc[1] as u16) } } rustls-v-0.21.10/rustls/src/msgs/fragmenter.rs000066400000000000000000000112501453461710000212460ustar00rootroot00000000000000use crate::enums::ContentType; use crate::enums::ProtocolVersion; use crate::msgs::message::{BorrowedPlainMessage, PlainMessage}; use crate::Error; pub const MAX_FRAGMENT_LEN: usize = 16384; pub const PACKET_OVERHEAD: usize = 1 + 2 + 2; pub 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 the Message `msg` and re-fragment it into new /// messages whose fragment is no more than max_frag. /// Return an iterator across those messages. /// Payloads are borrowed. pub fn fragment_message<'a>( &self, msg: &'a PlainMessage, ) -> impl Iterator> + 'a { self.fragment_slice(msg.typ, msg.version, &msg.payload.0) } /// Enqueue borrowed fragments of (version, typ, payload) which /// are no longer than max_frag onto the `out` deque. pub fn fragment_slice<'a>( &self, typ: ContentType, version: ProtocolVersion, payload: &'a [u8], ) -> impl Iterator> + 'a { payload .chunks(self.max_frag) .map(move |c| BorrowedPlainMessage { typ, version, payload: c, }) } /// 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) -> 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(()) } } #[cfg(test)] mod tests { use super::{MessageFragmenter, PACKET_OVERHEAD}; use crate::enums::ContentType; use crate::enums::ProtocolVersion; use crate::msgs::base::Payload; use crate::msgs::message::{BorrowedPlainMessage, PlainMessage}; fn msg_eq( m: &BorrowedPlainMessage, total_len: usize, typ: &ContentType, version: &ProtocolVersion, bytes: &[u8], ) { assert_eq!(&m.typ, typ); assert_eq!(&m.version, version); assert_eq!(m.payload, 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 = (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::>(); 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::>(); 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", ); } } rustls-v-0.21.10/rustls/src/msgs/handshake-test.1.bin000066400000000000000000000102701453461710000223030ustar00rootroot00000000000000IE7y̌~u`0`l0,($ kjih98762.*&=5/+'# g@?>3210EDCB1-)%</A    h google.com   # ?;W)Cݳt7ws֥y$QJDe|+#  |y00ߠ|0  *H  0I1 0 UUS10U  Google Inc1%0#UGoogle Internet Authority G20 160420135741Z 160713130800Z0f1 0 UUS10U California10U Mountain View10U Google Inc10U *.google.com0Y0*H=*H=B9JPjVe=B0!_yw0x"b[Ȳ~!3.300U%0++0NUE0A *.google.com *.android.com*.appengine.google.com*.cloud.google.com*.google-analytics.com *.google.ca *.google.cl*.google.co.in*.google.co.jp*.google.co.uk*.google.com.ar*.google.com.au*.google.com.br*.google.com.co*.google.com.mx*.google.com.tr*.google.com.vn *.google.de *.google.es *.google.fr *.google.hu *.google.it *.google.nl *.google.pl *.google.pt*.googleadapis.com*.googleapis.cn*.googlecommerce.com*.googlevideo.com *.gstatic.cn *.gstatic.com *.gvt1.com *.gvt2.com*.metric.gstatic.com *.urchin.com*.url.google.com*.youtube-nocookie.com *.youtube.com*.youtubeeducation.com *.ytimg.comandroid.clients.google.com android.comg.cogoo.glgoogle-analytics.com google.comgooglecommerce.com urchin.com www.goo.glyoutu.be youtube.comyoutubeeducation.com0 U0h+\0Z0++0http://pki.google.com/GIAG2.crt0++0http://clients1.google.com/ocsp0U%"7ٞbow`͢0 U00U#0JhvbZ/0!U 00  +y0g 00U)0'0%#!http://pki.google.com/GIAG2.crl0  *H  rAe9c+5ieF"SJ*캗 9az%NRu"jNF~{E3Ϻ>q%% 5y7ůri00U#0zhd }}eN0UJhvbZ/0U0.+"0 0+0http://g.symcd.com0U005U.0,0*(&$http://g.symcb.com/crls/gtglobal.crl0U 00  +y0  *H   jg^~%$-m~ޝe,c4f>R/_:jPz}*H l|5Rh_ )M˨ކ oV}?y}!:/QvAq%7JL#5#s|M4.nspUg2,g?p[6"ll5Bl =d "s!_䍅":s`h>` h6:C[7׭RdW^4~50}00  *H 0N1 0 UUS10U Equifax1-0+U $Equifax Secure Certificate Authority0 020521040000Z 180821040000Z0B1 0 UUS10U  GeoTrust Inc.10UGeoTrust Global CA0"0  *H 0 c0#V~[&d΃qN{U^8S\O-P#6fˎ99 8.M>o,`96S9^&+=2(Rq3=86by0_+qk00U#0Hh+ҲG# O30Uzhd }}eN0U00U0:U3010/-+)http://crl.geotrust.com/crls/secureca.crl0NU G0E0CU 0;09+-https://www.geotrust.com/resources/repository0  *H vnNK0q~f;NC80}Uj6HfmGZ\s284I6Voڼsc{>"=_8tPNa? A G߇\{tUƖPLLL[^ a&bQI)sZ0+xF0D vH!'* =X\+G jNVfW'y!!1f2RK_e骱I9n*Crustls-v-0.21.10/rustls/src/msgs/handshake.rs000066400000000000000000002073131453461710000210510ustar00rootroot00000000000000#![allow(non_camel_case_types)] use crate::dns_name::{DnsName, DnsNameRef}; use crate::enums::{CipherSuite, HandshakeType, ProtocolVersion, SignatureScheme}; use crate::error::InvalidMessage; use crate::key; #[cfg(feature = "logging")] use crate::log::warn; use crate::msgs::base::{Payload, PayloadU16, PayloadU24, PayloadU8}; use crate::msgs::codec::{self, Codec, ListLength, Reader, TlsListElement}; use crate::msgs::enums::{ CertificateStatusType, ClientCertificateType, Compression, ECCurveType, ECPointFormat, ExtensionType, KeyUpdateRequest, NamedGroup, PSKKeyExchangeMode, ServerNameType, }; use crate::rand; use crate::verify::DigitallySignedStruct; use std::collections; use std::fmt; /// 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])* $name:ident, $inner:ident,) => { $(#[$comment])* #[derive(Clone, Debug)] pub struct $name($inner); impl From> for $name { fn from(v: Vec) -> 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) { self.0.encode(bytes); } fn read(r: &mut Reader) -> Result { Ok(Self($inner::read(r)?)) } } } ); #[derive(Clone, Copy, Eq, PartialEq)] pub struct Random(pub [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) { bytes.extend_from_slice(&self.0); } fn read(r: &mut Reader) -> Result { let bytes = match r.take(32) { Some(bytes) => bytes, None => return Err(InvalidMessage::MissingData("Random")), }; let mut opaque = [0; 32]; opaque.clone_from_slice(bytes); Ok(Self(opaque)) } } impl Random { pub fn new() -> Result { let mut data = [0u8; 32]; rand::fill_random(&mut data)?; Ok(Self(data)) } pub fn write_slice(&self, bytes: &mut [u8]) { let buf = self.get_encoding(); bytes.copy_from_slice(&buf); } } impl From<[u8; 32]> for Random { #[inline] fn from(bytes: [u8; 32]) -> Self { Self(bytes) } } #[derive(Copy, Clone)] pub 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) { debug_assert!(self.len <= 32); bytes.push(self.len as u8); bytes.extend_from_slice(&self.data[..self.len]); } fn read(r: &mut Reader) -> Result { let len = u8::read(r)? as usize; if len > 32 { return Err(InvalidMessage::TrailingData("SessionID")); } let bytes = match r.take(len) { Some(bytes) => bytes, None => 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 fn random() -> Result { let mut data = [0u8; 32]; rand::fill_random(&mut data)?; Ok(Self { data, len: 32 }) } pub fn empty() -> Self { Self { data: [0u8; 32], len: 0, } } pub fn len(&self) -> usize { self.len } pub fn is_empty(&self) -> bool { self.len == 0 } } #[derive(Clone, Debug)] pub struct UnknownExtension { pub typ: ExtensionType, pub payload: Payload, } impl UnknownExtension { fn encode(&self, bytes: &mut Vec) { self.payload.encode(bytes); } fn read(typ: ExtensionType, r: &mut Reader) -> Self { let payload = Payload::read(r); Self { typ, payload } } } impl TlsListElement for ECPointFormat { const SIZE_LEN: ListLength = ListLength::U8; } impl TlsListElement for NamedGroup { const SIZE_LEN: ListLength = ListLength::U16; } impl TlsListElement for SignatureScheme { const SIZE_LEN: ListLength = ListLength::U16; } #[derive(Clone, Debug)] pub enum ServerNamePayload { HostName(DnsName), Unknown(Payload), } impl ServerNamePayload { pub fn new_hostname(hostname: DnsName) -> Self { Self::HostName(hostname) } fn read_hostname(r: &mut Reader) -> Result { let raw = PayloadU16::read(r)?; match DnsName::try_from_ascii(&raw.0) { Ok(dns_name) => Ok(Self::HostName(dns_name)), Err(_) => { warn!( "Illegal SNI hostname received {:?}", String::from_utf8_lossy(&raw.0) ); Err(InvalidMessage::InvalidServerName) } } } fn encode(&self, bytes: &mut Vec) { match *self { Self::HostName(ref name) => { (name.as_ref().len() as u16).encode(bytes); bytes.extend_from_slice(name.as_ref().as_bytes()); } Self::Unknown(ref r) => r.encode(bytes), } } } #[derive(Clone, Debug)] pub struct ServerName { pub typ: ServerNameType, pub payload: ServerNamePayload, } impl Codec for ServerName { fn encode(&self, bytes: &mut Vec) { self.typ.encode(bytes); self.payload.encode(bytes); } fn read(r: &mut Reader) -> Result { let typ = ServerNameType::read(r)?; let payload = match typ { ServerNameType::HostName => ServerNamePayload::read_hostname(r)?, _ => ServerNamePayload::Unknown(Payload::read(r)), }; Ok(Self { typ, payload }) } } impl TlsListElement for ServerName { const SIZE_LEN: ListLength = ListLength::U16; } pub trait ConvertServerNameList { fn has_duplicate_names_for_type(&self) -> bool; fn get_single_hostname(&self) -> Option; } impl ConvertServerNameList for [ServerName] { /// RFC6066: "The ServerNameList MUST NOT contain more than one name of the same name_type." fn has_duplicate_names_for_type(&self) -> bool { let mut seen = collections::HashSet::new(); for name in self { if !seen.insert(name.typ.get_u8()) { return true; } } false } fn get_single_hostname(&self) -> Option { fn only_dns_hostnames(name: &ServerName) -> Option { if let ServerNamePayload::HostName(ref dns) = name.payload { Some(dns.borrow()) } else { None } } self.iter() .filter_map(only_dns_hostnames) .next() } } wrapped_payload!(ProtocolName, PayloadU8,); impl TlsListElement for ProtocolName { const SIZE_LEN: ListLength = ListLength::U16; } pub trait ConvertProtocolNameList { fn from_slices(names: &[&[u8]]) -> Self; fn to_slices(&self) -> Vec<&[u8]>; fn as_single_slice(&self) -> Option<&[u8]>; } impl ConvertProtocolNameList for Vec { fn from_slices(names: &[&[u8]]) -> Self { let mut ret = Self::new(); for name in names { ret.push(ProtocolName::from(name.to_vec())); } ret } fn to_slices(&self) -> Vec<&[u8]> { self.iter() .map(|proto| proto.as_ref()) .collect::>() } fn as_single_slice(&self) -> Option<&[u8]> { if self.len() == 1 { Some(self[0].as_ref()) } else { None } } } // --- TLS 1.3 Key shares --- #[derive(Clone, Debug)] pub struct KeyShareEntry { pub group: NamedGroup, pub payload: PayloadU16, } impl KeyShareEntry { pub fn new(group: NamedGroup, payload: &[u8]) -> Self { Self { group, payload: PayloadU16::new(payload.to_vec()), } } } impl Codec for KeyShareEntry { fn encode(&self, bytes: &mut Vec) { self.group.encode(bytes); self.payload.encode(bytes); } fn read(r: &mut Reader) -> Result { let group = NamedGroup::read(r)?; let payload = PayloadU16::read(r)?; Ok(Self { group, payload }) } } // --- TLS 1.3 PresharedKey offers --- #[derive(Clone, Debug)] pub struct PresharedKeyIdentity { pub identity: PayloadU16, pub obfuscated_ticket_age: u32, } impl PresharedKeyIdentity { pub fn new(id: Vec, age: u32) -> Self { Self { identity: PayloadU16::new(id), obfuscated_ticket_age: age, } } } impl Codec for PresharedKeyIdentity { fn encode(&self, bytes: &mut Vec) { self.identity.encode(bytes); self.obfuscated_ticket_age.encode(bytes); } fn read(r: &mut Reader) -> Result { Ok(Self { identity: PayloadU16::read(r)?, obfuscated_ticket_age: u32::read(r)?, }) } } impl TlsListElement for PresharedKeyIdentity { const SIZE_LEN: ListLength = ListLength::U16; } wrapped_payload!(PresharedKeyBinder, PayloadU8,); impl TlsListElement for PresharedKeyBinder { const SIZE_LEN: ListLength = ListLength::U16; } #[derive(Clone, Debug)] pub struct PresharedKeyOffer { pub identities: Vec, pub binders: Vec, } impl PresharedKeyOffer { /// Make a new one with one entry. pub fn new(id: PresharedKeyIdentity, binder: Vec) -> Self { Self { identities: vec![id], binders: vec![PresharedKeyBinder::from(binder)], } } } impl Codec for PresharedKeyOffer { fn encode(&self, bytes: &mut Vec) { self.identities.encode(bytes); self.binders.encode(bytes); } fn read(r: &mut Reader) -> Result { Ok(Self { identities: Vec::read(r)?, binders: Vec::read(r)?, }) } } // --- RFC6066 certificate status request --- wrapped_payload!(ResponderId, PayloadU16,); impl TlsListElement for ResponderId { const SIZE_LEN: ListLength = ListLength::U16; } #[derive(Clone, Debug)] pub struct OCSPCertificateStatusRequest { pub responder_ids: Vec, pub extensions: PayloadU16, } impl Codec for OCSPCertificateStatusRequest { fn encode(&self, bytes: &mut Vec) { CertificateStatusType::OCSP.encode(bytes); self.responder_ids.encode(bytes); self.extensions.encode(bytes); } fn read(r: &mut Reader) -> Result { Ok(Self { responder_ids: Vec::read(r)?, extensions: PayloadU16::read(r)?, }) } } #[derive(Clone, Debug)] pub enum CertificateStatusRequest { OCSP(OCSPCertificateStatusRequest), Unknown((CertificateStatusType, Payload)), } impl Codec for CertificateStatusRequest { fn encode(&self, bytes: &mut Vec) { match self { Self::OCSP(ref r) => r.encode(bytes), Self::Unknown((typ, payload)) => { typ.encode(bytes); payload.encode(bytes); } } } fn read(r: &mut Reader) -> Result { 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); Ok(Self::Unknown((typ, data))) } } } } impl CertificateStatusRequest { pub fn build_ocsp() -> Self { let ocsp = OCSPCertificateStatusRequest { responder_ids: Vec::new(), extensions: PayloadU16::empty(), }; Self::OCSP(ocsp) } } // --- // SCTs wrapped_payload!(Sct, PayloadU16,); impl TlsListElement for Sct { const SIZE_LEN: ListLength = ListLength::U16; } // --- impl TlsListElement for PSKKeyExchangeMode { const SIZE_LEN: ListLength = ListLength::U8; } impl TlsListElement for KeyShareEntry { const SIZE_LEN: ListLength = ListLength::U16; } impl TlsListElement for ProtocolVersion { const SIZE_LEN: ListLength = ListLength::U8; } #[derive(Clone, Debug)] pub enum ClientExtension { ECPointFormats(Vec), NamedGroups(Vec), SignatureAlgorithms(Vec), ServerName(Vec), SessionTicket(ClientSessionTicket), Protocols(Vec), SupportedVersions(Vec), KeyShare(Vec), PresharedKeyModes(Vec), PresharedKey(PresharedKeyOffer), Cookie(PayloadU16), ExtendedMasterSecretRequest, CertificateStatusRequest(CertificateStatusRequest), SignedCertificateTimestampRequest, TransportParameters(Vec), TransportParametersDraft(Vec), EarlyData, Unknown(UnknownExtension), } impl ClientExtension { pub fn get_type(&self) -> ExtensionType { match *self { Self::ECPointFormats(_) => ExtensionType::ECPointFormats, Self::NamedGroups(_) => ExtensionType::EllipticCurves, Self::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, Self::ServerName(_) => ExtensionType::ServerName, Self::SessionTicket(_) => ExtensionType::SessionTicket, Self::Protocols(_) => ExtensionType::ALProtocolNegotiation, Self::SupportedVersions(_) => ExtensionType::SupportedVersions, Self::KeyShare(_) => ExtensionType::KeyShare, Self::PresharedKeyModes(_) => ExtensionType::PSKKeyExchangeModes, Self::PresharedKey(_) => ExtensionType::PreSharedKey, Self::Cookie(_) => ExtensionType::Cookie, Self::ExtendedMasterSecretRequest => ExtensionType::ExtendedMasterSecret, Self::CertificateStatusRequest(_) => ExtensionType::StatusRequest, Self::SignedCertificateTimestampRequest => ExtensionType::SCT, Self::TransportParameters(_) => ExtensionType::TransportParameters, Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft, Self::EarlyData => ExtensionType::EarlyData, Self::Unknown(ref r) => r.typ, } } } impl Codec for ClientExtension { fn encode(&self, bytes: &mut Vec) { self.get_type().encode(bytes); let mut sub: Vec = Vec::new(); match *self { Self::ECPointFormats(ref r) => r.encode(&mut sub), Self::NamedGroups(ref r) => r.encode(&mut sub), Self::SignatureAlgorithms(ref r) => r.encode(&mut sub), Self::ServerName(ref r) => r.encode(&mut sub), Self::SessionTicket(ClientSessionTicket::Request) | Self::ExtendedMasterSecretRequest | Self::SignedCertificateTimestampRequest | Self::EarlyData => {} Self::SessionTicket(ClientSessionTicket::Offer(ref r)) => r.encode(&mut sub), Self::Protocols(ref r) => r.encode(&mut sub), Self::SupportedVersions(ref r) => r.encode(&mut sub), Self::KeyShare(ref r) => r.encode(&mut sub), Self::PresharedKeyModes(ref r) => r.encode(&mut sub), Self::PresharedKey(ref r) => r.encode(&mut sub), Self::Cookie(ref r) => r.encode(&mut sub), Self::CertificateStatusRequest(ref r) => r.encode(&mut sub), Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => { sub.extend_from_slice(r); } Self::Unknown(ref r) => r.encode(&mut sub), } (sub.len() as u16).encode(bytes); bytes.append(&mut sub); } fn read(r: &mut Reader) -> Result { let typ = ExtensionType::read(r)?; let len = u16::read(r)? as usize; let mut sub = r.sub(len)?; let ext = match typ { ExtensionType::ECPointFormats => Self::ECPointFormats(Vec::read(&mut sub)?), ExtensionType::EllipticCurves => Self::NamedGroups(Vec::read(&mut sub)?), ExtensionType::SignatureAlgorithms => Self::SignatureAlgorithms(Vec::read(&mut sub)?), ExtensionType::ServerName => Self::ServerName(Vec::read(&mut sub)?), ExtensionType::SessionTicket => { if sub.any_left() { let contents = Payload::read(&mut sub); Self::SessionTicket(ClientSessionTicket::Offer(contents)) } else { Self::SessionTicket(ClientSessionTicket::Request) } } ExtensionType::ALProtocolNegotiation => Self::Protocols(Vec::read(&mut sub)?), ExtensionType::SupportedVersions => Self::SupportedVersions(Vec::read(&mut sub)?), ExtensionType::KeyShare => Self::KeyShare(Vec::read(&mut sub)?), ExtensionType::PSKKeyExchangeModes => Self::PresharedKeyModes(Vec::read(&mut sub)?), ExtensionType::PreSharedKey => Self::PresharedKey(PresharedKeyOffer::read(&mut sub)?), ExtensionType::Cookie => Self::Cookie(PayloadU16::read(&mut sub)?), ExtensionType::ExtendedMasterSecret if !sub.any_left() => { Self::ExtendedMasterSecretRequest } ExtensionType::StatusRequest => { let csr = CertificateStatusRequest::read(&mut sub)?; Self::CertificateStatusRequest(csr) } ExtensionType::SCT if !sub.any_left() => Self::SignedCertificateTimestampRequest, ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()), ExtensionType::TransportParametersDraft => { Self::TransportParametersDraft(sub.rest().to_vec()) } ExtensionType::EarlyData if !sub.any_left() => Self::EarlyData, _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; sub.expect_empty("ClientExtension") .map(|_| ext) } } fn trim_hostname_trailing_dot_for_sni(dns_name: DnsNameRef) -> DnsName { let dns_name_str: &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]; DnsNameRef::try_from(trimmed) .unwrap() .to_owned() } else { dns_name.to_owned() } } impl ClientExtension { /// Make a basic SNI ServerNameRequest quoting `hostname`. pub fn make_sni(dns_name: DnsNameRef) -> Self { let name = ServerName { typ: ServerNameType::HostName, payload: ServerNamePayload::new_hostname(trim_hostname_trailing_dot_for_sni(dns_name)), }; Self::ServerName(vec![name]) } } #[derive(Clone, Debug)] pub enum ClientSessionTicket { Request, Offer(Payload), } #[derive(Clone, Debug)] pub enum ServerExtension { ECPointFormats(Vec), ServerNameAck, SessionTicketAck, RenegotiationInfo(PayloadU8), Protocols(Vec), KeyShare(KeyShareEntry), PresharedKey(u16), ExtendedMasterSecretAck, CertificateStatusAck, SignedCertificateTimestamp(Vec), SupportedVersions(ProtocolVersion), TransportParameters(Vec), TransportParametersDraft(Vec), EarlyData, Unknown(UnknownExtension), } impl ServerExtension { pub fn get_type(&self) -> ExtensionType { match *self { Self::ECPointFormats(_) => ExtensionType::ECPointFormats, Self::ServerNameAck => ExtensionType::ServerName, Self::SessionTicketAck => ExtensionType::SessionTicket, Self::RenegotiationInfo(_) => ExtensionType::RenegotiationInfo, Self::Protocols(_) => ExtensionType::ALProtocolNegotiation, Self::KeyShare(_) => ExtensionType::KeyShare, Self::PresharedKey(_) => ExtensionType::PreSharedKey, Self::ExtendedMasterSecretAck => ExtensionType::ExtendedMasterSecret, Self::CertificateStatusAck => ExtensionType::StatusRequest, Self::SignedCertificateTimestamp(_) => ExtensionType::SCT, Self::SupportedVersions(_) => ExtensionType::SupportedVersions, Self::TransportParameters(_) => ExtensionType::TransportParameters, Self::TransportParametersDraft(_) => ExtensionType::TransportParametersDraft, Self::EarlyData => ExtensionType::EarlyData, Self::Unknown(ref r) => r.typ, } } } impl Codec for ServerExtension { fn encode(&self, bytes: &mut Vec) { self.get_type().encode(bytes); let mut sub: Vec = Vec::new(); match *self { Self::ECPointFormats(ref r) => r.encode(&mut sub), Self::ServerNameAck | Self::SessionTicketAck | Self::ExtendedMasterSecretAck | Self::CertificateStatusAck | Self::EarlyData => {} Self::RenegotiationInfo(ref r) => r.encode(&mut sub), Self::Protocols(ref r) => r.encode(&mut sub), Self::KeyShare(ref r) => r.encode(&mut sub), Self::PresharedKey(r) => r.encode(&mut sub), Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub), Self::SupportedVersions(ref r) => r.encode(&mut sub), Self::TransportParameters(ref r) | Self::TransportParametersDraft(ref r) => { sub.extend_from_slice(r); } Self::Unknown(ref r) => r.encode(&mut sub), } (sub.len() as u16).encode(bytes); bytes.append(&mut sub); } fn read(r: &mut Reader) -> Result { let typ = ExtensionType::read(r)?; let len = u16::read(r)? as usize; let mut sub = r.sub(len)?; let ext = match typ { ExtensionType::ECPointFormats => Self::ECPointFormats(Vec::read(&mut sub)?), ExtensionType::ServerName => Self::ServerNameAck, ExtensionType::SessionTicket => Self::SessionTicketAck, ExtensionType::StatusRequest => Self::CertificateStatusAck, ExtensionType::RenegotiationInfo => Self::RenegotiationInfo(PayloadU8::read(&mut sub)?), ExtensionType::ALProtocolNegotiation => Self::Protocols(Vec::read(&mut sub)?), ExtensionType::KeyShare => Self::KeyShare(KeyShareEntry::read(&mut sub)?), ExtensionType::PreSharedKey => Self::PresharedKey(u16::read(&mut sub)?), ExtensionType::ExtendedMasterSecret => Self::ExtendedMasterSecretAck, ExtensionType::SCT => Self::SignedCertificateTimestamp(Vec::read(&mut sub)?), ExtensionType::SupportedVersions => { Self::SupportedVersions(ProtocolVersion::read(&mut sub)?) } ExtensionType::TransportParameters => Self::TransportParameters(sub.rest().to_vec()), ExtensionType::TransportParametersDraft => { Self::TransportParametersDraft(sub.rest().to_vec()) } ExtensionType::EarlyData => Self::EarlyData, _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; sub.expect_empty("ServerExtension") .map(|_| ext) } } impl ServerExtension { pub fn make_alpn(proto: &[&[u8]]) -> Self { Self::Protocols(Vec::from_slices(proto)) } pub fn make_empty_renegotiation_info() -> Self { let empty = Vec::new(); Self::RenegotiationInfo(PayloadU8::new(empty)) } pub fn make_sct(sctl: Vec) -> Self { let scts = Vec::read_bytes(&sctl).expect("invalid SCT list"); Self::SignedCertificateTimestamp(scts) } } #[derive(Debug)] pub struct ClientHelloPayload { pub client_version: ProtocolVersion, pub random: Random, pub session_id: SessionId, pub cipher_suites: Vec, pub compression_methods: Vec, pub extensions: Vec, } impl Codec for ClientHelloPayload { fn encode(&self, bytes: &mut Vec) { self.client_version.encode(bytes); self.random.encode(bytes); self.session_id.encode(bytes); self.cipher_suites.encode(bytes); self.compression_methods.encode(bytes); if !self.extensions.is_empty() { self.extensions.encode(bytes); } } fn read(r: &mut Reader) -> Result { let mut 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: Vec::new(), }; if r.any_left() { ret.extensions = Vec::read(r)?; } match (r.any_left(), ret.extensions.is_empty()) { (true, _) => Err(InvalidMessage::TrailingData("ClientHelloPayload")), (_, true) => Err(InvalidMessage::MissingData("ClientHelloPayload")), _ => Ok(ret), } } } impl TlsListElement for CipherSuite { const SIZE_LEN: ListLength = ListLength::U16; } impl TlsListElement for Compression { const SIZE_LEN: ListLength = ListLength::U8; } impl TlsListElement for ClientExtension { const SIZE_LEN: ListLength = ListLength::U16; } impl ClientHelloPayload { /// Returns true if there is more than one extension of a given /// type. pub fn has_duplicate_extension(&self) -> bool { let mut seen = collections::HashSet::new(); for ext in &self.extensions { let typ = ext.get_type().get_u16(); if seen.contains(&typ) { return true; } seen.insert(typ); } false } pub fn find_extension(&self, ext: ExtensionType) -> Option<&ClientExtension> { self.extensions .iter() .find(|x| x.get_type() == ext) } pub fn get_sni_extension(&self) -> Option<&[ServerName]> { let ext = self.find_extension(ExtensionType::ServerName)?; match *ext { ClientExtension::ServerName(ref req) => Some(req), _ => None, } } pub fn get_sigalgs_extension(&self) -> Option<&[SignatureScheme]> { let ext = self.find_extension(ExtensionType::SignatureAlgorithms)?; match *ext { ClientExtension::SignatureAlgorithms(ref req) => Some(req), _ => None, } } pub fn get_namedgroups_extension(&self) -> Option<&[NamedGroup]> { let ext = self.find_extension(ExtensionType::EllipticCurves)?; match *ext { ClientExtension::NamedGroups(ref req) => Some(req), _ => None, } } pub fn get_ecpoints_extension(&self) -> Option<&[ECPointFormat]> { let ext = self.find_extension(ExtensionType::ECPointFormats)?; match *ext { ClientExtension::ECPointFormats(ref req) => Some(req), _ => None, } } pub fn get_alpn_extension(&self) -> Option<&Vec> { let ext = self.find_extension(ExtensionType::ALProtocolNegotiation)?; match *ext { ClientExtension::Protocols(ref req) => Some(req), _ => None, } } pub fn get_quic_params_extension(&self) -> Option> { let ext = self .find_extension(ExtensionType::TransportParameters) .or_else(|| self.find_extension(ExtensionType::TransportParametersDraft))?; match *ext { ClientExtension::TransportParameters(ref bytes) | ClientExtension::TransportParametersDraft(ref bytes) => Some(bytes.to_vec()), _ => None, } } pub fn get_ticket_extension(&self) -> Option<&ClientExtension> { self.find_extension(ExtensionType::SessionTicket) } pub fn get_versions_extension(&self) -> Option<&[ProtocolVersion]> { let ext = self.find_extension(ExtensionType::SupportedVersions)?; match *ext { ClientExtension::SupportedVersions(ref vers) => Some(vers), _ => None, } } pub fn get_keyshare_extension(&self) -> Option<&[KeyShareEntry]> { let ext = self.find_extension(ExtensionType::KeyShare)?; match *ext { ClientExtension::KeyShare(ref shares) => Some(shares), _ => None, } } pub fn has_keyshare_extension_with_duplicates(&self) -> bool { if let Some(entries) = self.get_keyshare_extension() { let mut seen = collections::HashSet::new(); for kse in entries { let grp = kse.group.get_u16(); if !seen.insert(grp) { return true; } } } false } pub fn get_psk(&self) -> Option<&PresharedKeyOffer> { let ext = self.find_extension(ExtensionType::PreSharedKey)?; match *ext { ClientExtension::PresharedKey(ref psk) => Some(psk), _ => None, } } pub fn check_psk_ext_is_last(&self) -> bool { self.extensions .last() .map_or(false, |ext| ext.get_type() == ExtensionType::PreSharedKey) } pub fn get_psk_modes(&self) -> Option<&[PSKKeyExchangeMode]> { let ext = self.find_extension(ExtensionType::PSKKeyExchangeModes)?; match *ext { ClientExtension::PresharedKeyModes(ref psk_modes) => Some(psk_modes), _ => None, } } pub fn psk_mode_offered(&self, mode: PSKKeyExchangeMode) -> bool { self.get_psk_modes() .map(|modes| modes.contains(&mode)) .unwrap_or(false) } pub fn set_psk_binder(&mut self, binder: impl Into>) { let last_extension = self.extensions.last_mut(); if let Some(ClientExtension::PresharedKey(ref mut offer)) = last_extension { offer.binders[0] = PresharedKeyBinder::from(binder.into()); } } pub fn ems_support_offered(&self) -> bool { self.find_extension(ExtensionType::ExtendedMasterSecret) .is_some() } pub fn early_data_extension_offered(&self) -> bool { self.find_extension(ExtensionType::EarlyData) .is_some() } } #[derive(Debug)] pub enum HelloRetryExtension { KeyShare(NamedGroup), Cookie(PayloadU16), SupportedVersions(ProtocolVersion), Unknown(UnknownExtension), } impl HelloRetryExtension { pub fn get_type(&self) -> ExtensionType { match *self { Self::KeyShare(_) => ExtensionType::KeyShare, Self::Cookie(_) => ExtensionType::Cookie, Self::SupportedVersions(_) => ExtensionType::SupportedVersions, Self::Unknown(ref r) => r.typ, } } } impl Codec for HelloRetryExtension { fn encode(&self, bytes: &mut Vec) { self.get_type().encode(bytes); let mut sub: Vec = Vec::new(); match *self { Self::KeyShare(ref r) => r.encode(&mut sub), Self::Cookie(ref r) => r.encode(&mut sub), Self::SupportedVersions(ref r) => r.encode(&mut sub), Self::Unknown(ref r) => r.encode(&mut sub), } (sub.len() as u16).encode(bytes); bytes.append(&mut sub); } fn read(r: &mut Reader) -> Result { let typ = ExtensionType::read(r)?; let len = u16::read(r)? as usize; let mut sub = r.sub(len)?; let ext = match typ { ExtensionType::KeyShare => Self::KeyShare(NamedGroup::read(&mut sub)?), ExtensionType::Cookie => Self::Cookie(PayloadU16::read(&mut sub)?), ExtensionType::SupportedVersions => { Self::SupportedVersions(ProtocolVersion::read(&mut sub)?) } _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; sub.expect_empty("HelloRetryExtension") .map(|_| ext) } } impl TlsListElement for HelloRetryExtension { const SIZE_LEN: ListLength = ListLength::U16; } #[derive(Debug)] pub struct HelloRetryRequest { pub legacy_version: ProtocolVersion, pub session_id: SessionId, pub cipher_suite: CipherSuite, pub extensions: Vec, } impl Codec for HelloRetryRequest { fn encode(&self, bytes: &mut Vec) { 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); self.extensions.encode(bytes); } fn read(r: &mut Reader) -> Result { 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: Vec::read(r)?, }) } } impl HelloRetryRequest { /// Returns true if there is more than one extension of a given /// type. pub fn has_duplicate_extension(&self) -> bool { let mut seen = collections::HashSet::new(); for ext in &self.extensions { let typ = ext.get_type().get_u16(); if seen.contains(&typ) { return true; } seen.insert(typ); } false } pub fn has_unknown_extension(&self) -> bool { self.extensions.iter().any(|ext| { ext.get_type() != ExtensionType::KeyShare && ext.get_type() != ExtensionType::SupportedVersions && ext.get_type() != ExtensionType::Cookie }) } fn find_extension(&self, ext: ExtensionType) -> Option<&HelloRetryExtension> { self.extensions .iter() .find(|x| x.get_type() == ext) } pub fn get_requested_key_share_group(&self) -> Option { let ext = self.find_extension(ExtensionType::KeyShare)?; match *ext { HelloRetryExtension::KeyShare(grp) => Some(grp), _ => None, } } pub fn get_cookie(&self) -> Option<&PayloadU16> { let ext = self.find_extension(ExtensionType::Cookie)?; match *ext { HelloRetryExtension::Cookie(ref ck) => Some(ck), _ => None, } } pub fn get_supported_versions(&self) -> Option { let ext = self.find_extension(ExtensionType::SupportedVersions)?; match *ext { HelloRetryExtension::SupportedVersions(ver) => Some(ver), _ => None, } } } #[derive(Debug)] pub struct ServerHelloPayload { pub legacy_version: ProtocolVersion, pub random: Random, pub session_id: SessionId, pub cipher_suite: CipherSuite, pub compression_method: Compression, pub extensions: Vec, } impl Codec for ServerHelloPayload { fn encode(&self, bytes: &mut Vec) { self.legacy_version.encode(bytes); self.random.encode(bytes); self.session_id.encode(bytes); self.cipher_suite.encode(bytes); self.compression_method.encode(bytes); if !self.extensions.is_empty() { self.extensions.encode(bytes); } } // minus version and random, which have already been read. fn read(r: &mut Reader) -> Result { 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 = if r.any_left() { Vec::read(r)? } else { vec![] }; 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 HasServerExtensions for ServerHelloPayload { fn get_extensions(&self) -> &[ServerExtension] { &self.extensions } } impl ServerHelloPayload { pub fn get_key_share(&self) -> Option<&KeyShareEntry> { let ext = self.find_extension(ExtensionType::KeyShare)?; match *ext { ServerExtension::KeyShare(ref share) => Some(share), _ => None, } } pub fn get_psk_index(&self) -> Option { let ext = self.find_extension(ExtensionType::PreSharedKey)?; match *ext { ServerExtension::PresharedKey(ref index) => Some(*index), _ => None, } } pub fn get_ecpoints_extension(&self) -> Option<&[ECPointFormat]> { let ext = self.find_extension(ExtensionType::ECPointFormats)?; match *ext { ServerExtension::ECPointFormats(ref fmts) => Some(fmts), _ => None, } } pub fn ems_support_acked(&self) -> bool { self.find_extension(ExtensionType::ExtendedMasterSecret) .is_some() } pub fn get_sct_list(&self) -> Option<&[Sct]> { let ext = self.find_extension(ExtensionType::SCT)?; match *ext { ServerExtension::SignedCertificateTimestamp(ref sctl) => Some(sctl), _ => None, } } pub fn get_supported_versions(&self) -> Option { let ext = self.find_extension(ExtensionType::SupportedVersions)?; match *ext { ServerExtension::SupportedVersions(vers) => Some(vers), _ => None, } } } pub type CertificatePayload = Vec; impl TlsListElement for key::Certificate { const SIZE_LEN: ListLength = ListLength::U24 { max: 0x1_0000 }; } // TLS1.3 changes the Certificate payload encoding. // That's annoying. It means the parsing is not // context-free any more. #[derive(Debug)] pub enum CertificateExtension { CertificateStatus(CertificateStatus), SignedCertificateTimestamp(Vec), Unknown(UnknownExtension), } impl CertificateExtension { pub fn get_type(&self) -> ExtensionType { match *self { Self::CertificateStatus(_) => ExtensionType::StatusRequest, Self::SignedCertificateTimestamp(_) => ExtensionType::SCT, Self::Unknown(ref r) => r.typ, } } pub fn make_sct(sct_list: Vec) -> Self { let sctl = Vec::read_bytes(&sct_list).expect("invalid SCT list"); Self::SignedCertificateTimestamp(sctl) } pub fn get_cert_status(&self) -> Option<&Vec> { match *self { Self::CertificateStatus(ref cs) => Some(&cs.ocsp_response.0), _ => None, } } pub fn get_sct_list(&self) -> Option<&[Sct]> { match *self { Self::SignedCertificateTimestamp(ref sctl) => Some(sctl), _ => None, } } } impl Codec for CertificateExtension { fn encode(&self, bytes: &mut Vec) { self.get_type().encode(bytes); let mut sub: Vec = Vec::new(); match *self { Self::CertificateStatus(ref r) => r.encode(&mut sub), Self::SignedCertificateTimestamp(ref r) => r.encode(&mut sub), Self::Unknown(ref r) => r.encode(&mut sub), } (sub.len() as u16).encode(bytes); bytes.append(&mut sub); } fn read(r: &mut Reader) -> Result { let typ = ExtensionType::read(r)?; let len = u16::read(r)? as usize; let mut sub = r.sub(len)?; let ext = match typ { ExtensionType::StatusRequest => { let st = CertificateStatus::read(&mut sub)?; Self::CertificateStatus(st) } ExtensionType::SCT => Self::SignedCertificateTimestamp(Vec::read(&mut sub)?), _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; sub.expect_empty("CertificateExtension") .map(|_| ext) } } impl TlsListElement for CertificateExtension { const SIZE_LEN: ListLength = ListLength::U16; } #[derive(Debug)] pub struct CertificateEntry { pub cert: key::Certificate, pub exts: Vec, } impl Codec for CertificateEntry { fn encode(&self, bytes: &mut Vec) { self.cert.encode(bytes); self.exts.encode(bytes); } fn read(r: &mut Reader) -> Result { Ok(Self { cert: key::Certificate::read(r)?, exts: Vec::read(r)?, }) } } impl CertificateEntry { pub fn new(cert: key::Certificate) -> Self { Self { cert, exts: Vec::new(), } } pub fn has_duplicate_extension(&self) -> bool { let mut seen = collections::HashSet::new(); for ext in &self.exts { let typ = ext.get_type().get_u16(); if seen.contains(&typ) { return true; } seen.insert(typ); } false } pub fn has_unknown_extension(&self) -> bool { self.exts.iter().any(|ext| { ext.get_type() != ExtensionType::StatusRequest && ext.get_type() != ExtensionType::SCT }) } pub fn get_ocsp_response(&self) -> Option<&Vec> { self.exts .iter() .find(|ext| ext.get_type() == ExtensionType::StatusRequest) .and_then(CertificateExtension::get_cert_status) } pub fn get_scts(&self) -> Option<&[Sct]> { self.exts .iter() .find(|ext| ext.get_type() == ExtensionType::SCT) .and_then(CertificateExtension::get_sct_list) } } impl TlsListElement for CertificateEntry { const SIZE_LEN: ListLength = ListLength::U24 { max: 0x1_0000 }; } #[derive(Debug)] pub struct CertificatePayloadTLS13 { pub context: PayloadU8, pub entries: Vec, } impl Codec for CertificatePayloadTLS13 { fn encode(&self, bytes: &mut Vec) { self.context.encode(bytes); self.entries.encode(bytes); } fn read(r: &mut Reader) -> Result { Ok(Self { context: PayloadU8::read(r)?, entries: Vec::read(r)?, }) } } impl CertificatePayloadTLS13 { pub fn new(entries: Vec) -> Self { Self { context: PayloadU8::empty(), entries, } } pub fn any_entry_has_duplicate_extension(&self) -> bool { for entry in &self.entries { if entry.has_duplicate_extension() { return true; } } false } pub fn any_entry_has_unknown_extension(&self) -> bool { for entry in &self.entries { if entry.has_unknown_extension() { return true; } } false } pub fn any_entry_has_extension(&self) -> bool { for entry in &self.entries { if !entry.exts.is_empty() { return true; } } false } pub fn get_end_entity_ocsp(&self) -> Vec { self.entries .first() .and_then(CertificateEntry::get_ocsp_response) .cloned() .unwrap_or_default() } pub fn get_end_entity_scts(&self) -> Option<&[Sct]> { self.entries .first() .and_then(CertificateEntry::get_scts) } pub fn convert(&self) -> CertificatePayload { let mut ret = Vec::new(); for entry in &self.entries { ret.push(entry.cert.clone()); } ret } } #[derive(Clone, Copy, Debug, PartialEq)] pub enum KeyExchangeAlgorithm { BulkOnly, DH, DHE, RSA, ECDH, ECDHE, } // We don't support arbitrary curves. It's a terrible // idea and unnecessary attack surface. Please, // get a grip. #[derive(Debug)] pub struct ECParameters { pub curve_type: ECCurveType, pub named_group: NamedGroup, } impl Codec for ECParameters { fn encode(&self, bytes: &mut Vec) { self.curve_type.encode(bytes); self.named_group.encode(bytes); } fn read(r: &mut Reader) -> Result { 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, }) } } #[derive(Debug)] pub struct ClientECDHParams { pub public: PayloadU8, } impl Codec for ClientECDHParams { fn encode(&self, bytes: &mut Vec) { self.public.encode(bytes); } fn read(r: &mut Reader) -> Result { let pb = PayloadU8::read(r)?; Ok(Self { public: pb }) } } #[derive(Debug)] pub struct ServerECDHParams { pub curve_params: ECParameters, pub public: PayloadU8, } impl ServerECDHParams { pub fn new(named_group: NamedGroup, pubkey: &[u8]) -> Self { Self { curve_params: ECParameters { curve_type: ECCurveType::NamedCurve, named_group, }, public: PayloadU8::new(pubkey.to_vec()), } } } impl Codec for ServerECDHParams { fn encode(&self, bytes: &mut Vec) { self.curve_params.encode(bytes); self.public.encode(bytes); } fn read(r: &mut Reader) -> Result { let cp = ECParameters::read(r)?; let pb = PayloadU8::read(r)?; Ok(Self { curve_params: cp, public: pb, }) } } #[derive(Debug)] pub struct ECDHEServerKeyExchange { pub params: ServerECDHParams, pub dss: DigitallySignedStruct, } impl Codec for ECDHEServerKeyExchange { fn encode(&self, bytes: &mut Vec) { self.params.encode(bytes); self.dss.encode(bytes); } fn read(r: &mut Reader) -> Result { let params = ServerECDHParams::read(r)?; let dss = DigitallySignedStruct::read(r)?; Ok(Self { params, dss }) } } #[derive(Debug)] pub enum ServerKeyExchangePayload { ECDHE(ECDHEServerKeyExchange), Unknown(Payload), } impl Codec for ServerKeyExchangePayload { fn encode(&self, bytes: &mut Vec) { match *self { Self::ECDHE(ref x) => x.encode(bytes), Self::Unknown(ref x) => x.encode(bytes), } } fn read(r: &mut Reader) -> Result { // read as Unknown, fully parse when we know the // KeyExchangeAlgorithm Ok(Self::Unknown(Payload::read(r))) } } impl ServerKeyExchangePayload { pub fn unwrap_given_kxa(&self, kxa: KeyExchangeAlgorithm) -> Option { if let Self::Unknown(ref unk) = *self { let mut rd = Reader::init(&unk.0); let result = match kxa { KeyExchangeAlgorithm::ECDHE => ECDHEServerKeyExchange::read(&mut rd), _ => return None, }; if !rd.any_left() { return result.ok(); }; } None } } // -- EncryptedExtensions (TLS1.3 only) -- impl TlsListElement for ServerExtension { const SIZE_LEN: ListLength = ListLength::U16; } pub trait HasServerExtensions { fn get_extensions(&self) -> &[ServerExtension]; /// Returns true if there is more than one extension of a given /// type. fn has_duplicate_extension(&self) -> bool { let mut seen = collections::HashSet::new(); for ext in self.get_extensions() { let typ = ext.get_type().get_u16(); if seen.contains(&typ) { return true; } seen.insert(typ); } false } fn find_extension(&self, ext: ExtensionType) -> Option<&ServerExtension> { self.get_extensions() .iter() .find(|x| x.get_type() == ext) } fn get_alpn_protocol(&self) -> Option<&[u8]> { let ext = self.find_extension(ExtensionType::ALProtocolNegotiation)?; match *ext { ServerExtension::Protocols(ref protos) => protos.as_single_slice(), _ => None, } } fn get_quic_params_extension(&self) -> Option> { let ext = self .find_extension(ExtensionType::TransportParameters) .or_else(|| self.find_extension(ExtensionType::TransportParametersDraft))?; match *ext { ServerExtension::TransportParameters(ref bytes) | ServerExtension::TransportParametersDraft(ref bytes) => Some(bytes.to_vec()), _ => None, } } fn early_data_extension_offered(&self) -> bool { self.find_extension(ExtensionType::EarlyData) .is_some() } } impl HasServerExtensions for Vec { fn get_extensions(&self) -> &[ServerExtension] { self } } impl TlsListElement for ClientCertificateType { const SIZE_LEN: ListLength = ListLength::U8; } wrapped_payload!( /// A `DistinguishedName` is a `Vec` 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); /// } /// ``` DistinguishedName, PayloadU16, ); impl TlsListElement for DistinguishedName { const SIZE_LEN: ListLength = ListLength::U16; } #[derive(Debug)] pub struct CertificateRequestPayload { pub certtypes: Vec, pub sigschemes: Vec, pub canames: Vec, } impl Codec for CertificateRequestPayload { fn encode(&self, bytes: &mut Vec) { self.certtypes.encode(bytes); self.sigschemes.encode(bytes); self.canames.encode(bytes); } fn read(r: &mut Reader) -> Result { 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, }) } } } #[derive(Debug)] pub enum CertReqExtension { SignatureAlgorithms(Vec), AuthorityNames(Vec), Unknown(UnknownExtension), } impl CertReqExtension { pub fn get_type(&self) -> ExtensionType { match *self { Self::SignatureAlgorithms(_) => ExtensionType::SignatureAlgorithms, Self::AuthorityNames(_) => ExtensionType::CertificateAuthorities, Self::Unknown(ref r) => r.typ, } } } impl Codec for CertReqExtension { fn encode(&self, bytes: &mut Vec) { self.get_type().encode(bytes); let mut sub: Vec = Vec::new(); match *self { Self::SignatureAlgorithms(ref r) => r.encode(&mut sub), Self::AuthorityNames(ref r) => r.encode(&mut sub), Self::Unknown(ref r) => r.encode(&mut sub), } (sub.len() as u16).encode(bytes); bytes.append(&mut sub); } fn read(r: &mut Reader) -> Result { let typ = ExtensionType::read(r)?; let len = u16::read(r)? as usize; let mut sub = r.sub(len)?; let ext = match typ { ExtensionType::SignatureAlgorithms => { let schemes = Vec::read(&mut sub)?; if schemes.is_empty() { return Err(InvalidMessage::NoSignatureSchemes); } Self::SignatureAlgorithms(schemes) } ExtensionType::CertificateAuthorities => { let cas = Vec::read(&mut sub)?; Self::AuthorityNames(cas) } _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; sub.expect_empty("CertReqExtension") .map(|_| ext) } } impl TlsListElement for CertReqExtension { const SIZE_LEN: ListLength = ListLength::U16; } #[derive(Debug)] pub struct CertificateRequestPayloadTLS13 { pub context: PayloadU8, pub extensions: Vec, } impl Codec for CertificateRequestPayloadTLS13 { fn encode(&self, bytes: &mut Vec) { self.context.encode(bytes); self.extensions.encode(bytes); } fn read(r: &mut Reader) -> Result { let context = PayloadU8::read(r)?; let extensions = Vec::read(r)?; Ok(Self { context, extensions, }) } } impl CertificateRequestPayloadTLS13 { pub fn find_extension(&self, ext: ExtensionType) -> Option<&CertReqExtension> { self.extensions .iter() .find(|x| x.get_type() == ext) } pub fn get_sigalgs_extension(&self) -> Option<&[SignatureScheme]> { let ext = self.find_extension(ExtensionType::SignatureAlgorithms)?; match *ext { CertReqExtension::SignatureAlgorithms(ref sa) => Some(sa), _ => None, } } pub fn get_authorities_extension(&self) -> Option<&[DistinguishedName]> { let ext = self.find_extension(ExtensionType::CertificateAuthorities)?; match *ext { CertReqExtension::AuthorityNames(ref an) => Some(an), _ => None, } } } // -- NewSessionTicket -- #[derive(Debug)] pub struct NewSessionTicketPayload { pub lifetime_hint: u32, pub ticket: PayloadU16, } impl NewSessionTicketPayload { pub fn new(lifetime_hint: u32, ticket: Vec) -> Self { Self { lifetime_hint, ticket: PayloadU16::new(ticket), } } } impl Codec for NewSessionTicketPayload { fn encode(&self, bytes: &mut Vec) { self.lifetime_hint.encode(bytes); self.ticket.encode(bytes); } fn read(r: &mut Reader) -> Result { let lifetime = u32::read(r)?; let ticket = PayloadU16::read(r)?; Ok(Self { lifetime_hint: lifetime, ticket, }) } } // -- NewSessionTicket electric boogaloo -- #[derive(Debug)] pub enum NewSessionTicketExtension { EarlyData(u32), Unknown(UnknownExtension), } impl NewSessionTicketExtension { pub fn get_type(&self) -> ExtensionType { match *self { Self::EarlyData(_) => ExtensionType::EarlyData, Self::Unknown(ref r) => r.typ, } } } impl Codec for NewSessionTicketExtension { fn encode(&self, bytes: &mut Vec) { self.get_type().encode(bytes); let mut sub: Vec = Vec::new(); match *self { Self::EarlyData(r) => r.encode(&mut sub), Self::Unknown(ref r) => r.encode(&mut sub), } (sub.len() as u16).encode(bytes); bytes.append(&mut sub); } fn read(r: &mut Reader) -> Result { let typ = ExtensionType::read(r)?; let len = u16::read(r)? as usize; let mut sub = r.sub(len)?; let ext = match typ { ExtensionType::EarlyData => Self::EarlyData(u32::read(&mut sub)?), _ => Self::Unknown(UnknownExtension::read(typ, &mut sub)), }; sub.expect_empty("NewSessionTicketExtension") .map(|_| ext) } } impl TlsListElement for NewSessionTicketExtension { const SIZE_LEN: ListLength = ListLength::U16; } #[derive(Debug)] pub struct NewSessionTicketPayloadTLS13 { pub lifetime: u32, pub age_add: u32, pub nonce: PayloadU8, pub ticket: PayloadU16, pub exts: Vec, } impl NewSessionTicketPayloadTLS13 { pub fn new(lifetime: u32, age_add: u32, nonce: Vec, ticket: Vec) -> Self { Self { lifetime, age_add, nonce: PayloadU8::new(nonce), ticket: PayloadU16::new(ticket), exts: vec![], } } pub fn has_duplicate_extension(&self) -> bool { let mut seen = collections::HashSet::new(); for ext in &self.exts { let typ = ext.get_type().get_u16(); if seen.contains(&typ) { return true; } seen.insert(typ); } false } pub fn find_extension(&self, ext: ExtensionType) -> Option<&NewSessionTicketExtension> { self.exts .iter() .find(|x| x.get_type() == ext) } pub fn get_max_early_data_size(&self) -> Option { let ext = self.find_extension(ExtensionType::EarlyData)?; match *ext { NewSessionTicketExtension::EarlyData(ref sz) => Some(*sz), _ => None, } } } impl Codec for NewSessionTicketPayloadTLS13 { fn encode(&self, bytes: &mut Vec) { self.lifetime.encode(bytes); self.age_add.encode(bytes); self.nonce.encode(bytes); self.ticket.encode(bytes); self.exts.encode(bytes); } fn read(r: &mut Reader) -> Result { let lifetime = u32::read(r)?; let age_add = u32::read(r)?; let nonce = PayloadU8::read(r)?; let ticket = PayloadU16::read(r)?; let exts = Vec::read(r)?; Ok(Self { lifetime, age_add, nonce, ticket, exts, }) } } // -- RFC6066 certificate status types /// Only supports OCSP #[derive(Debug)] pub struct CertificateStatus { pub ocsp_response: PayloadU24, } impl Codec for CertificateStatus { fn encode(&self, bytes: &mut Vec) { CertificateStatusType::OCSP.encode(bytes); self.ocsp_response.encode(bytes); } fn read(r: &mut Reader) -> Result { let typ = CertificateStatusType::read(r)?; match typ { CertificateStatusType::OCSP => Ok(Self { ocsp_response: PayloadU24::read(r)?, }), _ => Err(InvalidMessage::InvalidCertificateStatusType), } } } impl CertificateStatus { pub fn new(ocsp: Vec) -> Self { Self { ocsp_response: PayloadU24::new(ocsp), } } pub fn into_inner(self) -> Vec { self.ocsp_response.0 } } #[derive(Debug)] pub enum HandshakePayload { HelloRequest, ClientHello(ClientHelloPayload), ServerHello(ServerHelloPayload), HelloRetryRequest(HelloRetryRequest), Certificate(CertificatePayload), CertificateTLS13(CertificatePayloadTLS13), ServerKeyExchange(ServerKeyExchangePayload), CertificateRequest(CertificateRequestPayload), CertificateRequestTLS13(CertificateRequestPayloadTLS13), CertificateVerify(DigitallySignedStruct), ServerHelloDone, EndOfEarlyData, ClientKeyExchange(Payload), NewSessionTicket(NewSessionTicketPayload), NewSessionTicketTLS13(NewSessionTicketPayloadTLS13), EncryptedExtensions(Vec), KeyUpdate(KeyUpdateRequest), Finished(Payload), CertificateStatus(CertificateStatus), MessageHash(Payload), Unknown(Payload), } impl HandshakePayload { fn encode(&self, bytes: &mut Vec) { use self::HandshakePayload::*; match *self { HelloRequest | ServerHelloDone | EndOfEarlyData => {} ClientHello(ref x) => x.encode(bytes), ServerHello(ref x) => x.encode(bytes), HelloRetryRequest(ref x) => x.encode(bytes), Certificate(ref x) => x.encode(bytes), CertificateTLS13(ref x) => x.encode(bytes), ServerKeyExchange(ref x) => x.encode(bytes), ClientKeyExchange(ref x) => x.encode(bytes), CertificateRequest(ref x) => x.encode(bytes), CertificateRequestTLS13(ref x) => x.encode(bytes), CertificateVerify(ref x) => x.encode(bytes), NewSessionTicket(ref x) => x.encode(bytes), NewSessionTicketTLS13(ref x) => x.encode(bytes), EncryptedExtensions(ref x) => x.encode(bytes), KeyUpdate(ref x) => x.encode(bytes), Finished(ref x) => x.encode(bytes), CertificateStatus(ref x) => x.encode(bytes), MessageHash(ref x) => x.encode(bytes), Unknown(ref x) => x.encode(bytes), } } } #[derive(Debug)] pub struct HandshakeMessagePayload { pub typ: HandshakeType, pub payload: HandshakePayload, } impl Codec for HandshakeMessagePayload { fn encode(&self, bytes: &mut Vec) { // encode payload to learn length let mut sub: Vec = Vec::new(); self.payload.encode(&mut sub); // output type, length, and encoded payload match self.typ { HandshakeType::HelloRetryRequest => HandshakeType::ServerHello, _ => self.typ, } .encode(bytes); codec::u24(sub.len() as u32).encode(bytes); bytes.append(&mut sub); } fn read(r: &mut Reader) -> Result { Self::read_version(r, ProtocolVersion::TLSv1_2) } } impl HandshakeMessagePayload { pub fn read_version(r: &mut Reader, vers: ProtocolVersion) -> Result { let mut 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; typ = HandshakeType::HelloRetryRequest; 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(CertificatePayload::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::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(Vec::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(Payload::read(&mut sub)), }; sub.expect_empty("HandshakeMessagePayload") .map(|_| Self { typ, payload }) } pub fn build_key_update_notify() -> Self { Self { typ: HandshakeType::KeyUpdate, payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), } } pub fn get_encoding_for_binder_signing(&self) -> Vec { let mut ret = self.get_encoding(); let binder_len = match self.payload { HandshakePayload::ClientHello(ref ch) => match ch.extensions.last() { Some(ClientExtension::PresharedKey(ref offer)) => { let mut binders_encoding = Vec::new(); offer .binders .encode(&mut binders_encoding); binders_encoding.len() } _ => 0, }, _ => 0, }; let ret_len = ret.len() - binder_len; ret.truncate(ret_len); ret } pub fn build_handshake_hash(hash: &[u8]) -> Self { Self { typ: HandshakeType::MessageHash, payload: HandshakePayload::MessageHash(Payload::new(hash.to_vec())), } } } rustls-v-0.21.10/rustls/src/msgs/handshake_test.rs000066400000000000000000001165571453461710000221210ustar00rootroot00000000000000use crate::dns_name::DnsNameRef; use crate::enums::{CipherSuite, HandshakeType, ProtocolVersion, SignatureScheme}; use crate::key::Certificate; use crate::msgs::base::{Payload, PayloadU16, PayloadU24, PayloadU8}; use crate::msgs::codec::{put_u16, Codec, Reader}; use crate::msgs::enums::{ ClientCertificateType, Compression, ECCurveType, ECPointFormat, ExtensionType, KeyUpdateRequest, NamedGroup, PSKKeyExchangeMode, ServerNameType, }; use crate::msgs::handshake::{ CertReqExtension, CertificateEntry, CertificateExtension, CertificatePayloadTLS13, CertificateRequestPayload, CertificateRequestPayloadTLS13, CertificateStatus, CertificateStatusRequest, ClientExtension, ClientHelloPayload, ClientSessionTicket, ConvertProtocolNameList, ConvertServerNameList, DistinguishedName, ECDHEServerKeyExchange, ECParameters, HandshakeMessagePayload, HandshakePayload, HasServerExtensions, HelloRetryExtension, HelloRetryRequest, KeyShareEntry, NewSessionTicketExtension, NewSessionTicketPayload, NewSessionTicketPayloadTLS13, PresharedKeyBinder, PresharedKeyIdentity, PresharedKeyOffer, ProtocolName, Random, Sct, ServerECDHParams, ServerExtension, ServerHelloPayload, ServerKeyExchangePayload, SessionId, UnknownExtension, }; 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_sessionid() { let bytes = [32; 32]; let mut rd = Reader::init(&bytes); assert!(SessionId::read(&mut rd).is_err()); } #[test] fn rejects_sessionid_with_bad_length() { let bytes = [33; 33]; let mut rd = Reader::init(&bytes); assert!(SessionId::read(&mut rd).is_err()); } #[test] fn sessionid_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_sessionid() { let bytes = [1; 2]; let mut rd = Reader::init(&bytes); let sess = SessionId::read(&mut rd).unwrap(); println!("{:?}", sess); assert!(!sess.is_empty()); assert_eq!(sess.len(), 1); assert!(!rd.any_left()); } #[test] fn accepts_empty_sessionid() { let bytes = [0; 1]; let mut rd = Reader::init(&bytes); let sess = SessionId::read(&mut rd).unwrap(); println!("{:?}", sess); assert!(sess.is_empty()); assert_eq!(sess.len(), 0); assert!(!rd.any_left()); } #[test] fn debug_sessionid() { 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 can_roundtrip_unknown_client_ext() { let bytes = [0x12u8, 0x34u8, 0, 3, 1, 2, 3]; let mut rd = Reader::init(&bytes); let ext = ClientExtension::read(&mut rd).unwrap(); println!("{:?}", ext); assert_eq!(ext.get_type(), ExtensionType::Unknown(0x1234)); assert_eq!(bytes.to_vec(), ext.get_encoding()); } #[test] fn refuses_client_ext_with_unparsed_bytes() { let bytes = [0x00u8, 0x0b, 0x00, 0x04, 0x02, 0xf8, 0x01, 0x02]; let mut rd = Reader::init(&bytes); assert!(ClientExtension::read(&mut rd).is_err()); } #[test] fn refuses_server_ext_with_unparsed_bytes() { let bytes = [0x00u8, 0x0b, 0x00, 0x04, 0x02, 0xf8, 0x01, 0x02]; let mut rd = Reader::init(&bytes); assert!(ServerExtension::read(&mut rd).is_err()); } #[test] fn refuses_certificate_ext_with_unparsed_bytes() { let bytes = [0x00u8, 0x12, 0x00, 0x03, 0x00, 0x00, 0x01]; let mut rd = Reader::init(&bytes); assert!(CertificateExtension::read(&mut rd).is_err()); } #[test] fn refuses_certificate_req_ext_with_unparsed_bytes() { let bytes = [0x00u8, 0x0d, 0x00, 0x05, 0x00, 0x02, 0x01, 0x02, 0xff]; let mut rd = Reader::init(&bytes); assert!(CertReqExtension::read(&mut rd).is_err()); } #[test] fn refuses_helloreq_ext_with_unparsed_bytes() { let bytes = [0x00u8, 0x2b, 0x00, 0x03, 0x00, 0x00, 0x01]; let mut rd = Reader::init(&bytes); assert!(HelloRetryExtension::read(&mut rd).is_err()); } #[test] fn refuses_newsessionticket_ext_with_unparsed_bytes() { let bytes = [0x00u8, 0x2a, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x01]; let mut rd = Reader::init(&bytes); assert!(NewSessionTicketExtension::read(&mut rd).is_err()); } #[test] fn can_roundtrip_single_sni() { let bytes = [0, 0, 0, 7, 0, 5, 0, 0, 2, 0x6c, 0x6f]; let mut rd = Reader::init(&bytes); let ext = ClientExtension::read(&mut rd).unwrap(); println!("{:?}", ext); assert_eq!(ext.get_type(), ExtensionType::ServerName); assert_eq!(bytes.to_vec(), ext.get_encoding()); } #[test] fn can_round_trip_mixed_case_sni() { let bytes = [0, 0, 0, 7, 0, 5, 0, 0, 2, 0x4c, 0x6f]; let mut rd = Reader::init(&bytes); let ext = ClientExtension::read(&mut rd).unwrap(); println!("{:?}", ext); assert_eq!(ext.get_type(), ExtensionType::ServerName); assert_eq!(bytes.to_vec(), ext.get_encoding()); } #[test] fn can_roundtrip_other_sni_name_types() { let bytes = [0, 0, 0, 7, 0, 5, 1, 0, 2, 0x6c, 0x6f]; let mut rd = Reader::init(&bytes); let ext = ClientExtension::read(&mut rd).unwrap(); println!("{:?}", ext); assert_eq!(ext.get_type(), ExtensionType::ServerName); assert_eq!(bytes.to_vec(), ext.get_encoding()); } #[test] fn get_single_hostname_returns_none_for_other_sni_name_types() { let bytes = [0, 0, 0, 7, 0, 5, 1, 0, 2, 0x6c, 0x6f]; let mut rd = Reader::init(&bytes); let ext = ClientExtension::read(&mut rd).unwrap(); println!("{:?}", ext); assert_eq!(ext.get_type(), ExtensionType::ServerName); if let ClientExtension::ServerName(snr) = ext { assert!(!snr.has_duplicate_names_for_type()); assert!(snr.get_single_hostname().is_none()); } else { unreachable!(); } } #[test] fn can_roundtrip_multiname_sni() { let bytes = [0, 0, 0, 12, 0, 10, 0, 0, 2, 0x68, 0x69, 0, 0, 2, 0x6c, 0x6f]; let mut rd = Reader::init(&bytes); let ext = ClientExtension::read(&mut rd).unwrap(); println!("{:?}", ext); assert_eq!(ext.get_type(), ExtensionType::ServerName); assert_eq!(bytes.to_vec(), ext.get_encoding()); match ext { ClientExtension::ServerName(req) => { assert_eq!(2, req.len()); assert!(req.has_duplicate_names_for_type()); let dns_name = req.get_single_hostname().unwrap(); assert_eq!(dns_name.as_ref(), "hi"); assert_eq!(req[0].typ, ServerNameType::HostName); assert_eq!(req[1].typ, ServerNameType::HostName); } _ => unreachable!(), } } #[test] fn rejects_truncated_sni() { let bytes = [0, 0, 0, 1, 0]; assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); let bytes = [0, 0, 0, 2, 0, 1]; assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); let bytes = [0, 0, 0, 3, 0, 1, 0]; assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); let bytes = [0, 0, 0, 4, 0, 2, 0, 0]; assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); let bytes = [0, 0, 0, 5, 0, 3, 0, 0, 0]; assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); let bytes = [0, 0, 0, 5, 0, 3, 0, 0, 1]; assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); let bytes = [0, 0, 0, 6, 0, 4, 0, 0, 2, 0x68]; assert!(ClientExtension::read(&mut Reader::init(&bytes)).is_err()); } #[test] fn can_roundtrip_psk_identity() { let bytes = [0, 0, 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_roundtrip_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_roundtrip_certstatusreq_for_ocsp() { let ext = ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()); println!("{:?}", ext); let bytes = [ 0, 5, // CertificateStatusRequest 0, 11, 1, // OCSP 0, 5, 0, 3, 0, 1, 1, 0, 1, 2, ]; let csr = ClientExtension::read(&mut Reader::init(&bytes)).unwrap(); println!("{:?}", csr); assert_eq!(csr.get_encoding(), bytes.to_vec()); } #[test] fn can_roundtrip_certstatusreq_for_other() { let bytes = [ 0, 5, // CertificateStatusRequest 0, 5, 2, // !OCSP 1, 2, 3, 4, ]; let csr = ClientExtension::read(&mut Reader::init(&bytes)).unwrap(); println!("{:?}", csr); assert_eq!(csr.get_encoding(), bytes.to_vec()); } #[test] fn can_roundtrip_multi_proto() { let bytes = [0, 16, 0, 8, 0, 6, 2, 0x68, 0x69, 2, 0x6c, 0x6f]; let mut rd = Reader::init(&bytes); let ext = ClientExtension::read(&mut rd).unwrap(); println!("{:?}", ext); assert_eq!(ext.get_type(), ExtensionType::ALProtocolNegotiation); assert_eq!(ext.get_encoding(), bytes.to_vec()); match ext { ClientExtension::Protocols(prot) => { assert_eq!(2, prot.len()); assert_eq!(vec![b"hi", b"lo"], prot.to_slices()); assert_eq!(prot.as_single_slice(), None); } _ => unreachable!(), } } #[test] fn can_roundtrip_single_proto() { let bytes = [0, 16, 0, 5, 0, 3, 2, 0x68, 0x69]; let mut rd = Reader::init(&bytes); let ext = ClientExtension::read(&mut rd).unwrap(); println!("{:?}", ext); assert_eq!(ext.get_type(), ExtensionType::ALProtocolNegotiation); assert_eq!(bytes.to_vec(), ext.get_encoding()); match ext { ClientExtension::Protocols(prot) => { assert_eq!(1, prot.len()); assert_eq!(vec![b"hi"], prot.to_slices()); assert_eq!(prot.as_single_slice(), Some(&b"hi"[..])); } _ => unreachable!(), } } fn get_sample_clienthellopayload() -> 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: vec![ ClientExtension::ECPointFormats(ECPointFormat::SUPPORTED.to_vec()), ClientExtension::NamedGroups(vec![NamedGroup::X25519]), ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ECDSA_NISTP256_SHA256]), ClientExtension::make_sni(DnsNameRef::try_from("hello").unwrap()), ClientExtension::SessionTicket(ClientSessionTicket::Request), ClientExtension::SessionTicket(ClientSessionTicket::Offer(Payload(vec![]))), ClientExtension::Protocols(vec![ProtocolName::from(vec![0])]), ClientExtension::SupportedVersions(vec![ProtocolVersion::TLSv1_3]), ClientExtension::KeyShare(vec![KeyShareEntry::new(NamedGroup::X25519, &[1, 2, 3])]), ClientExtension::PresharedKeyModes(vec![PSKKeyExchangeMode::PSK_DHE_KE]), ClientExtension::PresharedKey(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]), ], }), ClientExtension::Cookie(PayloadU16(vec![1, 2, 3])), ClientExtension::ExtendedMasterSecretRequest, ClientExtension::CertificateStatusRequest(CertificateStatusRequest::build_ocsp()), ClientExtension::SignedCertificateTimestampRequest, ClientExtension::TransportParameters(vec![1, 2, 3]), ClientExtension::Unknown(UnknownExtension { typ: ExtensionType::Unknown(12345), payload: Payload(vec![1, 2, 3]), }), ], } } #[test] fn can_print_all_clientextensions() { println!("client hello {:?}", get_sample_clienthellopayload()); } #[test] fn can_clone_all_clientextensions() { let _ = get_sample_serverhellopayload().extensions; } #[test] fn client_has_duplicate_extensions_works() { let mut chp = get_sample_clienthellopayload(); assert!(chp.has_duplicate_extension()); // due to SessionTicketRequest/SessionTicketOffer chp.extensions.drain(1..); assert!(!chp.has_duplicate_extension()); chp.extensions = vec![]; assert!(!chp.has_duplicate_extension()); } #[test] fn test_truncated_psk_offer() { let ext = ClientExtension::PresharedKey(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 {:?} enc {:?}", ext, enc); for l in 0..enc.len() { if l == 9 { continue; } put_u16(l as u16, &mut enc[4..]); let rc = ClientExtension::read_bytes(&enc); assert!(rc.is_err()); } } #[test] fn test_truncated_client_hello_is_detected() { let ch = get_sample_clienthellopayload(); let enc = ch.get_encoding(); println!("testing {:?} enc {:?}", ch, 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 = get_sample_clienthellopayload(); for ext in &chp.extensions { let mut enc = ext.get_encoding(); println!("testing {:?} enc {:?}", ext, enc); // "outer" truncation, i.e., where the extension-level length is longer than // the input for l in 0..enc.len() { assert!(ClientExtension::read_bytes(&enc[..l]).is_err()); } // these extension types don't have any internal encoding that rustls validates: match ext.get_type() { ExtensionType::TransportParameters | ExtensionType::Unknown(_) => { continue; } _ => {} }; // "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 {:?} len {:?}", enc, l); assert!(ClientExtension::read_bytes(&enc).is_err()); } } } fn test_client_extension_getter(typ: ExtensionType, getter: fn(&ClientHelloPayload) -> bool) { let mut chp = get_sample_clienthellopayload(); let ext = chp.find_extension(typ).unwrap().clone(); chp.extensions = vec![]; assert!(!getter(&chp)); chp.extensions = vec![ext]; assert!(getter(&chp)); chp.extensions = vec![ClientExtension::Unknown(UnknownExtension { typ, payload: Payload(vec![]), })]; assert!(!getter(&chp)); } #[test] fn client_get_sni_extension() { test_client_extension_getter(ExtensionType::ServerName, |chp| { chp.get_sni_extension().is_some() }); } #[test] fn client_get_sigalgs_extension() { test_client_extension_getter(ExtensionType::SignatureAlgorithms, |chp| { chp.get_sigalgs_extension().is_some() }); } #[test] fn client_get_namedgroups_extension() { test_client_extension_getter(ExtensionType::EllipticCurves, |chp| { chp.get_namedgroups_extension() .is_some() }); } #[test] fn client_get_ecpoints_extension() { test_client_extension_getter(ExtensionType::ECPointFormats, |chp| { chp.get_ecpoints_extension().is_some() }); } #[test] fn client_get_alpn_extension() { test_client_extension_getter(ExtensionType::ALProtocolNegotiation, |chp| { chp.get_alpn_extension().is_some() }); } #[test] fn client_get_quic_params_extension() { test_client_extension_getter(ExtensionType::TransportParameters, |chp| { chp.get_quic_params_extension() .is_some() }); } #[test] fn client_get_versions_extension() { test_client_extension_getter(ExtensionType::SupportedVersions, |chp| { chp.get_versions_extension().is_some() }); } #[test] fn client_get_keyshare_extension() { test_client_extension_getter(ExtensionType::KeyShare, |chp| { chp.get_keyshare_extension().is_some() }); } #[test] fn client_get_psk() { test_client_extension_getter(ExtensionType::PreSharedKey, |chp| chp.get_psk().is_some()); } #[test] fn client_get_psk_modes() { test_client_extension_getter(ExtensionType::PSKKeyExchangeModes, |chp| { chp.get_psk_modes().is_some() }); } #[test] fn test_truncated_helloretry_extension_is_detected() { let hrr = get_sample_helloretryrequest(); for ext in &hrr.extensions { let mut enc = ext.get_encoding(); println!("testing {:?} enc {:?}", ext, enc); // "outer" truncation, i.e., where the extension-level length is longer than // the input for l in 0..enc.len() { assert!(HelloRetryExtension::read_bytes(&enc[..l]).is_err()); } // these extension types don't have any internal encoding that rustls validates: if let ExtensionType::Unknown(_) = ext.get_type() { continue; } // "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 {:?} len {:?}", enc, l); assert!(HelloRetryExtension::read_bytes(&enc).is_err()); } } } fn test_helloretry_extension_getter(typ: ExtensionType, getter: fn(&HelloRetryRequest) -> bool) { let mut hrr = get_sample_helloretryrequest(); let mut exts = std::mem::take(&mut hrr.extensions); exts.retain(|ext| ext.get_type() == typ); assert!(!getter(&hrr)); hrr.extensions = exts; assert!(getter(&hrr)); hrr.extensions = vec![HelloRetryExtension::Unknown(UnknownExtension { typ, payload: Payload(vec![]), })]; assert!(!getter(&hrr)); } #[test] fn helloretry_get_requested_key_share_group() { test_helloretry_extension_getter(ExtensionType::KeyShare, |hrr| { hrr.get_requested_key_share_group() .is_some() }); } #[test] fn helloretry_get_cookie() { test_helloretry_extension_getter(ExtensionType::Cookie, |hrr| hrr.get_cookie().is_some()); } #[test] fn helloretry_get_supported_versions() { test_helloretry_extension_getter(ExtensionType::SupportedVersions, |hrr| { hrr.get_supported_versions().is_some() }); } #[test] fn test_truncated_server_extension_is_detected() { let shp = get_sample_serverhellopayload(); for ext in &shp.extensions { let mut enc = ext.get_encoding(); println!("testing {:?} enc {:?}", ext, enc); // "outer" truncation, i.e., where the extension-level length is longer than // the input for l in 0..enc.len() { assert!(ServerExtension::read_bytes(&enc[..l]).is_err()); } // these extension types don't have any internal encoding that rustls validates: match ext.get_type() { ExtensionType::TransportParameters | ExtensionType::Unknown(_) => { continue; } _ => {} }; // "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 {:?} len {:?}", enc, l); assert!(ServerExtension::read_bytes(&enc).is_err()); } } } fn test_server_extension_getter(typ: ExtensionType, getter: fn(&ServerHelloPayload) -> bool) { let mut shp = get_sample_serverhellopayload(); let ext = shp.find_extension(typ).unwrap().clone(); shp.extensions = vec![]; assert!(!getter(&shp)); shp.extensions = vec![ext]; assert!(getter(&shp)); shp.extensions = vec![ServerExtension::Unknown(UnknownExtension { typ, payload: Payload(vec![]), })]; assert!(!getter(&shp)); } #[test] fn server_get_key_share() { test_server_extension_getter(ExtensionType::KeyShare, |shp| shp.get_key_share().is_some()); } #[test] fn server_get_psk_index() { test_server_extension_getter(ExtensionType::PreSharedKey, |shp| { shp.get_psk_index().is_some() }); } #[test] fn server_get_ecpoints_extension() { test_server_extension_getter(ExtensionType::ECPointFormats, |shp| { shp.get_ecpoints_extension().is_some() }); } #[test] fn server_get_sct_list() { test_server_extension_getter(ExtensionType::SCT, |shp| shp.get_sct_list().is_some()); } #[test] fn server_get_supported_versions() { test_server_extension_getter(ExtensionType::SupportedVersions, |shp| { shp.get_supported_versions().is_some() }); } fn test_cert_extension_getter(typ: ExtensionType, getter: fn(&CertificateEntry) -> bool) { let mut ce = get_sample_certificatepayloadtls13() .entries .remove(0); let mut exts = std::mem::take(&mut ce.exts); exts.retain(|ext| ext.get_type() == typ); assert!(!getter(&ce)); ce.exts = exts; assert!(getter(&ce)); ce.exts = vec![CertificateExtension::Unknown(UnknownExtension { typ, payload: Payload(vec![]), })]; assert!(!getter(&ce)); } #[test] fn certentry_get_ocsp_response() { test_cert_extension_getter(ExtensionType::StatusRequest, |ce| { ce.get_ocsp_response().is_some() }); } #[test] fn certentry_get_scts() { test_cert_extension_getter(ExtensionType::SCT, |ce| ce.get_scts().is_some()); } fn get_sample_serverhellopayload() -> 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: vec![ ServerExtension::ECPointFormats(ECPointFormat::SUPPORTED.to_vec()), ServerExtension::ServerNameAck, ServerExtension::SessionTicketAck, ServerExtension::RenegotiationInfo(PayloadU8(vec![0])), ServerExtension::Protocols(vec![ProtocolName::from(vec![0])]), ServerExtension::KeyShare(KeyShareEntry::new(NamedGroup::X25519, &[1, 2, 3])), ServerExtension::PresharedKey(3), ServerExtension::ExtendedMasterSecretAck, ServerExtension::CertificateStatusAck, ServerExtension::SignedCertificateTimestamp(vec![Sct::from(vec![0])]), ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_2), ServerExtension::TransportParameters(vec![1, 2, 3]), ServerExtension::Unknown(UnknownExtension { typ: ExtensionType::Unknown(12345), payload: Payload(vec![1, 2, 3]), }), ], } } #[test] fn can_print_all_serverextensions() { println!("server hello {:?}", get_sample_serverhellopayload()); } #[test] fn can_clone_all_serverextensions() { let _ = get_sample_serverhellopayload().extensions; } fn get_sample_helloretryrequest() -> HelloRetryRequest { HelloRetryRequest { legacy_version: ProtocolVersion::TLSv1_2, session_id: SessionId::empty(), cipher_suite: CipherSuite::TLS_NULL_WITH_NULL_NULL, extensions: vec![ HelloRetryExtension::KeyShare(NamedGroup::X25519), HelloRetryExtension::Cookie(PayloadU16(vec![0])), HelloRetryExtension::SupportedVersions(ProtocolVersion::TLSv1_2), HelloRetryExtension::Unknown(UnknownExtension { typ: ExtensionType::Unknown(12345), payload: Payload(vec![1, 2, 3]), }), ], } } fn get_sample_certificatepayloadtls13() -> CertificatePayloadTLS13 { CertificatePayloadTLS13 { context: PayloadU8(vec![1, 2, 3]), entries: vec![CertificateEntry { cert: Certificate(vec![3, 4, 5]), exts: vec![ CertificateExtension::CertificateStatus(CertificateStatus { ocsp_response: PayloadU24(vec![1, 2, 3]), }), CertificateExtension::SignedCertificateTimestamp(vec![Sct::from(vec![0])]), CertificateExtension::Unknown(UnknownExtension { typ: ExtensionType::Unknown(12345), payload: Payload(vec![1, 2, 3]), }), ], }], } } fn get_sample_serverkeyexchangepayload_ecdhe() -> ServerKeyExchangePayload { ServerKeyExchangePayload::ECDHE(ECDHEServerKeyExchange { params: ServerECDHParams { curve_params: ECParameters { curve_type: ECCurveType::NamedCurve, named_group: NamedGroup::X25519, }, public: PayloadU8(vec![1, 2, 3]), }, dss: DigitallySignedStruct::new(SignatureScheme::RSA_PSS_SHA256, vec![1, 2, 3]), }) } fn get_sample_serverkeyexchangepayload_unknown() -> ServerKeyExchangePayload { ServerKeyExchangePayload::Unknown(Payload(vec![1, 2, 3])) } fn get_sample_certificaterequestpayload() -> CertificateRequestPayload { CertificateRequestPayload { certtypes: vec![ClientCertificateType::RSASign], sigschemes: vec![SignatureScheme::ECDSA_NISTP256_SHA256], canames: vec![DistinguishedName::from(vec![1, 2, 3])], } } fn get_sample_certificaterequestpayloadtls13() -> CertificateRequestPayloadTLS13 { CertificateRequestPayloadTLS13 { context: PayloadU8(vec![1, 2, 3]), extensions: vec![ CertReqExtension::SignatureAlgorithms(vec![SignatureScheme::ECDSA_NISTP256_SHA256]), CertReqExtension::AuthorityNames(vec![DistinguishedName::from(vec![1, 2, 3])]), CertReqExtension::Unknown(UnknownExtension { typ: ExtensionType::Unknown(12345), payload: Payload(vec![1, 2, 3]), }), ], } } fn get_sample_newsessionticketpayload() -> NewSessionTicketPayload { NewSessionTicketPayload { lifetime_hint: 1234, ticket: PayloadU16(vec![1, 2, 3]), } } fn get_sample_newsessionticketpayloadtls13() -> NewSessionTicketPayloadTLS13 { NewSessionTicketPayloadTLS13 { lifetime: 123, age_add: 1234, nonce: PayloadU8(vec![1, 2, 3]), ticket: PayloadU16(vec![4, 5, 6]), exts: vec![NewSessionTicketExtension::Unknown(UnknownExtension { typ: ExtensionType::Unknown(12345), payload: Payload(vec![1, 2, 3]), })], } } fn get_sample_encryptedextensions() -> Vec { get_sample_serverhellopayload().extensions } fn get_sample_certificatestatus() -> CertificateStatus { CertificateStatus { ocsp_response: PayloadU24(vec![1, 2, 3]), } } fn get_all_tls12_handshake_payloads() -> Vec { vec![ HandshakeMessagePayload { typ: HandshakeType::HelloRequest, payload: HandshakePayload::HelloRequest, }, HandshakeMessagePayload { typ: HandshakeType::ClientHello, payload: HandshakePayload::ClientHello(get_sample_clienthellopayload()), }, HandshakeMessagePayload { typ: HandshakeType::ServerHello, payload: HandshakePayload::ServerHello(get_sample_serverhellopayload()), }, HandshakeMessagePayload { typ: HandshakeType::HelloRetryRequest, payload: HandshakePayload::HelloRetryRequest(get_sample_helloretryrequest()), }, HandshakeMessagePayload { typ: HandshakeType::Certificate, payload: HandshakePayload::Certificate(vec![Certificate(vec![1, 2, 3])]), }, HandshakeMessagePayload { typ: HandshakeType::ServerKeyExchange, payload: HandshakePayload::ServerKeyExchange( get_sample_serverkeyexchangepayload_ecdhe(), ), }, HandshakeMessagePayload { typ: HandshakeType::ServerKeyExchange, payload: HandshakePayload::ServerKeyExchange( get_sample_serverkeyexchangepayload_unknown(), ), }, HandshakeMessagePayload { typ: HandshakeType::CertificateRequest, payload: HandshakePayload::CertificateRequest(get_sample_certificaterequestpayload()), }, HandshakeMessagePayload { typ: HandshakeType::ServerHelloDone, payload: HandshakePayload::ServerHelloDone, }, HandshakeMessagePayload { typ: HandshakeType::ClientKeyExchange, payload: HandshakePayload::ClientKeyExchange(Payload(vec![1, 2, 3])), }, HandshakeMessagePayload { typ: HandshakeType::NewSessionTicket, payload: HandshakePayload::NewSessionTicket(get_sample_newsessionticketpayload()), }, HandshakeMessagePayload { typ: HandshakeType::EncryptedExtensions, payload: HandshakePayload::EncryptedExtensions(get_sample_encryptedextensions()), }, HandshakeMessagePayload { typ: HandshakeType::KeyUpdate, payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateRequested), }, HandshakeMessagePayload { typ: HandshakeType::KeyUpdate, payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), }, HandshakeMessagePayload { typ: HandshakeType::Finished, payload: HandshakePayload::Finished(Payload(vec![1, 2, 3])), }, HandshakeMessagePayload { typ: HandshakeType::CertificateStatus, payload: HandshakePayload::CertificateStatus(get_sample_certificatestatus()), }, HandshakeMessagePayload { typ: HandshakeType::Unknown(99), payload: HandshakePayload::Unknown(Payload(vec![1, 2, 3])), }, ] } #[test] fn can_roundtrip_all_tls12_handshake_payloads() { for ref hm in get_all_tls12_handshake_payloads().iter() { println!("{:?}", hm.typ); 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_detect_truncation_of_all_tls12_handshake_payloads() { for hm in get_all_tls12_handshake_payloads().iter() { let mut enc = hm.get_encoding(); println!("test {:?} enc {:?}", hm, 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 {:?} enc {:?}", l, enc); match (hm.typ, 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()); } } } fn get_all_tls13_handshake_payloads() -> Vec { vec![ HandshakeMessagePayload { typ: HandshakeType::HelloRequest, payload: HandshakePayload::HelloRequest, }, HandshakeMessagePayload { typ: HandshakeType::ClientHello, payload: HandshakePayload::ClientHello(get_sample_clienthellopayload()), }, HandshakeMessagePayload { typ: HandshakeType::ServerHello, payload: HandshakePayload::ServerHello(get_sample_serverhellopayload()), }, HandshakeMessagePayload { typ: HandshakeType::HelloRetryRequest, payload: HandshakePayload::HelloRetryRequest(get_sample_helloretryrequest()), }, HandshakeMessagePayload { typ: HandshakeType::Certificate, payload: HandshakePayload::CertificateTLS13(get_sample_certificatepayloadtls13()), }, HandshakeMessagePayload { typ: HandshakeType::ServerKeyExchange, payload: HandshakePayload::ServerKeyExchange( get_sample_serverkeyexchangepayload_ecdhe(), ), }, HandshakeMessagePayload { typ: HandshakeType::ServerKeyExchange, payload: HandshakePayload::ServerKeyExchange( get_sample_serverkeyexchangepayload_unknown(), ), }, HandshakeMessagePayload { typ: HandshakeType::CertificateRequest, payload: HandshakePayload::CertificateRequestTLS13( get_sample_certificaterequestpayloadtls13(), ), }, HandshakeMessagePayload { typ: HandshakeType::CertificateVerify, payload: HandshakePayload::CertificateVerify(DigitallySignedStruct::new( SignatureScheme::ECDSA_NISTP256_SHA256, vec![1, 2, 3], )), }, HandshakeMessagePayload { typ: HandshakeType::ServerHelloDone, payload: HandshakePayload::ServerHelloDone, }, HandshakeMessagePayload { typ: HandshakeType::ClientKeyExchange, payload: HandshakePayload::ClientKeyExchange(Payload(vec![1, 2, 3])), }, HandshakeMessagePayload { typ: HandshakeType::NewSessionTicket, payload: HandshakePayload::NewSessionTicketTLS13( get_sample_newsessionticketpayloadtls13(), ), }, HandshakeMessagePayload { typ: HandshakeType::EncryptedExtensions, payload: HandshakePayload::EncryptedExtensions(get_sample_encryptedextensions()), }, HandshakeMessagePayload { typ: HandshakeType::KeyUpdate, payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateRequested), }, HandshakeMessagePayload { typ: HandshakeType::KeyUpdate, payload: HandshakePayload::KeyUpdate(KeyUpdateRequest::UpdateNotRequested), }, HandshakeMessagePayload { typ: HandshakeType::Finished, payload: HandshakePayload::Finished(Payload(vec![1, 2, 3])), }, HandshakeMessagePayload { typ: HandshakeType::CertificateStatus, payload: HandshakePayload::CertificateStatus(get_sample_certificatestatus()), }, HandshakeMessagePayload { typ: HandshakeType::Unknown(99), payload: HandshakePayload::Unknown(Payload(vec![1, 2, 3])), }, ] } #[test] fn can_roundtrip_all_tls13_handshake_payloads() { for ref hm in get_all_tls13_handshake_payloads().iter() { println!("{:?}", hm.typ); 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); } } 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 can_detect_truncation_of_all_tls13_handshake_payloads() { for hm in get_all_tls13_handshake_payloads().iter() { let mut enc = hm.get_encoding(); println!("test {:?} enc {:?}", hm, 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 {:?} enc {:?}", l, enc); match (hm.typ, 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()); } } } #[test] fn cannot_read_messagehash_from_network() { let mh = HandshakeMessagePayload { typ: HandshakeType::MessageHash, payload: 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).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!(HandshakeMessagePayload::read_bytes(&buf).is_err()); } #[test] fn can_decode_server_hello_from_api_devicecheck_apple_com() { let data = include_bytes!("hello-api.devicecheck.apple.com.bin"); let mut r = Reader::init(data); let hm = HandshakeMessagePayload::read(&mut r).unwrap(); println!("msg: {:?}", hm); } rustls-v-0.21.10/rustls/src/msgs/hello-api.devicecheck.apple.com.bin000066400000000000000000000001121453461710000252160ustar00rootroot00000000000000FbN$W[½J1vgYPRH/[0m M\XZ4V >,hXS6Pj/rustls-v-0.21.10/rustls/src/msgs/macros.rs000066400000000000000000000057451453461710000204140ustar00rootroot00000000000000/// A macro which defines an enum type. macro_rules! enum_builder { ( $(#[$comment:meta])* @U8 EnumName: $enum_name: ident; EnumVal { $( $enum_var: ident => $enum_val: expr ),* } ) => { $(#[$comment])* #[non_exhaustive] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum $enum_name { $( $enum_var),* ,Unknown(u8) } impl $enum_name { pub fn get_u8(&self) -> u8 { let x = self.clone(); match x { $( $enum_name::$enum_var => $enum_val),* ,$enum_name::Unknown(x) => x } } } impl Codec for $enum_name { fn encode(&self, bytes: &mut Vec) { self.get_u8().encode(bytes); } fn read(r: &mut Reader) -> Result { match u8::read(r) { Ok(x) => Ok($enum_name::from(x)), Err(_) => Err(crate::error::InvalidMessage::MissingData(stringify!($enum_name))), } } } impl From for $enum_name { fn from(x: u8) -> Self { match x { $($enum_val => $enum_name::$enum_var),* , x => $enum_name::Unknown(x), } } } }; ( $(#[$comment:meta])* @U16 EnumName: $enum_name: ident; EnumVal { $( $enum_var: ident => $enum_val: expr ),* } ) => { $(#[$comment])* #[non_exhaustive] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum $enum_name { $( $enum_var),* ,Unknown(u16) } impl $enum_name { pub fn get_u16(&self) -> u16 { let x = self.clone(); match x { $( $enum_name::$enum_var => $enum_val),* ,$enum_name::Unknown(x) => x } } pub fn as_str(&self) -> Option<&'static str> { match self { $( $enum_name::$enum_var => Some(stringify!($enum_var))),* ,$enum_name::Unknown(_) => None, } } } impl Codec for $enum_name { fn encode(&self, bytes: &mut Vec) { self.get_u16().encode(bytes); } fn read(r: &mut Reader) -> Result { match u16::read(r) { Ok(x) => Ok($enum_name::from(x)), Err(_) => Err(crate::error::InvalidMessage::MissingData(stringify!($enum_name))), } } } impl From for $enum_name { fn from(x: u16) -> Self { match x { $($enum_val => $enum_name::$enum_var),* , x => $enum_name::Unknown(x), } } } }; } rustls-v-0.21.10/rustls/src/msgs/message.rs000066400000000000000000000217321453461710000205460ustar00rootroot00000000000000use crate::enums::ProtocolVersion; use crate::enums::{AlertDescription, ContentType, HandshakeType}; use crate::error::{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; use crate::msgs::handshake::HandshakeMessagePayload; #[derive(Debug)] pub enum MessagePayload { Alert(AlertMessagePayload), Handshake { parsed: HandshakeMessagePayload, encoded: Payload, }, ChangeCipherSpec(ChangeCipherSpecPayload), ApplicationData(Payload), } impl MessagePayload { pub fn encode(&self, bytes: &mut Vec) { match self { Self::Alert(x) => x.encode(bytes), Self::Handshake { encoded, .. } => bytes.extend(&encoded.0), Self::ChangeCipherSpec(x) => x.encode(bytes), Self::ApplicationData(x) => x.encode(bytes), } } pub fn handshake(parsed: HandshakeMessagePayload) -> Self { Self::Handshake { encoded: Payload::new(parsed.get_encoding()), parsed, } } pub fn new( typ: ContentType, vers: ProtocolVersion, payload: Payload, ) -> Result { let mut r = Reader::init(&payload.0); match typ { ContentType::ApplicationData => Ok(Self::ApplicationData(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, }) } 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 { .. } => ContentType::Handshake, Self::ChangeCipherSpec(_) => ContentType::ChangeCipherSpec, Self::ApplicationData(_) => ContentType::ApplicationData, } } } /// A TLS frame, named TLSPlaintext in the standard. /// /// This type owns all memory for its interior parts. It is used to read/write from/to I/O /// buffers as well as for fragmenting, joining and encryption/decryption. It can be converted /// into a `Message` by decoding the payload. #[derive(Clone, Debug)] pub struct OpaqueMessage { pub typ: ContentType, pub version: ProtocolVersion, pub payload: Payload, } impl OpaqueMessage { /// `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 { 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(ref 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 >= Self::MAX_PAYLOAD { return Err(MessageError::MessageTooLarge); } let mut sub = r .sub(len as usize) .map_err(|_| MessageError::TooShortForLength)?; let payload = Payload::read(&mut sub); Ok(Self { typ, version, payload, }) } pub fn encode(self) -> Vec { let mut buf = Vec::new(); self.typ.encode(&mut buf); self.version.encode(&mut buf); (self.payload.0.len() as u16).encode(&mut buf); self.payload.encode(&mut buf); buf } /// Force conversion into a plaintext message. /// /// This should only be used for messages that are known to be in plaintext. Otherwise, the /// `OpaqueMessage` should be decrypted into a `PlainMessage` using a `MessageDecrypter`. pub fn into_plain_message(self) -> PlainMessage { PlainMessage { version: self.version, typ: self.typ, payload: self.payload, } } /// This is the maximum on-the-wire size of a TLSCiphertext. /// That's 2^14 payload bytes, a header, and a 2KB allowance /// for ciphertext overheads. const MAX_PAYLOAD: u16 = 16384 + 2048; /// Content type, version and size. const HEADER_SIZE: u16 = 1 + 2 + 2; /// Maximum on-wire message size. pub const MAX_WIRE_SIZE: usize = (Self::MAX_PAYLOAD + Self::HEADER_SIZE) as usize; } impl From for PlainMessage { fn from(msg: Message) -> Self { let typ = msg.payload.content_type(); let payload = match msg.payload { MessagePayload::ApplicationData(payload) => payload, _ => { let mut buf = Vec::new(); msg.payload.encode(&mut buf); Payload(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, } impl PlainMessage { pub fn into_unencrypted_opaque(self) -> OpaqueMessage { OpaqueMessage { version: self.version, typ: self.typ, payload: self.payload, } } pub fn borrow(&self) -> BorrowedPlainMessage<'_> { BorrowedPlainMessage { version: self.version, typ: self.typ, payload: &self.payload.0, } } } /// A message with decoded payload #[derive(Debug)] pub struct Message { pub version: ProtocolVersion, pub payload: MessagePayload, } 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.typ == 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::build_key_update_notify()), } } } /// Parses a plaintext message into a well-typed [`Message`]. /// /// A [`PlainMessage`] must contain plaintext content. Encrypted content should be stored in an /// [`OpaqueMessage`] and decrypted before being stored into a [`PlainMessage`]. impl TryFrom for Message { type Error = Error; fn try_from(plain: PlainMessage) -> Result { Ok(Self { version: plain.version, payload: MessagePayload::new(plain.typ, plain.version, plain.payload)?, }) } } /// A TLS frame, named TLSPlaintext in the standard. /// /// This type differs from `OpaqueMessage` because it borrows /// its payload. You can make a `OpaqueMessage` from an /// `BorrowMessage`, but this involves a copy. /// /// This type also cannot decode its internals and /// cannot be read/encoded; only `OpaqueMessage` can do that. pub struct BorrowedPlainMessage<'a> { pub typ: ContentType, pub version: ProtocolVersion, pub payload: &'a [u8], } impl<'a> BorrowedPlainMessage<'a> { pub fn to_unencrypted_opaque(&self) -> OpaqueMessage { OpaqueMessage { version: self.version, typ: self.typ, payload: Payload(self.payload.to_vec()), } } } #[derive(Debug)] pub enum MessageError { TooShortForHeader, TooShortForLength, InvalidEmptyPayload, MessageTooLarge, InvalidContentType, UnknownProtocolVersion, } rustls-v-0.21.10/rustls/src/msgs/message_test.rs000066400000000000000000000077531453461710000216140ustar00rootroot00000000000000use crate::enums::{AlertDescription, HandshakeType}; use crate::msgs::base::{PayloadU16, PayloadU24, PayloadU8}; use super::base::Payload; use super::codec::Reader; use super::enums::AlertLevel; use super::message::{Message, OpaqueMessage, PlainMessage}; use std::fs; use std::io::Read; use std::path::{Path, PathBuf}; #[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 = OpaqueMessage::read(&mut rd) .unwrap() .into_plain_message(); println!("{:?}", msg); let msg = match Message::try_from(msg) { Ok(msg) => msg, Err(_) => 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() { 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 = OpaqueMessage::read(&mut rd).unwrap(); println!("m = {:?}", m); assert!(Message::try_from(m.into_plain_message()).is_err()); } #[test] fn alert_is_not_handshake() { let m = Message::build_alert(AlertLevel::Fatal, AlertDescription::DecodeError); assert!(!m.is_handshake_type(HandshakeType::ClientHello)); } #[test] fn alert_is_not_opaque() { let m = Message::build_alert(AlertLevel::Fatal, AlertDescription::DecodeError); assert!(Message::try_from(m).is_ok()); } #[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 = OpaqueMessage::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(vec![1, 2, 3, 4]))); assert_eq!("01020304", format!("{:?}", PayloadU8(vec![1, 2, 3, 4]))); assert_eq!("01020304", format!("{:?}", PayloadU16(vec![1, 2, 3, 4]))); assert_eq!("01020304", format!("{:?}", PayloadU24(vec![1, 2, 3, 4]))); } rustls-v-0.21.10/rustls/src/msgs/mod.rs000066400000000000000000000014621453461710000176770ustar00rootroot00000000000000#![allow(clippy::upper_case_acronyms)] #![allow(missing_docs)] #[macro_use] mod macros; pub mod alert; pub mod base; pub mod ccs; pub mod codec; pub mod deframer; pub mod enums; pub mod fragmenter; pub mod handshake; pub mod message; pub mod persist; #[cfg(test)] mod handshake_test; #[cfg(test)] mod message_test; #[cfg(test)] mod test { #[test] fn smoketest() { use super::codec::Reader; use super::message::{Message, OpaqueMessage}; let bytes = include_bytes!("handshake-test.1.bin"); let mut r = Reader::init(bytes); while r.any_left() { let m = OpaqueMessage::read(&mut r).unwrap(); let out = m.clone().encode(); assert!(!out.is_empty()); Message::try_from(m.into_plain_message()).unwrap(); } } } rustls-v-0.21.10/rustls/src/msgs/persist.rs000066400000000000000000000302021453461710000206030ustar00rootroot00000000000000use crate::dns_name::DnsName; use crate::enums::{CipherSuite, ProtocolVersion}; use crate::error::InvalidMessage; use crate::key; use crate::msgs::base::{PayloadU16, PayloadU8}; use crate::msgs::codec::{Codec, Reader}; use crate::msgs::handshake::CertificatePayload; use crate::msgs::handshake::SessionId; use crate::ticketer::TimeBase; #[cfg(feature = "tls12")] use crate::tls12::Tls12CipherSuite; use crate::tls13::Tls13CipherSuite; use std::cmp; #[cfg(feature = "tls12")] use std::mem; pub struct Retrieved { pub value: T, retrieved_at: TimeBase, } impl Retrieved { pub fn new(value: T, retrieved_at: TimeBase) -> Self { Self { value, retrieved_at, } } pub fn map(&self, f: impl FnOnce(&T) -> Option<&M>) -> Option> { Some(Retrieved { value: f(&self.value)?, retrieved_at: self.retrieved_at, }) } } impl Retrieved<&Tls13ClientSessionValue> { pub 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> Retrieved { pub 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 std::ops::Deref for Retrieved { 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, #[cfg(feature = "quic")] quic_params: PayloadU16, } impl Tls13ClientSessionValue { pub(crate) fn new( suite: &'static Tls13CipherSuite, ticket: Vec, secret: Vec, server_cert_chain: Vec, time_now: TimeBase, 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, ), #[cfg(feature = "quic")] quic_params: PayloadU16(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; } #[cfg(feature = "quic")] pub fn set_quic_params(&mut self, quic_params: &[u8]) { self.quic_params = PayloadU16(quic_params.to_vec()); } #[cfg(feature = "quic")] pub fn quic_params(&self) -> Vec { self.quic_params.0.clone() } } impl std::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: Vec, master_secret: Vec, server_cert_chain: Vec, time_now: TimeBase, 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, ), } } pub(crate) fn take_ticket(&mut self) -> Vec { mem::take(&mut self.common.ticket.0) } 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 std::ops::Deref for Tls12ClientSessionValue { type Target = ClientSessionCommon; fn deref(&self) -> &Self::Target { &self.common } } #[derive(Debug, Clone)] pub struct ClientSessionCommon { ticket: PayloadU16, secret: PayloadU8, epoch: u64, lifetime_secs: u32, server_cert_chain: CertificatePayload, } impl ClientSessionCommon { fn new( ticket: Vec, secret: Vec, time_now: TimeBase, lifetime_secs: u32, server_cert_chain: Vec, ) -> Self { Self { ticket: PayloadU16(ticket), secret: PayloadU8(secret), epoch: time_now.as_secs(), lifetime_secs: cmp::min(lifetime_secs, MAX_TICKET_LIFETIME), server_cert_chain, } } pub(crate) fn server_cert_chain(&self) -> &[key::Certificate] { self.server_cert_chain.as_ref() } 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 --- pub type ServerSessionKey = SessionId; #[derive(Debug)] pub struct ServerSessionValue { pub sni: Option, pub version: ProtocolVersion, pub cipher_suite: CipherSuite, pub master_secret: PayloadU8, pub extended_ms: bool, pub client_cert_chain: Option, pub alpn: Option, pub application_data: PayloadU16, pub creation_time_sec: u64, pub age_obfuscation_offset: u32, freshness: Option, } impl Codec for ServerSessionValue { fn encode(&self, bytes: &mut Vec) { if let Some(ref sni) = self.sni { 1u8.encode(bytes); let sni_bytes: &str = sni.as_ref(); PayloadU8::new(Vec::from(sni_bytes)).encode(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(ref chain) = self.client_cert_chain { 1u8.encode(bytes); chain.encode(bytes); } else { 0u8.encode(bytes); } if let Some(ref 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 { let has_sni = u8::read(r)?; let sni = if has_sni == 1 { let dns_name = PayloadU8::read(r)?; let dns_name = match DnsName::try_from_ascii(&dns_name.0) { Ok(dns_name) => dns_name, Err(_) => return Err(InvalidMessage::InvalidServerName), }; Some(dns_name) } else { None }; let v = ProtocolVersion::read(r)?; let cs = CipherSuite::read(r)?; let ms = PayloadU8::read(r)?; let ems = u8::read(r)?; let has_ccert = u8::read(r)? == 1; let ccert = if has_ccert { Some(CertificatePayload::read(r)?) } 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 fn new( sni: Option<&DnsName>, v: ProtocolVersion, cs: CipherSuite, ms: Vec, client_cert_chain: Option, alpn: Option>, application_data: Vec, creation_time: TimeBase, age_obfuscation_offset: u32, ) -> Self { Self { sni: sni.cloned(), version: v, cipher_suite: cs, master_secret: PayloadU8::new(ms), extended_ms: false, client_cert_chain, alpn: alpn.map(PayloadU8::new), application_data: PayloadU16::new(application_data), creation_time_sec: creation_time.as_secs(), age_obfuscation_offset, freshness: None, } } pub fn set_extended_ms_used(&mut self) { self.extended_ms = true; } pub fn set_freshness(mut self, obfuscated_client_age_ms: u32, time_now: TimeBase) -> 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 = if client_age_ms < server_age_ms { server_age_ms - client_age_ms } else { client_age_ms - server_age_ms }; self.freshness = Some(age_difference <= MAX_FRESHNESS_SKEW_MS); self } pub fn is_fresh(&self) -> bool { self.freshness.unwrap_or_default() } } #[cfg(test)] mod tests { use super::*; use crate::enums::*; use crate::msgs::codec::{Codec, Reader}; use crate::ticketer::TimeBase; #[test] fn serversessionvalue_is_debug() { let ssv = ServerSessionValue::new( None, ProtocolVersion::TLSv1_3, CipherSuite::TLS13_AES_128_GCM_SHA256, vec![1, 2, 3], None, None, vec![4, 5, 6], TimeBase::now().unwrap(), 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); } } rustls-v-0.21.10/rustls/src/quic.rs000066400000000000000000001120611453461710000171060ustar00rootroot00000000000000/// This module contains optional APIs for implementing QUIC TLS. use crate::cipher::{Iv, IvLen}; use crate::client::{ClientConfig, ClientConnectionData, ServerName}; use crate::common_state::{CommonState, Protocol, Side}; use crate::conn::{ConnectionCore, SideData}; use crate::enums::{AlertDescription, ProtocolVersion}; use crate::error::Error; use crate::msgs::handshake::{ClientExtension, ServerExtension}; use crate::server::{ServerConfig, ServerConnectionData}; use crate::suites::BulkAlgorithm; use crate::tls13::key_schedule::hkdf_expand; use crate::tls13::{Tls13CipherSuite, TLS13_AES_128_GCM_SHA256_INTERNAL}; use ring::{aead, hkdf}; use std::collections::VecDeque; use std::fmt::{self, Debug}; use std::ops::{Deref, DerefMut}; use std::sync::Arc; /// 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 { 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) -> Option { 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 { 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>( &self, output: T, label: &[u8], context: Option<&[u8]>, ) -> Result { 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, } impl ClientConnection { /// Make a new QUIC ClientConnection. This differs from `ClientConnection::new()` /// in that it takes an extra argument, `params`, which contains the /// TLS-encoded transport parameters to send. pub fn new( config: Arc, quic_version: Version, name: ServerName, params: Vec, ) -> Result { if !config.supports_version(ProtocolVersion::TLSv1_3) { return Err(Error::General( "TLS 1.3 support is required for QUIC".into(), )); } let ext = match quic_version { Version::V1Draft => ClientExtension::TransportParametersDraft(params), Version::V1 | Version::V2 => ClientExtension::TransportParameters(params), }; let mut inner = ConnectionCore::for_client(config, name, vec![ext], 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() } } impl Deref for ClientConnection { type Target = ConnectionCommon; 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 for Connection { fn from(c: ClientConnection) -> Self { Self::Client(c) } } /// A QUIC server connection. pub struct ServerConnection { inner: ConnectionCommon, } impl ServerConnection { /// Make a new QUIC ServerConnection. This differs from `ServerConnection::new()` /// in that it takes an extra argument, `params`, which contains the /// TLS-encoded transport parameters to send. pub fn new( config: Arc, quic_version: Version, params: Vec, ) -> Result { if !config.supports_version(ProtocolVersion::TLSv1_3) { return Err(Error::General( "TLS 1.3 support is required for 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 ext = match quic_version { Version::V1Draft => ServerExtension::TransportParametersDraft(params), Version::V1 | Version::V2 => ServerExtension::TransportParameters(params), }; let mut core = ConnectionCore::for_server(config, vec![ext])?; 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; 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 for Connection { fn from(c: ServerConnection) -> Self { Self::Server(c) } } /// A shared interface for QUIC connections. pub struct ConnectionCommon { core: ConnectionCore, } impl ConnectionCommon { /// 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 { Some(DirectionalKeys::new( self.core .common_state .suite .and_then(|suite| suite.tls13())?, 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> { self.core .message_deframer .push(ProtocolVersion::TLSv1_3, plaintext)?; self.core.process_new_packets()?; 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) -> Option { 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 { self.core.common_state.quic.alert } } impl Deref for ConnectionCommon { type Target = CommonState; fn deref(&self) -> &Self::Target { &self.core.common_state } } impl DerefMut for ConnectionCommon { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.core.common_state } } impl From> for ConnectionCommon { fn from(core: ConnectionCore) -> Self { Self { core } } } #[cfg(feature = "quic")] #[derive(Default)] pub(crate) struct Quic { /// QUIC transport parameters received from the peer during the handshake pub(crate) params: Option>, pub(crate) alert: Option, pub(crate) hs_queue: VecDeque<(bool, Vec)>, pub(crate) early_secret: Option, pub(crate) hs_secrets: Option, pub(crate) traffic_secrets: Option, /// Whether keys derived from traffic_secrets have been passed to the QUIC implementation pub(crate) returned_traffic_keys: bool, pub(crate) version: Version, } impl Quic { pub(crate) fn write_hs(&mut self, buf: &mut Vec) -> Option { 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, Debug)] pub struct Secrets { /// Secret used to encrypt packets transmitted by the client client: hkdf::Prk, /// Secret used to encrypt packets transmitted by the server server: hkdf::Prk, /// Cipher suite used with these secrets suite: &'static Tls13CipherSuite, side: Side, version: Version, } impl Secrets { pub(crate) fn new( client: hkdf::Prk, server: hkdf::Prk, suite: &'static Tls13CipherSuite, side: Side, version: Version, ) -> Self { Self { client, server, suite, 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 } fn update(&mut self) { let hkdf_alg = self.suite.hkdf_algorithm; self.client = hkdf_expand(&self.client, hkdf_alg, self.version.key_update_label(), &[]); self.server = hkdf_expand(&self.server, hkdf_alg, self.version.key_update_label(), &[]); } fn local_remote(&self) -> (&hkdf::Prk, &hkdf::Prk) { 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: HeaderProtectionKey, /// Encrypts or decrypts the payload of a packet pub packet: PacketKey, } impl DirectionalKeys { pub(crate) fn new( suite: &'static Tls13CipherSuite, secret: &hkdf::Prk, version: Version, ) -> Self { Self { header: HeaderProtectionKey::new(suite, secret, version), packet: PacketKey::new(suite, secret, version), } } } /// A QUIC header protection key pub struct HeaderProtectionKey(aead::quic::HeaderProtectionKey); impl HeaderProtectionKey { fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk, version: Version) -> Self { let alg = match suite.common.bulk { BulkAlgorithm::Aes128Gcm => &aead::quic::AES_128, BulkAlgorithm::Aes256Gcm => &aead::quic::AES_256, BulkAlgorithm::Chacha20Poly1305 => &aead::quic::CHACHA20, }; Self(hkdf_expand(secret, alg, version.header_key_label(), &[])) } /// 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 #[inline] pub 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) } /// 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 #[inline] pub 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) } 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. 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(()) } /// Expected sample length for the key's algorithm #[inline] pub fn sample_len(&self) -> usize { self.0.algorithm().sample_len() } } /// Keys to encrypt or decrypt the payload of a packet pub struct PacketKey { /// Encrypts or decrypts a packet's payload key: aead::LessSafeKey, /// Computes unique nonces for each packet iv: Iv, /// The cipher suite used for this packet key suite: &'static Tls13CipherSuite, } impl PacketKey { fn new(suite: &'static Tls13CipherSuite, secret: &hkdf::Prk, version: Version) -> Self { Self { key: aead::LessSafeKey::new(hkdf_expand( secret, suite.common.aead_algorithm, version.packet_key_label(), &[], )), iv: hkdf_expand(secret, IvLen, version.packet_iv_label(), &[]), suite, } } /// 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 iff the payload is longer than allowed by the cipher suite's AEAD algorithm. pub fn encrypt_in_place( &self, packet_number: u64, header: &[u8], payload: &mut [u8], ) -> Result { let aad = aead::Aad::from(header); let nonce = nonce_for(packet_number, &self.iv); let tag = self .key .seal_in_place_separate_tag(nonce, aad, payload) .map_err(|_| Error::EncryptError)?; Ok(Tag(tag)) } /// 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. pub 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 = nonce_for(packet_number, &self.iv); 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]) } /// Number of times the packet key can be used without sacrificing confidentiality /// /// See . #[inline] pub fn confidentiality_limit(&self) -> u64 { self.suite.confidentiality_limit } /// Number of times the packet key can be used without sacrificing integrity /// /// See . #[inline] pub fn integrity_limit(&self) -> u64 { self.suite.integrity_limit } /// Tag length for the underlying AEAD algorithm #[inline] pub fn tag_len(&self) -> usize { self.key.algorithm().tag_len() } } /// AEAD tag, must be appended to encrypted cipher text pub struct Tag(aead::Tag); impl AsRef<[u8]> for Tag { #[inline] fn as_ref(&self) -> &[u8] { self.0.as_ref() } } /// Packet protection keys for bidirectional 1-RTT communication pub struct PacketKeySet { /// Encrypts outgoing packets pub local: PacketKey, /// Decrypts incoming packets pub remote: PacketKey, } impl PacketKeySet { fn new(secrets: &Secrets) -> Self { let (local, remote) = secrets.local_remote(); Self { local: PacketKey::new(secrets.suite, local, secrets.version), remote: PacketKey::new(secrets.suite, remote, secrets.version), } } } /// 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, 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 = hkdf::Salt::new(hkdf::HKDF_SHA256, salt).extract(client_dst_connection_id); let secrets = Secrets { version, client: hkdf_expand(&hs_secret, hkdf::HKDF_SHA256, CLIENT_LABEL, &[]), server: hkdf_expand(&hs_secret, hkdf::HKDF_SHA256, SERVER_LABEL, &[]), suite: TLS13_AES_128_GCM_SHA256_INTERNAL, side, }; Self::new(&secrets) } fn new(secrets: &Secrets) -> Self { let (local, remote) = secrets.local_remote(); Self { local: DirectionalKeys::new(secrets.suite, local, secrets.version), remote: DirectionalKeys::new(secrets.suite, 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. #[allow(clippy::large_enum_variant)] 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, }, } /// Compute the nonce to use for encrypting or decrypting `packet_number` fn nonce_for(packet_number: u64, iv: &Iv) -> ring::aead::Nonce { let mut out = [0; aead::NONCE_LEN]; out[4..].copy_from_slice(&packet_number.to_be_bytes()); for (out, inp) in out.iter_mut().zip(iv.0.iter()) { *out ^= inp; } aead::Nonce::assume_unique_for_key(out) } /// 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, ], } } fn packet_key_label(&self) -> &'static [u8] { match self { Self::V1Draft | Self::V1 => b"quic key", Self::V2 => b"quicv2 key", } } fn packet_iv_label(&self) -> &'static [u8] { match self { Self::V1Draft | Self::V1 => b"quic iv", Self::V2 => b"quicv2 iv", } } 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 test { use super::*; 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 = hkdf::Prk::new_less_safe(hkdf::HKDF_SHA256, SECRET); use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; let hpk = HeaderProtectionKey::new(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, &secret, version); let packet = PacketKey::new(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, &secret, version); 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_prk(x: &hkdf::Prk, y: &hkdf::Prk) -> bool { let mut x_data = [0; 16]; let mut y_data = [0; 16]; let x_okm = x .expand(&[b"info"], &aead::quic::AES_128) .unwrap(); x_okm.fill(&mut x_data[..]).unwrap(); let y_okm = y .expand(&[b"info"], &aead::quic::AES_128) .unwrap(); y_okm.fill(&mut y_data[..]).unwrap(); x_data == y_data } let mut secrets = Secrets { // Constant dummy values for reproducibility client: hkdf::Prk::new_less_safe( hkdf::HKDF_SHA256, &[ 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, ], ), server: hkdf::Prk::new_less_safe( hkdf::HKDF_SHA256, &[ 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, ], ), suite: TLS13_AES_128_GCM_SHA256_INTERNAL, side: Side::Client, version: Version::V1, }; secrets.update(); assert!(equal_prk( &secrets.client, &hkdf::Prk::new_less_safe( hkdf::HKDF_SHA256, &[ 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_prk( &secrets.server, &hkdf::Prk::new_less_safe( hkdf::HKDF_SHA256, &[ 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, &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[..]); } } rustls-v-0.21.10/rustls/src/rand.rs000066400000000000000000000014071453461710000170720ustar00rootroot00000000000000//! The single place where we generate random material for our own use. use ring::rand::{SecureRandom, SystemRandom}; /// Fill the whole slice with random material. pub(crate) fn fill_random(bytes: &mut [u8]) -> Result<(), GetRandomFailed> { SystemRandom::new() .fill(bytes) .map_err(|_| GetRandomFailed) } /// Make a Vec of the given size /// containing random material. pub(crate) fn random_vec(len: usize) -> Result, GetRandomFailed> { let mut v = vec![0; len]; fill_random(&mut v)?; Ok(v) } /// Return a uniformly random u32. pub(crate) fn random_u32() -> Result { let mut buf = [0u8; 4]; fill_random(&mut buf)?; Ok(u32::from_be_bytes(buf)) } #[derive(Debug)] pub struct GetRandomFailed; rustls-v-0.21.10/rustls/src/record_layer.rs000066400000000000000000000167431453461710000206310ustar00rootroot00000000000000use crate::cipher::{MessageDecrypter, MessageEncrypter}; use crate::error::Error; use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; #[cfg(feature = "logging")] use crate::log::trace; static SEQ_SOFT_LIMIT: u64 = 0xffff_ffff_ffff_0000u64; static SEQ_HARD_LIMIT: u64 = 0xffff_ffff_ffff_fffeu64; #[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 struct RecordLayer { message_encrypter: Box, message_decrypter: Box, write_seq: u64, read_seq: u64, 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, } impl RecordLayer { /// Create new record layer with no keys. pub fn new() -> Self { Self { message_encrypter: ::invalid(), message_decrypter: ::invalid(), write_seq: 0, read_seq: 0, encrypt_state: DirectionState::Invalid, decrypt_state: DirectionState::Invalid, trial_decryption_len: None, } } pub(crate) fn is_encrypting(&self) -> bool { self.encrypt_state == DirectionState::Active } #[cfg(feature = "secret_extraction")] pub(crate) fn write_seq(&self) -> u64 { self.write_seq } #[cfg(feature = "secret_extraction")] pub(crate) fn read_seq(&self) -> u64 { self.read_seq } 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, } } /// 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) { self.message_encrypter = cipher; self.write_seq = 0; 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) { 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) { self.prepare_message_encrypter(cipher); 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) { 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, 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; } /// Return true if we are getting close to encrypting too many /// messages with our encryption key. pub(crate) fn wants_close_before_encrypt(&self) -> bool { self.write_seq == SEQ_SOFT_LIMIT } /// Return true if we outright refuse to do anything with the /// encryption key. pub(crate) fn encrypt_exhausted(&self) -> bool { self.write_seq >= SEQ_HARD_LIMIT } /// 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( &mut self, encr: OpaqueMessage, ) -> Result, 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.0.len(); match self .message_decrypter .decrypt(encr, self.read_seq) { Ok(plaintext) => { self.read_seq += 1; 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: BorrowedPlainMessage) -> OpaqueMessage { debug_assert!(self.encrypt_state == DirectionState::Active); assert!(!self.encrypt_exhausted()); let seq = self.write_seq; self.write_seq += 1; self.message_encrypter .encrypt(plain, seq) .unwrap() } } /// Result of decryption. #[derive(Debug)] pub struct Decrypted { /// Whether the peer appears to be getting close to encrypting too many messages with this key. pub want_close_before_decrypt: bool, /// The decrypted message. pub plaintext: PlainMessage, } rustls-v-0.21.10/rustls/src/server/000077500000000000000000000000001453461710000171045ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/server/builder.rs000066400000000000000000000106141453461710000211020ustar00rootroot00000000000000use crate::builder::{ConfigBuilder, WantsVerifier}; use crate::error::Error; use crate::key; use crate::kx::SupportedKxGroup; use crate::server::handy; use crate::server::{ResolvesServerCert, ServerConfig}; use crate::suites::SupportedCipherSuite; use crate::verify; use crate::versions; use crate::NoKeyLog; use std::marker::PhantomData; use std::sync::Arc; impl ConfigBuilder { /// Choose how to verify client certificates. pub fn with_client_cert_verifier( self, client_cert_verifier: Arc, ) -> ConfigBuilder { ConfigBuilder { state: WantsServerCert { cipher_suites: self.state.cipher_suites, kx_groups: self.state.kx_groups, versions: self.state.versions, verifier: client_cert_verifier, }, side: PhantomData, } } /// Disable client authentication. pub fn with_no_client_auth(self) -> ConfigBuilder { self.with_client_cert_verifier(verify::NoClientAuth::boxed()) } } /// 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 { cipher_suites: Vec, kx_groups: Vec<&'static SupportedKxGroup>, versions: versions::EnabledVersions, verifier: Arc, } impl ConfigBuilder { /// 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 RSA, ECDSA, or Ed25519 private key. /// /// This function fails if `key_der` is invalid. pub fn with_single_cert( self, cert_chain: Vec, key_der: key::PrivateKey, ) -> Result { let resolver = handy::AlwaysResolvesChain::new(cert_chain, &key_der)?; Ok(self.with_cert_resolver(Arc::new(resolver))) } /// Sets a single certificate chain, matching private key, OCSP /// response and SCTs. 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 RSA, ECDSA, or Ed25519 private key. /// `ocsp` is a DER-encoded OCSP response. Ignored if zero length. /// `scts` is an `SignedCertificateTimestampList` encoding (see RFC6962) /// and is ignored if empty. /// /// This function fails if `key_der` is invalid. pub fn with_single_cert_with_ocsp_and_sct( self, cert_chain: Vec, key_der: key::PrivateKey, ocsp: Vec, scts: Vec, ) -> Result { let resolver = handy::AlwaysResolvesChain::new_with_extras(cert_chain, &key_der, ocsp, scts)?; Ok(self.with_cert_resolver(Arc::new(resolver))) } /// Sets a custom [`ResolvesServerCert`]. pub fn with_cert_resolver(self, cert_resolver: Arc) -> ServerConfig { ServerConfig { cipher_suites: self.state.cipher_suites, kx_groups: self.state.kx_groups, verifier: self.state.verifier, cert_resolver, ignore_client_order: false, max_fragment_size: None, session_storage: handy::ServerSessionMemoryCache::new(256), ticketer: Arc::new(handy::NeverProducesTickets {}), alpn_protocols: Vec::new(), versions: self.state.versions, key_log: Arc::new(NoKeyLog {}), #[cfg(feature = "secret_extraction")] enable_secret_extraction: false, max_early_data_size: 0, send_half_rtt_data: false, send_tls13_tickets: 4, } } } rustls-v-0.21.10/rustls/src/server/common.rs000066400000000000000000000017431453461710000207470ustar00rootroot00000000000000use crate::{key, sign}; /// ActiveCertifiedKey wraps CertifiedKey and tracks OSCP and SCT state /// in a single handshake. pub(super) struct ActiveCertifiedKey<'a> { key: &'a sign::CertifiedKey, ocsp: Option<&'a [u8]>, sct_list: Option<&'a [u8]>, } impl<'a> ActiveCertifiedKey<'a> { pub(super) fn from_certified_key(key: &sign::CertifiedKey) -> ActiveCertifiedKey { ActiveCertifiedKey { key, ocsp: key.ocsp.as_deref(), sct_list: key.sct_list.as_deref(), } } /// Get the certificate chain #[inline] pub(super) fn get_cert(&self) -> &[key::Certificate] { &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 } #[inline] pub(super) fn get_sct_list(&self) -> Option<&[u8]> { self.sct_list } } rustls-v-0.21.10/rustls/src/server/handy.rs000066400000000000000000000231761453461710000205660ustar00rootroot00000000000000use crate::dns_name::DnsNameRef; use crate::error::Error; use crate::key; use crate::limited_cache; use crate::server; use crate::server::ClientHello; use crate::sign; use std::collections; use std::sync::{Arc, Mutex}; /// Something which never stores sessions. pub struct NoServerSessionStorage {} impl server::StoresServerSessions for NoServerSessionStorage { fn put(&self, _id: Vec, _sec: Vec) -> bool { false } fn get(&self, _id: &[u8]) -> Option> { None } fn take(&self, _id: &[u8]) -> Option> { None } fn can_cache(&self) -> bool { false } } /// 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, Vec>>, } impl ServerSessionMemoryCache { /// Make a new ServerSessionMemoryCache. `size` is the maximum /// number of stored sessions, and may be rounded-up for /// efficiency. pub fn new(size: usize) -> Arc { Arc::new(Self { cache: Mutex::new(limited_cache::LimitedCache::new(size)), }) } } impl server::StoresServerSessions for ServerSessionMemoryCache { fn put(&self, key: Vec, value: Vec) -> bool { self.cache .lock() .unwrap() .insert(key, value); true } fn get(&self, key: &[u8]) -> Option> { self.cache .lock() .unwrap() .get(key) .cloned() } fn take(&self, key: &[u8]) -> Option> { self.cache.lock().unwrap().remove(key) } fn can_cache(&self) -> bool { true } } /// Something which never produces tickets. 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> { None } fn decrypt(&self, _bytes: &[u8]) -> Option> { None } } /// Something which always resolves to the same cert chain. pub(super) struct AlwaysResolvesChain(Arc); impl AlwaysResolvesChain { /// Creates an `AlwaysResolvesChain`, auto-detecting the underlying private /// key type and encoding. pub(super) fn new( chain: Vec, priv_key: &key::PrivateKey, ) -> Result { let key = sign::any_supported_type(priv_key) .map_err(|_| Error::General("invalid private key".into()))?; Ok(Self(Arc::new(sign::CertifiedKey::new(chain, key)))) } /// Creates an `AlwaysResolvesChain`, auto-detecting the underlying private /// key type and encoding. /// /// If non-empty, the given OCSP response and SCTs are attached. pub(super) fn new_with_extras( chain: Vec, priv_key: &key::PrivateKey, ocsp: Vec, scts: Vec, ) -> Result { let mut r = Self::new(chain, priv_key)?; { let cert = Arc::make_mut(&mut r.0); if !ocsp.is_empty() { cert.ocsp = Some(ocsp); } if !scts.is_empty() { cert.sct_list = Some(scts); } } Ok(r) } } impl server::ResolvesServerCert for AlwaysResolvesChain { fn resolve(&self, _client_hello: ClientHello) -> Option> { Some(Arc::clone(&self.0)) } } /// Something that resolves do different cert chains/keys based /// on client-supplied server name (via SNI). pub struct ResolvesServerCertUsingSni { by_name: collections::HashMap>, } impl ResolvesServerCertUsingSni { /// Create a new and empty (i.e., knows no certificates) resolver. pub fn new() -> Self { Self { by_name: collections::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 checked_name = DnsNameRef::try_from(name) .map_err(|_| Error::General("Bad DNS name".into())) .map(|dns| dns.to_lowercase_owned())?; // 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. // Always reject an empty certificate chain. let end_entity_cert = ck.end_entity_cert().map_err(|_| { Error::General("No end-entity certificate in certificate chain".to_string()) })?; // Reject syntactically-invalid end-entity certificates. let end_entity_cert = webpki::EndEntityCert::try_from(end_entity_cert.as_ref()).map_err(|_| { Error::General( "End-entity certificate in certificate chain is syntactically invalid" .to_string(), ) })?; // Note that this doesn't fully validate that the certificate is valid; it only validates that the name is one // that the certificate is valid for, if the certificate is // valid. let general_error = || Error::General("The server certificate is not valid for the given name".to_string()); let name = webpki::DnsNameRef::try_from_ascii(checked_name.as_ref().as_bytes()) .map_err(|_| general_error())?; end_entity_cert .verify_is_valid_for_subject_name(webpki::SubjectNameRef::DnsName(name)) .map_err(|_| general_error())?; let as_str: &str = checked_name.as_ref(); self.by_name .insert(as_str.to_string(), Arc::new(ck)); Ok(()) } } impl server::ResolvesServerCert for ResolvesServerCertUsingSni { fn resolve(&self, client_hello: ClientHello) -> Option> { if let Some(name) = client_hello.server_name() { self.by_name.get(name).map(Arc::clone) } else { // This kind of resolver requires SNI None } } } #[cfg(test)] mod test { use super::*; use crate::server::ProducesTickets; use crate::server::ResolvesServerCert; use crate::server::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_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); } #[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(&[])); } #[test] fn test_resolvesservercertusingsni_requires_sni() { let rscsni = ResolvesServerCertUsingSni::new(); assert!(rscsni .resolve(ClientHello::new(&None, &[], None, &[])) .is_none()); } #[test] fn test_resolvesservercertusingsni_handles_unknown_name() { let rscsni = ResolvesServerCertUsingSni::new(); let name = DnsNameRef::try_from("hello.com") .unwrap() .to_owned(); assert!(rscsni .resolve(ClientHello::new(&Some(name), &[], None, &[])) .is_none()); } } rustls-v-0.21.10/rustls/src/server/hs.rs000066400000000000000000000457411453461710000200770ustar00rootroot00000000000000use crate::common_state::State; use crate::conn::ConnectionRandoms; use crate::dns_name::DnsName; #[cfg(feature = "tls12")] use crate::enums::CipherSuite; use crate::enums::{AlertDescription, HandshakeType, ProtocolVersion, SignatureScheme}; use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; use crate::hash_hs::{HandshakeHash, HandshakeHashBuffer}; #[cfg(feature = "logging")] use crate::log::{debug, trace}; use crate::msgs::enums::{Compression, ExtensionType}; #[cfg(feature = "tls12")] use crate::msgs::handshake::SessionId; use crate::msgs::handshake::{ClientHelloPayload, Random, ServerExtension}; use crate::msgs::handshake::{ConvertProtocolNameList, ConvertServerNameList, HandshakePayload}; use crate::msgs::message::{Message, MessagePayload}; use crate::msgs::persist; use crate::server::{ClientHello, ServerConfig}; use crate::suites; use crate::SupportedCipherSuite; use super::server_conn::ServerConnectionData; #[cfg(feature = "tls12")] use super::tls12; use crate::server::common::ActiveCertifiedKey; use crate::server::tls13; use std::sync::Arc; pub(super) type NextState = Box>; pub(super) type NextStateOrError = Result; pub(super) type ServerContext<'a> = crate::common_state::Context<'a, ServerConnectionData>; pub(super) fn can_resume( suite: SupportedCipherSuite, sni: &Option, 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." 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) exts: Vec, #[cfg(feature = "tls12")] pub(super) send_ticket: bool, } impl ExtensionProcessing { pub(super) fn new() -> Self { Default::default() } pub(super) fn process_common( &mut self, config: &ServerConfig, cx: &mut ServerContext<'_>, ocsp_response: &mut Option<&[u8]>, sct_list: &mut Option<&[u8]>, hello: &ClientHelloPayload, resumedata: Option<&persist::ServerSessionValue>, extra_exts: Vec, ) -> Result<(), Error> { // ALPN let our_protocols = &config.alpn_protocols; let maybe_their_protocols = hello.get_alpn_extension(); if let Some(their_protocols) = maybe_their_protocols { let their_protocols = their_protocols.to_slices(); if their_protocols .iter() .any(|protocol| protocol.is_empty()) { return Err(PeerMisbehaved::OfferedEmptyApplicationProtocol.into()); } cx.common.alpn_protocol = our_protocols .iter() .find(|protocol| their_protocols.contains(&protocol.as_slice())) .cloned(); if let Some(ref selected_protocol) = cx.common.alpn_protocol { debug!("Chosen ALPN protocol {:?}", selected_protocol); self.exts .push(ServerExtension::make_alpn(&[selected_protocol])); } else if !our_protocols.is_empty() { return Err(cx.common.send_fatal_alert( AlertDescription::NoApplicationProtocol, Error::NoApplicationProtocol, )); } } #[cfg(feature = "quic")] { 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) iff 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() || maybe_their_protocols.is_some()) { return Err(cx.common.send_fatal_alert( AlertDescription::NoApplicationProtocol, Error::NoApplicationProtocol, )); } match hello.get_quic_params_extension() { Some(params) => cx.common.quic.params = Some(params), None => { return Err(cx .common .missing_extension(PeerMisbehaved::MissingQuicTransportParameters)); } } } } let for_resume = resumedata.is_some(); // SNI if !for_resume && hello.get_sni_extension().is_some() { self.exts .push(ServerExtension::ServerNameAck); } // 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 .find_extension(ExtensionType::StatusRequest) .is_some() { if ocsp_response.is_some() && !cx.common.is_tls13() { // Only TLS1.2 sends confirmation in ServerHello self.exts .push(ServerExtension::CertificateStatusAck); } } else { // Throw away any OCSP response so we don't try to send it later. ocsp_response.take(); } if !for_resume && hello .find_extension(ExtensionType::SCT) .is_some() { if !cx.common.is_tls13() { // Take the SCT list, if any, so we don't send it later, // and put it in the legacy extension. if let Some(sct_list) = sct_list.take() { self.exts .push(ServerExtension::make_sct(sct_list.to_vec())); } } } else { // Throw away any SCT list so we don't send it later. sct_list.take(); } self.exts.extend(extra_exts); 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.) let secure_reneg_offered = hello .find_extension(ExtensionType::RenegotiationInfo) .is_some() || hello .cipher_suites .contains(&CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if secure_reneg_offered { self.exts .push(ServerExtension::make_empty_renegotiation_info()); } // Tickets: // If we get any SessionTicket extension and have tickets enabled, // we send an ack. if hello .find_extension(ExtensionType::SessionTicket) .is_some() && config.ticketer.enabled() { self.send_ticket = true; self.exts .push(ServerExtension::SessionTicketAck); } // Confirm use of EMS if offered. if using_ems { self.exts .push(ServerExtension::ExtendedMasterSecretAck); } } } pub(super) struct ExpectClientHello { pub(super) config: Arc, pub(super) extra_exts: Vec, 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, extra_exts: Vec) -> 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, client_hello: &ClientHelloPayload, m: &Message, cx: &mut ServerContext<'_>, ) -> NextStateOrError { 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 maybe_versions_ext = client_hello.get_versions_extension(); let version = if let Some(versions) = maybe_versions_ext { if versions.contains(&ProtocolVersion::TLSv1_3) && tls13_enabled { ProtocolVersion::TLSv1_3 } else if !versions.contains(&ProtocolVersion::TLSv1_2) || !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 client_hello.client_version.get_u16() < ProtocolVersion::TLSv1_2.get_u16() { 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 .cipher_suites .iter() .copied() .filter(|scs| { client_hello .cipher_suites .contains(&scs.suite()) }) .collect::>(); sig_schemes .retain(|scheme| suites::compatible_sigscheme_for_suites(*scheme, &client_suites)); // Choose a certificate. let certkey = { let client_hello = ClientHello::new( &cx.data.sni, &sig_schemes, client_hello.get_alpn_extension(), &client_hello.cipher_suites, ); 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); // Reduce our supported ciphersuites by the certificate. // (no-op for TLS1.3) let suitable_suites = suites::reduce_given_sigalg(&self.config.cipher_suites, certkey.get_key().algorithm()); // And version let suitable_suites = suites::reduce_given_version(&suitable_suites, version); let suite = if self.config.ignore_client_order { suites::choose_ciphersuite_preferring_server( &client_hello.cipher_suites, &suitable_suites, ) } else { suites::choose_ciphersuite_preferring_client( &client_hello.cipher_suites, &suitable_suites, ) } .ok_or_else(|| { cx.common.send_fatal_alert( AlertDescription::HandshakeFailure, PeerIncompatible::NoCipherSuitesInCommon, ) })?; debug!("decided upon suite {:?}", suite); cx.common.suite = Some(suite); // Start handshake hash. let starting_hash = suite.hash_algorithm(); let transcript = match self.transcript { HandshakeHashOrBuffer::Buffer(inner) => inner.start_hash(starting_hash), HandshakeHashOrBuffer::Hash(inner) if inner.algorithm() == starting_hash => inner, _ => { return Err(cx.common.send_fatal_alert( AlertDescription::IllegalParameter, PeerMisbehaved::HandshakeHashVariedAfterRetry, )); } }; // Save their Random. let randoms = ConnectionRandoms::new(client_hello.random, Random::new()?); 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, 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, sig_schemes, tls13_enabled, ), } } } impl State for ExpectClientHello { fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> NextStateOrError { let (client_hello, sig_schemes) = process_client_hello(&m, self.done_retry, cx)?; self.with_certified_key(sig_schemes, client_hello, &m, cx) } } /// 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 [`ResolvesServerConfig`]/`ResolvesServerCert`]. /// /// Note that this will modify `data.sni` even if config or certificate resolution fail. pub(super) fn process_client_hello<'a>( m: &'a Message, done_retry: bool, cx: &mut ServerContext, ) -> Result<(&'a ClientHelloPayload, Vec), 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, )); } if client_hello.has_duplicate_extension() { return Err(cx.common.send_fatal_alert( AlertDescription::DecodeError, PeerMisbehaved::DuplicateClientHelloExtensions, )); } // 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. let sni: Option = match client_hello.get_sni_extension() { Some(sni) => { if sni.has_duplicate_names_for_type() { return Err(cx.common.send_fatal_alert( AlertDescription::DecodeError, PeerMisbehaved::DuplicateServerNameTypes, )); } if let Some(hostname) = sni.get_single_hostname() { Some(hostname.to_lowercase_owned()) } else { 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 .get_sigalgs_extension() .ok_or_else(|| { cx.common.send_fatal_alert( AlertDescription::HandshakeFailure, PeerIncompatible::SignatureAlgorithmsExtensionRequired, ) })?; Ok((client_hello, sig_schemes.to_owned())) } #[allow(clippy::large_enum_variant)] pub(crate) enum HandshakeHashOrBuffer { Buffer(HandshakeHashBuffer), Hash(HandshakeHash), } rustls-v-0.21.10/rustls/src/server/server_conn.rs000066400000000000000000000704711453461710000220060ustar00rootroot00000000000000use crate::builder::{ConfigBuilder, WantsCipherSuites}; use crate::common_state::{CommonState, Context, Side, State}; use crate::conn::{ConnectionCommon, ConnectionCore}; use crate::dns_name::DnsName; use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; use crate::error::Error; use crate::kx::SupportedKxGroup; #[cfg(feature = "logging")] use crate::log::trace; use crate::msgs::base::Payload; use crate::msgs::handshake::{ClientHelloPayload, ProtocolName, ServerExtension}; use crate::msgs::message::Message; use crate::sign; use crate::suites::SupportedCipherSuite; use crate::vecbuf::ChunkVecBuffer; use crate::verify; #[cfg(feature = "secret_extraction")] use crate::ExtractedSecrets; use crate::KeyLog; use super::hs; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::sync::Arc; use std::{fmt, io}; /// A trait for the ability to store server session data. /// /// The keys and values are opaque. /// /// 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: 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, value: Vec) -> bool; /// Find a value with the given `key`. Return it, or None /// if it doesn't exist. fn get(&self, key: &[u8]) -> Option>; /// 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>; /// 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: 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>; /// 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>; } /// How to choose a certificate chain and signing key for use /// in server authentication. pub trait ResolvesServerCert: 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>; } /// A struct representing the received Client Hello pub struct ClientHello<'a> { server_name: &'a Option, signature_schemes: &'a [SignatureScheme], alpn: Option<&'a Vec>, cipher_suites: &'a [CipherSuite], } impl<'a> ClientHello<'a> { /// Creates a new ClientHello pub(super) fn new( server_name: &'a Option, signature_schemes: &'a [SignatureScheme], alpn: Option<&'a Vec>, cipher_suites: &'a [CipherSuite], ) -> Self { trace!("sni {:?}", server_name); trace!("sig schemes {:?}", signature_schemes); trace!("alpn protocols {:?}", alpn); trace!("cipher suites {:?}", cipher_suites); ClientHello { server_name, signature_schemes, alpn, cipher_suites, } } /// 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(>::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 /// 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 /// . /// /// 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> { self.alpn.map(|protocols| { protocols .iter() .map(|proto| proto.as_ref()) }) } /// Get cipher suites. pub fn cipher_suites(&self) -> &[CipherSuite] { self.cipher_suites } } /// 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()`] function. /// /// # Defaults /// /// * [`ServerConfig::max_fragment_size`]: the default is `None`: TLS packets are not fragmented to a specific size. /// * [`ServerConfig::session_storage`]: the default stores 256 sessions in memory. /// * [`ServerConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. /// * [`ServerConfig::key_log`]: key material is not logged. /// * [`ServerConfig::send_tls13_tickets`]: 4 tickets are sent. /// /// [`RootCertStore`]: crate::RootCertStore #[derive(Clone)] pub struct ServerConfig { /// List of ciphersuites, in preference order. pub(super) cipher_suites: Vec, /// List of supported key exchange groups. /// /// The first is the highest priority: they will be /// offered to the client in this order. pub(super) kx_groups: Vec<&'static SupportedKxGroup>, /// 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 TLS message we'll emit. If None, we don't limit TLS /// message lengths except to the 2**16 limit specified in the standard. /// /// 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 the TCP MSS may improve latency for stream-y workloads. pub max_fragment_size: Option, /// How to store client sessions. pub session_storage: Arc, /// How to produce tickets. pub ticketer: Arc, /// How to choose a server cert and key. pub cert_resolver: Arc, /// Protocol names we support, most preferred first. /// If empty we don't do ALPN at all. pub alpn_protocols: Vec>, /// Supported protocol versions, in no particular order. /// The default is all supported versions. pub(super) versions: crate::versions::EnabledVersions, /// How to verify client certificates. pub(super) verifier: Arc, /// How to output key material for debugging. The default /// does nothing. pub key_log: Arc, /// Allows traffic secrets to be extracted after the handshake, /// e.g. for kTLS setup. #[cfg(feature = "secret_extraction")] #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] 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 4. /// /// If this is 0, no tickets are sent and clients will not be able to /// do any resumption. pub send_tls13_tickets: usize, } impl fmt::Debug for ServerConfig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ServerConfig") .field("ignore_client_order", &self.ignore_client_order) .field("max_fragment_size", &self.max_fragment_size) .field("alpn_protocols", &self.alpn_protocols) .field("max_early_data_size", &self.max_early_data_size) .field("send_half_rtt_data", &self.send_half_rtt_data) .field("send_tls13_tickets", &self.send_tls13_tickets) .finish_non_exhaustive() } } impl ServerConfig { /// Create builder to build up the server configuration. /// /// For more information, see the [`ConfigBuilder`] documentation. pub fn builder() -> ConfigBuilder { ConfigBuilder { state: WantsCipherSuites(()), side: PhantomData, } } /// 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 .cipher_suites .iter() .any(|cs| cs.version().version == v) } } /// 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<'a> std::io::Read for ReadEarlyData<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { 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 { inner: ConnectionCommon, } impl ServerConnection { /// Make a new ServerConnection. `config` controls how /// we behave in the TLS protocol. pub fn new(config: Arc) -> Result { Ok(Self { inner: ConnectionCommon::from(ConnectionCore::for_server(config, Vec::new())?), }) } /// 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` iff 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 { let data = &mut self.inner.core.data; if data.early_data.was_accepted() { Some(ReadEarlyData::new(&mut data.early_data)) } else { None } } /// Extract secrets, so they can be used when configuring kTLS, for example. #[cfg(feature = "secret_extraction")] #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] pub fn extract_secrets(self) -> Result { self.inner.extract_secrets() } } impl fmt::Debug for ServerConnection { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ServerConnection") .finish() } } impl Deref for ServerConnection { type Target = ConnectionCommon; fn deref(&self) -> &Self::Target { &self.inner } } impl DerefMut for ServerConnection { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } impl From for crate::Connection { fn from(conn: ServerConnection) -> Self { Self::Server(conn) } } /// Handle on a server-side connection before configuration is available. /// /// `Acceptor` allows the caller to choose a [`ServerConfig`] after reading /// the [`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 /// [`ResolvesServerCert`]. /// /// Create an Acceptor with [`Acceptor::default()`]. /// /// # Example /// /// ```no_run /// # fn choose_server_config( /// # _: rustls::server::ClientHello, /// # ) -> std::sync::Arc { /// # 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>, } 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 { 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)` if an error occurred. Do not call this function again. pub fn accept(&mut self) -> Result, Error> { let mut connection = match self.inner.take() { Some(conn) => conn, None => { return Err(Error::General("Acceptor polled after completion".into())); } }; let message = match connection.first_handshake_message()? { Some(msg) => msg, None => { self.inner = Some(connection); return Ok(None); } }; let (_, sig_schemes) = hs::process_client_hello(&message, false, &mut Context::from(&mut connection))?; Ok(Some(Accepted { connection, message, sig_schemes, })) } } /// 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, message: Message, sig_schemes: Vec, } impl Accepted { /// Get the [`ClientHello`] for this connection. pub fn client_hello(&self) -> ClientHello<'_> { let payload = Self::client_hello_payload(&self.message); ClientHello::new( &self.connection.core.data.sni, &self.sig_schemes, payload.get_alpn_extension(), &payload.cipher_suites, ) } /// 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. pub fn into_connection(mut self, config: Arc) -> Result { self.connection .set_max_fragment_size(config.max_fragment_size)?; #[cfg(feature = "secret_extraction")] { self.connection.enable_secret_extraction = config.enable_secret_extraction; } let state = hs::ExpectClientHello::new(config, Vec::new()); let mut cx = hs::ServerContext::from(&mut self.connection); let new = state.with_certified_key( self.sig_schemes, Self::client_hello_payload(&self.message), &self.message, &mut cx, )?; self.connection.replace_state(new); Ok(ServerConnection { inner: self.connection, }) } fn client_hello_payload(message: &Message) -> &ClientHelloPayload { match &message.payload { crate::msgs::message::MessagePayload::Handshake { parsed, .. } => match &parsed.payload { crate::msgs::handshake::HandshakePayload::ClientHello(ch) => ch, _ => unreachable!(), }, _ => unreachable!(), } } } struct Accepting; impl State for Accepting { fn handle( self: Box, _cx: &mut hs::ServerContext<'_>, _m: Message, ) -> Result>, Error> { Err(Error::General("unreachable state".into())) } } pub(super) enum EarlyDataState { New, Accepted(ChunkVecBuffer), 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(ChunkVecBuffer::new(Some(max_size))); } fn was_accepted(&self) -> bool { matches!(self, Self::Accepted(_)) } pub(super) fn was_rejected(&self) -> bool { matches!(self, Self::Rejected) } fn read(&mut self, buf: &mut [u8]) -> io::Result { match self { Self::Accepted(ref mut 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(ref mut 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.0.len(); match self { Self::Accepted(ref mut received) if received.apply_limit(available) == available => { received.append(bytes.0); true } _ => false, } } } // 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 std::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))" ); } impl ConnectionCore { pub(crate) fn for_server( config: Arc, extra_exts: Vec, ) -> Result { let mut common = CommonState::new(Side::Server); common.set_max_fragment_size(config.max_fragment_size)?; #[cfg(feature = "secret_extraction")] { common.enable_secret_extraction = config.enable_secret_extraction; } Ok(Self::new( Box::new(hs::ExpectClientHello::new(config, extra_exts)), ServerConnectionData::default(), common, )) } pub(crate) fn reject_early_data(&mut self) { assert!( self.common_state.is_handshaking(), "cannot retroactively reject early data" ); self.data.early_data.reject(); } pub(crate) fn get_sni_str(&self) -> Option<&str> { self.data.get_sni_str() } } /// State associated with a server connection. #[derive(Default)] pub struct ServerConnectionData { pub(super) sni: Option, pub(super) received_resumption_data: Option>, pub(super) resumption_data: Vec, pub(super) early_data: EarlyDataState, } impl ServerConnectionData { pub(super) fn get_sni_str(&self) -> Option<&str> { self.sni.as_ref().map(AsRef::as_ref) } } impl crate::conn::SideData for ServerConnectionData {} rustls-v-0.21.10/rustls/src/server/tls12.rs000066400000000000000000000772341453461710000204340ustar00rootroot00000000000000use crate::check::inappropriate_message; use crate::common_state::{CommonState, Side, State}; use crate::conn::ConnectionRandoms; use crate::enums::ProtocolVersion; use crate::enums::{AlertDescription, ContentType, HandshakeType}; use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; use crate::hash_hs::HandshakeHash; use crate::key::Certificate; #[cfg(feature = "logging")] use crate::log::{debug, trace}; use crate::msgs::base::Payload; use crate::msgs::ccs::ChangeCipherSpecPayload; use crate::msgs::codec::Codec; use crate::msgs::handshake::{ClientECDHParams, HandshakeMessagePayload, HandshakePayload}; use crate::msgs::handshake::{NewSessionTicketPayload, SessionId}; use crate::msgs::message::{Message, MessagePayload}; use crate::msgs::persist; #[cfg(feature = "secret_extraction")] use crate::suites::PartiallyExtractedSecrets; use crate::tls12::{self, ConnectionSecrets, Tls12CipherSuite}; use crate::{kx, ticketer, verify}; use super::common::ActiveCertifiedKey; use super::hs::{self, ServerContext}; use super::server_conn::{ProducesTickets, ServerConfig, ServerConnectionData}; use ring::constant_time; use std::sync::Arc; pub(super) use client_hello::CompleteClientHelloHandling; mod client_hello { use crate::enums::SignatureScheme; use crate::msgs::enums::ECPointFormat; use crate::msgs::enums::{ClientCertificateType, Compression}; use crate::msgs::handshake::ServerECDHParams; use crate::msgs::handshake::{CertificateRequestPayload, ClientSessionTicket, Random}; use crate::msgs::handshake::{CertificateStatus, ECDHEServerKeyExchange}; use crate::msgs::handshake::{ClientExtension, SessionId}; use crate::msgs::handshake::{ClientHelloPayload, ServerHelloPayload}; use crate::msgs::handshake::{ServerExtension, ServerKeyExchangePayload}; use crate::sign; use crate::verify::DigitallySignedStruct; use super::*; pub(in crate::server) struct CompleteClientHelloHandling { pub(in crate::server) config: Arc, 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: Vec, } impl CompleteClientHelloHandling { pub(in crate::server) fn handle_client_hello( mut self, cx: &mut ServerContext<'_>, server_key: ActiveCertifiedKey, chm: &Message, client_hello: &ClientHelloPayload, sigschemes_ext: Vec, tls13_enabled: bool, ) -> hs::NextStateOrError { // -- TLS1.2 only from hereon in -- self.transcript.add_message(chm); if client_hello.ems_support_offered() { self.using_ems = true; } let groups_ext = client_hello .get_namedgroups_extension() .ok_or_else(|| { cx.common.send_fatal_alert( AlertDescription::HandshakeFailure, PeerIncompatible::NamedGroupsExtensionRequired, ) })?; let ecpoints_ext = client_hello .get_ecpoints_extension() .ok_or_else(|| { cx.common.send_fatal_alert( AlertDescription::HandshakeFailure, PeerIncompatible::EcPointsExtensionRequired, ) })?; trace!("namedgroups {:?}", groups_ext); trace!("ecpoints {:?}", ecpoints_ext); if !ecpoints_ext.contains(&ECPointFormat::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 .get_ticket_extension() .and_then(|ticket_ext| match ticket_ext { ClientExtension::SessionTicket(ClientSessionTicket::Offer(ticket)) => { Some(ticket) } _ => None, }) .and_then(|ticket| { ticket_received = true; debug!("Ticket received"); let data = self.config.ticketer.decrypt(&ticket.0); 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.get_encoding()) }) .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 group = self .config .kx_groups .iter() .find(|skxg| groups_ext.contains(&skxg.name)) .cloned() .ok_or_else(|| { cx.common.send_fatal_alert( AlertDescription::HandshakeFailure, PeerIncompatible::NoKxGroupsInCommon, ) })?; let ecpoint = ECPointFormat::SUPPORTED .iter() .find(|format| ecpoints_ext.contains(format)) .cloned() .ok_or_else(|| { cx.common.send_fatal_alert( AlertDescription::HandshakeFailure, PeerIncompatible::NoEcPointFormatsInCommon, ) })?; debug_assert_eq!(ecpoint, ECPointFormat::Uncompressed); let (mut ocsp_response, mut sct_list) = (server_key.get_ocsp(), server_key.get_sct_list()); // 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.send_ticket = emit_server_hello( &self.config, &mut self.transcript, cx, self.session_id, self.suite, self.using_ems, &mut ocsp_response, &mut sct_list, client_hello, None, &self.randoms, self.extra_exts, )?; emit_certificate(&mut self.transcript, cx.common, server_key.get_cert()); if let Some(ocsp_response) = ocsp_response { emit_cert_status(&mut self.transcript, cx.common, ocsp_response); } let server_kx = emit_server_kx( &mut self.transcript, cx.common, sigschemes, group, server_key.get_key(), &self.randoms, )?; let doing_client_auth = emit_certificate_req(&self.config, &mut self.transcript, cx)?; emit_server_hello_done(&mut self.transcript, 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 { 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; self.send_ticket = emit_server_hello( &self.config, &mut self.transcript, cx, self.session_id, self.suite, self.using_ems, &mut None, &mut None, client_hello, Some(&resumedata), &self.randoms, self.extra_exts, )?; 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; if self.send_ticket { emit_ticket( &secrets, &mut self.transcript, self.using_ems, cx, &*self.config.ticketer, )?; } 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( config: &ServerConfig, transcript: &mut HandshakeHash, cx: &mut ServerContext<'_>, session_id: SessionId, suite: &'static Tls12CipherSuite, using_ems: bool, ocsp_response: &mut Option<&[u8]>, sct_list: &mut Option<&[u8]>, hello: &ClientHelloPayload, resumedata: Option<&persist::ServerSessionValue>, randoms: &ConnectionRandoms, extra_exts: Vec, ) -> Result { let mut ep = hs::ExtensionProcessing::new(); ep.process_common( config, cx, ocsp_response, sct_list, hello, resumedata, extra_exts, )?; ep.process_tls12(config, hello, using_ems); let sh = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::ServerHello, payload: 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.exts, }), }), }; trace!("sending server hello {:?}", sh); transcript.add_message(&sh); cx.common.send_msg(sh, false); Ok(ep.send_ticket) } fn emit_certificate( transcript: &mut HandshakeHash, common: &mut CommonState, cert_chain: &[Certificate], ) { let c = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::Certificate, payload: HandshakePayload::Certificate(cert_chain.to_owned()), }), }; transcript.add_message(&c); common.send_msg(c, false); } fn emit_cert_status(transcript: &mut HandshakeHash, common: &mut CommonState, ocsp: &[u8]) { let st = CertificateStatus::new(ocsp.to_owned()); let c = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::CertificateStatus, payload: HandshakePayload::CertificateStatus(st), }), }; transcript.add_message(&c); common.send_msg(c, false); } fn emit_server_kx( transcript: &mut HandshakeHash, common: &mut CommonState, sigschemes: Vec, skxg: &'static kx::SupportedKxGroup, signing_key: &dyn sign::SigningKey, randoms: &ConnectionRandoms, ) -> Result { let kx = kx::KeyExchange::start(skxg).ok_or(Error::FailedToGetRandomBytes)?; let secdh = ServerECDHParams::new(skxg.name, kx.pubkey.as_ref()); let mut msg = Vec::new(); msg.extend(randoms.client); msg.extend(randoms.server); secdh.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::ECDHE(ECDHEServerKeyExchange { params: secdh, dss: DigitallySignedStruct::new(sigscheme, sig), }); let m = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::ServerKeyExchange, payload: HandshakePayload::ServerKeyExchange(skx), }), }; transcript.add_message(&m); common.send_msg(m, false); Ok(kx) } fn emit_certificate_req( config: &ServerConfig, transcript: &mut HandshakeHash, cx: &mut ServerContext<'_>, ) -> Result { 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 .client_auth_root_subjects() .to_vec(); let cr = CertificateRequestPayload { certtypes: vec![ ClientCertificateType::RSASign, ClientCertificateType::ECDSASign, ], sigschemes: verify_schemes, canames: names, }; let m = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::CertificateRequest, payload: HandshakePayload::CertificateRequest(cr), }), }; trace!("Sending CertificateRequest {:?}", m); transcript.add_message(&m); cx.common.send_msg(m, false); Ok(true) } fn emit_server_hello_done(transcript: &mut HandshakeHash, common: &mut CommonState) { let m = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::ServerHelloDone, payload: HandshakePayload::ServerHelloDone, }), }; transcript.add_message(&m); common.send_msg(m, false); } } // --- Process client's Certificate for client auth --- struct ExpectCertificate { config: Arc, transcript: HandshakeHash, randoms: ConnectionRandoms, session_id: SessionId, suite: &'static Tls12CipherSuite, using_ems: bool, server_kx: kx::KeyExchange, send_ticket: bool, } impl State for ExpectCertificate { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { 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 = std::time::SystemTime::now(); 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, })) } } // --- Process client's KeyExchange --- struct ExpectClientKx { config: Arc, transcript: HandshakeHash, randoms: ConnectionRandoms, session_id: SessionId, suite: &'static Tls12CipherSuite, using_ems: bool, server_kx: kx::KeyExchange, client_cert: Option>, send_ticket: bool, } impl State for ExpectClientKx { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { 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.get_current_hash()); // Complete key agreement, and set up encryption with the // resulting premaster secret. let peer_kx_params = tls12::decode_ecdh_params::(cx.common, &client_kx.0)?; let secrets = ConnectionSecrets::from_key_exchange( self.server_kx, &peer_kx_params.public.0, ems_seed, self.randoms, self.suite, )?; self.config.key_log.log( "CLIENT_RANDOM", &secrets.randoms.client, &secrets.master_secret, ); cx.common .start_encryption_tls12(&secrets, Side::Server); if let Some(client_cert) = self.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, })) } else { 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, })) } } } // --- Process client's certificate proof --- struct ExpectCertificateVerify { config: Arc, secrets: ConnectionSecrets, transcript: HandshakeHash, session_id: SessionId, using_ems: bool, client_cert: Vec, send_ticket: bool, } impl State for ExpectCertificateVerify { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { 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); 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, })) } } // --- Process client's ChangeCipherSpec --- struct ExpectCcs { config: Arc, secrets: ConnectionSecrets, transcript: HandshakeHash, session_id: SessionId, using_ems: bool, resuming: bool, send_ticket: bool, } impl State for ExpectCcs { fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { 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, })) } } // --- Process client's Finished --- fn get_server_connection_value_tls12( secrets: &ConnectionSecrets, using_ems: bool, cx: &ServerContext<'_>, time_now: ticketer::TimeBase, ) -> persist::ServerSessionValue { let version = ProtocolVersion::TLSv1_2; let secret = secrets.get_master_secret(); let mut v = persist::ServerSessionValue::new( cx.data.sni.as_ref(), version, secrets.suite().common.suite, 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, ) -> Result<(), Error> { let time_now = ticketer::TimeBase::now()?; let plain = get_server_connection_value_tls12(secrets, using_ems, cx, time_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 { typ: HandshakeType::NewSessionTicket, payload: 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.get_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 { typ: HandshakeType::Finished, payload: HandshakePayload::Finished(verify_data_payload), }), }; transcript.add_message(&f); common.send_msg(f, true); } struct ExpectFinished { config: Arc, secrets: ConnectionSecrets, transcript: HandshakeHash, session_id: SessionId, using_ems: bool, resuming: bool, send_ticket: bool, } impl State for ExpectFinished { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { let finished = require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; cx.common.check_aligned_handshake()?; let vh = self.transcript.get_current_hash(); let expect_verify_data = self.secrets.client_verify_data(&vh); let _fin_verified = constant_time::verify_slices_are_equal(&expect_verify_data, &finished.0) .map_err(|_| { cx.common .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError) }) .map(|_| verify::FinishedMessageVerified::assertion())?; // Save connection, perhaps if !self.resuming && !self.session_id.is_empty() { let time_now = ticketer::TimeBase::now()?; let value = get_server_connection_value_tls12(&self.secrets, self.using_ems, cx, time_now); let worked = self .config .session_storage .put(self.session_id.get_encoding(), value.get_encoding()); 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 { emit_ticket( &self.secrets, &mut self.transcript, self.using_ems, cx, &*self.config.ticketer, )?; } emit_ccs(cx.common); cx.common .record_layer .start_encrypting(); emit_finished(&self.secrets, &mut self.transcript, cx.common); } cx.common.start_traffic(); Ok(Box::new(ExpectTraffic { secrets: self.secrets, _fin_verified, })) } } // --- Process traffic --- struct ExpectTraffic { secrets: ConnectionSecrets, _fin_verified: verify::FinishedMessageVerified, } impl ExpectTraffic {} impl State for ExpectTraffic { fn handle(self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { 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(()) } #[cfg(feature = "secret_extraction")] fn extract_secrets(&self) -> Result { self.secrets .extract_secrets(Side::Server) } } rustls-v-0.21.10/rustls/src/server/tls13.rs000066400000000000000000001352231453461710000204260ustar00rootroot00000000000000use crate::check::inappropriate_handshake_message; #[cfg(feature = "quic")] use crate::check::inappropriate_message; #[cfg(feature = "quic")] use crate::common_state::Protocol; #[cfg(feature = "secret_extraction")] use crate::common_state::Side; use crate::common_state::{CommonState, State}; use crate::conn::ConnectionRandoms; use crate::enums::ProtocolVersion; use crate::enums::{AlertDescription, ContentType, HandshakeType}; use crate::error::{Error, PeerIncompatible, PeerMisbehaved}; use crate::hash_hs::HandshakeHash; use crate::key::Certificate; #[cfg(feature = "logging")] use crate::log::{debug, trace, warn}; use crate::msgs::codec::Codec; use crate::msgs::enums::KeyUpdateRequest; use crate::msgs::handshake::HandshakeMessagePayload; use crate::msgs::handshake::HandshakePayload; use crate::msgs::handshake::{NewSessionTicketExtension, NewSessionTicketPayloadTLS13}; use crate::msgs::message::{Message, MessagePayload}; use crate::msgs::persist; use crate::rand; use crate::server::ServerConfig; #[cfg(feature = "secret_extraction")] use crate::suites::PartiallyExtractedSecrets; use crate::ticketer; use crate::tls13::key_schedule::{KeyScheduleTraffic, KeyScheduleTrafficWithClientFinishedPending}; use crate::tls13::Tls13CipherSuite; use crate::verify; use super::hs::{self, HandshakeHashOrBuffer, ServerContext}; use super::server_conn::ServerConnectionData; use std::sync::Arc; use ring::constant_time; pub(super) use client_hello::CompleteClientHelloHandling; mod client_hello { use crate::enums::SignatureScheme; use crate::kx; use crate::msgs::base::{Payload, PayloadU8}; use crate::msgs::ccs::ChangeCipherSpecPayload; use crate::msgs::enums::NamedGroup; use crate::msgs::enums::{Compression, PSKKeyExchangeMode}; use crate::msgs::handshake::CertReqExtension; use crate::msgs::handshake::CertificateEntry; use crate::msgs::handshake::CertificateExtension; use crate::msgs::handshake::CertificatePayloadTLS13; use crate::msgs::handshake::CertificateRequestPayloadTLS13; use crate::msgs::handshake::CertificateStatus; use crate::msgs::handshake::ClientHelloPayload; use crate::msgs::handshake::HelloRetryExtension; use crate::msgs::handshake::HelloRetryRequest; use crate::msgs::handshake::KeyShareEntry; use crate::msgs::handshake::Random; use crate::msgs::handshake::ServerExtension; use crate::msgs::handshake::ServerHelloPayload; use crate::msgs::handshake::SessionId; use crate::server::common::ActiveCertifiedKey; use crate::sign; use crate::tls13::key_schedule::{ KeyScheduleEarly, KeyScheduleHandshake, KeySchedulePreHandshake, }; use crate::verify::DigitallySignedStruct; use super::*; #[derive(PartialEq)] pub(super) enum EarlyDataDecision { Disabled, RequestedButRejected, Accepted, } pub(in crate::server) struct CompleteClientHelloHandling { pub(in crate::server) config: Arc, 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: Vec, } 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, .. } => { parsed.get_encoding_for_binder_signing() } _ => unreachable!(), }; let handshake_hash = self .transcript .get_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); constant_time::verify_slices_are_equal(real_binder.as_ref(), binder).is_ok() } fn attempt_tls13_ticket_decryption( &mut self, ticket: &[u8], ) -> Option { 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, mut sigschemes_ext: Vec, ) -> hs::NextStateOrError { if client_hello.compression_methods.len() != 1 { return Err(cx.common.send_fatal_alert( AlertDescription::IllegalParameter, PeerMisbehaved::OfferedIncorrectCompressions, )); } let groups_ext = client_hello .get_namedgroups_extension() .ok_or_else(|| { cx.common.send_fatal_alert( AlertDescription::HandshakeFailure, PeerIncompatible::NamedGroupsExtensionRequired, ) })?; let tls13_schemes = sign::supported_sign_tls13(); sigschemes_ext.retain(|scheme| tls13_schemes.contains(scheme)); let shares_ext = client_hello .get_keyshare_extension() .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, )); } let early_data_requested = client_hello.early_data_extension_offered(); // 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, ) }); } // choose a share that we support let chosen_share = self .config .kx_groups .iter() .find_map(|group| { shares_ext .iter() .find(|share| share.group == group.name) }); let chosen_share = match chosen_share { Some(s) => s, None => { // We don't have a suitable key share. Choose a suitable group and // send a HelloRetryRequest. let retry_group_maybe = self .config .kx_groups .iter() .find(|group| groups_ext.contains(&group.name)) .cloned(); self.transcript.add_message(chm); if let Some(group) = retry_group_maybe { 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, group.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) }; } return Err(cx.common.send_fatal_alert( AlertDescription::HandshakeFailure, PeerIncompatible::NoKxGroupsInCommon, )); } }; let mut chosen_psk_index = None; let mut resumedata = None; let time_now = ticketer::TimeBase::now()?; if let Some(psk_offer) = client_hello.get_psk() { if !client_hello.check_psk_ext_is_last() { return Err(cx.common.send_fatal_alert( AlertDescription::IllegalParameter, PeerMisbehaved::PskExtensionMustBeLast, )); } // "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.get_psk_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, )); } for (i, psk_id) in psk_offer.identities.iter().enumerate() { let resume = match self .attempt_tls13_ticket_decryption(&psk_id.identity.0) .map(|resumedata| { resumedata.set_freshness(psk_id.obfuscated_ticket_age, time_now) }) .filter(|resumedata| { hs::can_resume(self.suite.into(), &cx.data.sni, false, resumedata) }) { Some(resume) => resume, None => 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.psk_mode_offered(PSKKeyExchangeMode::PSK_DHE_KE) { debug!("Client unwilling to resume, 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(ref resume) = resumedata { cx.data.received_resumption_data = Some(resume.application_data.0.clone()); cx.common.peer_certificates = resume.client_cert_chain.clone(); } 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, chosen_psk_index, resumedata .as_ref() .map(|x| &x.master_secret.0[..]), &self.config, )?; if !self.done_retry { emit_fake_ccs(cx.common); } let (mut ocsp_response, mut sct_list) = (server_key.get_ocsp(), server_key.get_sct_list()); let doing_early_data = emit_encrypted_extensions( &mut self.transcript, self.suite, cx, &mut ocsp_response, &mut sct_list, 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 self.transcript, cx, &self.config)?; emit_certificate_tls13( &mut self.transcript, cx.common, server_key.get_cert(), ocsp_response, sct_list, ); emit_certificate_verify_tls13( &mut self.transcript, 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( &mut self.transcript, &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(); } if doing_client_auth { Ok(Box::new(ExpectCertificate { 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: &KeyShareEntry, chosen_psk_idx: Option, resuming_psk: Option<&[u8]>, config: &ServerConfig, ) -> Result { let mut extensions = Vec::new(); // Prepare key exchange let kx = kx::KeyExchange::choose(share.group, &config.kx_groups) .and_then(kx::KeyExchange::start) .ok_or(Error::FailedToGetRandomBytes)?; let kse = KeyShareEntry::new(share.group, kx.pubkey.as_ref()); extensions.push(ServerExtension::KeyShare(kse)); extensions.push(ServerExtension::SupportedVersions(ProtocolVersion::TLSv1_3)); if let Some(psk_idx) = chosen_psk_idx { extensions.push(ServerExtension::PresharedKey(psk_idx as u16)); } let sh = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::ServerHello, payload: 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.get_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 = kx.complete(&share.payload.0, |secret| { key_schedule_pre_handshake.into_handshake(secret) })?; let handshake_hash = transcript.get_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 mut req = HelloRetryRequest { legacy_version: ProtocolVersion::TLSv1_2, session_id, cipher_suite: suite.common.suite, extensions: Vec::new(), }; req.extensions .push(HelloRetryExtension::KeyShare(group)); req.extensions .push(HelloRetryExtension::SupportedVersions( ProtocolVersion::TLSv1_3, )); let m = Message { version: ProtocolVersion::TLSv1_2, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::HelloRetryRequest, payload: HandshakePayload::HelloRetryRequest(req), }), }; trace!("Requesting retry {:?}", m); transcript.rollup_for_hrr(); transcript.add_message(&m); common.send_msg(m, false); } #[allow(clippy::needless_pass_by_ref_mut)] // cx only mutated if cfg(feature = "quic") 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_extension_offered(); let rejected_or_disabled = match early_data_requested { true => EarlyDataDecision::RequestedButRejected, false => EarlyDataDecision::Disabled, }; let resume = match resumedata { Some(resume) => resume, None => { // 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(|x| &x.0) == cx.common.alpn_protocol.as_ref(); if early_data_configured && early_data_possible && !cx.data.early_data.was_rejected() { EarlyDataDecision::Accepted } else { #[cfg(feature = "quic")] 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( transcript: &mut HandshakeHash, suite: &'static Tls13CipherSuite, cx: &mut ServerContext<'_>, ocsp_response: &mut Option<&[u8]>, sct_list: &mut Option<&[u8]>, hello: &ClientHelloPayload, resumedata: Option<&persist::ServerSessionValue>, extra_exts: Vec, config: &ServerConfig, ) -> Result { let mut ep = hs::ExtensionProcessing::new(); ep.process_common( config, cx, ocsp_response, sct_list, hello, resumedata, extra_exts, )?; let early_data = decide_if_early_data_allowed(cx, hello, resumedata, suite, config); if early_data == EarlyDataDecision::Accepted { ep.exts.push(ServerExtension::EarlyData); } let ee = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::EncryptedExtensions, payload: HandshakePayload::EncryptedExtensions(ep.exts), }), }; trace!("sending encrypted extensions {:?}", ee); transcript.add_message(&ee); cx.common.send_msg(ee, true); Ok(early_data) } fn emit_certificate_req_tls13( transcript: &mut HandshakeHash, cx: &mut ServerContext<'_>, config: &ServerConfig, ) -> Result { if !config.verifier.offer_client_auth() { return Ok(false); } let mut cr = CertificateRequestPayloadTLS13 { context: PayloadU8::empty(), extensions: Vec::new(), }; let schemes = config .verifier .supported_verify_schemes(); cr.extensions .push(CertReqExtension::SignatureAlgorithms(schemes.to_vec())); let names = config .verifier .client_auth_root_subjects() .to_vec(); if !names.is_empty() { cr.extensions .push(CertReqExtension::AuthorityNames(names)); } let m = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::CertificateRequest, payload: HandshakePayload::CertificateRequestTLS13(cr), }), }; trace!("Sending CertificateRequest {:?}", m); transcript.add_message(&m); cx.common.send_msg(m, true); Ok(true) } fn emit_certificate_tls13( transcript: &mut HandshakeHash, common: &mut CommonState, cert_chain: &[Certificate], ocsp_response: Option<&[u8]>, sct_list: Option<&[u8]>, ) { let mut cert_entries = vec![]; for cert in cert_chain { let entry = CertificateEntry { cert: cert.to_owned(), exts: Vec::new(), }; cert_entries.push(entry); } if let Some(end_entity_cert) = cert_entries.first_mut() { // Apply OCSP response to first certificate (we don't support OCSP // except for leaf certs). if let Some(ocsp) = ocsp_response { let cst = CertificateStatus::new(ocsp.to_owned()); end_entity_cert .exts .push(CertificateExtension::CertificateStatus(cst)); } // Likewise, SCT if let Some(sct_list) = sct_list { end_entity_cert .exts .push(CertificateExtension::make_sct(sct_list.to_owned())); } } let cert_body = CertificatePayloadTLS13::new(cert_entries); let c = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::Certificate, payload: HandshakePayload::CertificateTLS13(cert_body), }), }; trace!("sending certificate {:?}", c); transcript.add_message(&c); common.send_msg(c, true); } fn emit_certificate_verify_tls13( transcript: &mut HandshakeHash, common: &mut CommonState, signing_key: &dyn sign::SigningKey, schemes: &[SignatureScheme], ) -> Result<(), Error> { let message = verify::construct_tls13_server_verify_message(&transcript.get_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)?; let cv = DigitallySignedStruct::new(scheme, sig); let m = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::CertificateVerify, payload: HandshakePayload::CertificateVerify(cv), }), }; trace!("sending certificate-verify {:?}", m); transcript.add_message(&m); common.send_msg(m, true); Ok(()) } fn emit_finished_tls13( transcript: &mut HandshakeHash, randoms: &ConnectionRandoms, cx: &mut ServerContext<'_>, key_schedule: KeyScheduleHandshake, config: &ServerConfig, ) -> KeyScheduleTrafficWithClientFinishedPending { let handshake_hash = transcript.get_current_hash(); let verify_data = key_schedule.sign_server_finish(&handshake_hash); let verify_data_payload = Payload::new(verify_data.as_ref()); let m = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::Finished, payload: HandshakePayload::Finished(verify_data_payload), }), }; trace!("sending finished {:?}", m); transcript.add_message(&m); let hash_at_server_fin = transcript.get_current_hash(); cx.common.send_msg(m, true); // 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, } impl State for ExpectAndSkipRejectedEarlyData { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { /* "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(ref skip_data) = m.payload { if skip_data.0.len() <= self.skip_data_left { self.skip_data_left -= skip_data.0.len(); return Ok(self); } } self.next.handle(cx, m) } } struct ExpectCertificate { config: Arc, transcript: HandshakeHash, suite: &'static Tls13CipherSuite, key_schedule: KeyScheduleTrafficWithClientFinishedPending, send_tickets: usize, } impl State for ExpectCertificate { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { let certp = require_handshake_msg!( m, HandshakeType::Certificate, HandshakePayload::CertificateTLS13 )?; self.transcript.add_message(&m); // We don't send any CertificateRequest extensions, so any extensions // here are illegal. if certp.any_entry_has_extension() { return Err(PeerMisbehaved::UnsolicitedCertExtension.into()); } let client_cert = certp.convert(); let mandatory = self .config .verifier .client_auth_mandatory(); let (end_entity, intermediates) = match client_cert.split_first() { None => { 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, )); } Some(chain) => chain, }; let now = std::time::SystemTime::now(); 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, send_tickets: self.send_tickets, })) } } struct ExpectCertificateVerify { config: Arc, transcript: HandshakeHash, suite: &'static Tls13CipherSuite, key_schedule: KeyScheduleTrafficWithClientFinishedPending, client_cert: Vec, send_tickets: usize, } impl State for ExpectCertificateVerify { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { let rc = { let sig = require_handshake_msg!( m, HandshakeType::CertificateVerify, HandshakePayload::CertificateVerify )?; let handshake_hash = self.transcript.get_current_hash(); self.transcript.abandon_client_auth(); let certs = &self.client_cert; let msg = verify::construct_tls13_client_verify_message(&handshake_hash); self.config .verifier .verify_tls13_signature(&msg, &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, })) } } // --- Process (any number of) early ApplicationData messages, // followed by a terminating handshake EndOfEarlyData message --- struct ExpectEarlyData { config: Arc, transcript: HandshakeHash, suite: &'static Tls13CipherSuite, key_schedule: KeyScheduleTrafficWithClientFinishedPending, send_tickets: usize, } impl State for ExpectEarlyData { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { 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 { typ: HandshakeType::EndOfEarlyData, payload: 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], )), } } } // --- Process client's Finished --- fn get_server_session_value( transcript: &HandshakeHash, suite: &'static Tls13CipherSuite, key_schedule: &KeyScheduleTraffic, cx: &ServerContext<'_>, nonce: &[u8], time_now: ticketer::TimeBase, age_obfuscation_offset: u32, ) -> persist::ServerSessionValue { let version = ProtocolVersion::TLSv1_3; let handshake_hash = transcript.get_current_hash(); let secret = key_schedule.resumption_master_secret_and_derive_ticket_psk(&handshake_hash, nonce); persist::ServerSessionValue::new( cx.data.sni.as_ref(), version, suite.common.suite, secret, cx.common.peer_certificates.clone(), cx.common.alpn_protocol.clone(), cx.data.resumption_data.clone(), time_now, age_obfuscation_offset, ) } struct ExpectFinished { config: Arc, transcript: HandshakeHash, suite: &'static Tls13CipherSuite, key_schedule: KeyScheduleTrafficWithClientFinishedPending, send_tickets: usize, } impl ExpectFinished { fn emit_ticket( transcript: &HandshakeHash, suite: &'static Tls13CipherSuite, cx: &mut ServerContext<'_>, key_schedule: &KeyScheduleTraffic, config: &ServerConfig, ) -> Result<(), Error> { let nonce = rand::random_vec(32)?; let now = ticketer::TimeBase::now()?; let age_add = rand::random_u32()?; let plain = get_server_session_value(transcript, suite, key_schedule, cx, &nonce, now, age_add) .get_encoding(); let stateless = config.ticketer.enabled(); let (ticket, lifetime) = if stateless { let ticket = match config.ticketer.encrypt(&plain) { Some(t) => t, None => return Ok(()), }; (ticket, config.ticketer.lifetime()) } else { let id = rand::random_vec(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 .exts .push(NewSessionTicketExtension::EarlyData( 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 m = Message { version: ProtocolVersion::TLSv1_3, payload: MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::NewSessionTicket, payload: HandshakePayload::NewSessionTicketTLS13(payload), }), }; trace!("sending new ticket {:?} (stateless: {})", m, stateless); cx.common.send_msg(m, true); Ok(()) } } impl State for ExpectFinished { fn handle(mut self: Box, cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { let finished = require_handshake_msg!(m, HandshakeType::Finished, HandshakePayload::Finished)?; let handshake_hash = self.transcript.get_current_hash(); let (key_schedule_traffic, expect_verify_data) = self .key_schedule .sign_client_finish(&handshake_hash, cx.common); let fin = constant_time::verify_slices_are_equal(expect_verify_data.as_ref(), &finished.0) .map_err(|_| { warn!("Finished wrong"); cx.common .send_fatal_alert(AlertDescription::DecryptError, Error::DecryptError) }) .map(|_| verify::FinishedMessageVerified::assertion())?; // nb. future derivations include Client Finished, but not the // main application data keying. self.transcript.add_message(&m); cx.common.check_aligned_handshake()?; for _ in 0..self.send_tickets { Self::emit_ticket( &self.transcript, self.suite, cx, &key_schedule_traffic, &self.config, )?; } // Application data may now flow, even if we have client auth enabled. cx.common.start_traffic(); #[cfg(feature = "quic")] { if cx.common.protocol == Protocol::Quic { return Ok(Box::new(ExpectQuicTraffic { key_schedule: key_schedule_traffic, _fin_verified: fin, })); } } Ok(Box::new(ExpectTraffic { key_schedule: key_schedule_traffic, _fin_verified: fin, })) } } // --- 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> { #[cfg(feature = "quic")] { 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 for ExpectTraffic { fn handle(mut self: Box, cx: &mut ServerContext, m: Message) -> hs::NextStateOrError { match m.payload { MessagePayload::ApplicationData(payload) => cx .common .take_received_plaintext(payload), MessagePayload::Handshake { parsed: HandshakeMessagePayload { payload: 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) } #[cfg(feature = "secret_extraction")] fn extract_secrets(&self) -> Result { self.key_schedule .extract_secrets(Side::Server) } } #[cfg(feature = "quic")] struct ExpectQuicTraffic { key_schedule: KeyScheduleTraffic, _fin_verified: verify::FinishedMessageVerified, } #[cfg(feature = "quic")] impl State for ExpectQuicTraffic { fn handle(self: Box, _cx: &mut ServerContext<'_>, m: Message) -> hs::NextStateOrError { // 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) } } rustls-v-0.21.10/rustls/src/sign.rs000066400000000000000000000350351453461710000171120ustar00rootroot00000000000000use crate::enums::{SignatureAlgorithm, SignatureScheme}; use crate::error::Error; use crate::key; use crate::x509::{wrap_in_asn1_len, wrap_in_sequence}; use ring::io::der; use ring::rand::{SecureRandom, SystemRandom}; use ring::signature::{self, EcdsaKeyPair, Ed25519KeyPair, RsaKeyPair}; use std::error::Error as StdError; use std::fmt; use std::sync::Arc; /// An abstract signing key. pub trait SigningKey: 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>; /// What kind of key we have. fn algorithm(&self) -> SignatureAlgorithm; } /// A thing that can sign a message. pub trait Signer: Send + Sync { /// Signs `message` using the selected scheme. fn sign(&self, message: &[u8]) -> Result, Error>; /// Reveals which scheme will be used when you call `sign()`. fn scheme(&self) -> SignatureScheme; } /// A packaged-together certificate chain, matching `SigningKey` and /// optional stapled OCSP response and/or SCT list. #[derive(Clone)] pub struct CertifiedKey { /// The certificate chain. pub cert: Vec, /// The certified key. pub key: Arc, /// An optional OCSP response from the certificate issuer, /// attesting to its continued validity. pub ocsp: Option>, /// An optional collection of SCTs from CT logs, proving the /// certificate is included on those logs. This must be /// a `SignedCertificateTimestampList` encoding; see RFC6962. pub sct_list: Option>, } impl CertifiedKey { /// 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, key: Arc) -> Self { Self { cert, key, ocsp: None, sct_list: None, } } /// The end-entity certificate. pub fn end_entity_cert(&self) -> Result<&key::Certificate, SignError> { self.cert.first().ok_or(SignError(())) } } /// Parse `der` as any supported key encoding/type, returning /// the first which works. pub fn any_supported_type(der: &key::PrivateKey) -> Result, SignError> { if let Ok(rsa) = RsaSigningKey::new(der) { Ok(Arc::new(rsa)) } else if let Ok(ecdsa) = any_ecdsa_type(der) { Ok(ecdsa) } else { any_eddsa_type(der) } } /// 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: &key::PrivateKey) -> Result, SignError> { 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(SignError(())) } /// Parse `der` as any EdDSA key type, returning the first which works. pub fn any_eddsa_type(der: &key::PrivateKey) -> Result, SignError> { if let Ok(ed25519) = Ed25519SigningKey::new(der, SignatureScheme::ED25519) { return Ok(Arc::new(ed25519)); } // TODO: Add support for Ed448 Err(SignError(())) } /// 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, } 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: &key::PrivateKey) -> Result { RsaKeyPair::from_der(&der.0) .or_else(|_| RsaKeyPair::from_pkcs8(&der.0)) .map(|s| Self { key: Arc::new(s) }) .map_err(|_| SignError(())) } } impl SigningKey for RsaSigningKey { fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { ALL_RSA_SCHEMES .iter() .find(|scheme| offered.contains(scheme)) .map(|scheme| RsaSigner::new(Arc::clone(&self.key), *scheme)) } fn algorithm(&self) -> SignatureAlgorithm { SignatureAlgorithm::RSA } } struct RsaSigner { key: Arc, scheme: SignatureScheme, encoding: &'static dyn signature::RsaEncoding, } impl RsaSigner { fn new(key: Arc, scheme: SignatureScheme) -> Box { 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, Error> { let mut sig = vec![0; self.key.public().modulus_len()]; let rng = ring::rand::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 } } /// 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, 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: &key::PrivateKey, scheme: SignatureScheme, sigalg: &'static signature::EcdsaSigningAlgorithm, ) -> Result { let rng = SystemRandom::new(); EcdsaKeyPair::from_pkcs8(sigalg, &der.0, &rng) .map_err(|_| ()) .or_else(|_| Self::convert_sec1_to_pkcs8(scheme, sigalg, &der.0, &rng)) .map(|kp| Self { key: Arc::new(kp), 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 { 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 }; // wrap sec1 encoding in an OCTET STRING let mut sec1_wrap = Vec::with_capacity(maybe_sec1_der.len() + 8); sec1_wrap.extend_from_slice(maybe_sec1_der); wrap_in_asn1_len(&mut sec1_wrap); sec1_wrap.insert(0, der::Tag::OctetString as u8); let mut pkcs8 = Vec::with_capacity(pkcs8_prefix.len() + sec1_wrap.len() + 4); pkcs8.extend_from_slice(pkcs8_prefix); pkcs8.extend_from_slice(&sec1_wrap); wrap_in_sequence(&mut pkcs8); 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> { if offered.contains(&self.scheme) { Some(Box::new(EcdsaSigner { key: Arc::clone(&self.key), scheme: self.scheme, })) } else { None } } fn algorithm(&self) -> SignatureAlgorithm { self.scheme.sign() } } struct EcdsaSigner { key: Arc, scheme: SignatureScheme, } impl Signer for EcdsaSigner { fn sign(&self, message: &[u8]) -> Result, Error> { let rng = ring::rand::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 } } /// 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, 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: &key::PrivateKey, scheme: SignatureScheme) -> Result { Ed25519KeyPair::from_pkcs8_maybe_unchecked(&der.0) .map(|kp| Self { key: Arc::new(kp), scheme, }) .map_err(|_| SignError(())) } } impl SigningKey for Ed25519SigningKey { fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option> { if offered.contains(&self.scheme) { Some(Box::new(Ed25519Signer { key: Arc::clone(&self.key), scheme: self.scheme, })) } else { None } } fn algorithm(&self) -> SignatureAlgorithm { self.scheme.sign() } } struct Ed25519Signer { key: Arc, scheme: SignatureScheme, } impl Signer for Ed25519Signer { fn sign(&self, message: &[u8]) -> Result, Error> { Ok(self.key.sign(message).as_ref().into()) } fn scheme(&self) -> SignatureScheme { self.scheme } } /// The set of schemes we support for signatures and /// that are allowed for TLS1.3. pub fn supported_sign_tls13() -> &'static [SignatureScheme] { &[ SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP256_SHA256, SignatureScheme::RSA_PSS_SHA512, SignatureScheme::RSA_PSS_SHA384, SignatureScheme::RSA_PSS_SHA256, SignatureScheme::ED25519, ] } /// Errors while signing #[derive(Debug)] pub struct SignError(()); impl fmt::Display for SignError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("sign error") } } impl StdError for SignError {} #[test] fn can_load_ecdsa_nistp256_pkcs8() { let key = key::PrivateKey(include_bytes!("testdata/nistp256key.pkcs8.der").to_vec()); assert!(any_supported_type(&key).is_ok()); assert!(any_ecdsa_type(&key).is_ok()); assert!(any_eddsa_type(&key).is_err()); } #[test] fn can_load_ecdsa_nistp256_sec1() { let key = key::PrivateKey(include_bytes!("testdata/nistp256key.der").to_vec()); assert!(any_supported_type(&key).is_ok()); assert!(any_ecdsa_type(&key).is_ok()); assert!(any_eddsa_type(&key).is_err()); } #[test] fn can_load_ecdsa_nistp384_pkcs8() { let key = key::PrivateKey(include_bytes!("testdata/nistp384key.pkcs8.der").to_vec()); assert!(any_supported_type(&key).is_ok()); assert!(any_ecdsa_type(&key).is_ok()); assert!(any_eddsa_type(&key).is_err()); } #[test] fn can_load_ecdsa_nistp384_sec1() { let key = key::PrivateKey(include_bytes!("testdata/nistp384key.der").to_vec()); assert!(any_supported_type(&key).is_ok()); assert!(any_ecdsa_type(&key).is_ok()); assert!(any_eddsa_type(&key).is_err()); } #[test] fn can_load_eddsa_pkcs8() { let key = key::PrivateKey(include_bytes!("testdata/eddsakey.der").to_vec()); assert!(any_supported_type(&key).is_ok()); assert!(any_eddsa_type(&key).is_ok()); assert!(any_ecdsa_type(&key).is_err()); } #[test] fn can_load_rsa2048_pkcs8() { let key = key::PrivateKey(include_bytes!("testdata/rsa2048key.pkcs8.der").to_vec()); assert!(any_supported_type(&key).is_ok()); assert!(any_eddsa_type(&key).is_err()); assert!(any_ecdsa_type(&key).is_err()); } #[test] fn can_load_rsa2048_pkcs1() { let key = key::PrivateKey(include_bytes!("testdata/rsa2048key.pkcs1.der").to_vec()); assert!(any_supported_type(&key).is_ok()); assert!(any_eddsa_type(&key).is_err()); assert!(any_ecdsa_type(&key).is_err()); } rustls-v-0.21.10/rustls/src/stream.rs000066400000000000000000000147171453461710000174510ustar00rootroot00000000000000use crate::conn::{ConnectionCommon, SideData}; use std::io::{IoSlice, Read, Result, Write}; use std::ops::{Deref, DerefMut}; /// 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>, 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(()) } } impl<'a, C, T, S> Read for Stream<'a, C, T> where C: 'a + DerefMut + Deref>, T: 'a + Read + Write, S: SideData, { fn read(&mut self, buf: &mut [u8]) -> 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; } } self.conn.reader().read(buf) } #[cfg(read_buf)] fn read_buf(&mut self, cursor: core::io::BorrowedCursor<'_>) -> 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; } } self.conn.reader().read_buf(cursor) } } impl<'a, C, T, S> Write for Stream<'a, C, T> where C: 'a + DerefMut + Deref>, T: 'a + Read + Write, S: SideData, { fn write(&mut self, buf: &[u8]) -> Result { 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 { 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 { /// Our connection pub conn: C, /// The underlying transport, like a socket pub sock: T, } impl StreamOwned where C: DerefMut + Deref>, 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 } } impl<'a, C, T, S> StreamOwned where C: DerefMut + Deref>, 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 Read for StreamOwned where C: DerefMut + Deref>, T: Read + Write, S: SideData, { fn read(&mut self, buf: &mut [u8]) -> Result { 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 Write for StreamOwned where C: DerefMut + Deref>, T: Read + Write, S: SideData, { fn write(&mut self, buf: &[u8]) -> Result { self.as_stream().write(buf) } fn flush(&mut self) -> Result<()> { self.as_stream().flush() } } #[cfg(test)] mod tests { use super::{Stream, StreamOwned}; use crate::client::ClientConnection; use crate::server::ServerConnection; use std::net::TcpStream; #[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; } #[test] fn streamowned_can_be_created_for_server_and_tcpstream() { type _Test = StreamOwned; } } rustls-v-0.21.10/rustls/src/suites.rs000066400000000000000000000245241453461710000174670ustar00rootroot00000000000000use std::fmt; use crate::enums::{CipherSuite, ProtocolVersion, SignatureAlgorithm, SignatureScheme}; #[cfg(feature = "tls12")] use crate::tls12::Tls12CipherSuite; #[cfg(feature = "tls12")] use crate::tls12::{ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, // TLS1.2 suites 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, }; use crate::tls13::Tls13CipherSuite; use crate::tls13::{ TLS13_AES_128_GCM_SHA256, TLS13_AES_256_GCM_SHA384, TLS13_CHACHA20_POLY1305_SHA256, }; #[cfg(feature = "tls12")] use crate::versions::TLS12; use crate::versions::{SupportedProtocolVersion, TLS13}; /// Bulk symmetric encryption scheme used by a cipher suite. #[allow(non_camel_case_types)] #[derive(Debug, Eq, PartialEq)] pub enum BulkAlgorithm { /// AES with 128-bit keys in Galois counter mode. Aes128Gcm, /// AES with 256-bit keys in Galois counter mode. Aes256Gcm, /// Chacha20 for confidentiality with poly1305 for authenticity. Chacha20Poly1305, } /// Common state for cipher suites (both for TLS 1.2 and TLS 1.3) #[derive(Debug)] pub struct CipherSuiteCommon { /// The TLS enumeration naming this cipher suite. pub suite: CipherSuite, /// How to do bulk encryption. pub bulk: BulkAlgorithm, pub(crate) aead_algorithm: &'static ring::aead::Algorithm, } /// A cipher suite supported by rustls. /// /// All possible instances of this type are provided by the library in /// the [`ALL_CIPHER_SUITES`] array. #[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 fmt::Debug for SupportedCipherSuite { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.suite().fmt(f) } } impl SupportedCipherSuite { /// Which hash function to use with this suite. pub fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { match self { #[cfg(feature = "tls12")] Self::Tls12(inner) => inner.hash_algorithm(), Self::Tls13(inner) => inner.hash_algorithm(), } } /// The cipher suite's identifier pub fn suite(&self) -> CipherSuite { self.common().suite } pub(crate) fn common(&self) -> &CipherSuiteCommon { match self { #[cfg(feature = "tls12")] Self::Tls12(inner) => &inner.common, Self::Tls13(inner) => &inner.common, } } #[cfg(any(test, feature = "quic"))] pub(crate) 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.sign() == _sig_alg), } } } /// A list of all the cipher suites supported by rustls. pub static ALL_CIPHER_SUITES: &[SupportedCipherSuite] = &[ // TLS1.3 suites TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256, TLS13_CHACHA20_POLY1305_SHA256, // TLS1.2 suites #[cfg(feature = "tls12")] TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, #[cfg(feature = "tls12")] TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, #[cfg(feature = "tls12")] TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, #[cfg(feature = "tls12")] TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, #[cfg(feature = "tls12")] TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, #[cfg(feature = "tls12")] TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ]; /// 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; // These both O(N^2)! pub(crate) fn choose_ciphersuite_preferring_client( client_suites: &[CipherSuite], server_suites: &[SupportedCipherSuite], ) -> Option { for client_suite in client_suites { if let Some(selected) = server_suites .iter() .find(|x| *client_suite == x.suite()) { return Some(*selected); } } None } pub(crate) fn choose_ciphersuite_preferring_server( client_suites: &[CipherSuite], server_suites: &[SupportedCipherSuite], ) -> Option { if let Some(selected) = server_suites .iter() .find(|x| client_suites.contains(&x.suite())) { return Some(*selected); } None } /// Return a list of the ciphersuites in `all` with the suites /// incompatible with `SignatureAlgorithm` `sigalg` removed. pub(crate) fn reduce_given_sigalg( all: &[SupportedCipherSuite], sigalg: SignatureAlgorithm, ) -> Vec { all.iter() .filter(|&&suite| suite.usable_for_signature_algorithm(sigalg)) .copied() .collect() } /// Return a list of the ciphersuites in `all` with the suites /// incompatible with the chosen `version` removed. pub(crate) fn reduce_given_version( all: &[SupportedCipherSuite], version: ProtocolVersion, ) -> Vec { all.iter() .filter(|&&suite| suite.version().version == version) .copied() .collect() } /// 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.sign(); 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. #[cfg(feature = "secret_extraction")] #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] 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 #[cfg(feature = "secret_extraction")] 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]. #[cfg(feature = "secret_extraction")] #[cfg_attr(docsrs, doc(cfg(feature = "secret_extraction")))] #[non_exhaustive] pub enum ConnectionTrafficSecrets { /// Secrets for the AES_128_GCM AEAD algorithm Aes128Gcm { /// key (16 bytes) key: [u8; 16], /// salt (4 bytes) salt: [u8; 4], /// initialization vector (8 bytes, chopped from key block) iv: [u8; 8], }, /// Secrets for the AES_256_GCM AEAD algorithm Aes256Gcm { /// key (32 bytes) key: [u8; 32], /// salt (4 bytes) salt: [u8; 4], /// initialization vector (8 bytes, chopped from key block) iv: [u8; 8], }, /// Secrets for the CHACHA20_POLY1305 AEAD algorithm Chacha20Poly1305 { /// key (32 bytes) key: [u8; 32], /// initialization vector (12 bytes) iv: [u8; 12], }, } #[cfg(test)] mod test { use super::*; use crate::enums::CipherSuite; #[test] fn test_client_pref() { let client = vec![ CipherSuite::TLS13_AES_128_GCM_SHA256, CipherSuite::TLS13_AES_256_GCM_SHA384, ]; let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256]; let chosen = choose_ciphersuite_preferring_client(&client, &server); assert!(chosen.is_some()); assert_eq!(chosen.unwrap(), TLS13_AES_128_GCM_SHA256); } #[test] fn test_server_pref() { let client = vec![ CipherSuite::TLS13_AES_128_GCM_SHA256, CipherSuite::TLS13_AES_256_GCM_SHA384, ]; let server = vec![TLS13_AES_256_GCM_SHA384, TLS13_AES_128_GCM_SHA256]; let chosen = choose_ciphersuite_preferring_server(&client, &server); assert!(chosen.is_some()); assert_eq!(chosen.unwrap(), TLS13_AES_256_GCM_SHA384); } #[test] fn test_pref_fails() { assert!(choose_ciphersuite_preferring_client( &[CipherSuite::TLS_NULL_WITH_NULL_NULL], ALL_CIPHER_SUITES ) .is_none()); assert!(choose_ciphersuite_preferring_server( &[CipherSuite::TLS_NULL_WITH_NULL_NULL], ALL_CIPHER_SUITES ) .is_none()); } #[test] fn test_scs_is_debug() { println!("{:?}", ALL_CIPHER_SUITES); } #[test] fn test_can_resume_to() { assert!(TLS13_AES_128_GCM_SHA256 .tls13() .unwrap() .can_resume_from(crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL) .is_some()); assert!(TLS13_AES_256_GCM_SHA384 .tls13() .unwrap() .can_resume_from(crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL) .is_none()); } } rustls-v-0.21.10/rustls/src/testdata/000077500000000000000000000000001453461710000174075ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/testdata/cert-arstechnica.0.der000066400000000000000000000027551453461710000234710ustar00rootroot0000000000000000Ѡ E1q%0  *H  0F1 0 UUS10 U Amazon10U  Server CA 1B10 UAmazon0 211129000000Z 221227235959Z010U *.arstechnica.com0"0  *H 0 9 Bw#o+'><~[S4\_! v_C_)jn,#k&JUjWsއ@q5f@z \%8Fr\ T{Ţ(m[U@""B%z$=kiB)/ VVgF}=x5꦳ Ѷ2=rRBom^Y/14-{EEKD|&ƁJǧS6#*a2rustls-v-0.21.10/rustls/src/testdata/cert-arstechnica.1.der000066400000000000000000000021151453461710000234600ustar00rootroot000000000000000I01Ww޲S2[V 0  *H  091 0 UUS10 U Amazon10UAmazon Root CA 10 151022000000Z 251019000000Z0F1 0 UUS10 U Amazon10U  Server CA 1B10 UAmazon0"0  *H 0 Ngμj7Z:0(H)nSգ9wpkqm˦*N֧ < 9ĵXV%>Rz)nP_1Jb>G' 5_Mk7P>DZf~jU5uNXU}Sk kB+ SgЈ:s_r~0c*z-2><PC* hӈJeJ.LU;070U00U0UYfR{<'t[=0U#0̅4 .YDzN 0{+o0m0/+0#http://ocsp.rootca1.amazontrust.com0:+0.http://crt.rootca1.amazontrust.com/rootca1.cer0?U8060420.http://crl.rootca1.amazontrust.com/rootca1.crl0U  0 0g 0  *H  5yϣBcsS9R5ѭ/oNr 0aͥ'Ev>JECmn1/1 ma7{XQ(Ov^f.) `HSe5kQ@UW_">^óAZR6O-h5r}Wy7{`-w I'8H vRȼAxpmJx-^L`Gx-R9,/3ڔrustls-v-0.21.10/rustls/src/testdata/cert-arstechnica.2.der000066400000000000000000000022261453461710000234640ustar00rootroot0000000000000000zJ*'®+0  *H  01 0 UUS10UArizona10U Scottsdale1%0#U Starfield Technologies, Inc.1;09U2Starfield Services Root Certificate Authority - G20 150525120000Z 371231010000Z091 0 UUS10 U Amazon10UAmazon Root CA 10"0  *H 0 xqxqGPt}n׈vhX!`t/-ӠCzN6H6L#>7Ih׹v8a6JVEtڜ59/ PlzЀGP8ܢ9XթHg0x^oQ0fEfTÑH0-}-tp5׈$Yns2F(Cʴ$-Kq\^i8P8o-bTwg#?@  ĀL>;$&lȪ 10-0U00U0U̅4 .YDzN 0U#0_ߪ0+8mJ0x+l0j0.+0"http://ocsp.rootg2.amazontrust.com08+0,http://crt.rootg2.amazontrust.com/rootg2.cer0=U604020.,http://crl.rootg2.amazontrust.com/rootg2.crl0U  00U 0  *H  b7B\>, lEzX >%ChlW .j].JmX91_|sːj'فF~r R>cwi9ҫEMQ:]]7dL~0U$B6]a$ t{E)P95%jG#1/\bQ*4!rustls-v-0.21.10/rustls/src/testdata/cert-arstechnica.3.der000066400000000000000000000021711453461710000234640ustar00rootroot000000000000000u0] JL40  *H  0h1 0 UUS1%0#U Starfield Technologies, Inc.1200U )Starfield Class 2 Certification Authority0 090902000000Z 340628173916Z01 0 UUS10UArizona10U Scottsdale1%0#U Starfield Technologies, Inc.1;09U2Starfield Services Root Certificate Authority - G20"0  *H 0  :*N_S?ϟ m):}GU6S]4(kUg?3X/`ݧuOm~@,v3w Sd'iM^uXD-/M0  *H  0O1 0 UUS10U  DigiCert Inc1)0'U DigiCert TLS RSA SHA256 2020 CA10 211205000000Z 221126235959Z0l1 0 UUS10U Pennsylvania10 UPaoli10U Duck Duck Go, Inc.10U *.duckduckgo.com0"0  *H 0 mŵXXH#^{p'm>9 eQffXUSɺAomT *|.ԫ8K=! NkyF0K?Zu. w3"qUYh,UA+\U|줲U.B>j>Y@묰J6{#»ϰT$J"9`0į~e߽xy䶤۫Є( S2 :pg0!pIr,0~0U#0kꨪyŕv0Ut?"aRe'vF0+U$0"*.duckduckgo.comduckduckgo.com0U0U%0++0U00@><:http://crl3.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl0@><:http://crl4.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl0>U 70503g 0)0'+http://www.digicert.com/CPS0+s0q0$+0http://ocsp.digicert.com0I+0=http://cacerts.digicert.com/DigiCertTLSRSASHA2562020CA1-1.crt0 U00} +ymigv)y99!VscwW}` M]&\%]DŽ} G0E ktzߓ0a cRJo*O!a8g8^xe H6R0vAʱ"FJơ: B^N1Khb} G0E!߬I1^癩A؜_[':s;N]u "oPS8p>x%r兹s]: &,#Euߥ^hOl_N>Z͢j^; D\*s} F0D!5I}U¥%d #b1C FQv<F*9+ncKpTD'm0  *H  ^cjyɈn9O=D2o m ?}N/ut]OQIso7TN6rmR2Lva2D畫ƈ{+I`͝^ELٔ5FaE_v.UþRw2sW0i)8<2@7c4XPr 1Lke{c>!M&zCJ %x4[rustls-v-0.21.10/rustls/src/testdata/cert-duckduckgo.1.der000066400000000000000000000023021453461710000233150ustar00rootroot0000000000000000XCF/T"~0  *H  0a1 0 UUS10U  DigiCert Inc10U www.digicert.com1 0UDigiCert Global Root CA0 210414000000Z 310413235959Z0O1 0 UUS10U  DigiCert Inc1)0'U DigiCert TLS RSA SHA256 2020 CA10"0  *H 0 KeGpOXf1TJfF, d.ܹ ОzVXQ,4 .ҒVy_%{RAf`OWI7gKgL"QWQt&}b.#%So4XXI"{|Qհ76KbIg>^DqB}X2''+tԨ֗dSVxI)IO\Wmky+' =@!00~0U00Ukꨪyŕv0U#0P5VLf×=U0U0U%0++0v+j0h0$+0http://ocsp.digicert.com0@+04http://cacerts.digicert.com/DigiCertGlobalRootCA.crt0BU;0907531http://crl3.digicert.com/DigiCertGlobalRootCA.crl0=U 6040  `Hl0g 0g 0g 0g 0  *H  2^ nZ քp] +u@ 1xpKXk~ XYԐlИmq[m Z {C*ޞA&_ݮot Og]]|{z6oؓqφs0{*YB;R}[rgqWGfŸJe4^*< QLRk+ ~6C*cu? <0L6s>rustls-v-0.21.10/rustls/src/testdata/cert-github.0.der000066400000000000000000000024121453461710000224550ustar00rootroot0000000000000000w іaU 70503g 0)0'+http://www.digicert.com/CPS0+00$+0http://ocsp.digicert.com0Z+0Nhttp://cacerts.digicert.com/DigiCertHighAssuranceTLSHybridECCSHA2562020CA1.crt0 U00 +yv)y99!VscwW}` M]&\%]DŽxjG0E!D4E2Mc-_cF 9 HT'2wh4 rDYw"EEYU$V?/m#&cK]ƃ\nxj9H0F!J A\(ޅlXޖj/i!h˫ԨRg0; Ц0 *H=G0D +o*E57=κghkIFV ]-Yϲ=us~2ܯD>rustls-v-0.21.10/rustls/src/testdata/cert-github.1.der000066400000000000000000000020371453461710000224610ustar00rootroot0000000000000000g[c֨SN0  *H  0l1 0 UUS10U  DigiCert Inc10U www.digicert.com1+0)U"DigiCert High Assurance EV Root CA0 201217000000Z 301216235959Z0g1 0 UUS10U DigiCert, Inc.1?0=U6DigiCert High Assurance TLS Hybrid ECC SHA256 2020 CA10Y0*H=*H=Bgo<띾жlן叐~SȮ>rH}C# kǩK;C ?NG00U00UPa5* B)K0U#0>iGԘ&cd+0U0U%0++0+s0q0$+0http://ocsp.digicert.com0I+0=http://cacerts.digicert.com/DigiCertHighAssuranceEVRootCA.crt0KUD0B0@><:http://crl3.digicert.com/DigiCertHighAssuranceEVRootCA.crl00U )0'0g 0g 0g 0g 0  *H  saoL "Кd.myƙ18h#aJgO:*<5fgj%UE꠺~- |L~ХEt}'FvT9CG5hy1Meh<;<^Y/~S j*쿌^Qaѳ,zvw S<>JdiP`N*C-@z0TX8.h6=rustls-v-0.21.10/rustls/src/testdata/cert-google.0.der000066400000000000000000000022141453461710000224470ustar00rootroot0000000000000000p Cj &D0  *H  0F1 0 UUS1"0 U Google Trust Services LLC10U GTS CA 1C30 211129033634Z 220221033633Z010Uwww.google.com0Y0*H=*H=BS<3>)SWD-ihyT Ւ4W]yǎĮK G,ߪg0c0U0U% 0 +0 U00UVDڙn)/50U#0t=Fq5'0j+^0\0'+0http://ocsp.pki.goog/gts1c301+0%http://pki.goog/repo/certs/gts1c3.der0U0www.google.com0!U 00g 0  +y0<U50301/-+http://crls.pki.goog/gts1c3/QqFxbi9M48c.crl0 +yuQyVm7x z'B ԋ}i F0D a1nH~BF*M B,x qi_I 0#tےʿrw)y99!VscwW}` M]&\%]DŽ}iH0F!$1Zz - 1V}r!<<UB˫}z\iNW=f#d;vT}@jѥpx~-O= \n+n<,Oř ^{#)nhSXSә2>aȠ}qpsu yL9=xk#&KLm_f0'GtXoLx>rustls-v-0.21.10/rustls/src/testdata/cert-google.1.der000066400000000000000000000026321453461710000224540ustar00rootroot0000000000000000~ SYk4Pf0  *H  0G1 0 UUS1"0 U Google Trust Services LLC10U GTS Root R10 200813000042Z 270930000042Z0F1 0 UUS1"0 U Google Trust Services LLC10U GTS CA 1C30"0  *H 0 b77Ble%kmZ#| B^V$z3itWLfhw7US9M4_%w7;<ռôC.GDcشAA0HE!B+eV4& }.H|7M?u.yW\Wn%,*c0h+\0Z0&+0http://ocsp.pki.goog/gtsr100+0$http://pki.goog/repo/certs/gtsr1.der04U-0+0)'%#http://crl.pki.goog/gtsr1/gtsr1.crl0WU P0N08 +y0*0(+https://pki.goog/repository/0g 0g 0  *H  } \ zFI_FAטMe4?OlISA!D[*PMS6BTwSd8' X|9-[ S$ y&aSRBf+?ずq5($-H=YQtƝ|Ʊ[4ԁ"qs$7S?\6;):b;lcـYqc'Ls*ޏl23ІQq4]QXYqM(mFkw# DӢu#4 ^RF!pQU+3wKBws7?*fs22l2#[}Mep+=m2c]q^*"e:eԅ[YG-$:Ȁ&7oQűQrustls-v-0.21.10/rustls/src/testdata/cert-google.2.der000066400000000000000000000025461453461710000224610ustar00rootroot000000000000000b0Jw l6!X 0  *H  0W1 0 UBE10U GlobalSign nv-sa10U Root CA10UGlobalSign Root CA0 200619000042Z 280128000042Z0G1 0 UUS1"0 U Google Trust Services LLC10U GTS Root R10"0  *H 0 w;ܿ>@<}2qۼj.K+΄ŗ^R#'ˤcי~ ^hZG M3NlK ߝd)%#=.` HMzY֯1.ml~&E=y(&ߑ"2cQr])h3:f&Wex'^I! lH<@~ ZV<їK9K?Un$qA=:Ȯz78040U0U00U+&q+H'/Rf,q>0U#0`{fE ʉP/}4K0`+T0R0%+0http://ocsp.pki.goog/gsr10)+0http://pki.goog/gsr1/gsr1.crt02U+0)0'%#!http://crl.pki.goog/gsr1/gsr1.crl0;U 4020g 0g 0  +y0  +y0  *H  4(дv1z!R>tA=5\_| ыW&o[Fh7okz7%QhIZ#+Iju޲ɗXHW5ooϗ*Ni -h+s"7 fIUg2&p=gm=|42njoK;7D~lF!fUl) f[wIH(3rS5b$9 ~*AR‚?rustls-v-0.21.10/rustls/src/testdata/cert-hn.0.der000066400000000000000000000033141453461710000216020ustar00rootroot0000000000000000WE|1^0  *H  0O1 0 UUS10U  DigiCert Inc1)0'U DigiCert TLS RSA SHA256 2020 CA10 210907000000Z 221008235959Z0v1 0 UUS10U California10U San Francisco10U Y Combinator, Inc.10Unews.ycombinator.com0"0  *H 0 ȵԵ< 75%7ȯ2/SidN6SnRPkH4!_k"ts-^5C~YF""Vzv(PU;@ p`!1EDT 9Z"T7G'|Hx+~,Yl| C/+]۶PQh}}Fٛ&痎~8&zSsJ)ypVŌ)&I)s`΀jCy%:Bu>w0s0U#0kꨪyŕv0U-3 7lsA#Wqah0U0news.ycombinator.com0U0U%0++0U00@><:http://crl3.digicert.com/DigiCertTLSRSASHA2562020CA1-3.crl0@><:http://crl4.digicert.com/DigiCertTLSRSASHA2562020CA1-3.crl0>U 70503g 0)0'+http://www.digicert.com/CPS0+s0q0$+0http://ocsp.digicert.com0I+0=http://cacerts.digicert.com/DigiCertTLSRSASHA2562020CA1-1.crt0 U00~ +ynjhv)y99!VscwW}` M]&\%]DŽ{<"G0E!*o;P/u|CBRŴkEJN9ZJ -$E$G1w@a"R[ꍓwW}(vQyVm7x z'B ԋ{<#3G0E! %VH^4.yuԆ @SYRVߓЬ$F#`vAʱ"FJơ: B^N1Khb{<#,G0E!Ϫ<%s",4Nf(/eJa 4jZo:,|/4WbGwA}^0  *H  @f\b=Ni=ϪܸaglRwٵY-Tヲx Gw߂oVx<% -/*iQ&_ۚ&[MI*JYuA.k@5C4'l|fv:pIz`fG˄tCs`ۖ@-75nMȌwI6AV$M|}>O~35SK/B&A6u&^G$Prustls-v-0.21.10/rustls/src/testdata/cert-hn.1.der000066400000000000000000000023021453461710000215770ustar00rootroot0000000000000000XCF/T"~0  *H  0a1 0 UUS10U  DigiCert Inc10U www.digicert.com1 0UDigiCert Global Root CA0 210414000000Z 310413235959Z0O1 0 UUS10U  DigiCert Inc1)0'U DigiCert TLS RSA SHA256 2020 CA10"0  *H 0 KeGpOXf1TJfF, d.ܹ ОzVXQ,4 .ҒVy_%{RAf`OWI7gKgL"QWQt&}b.#%So4XXI"{|Qհ76KbIg>^DqB}X2''+tԨ֗dSVxI)IO\Wmky+' =@!00~0U00Ukꨪyŕv0U#0P5VLf×=U0U0U%0++0v+j0h0$+0http://ocsp.digicert.com0@+04http://cacerts.digicert.com/DigiCertGlobalRootCA.crt0BU;0907531http://crl3.digicert.com/DigiCertGlobalRootCA.crl0=U 6040  `Hl0g 0g 0g 0g 0  *H  2^ nZ քp] +u@ 1xpKXk~ XYԐlИmq[m Z {C*ޞA&_ݮot Og]]|{z6oؓqφs0{*YB;R}[rgqWGfŸJe4^*< QLRk+ ~6C*cu? <0L6s>rustls-v-0.21.10/rustls/src/testdata/cert-reddit.0.der000066400000000000000000000033021453461710000224450ustar00rootroot00000000000000009Cw.0  *H  0O1 0 UUS10U  DigiCert Inc1)0'U DigiCert TLS RSA SHA256 2020 CA10 211005000000Z 220402235959Z0g1 0 UUS10U CALIFORNIA10U SAN FRANCISCO10U  Reddit Inc.10U *.reddit.com0"0  *H 0 T)-ErL+=il2hpUZBܐ~Sl8'z^ Ze :=xr}]a>E"[tZeRQ SׯE"M)=xjDHHCp(n9$l倢twU uEVT $u=G.9Xe C,M6mxܶXkx(^Y_l/AEU%7^!s{ 5r|0x0U#0kꨪyŕv0UqPR#eC1Vi&0#U0 reddit.com *.reddit.com0U0U%0++0U00@><:http://crl3.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl0@><:http://crl4.digicert.com/DigiCertTLSRSASHA2562020CA1-4.crl0>U 70503g 0)0'+http://www.digicert.com/CPS0+s0q0$+0http://ocsp.digicert.com0I+0=http://cacerts.digicert.com/DigiCertTLSRSASHA2562020CA1-1.crt0 U00 +yokiw)y99!VscwW}` M]&\%]DŽ|P'H0F!j9҈JsG;3mBJ7X\#vK!gplr3Tމ t=^K^+wQyVm7x z'B ԋ|P H0F!;y^DqB}X2''+tԨ֗dSVxI)IO\Wmky+' =@!00~0U00Ukꨪyŕv0U#0P5VLf×=U0U0U%0++0v+j0h0$+0http://ocsp.digicert.com0@+04http://cacerts.digicert.com/DigiCertGlobalRootCA.crt0BU;0907531http://crl3.digicert.com/DigiCertGlobalRootCA.crl0=U 6040  `Hl0g 0g 0g 0g 0  *H  2^ nZ քp] +u@ 1xpKXk~ XYԐlИmq[m Z {C*ޞA&_ݮot Og]]|{z6oؓqφs0{*YB;R}[rgqWGfŸJe4^*< QLRk+ ~6C*cu? <0L6s>rustls-v-0.21.10/rustls/src/testdata/cert-rustlang.0.der000066400000000000000000000030041453461710000230300ustar00rootroot0000000000000000 j^+uR d0  *H  0F1 0 UUS10 U Amazon10U  Server CA 1B10 UAmazon0 210912000000Z 221011235959Z010Uwww.rust-lang.org0"0  *H 0 |a4m>^mk]An/d! Ďyˠ]Qe]36kK)f(+Ĉw۲0Y bFtE4421ix_I. l)Dt7~*!yXuF8vkzJGmn^p.aPӣbC HtuL(^SU+kHwO>2c~VVxk.@F mIm GgAp 00U#0YfR{<'t[=0U=&CELW-!Ke_4|QYoZyrD7β g;\vQyVm7x z'B ԋ{@;'G0E !)l ]*}-m89KV,n!!IqC4/9q bJ %s}vvAʱ"FJơ: B^N1Khb{@;G0E #T>y{Td^Mmޥ4}"!ڀ$Xe0fGW|1 5f0  *H  G nʠ XeR &uտ4w2R뙆7?t}8ZM@ޢN~tkI=j-7G^&L~qX`czmW$8'`2fl+Qݵ{Qw͚Ռ)96sGߘoTKX5Ϙt>V[i"!D|j7n=;b,SpQ\=jyqQJ.Rz)nP_1Jb>G' 5_Mk7P>DZf~jU5uNXU}Sk kB+ SgЈ:s_r~0c*z-2><PC* hӈJeJ.LU;070U00U0UYfR{<'t[=0U#0̅4 .YDzN 0{+o0m0/+0#http://ocsp.rootca1.amazontrust.com0:+0.http://crt.rootca1.amazontrust.com/rootca1.cer0?U8060420.http://crl.rootca1.amazontrust.com/rootca1.crl0U  0 0g 0  *H  5yϣBcsS9R5ѭ/oNr 0aͥ'Ev>JECmn1/1 ma7{XQ(Ov^f.) `HSe5kQ@UW_">^óAZR6O-h5r}Wy7{`-w I'8H vRȼAxpmJx-^L`Gx-R9,/3ڔrustls-v-0.21.10/rustls/src/testdata/cert-rustlang.2.der000066400000000000000000000022261453461710000230370ustar00rootroot0000000000000000zJ*'®+0  *H  01 0 UUS10UArizona10U Scottsdale1%0#U Starfield Technologies, Inc.1;09U2Starfield Services Root Certificate Authority - G20 150525120000Z 371231010000Z091 0 UUS10 U Amazon10UAmazon Root CA 10"0  *H 0 xqxqGPt}n׈vhX!`t/-ӠCzN6H6L#>7Ih׹v8a6JVEtڜ59/ PlzЀGP8ܢ9XթHg0x^oQ0fEfTÑH0-}-tp5׈$Yns2F(Cʴ$-Kq\^i8P8o-bTwg#?@  ĀL>;$&lȪ 10-0U00U0U̅4 .YDzN 0U#0_ߪ0+8mJ0x+l0j0.+0"http://ocsp.rootg2.amazontrust.com08+0,http://crt.rootg2.amazontrust.com/rootg2.cer0=U604020.,http://crl.rootg2.amazontrust.com/rootg2.crl0U  00U 0  *H  b7B\>, lEzX >%ChlW .j].JmX91_|sːj'فF~r R>cwi9ҫEMQ:]]7dL~0U$B6]a$ t{E)P95%jG#1/\bQ*4!rustls-v-0.21.10/rustls/src/testdata/cert-rustlang.3.der000066400000000000000000000021711453461710000230370ustar00rootroot000000000000000u0] JL40  *H  0h1 0 UUS1%0#U Starfield Technologies, Inc.1200U )Starfield Class 2 Certification Authority0 090902000000Z 340628173916Z01 0 UUS10UArizona10U Scottsdale1%0#U Starfield Technologies, Inc.1;09U2Starfield Services Root Certificate Authority - G20"0  *H 0  :*N_S?ϟ m):}GU6S]4(kUg?3X/`ݧuOm~@,v3w Sd'iM^uXD-ꦫX݌]*>=5O8 Rs0o0U#07ugE$0UϝP6U 08U10/sni.cloudflaressl.com *.servo.org servo.org0U0U%0++0{Ut0r07531http://crl3.digicert.com/CloudflareIncECCCA-3.crl07531http://crl4.digicert.com/CloudflareIncECCCA-3.crl0>U 70503g 0)0'+http://www.digicert.com/CPS0v+j0h0$+0http://ocsp.digicert.com0@+04http://cacerts.digicert.com/CloudflareIncECCCA-3.crt0 U00 +yokiwFUu 0i},AtIpmGz>HH0F!E>~s\ !L F_>R19<!;fZhJR"iGnŰnTv"EEYU$V?/m#&cK]ƃ\nz>HG0E!*UI-X(b nrΧ |Ya~>M2C#_vAʱ"FJơ: B^N1Khbz>HG0E!?V&Mooli [RO/cǁKe SXeqR{('3 zI)M@<(f0 *H=I0F!ZP@zt`d@ՊNQ<4h!gԀ>"6ay2hGrustls-v-0.21.10/rustls/src/testdata/cert-servo.1.der000066400000000000000000000017211453461710000223340ustar00rootroot0000000000000000 7d^_"N <0  *H  0Z1 0 UIE10U  Baltimore10U  CyberTrust1"0 UBaltimore CyberTrust Root0 200127124808Z 241231235959Z0J1 0 UUS10U Cloudflare, Inc.1 0UCloudflare Inc ECC CA-30Y0*H=*H=BMf F*P/4}-8_MaFs$OlQq/jL wrbףh0d0U7ugE$0U#0Y0GX̬T6{:M0U0U%0++0U004+(0&0$+0http://ocsp.digicert.com0:U3010/-+)http://crl3.digicert.com/Omniroot2025.crl0mU f0d07 `Hl0*0(+https://www.digicert.com/CPS0  `Hl0g 0g 0g 0  *H  $*օ9M^kWW1WeD8ZwBᒤE'G,hVST@ 8HlP,I[dH0.I" ^ Vl咓z7I+t9WX`O̎F{41>MG:]M n$2%]xQ=5#/eoC1gY'ku $$)#ør?$DSzaeLHucpERӕE1~  >ݪ<^tҬrustls-v-0.21.10/rustls/src/testdata/cert-stackoverflow.0.der000066400000000000000000000033711453461710000240710ustar00rootroot0000000000000000ݠӥ hX0  *H  021 0 UUS10U  Let's Encrypt1 0 UR30 211205141552Z 220305141551Z010U *.stackexchange.com0"0  *H 0 weNɱ_ 2I>=^r!g2R޲Ҽ^.4E>nӚp$q%*(Iξ5$TDEYtִ݆o ("=.ySLRKh3qJk1ʮ,Ң\rSDv㦯>n)пz2u [IXA(ιSm;Io<TM&Hӏ#{!gy3tW4F>s^H@ >ȷQa3{00U0U%0++0 U00U7Dk 8Z=S\0U#0.XVˮP @0U+I0G0!+0http://r3.o.lencr.org0"+0http://r3.i.lencr.org/0U0ׂ*.askubuntu.com*.blogoverflow.com*.mathoverflow.net*.meta.stackexchange.com*.meta.stackoverflow.com*.serverfault.com *.sstatic.net*.stackexchange.com*.stackoverflow.com*.stackoverflow.email*.superuser.com askubuntu.comblogoverflow.commathoverflow.netopenid.stackauth.comserverfault.com sstatic.net stackapps.com stackauth.comstackexchange.comstackoverflow.blogstackoverflow.comstackoverflow.emailstacksnippets.net superuser.com0LU E0C0g 07 +0(0&+http://cps.letsencrypt.org0 +ywߥ^hOl_N>Z͢j^; D\*s}*jLH0F!”"Vqg#nMp"f!S6ڼ\TD>F&j_3\ۃ9xv)y99!VscwW}` M]&\%]DŽ}*jDG0E!҂xwh5E@7iu~.5H !^#sM-,* ^;ewߓ0  *H  ~ŌIf$׾]k_ϤXC/ڦ=e4 Dlrnn_ ~y8b2h틽*I\:ԗ[.fI7\ J;FF|Q*\Q"lA׮RCR~;6LOm]s$[˛29g6E{f98E.K#~٘v';Mo~~s$;5OTHvTQXeD}ĽQۄ?1#$ rustls-v-0.21.10/rustls/src/testdata/cert-stackoverflow.1.der000066400000000000000000000024321453461710000240670ustar00rootroot0000000000000000+J S.%_Z0  *H  0O1 0 UUS1)0'U  Internet Security Research Group10U ISRG Root X10 200904000000Z 250915160000Z021 0 UUS10U  Let's Encrypt1 0 UR30"0  *H 0 (UzB]&+LkuȣGU5W9DgxcuM=3erT- _̷pn;^ 碵<δ9|%Gen?FΔ+T'K/qJȸ#{-W>3 G!x '*ț\dyOmD ^.D)Y c!&We " C~7Z0n+*!N^åj.;3K䯄 ?UC6h6j@4c959unvȓKl ٽhe=wSy 1u*CUr)]NȮF0_y^pᆓùaq%*%PRhֵ}Їl!1ȉ=L8+= ~YX[H\O)U#|/ GF?鰷(Mh2g^i/ RCo2WeM28S]~]f)䕵͵VBN%8DPmUIdNʗ[sGrustls-v-0.21.10/rustls/src/testdata/cert-stackoverflow.2.der000066400000000000000000000025441453461710000240740ustar00rootroot000000000000000`0H@w!7BvY>&$ZL@F:Qn;}rxY>Qx />{JKsP|Ctt0[q600\H;}`)̺A¶|;FH*vvj=8d+ (B"']ypNً:'Qnd3COF0B0U00U0K+?0=0;+0/http://apps.identrust.com/roots/dstrootcax3.p7c0U#0ħ{,qKu`0TU M0K0g 0? +000.+"http://cps.root-x1.letsencrypt.org0<U50301/-+http://crl.identrust.com/DSTROOTCAX3CRL.crl0UyY{sXn0  *H   slnRЮ݌Z/㏿ PlBoODubnx'9\nVpSТ+Ԗ 53a6qE#(֡gڠC,i][X"MUpgmWF9AϊXXmW6#\I5.N;l)# `EL;DXEE]foB ޝ8}I+kO 8w.9rustls-v-0.21.10/rustls/src/testdata/cert-twitter.0.der000066400000000000000000000031061453461710000226760ustar00rootroot000000000000000B0*Q_Ae2Gv0  *H  0O1 0 UUS10U  DigiCert Inc1)0'U DigiCert TLS RSA SHA256 2020 CA10 210224000000Z 220222235959Z0h1 0 UUS10U California10U San Francisco10U  Twitter, Inc.10U twitter.com0"0  *H 0 /qTYG'i>&Kayc< =Ac´QS&A͘ vF5xԂdd31{ۆa.+|#4ɲ3"!/*AU; K@'ʆI_ģn3-{^#al}Ԓa>j~jQF:JL]Jg/:(p.ppmt"x~iɨ[A<{Ÿ-"@!JKO_# 0a79/00U#0kꨪyŕv0U[IhH0'U 0 twitter.comwww.twitter.com0U0U%0++0U00><:8http://crl3.digicert.com/DigiCertTLSRSASHA2562020CA1.crl0><:8http://crl4.digicert.com/DigiCertTLSRSASHA2562020CA1.crl0>U 70503g 0)0'+http://www.digicert.com/CPS0}+q0o0$+0http://ocsp.digicert.com0G+0;http://cacerts.digicert.com/DigiCertTLSRSASHA2562020CA1.crt0 U00 +yvFUu 0i},AtIpmGwcG0E! 1u01.J+^ p6(gg?Gj)z vb*e #֔wM;T)FL"iRG h30  *H  u D,ɮ _p3MQ\, c}Dp(Z>Ĝ/-z7) eژ/gȔw47J. -XCbOjxLTkivu/ؙ̦ wdWZ*f.Jwi}v;ē/A+|]BPxGx.)i6"b [Bn ;.㽮QZC4õ:G۟Yc}rustls-v-0.21.10/rustls/src/testdata/cert-twitter.1.der000066400000000000000000000023561453461710000227050ustar00rootroot0000000000000000Ҡ 5\)+}e0  *H  0a1 0 UUS10U  DigiCert Inc10U www.digicert.com1 0UDigiCert Global Root CA0 200924000000Z 300923235959Z0O1 0 UUS10U  DigiCert Inc1)0'U DigiCert TLS RSA SHA256 2020 CA10"0  *H 0 KeGpOXf1TJfF, d.ܹ ОzVXQ,4 .ҒVy_%{RAf`OWI7gKgL"QWQt&}b.#%So4XXI"{|Qհ76KbIg>^DqB}X2''+tԨ֗dSVxI)IO\Wmky+' =@!000Ukꨪyŕv0U#0P5VLf×=U0U0U%0++0U00v+j0h0$+0http://ocsp.digicert.com0@+04http://cacerts.digicert.com/DigiCertGlobalRootCA.crt0{Ut0r07531http://crl3.digicert.com/DigiCertGlobalRootCA.crl07531http://crl4.digicert.com/DigiCertGlobalRootCA.crl00U )0'0g 0g 0g 0g 0  *H  wz'=ZVɄ[q"GNIߌE,F*c9 J$AȩT\Ze!Va鏘vkr P0)z`Yf:-l-# >;塜ۇJ^H[J Fv\U։omXG0E!xMvi MY}6j*5םqF`o 7Iic׾yon S%̌lkv Xgp <5߸w omXG0E!chU+ؔU>Hݛm^ Z sIzI2)KKכ4N1MyI0U0U%0++0h+\0Z0#+0http://ocsp.entrust.net03+0'http://aia.entrust.net/l1m-chain256.cer03U,0*0(&$"http://crl.entrust.net/level1m.crl0JU C0A06 `Hl 0(0&+http://www.entrust.net/rpa0g 0U#0е*0 !p9Tݼp:0Uj_W~')]rFɕ0 U00  *H  4hY;[aE4H"u!ѭ$MdAbEq;$J%J}=2$jo(}#D1Sc>hV$!z*[z±sv TȊ G7n^ԅdQh_!W?w?=en ! cweR\1ۇ 5vZ0]V%?b{BrqNz=9ޗz~sOfFAt?7Ԡẕ8_lk"F>c1 rustls-v-0.21.10/rustls/src/testdata/cert-wapo.1.der000066400000000000000000000024611453461710000221460ustar00rootroot000000000000000-0 aQf0  *H  01 0 UUS10U  Entrust, Inc.1(0&U See www.entrust.net/legal-terms1907U 0(c) 2009 Entrust, Inc. - for authorized use only1200U)Entrust Root Certification Authority - G20 141215152503Z 301015155503Z01 0 UUS10U  Entrust, Inc.1(0&U See www.entrust.net/legal-terms1907U 0(c) 2014 Entrust, Inc. - for authorized use only1.0,U%Entrust Certification Authority - L1M0"0  *H 0 Ё9#±WU$6 "HR ?3Nz"=VqmRw3^ǪiCj?"39FՔL"gJ|l< k犃auG; '2S5b팽IqCC!*#pu=lFaog)~<_ nDN!XHUH*4|IX:9a3U*.?љb4v1y)xˁiYD O,1k-+0'0U0U%0++0U003+'0%0#+0http://ocsp.entrust.net00U)0'0%#!http://crl.entrust.net/g2ca.crl0;U 40200U 0(0&+http://www.entrust.net/rpa0Uе*0 !p9Tݼp:0U#0jr&z};iQlf0  *H  DŽ")xOowYC/Xަ[.CLBAf ""hh2qR~B ],Dk$f$߉^PuJKt?XSl&|5Qe;lvĹ Յ$*ړKdp|T)ӂTϥ3M4g8vf/ƫ r/5ߌ%W(ق(i#(^ ;AWDnlgb`" rustls-v-0.21.10/rustls/src/testdata/cert-wikipedia.0.der000066400000000000000000000040461453461710000231460ustar00rootroot000000000000000"0}),.St>0 *H=0V1 0 UUS10U  DigiCert Inc100.U'DigiCert TLS Hybrid ECC SHA384 2020 CA10 211019000000Z 221117235959Z0y1 0 UUS10U California10U San Francisco1#0!U Wikimedia Foundation, Inc.10U *.wikipedia.org0Y0*H=*H=BP,NsϠW|nUJg?F#RH;dd#)nr20.0U#0 )9mz3.z0U%\чJ^2QD0U0*.wikipedia.org wikimedia.org mediawiki.org wikibooks.org wikidata.org wikinews.org wikiquote.orgwikisource.orgwikiversity.orgwikivoyage.orgwiktionary.orgwikimediafoundation.orgw.wikiwmfusercontent.org*.m.wikipedia.org*.wikimedia.org*.m.wikimedia.org*.planet.wikimedia.org*.mediawiki.org*.m.mediawiki.org*.wikibooks.org*.m.wikibooks.org*.wikidata.org*.m.wikidata.org*.wikinews.org*.m.wikinews.org*.wikiquote.org*.m.wikiquote.org*.wikisource.org*.m.wikisource.org*.wikiversity.org*.m.wikiversity.org*.wikivoyage.org*.m.wikivoyage.org*.wiktionary.org*.m.wiktionary.org*.wikimediafoundation.org*.wmfusercontent.org wikipedia.org0U0U%0++0U00FDB@http://crl3.digicert.com/DigiCertTLSHybridECCSHA3842020CA1-1.crl0FDB@http://crl4.digicert.com/DigiCertTLSHybridECCSHA3842020CA1-1.crl0>U 70503g 0)0'+http://www.digicert.com/CPS0+y0w0$+0http://ocsp.digicert.com0O+0Chttp://cacerts.digicert.com/DigiCertTLSHybridECCSHA3842020CA1-1.crt0 U00~ +ynjhv)y99!VscwW}` M]&\%]DŽ|^JG0E +Կ]f5:sA%ۀ"!U#,NnsNPdOB!vQyVm7x z'B ԋ|^JG0E!->]Hp[c2&fhdg`. ^yЪP@(4AI(1vAʱ"FJơ: B^N1Khb|^JG0E!> /qRd$֣"Plm \Β5qư%Uy1)v.0 *H=i0f1ͪ ^$DvR~W, ⯴g>j6`0[NP'1 (~ wpo?Y}l!i.iSēœփs9r}rustls-v-0.21.10/rustls/src/testdata/cert-wikipedia.1.der000066400000000000000000000020331453461710000231410ustar00rootroot0000000000000000\wzG5%0  *H  0a1 0 UUS10U  DigiCert Inc10U www.digicert.com1 0UDigiCert Global Root CA0 210414000000Z 310413235959Z0V1 0 UUS10U  DigiCert Inc100.U'DigiCert TLS Hybrid ECC SHA384 2020 CA10v0*H=+"bƚ[٤)릲lUI/'Q˿pzñɨȸt56F#}OE:t0rustls-v-0.21.10/rustls/src/testdata/deframer-empty-applicationdata.bin000066400000000000000000000000051453461710000261500ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/testdata/deframer-invalid-contenttype.bin000066400000000000000000000000071453461710000256610ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/testdata/deframer-invalid-empty.bin000066400000000000000000000000051453461710000244410ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/testdata/deframer-invalid-length.bin000066400000000000000000000000061453461710000245650ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/testdata/deframer-invalid-version.bin000066400000000000000000000000071453461710000247720ustar00rootroot00000000000000#rustls-v-0.21.10/rustls/src/testdata/deframer-test.1.bin000066400000000000000000000005161453461710000230040ustar00rootroot00000000000000IE7y̌~u`0`l0,($ kjih98762.*&=5/+'# g@?>3210EDCB1-)%</A    h google.com   # rustls-v-0.21.10/rustls/src/testdata/deframer-test.2.bin000066400000000000000000000000071453461710000230000ustar00rootroot00000000000000nrustls-v-0.21.10/rustls/src/testdata/eddsakey.der000066400000000000000000000000601453461710000216700ustar00rootroot000000000000000.0+ep" f)='. _lAݘQlrustls-v-0.21.10/rustls/src/testdata/nistp256key.der000066400000000000000000000001711453461710000222050ustar00rootroot000000000000000w ƀk0J)4*ArY7e!ae *H=DB'@@]:vnfG?َPIJ8EՁg# KKtrustls-v-0.21.10/rustls/src/testdata/nistp256key.pkcs8.der000066400000000000000000000002121453461710000232300ustar00rootroot0000000000000000*H=*H=m0k ƀk0J)4*ArY7e!aeDB'@@]:vnfG?َPIJ8EՁg# KKtrustls-v-0.21.10/rustls/src/testdata/nistp384key.der000066400000000000000000000002471453461710000222130ustar00rootroot0000000000000000 h+Q" Rwo4 s{*6ހso!E9+"dbU9J<=a-m̼BVMVztvbԈfQa%D{I認ZS,9z8gk0ryo]U A.Crustls-v-0.21.10/rustls/src/testdata/nistp384key.pkcs8.der000066400000000000000000000002711453461710000232370ustar00rootroot0000000000000000*H=+"00 h+Q" Rwo4 s{*6ހso!E9dbU9J<=a-m̼BVMVztvbԈfQa%D{I認ZS,9z8gk0ryo]U A.Crustls-v-0.21.10/rustls/src/testdata/prf-result.1.bin000066400000000000000000000001441453461710000223420ustar00rootroot00000000000000)r{{& U|Sªԕ2RZk0 5ɤkN"}7VKOfnOyg"Bŧ.ZQ4{frustls-v-0.21.10/rustls/src/testdata/prf-result.2.bin000066400000000000000000000003041453461710000223410ustar00rootroot00000000000000aǘnzLf*F8-xu~m\E q;'7hC%܎">he= @V%]ߦT У#>I>uc"%N3fuVXܜ9uE@@lz@ 9z(PfhBv2Oc?6@ؘrustls-v-0.21.10/rustls/src/testdata/rsa2048key.pkcs1.der000066400000000000000000000022461453461710000227430ustar00rootroot000000000000000ЁNZc)/)vO'hX9Pzt6w|x!5KW nB8Z*,`4z~qA-qG,<{s܍Q]E@@9BU&V!MZ\>'{l kRhE6ʈ]Rxؽj%)//^G{t"7S#?@;9l: 8o6q!K)טd?Z  # bk@SJ5rtiHPk%E.(X,T9TRV"nԑ&Q[4g45>3^M8DF%Ci8D*޹U^xUV-I:p>9eJdcS?D>FXȣL3pQFqR5M۠Fv~]OFx>^ Rf/(TvE53pˆGQzhN_4.9?os ]yCulJ̢Uev;hiXڏ%s%<+O ;o\EDFbCIIa#61qcbhAJw_~0!HFѮt"003 0>dwNbX5HDg s@HD{1L%AajsT[i'TR/Dd nu_RcbFd`H d``V‘U ;l~,՛ L{ d \[ǚ|{FZG6Q$!E̼AJb<1@(vqiBFaW25٣scl\k>&ry6Ej3eE0q#dՉ^ܓE{euG4M7)3isL'%Ha^K$o*(Gk8Yoe3yO,}䮏Xݚ!7E%H wycRT9v'{l kRhE6ʈ]Rxؽj%)//^G{t"7S#?@;9l: 8o6q!K)טd?Z  # bk@SJ5rtiHPk%E.(X,T9TRV"nԑ&Q[4g45>3^M8DF%Ci8D*޹U^xUV-I:p>9eJdcS?D>FXȣL3pQFqR5M۠Fv~]OFx>^ Rf/(TvE53pˆGQzhN_4.9?os ]yCulJ̢Uev;hiXڏ%s%<+O ;o\EDFbCIIa#61qcbhAJw_~0!HFѮt"003 0>dwNbX5HDg s@HD{1L%AajsT[i'TR/Dd nu_RcbFd`H d``V‘U ;l~,՛ L{ d \[ǚ|{FZG6Q$!E̼AJb<1@(vqiBFaW25٣scl\k>&ry6Ej3eE0q#dՉ^ܓE{euG4M7)3isL'%Ha^K$o*(Gk8Yoe3yO,}䮏Xݚ!7E%H wycRT9v Result { Ok(Self( time::SystemTime::now().duration_since(time::UNIX_EPOCH)?, )) } #[inline] pub fn as_secs(&self) -> u64 { self.0.as_secs() } } /// 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, lifetime: u32, } impl AeadTicketer { /// Make a ticketer with recommended configuration and a random key. fn new() -> Result { let mut key = [0u8; 32]; rand::fill_random(&mut key)?; let alg = &aead::CHACHA20_POLY1305; let key = aead::UnboundKey::new(alg, &key).unwrap(); Ok(Self { alg, key: aead::LessSafeKey::new(key), lifetime: 60 * 60 * 12, }) } } 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> { // Random nonce, because a counter is a privacy leak. let mut nonce_buf = [0u8; 12]; rand::fill_random(&mut nonce_buf).ok()?; let nonce = ring::aead::Nonce::assume_unique_for_key(nonce_buf); let aad = ring::aead::Aad::empty(); let mut ciphertext = Vec::with_capacity(nonce_buf.len() + message.len() + self.key.algorithm().tag_len()); ciphertext.extend(nonce_buf); ciphertext.extend(message); self.key .seal_in_place_separate_tag(nonce, aad, &mut ciphertext[nonce_buf.len()..]) .map(|tag| { ciphertext.extend(tag.as_ref()); ciphertext }) .ok() } /// Decrypt `ciphertext` and recover the original message. fn decrypt(&self, ciphertext: &[u8]) -> Option> { // Non-panicking `let (nonce, ciphertext) = ciphertext.split_at(...)`. let nonce = ciphertext.get(..self.alg.nonce_len())?; let ciphertext = ciphertext.get(nonce.len()..)?; // This won't fail since `nonce` has the required length. let nonce = ring::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::empty(), &mut out) .ok()? .len(); out.truncate(plain_len); Some(out) } } struct TicketSwitcherState { next: Option>, current: Box, previous: Option>, 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. struct TicketSwitcher { generator: fn() -> Result, rand::GetRandomFailed>, lifetime: u32, state: Mutex, } impl TicketSwitcher { /// `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. fn new( lifetime: u32, generator: fn() -> Result, rand::GetRandomFailed>, ) -> Result { let now = TimeBase::now()?; Ok(Self { generator, lifetime, state: Mutex::new(TicketSwitcherState { next: Some(generator()?), current: generator()?, previous: None, next_switch_time: 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 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. fn maybe_roll(&self, now: TimeBase) -> Option> { // 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().ok()?; // 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 if let Some(next) = state.next.take() { state.previous = Some(mem::replace(&mut state.current, next)); state.next_switch_time = now.saturating_add(u64::from(self.lifetime)); } else { 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().ok()?; 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().ok()?; 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> { let state = self.maybe_roll(TimeBase::now().ok()?)?; state.current.encrypt(message) } fn decrypt(&self, ciphertext: &[u8]) -> Option> { let state = self.maybe_roll(TimeBase::now().ok()?)?; // 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)) }) } } /// A concrete, safe ticket creation mechanism. pub struct Ticketer {} fn generate_inner() -> Result, rand::GetRandomFailed> { Ok(Box::new(AeadTicketer::new()?)) } impl Ticketer { /// Make the recommended Ticketer. This produces tickets /// with a 12 hour life and randomly generated keys. /// /// The encryption mechanism used in Chacha20Poly1305. pub fn new() -> Result, Error> { Ok(Arc::new(TicketSwitcher::new(6 * 60 * 60, generate_inner)?)) } } #[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 ticketswitcher_switching_test() { let t = Arc::new(TicketSwitcher::new(1, generate_inner).unwrap()); let now = TimeBase::now().unwrap(); let cipher1 = t.encrypt(b"ticket 1").unwrap(); assert_eq!(t.decrypt(&cipher1).unwrap(), b"ticket 1"); { // Trigger new ticketer t.maybe_roll(TimeBase(now.0 + std::time::Duration::from_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(TimeBase(now.0 + std::time::Duration::from_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"); } #[cfg(test)] fn fail_generator() -> Result, rand::GetRandomFailed> { Err(rand::GetRandomFailed) } #[test] fn ticketswitcher_recover_test() { let mut t = TicketSwitcher::new(1, generate_inner).unwrap(); let now = TimeBase::now().unwrap(); 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(TimeBase(now.0 + std::time::Duration::from_secs(10))); } t.generator = generate_inner; 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(TimeBase(now.0 + std::time::Duration::from_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"); } rustls-v-0.21.10/rustls/src/tls12/000077500000000000000000000000001453461710000165435ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/tls12/cipher.rs000066400000000000000000000163111453461710000203650ustar00rootroot00000000000000use crate::cipher::{make_nonce, Iv, MessageDecrypter, MessageEncrypter}; use crate::enums::ContentType; use crate::enums::ProtocolVersion; use crate::error::Error; use crate::msgs::base::Payload; use crate::msgs::codec; use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; use ring::aead; const TLS12_AAD_SIZE: usize = 8 + 1 + 2 + 2; fn make_tls12_aad( seq: u64, typ: ContentType, vers: ProtocolVersion, len: usize, ) -> ring::aead::Aad<[u8; TLS12_AAD_SIZE]> { let mut out = [0; TLS12_AAD_SIZE]; codec::put_u64(seq, &mut out[0..]); out[8] = typ.get_u8(); codec::put_u16(vers.get_u16(), &mut out[9..]); codec::put_u16(len as u16, &mut out[11..]); ring::aead::Aad::from(out) } pub(crate) struct AesGcm; impl Tls12AeadAlgorithm for AesGcm { fn decrypter(&self, dec_key: aead::LessSafeKey, dec_iv: &[u8]) -> Box { 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: aead::LessSafeKey, write_iv: &[u8], explicit: &[u8], ) -> Box { 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 = Iv(Default::default()); iv.0[..4].copy_from_slice(write_iv); iv.0[4..].copy_from_slice(explicit); Box::new(GcmMessageEncrypter { enc_key, iv }) } } pub(crate) struct ChaCha20Poly1305; impl Tls12AeadAlgorithm for ChaCha20Poly1305 { fn decrypter(&self, dec_key: aead::LessSafeKey, iv: &[u8]) -> Box { Box::new(ChaCha20Poly1305MessageDecrypter { dec_key, dec_offset: Iv::copy(iv), }) } fn encrypter( &self, enc_key: aead::LessSafeKey, enc_iv: &[u8], _: &[u8], ) -> Box { Box::new(ChaCha20Poly1305MessageEncrypter { enc_key, enc_offset: Iv::copy(enc_iv), }) } } pub(crate) trait Tls12AeadAlgorithm: Send + Sync + 'static { fn decrypter(&self, key: aead::LessSafeKey, iv: &[u8]) -> Box; fn encrypter( &self, key: aead::LessSafeKey, iv: &[u8], extra: &[u8], ) -> Box; } /// 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(&self, mut msg: OpaqueMessage, seq: u64) -> Result { let payload = &mut msg.payload.0; 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 = make_tls12_aad(seq, msg.typ, msg.version, payload.len() - GCM_OVERHEAD); 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(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { let nonce = make_nonce(&self.iv, seq); let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()); let total_len = msg.payload.len() + self.enc_key.algorithm().tag_len(); let mut payload = Vec::with_capacity(GCM_EXPLICIT_NONCE_LEN + total_len); payload.extend_from_slice(&nonce.as_ref()[4..]); payload.extend_from_slice(msg.payload); self.enc_key .seal_in_place_separate_tag(nonce, aad, &mut payload[GCM_EXPLICIT_NONCE_LEN..]) .map(|tag| payload.extend(tag.as_ref())) .map_err(|_| Error::EncryptError)?; Ok(OpaqueMessage { typ: msg.typ, version: msg.version, payload: Payload::new(payload), }) } } /// 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(&self, mut msg: OpaqueMessage, seq: u64) -> Result { let payload = &mut msg.payload.0; if payload.len() < CHACHAPOLY1305_OVERHEAD { return Err(Error::DecryptError); } let nonce = make_nonce(&self.dec_offset, seq); let aad = make_tls12_aad( seq, msg.typ, msg.version, payload.len() - CHACHAPOLY1305_OVERHEAD, ); 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(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { let nonce = make_nonce(&self.enc_offset, seq); let aad = make_tls12_aad(seq, msg.typ, msg.version, msg.payload.len()); let total_len = msg.payload.len() + self.enc_key.algorithm().tag_len(); let mut buf = Vec::with_capacity(total_len); buf.extend_from_slice(msg.payload); self.enc_key .seal_in_place_append_tag(nonce, aad, &mut buf) .map_err(|_| Error::EncryptError)?; Ok(OpaqueMessage { typ: msg.typ, version: msg.version, payload: Payload::new(buf), }) } } rustls-v-0.21.10/rustls/src/tls12/mod.rs000066400000000000000000000422161453461710000176750ustar00rootroot00000000000000use crate::cipher::{MessageDecrypter, MessageEncrypter}; use crate::common_state::{CommonState, Side}; use crate::conn::ConnectionRandoms; use crate::enums::{AlertDescription, CipherSuite, SignatureScheme}; use crate::error::{Error, InvalidMessage}; use crate::kx; use crate::msgs::codec::{Codec, Reader}; use crate::msgs::handshake::KeyExchangeAlgorithm; use crate::suites::{BulkAlgorithm, CipherSuiteCommon, SupportedCipherSuite}; #[cfg(feature = "secret_extraction")] use crate::suites::{ConnectionTrafficSecrets, PartiallyExtractedSecrets}; use ring::aead; use ring::digest::Digest; use std::fmt; mod cipher; pub(crate) use cipher::{AesGcm, ChaCha20Poly1305, Tls12AeadAlgorithm}; mod prf; /// 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, bulk: BulkAlgorithm::Chacha20Poly1305, aead_algorithm: &ring::aead::CHACHA20_POLY1305, }, kx: KeyExchangeAlgorithm::ECDHE, sign: TLS12_ECDSA_SCHEMES, fixed_iv_len: 12, explicit_nonce_len: 0, aead_alg: &ChaCha20Poly1305, hmac_algorithm: ring::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, bulk: BulkAlgorithm::Chacha20Poly1305, aead_algorithm: &ring::aead::CHACHA20_POLY1305, }, kx: KeyExchangeAlgorithm::ECDHE, sign: TLS12_RSA_SCHEMES, fixed_iv_len: 12, explicit_nonce_len: 0, aead_alg: &ChaCha20Poly1305, hmac_algorithm: ring::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, bulk: BulkAlgorithm::Aes128Gcm, aead_algorithm: &ring::aead::AES_128_GCM, }, kx: KeyExchangeAlgorithm::ECDHE, sign: TLS12_RSA_SCHEMES, fixed_iv_len: 4, explicit_nonce_len: 8, aead_alg: &AesGcm, hmac_algorithm: ring::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, bulk: BulkAlgorithm::Aes256Gcm, aead_algorithm: &ring::aead::AES_256_GCM, }, kx: KeyExchangeAlgorithm::ECDHE, sign: TLS12_RSA_SCHEMES, fixed_iv_len: 4, explicit_nonce_len: 8, aead_alg: &AesGcm, hmac_algorithm: ring::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, bulk: BulkAlgorithm::Aes128Gcm, aead_algorithm: &ring::aead::AES_128_GCM, }, kx: KeyExchangeAlgorithm::ECDHE, sign: TLS12_ECDSA_SCHEMES, fixed_iv_len: 4, explicit_nonce_len: 8, aead_alg: &AesGcm, hmac_algorithm: ring::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, bulk: BulkAlgorithm::Aes256Gcm, aead_algorithm: &ring::aead::AES_256_GCM, }, kx: KeyExchangeAlgorithm::ECDHE, sign: TLS12_ECDSA_SCHEMES, fixed_iv_len: 4, explicit_nonce_len: 8, aead_alg: &AesGcm, hmac_algorithm: ring::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, ]; /// A TLS 1.2 cipher suite supported by rustls. pub struct Tls12CipherSuite { /// Common cipher suite fields. pub common: CipherSuiteCommon, pub(crate) hmac_algorithm: ring::hmac::Algorithm, /// How to exchange/agree keys. pub kx: KeyExchangeAlgorithm, /// How to sign messages for authentication. pub sign: &'static [SignatureScheme], /// How long the fixed part of the 'IV' is. /// /// This isn't usually an IV, but we continue the /// terminology misuse to match the standard. 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, pub(crate) aead_alg: &'static dyn Tls12AeadAlgorithm, } impl Tls12CipherSuite { /// Resolve the set of supported `SignatureScheme`s from the /// offered `SupportedSignatureSchemes`. If we return an empty /// set, the handshake terminates. pub fn resolve_sig_schemes(&self, offered: &[SignatureScheme]) -> Vec { self.sign .iter() .filter(|pref| offered.contains(pref)) .cloned() .collect() } /// Which hash function to use with this suite. pub(crate) fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { self.hmac_algorithm.digest_algorithm() } } 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) .field("bulk", &self.common.bulk) .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: kx::KeyExchange, peer_pub_key: &[u8], ems_seed: Option, randoms: ConnectionRandoms, suite: &'static Tls12CipherSuite, ) -> Result { 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)), ), }; kx.complete(peer_pub_key, |secret| { prf::prf( &mut ret.master_secret, suite.hmac_algorithm, secret, 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 `scs`, /// and the session's `secrets`. pub(crate) fn make_cipher_pair(&self, side: Side) -> MessageCipherPair { fn split_key<'a>( key_block: &'a [u8], alg: &'static aead::Algorithm, ) -> (aead::LessSafeKey, &'a [u8]) { // Might panic if the key block is too small. let (key, rest) = key_block.split_at(alg.key_len()); // Won't panic because its only prerequisite is that `key` is `alg.key_len()` bytes long. let key = aead::UnboundKey::new(alg, key).unwrap(); (aead::LessSafeKey::new(key), rest) } // Make a key block, and chop it up. // nb. we don't implement any ciphersuites with nonzero mac_key_len. let key_block = self.make_key_block(); let suite = self.suite; let scs = &suite.common; let (client_write_key, key_block) = split_key(&key_block, scs.aead_algorithm); let (server_write_key, key_block) = split_key(key_block, scs.aead_algorithm); let (client_write_iv, key_block) = key_block.split_at(suite.fixed_iv_len); let (server_write_iv, extra) = key_block.split_at(suite.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, ), }; ( suite .aead_alg .decrypter(read_key, read_iv), suite .aead_alg .encrypter(write_key, write_iv, extra), ) } fn make_key_block(&self) -> Vec { let suite = &self.suite; let common = &self.suite.common; let len = (common.aead_algorithm.key_len() + suite.fixed_iv_len) * 2 + suite.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); prf::prf( &mut out, self.suite.hmac_algorithm, &self.master_secret, b"key expansion", &randoms, ); out } pub(crate) fn suite(&self) -> &'static Tls12CipherSuite { self.suite } pub(crate) fn get_master_secret(&self) -> Vec { let mut ret = Vec::new(); ret.extend_from_slice(&self.master_secret); ret } fn make_verify_data(&self, handshake_hash: &Digest, label: &[u8]) -> Vec { let mut out = vec![0u8; 12]; prf::prf( &mut out, self.suite.hmac_algorithm, &self.master_secret, label, handshake_hash.as_ref(), ); out } pub(crate) fn client_verify_data(&self, handshake_hash: &Digest) -> Vec { self.make_verify_data(handshake_hash, b"client finished") } pub(crate) fn server_verify_data(&self, handshake_hash: &Digest) -> Vec { 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); } prf::prf( output, self.suite.hmac_algorithm, &self.master_secret, label, &randoms, ); } #[cfg(feature = "secret_extraction")] pub(crate) fn extract_secrets(&self, side: Side) -> Result { // Make a key block, and chop it up let key_block = self.make_key_block(); let suite = self.suite; let algo = suite.common.aead_algorithm; let (client_key, key_block) = key_block.split_at(algo.key_len()); let (server_key, key_block) = key_block.split_at(algo.key_len()); let (client_iv, key_block) = key_block.split_at(suite.fixed_iv_len); let (server_iv, extra) = key_block.split_at(suite.fixed_iv_len); // A key/IV pair (fixed IV len is 4 for GCM, 12 for Chacha) struct Pair<'a> { key: &'a [u8], iv: &'a [u8], } let client_pair = Pair { key: client_key, iv: client_iv, }; let server_pair = Pair { key: server_key, iv: server_iv, }; let (client_secrets, server_secrets) = if algo == &ring::aead::AES_128_GCM { let extract = |pair: Pair| -> ConnectionTrafficSecrets { let mut key = [0u8; 16]; key.copy_from_slice(pair.key); let mut salt = [0u8; 4]; salt.copy_from_slice(pair.iv); let mut iv = [0u8; 8]; iv.copy_from_slice(&extra[..8]); ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv } }; (extract(client_pair), extract(server_pair)) } else if algo == &ring::aead::AES_256_GCM { let extract = |pair: Pair| -> ConnectionTrafficSecrets { let mut key = [0u8; 32]; key.copy_from_slice(pair.key); let mut salt = [0u8; 4]; salt.copy_from_slice(pair.iv); let mut iv = [0u8; 8]; iv.copy_from_slice(&extra[..8]); ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv } }; (extract(client_pair), extract(server_pair)) } else if algo == &ring::aead::CHACHA20_POLY1305 { let extract = |pair: Pair| -> ConnectionTrafficSecrets { let mut key = [0u8; 32]; key.copy_from_slice(pair.key); let mut iv = [0u8; 12]; iv.copy_from_slice(pair.iv); ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv } }; (extract(client_pair), extract(server_pair)) } else { return Err(Error::General(format!( "exporting secrets for {:?}: unimplemented", algo ))); }; let (tx, rx) = match side { Side::Client => (client_secrets, server_secrets), Side::Server => (server_secrets, client_secrets), }; Ok(PartiallyExtractedSecrets { tx, rx }) } } enum Seed { Ems(Digest), Randoms([u8; 64]), } impl AsRef<[u8]> for Seed { fn as_ref(&self) -> &[u8] { match self { Self::Ems(seed) => seed.as_ref(), 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, Box); pub(crate) fn decode_ecdh_params( common: &mut CommonState, kx_params: &[u8], ) -> Result { let mut rd = Reader::init(kx_params); let ecdh_params = T::read(&mut rd)?; match rd.any_left() { false => Ok(ecdh_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)] mod tests { use super::*; use crate::common_state::{CommonState, Side}; use crate::msgs::handshake::{ClientECDHParams, ServerECDHParams}; #[test] fn server_ecdhe_remaining_bytes() { let key = kx::KeyExchange::start(&kx::X25519).unwrap(); let server_params = ServerECDHParams::new(key.group(), key.pubkey.as_ref()); 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_ecdh_params::(&mut common, &server_buf).is_err()); } #[test] fn client_ecdhe_invalid() { let mut common = CommonState::new(Side::Server); assert!(decode_ecdh_params::(&mut common, &[34]).is_err()); } } rustls-v-0.21.10/rustls/src/tls12/prf.rs000066400000000000000000000051321453461710000177010ustar00rootroot00000000000000use ring::hmac; fn concat_sign(key: &hmac::Key, a: &[u8], b: &[u8]) -> hmac::Tag { let mut ctx = hmac::Context::with_key(key); ctx.update(a); ctx.update(b); ctx.sign() } fn p(out: &mut [u8], alg: hmac::Algorithm, secret: &[u8], seed: &[u8]) { let hmac_key = hmac::Key::new(alg, secret); // A(1) let mut current_a = hmac::sign(&hmac_key, seed); let chunk_size = alg.digest_algorithm().output_len(); for chunk in out.chunks_mut(chunk_size) { // P_hash[i] = HMAC_hash(secret, A(i) + seed) let p_term = concat_sign(&hmac_key, current_a.as_ref(), seed); chunk.copy_from_slice(&p_term.as_ref()[..chunk.len()]); // A(i+1) = HMAC_hash(secret, A(i)) current_a = hmac::sign(&hmac_key, current_a.as_ref()); } } fn concat(a: &[u8], b: &[u8]) -> Vec { let mut ret = Vec::new(); ret.extend_from_slice(a); ret.extend_from_slice(b); ret } pub(crate) fn prf(out: &mut [u8], alg: hmac::Algorithm, secret: &[u8], label: &[u8], seed: &[u8]) { let joined_seed = concat(label, seed); p(out, alg, secret, &joined_seed); } #[cfg(test)] mod tests { use ring::hmac::{HMAC_SHA256, HMAC_SHA512}; #[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_SHA256, 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_SHA512, secret, label, seed); assert_eq!(expect.len(), output.len()); assert_eq!(expect.to_vec(), output.to_vec()); } } #[cfg(bench)] mod benchmarks { #[bench] fn bench_sha256(b: &mut test::Bencher) { 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, ring::hmac::HMAC_SHA256, key, &label, &seed); test::black_box(out); }); } } rustls-v-0.21.10/rustls/src/tls13/000077500000000000000000000000001453461710000165445ustar00rootroot00000000000000rustls-v-0.21.10/rustls/src/tls13/key_schedule.rs000066400000000000000000001024161453461710000215620ustar00rootroot00000000000000use crate::cipher::{Iv, IvLen, MessageDecrypter}; use crate::common_state::{CommonState, Side}; use crate::error::Error; use crate::msgs::base::PayloadU8; #[cfg(feature = "quic")] use crate::quic; #[cfg(feature = "secret_extraction")] use crate::suites::{ConnectionTrafficSecrets, PartiallyExtractedSecrets}; use crate::{KeyLog, Tls13CipherSuite}; /// Key schedule maintenance for TLS1.3 use ring::{ aead, digest::{self, Digest}, hkdf::{self, KeyType as _}, hmac, }; use super::{Tls13MessageDecrypter, Tls13MessageEncrypter}; /// 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, } 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", } } 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; } }) } } /// 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: hkdf::Prk, suite: &'static Tls13CipherSuite, } // 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. /// KeySchedule for early data stage. pub(crate) struct KeyScheduleEarly { ks: KeySchedule, } impl KeyScheduleEarly { pub(crate) fn new(suite: &'static Tls13CipherSuite, secret: &[u8]) -> Self { Self { ks: KeySchedule::new(suite, secret), } } pub(crate) fn client_early_traffic_secret( &self, hs_hash: &Digest, 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), } #[cfg(feature = "quic")] 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: &Digest, ) -> 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) } } /// Pre-handshake key schedule /// /// The inner `KeySchedule` is either constructed without any secrets based on ths HKDF algorithm /// or is extracted from a `KeyScheduleEarly`. This can then be used to derive the `KeyScheduleHandshakeStart`. pub(crate) struct KeySchedulePreHandshake { ks: KeySchedule, } impl KeySchedulePreHandshake { pub(crate) fn new(suite: &'static Tls13CipherSuite) -> Self { Self { ks: KeySchedule::new_with_empty_secret(suite), } } pub(crate) fn into_handshake(mut self, secret: &[u8]) -> KeyScheduleHandshakeStart { self.ks.input_secret(secret); KeyScheduleHandshakeStart { ks: self.ks } } } impl From for KeySchedulePreHandshake { fn from(KeyScheduleEarly { ks }: KeyScheduleEarly) -> Self { Self { ks } } } /// KeySchedule during handshake. pub(crate) struct KeyScheduleHandshakeStart { ks: KeySchedule, } impl KeyScheduleHandshakeStart { pub(crate) fn derive_client_handshake_secrets( mut self, early_data_enabled: bool, hs_hash: Digest, 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.suite = suite; 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: Digest, 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 } fn into_handshake( self, hs_hash: Digest, 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, ); #[cfg(feature = "quic")] if _common.is_quic() { _common.quic.hs_secrets = Some(quic::Secrets::new( client_secret.clone(), server_secret.clone(), self.ks.suite, _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: hkdf::Prk, server_handshake_traffic_secret: hkdf::Prk, } impl KeyScheduleHandshake { pub(crate) fn sign_server_finish(&self, hs_hash: &Digest) -> 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, 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: Digest, key_log: &dyn KeyLog, client_random: &[u8; 32], common: &mut CommonState, ) -> KeyScheduleTrafficWithClientFinishedPending { debug_assert_eq!(common.side, Side::Server); let traffic = KeyScheduleTraffic::new(self.ks, hs_hash, key_log, client_random); let (_client_secret, server_secret) = ( &traffic.current_client_traffic_secret, &traffic.current_server_traffic_secret, ); traffic .ks .set_encrypter(server_secret, common); #[cfg(feature = "quic")] if common.is_quic() { common.quic.traffic_secrets = Some(quic::Secrets::new( _client_secret.clone(), server_secret.clone(), traffic.ks.suite, common.side, common.quic.version, )); } KeyScheduleTrafficWithClientFinishedPending { handshake_client_traffic_secret: self.client_handshake_traffic_secret, traffic, } } pub(crate) fn into_pre_finished_client_traffic( self, pre_finished_hash: Digest, handshake_hash: Digest, key_log: &dyn KeyLog, client_random: &[u8; 32], ) -> (KeyScheduleClientBeforeFinished, hmac::Tag) { let traffic = KeyScheduleTraffic::new(self.ks, pre_finished_hash, key_log, client_random); let tag = traffic .ks .sign_finish(&self.client_handshake_traffic_secret, &handshake_hash); (KeyScheduleClientBeforeFinished { traffic }, tag) } } pub(crate) struct KeyScheduleClientBeforeFinished { traffic: KeyScheduleTraffic, } impl KeyScheduleClientBeforeFinished { pub(crate) fn into_traffic(self, common: &mut CommonState) -> KeyScheduleTraffic { debug_assert_eq!(common.side, Side::Client); let (client_secret, server_secret) = ( &self .traffic .current_client_traffic_secret, &self .traffic .current_server_traffic_secret, ); self.traffic .ks .set_decrypter(server_secret, common); self.traffic .ks .set_encrypter(client_secret, common); #[cfg(feature = "quic")] if common.is_quic() { common.quic.traffic_secrets = Some(quic::Secrets::new( client_secret.clone(), server_secret.clone(), self.traffic.ks.suite, common.side, common.quic.version, )); } self.traffic } } /// 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: hkdf::Prk, traffic: KeyScheduleTraffic, } impl KeyScheduleTrafficWithClientFinishedPending { pub(crate) fn update_decrypter(&self, common: &mut CommonState) { debug_assert_eq!(common.side, Side::Server); self.traffic .ks .set_decrypter(&self.handshake_client_traffic_secret, common); } pub(crate) fn sign_client_finish( self, hs_hash: &Digest, common: &mut CommonState, ) -> (KeyScheduleTraffic, hmac::Tag) { debug_assert_eq!(common.side, Side::Server); let tag = self .traffic .ks .sign_finish(&self.handshake_client_traffic_secret, hs_hash); // Install keying to read future messages. self.traffic.ks.set_decrypter( &self .traffic .current_client_traffic_secret, common, ); (self.traffic, tag) } } /// KeySchedule during traffic stage. All traffic & exporter keys are guaranteed /// to be available. pub(crate) struct KeyScheduleTraffic { ks: KeySchedule, current_client_traffic_secret: hkdf::Prk, current_server_traffic_secret: hkdf::Prk, current_exporter_secret: hkdf::Prk, } impl KeyScheduleTraffic { fn new( mut ks: KeySchedule, hs_hash: Digest, 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 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 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) -> hkdf::Prk { 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 resumption_master_secret_and_derive_ticket_psk( &self, hs_hash: &Digest, nonce: &[u8], ) -> Vec { let resumption_master_secret = self.ks.derive( self.ks.algorithm(), SecretKind::ResumptionMasterSecret, hs_hash.as_ref(), ); self.ks .derive_ticket_psk(&resumption_master_secret, nonce) } 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) } #[cfg(feature = "secret_extraction")] pub(crate) fn extract_secrets(&self, side: Side) -> Result { fn expand( secret: &hkdf::Prk, ) -> Result<([u8; KEY_LEN], [u8; IV_LEN]), Error> { let mut key = [0u8; KEY_LEN]; let mut iv = [0u8; IV_LEN]; hkdf_expand_info(secret, PayloadU8Len(key.len()), b"key", &[], |okm| { okm.fill(&mut key) }) .map_err(|_| Error::General("hkdf_expand_info failed".to_string()))?; hkdf_expand_info(secret, PayloadU8Len(iv.len()), b"iv", &[], |okm| { okm.fill(&mut iv) }) .map_err(|_| Error::General("hkdf_expand_info failed".to_string()))?; Ok((key, iv)) } let client_secrets; let server_secrets; let algo = self.ks.suite.common.aead_algorithm; if algo == &ring::aead::AES_128_GCM { let extract = |secret: &hkdf::Prk| -> Result { let (key, iv_in) = expand::<16, 12>(secret)?; let mut salt = [0u8; 4]; salt.copy_from_slice(&iv_in[..4]); let mut iv = [0u8; 8]; iv.copy_from_slice(&iv_in[4..]); Ok(ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv }) }; client_secrets = extract(&self.current_client_traffic_secret)?; server_secrets = extract(&self.current_server_traffic_secret)?; } else if algo == &ring::aead::AES_256_GCM { let extract = |secret: &hkdf::Prk| -> Result { let (key, iv_in) = expand::<32, 12>(secret)?; let mut salt = [0u8; 4]; salt.copy_from_slice(&iv_in[..4]); let mut iv = [0u8; 8]; iv.copy_from_slice(&iv_in[4..]); Ok(ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv }) }; client_secrets = extract(&self.current_client_traffic_secret)?; server_secrets = extract(&self.current_server_traffic_secret)?; } else if algo == &ring::aead::CHACHA20_POLY1305 { let extract = |secret: &hkdf::Prk| -> Result { let (key, iv) = expand::<32, 12>(secret)?; Ok(ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv }) }; client_secrets = extract(&self.current_client_traffic_secret)?; server_secrets = extract(&self.current_server_traffic_secret)?; } else { return Err(Error::General(format!( "exporting secrets for {:?}: unimplemented", algo ))); } let (tx, rx) = match side { Side::Client => (client_secrets, server_secrets), Side::Server => (server_secrets, client_secrets), }; Ok(PartiallyExtractedSecrets { tx, rx }) } } impl KeySchedule { fn new(suite: &'static Tls13CipherSuite, secret: &[u8]) -> Self { let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; let salt = hkdf::Salt::new(suite.hkdf_algorithm, &zeroes[..suite.hkdf_algorithm.len()]); Self { current: salt.extract(secret), suite, } } fn set_encrypter(&self, secret: &hkdf::Prk, common: &mut CommonState) { let key = derive_traffic_key(secret, self.suite.common.aead_algorithm); let iv = derive_traffic_iv(secret); common .record_layer .set_message_encrypter(Box::new(Tls13MessageEncrypter { enc_key: aead::LessSafeKey::new(key), iv, })); } fn set_decrypter(&self, secret: &hkdf::Prk, common: &mut CommonState) { common .record_layer .set_message_decrypter(self.derive_decrypter(secret)); } fn derive_decrypter(&self, secret: &hkdf::Prk) -> Box { let key = derive_traffic_key(secret, self.suite.common.aead_algorithm); let iv = derive_traffic_iv(secret); Box::new(Tls13MessageDecrypter { dec_key: aead::LessSafeKey::new(key), iv, }) } #[inline] fn algorithm(&self) -> hkdf::Algorithm { self.suite.hkdf_algorithm } fn new_with_empty_secret(suite: &'static Tls13CipherSuite) -> Self { let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; Self::new(suite, &zeroes[..suite.hkdf_algorithm.len()]) } /// Input the empty secret. fn input_empty(&mut self) { let zeroes = [0u8; digest::MAX_OUTPUT_LEN]; self.input_secret(&zeroes[..self.suite.hkdf_algorithm.len()]); } /// Input the given secret. fn input_secret(&mut self, secret: &[u8]) { let salt: hkdf::Salt = self.derive_for_empty_hash(SecretKind::DerivedSecret); self.current = salt.extract(secret); } /// Derive a secret of given `kind`, using current handshake hash `hs_hash`. fn derive(&self, key_type: L, kind: SecretKind, hs_hash: &[u8]) -> T where T: for<'a> From>, L: hkdf::KeyType, { hkdf_expand(&self.current, key_type, kind.to_bytes(), hs_hash) } fn derive_logged_secret( &self, kind: SecretKind, hs_hash: &[u8], key_log: &dyn KeyLog, client_random: &[u8; 32], ) -> hkdf::Prk { let log_label = kind .log_label() .expect("not a loggable secret"); if key_log.will_log(log_label) { let secret = self .derive::( PayloadU8Len(self.suite.hkdf_algorithm.len()), kind, hs_hash, ) .into_inner(); key_log.log(log_label, client_random, &secret); } self.derive(self.suite.hkdf_algorithm, kind, hs_hash) } /// Derive a secret of given `kind` using the hash of the empty string /// for the handshake hash. Useful only for /// `SecretKind::ResumptionPSKBinderKey` and /// `SecretKind::DerivedSecret`. fn derive_for_empty_hash(&self, kind: SecretKind) -> T where T: for<'a> From>, { let digest_alg = self .suite .hkdf_algorithm .hmac_algorithm() .digest_algorithm(); let empty_hash = digest::digest(digest_alg, &[]); self.derive(self.suite.hkdf_algorithm, kind, empty_hash.as_ref()) } /// Sign the finished message consisting of `hs_hash` using a current /// traffic secret. fn sign_finish(&self, base_key: &hkdf::Prk, hs_hash: &Digest) -> hmac::Tag { self.sign_verify_data(base_key, hs_hash) } /// Sign the finished message consisting of `hs_hash` using the key material /// `base_key`. fn sign_verify_data(&self, base_key: &hkdf::Prk, hs_hash: &Digest) -> hmac::Tag { let hmac_alg = self .suite .hkdf_algorithm .hmac_algorithm(); let hmac_key = hkdf_expand(base_key, hmac_alg, b"finished", &[]); hmac::sign(&hmac_key, hs_hash.as_ref()) } /// Derive the next application traffic secret, returning it. fn derive_next(&self, base_key: &hkdf::Prk) -> hkdf::Prk { hkdf_expand(base_key, self.suite.hkdf_algorithm, b"traffic upd", &[]) } /// Derive the PSK to use given a resumption_master_secret and /// ticket_nonce. fn derive_ticket_psk(&self, rms: &hkdf::Prk, nonce: &[u8]) -> Vec { let payload: PayloadU8 = hkdf_expand( rms, PayloadU8Len(self.suite.hkdf_algorithm.len()), b"resumption", nonce, ); payload.into_inner() } fn export_keying_material( &self, current_exporter_secret: &hkdf::Prk, out: &mut [u8], label: &[u8], context: Option<&[u8]>, ) -> Result<(), Error> { let digest_alg = self .suite .hkdf_algorithm .hmac_algorithm() .digest_algorithm(); let h_empty = digest::digest(digest_alg, &[]); let secret: hkdf::Prk = hkdf_expand( current_exporter_secret, self.suite.hkdf_algorithm, label, h_empty.as_ref(), ); let h_context = digest::digest(digest_alg, context.unwrap_or(&[])); // TODO: Test what happens when this fails hkdf_expand_info( &secret, PayloadU8Len(out.len()), b"exporter", h_context.as_ref(), |okm| okm.fill(out), ) .map_err(|_| Error::General("exporting too much".to_string())) } } pub(crate) fn hkdf_expand(secret: &hkdf::Prk, key_type: L, label: &[u8], context: &[u8]) -> T where T: for<'a> From>, L: hkdf::KeyType, { hkdf_expand_info(secret, key_type, label, context, |okm| okm.into()) } fn hkdf_expand_info( secret: &hkdf::Prk, key_type: L, label: &[u8], context: &[u8], f: F, ) -> T where F: for<'b> FnOnce(hkdf::Okm<'b, L>) -> T, L: hkdf::KeyType, { const LABEL_PREFIX: &[u8] = b"tls13 "; let output_len = u16::to_be_bytes(key_type.len() 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, ]; let okm = secret.expand(info, key_type).unwrap(); f(okm) } pub(crate) struct PayloadU8Len(pub(crate) usize); impl hkdf::KeyType for PayloadU8Len { fn len(&self) -> usize { self.0 } } impl From> for PayloadU8 { fn from(okm: hkdf::Okm) -> Self { let mut r = vec![0u8; okm.len().0]; okm.fill(&mut r[..]).unwrap(); Self::new(r) } } pub(crate) fn derive_traffic_key( secret: &hkdf::Prk, aead_algorithm: &'static aead::Algorithm, ) -> aead::UnboundKey { hkdf_expand(secret, aead_algorithm, b"key", &[]) } pub(crate) fn derive_traffic_iv(secret: &hkdf::Prk) -> Iv { hkdf_expand(secret, IvLen, b"iv", &[]) } #[cfg(test)] mod test { use super::{derive_traffic_iv, derive_traffic_key, KeySchedule, SecretKind}; use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; use crate::KeyLog; use ring::aead; #[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], ) { 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 key = derive_traffic_key(&traffic_secret, aead_alg); 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(&traffic_secret); assert_eq!(iv.value(), expected_iv); } fn seal_zeroes(key: aead::UnboundKey) -> Vec { 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(bench)] mod benchmarks { #[bench] fn bench_sha256(b: &mut test::Bencher) { use super::{derive_traffic_iv, derive_traffic_key, KeySchedule, SecretKind}; use crate::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; use crate::KeyLog; use ring::aead; fn extract_traffic_secret(ks: &KeySchedule, kind: SecretKind) { struct Log; impl KeyLog for Log { fn log(&self, _label: &str, _client_random: &[u8], _secret: &[u8]) {} } let aead_alg = &aead::CHACHA20_POLY1305; let hash = [0u8; 32]; let traffic_secret = ks.derive_logged_secret(kind, &hash, &Log, &[0u8; 32]); test::black_box(derive_traffic_key(&traffic_secret, aead_alg)); test::black_box(derive_traffic_iv(&traffic_secret)); } 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); }); } } rustls-v-0.21.10/rustls/src/tls13/mod.rs000066400000000000000000000145011453461710000176720ustar00rootroot00000000000000use crate::cipher::{make_nonce, Iv, MessageDecrypter, MessageEncrypter}; use crate::enums::ContentType; use crate::enums::{CipherSuite, ProtocolVersion}; use crate::error::{Error, PeerMisbehaved}; use crate::msgs::base::Payload; use crate::msgs::codec::Codec; use crate::msgs::fragmenter::MAX_FRAGMENT_LEN; use crate::msgs::message::{BorrowedPlainMessage, OpaqueMessage, PlainMessage}; use crate::suites::{BulkAlgorithm, CipherSuiteCommon, SupportedCipherSuite}; use ring::aead; use std::fmt; pub(crate) mod key_schedule; /// 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, bulk: BulkAlgorithm::Chacha20Poly1305, aead_algorithm: &ring::aead::CHACHA20_POLY1305, }, hkdf_algorithm: ring::hkdf::HKDF_SHA256, #[cfg(feature = "quic")] confidentiality_limit: u64::MAX, #[cfg(feature = "quic")] 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, bulk: BulkAlgorithm::Aes256Gcm, aead_algorithm: &ring::aead::AES_256_GCM, }, hkdf_algorithm: ring::hkdf::HKDF_SHA384, #[cfg(feature = "quic")] confidentiality_limit: 1 << 23, #[cfg(feature = "quic")] 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, bulk: BulkAlgorithm::Aes128Gcm, aead_algorithm: &ring::aead::AES_128_GCM, }, hkdf_algorithm: ring::hkdf::HKDF_SHA256, #[cfg(feature = "quic")] confidentiality_limit: 1 << 23, #[cfg(feature = "quic")] integrity_limit: 1 << 52, }; /// A TLS 1.3 cipher suite supported by rustls. pub struct Tls13CipherSuite { /// Common cipher suite fields. pub common: CipherSuiteCommon, pub(crate) hkdf_algorithm: ring::hkdf::Algorithm, #[cfg(feature = "quic")] pub(crate) confidentiality_limit: u64, #[cfg(feature = "quic")] pub(crate) integrity_limit: u64, } impl Tls13CipherSuite { /// Which hash function to use with this suite. pub(crate) fn hash_algorithm(&self) -> &'static ring::digest::Algorithm { self.hkdf_algorithm .hmac_algorithm() .digest_algorithm() } /// Can a session using suite self resume from suite prev? pub fn can_resume_from(&self, prev: &'static Self) -> Option<&'static Self> { (prev.hash_algorithm() == self.hash_algorithm()).then(|| prev) } } 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) .field("bulk", &self.common.bulk) .finish() } } struct Tls13MessageEncrypter { enc_key: aead::LessSafeKey, iv: Iv, } struct Tls13MessageDecrypter { dec_key: aead::LessSafeKey, iv: Iv, } fn unpad_tls13(v: &mut Vec) -> ContentType { loop { match v.pop() { Some(0) => {} Some(content_type) => return ContentType::from(content_type), None => return ContentType::Unknown(0), } } } fn make_tls13_aad(len: usize) -> ring::aead::Aad<[u8; TLS13_AAD_SIZE]> { ring::aead::Aad::from([ 0x17, // ContentType::ApplicationData 0x3, // ProtocolVersion (major) 0x3, // ProtocolVersion (minor) (len >> 8) as u8, len as u8, ]) } // https://datatracker.ietf.org/doc/html/rfc8446#section-5.2 const TLS13_AAD_SIZE: usize = 1 + 2 + 2; impl MessageEncrypter for Tls13MessageEncrypter { fn encrypt(&self, msg: BorrowedPlainMessage, seq: u64) -> Result { let total_len = msg.payload.len() + 1 + self.enc_key.algorithm().tag_len(); let mut payload = Vec::with_capacity(total_len); payload.extend_from_slice(msg.payload); msg.typ.encode(&mut payload); let nonce = make_nonce(&self.iv, seq); let aad = make_tls13_aad(total_len); self.enc_key .seal_in_place_append_tag(nonce, aad, &mut payload) .map_err(|_| Error::General("encrypt failed".to_string()))?; Ok(OpaqueMessage { typ: ContentType::ApplicationData, version: ProtocolVersion::TLSv1_2, payload: Payload::new(payload), }) } } impl MessageDecrypter for Tls13MessageDecrypter { fn decrypt(&self, mut msg: OpaqueMessage, seq: u64) -> Result { let payload = &mut msg.payload.0; if payload.len() < self.dec_key.algorithm().tag_len() { return Err(Error::DecryptError); } let nonce = make_nonce(&self.iv, seq); let aad = 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); if payload.len() > MAX_FRAGMENT_LEN + 1 { return Err(Error::PeerSentOversizedRecord); } msg.typ = unpad_tls13(payload); if msg.typ == ContentType::Unknown(0) { return Err(PeerMisbehaved::IllegalTlsInnerPlaintext.into()); } if payload.len() > MAX_FRAGMENT_LEN { return Err(Error::PeerSentOversizedRecord); } msg.version = ProtocolVersion::TLSv1_3; Ok(msg.into_plain_message()) } } rustls-v-0.21.10/rustls/src/vecbuf.rs000066400000000000000000000135171453461710000174250ustar00rootroot00000000000000use std::cmp; use std::collections::VecDeque; use std::io; use std::io::Read; /// This is a byte buffer that is built from a vector /// 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 { chunks: VecDeque>, limit: Option, } impl ChunkVecBuffer { pub(crate) fn new(limit: Option) -> Self { Self { 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) { self.limit = new_limit; } /// If we're empty pub(crate) fn is_empty(&self) -> bool { self.chunks.is_empty() } pub(crate) fn is_full(&self) -> bool { self.limit .map(|limit| self.len() > limit) .unwrap_or_default() } /// How many bytes we're storing pub(crate) fn len(&self) -> usize { let mut len = 0; for ch in &self.chunks { len += ch.len(); } len } /// 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 } } /// Append a copy of `bytes`, perhaps a prefix if /// we're near the limit. pub(crate) fn append_limited_copy(&mut self, bytes: &[u8]) -> usize { let take = self.apply_limit(bytes.len()); self.append(bytes[..take].to_vec()); take } /// Take and append the given `bytes`. pub(crate) fn append(&mut self, bytes: Vec) -> usize { let len = bytes.len(); if !bytes.is_empty() { self.chunks.push_back(bytes); } len } /// Take one of the chunks from this object. This /// function panics if the object `is_empty`. pub(crate) fn pop(&mut self) -> Option> { self.chunks.pop_front() } /// 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 { let mut offs = 0; while offs < buf.len() && !self.is_empty() { let used = self.chunks[0] .as_slice() .read(&mut buf[offs..])?; self.consume(used); offs += used; } Ok(offs) } #[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].as_slice(); let used = std::cmp::min(chunk.len(), cursor.capacity()); cursor.append(&chunk[..used]); self.consume(used); } Ok(()) } fn consume(&mut self, mut used: usize) { while let Some(mut buf) = self.chunks.pop_front() { if used < buf.len() { self.chunks .push_front(buf.split_off(used)); break; } else { used -= buf.len(); } } } /// Read data out of this object, passing it `wr` pub(crate) fn write_to(&mut self, wr: &mut dyn io::Write) -> io::Result { if self.is_empty() { return Ok(0); } let mut bufs = [io::IoSlice::new(&[]); 64]; for (iov, chunk) in bufs.iter_mut().zip(self.chunks.iter()) { *iov = io::IoSlice::new(chunk); } let len = cmp::min(bufs.len(), self.chunks.len()); let used = wr.write_vectored(&bufs[..len])?; self.consume(used); Ok(used) } } #[cfg(test)] mod test { 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"), 5); assert_eq!(cvb.append_limited_copy(b"world"), 5); assert_eq!(cvb.append_limited_copy(b"hello"), 2); assert_eq!(cvb.append_limited_copy(b"world"), 0); let mut buf = [0u8; 12]; assert_eq!(cvb.read(&mut buf).unwrap(), 12); assert_eq!(buf.to_vec(), b"helloworldhe".to_vec()); } #[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::::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::::uninit(); 1024]; let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); cvb.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), b"short message"); } } } rustls-v-0.21.10/rustls/src/verify.rs000066400000000000000000001060201453461710000174470ustar00rootroot00000000000000use std::fmt; use crate::anchors::{OwnedTrustAnchor, RootCertStore}; use crate::client::ServerName; use crate::enums::SignatureScheme; use crate::error::{ CertRevocationListError, CertificateError, Error, InvalidMessage, PeerMisbehaved, }; use crate::key::{Certificate, ParsedCertificate}; #[cfg(feature = "logging")] use crate::log::{debug, trace, warn}; use crate::msgs::base::PayloadU16; use crate::msgs::codec::{Codec, Reader}; use crate::msgs::handshake::DistinguishedName; use ring::digest::Digest; use std::sync::Arc; use std::time::SystemTime; type SignatureAlgorithms = &'static [&'static webpki::SignatureAlgorithm]; /// Which signature verification mechanisms we support. No particular /// order. static SUPPORTED_SIG_ALGS: SignatureAlgorithms = &[ &webpki::ECDSA_P256_SHA256, &webpki::ECDSA_P256_SHA384, &webpki::ECDSA_P384_SHA256, &webpki::ECDSA_P384_SHA384, &webpki::ED25519, &webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, &webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY, &webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY, &webpki::RSA_PKCS1_2048_8192_SHA256, &webpki::RSA_PKCS1_2048_8192_SHA384, &webpki::RSA_PKCS1_2048_8192_SHA512, &webpki::RSA_PKCS1_3072_8192_SHA384, ]; // 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)] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] 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)] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] 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)] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] 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)] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] pub trait ServerCertVerifier: 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 implementor to handle invalid data. It is recommended that the implementor returns /// [`Error::InvalidCertificate(CertificateError::BadEncoding)`] when these cases are encountered. /// /// `scts` contains the Signed Certificate Timestamps (SCTs) the server /// sent with the end-entity certificate, if any. /// /// [Certificate]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.4.2 fn verify_server_cert( &self, end_entity: &Certificate, intermediates: &[Certificate], server_name: &ServerName, scts: &mut dyn Iterator, ocsp_response: &[u8], now: SystemTime, ) -> Result; /// 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. /// /// This trait method has a default implementation that uses webpki to verify /// the signature. fn verify_tls12_signature( &self, message: &[u8], cert: &Certificate, dss: &DigitallySignedStruct, ) -> Result { verify_signed_struct(message, cert, dss) } /// 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. /// /// This trait method has a default implementation that uses webpki to verify /// the signature. fn verify_tls13_signature( &self, message: &[u8], cert: &Certificate, dss: &DigitallySignedStruct, ) -> Result { verify_tls13(message, cert, dss) } /// 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. /// /// This trait method has a default implementation that reflects the schemes /// supported by webpki. fn supported_verify_schemes(&self) -> Vec { WebPkiVerifier::verification_schemes() } /// Returns `true` if Rustls should ask the server to send SCTs. /// /// Signed Certificate Timestamps (SCTs) are used for Certificate /// Transparency validation. /// /// The default implementation of this function returns true. fn request_scts(&self) -> bool { true } } impl fmt::Debug for dyn ServerCertVerifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "dyn ServerCertVerifier") } } /// Something that can verify a client certificate chain #[allow(unreachable_pub)] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] pub trait ClientCertVerifier: 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 `Some(self.offer_client_auth())`. fn client_auth_mandatory(&self) -> bool { self.offer_client_auth() } /// Returns the [Subjects] of the client authentication trust anchors to /// share with the client when requesting client authentication. /// /// These must be DER-encoded X.500 distinguished names, per RFC 5280. /// They are sent in the [`certificate_authorities`] extension of a /// [`CertificateRequest`] message. /// /// [Subjects]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.6 /// [`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 /// /// If the return value is empty, no CertificateRequest message will be sent. fn client_auth_root_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 implementor to handle invalid data. It is recommended that the implementor returns /// an [InvalidCertificate] error with the [BadEncoding] variant when these cases are encountered. /// /// [InvalidCertificate]: Error#variant.InvalidCertificate /// [BadEncoding]: CertificateError#variant.BadEncoding fn verify_client_cert( &self, end_entity: &Certificate, intermediates: &[Certificate], now: SystemTime, ) -> Result; /// 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. /// /// This trait method has a default implementation that uses webpki to verify /// the signature. fn verify_tls12_signature( &self, message: &[u8], cert: &Certificate, dss: &DigitallySignedStruct, ) -> Result { verify_signed_struct(message, cert, dss) } /// 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. /// /// This trait method has a default implementation that uses webpki to verify /// the signature. fn verify_tls13_signature( &self, message: &[u8], cert: &Certificate, dss: &DigitallySignedStruct, ) -> Result { verify_tls13(message, cert, dss) } /// 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. /// /// This trait method has a default implementation that reflects the schemes /// supported by webpki. fn supported_verify_schemes(&self) -> Vec { WebPkiVerifier::verification_schemes() } } impl fmt::Debug for dyn ClientCertVerifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "dyn ClientCertVerifier") } } /// Verify that the end-entity certificate `end_entity` is a valid server cert /// and chains to at least one of the [OwnedTrustAnchor] 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. #[allow(dead_code)] #[cfg_attr(not(feature = "dangerous_configuration"), allow(unreachable_pub))] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] pub fn verify_server_cert_signed_by_trust_anchor( cert: &ParsedCertificate, roots: &RootCertStore, intermediates: &[Certificate], now: SystemTime, ) -> Result<(), Error> { let chain = intermediate_chain(intermediates); let trust_roots = trust_roots(roots); let webpki_now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?; cert.0 .verify_for_usage( SUPPORTED_SIG_ALGS, &trust_roots, &chain, webpki_now, webpki::KeyUsage::server_auth(), &[], // no CRLs ) .map_err(pki_error) .map(|_| ()) } /// Verify that the `end_entity` has a name or alternative name matching the `server_name` /// note: this only verifies the name and should be used in conjuction with more verification /// like [verify_server_cert_signed_by_trust_anchor] #[cfg_attr(not(feature = "dangerous_configuration"), allow(unreachable_pub))] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] pub fn verify_server_name(cert: &ParsedCertificate, server_name: &ServerName) -> Result<(), Error> { match server_name { ServerName::DnsName(dns_name) => { // unlikely error because dns_name::DnsNameRef and webpki::DnsNameRef // should have the same encoding rules. let dns_name = webpki::DnsNameRef::try_from_ascii_str(dns_name.as_ref()) .map_err(|_| Error::InvalidCertificate(CertificateError::BadEncoding))?; let name = webpki::SubjectNameRef::DnsName(dns_name); cert.0 .verify_is_valid_for_subject_name(name) .map_err(pki_error)?; } ServerName::IpAddress(ip_addr) => { let ip_addr = webpki::IpAddr::from(*ip_addr); cert.0 .verify_is_valid_for_subject_name(webpki::SubjectNameRef::IpAddress( webpki::IpAddrRef::from(&ip_addr), )) .map_err(pki_error)?; } } Ok(()) } impl ServerCertVerifier for WebPkiVerifier { /// Will verify the certificate is valid in the following ways: /// - Signed by a trusted `RootCertStore` CA /// - Not Expired /// - Valid for DNS entry fn verify_server_cert( &self, end_entity: &Certificate, intermediates: &[Certificate], server_name: &ServerName, scts: &mut dyn Iterator, ocsp_response: &[u8], now: SystemTime, ) -> Result { let cert = ParsedCertificate::try_from(end_entity)?; verify_server_cert_signed_by_trust_anchor(&cert, &self.roots, intermediates, now)?; if let Some(policy) = &self.ct_policy { policy.verify(end_entity, now, scts)?; } if !ocsp_response.is_empty() { trace!("Unvalidated OCSP response: {:?}", ocsp_response.to_vec()); } verify_server_name(&cert, server_name)?; Ok(ServerCertVerified::assertion()) } } /// Default `ServerCertVerifier`, see the trait impl for more information. #[allow(unreachable_pub)] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] pub struct WebPkiVerifier { roots: Arc, ct_policy: Option, } #[allow(unreachable_pub)] impl WebPkiVerifier { /// Constructs a new `WebPkiVerifier`. /// /// `roots` is the set of trust anchors to trust for issuing server certs. /// /// `ct_logs` is the list of logs that are trusted for Certificate /// Transparency. Currently CT log enforcement is opportunistic; see /// . pub fn new( roots: impl Into>, ct_policy: Option, ) -> Self { Self { roots: roots.into(), ct_policy, } } /// Returns the signature verification methods supported by /// webpki. pub fn verification_schemes() -> Vec { vec![ SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP256_SHA256, SignatureScheme::ED25519, SignatureScheme::RSA_PSS_SHA512, SignatureScheme::RSA_PSS_SHA384, SignatureScheme::RSA_PSS_SHA256, SignatureScheme::RSA_PKCS1_SHA512, SignatureScheme::RSA_PKCS1_SHA384, SignatureScheme::RSA_PKCS1_SHA256, ] } } /// Policy for enforcing Certificate Transparency. /// /// Because Certificate Transparency logs are sharded on a per-year basis and can be trusted or /// distrusted relatively quickly, rustls stores a validation deadline. Server certificates will /// be validated against the configured CT logs until the deadline expires. After the deadline, /// certificates will no longer be validated, and a warning message will be logged. The deadline /// may vary depending on how often you deploy builds with updated dependencies. #[allow(unreachable_pub)] #[cfg_attr(docsrs, doc(cfg(feature = "dangerous_configuration")))] pub struct CertificateTransparencyPolicy { logs: &'static [&'static sct::Log<'static>], validation_deadline: SystemTime, } impl CertificateTransparencyPolicy { /// Create a new policy. #[allow(unreachable_pub)] pub fn new( logs: &'static [&'static sct::Log<'static>], validation_deadline: SystemTime, ) -> Self { Self { logs, validation_deadline, } } fn verify( &self, cert: &Certificate, now: SystemTime, scts: &mut dyn Iterator, ) -> Result<(), Error> { if self.logs.is_empty() { return Ok(()); } else if self .validation_deadline .duration_since(now) .is_err() { warn!("certificate transparency logs have expired, validation disabled"); return Ok(()); } let now = unix_time_millis(now)?; let mut last_sct_error = None; for sct in scts { #[cfg_attr(not(feature = "logging"), allow(unused_variables))] match sct::verify_sct(&cert.0, sct, now, self.logs) { Ok(index) => { debug!( "Valid SCT signed by {} on {}", self.logs[index].operated_by, self.logs[index].description ); return Ok(()); } Err(e) => { if e.should_be_fatal() { return Err(Error::InvalidSct(e)); } debug!("SCT ignored because {:?}", e); last_sct_error = Some(e); } } } /* If we were supplied with some logs, and some SCTs, * but couldn't verify any of them, fail the handshake. */ if let Some(last_sct_error) = last_sct_error { warn!("No valid SCTs provided"); return Err(Error::InvalidSct(last_sct_error)); } Ok(()) } } fn intermediate_chain(intermediates: &[Certificate]) -> Vec<&[u8]> { intermediates .iter() .map(|cert| cert.0.as_ref()) .collect() } fn trust_roots(roots: &RootCertStore) -> Vec { roots .roots .iter() .map(OwnedTrustAnchor::to_trust_anchor) .collect() } /// An unparsed DER encoded Certificate Revocation List (CRL). pub struct UnparsedCertRevocationList(pub Vec); impl UnparsedCertRevocationList { /// Parse the CRL DER, yielding a [`webpki::CertRevocationList`] or an error if the CRL /// is malformed, or uses unsupported features. pub fn parse(&self) -> Result { webpki::BorrowedCertRevocationList::from_der(&self.0) .and_then(|crl| crl.to_owned()) .map_err(CertRevocationListError::from) } } /// A `ClientCertVerifier` that will ensure that every client provides a trusted /// certificate, without any name checking. Optionally, client certificates will /// have their revocation status checked using the DER encoded CRLs provided. pub struct AllowAnyAuthenticatedClient { roots: RootCertStore, subjects: Vec, crls: Vec, } impl AllowAnyAuthenticatedClient { /// Construct a new `AllowAnyAuthenticatedClient`. /// /// `roots` is the list of trust anchors to use for certificate validation. pub fn new(roots: RootCertStore) -> Self { Self { subjects: roots .roots .iter() .map(|r| r.subject().clone()) .collect(), crls: Vec::new(), roots, } } /// Update the verifier to validate client certificates against the provided DER format /// unparsed certificate revocation lists (CRLs). pub fn with_crls( self, crls: impl IntoIterator, ) -> Result { Ok(Self { crls: crls .into_iter() .map(|der_crl| der_crl.parse()) .collect::, CertRevocationListError>>()?, ..self }) } /// Wrap this verifier in an [`Arc`] and coerce it to `dyn ClientCertVerifier` #[inline(always)] pub fn boxed(self) -> Arc { // This function is needed because `ClientCertVerifier` is only reachable if the // `dangerous_configuration` feature is enabled, which makes coercing hard to outside users Arc::new(self) } } impl ClientCertVerifier for AllowAnyAuthenticatedClient { fn offer_client_auth(&self) -> bool { true } fn client_auth_root_subjects(&self) -> &[DistinguishedName] { &self.subjects } fn verify_client_cert( &self, end_entity: &Certificate, intermediates: &[Certificate], now: SystemTime, ) -> Result { let cert = ParsedCertificate::try_from(end_entity)?; let chain = intermediate_chain(intermediates); let trust_roots = trust_roots(&self.roots); let now = webpki::Time::try_from(now).map_err(|_| Error::FailedToGetCurrentTime)?; #[allow(trivial_casts)] // Cast to &dyn trait is required. let crls = self .crls .iter() .map(|crl| crl as &dyn webpki::CertRevocationList) .collect::>(); cert.0 .verify_for_usage( SUPPORTED_SIG_ALGS, &trust_roots, &chain, now, webpki::KeyUsage::client_auth(), crls.as_slice(), ) .map_err(pki_error) .map(|_| ClientCertVerified::assertion()) } } /// A `ClientCertVerifier` that will allow both anonymous and authenticated /// clients, without any name checking. /// /// Client authentication will be requested during the TLS handshake. If the /// client offers a certificate then this acts like /// `AllowAnyAuthenticatedClient`, otherwise this acts like `NoClientAuth`. pub struct AllowAnyAnonymousOrAuthenticatedClient { inner: AllowAnyAuthenticatedClient, } impl AllowAnyAnonymousOrAuthenticatedClient { /// Construct a new `AllowAnyAnonymousOrAuthenticatedClient`. /// /// `roots` is the list of trust anchors to use for certificate validation. pub fn new(roots: RootCertStore) -> Self { Self { inner: AllowAnyAuthenticatedClient::new(roots), } } /// Update the verifier to validate client certificates against the provided DER format /// unparsed certificate revocation lists (CRLs). pub fn with_crls( self, crls: impl IntoIterator, ) -> Result { Ok(Self { inner: self.inner.with_crls(crls)?, }) } /// Wrap this verifier in an [`Arc`] and coerce it to `dyn ClientCertVerifier` #[inline(always)] pub fn boxed(self) -> Arc { // This function is needed because `ClientCertVerifier` is only reachable if the // `dangerous_configuration` feature is enabled, which makes coercing hard to outside users Arc::new(self) } } impl ClientCertVerifier for AllowAnyAnonymousOrAuthenticatedClient { fn offer_client_auth(&self) -> bool { self.inner.offer_client_auth() } fn client_auth_mandatory(&self) -> bool { false } fn client_auth_root_subjects(&self) -> &[DistinguishedName] { self.inner.client_auth_root_subjects() } fn verify_client_cert( &self, end_entity: &Certificate, intermediates: &[Certificate], now: SystemTime, ) -> Result { self.inner .verify_client_cert(end_entity, intermediates, now) } } pub(crate) fn pki_error(error: webpki::Error) -> Error { use webpki::Error::*; match error { BadDer | BadDerTime => CertificateError::BadEncoding.into(), CertNotValidYet => CertificateError::NotValidYet.into(), CertExpired | InvalidCertValidity => CertificateError::Expired.into(), UnknownIssuer => CertificateError::UnknownIssuer.into(), CertNotValidForName => CertificateError::NotValidForName.into(), CertRevoked => CertificateError::Revoked.into(), IssuerNotCrlSigner => CertRevocationListError::IssuerInvalidForCrl.into(), InvalidSignatureForPublicKey | UnsupportedSignatureAlgorithm | UnsupportedSignatureAlgorithmForPublicKey => CertificateError::BadSignature.into(), InvalidCrlSignatureForPublicKey | UnsupportedCrlSignatureAlgorithm | UnsupportedCrlSignatureAlgorithmForPublicKey => { CertRevocationListError::BadSignature.into() } _ => CertificateError::Other(Arc::new(error)).into(), } } /// Turns off client authentication. pub struct NoClientAuth; impl NoClientAuth { /// Construct a [`NoClientAuth`], wrap it in an [`Arc`] and coerce it to /// `dyn ClientCertVerifier`. #[inline(always)] pub fn boxed() -> Arc { // This function is needed because `ClientCertVerifier` is only reachable if the // `dangerous_configuration` feature is enabled, which makes coercing hard to outside users Arc::new(Self) } } impl ClientCertVerifier for NoClientAuth { fn offer_client_auth(&self) -> bool { false } fn client_auth_root_subjects(&self) -> &[DistinguishedName] { unimplemented!(); } fn verify_client_cert( &self, _end_entity: &Certificate, _intermediates: &[Certificate], _now: SystemTime, ) -> Result { 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) -> 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) { self.scheme.encode(bytes); self.sig.encode(bytes); } fn read(r: &mut Reader) -> Result { let scheme = SignatureScheme::read(r)?; let sig = PayloadU16::read(r)?; Ok(Self { scheme, sig }) } } static ECDSA_SHA256: SignatureAlgorithms = &[&webpki::ECDSA_P256_SHA256, &webpki::ECDSA_P384_SHA256]; static ECDSA_SHA384: SignatureAlgorithms = &[&webpki::ECDSA_P256_SHA384, &webpki::ECDSA_P384_SHA384]; static ED25519: SignatureAlgorithms = &[&webpki::ED25519]; static RSA_SHA256: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA256]; static RSA_SHA384: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA384]; static RSA_SHA512: SignatureAlgorithms = &[&webpki::RSA_PKCS1_2048_8192_SHA512]; static RSA_PSS_SHA256: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY]; static RSA_PSS_SHA384: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY]; static RSA_PSS_SHA512: SignatureAlgorithms = &[&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY]; fn convert_scheme(scheme: SignatureScheme) -> Result { match scheme { // nb. for TLS1.2 the curve is not fixed by SignatureScheme. SignatureScheme::ECDSA_NISTP256_SHA256 => Ok(ECDSA_SHA256), SignatureScheme::ECDSA_NISTP384_SHA384 => Ok(ECDSA_SHA384), SignatureScheme::ED25519 => Ok(ED25519), SignatureScheme::RSA_PKCS1_SHA256 => Ok(RSA_SHA256), SignatureScheme::RSA_PKCS1_SHA384 => Ok(RSA_SHA384), SignatureScheme::RSA_PKCS1_SHA512 => Ok(RSA_SHA512), SignatureScheme::RSA_PSS_SHA256 => Ok(RSA_PSS_SHA256), SignatureScheme::RSA_PSS_SHA384 => Ok(RSA_PSS_SHA384), SignatureScheme::RSA_PSS_SHA512 => Ok(RSA_PSS_SHA512), _ => Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into()), } } fn verify_sig_using_any_alg( cert: &webpki::EndEntityCert, algs: SignatureAlgorithms, message: &[u8], sig: &[u8], ) -> Result<(), webpki::Error> { // TLS doesn't itself give us enough info to map to a single webpki::SignatureAlgorithm. // Therefore, convert_algs maps to several and we try them all. for alg in algs { match cert.verify_signature(alg, message, sig) { Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey) => continue, res => return res, } } Err(webpki::Error::UnsupportedSignatureAlgorithmForPublicKey) } fn verify_signed_struct( message: &[u8], cert: &Certificate, dss: &DigitallySignedStruct, ) -> Result { let possible_algs = convert_scheme(dss.scheme)?; let cert = webpki::EndEntityCert::try_from(cert.0.as_ref()).map_err(pki_error)?; verify_sig_using_any_alg(&cert, possible_algs, message, dss.signature()) .map_err(pki_error) .map(|_| HandshakeSignatureValid::assertion()) } fn convert_alg_tls13( scheme: SignatureScheme, ) -> Result<&'static webpki::SignatureAlgorithm, Error> { use crate::enums::SignatureScheme::*; match scheme { ECDSA_NISTP256_SHA256 => Ok(&webpki::ECDSA_P256_SHA256), ECDSA_NISTP384_SHA384 => Ok(&webpki::ECDSA_P384_SHA384), ED25519 => Ok(&webpki::ED25519), RSA_PSS_SHA256 => Ok(&webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY), RSA_PSS_SHA384 => Ok(&webpki::RSA_PSS_2048_8192_SHA384_LEGACY_KEY), RSA_PSS_SHA512 => Ok(&webpki::RSA_PSS_2048_8192_SHA512_LEGACY_KEY), _ => Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into()), } } /// Constructs the signature message specified in section 4.4.3 of RFC8446. pub(crate) fn construct_tls13_client_verify_message(handshake_hash: &Digest) -> Vec { construct_tls13_verify_message(handshake_hash, b"TLS 1.3, client CertificateVerify\x00") } /// Constructs the signature message specified in section 4.4.3 of RFC8446. pub(crate) fn construct_tls13_server_verify_message(handshake_hash: &Digest) -> Vec { construct_tls13_verify_message(handshake_hash, b"TLS 1.3, server CertificateVerify\x00") } fn construct_tls13_verify_message( handshake_hash: &Digest, context_string_with_0: &[u8], ) -> Vec { let mut msg = Vec::new(); msg.resize(64, 0x20u8); msg.extend_from_slice(context_string_with_0); msg.extend_from_slice(handshake_hash.as_ref()); msg } fn verify_tls13( msg: &[u8], cert: &Certificate, dss: &DigitallySignedStruct, ) -> Result { let alg = convert_alg_tls13(dss.scheme)?; let cert = webpki::EndEntityCert::try_from(cert.0.as_ref()).map_err(pki_error)?; cert.verify_signature(alg, msg, dss.signature()) .map_err(pki_error) .map(|_| HandshakeSignatureValid::assertion()) } fn unix_time_millis(now: SystemTime) -> Result { now.duration_since(std::time::UNIX_EPOCH) .map(|dur| dur.as_secs()) .map_err(|_| Error::FailedToGetCurrentTime) .and_then(|secs| { secs.checked_mul(1000) .ok_or(Error::FailedToGetCurrentTime) }) } #[cfg(test)] mod tests { use super::*; #[test] fn assertions_are_debug() { assert_eq!( format!("{:?}", ClientCertVerified::assertion()), "ClientCertVerified(())" ); assert_eq!( format!("{:?}", HandshakeSignatureValid::assertion()), "HandshakeSignatureValid(())" ); assert_eq!( format!("{:?}", FinishedMessageVerified::assertion()), "FinishedMessageVerified(())" ); assert_eq!( format!("{:?}", ServerCertVerified::assertion()), "ServerCertVerified(())" ); } #[test] fn pki_crl_errors() { // CRL signature errors should be turned into BadSignature. assert_eq!( pki_error(webpki::Error::InvalidCrlSignatureForPublicKey), Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), ); assert_eq!( pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithm), Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), ); assert_eq!( pki_error(webpki::Error::UnsupportedCrlSignatureAlgorithmForPublicKey), Error::InvalidCertRevocationList(CertRevocationListError::BadSignature), ); // 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) ); } } rustls-v-0.21.10/rustls/src/verifybench.rs000066400000000000000000000134271453461710000204570ustar00rootroot00000000000000// This program does benchmarking of the functions in verify.rs, // that do certificate chain validation and signature verification. // // Note: we don't use any of the standard 'cargo bench', 'test::Bencher', // etc. because it's unstable at the time of writing. use std::time::{Duration, Instant, SystemTime}; use crate::key; use crate::verify; use crate::verify::ServerCertVerifier; use crate::{anchors, OwnedTrustAnchor}; use webpki_roots; fn duration_nanos(d: Duration) -> u64 { ((d.as_secs() as f64) * 1e9 + (d.subsec_nanos() as f64)) as u64 } #[test] fn test_reddit_cert() { Context::new( "reddit", "reddit.com", &[ include_bytes!("testdata/cert-reddit.0.der"), include_bytes!("testdata/cert-reddit.1.der"), ], ) .bench(100) } #[test] fn test_github_cert() { Context::new( "github", "github.com", &[ include_bytes!("testdata/cert-github.0.der"), include_bytes!("testdata/cert-github.1.der"), ], ) .bench(100) } #[test] fn test_arstechnica_cert() { Context::new( "arstechnica", "arstechnica.com", &[ include_bytes!("testdata/cert-arstechnica.0.der"), include_bytes!("testdata/cert-arstechnica.1.der"), include_bytes!("testdata/cert-arstechnica.2.der"), include_bytes!("testdata/cert-arstechnica.3.der"), ], ) .bench(100) } #[test] fn test_servo_cert() { Context::new( "servo", "servo.org", &[ include_bytes!("testdata/cert-servo.0.der"), include_bytes!("testdata/cert-servo.1.der"), ], ) .bench(100) } #[test] fn test_twitter_cert() { Context::new( "twitter", "twitter.com", &[ include_bytes!("testdata/cert-twitter.0.der"), include_bytes!("testdata/cert-twitter.1.der"), ], ) .bench(100) } #[test] fn test_wikipedia_cert() { Context::new( "wikipedia", "wikipedia.org", &[ include_bytes!("testdata/cert-wikipedia.0.der"), include_bytes!("testdata/cert-wikipedia.1.der"), ], ) .bench(100) } #[test] fn test_google_cert() { Context::new( "google", "www.google.com", &[ include_bytes!("testdata/cert-google.0.der"), include_bytes!("testdata/cert-google.1.der"), ], ) .bench(100) } #[test] fn test_hn_cert() { Context::new( "hn", "news.ycombinator.com", &[ include_bytes!("testdata/cert-hn.0.der"), include_bytes!("testdata/cert-hn.1.der"), ], ) .bench(100) } #[test] fn test_stackoverflow_cert() { Context::new( "stackoverflow", "stackoverflow.com", &[ include_bytes!("testdata/cert-stackoverflow.0.der"), include_bytes!("testdata/cert-stackoverflow.1.der"), ], ) .bench(100) } #[test] fn test_duckduckgo_cert() { Context::new( "duckduckgo", "duckduckgo.com", &[ include_bytes!("testdata/cert-duckduckgo.0.der"), include_bytes!("testdata/cert-duckduckgo.1.der"), ], ) .bench(100) } #[test] fn test_rustlang_cert() { Context::new( "rustlang", "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"), ], ) .bench(100) } #[test] fn test_wapo_cert() { Context::new( "wapo", "www.washingtonpost.com", &[ include_bytes!("testdata/cert-wapo.0.der"), include_bytes!("testdata/cert-wapo.1.der"), ], ) .bench(100) } struct Context { name: &'static str, domain: &'static str, roots: anchors::RootCertStore, chain: Vec, now: SystemTime, } impl Context { fn new(name: &'static str, domain: &'static str, certs: &[&'static [u8]]) -> Self { let mut roots = anchors::RootCertStore::empty(); roots.add_trust_anchors( webpki_roots::TLS_SERVER_ROOTS .iter() .map(|ta| { OwnedTrustAnchor::from_subject_spki_name_constraints( ta.subject, ta.spki, ta.name_constraints, ) }), ); Self { name, domain, roots, chain: certs .iter() .copied() .map(|bytes| key::Certificate(bytes.to_vec())) .collect(), now: SystemTime::UNIX_EPOCH + Duration::from_secs(1640870720), } } fn bench(&self, count: usize) { let verifier = verify::WebPkiVerifier::new(self.roots.clone(), None); const SCTS: &[&[u8]] = &[]; const OCSP_RESPONSE: &[u8] = &[]; let mut times = Vec::new(); let (end_entity, intermediates) = self.chain.split_first().unwrap(); for _ in 0..count { let start = Instant::now(); let server_name = self.domain.try_into().unwrap(); verifier .verify_server_cert( end_entity, intermediates, &server_name, &mut SCTS.iter().copied(), OCSP_RESPONSE, self.now, ) .unwrap(); times.push(duration_nanos(Instant::now().duration_since(start))); } println!( "verify_server_cert({}): min {:?}us", self.name, times.iter().min().unwrap() / 1000 ); } } rustls-v-0.21.10/rustls/src/versions.rs000066400000000000000000000054221453461710000200170ustar00rootroot00000000000000use std::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`]. #[derive(Eq, PartialEq)] #[allow(clippy::manual_non_exhaustive)] // Fixed in main pub struct SupportedProtocolVersion { /// The TLS enumeration naming this version. pub version: ProtocolVersion, is_private: (), } 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, is_private: (), }; /// TLS1.3 pub static TLS13: SupportedProtocolVersion = SupportedProtocolVersion { version: ProtocolVersion::TLSv1_3, is_private: (), }; /// 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)] 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, } } } rustls-v-0.21.10/rustls/src/x509.rs000066400000000000000000000042671453461710000166620ustar00rootroot00000000000000// Additional x509/asn1 functions to those provided in webpki/ring. use ring::io::der; pub(crate) fn wrap_in_asn1_len(bytes: &mut Vec) { let len = bytes.len(); if len <= 0x7f { bytes.insert(0, len as u8); } else { bytes.insert(0, 0x80u8); let mut left = len; while left > 0 { let byte = (left & 0xff) as u8; bytes.insert(1, byte); bytes[0] += 1; left >>= 8; } } } /// Prepend stuff to `bytes` to put it in a DER SEQUENCE. pub(crate) fn wrap_in_sequence(bytes: &mut Vec) { wrap_in_asn1_len(bytes); bytes.insert(0, der::Tag::Sequence as u8); } #[test] fn test_empty() { let mut val = Vec::new(); wrap_in_sequence(&mut val); assert_eq!(vec![0x30, 0x00], val); } #[test] fn test_small() { let mut val = Vec::new(); val.insert(0, 0x00); val.insert(1, 0x11); val.insert(2, 0x22); val.insert(3, 0x33); wrap_in_sequence(&mut val); assert_eq!(vec![0x30, 0x04, 0x00, 0x11, 0x22, 0x33], val); } #[test] fn test_medium() { let mut val = Vec::new(); val.resize(255, 0x12); wrap_in_sequence(&mut val); assert_eq!(vec![0x30, 0x81, 0xff, 0x12, 0x12, 0x12], val[..6].to_vec()); } #[test] fn test_large() { let mut val = Vec::new(); val.resize(4660, 0x12); wrap_in_sequence(&mut val); assert_eq!(vec![0x30, 0x82, 0x12, 0x34, 0x12, 0x12], val[..6].to_vec()); } #[test] fn test_huge() { let mut val = Vec::new(); val.resize(0xffff, 0x12); wrap_in_sequence(&mut val); assert_eq!(vec![0x30, 0x82, 0xff, 0xff, 0x12, 0x12], val[..6].to_vec()); assert_eq!(val.len(), 0xffff + 4); } #[test] fn test_gigantic() { let mut val = Vec::new(); val.resize(0x100000, 0x12); wrap_in_sequence(&mut val); assert_eq!( vec![0x30, 0x83, 0x10, 0x00, 0x00, 0x12, 0x12], val[..7].to_vec() ); assert_eq!(val.len(), 0x100000 + 5); } #[test] fn test_ludicrous() { let mut val = Vec::new(); val.resize(0x1000000, 0x12); wrap_in_sequence(&mut val); assert_eq!( vec![0x30, 0x84, 0x01, 0x00, 0x00, 0x00, 0x12, 0x12], val[..8].to_vec() ); assert_eq!(val.len(), 0x1000000 + 6); } rustls-v-0.21.10/rustls/tests/000077500000000000000000000000001453461710000161515ustar00rootroot00000000000000rustls-v-0.21.10/rustls/tests/api.rs000066400000000000000000005073731453461710000173070ustar00rootroot00000000000000#![cfg_attr(read_buf, feature(read_buf))] #![cfg_attr(read_buf, feature(core_io_borrowed_buf))] //! Assorted public API tests. use std::cell::RefCell; use std::fmt; use std::io::{self, IoSlice, Read, Write}; use std::mem; use std::ops::{Deref, DerefMut}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use std::sync::Mutex; use rustls::client::{ResolvesClientCert, Resumption}; use rustls::internal::msgs::base::Payload; use rustls::internal::msgs::codec::Codec; use rustls::server::{AllowAnyAnonymousOrAuthenticatedClient, ClientHello, ResolvesServerCert}; #[cfg(feature = "secret_extraction")] use rustls::ConnectionTrafficSecrets; use rustls::{ sign, CertificateError, ConnectionCommon, Error, KeyLog, PeerIncompatible, PeerMisbehaved, SideData, }; use rustls::{CipherSuite, ProtocolVersion, SignatureScheme}; use rustls::{ClientConfig, ClientConnection}; use rustls::{ServerConfig, ServerConnection}; use rustls::{Stream, StreamOwned}; use rustls::{SupportedCipherSuite, ALL_CIPHER_SUITES}; mod common; use crate::common::*; fn alpn_test_error( server_protos: Vec>, client_protos: Vec>, agreed: Option<&[u8]>, expected_error: Option, ) { let mut server_config = make_server_config(KeyType::Rsa); server_config.alpn_protocols = server_protos; let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let mut client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); client_config.alpn_protocols = client_protos.clone(); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); assert_eq!(client.alpn_protocol(), None); assert_eq!(server.alpn_protocol(), None); let error = do_handshake_until_error(&mut client, &mut server); assert_eq!(client.alpn_protocol(), agreed); assert_eq!(server.alpn_protocol(), agreed); assert_eq!(error.err(), expected_error); } } fn alpn_test(server_protos: Vec>, client_protos: Vec>, agreed: Option<&[u8]>) { alpn_test_error(server_protos, client_protos, agreed, None) } #[test] fn alpn() { // no support alpn_test(vec![], vec![], None); // server support alpn_test(vec![b"server-proto".to_vec()], vec![], None); // client support alpn_test(vec![], vec![b"client-proto".to_vec()], None); // no overlap alpn_test_error( vec![b"server-proto".to_vec()], vec![b"client-proto".to_vec()], None, Some(ErrorFromPeer::Server(Error::NoApplicationProtocol)), ); // server chooses preference alpn_test( vec![b"server-proto".to_vec(), b"client-proto".to_vec()], vec![b"client-proto".to_vec(), b"server-proto".to_vec()], Some(b"server-proto"), ); // case sensitive alpn_test_error( vec![b"PROTO".to_vec()], vec![b"proto".to_vec()], None, Some(ErrorFromPeer::Server(Error::NoApplicationProtocol)), ); } fn version_test( client_versions: &[&'static rustls::SupportedProtocolVersion], server_versions: &[&'static rustls::SupportedProtocolVersion], result: Option, ) { let client_versions = if client_versions.is_empty() { rustls::ALL_VERSIONS } else { client_versions }; let server_versions = if server_versions.is_empty() { rustls::ALL_VERSIONS } else { server_versions }; let client_config = make_client_config_with_versions(KeyType::Rsa, client_versions); let server_config = make_server_config_with_versions(KeyType::Rsa, server_versions); println!( "version {:?} {:?} -> {:?}", client_versions, server_versions, result ); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); assert_eq!(client.protocol_version(), None); assert_eq!(server.protocol_version(), None); if result.is_none() { let err = do_handshake_until_error(&mut client, &mut server); assert!(err.is_err()); } else { do_handshake(&mut client, &mut server); assert_eq!(client.protocol_version(), result); assert_eq!(server.protocol_version(), result); } } #[test] fn versions() { // default -> 1.3 version_test(&[], &[], Some(ProtocolVersion::TLSv1_3)); // client default, server 1.2 -> 1.2 #[cfg(feature = "tls12")] version_test( &[], &[&rustls::version::TLS12], Some(ProtocolVersion::TLSv1_2), ); // client 1.2, server default -> 1.2 #[cfg(feature = "tls12")] version_test( &[&rustls::version::TLS12], &[], Some(ProtocolVersion::TLSv1_2), ); // client 1.2, server 1.3 -> fail #[cfg(feature = "tls12")] version_test(&[&rustls::version::TLS12], &[&rustls::version::TLS13], None); // client 1.3, server 1.2 -> fail #[cfg(feature = "tls12")] version_test(&[&rustls::version::TLS13], &[&rustls::version::TLS12], None); // client 1.3, server 1.2+1.3 -> 1.3 #[cfg(feature = "tls12")] version_test( &[&rustls::version::TLS13], &[&rustls::version::TLS12, &rustls::version::TLS13], Some(ProtocolVersion::TLSv1_3), ); // client 1.2+1.3, server 1.2 -> 1.2 #[cfg(feature = "tls12")] version_test( &[&rustls::version::TLS13, &rustls::version::TLS12], &[&rustls::version::TLS12], Some(ProtocolVersion::TLSv1_2), ); } fn check_read(reader: &mut dyn io::Read, bytes: &[u8]) { let mut buf = vec![0u8; bytes.len() + 1]; assert_eq!(bytes.len(), reader.read(&mut buf).unwrap()); assert_eq!(bytes, &buf[..bytes.len()]); } fn check_read_err(reader: &mut dyn io::Read, err_kind: io::ErrorKind) { let mut buf = vec![0u8; 1]; let err = reader.read(&mut buf).unwrap_err(); assert!(matches!(err, err if err.kind() == err_kind)) } #[cfg(read_buf)] fn check_read_buf(reader: &mut dyn io::Read, bytes: &[u8]) { use core::io::BorrowedBuf; use std::mem::MaybeUninit; let mut buf = [MaybeUninit::::uninit(); 128]; let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); reader.read_buf(buf.unfilled()).unwrap(); assert_eq!(buf.filled(), bytes); } #[cfg(read_buf)] fn check_read_buf_err(reader: &mut dyn io::Read, err_kind: io::ErrorKind) { use core::io::BorrowedBuf; use std::mem::MaybeUninit; let mut buf = [MaybeUninit::::uninit(); 1]; let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); let err = reader .read_buf(buf.unfilled()) .unwrap_err(); assert!(matches!(err, err if err.kind() == err_kind)) } #[test] fn config_builder_for_client_rejects_empty_kx_groups() { assert_eq!( ClientConfig::builder() .with_safe_default_cipher_suites() .with_kx_groups(&[]) .with_safe_default_protocol_versions() .err(), Some(Error::General("no kx groups configured".into())) ); } #[test] fn config_builder_for_client_rejects_empty_cipher_suites() { assert_eq!( ClientConfig::builder() .with_cipher_suites(&[]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .err(), Some(Error::General("no usable cipher suites configured".into())) ); } #[cfg(feature = "tls12")] #[test] fn config_builder_for_client_rejects_incompatible_cipher_suites() { assert_eq!( ClientConfig::builder() .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS12]) .err(), Some(Error::General("no usable cipher suites configured".into())) ); } #[test] fn config_builder_for_server_rejects_empty_kx_groups() { assert_eq!( ServerConfig::builder() .with_safe_default_cipher_suites() .with_kx_groups(&[]) .with_safe_default_protocol_versions() .err(), Some(Error::General("no kx groups configured".into())) ); } #[test] fn config_builder_for_server_rejects_empty_cipher_suites() { assert_eq!( ServerConfig::builder() .with_cipher_suites(&[]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .err(), Some(Error::General("no usable cipher suites configured".into())) ); } #[cfg(feature = "tls12")] #[test] fn config_builder_for_server_rejects_incompatible_cipher_suites() { assert_eq!( ServerConfig::builder() .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS12]) .err(), Some(Error::General("no usable cipher suites configured".into())) ); } #[test] fn buffered_client_data_sent() { let server_config = Arc::new(make_server_config(KeyType::Rsa)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); assert_eq!(5, client.writer().write(b"hello").unwrap()); do_handshake(&mut client, &mut server); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); check_read(&mut server.reader(), b"hello"); } } #[test] fn buffered_server_data_sent() { let server_config = Arc::new(make_server_config(KeyType::Rsa)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); assert_eq!(5, server.writer().write(b"hello").unwrap()); do_handshake(&mut client, &mut server); transfer(&mut server, &mut client); client.process_new_packets().unwrap(); check_read(&mut client.reader(), b"hello"); } } #[test] fn buffered_both_data_sent() { let server_config = Arc::new(make_server_config(KeyType::Rsa)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); assert_eq!( 12, server .writer() .write(b"from-server!") .unwrap() ); assert_eq!( 12, client .writer() .write(b"from-client!") .unwrap() ); do_handshake(&mut client, &mut server); transfer(&mut server, &mut client); client.process_new_packets().unwrap(); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); check_read(&mut client.reader(), b"from-server!"); check_read(&mut server.reader(), b"from-client!"); } } #[test] fn client_can_get_server_cert() { for kt in ALL_KEY_TYPES.iter() { for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(*kt, &[version]); let (mut client, mut server) = make_pair_for_configs(client_config, make_server_config(*kt)); do_handshake(&mut client, &mut server); let certs = client.peer_certificates(); assert_eq!(certs, Some(kt.get_chain().as_slice())); } } } #[test] fn client_can_get_server_cert_after_resumption() { for kt in ALL_KEY_TYPES.iter() { let server_config = make_server_config(*kt); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(*kt, &[version]); let (mut client, mut server) = make_pair_for_configs(client_config.clone(), server_config.clone()); do_handshake(&mut client, &mut server); let original_certs = client.peer_certificates(); let (mut client, mut server) = make_pair_for_configs(client_config.clone(), server_config.clone()); do_handshake(&mut client, &mut server); let resumed_certs = client.peer_certificates(); assert_eq!(original_certs, resumed_certs); } } } #[test] fn server_can_get_client_cert() { for kt in ALL_KEY_TYPES.iter() { let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); let certs = server.peer_certificates(); assert_eq!(certs, Some(kt.get_client_chain().as_slice())); } } } #[test] fn server_can_get_client_cert_after_resumption() { for kt in ALL_KEY_TYPES.iter() { let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); let client_config = Arc::new(client_config); let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); let original_certs = server.peer_certificates(); let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); let resumed_certs = server.peer_certificates(); assert_eq!(original_certs, resumed_certs); } } } #[test] fn test_config_builders_debug() { let b = ServerConfig::builder(); assert_eq!( "ConfigBuilder { state: WantsCipherSuites(()) }", format!("{:?}", b) ); let b = b.with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256] } }", format!("{:?}", b)); let b = b.with_kx_groups(&[&rustls::kx_group::X25519]); assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519] } }", format!("{:?}", b)); let b = b .with_protocol_versions(&[&rustls::version::TLS13]) .unwrap(); let b = b.with_no_client_auth(); assert_eq!("ConfigBuilder { state: WantsServerCert { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], versions: [TLSv1_3], verifier: dyn ClientCertVerifier } }", format!("{:?}", b)); let b = ClientConfig::builder(); assert_eq!( "ConfigBuilder { state: WantsCipherSuites(()) }", format!("{:?}", b) ); let b = b.with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]); assert_eq!("ConfigBuilder { state: WantsKxGroups { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256] } }", format!("{:?}", b)); let b = b.with_kx_groups(&[&rustls::kx_group::X25519]); assert_eq!("ConfigBuilder { state: WantsVersions { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519] } }", format!("{:?}", b)); let b = b .with_protocol_versions(&[&rustls::version::TLS13]) .unwrap(); assert_eq!("ConfigBuilder { state: WantsVerifier { cipher_suites: [TLS13_CHACHA20_POLY1305_SHA256], kx_groups: [X25519], versions: [TLSv1_3] } }", format!("{:?}", b)); } /// Test that the server handles combination of `offer_client_auth()` returning true /// and `client_auth_mandatory` returning `Some(false)`. This exercises both the /// client's and server's ability to "recover" from the server asking for a client /// certificate and not being given one. This also covers the implementation /// of `AllowAnyAnonymousOrAuthenticatedClient`. #[test] fn server_allow_any_anonymous_or_authenticated_client() { let kt = KeyType::Rsa; for client_cert_chain in [None, Some(kt.get_client_chain())].iter() { let client_auth_roots = get_client_root_store(kt); let client_auth = AllowAnyAnonymousOrAuthenticatedClient::new(client_auth_roots); let server_config = ServerConfig::builder() .with_safe_defaults() .with_client_cert_verifier(Arc::new(client_auth)) .with_single_cert(kt.get_chain(), kt.get_key()) .unwrap(); let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let client_config = if client_cert_chain.is_some() { make_client_config_with_versions_with_auth(kt, &[version]) } else { make_client_config_with_versions(kt, &[version]) }; let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); let certs = server.peer_certificates(); assert_eq!(certs, client_cert_chain.as_deref()); } } } fn check_read_and_close(reader: &mut dyn io::Read, expect: &[u8]) { check_read(reader, expect); assert!(matches!(reader.read(&mut [0u8; 5]), Ok(0))); } #[test] fn server_close_notify() { let kt = KeyType::Rsa; let server_config = Arc::new(make_server_config_with_mandatory_client_auth(kt)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); // check that alerts don't overtake appdata assert_eq!( 12, server .writer() .write(b"from-server!") .unwrap() ); assert_eq!( 12, client .writer() .write(b"from-client!") .unwrap() ); server.send_close_notify(); transfer(&mut server, &mut client); let io_state = client.process_new_packets().unwrap(); assert!(io_state.peer_has_closed()); check_read_and_close(&mut client.reader(), b"from-server!"); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); check_read(&mut server.reader(), b"from-client!"); } } #[test] fn client_close_notify() { let kt = KeyType::Rsa; let server_config = Arc::new(make_server_config_with_mandatory_client_auth(kt)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); // check that alerts don't overtake appdata assert_eq!( 12, server .writer() .write(b"from-server!") .unwrap() ); assert_eq!( 12, client .writer() .write(b"from-client!") .unwrap() ); client.send_close_notify(); transfer(&mut client, &mut server); let io_state = server.process_new_packets().unwrap(); assert!(io_state.peer_has_closed()); check_read_and_close(&mut server.reader(), b"from-client!"); transfer(&mut server, &mut client); client.process_new_packets().unwrap(); check_read(&mut client.reader(), b"from-server!"); } } #[test] fn server_closes_uncleanly() { let kt = KeyType::Rsa; let server_config = Arc::new(make_server_config(kt)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); // check that unclean EOF reporting does not overtake appdata assert_eq!( 12, server .writer() .write(b"from-server!") .unwrap() ); assert_eq!( 12, client .writer() .write(b"from-client!") .unwrap() ); transfer(&mut server, &mut client); transfer_eof(&mut client); let io_state = client.process_new_packets().unwrap(); assert!(!io_state.peer_has_closed()); check_read(&mut client.reader(), b"from-server!"); check_read_err( &mut client.reader() as &mut dyn io::Read, io::ErrorKind::UnexpectedEof, ); // may still transmit pending frames transfer(&mut client, &mut server); server.process_new_packets().unwrap(); check_read(&mut server.reader(), b"from-client!"); } } #[test] fn client_closes_uncleanly() { let kt = KeyType::Rsa; let server_config = Arc::new(make_server_config(kt)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); // check that unclean EOF reporting does not overtake appdata assert_eq!( 12, server .writer() .write(b"from-server!") .unwrap() ); assert_eq!( 12, client .writer() .write(b"from-client!") .unwrap() ); transfer(&mut client, &mut server); transfer_eof(&mut server); let io_state = server.process_new_packets().unwrap(); assert!(!io_state.peer_has_closed()); check_read(&mut server.reader(), b"from-client!"); check_read_err( &mut server.reader() as &mut dyn io::Read, io::ErrorKind::UnexpectedEof, ); // may still transmit pending frames transfer(&mut server, &mut client); client.process_new_packets().unwrap(); check_read(&mut client.reader(), b"from-server!"); } } #[derive(Default)] struct ServerCheckCertResolve { expected_sni: Option, expected_sigalgs: Option>, expected_alpn: Option>>, expected_cipher_suites: Option>, } impl ResolvesServerCert for ServerCheckCertResolve { fn resolve(&self, client_hello: ClientHello) -> Option> { if client_hello .signature_schemes() .is_empty() { panic!("no signature schemes shared by client"); } if client_hello.cipher_suites().is_empty() { panic!("no cipher suites shared by client"); } if let Some(expected_sni) = &self.expected_sni { let sni: &str = client_hello .server_name() .expect("sni unexpectedly absent"); assert_eq!(expected_sni, sni); } if let Some(expected_sigalgs) = &self.expected_sigalgs { assert_eq!( expected_sigalgs, client_hello.signature_schemes(), "unexpected signature schemes" ); } if let Some(expected_alpn) = &self.expected_alpn { let alpn = client_hello .alpn() .expect("alpn unexpectedly absent") .collect::>(); assert_eq!(alpn.len(), expected_alpn.len()); for (got, wanted) in alpn.iter().zip(expected_alpn.iter()) { assert_eq!(got, &wanted.as_slice()); } } if let Some(expected_cipher_suites) = &self.expected_cipher_suites { assert_eq!( expected_cipher_suites, client_hello.cipher_suites(), "unexpected cipher suites" ); } None } } #[test] fn server_cert_resolve_with_sni() { for kt in ALL_KEY_TYPES.iter() { let client_config = make_client_config(*kt); let mut server_config = make_server_config(*kt); server_config.cert_resolver = Arc::new(ServerCheckCertResolve { expected_sni: Some("the-value-from-sni".into()), ..Default::default() }); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("the-value-from-sni")).unwrap(); let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); let err = do_handshake_until_error(&mut client, &mut server); assert!(err.is_err()); } } #[test] fn server_cert_resolve_with_alpn() { for kt in ALL_KEY_TYPES.iter() { let mut client_config = make_client_config(*kt); client_config.alpn_protocols = vec!["foo".into(), "bar".into()]; let mut server_config = make_server_config(*kt); server_config.cert_resolver = Arc::new(ServerCheckCertResolve { expected_alpn: Some(vec![b"foo".to_vec(), b"bar".to_vec()]), ..Default::default() }); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("sni-value")).unwrap(); let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); let err = do_handshake_until_error(&mut client, &mut server); assert!(err.is_err()); } } #[test] fn client_trims_terminating_dot() { for kt in ALL_KEY_TYPES.iter() { let client_config = make_client_config(*kt); let mut server_config = make_server_config(*kt); server_config.cert_resolver = Arc::new(ServerCheckCertResolve { expected_sni: Some("some-host.com".into()), ..Default::default() }); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("some-host.com.")).unwrap(); let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); let err = do_handshake_until_error(&mut client, &mut server); assert!(err.is_err()); } } #[cfg(feature = "tls12")] fn check_sigalgs_reduced_by_ciphersuite( kt: KeyType, suite: CipherSuite, expected_sigalgs: Vec, ) { let client_config = finish_client_config( kt, ClientConfig::builder() .with_cipher_suites(&[find_suite(suite)]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .unwrap(), ); let mut server_config = make_server_config(kt); server_config.cert_resolver = Arc::new(ServerCheckCertResolve { expected_sigalgs: Some(expected_sigalgs), expected_cipher_suites: Some(vec![suite, CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV]), ..Default::default() }); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); let mut server = ServerConnection::new(Arc::new(server_config)).unwrap(); let err = do_handshake_until_error(&mut client, &mut server); assert!(err.is_err()); } #[cfg(feature = "tls12")] #[test] fn server_cert_resolve_reduces_sigalgs_for_rsa_ciphersuite() { check_sigalgs_reduced_by_ciphersuite( KeyType::Rsa, CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, vec![ SignatureScheme::RSA_PSS_SHA512, SignatureScheme::RSA_PSS_SHA384, SignatureScheme::RSA_PSS_SHA256, SignatureScheme::RSA_PKCS1_SHA512, SignatureScheme::RSA_PKCS1_SHA384, SignatureScheme::RSA_PKCS1_SHA256, ], ); } #[cfg(feature = "tls12")] #[test] fn server_cert_resolve_reduces_sigalgs_for_ecdsa_ciphersuite() { check_sigalgs_reduced_by_ciphersuite( KeyType::Ecdsa, CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, vec![ SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP256_SHA256, SignatureScheme::ED25519, ], ); } struct ServerCheckNoSNI {} impl ResolvesServerCert for ServerCheckNoSNI { fn resolve(&self, client_hello: ClientHello) -> Option> { assert!(client_hello.server_name().is_none()); None } } #[test] fn client_with_sni_disabled_does_not_send_sni() { for kt in ALL_KEY_TYPES.iter() { let mut server_config = make_server_config(*kt); server_config.cert_resolver = Arc::new(ServerCheckNoSNI {}); let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let mut client_config = make_client_config_with_versions(*kt, &[version]); client_config.enable_sni = false; let mut client = ClientConnection::new(Arc::new(client_config), dns_name("value-not-sent")).unwrap(); let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let err = do_handshake_until_error(&mut client, &mut server); assert!(err.is_err()); } } } #[test] fn client_checks_server_certificate_with_given_name() { for kt in ALL_KEY_TYPES.iter() { let server_config = Arc::new(make_server_config(*kt)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(*kt, &[version]); let mut client = ClientConnection::new( Arc::new(client_config), dns_name("not-the-right-hostname.com"), ) .unwrap(); let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let err = do_handshake_until_error(&mut client, &mut server); assert_eq!( err, Err(ErrorFromPeer::Client(Error::InvalidCertificate( CertificateError::NotValidForName ))) ); } } } struct ClientCheckCertResolve { query_count: AtomicUsize, expect_queries: usize, expect_issuers: Vec>, expect_sigschemes: Vec, } impl ClientCheckCertResolve { fn new( expect_queries: usize, expect_issuers: Vec>, expect_sigschemes: Vec, ) -> Self { Self { query_count: AtomicUsize::new(0), expect_queries, expect_issuers, expect_sigschemes, } } } impl Drop for ClientCheckCertResolve { fn drop(&mut self) { if !std::thread::panicking() { let count = self.query_count.load(Ordering::SeqCst); assert_eq!(count, self.expect_queries); } } } impl ResolvesClientCert for ClientCheckCertResolve { fn resolve( &self, acceptable_issuers: &[&[u8]], sigschemes: &[SignatureScheme], ) -> Option> { self.query_count .fetch_add(1, Ordering::SeqCst); if acceptable_issuers.is_empty() { panic!("no issuers offered by server"); } if sigschemes.is_empty() { panic!("no signature schemes shared by server"); } assert_eq!(acceptable_issuers, self.expect_issuers); assert_eq!(sigschemes, self.expect_sigschemes); None } fn has_certs(&self) -> bool { true } } #[test] fn client_cert_resolve() { for kt in ALL_KEY_TYPES.iter() { let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); let expected_issuers = match *kt { KeyType::Rsa => vec![ b"0,1*0(\x06\x03U\x04\x03\x0c!ponytown RSA level 2 intermediate".to_vec(), b"0\x1a1\x180\x16\x06\x03U\x04\x03\x0c\x0fponytown RSA CA".to_vec(), ], KeyType::Ecdsa => vec![ b"0.1,0*\x06\x03U\x04\x03\x0c#ponytown ECDSA level 2 intermediate".to_vec(), b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown ECDSA CA".to_vec(), ], KeyType::Ed25519 => vec![ b"0.1,0*\x06\x03U\x04\x03\x0c#ponytown EdDSA level 2 intermediate".to_vec(), b"0\x1c1\x1a0\x18\x06\x03U\x04\x03\x0c\x11ponytown EdDSA CA".to_vec(), ], }; for version in rustls::ALL_VERSIONS { let expected_sigschemes = match version.version { ProtocolVersion::TLSv1_2 => vec![ SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP256_SHA256, SignatureScheme::ED25519, SignatureScheme::RSA_PSS_SHA512, SignatureScheme::RSA_PSS_SHA384, SignatureScheme::RSA_PSS_SHA256, SignatureScheme::RSA_PKCS1_SHA512, SignatureScheme::RSA_PKCS1_SHA384, SignatureScheme::RSA_PKCS1_SHA256, ], ProtocolVersion::TLSv1_3 => vec![ SignatureScheme::ECDSA_NISTP384_SHA384, SignatureScheme::ECDSA_NISTP256_SHA256, SignatureScheme::ED25519, SignatureScheme::RSA_PSS_SHA512, SignatureScheme::RSA_PSS_SHA384, SignatureScheme::RSA_PSS_SHA256, ], _ => unreachable!(), }; println!("{:?} {:?}:", version.version, *kt); let mut client_config = make_client_config_with_versions(*kt, &[version]); client_config.client_auth_cert_resolver = Arc::new(ClientCheckCertResolve::new( 1, expected_issuers.clone(), expected_sigschemes, )); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); assert_eq!( do_handshake_until_error(&mut client, &mut server), Err(ErrorFromPeer::Server(Error::NoCertificatesPresented)) ); } } } #[test] fn client_auth_works() { for kt in ALL_KEY_TYPES.iter() { let server_config = Arc::new(make_server_config_with_mandatory_client_auth(*kt)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); } } } #[test] fn client_mandatory_auth_revocation_works() { for kt in ALL_KEY_TYPES.iter() { // Create a server configuration that includes a CRL that specifies the client certificate // is revoked. let crls = vec![kt.client_crl()]; let server_config = Arc::new(make_server_config_with_mandatory_client_auth_crls( *kt, crls, )); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); // Because the client certificate is revoked, the handshake should fail. let err = do_handshake_until_error(&mut client, &mut server); assert_eq!( err, Err(ErrorFromPeer::Server(Error::InvalidCertificate( CertificateError::Revoked ))) ); } } } #[test] fn client_optional_auth_revocation_works() { for kt in ALL_KEY_TYPES.iter() { // Create a server configuration that includes a CRL that specifies the client certificate // is revoked. let crls = vec![kt.client_crl()]; let server_config = Arc::new(make_server_config_with_optional_client_auth(*kt, crls)); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); // Because the client certificate is revoked, the handshake should fail. let err = do_handshake_until_error(&mut client, &mut server); assert_eq!( err, Err(ErrorFromPeer::Server(Error::InvalidCertificate( CertificateError::Revoked ))) ); } } } #[test] fn client_error_is_sticky() { let (mut client, _) = make_pair(KeyType::Rsa); client .read_tls(&mut b"\x16\x03\x03\x00\x08\x0f\x00\x00\x04junk".as_ref()) .unwrap(); let mut err = client.process_new_packets(); assert!(err.is_err()); err = client.process_new_packets(); assert!(err.is_err()); } #[test] fn server_error_is_sticky() { let (_, mut server) = make_pair(KeyType::Rsa); server .read_tls(&mut b"\x16\x03\x03\x00\x08\x0f\x00\x00\x04junk".as_ref()) .unwrap(); let mut err = server.process_new_packets(); assert!(err.is_err()); err = server.process_new_packets(); assert!(err.is_err()); } #[test] fn server_flush_does_nothing() { let (_, mut server) = make_pair(KeyType::Rsa); assert!(matches!(server.writer().flush(), Ok(()))); } #[test] fn client_flush_does_nothing() { let (mut client, _) = make_pair(KeyType::Rsa); assert!(matches!(client.writer().flush(), Ok(()))); } #[test] fn server_is_send_and_sync() { let (_, server) = make_pair(KeyType::Rsa); &server as &dyn Send; &server as &dyn Sync; } #[test] fn client_is_send_and_sync() { let (client, _) = make_pair(KeyType::Rsa); &client as &dyn Send; &client as &dyn Sync; } #[test] fn server_respects_buffer_limit_pre_handshake() { let (mut client, mut server) = make_pair(KeyType::Rsa); server.set_buffer_limit(Some(32)); assert_eq!( server .writer() .write(b"01234567890123456789") .unwrap(), 20 ); assert_eq!( server .writer() .write(b"01234567890123456789") .unwrap(), 12 ); do_handshake(&mut client, &mut server); transfer(&mut server, &mut client); client.process_new_packets().unwrap(); check_read(&mut client.reader(), b"01234567890123456789012345678901"); } #[test] fn server_respects_buffer_limit_pre_handshake_with_vectored_write() { let (mut client, mut server) = make_pair(KeyType::Rsa); server.set_buffer_limit(Some(32)); assert_eq!( server .writer() .write_vectored(&[ IoSlice::new(b"01234567890123456789"), IoSlice::new(b"01234567890123456789") ]) .unwrap(), 32 ); do_handshake(&mut client, &mut server); transfer(&mut server, &mut client); client.process_new_packets().unwrap(); check_read(&mut client.reader(), b"01234567890123456789012345678901"); } #[test] fn server_respects_buffer_limit_post_handshake() { let (mut client, mut server) = make_pair(KeyType::Rsa); // this test will vary in behaviour depending on the default suites do_handshake(&mut client, &mut server); server.set_buffer_limit(Some(48)); assert_eq!( server .writer() .write(b"01234567890123456789") .unwrap(), 20 ); assert_eq!( server .writer() .write(b"01234567890123456789") .unwrap(), 6 ); transfer(&mut server, &mut client); client.process_new_packets().unwrap(); check_read(&mut client.reader(), b"01234567890123456789012345"); } #[test] fn client_respects_buffer_limit_pre_handshake() { let (mut client, mut server) = make_pair(KeyType::Rsa); client.set_buffer_limit(Some(32)); assert_eq!( client .writer() .write(b"01234567890123456789") .unwrap(), 20 ); assert_eq!( client .writer() .write(b"01234567890123456789") .unwrap(), 12 ); do_handshake(&mut client, &mut server); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); check_read(&mut server.reader(), b"01234567890123456789012345678901"); } #[test] fn client_respects_buffer_limit_pre_handshake_with_vectored_write() { let (mut client, mut server) = make_pair(KeyType::Rsa); client.set_buffer_limit(Some(32)); assert_eq!( client .writer() .write_vectored(&[ IoSlice::new(b"01234567890123456789"), IoSlice::new(b"01234567890123456789") ]) .unwrap(), 32 ); do_handshake(&mut client, &mut server); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); check_read(&mut server.reader(), b"01234567890123456789012345678901"); } #[test] fn client_respects_buffer_limit_post_handshake() { let (mut client, mut server) = make_pair(KeyType::Rsa); do_handshake(&mut client, &mut server); client.set_buffer_limit(Some(48)); assert_eq!( client .writer() .write(b"01234567890123456789") .unwrap(), 20 ); assert_eq!( client .writer() .write(b"01234567890123456789") .unwrap(), 6 ); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); check_read(&mut server.reader(), b"01234567890123456789012345"); } struct OtherSession<'a, C, S> where C: DerefMut + Deref>, S: SideData, { sess: &'a mut C, pub reads: usize, pub writevs: Vec>, fail_ok: bool, pub short_writes: bool, pub last_error: Option, pub buffered: bool, buffer: Vec>, } impl<'a, C, S> OtherSession<'a, C, S> where C: DerefMut + Deref>, S: SideData, { fn new(sess: &'a mut C) -> OtherSession<'a, C, S> { OtherSession { sess, reads: 0, writevs: vec![], fail_ok: false, short_writes: false, last_error: None, buffered: false, buffer: vec![], } } fn new_buffered(sess: &'a mut C) -> OtherSession<'a, C, S> { let mut os = OtherSession::new(sess); os.buffered = true; os } fn new_fails(sess: &'a mut C) -> OtherSession<'a, C, S> { let mut os = OtherSession::new(sess); os.fail_ok = true; os } fn flush_vectored(&mut self, b: &[io::IoSlice<'_>]) -> io::Result { let mut total = 0; let mut lengths = vec![]; for bytes in b { let write_len = if self.short_writes { if bytes.len() > 5 { bytes.len() / 2 } else { bytes.len() } } else { bytes.len() }; let l = self .sess .read_tls(&mut io::Cursor::new(&bytes[..write_len]))?; lengths.push(l); total += l; if bytes.len() != l { break; } } let rc = self.sess.process_new_packets(); if !self.fail_ok { rc.unwrap(); } else if rc.is_err() { self.last_error = rc.err(); } self.writevs.push(lengths); Ok(total) } } impl<'a, C, S> io::Read for OtherSession<'a, C, S> where C: DerefMut + Deref>, S: SideData, { fn read(&mut self, mut b: &mut [u8]) -> io::Result { self.reads += 1; self.sess.write_tls(b.by_ref()) } } impl<'a, C, S> io::Write for OtherSession<'a, C, S> where C: DerefMut + Deref>, S: SideData, { fn write(&mut self, _: &[u8]) -> io::Result { unreachable!() } fn flush(&mut self) -> io::Result<()> { if !self.buffer.is_empty() { let buffer = mem::take(&mut self.buffer); let slices = buffer .iter() .map(|b| io::IoSlice::new(b)) .collect::>(); self.flush_vectored(&slices)?; } Ok(()) } fn write_vectored(&mut self, b: &[io::IoSlice<'_>]) -> io::Result { if self.buffered { self.buffer .extend(b.iter().map(|s| s.to_vec())); return Ok(b.iter().map(|s| s.len()).sum()); } self.flush_vectored(b) } } #[test] fn server_read_returns_wouldblock_when_no_data() { let (_, mut server) = make_pair(KeyType::Rsa); assert!(matches!(server.reader().read(&mut [0u8; 1]), Err(err) if err.kind() == io::ErrorKind::WouldBlock)); } #[test] fn client_read_returns_wouldblock_when_no_data() { let (mut client, _) = make_pair(KeyType::Rsa); assert!(matches!(client.reader().read(&mut [0u8; 1]), Err(err) if err.kind() == io::ErrorKind::WouldBlock)); } #[test] fn new_server_returns_initial_io_state() { let (_, mut server) = make_pair(KeyType::Rsa); let io_state = server.process_new_packets().unwrap(); println!("IoState is Debug {:?}", io_state); assert_eq!(io_state.plaintext_bytes_to_read(), 0); assert!(!io_state.peer_has_closed()); assert_eq!(io_state.tls_bytes_to_write(), 0); } #[test] fn new_client_returns_initial_io_state() { let (mut client, _) = make_pair(KeyType::Rsa); let io_state = client.process_new_packets().unwrap(); println!("IoState is Debug {:?}", io_state); assert_eq!(io_state.plaintext_bytes_to_read(), 0); assert!(!io_state.peer_has_closed()); assert!(io_state.tls_bytes_to_write() > 200); } #[test] fn client_complete_io_for_handshake() { let (mut client, mut server) = make_pair(KeyType::Rsa); assert!(client.is_handshaking()); let (rdlen, wrlen) = client .complete_io(&mut OtherSession::new(&mut server)) .unwrap(); assert!(rdlen > 0 && wrlen > 0); assert!(!client.is_handshaking()); assert!(!client.wants_write()); } #[test] fn buffered_client_complete_io_for_handshake() { let (mut client, mut server) = make_pair(KeyType::Rsa); assert!(client.is_handshaking()); let (rdlen, wrlen) = client .complete_io(&mut OtherSession::new_buffered(&mut server)) .unwrap(); assert!(rdlen > 0 && wrlen > 0); assert!(!client.is_handshaking()); assert!(!client.wants_write()); } #[test] fn client_complete_io_for_handshake_eof() { let (mut client, _) = make_pair(KeyType::Rsa); let mut input = io::Cursor::new(Vec::new()); assert!(client.is_handshaking()); let err = client .complete_io(&mut input) .unwrap_err(); assert_eq!(io::ErrorKind::UnexpectedEof, err.kind()); } #[test] fn client_complete_io_for_write() { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); do_handshake(&mut client, &mut server); client .writer() .write_all(b"01234567890123456789") .unwrap(); client .writer() .write_all(b"01234567890123456789") .unwrap(); { let mut pipe = OtherSession::new(&mut server); let (rdlen, wrlen) = client.complete_io(&mut pipe).unwrap(); assert!(rdlen == 0 && wrlen > 0); println!("{:?}", pipe.writevs); assert_eq!(pipe.writevs, vec![vec![42, 42]]); } check_read( &mut server.reader(), b"0123456789012345678901234567890123456789", ); } } #[test] fn buffered_client_complete_io_for_write() { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); do_handshake(&mut client, &mut server); client .writer() .write_all(b"01234567890123456789") .unwrap(); client .writer() .write_all(b"01234567890123456789") .unwrap(); { let mut pipe = OtherSession::new_buffered(&mut server); let (rdlen, wrlen) = client.complete_io(&mut pipe).unwrap(); assert!(rdlen == 0 && wrlen > 0); println!("{:?}", pipe.writevs); assert_eq!(pipe.writevs, vec![vec![42, 42]]); } check_read( &mut server.reader(), b"0123456789012345678901234567890123456789", ); } } #[test] fn client_complete_io_for_read() { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); do_handshake(&mut client, &mut server); server .writer() .write_all(b"01234567890123456789") .unwrap(); { let mut pipe = OtherSession::new(&mut server); let (rdlen, wrlen) = client.complete_io(&mut pipe).unwrap(); assert!(rdlen > 0 && wrlen == 0); assert_eq!(pipe.reads, 1); } check_read(&mut client.reader(), b"01234567890123456789"); } } #[test] fn server_complete_io_for_handshake() { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); assert!(server.is_handshaking()); let (rdlen, wrlen) = server .complete_io(&mut OtherSession::new(&mut client)) .unwrap(); assert!(rdlen > 0 && wrlen > 0); assert!(!server.is_handshaking()); assert!(!server.wants_write()); } } #[test] fn server_complete_io_for_handshake_eof() { let (_, mut server) = make_pair(KeyType::Rsa); let mut input = io::Cursor::new(Vec::new()); assert!(server.is_handshaking()); let err = server .complete_io(&mut input) .unwrap_err(); assert_eq!(io::ErrorKind::UnexpectedEof, err.kind()); } #[test] fn server_complete_io_for_write() { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); do_handshake(&mut client, &mut server); server .writer() .write_all(b"01234567890123456789") .unwrap(); server .writer() .write_all(b"01234567890123456789") .unwrap(); { let mut pipe = OtherSession::new(&mut client); let (rdlen, wrlen) = server.complete_io(&mut pipe).unwrap(); assert!(rdlen == 0 && wrlen > 0); assert_eq!(pipe.writevs, vec![vec![42, 42]]); } check_read( &mut client.reader(), b"0123456789012345678901234567890123456789", ); } } #[test] fn server_complete_io_for_read() { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); do_handshake(&mut client, &mut server); client .writer() .write_all(b"01234567890123456789") .unwrap(); { let mut pipe = OtherSession::new(&mut client); let (rdlen, wrlen) = server.complete_io(&mut pipe).unwrap(); assert!(rdlen > 0 && wrlen == 0); assert_eq!(pipe.reads, 1); } check_read(&mut server.reader(), b"01234567890123456789"); } } #[test] fn client_stream_write() { test_client_stream_write(StreamKind::Ref); test_client_stream_write(StreamKind::Owned); } #[test] fn server_stream_write() { test_server_stream_write(StreamKind::Ref); test_server_stream_write(StreamKind::Owned); } #[derive(Debug, Copy, Clone)] enum StreamKind { Owned, Ref, } fn test_client_stream_write(stream_kind: StreamKind) { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); let data = b"hello"; { let mut pipe = OtherSession::new(&mut server); let mut stream: Box = match stream_kind { StreamKind::Ref => Box::new(Stream::new(&mut client, &mut pipe)), StreamKind::Owned => Box::new(StreamOwned::new(client, pipe)), }; assert_eq!(stream.write(data).unwrap(), 5); } check_read(&mut server.reader(), data); } } fn test_server_stream_write(stream_kind: StreamKind) { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); let data = b"hello"; { let mut pipe = OtherSession::new(&mut client); let mut stream: Box = match stream_kind { StreamKind::Ref => Box::new(Stream::new(&mut server, &mut pipe)), StreamKind::Owned => Box::new(StreamOwned::new(server, pipe)), }; assert_eq!(stream.write(data).unwrap(), 5); } check_read(&mut client.reader(), data); } } #[test] fn client_stream_read() { test_client_stream_read(StreamKind::Ref, ReadKind::Buf); test_client_stream_read(StreamKind::Owned, ReadKind::Buf); #[cfg(read_buf)] { test_client_stream_read(StreamKind::Ref, ReadKind::BorrowedBuf); test_client_stream_read(StreamKind::Owned, ReadKind::BorrowedBuf); } } #[test] fn server_stream_read() { test_server_stream_read(StreamKind::Ref, ReadKind::Buf); test_server_stream_read(StreamKind::Owned, ReadKind::Buf); #[cfg(read_buf)] { test_server_stream_read(StreamKind::Ref, ReadKind::BorrowedBuf); test_server_stream_read(StreamKind::Owned, ReadKind::BorrowedBuf); } } #[derive(Debug, Copy, Clone)] enum ReadKind { Buf, #[cfg(read_buf)] BorrowedBuf, } fn test_stream_read(read_kind: ReadKind, mut stream: impl Read, data: &[u8]) { match read_kind { ReadKind::Buf => { check_read(&mut stream, data); check_read_err(&mut stream, io::ErrorKind::UnexpectedEof) } #[cfg(read_buf)] ReadKind::BorrowedBuf => { check_read_buf(&mut stream, data); check_read_buf_err(&mut stream, io::ErrorKind::UnexpectedEof) } } } fn test_client_stream_read(stream_kind: StreamKind, read_kind: ReadKind) { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); let data = b"world"; server.writer().write_all(data).unwrap(); { let mut pipe = OtherSession::new(&mut server); transfer_eof(&mut client); let stream: Box = match stream_kind { StreamKind::Ref => Box::new(Stream::new(&mut client, &mut pipe)), StreamKind::Owned => Box::new(StreamOwned::new(client, pipe)), }; test_stream_read(read_kind, stream, data) } } } fn test_server_stream_read(stream_kind: StreamKind, read_kind: ReadKind) { for kt in ALL_KEY_TYPES.iter() { let (mut client, mut server) = make_pair(*kt); let data = b"world"; client.writer().write_all(data).unwrap(); { let mut pipe = OtherSession::new(&mut client); transfer_eof(&mut server); let stream: Box = match stream_kind { StreamKind::Ref => Box::new(Stream::new(&mut server, &mut pipe)), StreamKind::Owned => Box::new(StreamOwned::new(server, pipe)), }; test_stream_read(read_kind, stream, data) } } } struct FailsWrites { errkind: io::ErrorKind, after: usize, } impl io::Read for FailsWrites { fn read(&mut self, _b: &mut [u8]) -> io::Result { Ok(0) } } impl io::Write for FailsWrites { fn write(&mut self, b: &[u8]) -> io::Result { if self.after > 0 { self.after -= 1; Ok(b.len()) } else { Err(io::Error::new(self.errkind, "oops")) } } fn flush(&mut self) -> io::Result<()> { Ok(()) } } #[test] fn stream_write_reports_underlying_io_error_before_plaintext_processed() { let (mut client, mut server) = make_pair(KeyType::Rsa); do_handshake(&mut client, &mut server); let mut pipe = FailsWrites { errkind: io::ErrorKind::ConnectionAborted, after: 0, }; client .writer() .write_all(b"hello") .unwrap(); let mut client_stream = Stream::new(&mut client, &mut pipe); let rc = client_stream.write(b"world"); assert!(rc.is_err()); let err = rc.err().unwrap(); assert_eq!(err.kind(), io::ErrorKind::ConnectionAborted); } #[test] fn stream_write_swallows_underlying_io_error_after_plaintext_processed() { let (mut client, mut server) = make_pair(KeyType::Rsa); do_handshake(&mut client, &mut server); let mut pipe = FailsWrites { errkind: io::ErrorKind::ConnectionAborted, after: 1, }; client .writer() .write_all(b"hello") .unwrap(); let mut client_stream = Stream::new(&mut client, &mut pipe); let rc = client_stream.write(b"world"); assert_eq!(format!("{:?}", rc), "Ok(5)"); } fn make_disjoint_suite_configs() -> (ClientConfig, ServerConfig) { let kt = KeyType::Rsa; let server_config = finish_server_config( kt, ServerConfig::builder() .with_cipher_suites(&[rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .unwrap(), ); let client_config = finish_client_config( kt, ClientConfig::builder() .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .unwrap(), ); (client_config, server_config) } #[test] fn client_stream_handshake_error() { let (client_config, server_config) = make_disjoint_suite_configs(); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); { let mut pipe = OtherSession::new_fails(&mut server); let mut client_stream = Stream::new(&mut client, &mut pipe); let rc = client_stream.write(b"hello"); assert!(rc.is_err()); assert_eq!( format!("{:?}", rc), "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" ); let rc = client_stream.write(b"hello"); assert!(rc.is_err()); assert_eq!( format!("{:?}", rc), "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" ); } } #[test] fn client_streamowned_handshake_error() { let (client_config, server_config) = make_disjoint_suite_configs(); let (client, mut server) = make_pair_for_configs(client_config, server_config); let pipe = OtherSession::new_fails(&mut server); let mut client_stream = StreamOwned::new(client, pipe); let rc = client_stream.write(b"hello"); assert!(rc.is_err()); assert_eq!( format!("{:?}", rc), "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" ); let rc = client_stream.write(b"hello"); assert!(rc.is_err()); assert_eq!( format!("{:?}", rc), "Err(Custom { kind: InvalidData, error: AlertReceived(HandshakeFailure) })" ); } #[test] fn server_stream_handshake_error() { let (client_config, server_config) = make_disjoint_suite_configs(); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); client .writer() .write_all(b"world") .unwrap(); { let mut pipe = OtherSession::new_fails(&mut client); let mut server_stream = Stream::new(&mut server, &mut pipe); let mut bytes = [0u8; 5]; let rc = server_stream.read(&mut bytes); assert!(rc.is_err()); assert_eq!( format!("{:?}", rc), "Err(Custom { kind: InvalidData, error: PeerIncompatible(NoCipherSuitesInCommon) })" ); } } #[test] fn server_streamowned_handshake_error() { let (client_config, server_config) = make_disjoint_suite_configs(); let (mut client, server) = make_pair_for_configs(client_config, server_config); client .writer() .write_all(b"world") .unwrap(); let pipe = OtherSession::new_fails(&mut client); let mut server_stream = StreamOwned::new(server, pipe); let mut bytes = [0u8; 5]; let rc = server_stream.read(&mut bytes); assert!(rc.is_err()); assert_eq!( format!("{:?}", rc), "Err(Custom { kind: InvalidData, error: PeerIncompatible(NoCipherSuitesInCommon) })" ); } #[test] fn server_config_is_clone() { let _ = make_server_config(KeyType::Rsa); } #[test] fn client_config_is_clone() { let _ = make_client_config(KeyType::Rsa); } #[test] fn client_connection_is_debug() { let (client, _) = make_pair(KeyType::Rsa); println!("{:?}", client); } #[test] fn server_connection_is_debug() { let (_, server) = make_pair(KeyType::Rsa); println!("{:?}", server); } #[test] fn server_complete_io_for_handshake_ending_with_alert() { let (client_config, server_config) = make_disjoint_suite_configs(); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); assert!(server.is_handshaking()); let mut pipe = OtherSession::new_fails(&mut client); let rc = server.complete_io(&mut pipe); assert!(rc.is_err(), "server io failed due to handshake failure"); assert!(!server.wants_write(), "but server did send its alert"); assert_eq!( format!("{:?}", pipe.last_error), "Some(AlertReceived(HandshakeFailure))", "which was received by client" ); } #[test] fn server_exposes_offered_sni() { let kt = KeyType::Rsa; for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(kt, &[version]); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("second.testserver.com")) .unwrap(); let mut server = ServerConnection::new(Arc::new(make_server_config(kt))).unwrap(); assert_eq!(None, server.server_name()); do_handshake(&mut client, &mut server); assert_eq!(Some("second.testserver.com"), server.server_name()); } } #[test] fn server_exposes_offered_sni_smashed_to_lowercase() { // webpki actually does this for us in its DnsName type let kt = KeyType::Rsa; for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(kt, &[version]); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("SECOND.TESTServer.com")) .unwrap(); let mut server = ServerConnection::new(Arc::new(make_server_config(kt))).unwrap(); assert_eq!(None, server.server_name()); do_handshake(&mut client, &mut server); assert_eq!(Some("second.testserver.com"), server.server_name()); } } #[test] fn server_exposes_offered_sni_even_if_resolver_fails() { let kt = KeyType::Rsa; let resolver = rustls::server::ResolvesServerCertUsingSni::new(); let mut server_config = make_server_config(kt); server_config.cert_resolver = Arc::new(resolver); let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(kt, &[version]); let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("thisdoesNOTexist.com")) .unwrap(); assert_eq!(None, server.server_name()); transfer(&mut client, &mut server); assert_eq!( server.process_new_packets(), Err(Error::General( "no server certificate chain resolved".to_string() )) ); assert_eq!(Some("thisdoesnotexist.com"), server.server_name()); } } #[test] fn sni_resolver_works() { let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); resolver .add( "localhost", sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()), ) .unwrap(); let mut server_config = make_server_config(kt); server_config.cert_resolver = Arc::new(resolver); let server_config = Arc::new(server_config); let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let mut client1 = ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("localhost")).unwrap(); let err = do_handshake_until_error(&mut client1, &mut server1); assert_eq!(err, Ok(())); let mut server2 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let mut client2 = ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("notlocalhost")).unwrap(); let err = do_handshake_until_error(&mut client2, &mut server2); assert_eq!( err, Err(ErrorFromPeer::Server(Error::General( "no server certificate chain resolved".into() ))) ); } #[test] fn sni_resolver_rejects_wrong_names() { let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); assert_eq!( Ok(()), resolver.add( "localhost", sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) ) ); assert_eq!( Err(Error::General( "The server certificate is not valid for the given name".into() )), resolver.add( "not-localhost", sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) ) ); assert_eq!( Err(Error::General("Bad DNS name".into())), resolver.add( "not ascii 🦀", sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) ) ); } #[test] fn sni_resolver_lower_cases_configured_names() { let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); assert_eq!( Ok(()), resolver.add( "LOCALHOST", sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) ) ); let mut server_config = make_server_config(kt); server_config.cert_resolver = Arc::new(resolver); let server_config = Arc::new(server_config); let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let mut client1 = ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("localhost")).unwrap(); let err = do_handshake_until_error(&mut client1, &mut server1); assert_eq!(err, Ok(())); } #[test] fn sni_resolver_lower_cases_queried_names() { // actually, the handshake parser does this, but the effect is the same. let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); assert_eq!( Ok(()), resolver.add( "localhost", sign::CertifiedKey::new(kt.get_chain(), signing_key.clone()) ) ); let mut server_config = make_server_config(kt); server_config.cert_resolver = Arc::new(resolver); let server_config = Arc::new(server_config); let mut server1 = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let mut client1 = ClientConnection::new(Arc::new(make_client_config(kt)), dns_name("LOCALHOST")).unwrap(); let err = do_handshake_until_error(&mut client1, &mut server1); assert_eq!(err, Ok(())); } #[test] fn sni_resolver_rejects_bad_certs() { let kt = KeyType::Rsa; let mut resolver = rustls::server::ResolvesServerCertUsingSni::new(); let signing_key = sign::RsaSigningKey::new(&kt.get_key()).unwrap(); let signing_key: Arc = Arc::new(signing_key); assert_eq!( Err(Error::General( "No end-entity certificate in certificate chain".into() )), resolver.add( "localhost", sign::CertifiedKey::new(vec![], signing_key.clone()) ) ); let bad_chain = vec![rustls::Certificate(vec![0xa0])]; assert_eq!( Err(Error::General( "End-entity certificate in certificate chain is syntactically invalid".into() )), resolver.add( "localhost", sign::CertifiedKey::new(bad_chain, signing_key.clone()) ) ); } fn do_exporter_test(client_config: ClientConfig, server_config: ServerConfig) { let mut client_secret = [0u8; 64]; let mut server_secret = [0u8; 64]; let (mut client, mut server) = make_pair_for_configs(client_config, server_config); assert_eq!( Err(Error::HandshakeNotComplete), client.export_keying_material(&mut client_secret, b"label", Some(b"context")) ); assert_eq!( Err(Error::HandshakeNotComplete), server.export_keying_material(&mut server_secret, b"label", Some(b"context")) ); do_handshake(&mut client, &mut server); assert!(client .export_keying_material(&mut client_secret, b"label", Some(b"context")) .is_ok()); assert!(server .export_keying_material(&mut server_secret, b"label", Some(b"context")) .is_ok()); assert_eq!(client_secret.to_vec(), server_secret.to_vec()); assert!(client .export_keying_material(&mut client_secret, b"label", None) .is_ok()); assert_ne!(client_secret.to_vec(), server_secret.to_vec()); assert!(server .export_keying_material(&mut server_secret, b"label", None) .is_ok()); assert_eq!(client_secret.to_vec(), server_secret.to_vec()); } #[cfg(feature = "tls12")] #[test] fn test_tls12_exporter() { for kt in ALL_KEY_TYPES.iter() { let client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS12]); let server_config = make_server_config(*kt); do_exporter_test(client_config, server_config); } } #[test] fn test_tls13_exporter() { for kt in ALL_KEY_TYPES.iter() { let client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS13]); let server_config = make_server_config(*kt); do_exporter_test(client_config, server_config); } } fn do_suite_test( client_config: ClientConfig, server_config: ServerConfig, expect_suite: SupportedCipherSuite, expect_version: ProtocolVersion, ) { println!( "do_suite_test {:?} {:?}", expect_version, expect_suite.suite() ); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); assert_eq!(None, client.negotiated_cipher_suite()); assert_eq!(None, server.negotiated_cipher_suite()); assert_eq!(None, client.protocol_version()); assert_eq!(None, server.protocol_version()); assert!(client.is_handshaking()); assert!(server.is_handshaking()); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); assert!(client.is_handshaking()); assert!(server.is_handshaking()); assert_eq!(None, client.protocol_version()); assert_eq!(Some(expect_version), server.protocol_version()); assert_eq!(None, client.negotiated_cipher_suite()); assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); transfer(&mut server, &mut client); client.process_new_packets().unwrap(); assert_eq!(Some(expect_suite), client.negotiated_cipher_suite()); assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); transfer(&mut server, &mut client); client.process_new_packets().unwrap(); assert!(!client.is_handshaking()); assert!(!server.is_handshaking()); assert_eq!(Some(expect_version), client.protocol_version()); assert_eq!(Some(expect_version), server.protocol_version()); assert_eq!(Some(expect_suite), client.negotiated_cipher_suite()); assert_eq!(Some(expect_suite), server.negotiated_cipher_suite()); } fn find_suite(suite: CipherSuite) -> SupportedCipherSuite { for scs in ALL_CIPHER_SUITES.iter().copied() { if scs.suite() == suite { return scs; } } panic!("find_suite given unsupported suite"); } static TEST_CIPHERSUITES: &[(&rustls::SupportedProtocolVersion, KeyType, CipherSuite)] = &[ ( &rustls::version::TLS13, KeyType::Rsa, CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, ), ( &rustls::version::TLS13, KeyType::Rsa, CipherSuite::TLS13_AES_256_GCM_SHA384, ), ( &rustls::version::TLS13, KeyType::Rsa, CipherSuite::TLS13_AES_128_GCM_SHA256, ), #[cfg(feature = "tls12")] ( &rustls::version::TLS12, KeyType::Ecdsa, CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, ), #[cfg(feature = "tls12")] ( &rustls::version::TLS12, KeyType::Rsa, CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ), #[cfg(feature = "tls12")] ( &rustls::version::TLS12, KeyType::Ecdsa, CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, ), #[cfg(feature = "tls12")] ( &rustls::version::TLS12, KeyType::Ecdsa, CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ), #[cfg(feature = "tls12")] ( &rustls::version::TLS12, KeyType::Rsa, CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, ), #[cfg(feature = "tls12")] ( &rustls::version::TLS12, KeyType::Rsa, CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, ), ]; #[test] fn negotiated_ciphersuite_default() { for kt in ALL_KEY_TYPES.iter() { do_suite_test( make_client_config(*kt), make_server_config(*kt), find_suite(CipherSuite::TLS13_AES_256_GCM_SHA384), ProtocolVersion::TLSv1_3, ); } } #[test] fn all_suites_covered() { assert_eq!(ALL_CIPHER_SUITES.len(), TEST_CIPHERSUITES.len()); } #[test] fn negotiated_ciphersuite_client() { for item in TEST_CIPHERSUITES.iter() { let (version, kt, suite) = *item; let scs = find_suite(suite); let client_config = finish_client_config( kt, ClientConfig::builder() .with_cipher_suites(&[scs]) .with_safe_default_kx_groups() .with_protocol_versions(&[version]) .unwrap(), ); do_suite_test(client_config, make_server_config(kt), scs, version.version); } } #[test] fn negotiated_ciphersuite_server() { for item in TEST_CIPHERSUITES.iter() { let (version, kt, suite) = *item; let scs = find_suite(suite); let server_config = finish_server_config( kt, ServerConfig::builder() .with_cipher_suites(&[scs]) .with_safe_default_kx_groups() .with_protocol_versions(&[version]) .unwrap(), ); do_suite_test(make_client_config(kt), server_config, scs, version.version); } } #[derive(Debug, PartialEq)] struct KeyLogItem { label: String, client_random: Vec, secret: Vec, } struct KeyLogToVec { label: &'static str, items: Mutex>, } impl KeyLogToVec { fn new(who: &'static str) -> Self { Self { label: who, items: Mutex::new(vec![]), } } fn take(&self) -> Vec { std::mem::take(&mut self.items.lock().unwrap()) } } impl KeyLog for KeyLogToVec { fn log(&self, label: &str, client: &[u8], secret: &[u8]) { let value = KeyLogItem { label: label.into(), client_random: client.into(), secret: secret.into(), }; println!("key log {:?}: {:?}", self.label, value); self.items.lock().unwrap().push(value); } } #[cfg(feature = "tls12")] #[test] fn key_log_for_tls12() { let client_key_log = Arc::new(KeyLogToVec::new("client")); let server_key_log = Arc::new(KeyLogToVec::new("server")); let kt = KeyType::Rsa; let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS12]); client_config.key_log = client_key_log.clone(); let client_config = Arc::new(client_config); let mut server_config = make_server_config(kt); server_config.key_log = server_key_log.clone(); let server_config = Arc::new(server_config); // full handshake let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); let client_full_log = client_key_log.take(); let server_full_log = server_key_log.take(); assert_eq!(client_full_log, server_full_log); assert_eq!(1, client_full_log.len()); assert_eq!("CLIENT_RANDOM", client_full_log[0].label); // resumed let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); let client_resume_log = client_key_log.take(); let server_resume_log = server_key_log.take(); assert_eq!(client_resume_log, server_resume_log); assert_eq!(1, client_resume_log.len()); assert_eq!("CLIENT_RANDOM", client_resume_log[0].label); assert_eq!(client_full_log[0].secret, client_resume_log[0].secret); } #[test] fn key_log_for_tls13() { let client_key_log = Arc::new(KeyLogToVec::new("client")); let server_key_log = Arc::new(KeyLogToVec::new("server")); let kt = KeyType::Rsa; let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); client_config.key_log = client_key_log.clone(); let client_config = Arc::new(client_config); let mut server_config = make_server_config(kt); server_config.key_log = server_key_log.clone(); let server_config = Arc::new(server_config); // full handshake let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); let client_full_log = client_key_log.take(); let server_full_log = server_key_log.take(); assert_eq!(5, client_full_log.len()); assert_eq!("CLIENT_HANDSHAKE_TRAFFIC_SECRET", client_full_log[0].label); assert_eq!("SERVER_HANDSHAKE_TRAFFIC_SECRET", client_full_log[1].label); assert_eq!("CLIENT_TRAFFIC_SECRET_0", client_full_log[2].label); assert_eq!("SERVER_TRAFFIC_SECRET_0", client_full_log[3].label); assert_eq!("EXPORTER_SECRET", client_full_log[4].label); assert_eq!(client_full_log[0], server_full_log[0]); assert_eq!(client_full_log[1], server_full_log[1]); assert_eq!(client_full_log[2], server_full_log[2]); assert_eq!(client_full_log[3], server_full_log[3]); assert_eq!(client_full_log[4], server_full_log[4]); // resumed let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); let client_resume_log = client_key_log.take(); let server_resume_log = server_key_log.take(); assert_eq!(5, client_resume_log.len()); assert_eq!( "CLIENT_HANDSHAKE_TRAFFIC_SECRET", client_resume_log[0].label ); assert_eq!( "SERVER_HANDSHAKE_TRAFFIC_SECRET", client_resume_log[1].label ); assert_eq!("CLIENT_TRAFFIC_SECRET_0", client_resume_log[2].label); assert_eq!("SERVER_TRAFFIC_SECRET_0", client_resume_log[3].label); assert_eq!("EXPORTER_SECRET", client_resume_log[4].label); assert_eq!(6, server_resume_log.len()); assert_eq!("CLIENT_EARLY_TRAFFIC_SECRET", server_resume_log[0].label); assert_eq!( "CLIENT_HANDSHAKE_TRAFFIC_SECRET", server_resume_log[1].label ); assert_eq!( "SERVER_HANDSHAKE_TRAFFIC_SECRET", server_resume_log[2].label ); assert_eq!("CLIENT_TRAFFIC_SECRET_0", server_resume_log[3].label); assert_eq!("SERVER_TRAFFIC_SECRET_0", server_resume_log[4].label); assert_eq!("EXPORTER_SECRET", server_resume_log[5].label); assert_eq!(client_resume_log[0], server_resume_log[1]); assert_eq!(client_resume_log[1], server_resume_log[2]); assert_eq!(client_resume_log[2], server_resume_log[3]); assert_eq!(client_resume_log[3], server_resume_log[4]); assert_eq!(client_resume_log[4], server_resume_log[5]); } #[test] fn vectored_write_for_server_appdata() { let (mut client, mut server) = make_pair(KeyType::Rsa); do_handshake(&mut client, &mut server); server .writer() .write_all(b"01234567890123456789") .unwrap(); server .writer() .write_all(b"01234567890123456789") .unwrap(); { let mut pipe = OtherSession::new(&mut client); let wrlen = server.write_tls(&mut pipe).unwrap(); assert_eq!(84, wrlen); assert_eq!(pipe.writevs, vec![vec![42, 42]]); } check_read( &mut client.reader(), b"0123456789012345678901234567890123456789", ); } #[test] fn vectored_write_for_client_appdata() { let (mut client, mut server) = make_pair(KeyType::Rsa); do_handshake(&mut client, &mut server); client .writer() .write_all(b"01234567890123456789") .unwrap(); client .writer() .write_all(b"01234567890123456789") .unwrap(); { let mut pipe = OtherSession::new(&mut server); let wrlen = client.write_tls(&mut pipe).unwrap(); assert_eq!(84, wrlen); assert_eq!(pipe.writevs, vec![vec![42, 42]]); } check_read( &mut server.reader(), b"0123456789012345678901234567890123456789", ); } #[test] fn vectored_write_for_server_handshake_with_half_rtt_data() { let mut server_config = make_server_config(KeyType::Rsa); server_config.send_half_rtt_data = true; let (mut client, mut server) = make_pair_for_configs(make_client_config_with_auth(KeyType::Rsa), server_config); server .writer() .write_all(b"01234567890123456789") .unwrap(); server .writer() .write_all(b"0123456789") .unwrap(); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); { let mut pipe = OtherSession::new(&mut client); let wrlen = server.write_tls(&mut pipe).unwrap(); // don't assert exact sizes here, to avoid a brittle test assert!(wrlen > 4000); // its pretty big (contains cert chain) assert_eq!(pipe.writevs.len(), 1); // only one writev assert_eq!(pipe.writevs[0].len(), 8); // at least a server hello/ccs/cert/serverkx/0.5rtt data } client.process_new_packets().unwrap(); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); { let mut pipe = OtherSession::new(&mut client); let wrlen = server.write_tls(&mut pipe).unwrap(); // 4 tickets assert_eq!(wrlen, 103 * 4); assert_eq!(pipe.writevs, vec![vec![103, 103, 103, 103]]); } assert!(!server.is_handshaking()); assert!(!client.is_handshaking()); check_read(&mut client.reader(), b"012345678901234567890123456789"); } fn check_half_rtt_does_not_work(server_config: ServerConfig) { let (mut client, mut server) = make_pair_for_configs(make_client_config_with_auth(KeyType::Rsa), server_config); server .writer() .write_all(b"01234567890123456789") .unwrap(); server .writer() .write_all(b"0123456789") .unwrap(); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); { let mut pipe = OtherSession::new(&mut client); let wrlen = server.write_tls(&mut pipe).unwrap(); // don't assert exact sizes here, to avoid a brittle test assert!(wrlen > 4000); // its pretty big (contains cert chain) assert_eq!(pipe.writevs.len(), 1); // only one writev assert!(pipe.writevs[0].len() >= 6); // at least a server hello/ccs/cert/serverkx data } // client second flight client.process_new_packets().unwrap(); transfer(&mut client, &mut server); // when client auth is enabled, we don't sent 0.5-rtt data, as we'd be sending // it to an unauthenticated peer. so it happens here, in the server's second // flight (42 and 32 are lengths of appdata sent above). server.process_new_packets().unwrap(); { let mut pipe = OtherSession::new(&mut client); let wrlen = server.write_tls(&mut pipe).unwrap(); assert_eq!(wrlen, 486); assert_eq!(pipe.writevs, vec![vec![103, 103, 103, 103, 42, 32]]); } assert!(!server.is_handshaking()); assert!(!client.is_handshaking()); check_read(&mut client.reader(), b"012345678901234567890123456789"); } #[test] fn vectored_write_for_server_handshake_no_half_rtt_with_client_auth() { let mut server_config = make_server_config_with_mandatory_client_auth(KeyType::Rsa); server_config.send_half_rtt_data = true; // ask even though it will be ignored check_half_rtt_does_not_work(server_config); } #[test] fn vectored_write_for_server_handshake_no_half_rtt_by_default() { let server_config = make_server_config(KeyType::Rsa); assert!(!server_config.send_half_rtt_data); check_half_rtt_does_not_work(server_config); } #[test] fn vectored_write_for_client_handshake() { let (mut client, mut server) = make_pair(KeyType::Rsa); client .writer() .write_all(b"01234567890123456789") .unwrap(); client .writer() .write_all(b"0123456789") .unwrap(); { let mut pipe = OtherSession::new(&mut server); let wrlen = client.write_tls(&mut pipe).unwrap(); // don't assert exact sizes here, to avoid a brittle test assert!(wrlen > 200); // just the client hello assert_eq!(pipe.writevs.len(), 1); // only one writev assert!(pipe.writevs[0].len() == 1); // only a client hello } transfer(&mut server, &mut client); client.process_new_packets().unwrap(); { let mut pipe = OtherSession::new(&mut server); let wrlen = client.write_tls(&mut pipe).unwrap(); assert_eq!(wrlen, 154); // CCS, finished, then two application datas assert_eq!(pipe.writevs, vec![vec![6, 74, 42, 32]]); } assert!(!server.is_handshaking()); assert!(!client.is_handshaking()); check_read(&mut server.reader(), b"012345678901234567890123456789"); } #[test] fn vectored_write_with_slow_client() { let (mut client, mut server) = make_pair(KeyType::Rsa); client.set_buffer_limit(Some(32)); do_handshake(&mut client, &mut server); server .writer() .write_all(b"01234567890123456789") .unwrap(); { let mut pipe = OtherSession::new(&mut client); pipe.short_writes = true; let wrlen = server.write_tls(&mut pipe).unwrap() + server.write_tls(&mut pipe).unwrap() + server.write_tls(&mut pipe).unwrap() + server.write_tls(&mut pipe).unwrap() + server.write_tls(&mut pipe).unwrap() + server.write_tls(&mut pipe).unwrap(); assert_eq!(42, wrlen); assert_eq!( pipe.writevs, vec![vec![21], vec![10], vec![5], vec![3], vec![3]] ); } check_read(&mut client.reader(), b"01234567890123456789"); } struct ServerStorage { storage: Arc, put_count: AtomicUsize, get_count: AtomicUsize, take_count: AtomicUsize, } impl ServerStorage { fn new() -> Self { Self { storage: rustls::server::ServerSessionMemoryCache::new(1024), put_count: AtomicUsize::new(0), get_count: AtomicUsize::new(0), take_count: AtomicUsize::new(0), } } fn puts(&self) -> usize { self.put_count.load(Ordering::SeqCst) } fn gets(&self) -> usize { self.get_count.load(Ordering::SeqCst) } fn takes(&self) -> usize { self.take_count.load(Ordering::SeqCst) } } impl fmt::Debug for ServerStorage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "(put: {:?}, get: {:?}, take: {:?})", self.put_count, self.get_count, self.take_count ) } } impl rustls::server::StoresServerSessions for ServerStorage { fn put(&self, key: Vec, value: Vec) -> bool { self.put_count .fetch_add(1, Ordering::SeqCst); self.storage.put(key, value) } fn get(&self, key: &[u8]) -> Option> { self.get_count .fetch_add(1, Ordering::SeqCst); self.storage.get(key) } fn take(&self, key: &[u8]) -> Option> { self.take_count .fetch_add(1, Ordering::SeqCst); self.storage.take(key) } fn can_cache(&self) -> bool { true } } #[derive(Debug, Clone)] enum ClientStorageOp { SetKxHint(rustls::ServerName, rustls::NamedGroup), GetKxHint(rustls::ServerName, Option), SetTls12Session(rustls::ServerName), GetTls12Session(rustls::ServerName, bool), RemoveTls12Session(rustls::ServerName), InsertTls13Ticket(rustls::ServerName), TakeTls13Ticket(rustls::ServerName, bool), } struct ClientStorage { storage: Arc, ops: Mutex>, } impl ClientStorage { fn new() -> Self { Self { storage: Arc::new(rustls::client::ClientSessionMemoryCache::new(1024)), ops: Mutex::new(Vec::new()), } } #[cfg(feature = "tls12")] fn ops(&self) -> Vec { self.ops.lock().unwrap().clone() } #[cfg(feature = "tls12")] fn ops_and_reset(&self) -> Vec { std::mem::take(&mut self.ops.lock().unwrap()) } } impl fmt::Debug for ClientStorage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "(ops: {:?})", self.ops.lock().unwrap()) } } impl rustls::client::ClientSessionStore for ClientStorage { fn set_kx_hint(&self, server_name: &rustls::ServerName, group: rustls::NamedGroup) { self.ops .lock() .unwrap() .push(ClientStorageOp::SetKxHint(server_name.clone(), group)); self.storage .set_kx_hint(server_name, group) } fn kx_hint(&self, server_name: &rustls::ServerName) -> Option { let rc = self.storage.kx_hint(server_name); self.ops .lock() .unwrap() .push(ClientStorageOp::GetKxHint(server_name.clone(), rc)); rc } fn set_tls12_session( &self, server_name: &rustls::ServerName, value: rustls::client::Tls12ClientSessionValue, ) { self.ops .lock() .unwrap() .push(ClientStorageOp::SetTls12Session(server_name.clone())); self.storage .set_tls12_session(server_name, value) } fn tls12_session( &self, server_name: &rustls::ServerName, ) -> Option { let rc = self.storage.tls12_session(server_name); self.ops .lock() .unwrap() .push(ClientStorageOp::GetTls12Session( server_name.clone(), rc.is_some(), )); rc } fn remove_tls12_session(&self, server_name: &rustls::ServerName) { self.ops .lock() .unwrap() .push(ClientStorageOp::RemoveTls12Session(server_name.clone())); self.storage .remove_tls12_session(server_name); } fn insert_tls13_ticket( &self, server_name: &rustls::ServerName, value: rustls::client::Tls13ClientSessionValue, ) { self.ops .lock() .unwrap() .push(ClientStorageOp::InsertTls13Ticket(server_name.clone())); self.storage .insert_tls13_ticket(server_name, value); } fn take_tls13_ticket( &self, server_name: &rustls::ServerName, ) -> Option { let rc = self .storage .take_tls13_ticket(server_name); self.ops .lock() .unwrap() .push(ClientStorageOp::TakeTls13Ticket( server_name.clone(), rc.is_some(), )); rc } } #[test] fn tls13_stateful_resumption() { let kt = KeyType::Rsa; let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); let client_config = Arc::new(client_config); let mut server_config = make_server_config(kt); let storage = Arc::new(ServerStorage::new()); server_config.session_storage = storage.clone(); let server_config = Arc::new(server_config); // full handshake let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); let (full_c2s, full_s2c) = do_handshake(&mut client, &mut server); assert_eq!(storage.puts(), 4); assert_eq!(storage.gets(), 0); assert_eq!(storage.takes(), 0); assert_eq!( client .peer_certificates() .map(|certs| certs.len()), Some(3) ); // resumed let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); let (resume_c2s, resume_s2c) = do_handshake(&mut client, &mut server); assert!(resume_c2s > full_c2s); assert!(resume_s2c < full_s2c); assert_eq!(storage.puts(), 8); assert_eq!(storage.gets(), 0); assert_eq!(storage.takes(), 1); assert_eq!( client .peer_certificates() .map(|certs| certs.len()), Some(3) ); // resumed again let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); let (resume2_c2s, resume2_s2c) = do_handshake(&mut client, &mut server); assert_eq!(resume_s2c, resume2_s2c); assert_eq!(resume_c2s, resume2_c2s); assert_eq!(storage.puts(), 12); assert_eq!(storage.gets(), 0); assert_eq!(storage.takes(), 2); assert_eq!( client .peer_certificates() .map(|certs| certs.len()), Some(3) ); } #[test] fn tls13_stateless_resumption() { let kt = KeyType::Rsa; let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); let client_config = Arc::new(client_config); let mut server_config = make_server_config(kt); server_config.ticketer = rustls::Ticketer::new().unwrap(); let storage = Arc::new(ServerStorage::new()); server_config.session_storage = storage.clone(); let server_config = Arc::new(server_config); // full handshake let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); let (full_c2s, full_s2c) = do_handshake(&mut client, &mut server); assert_eq!(storage.puts(), 0); assert_eq!(storage.gets(), 0); assert_eq!(storage.takes(), 0); assert_eq!( client .peer_certificates() .map(|certs| certs.len()), Some(3) ); // resumed let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); let (resume_c2s, resume_s2c) = do_handshake(&mut client, &mut server); assert!(resume_c2s > full_c2s); assert!(resume_s2c < full_s2c); assert_eq!(storage.puts(), 0); assert_eq!(storage.gets(), 0); assert_eq!(storage.takes(), 0); assert_eq!( client .peer_certificates() .map(|certs| certs.len()), Some(3) ); // resumed again let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); let (resume2_c2s, resume2_s2c) = do_handshake(&mut client, &mut server); assert_eq!(resume_s2c, resume2_s2c); assert_eq!(resume_c2s, resume2_c2s); assert_eq!(storage.puts(), 0); assert_eq!(storage.gets(), 0); assert_eq!(storage.takes(), 0); assert_eq!( client .peer_certificates() .map(|certs| certs.len()), Some(3) ); } #[test] fn early_data_not_available() { let (mut client, _) = make_pair(KeyType::Rsa); assert!(client.early_data().is_none()); } fn early_data_configs() -> (Arc, Arc) { let kt = KeyType::Rsa; let mut client_config = make_client_config(kt); client_config.enable_early_data = true; client_config.resumption = Resumption::store(Arc::new(ClientStorage::new())); let mut server_config = make_server_config(kt); server_config.max_early_data_size = 1234; (Arc::new(client_config), Arc::new(server_config)) } #[test] fn early_data_is_available_on_resumption() { let (client_config, server_config) = early_data_configs(); let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); assert!(client.early_data().is_some()); assert_eq!( client .early_data() .unwrap() .bytes_left(), 1234 ); client .early_data() .unwrap() .flush() .unwrap(); assert_eq!( client .early_data() .unwrap() .write(b"hello") .unwrap(), 5 ); do_handshake(&mut client, &mut server); let mut received_early_data = [0u8; 5]; assert_eq!( server .early_data() .expect("early_data didn't happen") .read(&mut received_early_data) .expect("early_data failed unexpectedly"), 5 ); assert_eq!(&received_early_data[..], b"hello"); } #[test] fn early_data_not_available_on_server_before_client_hello() { let mut server = ServerConnection::new(Arc::new(make_server_config(KeyType::Rsa))).unwrap(); assert!(server.early_data().is_none()); } #[test] fn early_data_can_be_rejected_by_server() { let (client_config, server_config) = early_data_configs(); let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); assert!(client.early_data().is_some()); assert_eq!( client .early_data() .unwrap() .bytes_left(), 1234 ); client .early_data() .unwrap() .flush() .unwrap(); assert_eq!( client .early_data() .unwrap() .write(b"hello") .unwrap(), 5 ); server.reject_early_data(); do_handshake(&mut client, &mut server); assert!(!client.is_early_data_accepted()); } #[cfg(feature = "quic")] mod test_quic { use super::*; use rustls::quic::{self, ConnectionCommon}; // Returns the sender's next secrets to use, or the receiver's error. fn step( send: &mut ConnectionCommon, recv: &mut ConnectionCommon, ) -> Result, Error> { let mut buf = Vec::new(); let change = loop { let prev = buf.len(); if let Some(x) = send.write_hs(&mut buf) { break Some(x); } if prev == buf.len() { break None; } }; if let Err(e) = recv.read_hs(&buf) { return Err(e); } else { assert_eq!(recv.alert(), None); } Ok(change) } #[test] fn test_quic_handshake() { fn equal_packet_keys(x: &quic::PacketKey, y: &quic::PacketKey) -> bool { // Check that these two sets of keys are equal. let mut buf = vec![0; 32]; let (header, payload_tag) = buf.split_at_mut(8); let (payload, tag_buf) = payload_tag.split_at_mut(8); let tag = x .encrypt_in_place(42, &*header, payload) .unwrap(); tag_buf.copy_from_slice(tag.as_ref()); let result = y.decrypt_in_place(42, &*header, payload_tag); match result { Ok(payload) => payload == &[0; 8], Err(_) => false, } } fn compatible_keys(x: &quic::KeyChange, y: &quic::KeyChange) -> bool { fn keys(kc: &quic::KeyChange) -> &quic::Keys { match kc { quic::KeyChange::Handshake { keys } => keys, quic::KeyChange::OneRtt { keys, .. } => keys, } } let (x, y) = (keys(x), keys(y)); equal_packet_keys(&x.local.packet, &y.remote.packet) && equal_packet_keys(&x.remote.packet, &y.local.packet) } let kt = KeyType::Rsa; let mut client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); client_config.enable_early_data = true; let client_config = Arc::new(client_config); let mut server_config = make_server_config_with_versions(kt, &[&rustls::version::TLS13]); server_config.max_early_data_size = 0xffffffff; let server_config = Arc::new(server_config); let client_params = &b"client params"[..]; let server_params = &b"server params"[..]; // full handshake let mut client = quic::ClientConnection::new( Arc::clone(&client_config), quic::Version::V1, dns_name("localhost"), client_params.into(), ) .unwrap(); let mut server = quic::ServerConnection::new( Arc::clone(&server_config), quic::Version::V1, server_params.into(), ) .unwrap(); let client_initial = step(&mut client, &mut server).unwrap(); assert!(client_initial.is_none()); assert!(client.zero_rtt_keys().is_none()); assert_eq!(server.quic_transport_parameters(), Some(client_params)); let server_hs = step(&mut server, &mut client) .unwrap() .unwrap(); assert!(server.zero_rtt_keys().is_none()); let client_hs = step(&mut client, &mut server) .unwrap() .unwrap(); assert!(compatible_keys(&server_hs, &client_hs)); assert!(client.is_handshaking()); let server_1rtt = step(&mut server, &mut client) .unwrap() .unwrap(); assert!(!client.is_handshaking()); assert_eq!(client.quic_transport_parameters(), Some(server_params)); assert!(server.is_handshaking()); let client_1rtt = step(&mut client, &mut server) .unwrap() .unwrap(); assert!(!server.is_handshaking()); assert!(compatible_keys(&server_1rtt, &client_1rtt)); assert!(!compatible_keys(&server_hs, &server_1rtt)); assert!(step(&mut client, &mut server) .unwrap() .is_none()); assert!(step(&mut server, &mut client) .unwrap() .is_none()); // 0-RTT handshake let mut client = quic::ClientConnection::new( Arc::clone(&client_config), quic::Version::V1, dns_name("localhost"), client_params.into(), ) .unwrap(); assert!(client .negotiated_cipher_suite() .is_some()); let mut server = quic::ServerConnection::new( Arc::clone(&server_config), quic::Version::V1, server_params.into(), ) .unwrap(); step(&mut client, &mut server).unwrap(); assert_eq!(client.quic_transport_parameters(), Some(server_params)); { let client_early = client.zero_rtt_keys().unwrap(); let server_early = server.zero_rtt_keys().unwrap(); assert!(equal_packet_keys( &client_early.packet, &server_early.packet )); } step(&mut server, &mut client) .unwrap() .unwrap(); step(&mut client, &mut server) .unwrap() .unwrap(); step(&mut server, &mut client) .unwrap() .unwrap(); assert!(client.is_early_data_accepted()); // 0-RTT rejection { let client_config = (*client_config).clone(); let mut client = quic::ClientConnection::new( Arc::new(client_config), quic::Version::V1, dns_name("localhost"), client_params.into(), ) .unwrap(); let mut server = quic::ServerConnection::new( Arc::clone(&server_config), quic::Version::V1, server_params.into(), ) .unwrap(); server.reject_early_data(); step(&mut client, &mut server).unwrap(); assert_eq!(client.quic_transport_parameters(), Some(server_params)); assert!(client.zero_rtt_keys().is_some()); assert!(server.zero_rtt_keys().is_none()); step(&mut server, &mut client) .unwrap() .unwrap(); step(&mut client, &mut server) .unwrap() .unwrap(); step(&mut server, &mut client) .unwrap() .unwrap(); assert!(!client.is_early_data_accepted()); } // failed handshake let mut client = quic::ClientConnection::new( client_config, quic::Version::V1, dns_name("example.com"), client_params.into(), ) .unwrap(); let mut server = quic::ServerConnection::new(server_config, quic::Version::V1, server_params.into()) .unwrap(); step(&mut client, &mut server).unwrap(); step(&mut server, &mut client) .unwrap() .unwrap(); assert!(step(&mut server, &mut client).is_err()); assert_eq!( client.alert(), Some(rustls::AlertDescription::BadCertificate) ); // Key updates let (mut client_secrets, mut server_secrets) = match (client_1rtt, server_1rtt) { (quic::KeyChange::OneRtt { next: c, .. }, quic::KeyChange::OneRtt { next: s, .. }) => { (c, s) } _ => unreachable!(), }; let mut client_next = client_secrets.next_packet_keys(); let mut server_next = server_secrets.next_packet_keys(); assert!(equal_packet_keys(&client_next.local, &server_next.remote)); assert!(equal_packet_keys(&server_next.local, &client_next.remote)); client_next = client_secrets.next_packet_keys(); server_next = server_secrets.next_packet_keys(); assert!(equal_packet_keys(&client_next.local, &server_next.remote)); assert!(equal_packet_keys(&server_next.local, &client_next.remote)); } #[test] fn test_quic_rejects_missing_alpn() { let client_params = &b"client params"[..]; let server_params = &b"server params"[..]; for &kt in ALL_KEY_TYPES.iter() { let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); let client_config = Arc::new(client_config); let mut server_config = make_server_config_with_versions(kt, &[&rustls::version::TLS13]); server_config.alpn_protocols = vec!["foo".into()]; let server_config = Arc::new(server_config); let mut client = quic::ClientConnection::new( client_config, quic::Version::V1, dns_name("localhost"), client_params.into(), ) .unwrap(); let mut server = quic::ServerConnection::new(server_config, quic::Version::V1, server_params.into()) .unwrap(); assert_eq!( step(&mut client, &mut server) .err() .unwrap(), Error::NoApplicationProtocol ); assert_eq!( server.alert(), Some(rustls::AlertDescription::NoApplicationProtocol) ); } } #[cfg(feature = "tls12")] #[test] fn test_quic_no_tls13_error() { let mut client_config = make_client_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS12]); client_config.alpn_protocols = vec!["foo".into()]; let client_config = Arc::new(client_config); assert!(quic::ClientConnection::new( client_config, quic::Version::V1, dns_name("localhost"), b"client params".to_vec(), ) .is_err()); let mut server_config = make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS12]); server_config.alpn_protocols = vec!["foo".into()]; let server_config = Arc::new(server_config); assert!(quic::ServerConnection::new( server_config, quic::Version::V1, b"server params".to_vec(), ) .is_err()); } #[test] fn test_quic_invalid_early_data_size() { let mut server_config = make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); server_config.alpn_protocols = vec!["foo".into()]; let cases = [ (None, true), (Some(0u32), true), (Some(5), false), (Some(0xffff_ffff), true), ]; for &(size, ok) in cases.iter() { println!("early data size case: {:?}", size); if let Some(new) = size { server_config.max_early_data_size = new; } let wrapped = Arc::new(server_config.clone()); assert_eq!( quic::ServerConnection::new(wrapped, quic::Version::V1, b"server params".to_vec(),) .is_ok(), ok ); } } #[test] fn test_quic_server_no_params_received() { let server_config = make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); let server_config = Arc::new(server_config); let mut server = quic::ServerConnection::new( server_config, quic::Version::V1, b"server params".to_vec(), ) .unwrap(); use ring::rand::SecureRandom; use rustls::internal::msgs::base::PayloadU16; use rustls::internal::msgs::enums::{Compression, NamedGroup}; use rustls::internal::msgs::handshake::{ ClientHelloPayload, HandshakeMessagePayload, KeyShareEntry, Random, SessionId, }; use rustls::{CipherSuite, HandshakeType, SignatureScheme}; let rng = ring::rand::SystemRandom::new(); let mut random = [0; 32]; rng.fill(&mut random).unwrap(); let random = Random::from(random); let kx = ring::agreement::EphemeralPrivateKey::generate(&ring::agreement::X25519, &rng) .unwrap() .compute_public_key() .unwrap(); let client_hello = MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::ClientHello, payload: HandshakePayload::ClientHello(ClientHelloPayload { client_version: ProtocolVersion::TLSv1_3, random, session_id: SessionId::random().unwrap(), cipher_suites: vec![CipherSuite::TLS13_AES_128_GCM_SHA256], compression_methods: vec![Compression::Null], extensions: vec![ ClientExtension::SupportedVersions(vec![ProtocolVersion::TLSv1_3]), ClientExtension::NamedGroups(vec![NamedGroup::X25519]), ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ED25519]), ClientExtension::KeyShare(vec![KeyShareEntry { group: NamedGroup::X25519, payload: PayloadU16::new(kx.as_ref().to_vec()), }]), ], }), }); let mut buf = Vec::with_capacity(512); client_hello.encode(&mut buf); assert_eq!( server .read_hs(&mut buf.as_slice()) .err(), Some(Error::PeerMisbehaved( PeerMisbehaved::MissingQuicTransportParameters )) ); } #[test] fn test_quic_server_no_tls12() { let mut server_config = make_server_config_with_versions(KeyType::Ed25519, &[&rustls::version::TLS13]); server_config.alpn_protocols = vec!["foo".into()]; let server_config = Arc::new(server_config); use ring::rand::SecureRandom; use rustls::internal::msgs::base::PayloadU16; use rustls::internal::msgs::enums::{Compression, NamedGroup}; use rustls::internal::msgs::handshake::{ ClientHelloPayload, HandshakeMessagePayload, KeyShareEntry, Random, SessionId, }; use rustls::{CipherSuite, HandshakeType, SignatureScheme}; let rng = ring::rand::SystemRandom::new(); let mut random = [0; 32]; rng.fill(&mut random).unwrap(); let random = Random::from(random); let kx = ring::agreement::EphemeralPrivateKey::generate(&ring::agreement::X25519, &rng) .unwrap() .compute_public_key() .unwrap(); let mut server = quic::ServerConnection::new( server_config, quic::Version::V1, b"server params".to_vec(), ) .unwrap(); let client_hello = MessagePayload::handshake(HandshakeMessagePayload { typ: HandshakeType::ClientHello, payload: HandshakePayload::ClientHello(ClientHelloPayload { client_version: ProtocolVersion::TLSv1_2, random: random.clone(), session_id: SessionId::random().unwrap(), cipher_suites: vec![CipherSuite::TLS13_AES_128_GCM_SHA256], compression_methods: vec![Compression::Null], extensions: vec![ ClientExtension::NamedGroups(vec![NamedGroup::X25519]), ClientExtension::SignatureAlgorithms(vec![SignatureScheme::ED25519]), ClientExtension::KeyShare(vec![KeyShareEntry { group: NamedGroup::X25519, payload: PayloadU16::new(kx.as_ref().to_vec()), }]), ], }), }); let mut buf = Vec::with_capacity(512); client_hello.encode(&mut buf); assert_eq!( server .read_hs(&mut buf.as_slice()) .err(), Some(Error::PeerIncompatible( PeerIncompatible::SupportedVersionsExtensionRequired )), ); } #[test] fn packet_key_api() { use rustls::quic::{Keys, Version}; use rustls::Side; // Test vectors: https://www.rfc-editor.org/rfc/rfc9001.html#name-client-initial const CONNECTION_ID: &[u8] = &[0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08]; const PACKET_NUMBER: u64 = 2; const PLAIN_HEADER: &[u8] = &[ 0xc3, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x00, 0x00, 0x00, 0x02, ]; const PAYLOAD: &[u8] = &[ 0x06, 0x00, 0x40, 0xf1, 0x01, 0x00, 0x00, 0xed, 0x03, 0x03, 0xeb, 0xf8, 0xfa, 0x56, 0xf1, 0x29, 0x39, 0xb9, 0x58, 0x4a, 0x38, 0x96, 0x47, 0x2e, 0xc4, 0x0b, 0xb8, 0x63, 0xcf, 0xd3, 0xe8, 0x68, 0x04, 0xfe, 0x3a, 0x47, 0xf0, 0x6a, 0x2b, 0x69, 0x48, 0x4c, 0x00, 0x00, 0x04, 0x13, 0x01, 0x13, 0x02, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18, 0x00, 0x10, 0x00, 0x07, 0x00, 0x05, 0x04, 0x61, 0x6c, 0x70, 0x6e, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x26, 0x00, 0x24, 0x00, 0x1d, 0x00, 0x20, 0x93, 0x70, 0xb2, 0xc9, 0xca, 0xa4, 0x7f, 0xba, 0xba, 0xf4, 0x55, 0x9f, 0xed, 0xba, 0x75, 0x3d, 0xe1, 0x71, 0xfa, 0x71, 0xf5, 0x0f, 0x1c, 0xe1, 0x5d, 0x43, 0xe9, 0x94, 0xec, 0x74, 0xd7, 0x48, 0x00, 0x2b, 0x00, 0x03, 0x02, 0x03, 0x04, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x0e, 0x04, 0x03, 0x05, 0x03, 0x06, 0x03, 0x02, 0x03, 0x08, 0x04, 0x08, 0x05, 0x08, 0x06, 0x00, 0x2d, 0x00, 0x02, 0x01, 0x01, 0x00, 0x1c, 0x00, 0x02, 0x40, 0x01, 0x00, 0x39, 0x00, 0x32, 0x04, 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x05, 0x04, 0x80, 0x00, 0xff, 0xff, 0x07, 0x04, 0x80, 0x00, 0xff, 0xff, 0x08, 0x01, 0x10, 0x01, 0x04, 0x80, 0x00, 0x75, 0x30, 0x09, 0x01, 0x10, 0x0f, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x06, 0x04, 0x80, 0x00, 0xff, 0xff, ]; let client_keys = Keys::initial(Version::V1, &CONNECTION_ID, Side::Client); assert_eq!( client_keys .local .packet .confidentiality_limit(), 2u64.pow(23) ); assert_eq!( client_keys .local .packet .integrity_limit(), 2u64.pow(52) ); assert_eq!(client_keys.local.packet.tag_len(), 16); let mut buf = Vec::new(); buf.extend(PLAIN_HEADER); buf.extend(PAYLOAD); let header_len = PLAIN_HEADER.len(); let tag_len = client_keys.local.packet.tag_len(); let padding_len = 1200 - header_len - PAYLOAD.len() - tag_len; buf.extend(std::iter::repeat(0).take(padding_len)); let (header, payload) = buf.split_at_mut(header_len); let tag = client_keys .local .packet .encrypt_in_place(PACKET_NUMBER, &*header, payload) .unwrap(); let sample_len = client_keys.local.header.sample_len(); let sample = &payload[..sample_len]; let (first, rest) = header.split_at_mut(1); client_keys .local .header .encrypt_in_place(sample, &mut first[0], &mut rest[17..21]) .unwrap(); buf.extend_from_slice(tag.as_ref()); const PROTECTED: &[u8] = &[ 0xc0, 0x00, 0x00, 0x00, 0x01, 0x08, 0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0x00, 0x00, 0x44, 0x9e, 0x7b, 0x9a, 0xec, 0x34, 0xd1, 0xb1, 0xc9, 0x8d, 0xd7, 0x68, 0x9f, 0xb8, 0xec, 0x11, 0xd2, 0x42, 0xb1, 0x23, 0xdc, 0x9b, 0xd8, 0xba, 0xb9, 0x36, 0xb4, 0x7d, 0x92, 0xec, 0x35, 0x6c, 0x0b, 0xab, 0x7d, 0xf5, 0x97, 0x6d, 0x27, 0xcd, 0x44, 0x9f, 0x63, 0x30, 0x00, 0x99, 0xf3, 0x99, 0x1c, 0x26, 0x0e, 0xc4, 0xc6, 0x0d, 0x17, 0xb3, 0x1f, 0x84, 0x29, 0x15, 0x7b, 0xb3, 0x5a, 0x12, 0x82, 0xa6, 0x43, 0xa8, 0xd2, 0x26, 0x2c, 0xad, 0x67, 0x50, 0x0c, 0xad, 0xb8, 0xe7, 0x37, 0x8c, 0x8e, 0xb7, 0x53, 0x9e, 0xc4, 0xd4, 0x90, 0x5f, 0xed, 0x1b, 0xee, 0x1f, 0xc8, 0xaa, 0xfb, 0xa1, 0x7c, 0x75, 0x0e, 0x2c, 0x7a, 0xce, 0x01, 0xe6, 0x00, 0x5f, 0x80, 0xfc, 0xb7, 0xdf, 0x62, 0x12, 0x30, 0xc8, 0x37, 0x11, 0xb3, 0x93, 0x43, 0xfa, 0x02, 0x8c, 0xea, 0x7f, 0x7f, 0xb5, 0xff, 0x89, 0xea, 0xc2, 0x30, 0x82, 0x49, 0xa0, 0x22, 0x52, 0x15, 0x5e, 0x23, 0x47, 0xb6, 0x3d, 0x58, 0xc5, 0x45, 0x7a, 0xfd, 0x84, 0xd0, 0x5d, 0xff, 0xfd, 0xb2, 0x03, 0x92, 0x84, 0x4a, 0xe8, 0x12, 0x15, 0x46, 0x82, 0xe9, 0xcf, 0x01, 0x2f, 0x90, 0x21, 0xa6, 0xf0, 0xbe, 0x17, 0xdd, 0xd0, 0xc2, 0x08, 0x4d, 0xce, 0x25, 0xff, 0x9b, 0x06, 0xcd, 0xe5, 0x35, 0xd0, 0xf9, 0x20, 0xa2, 0xdb, 0x1b, 0xf3, 0x62, 0xc2, 0x3e, 0x59, 0x6d, 0x11, 0xa4, 0xf5, 0xa6, 0xcf, 0x39, 0x48, 0x83, 0x8a, 0x3a, 0xec, 0x4e, 0x15, 0xda, 0xf8, 0x50, 0x0a, 0x6e, 0xf6, 0x9e, 0xc4, 0xe3, 0xfe, 0xb6, 0xb1, 0xd9, 0x8e, 0x61, 0x0a, 0xc8, 0xb7, 0xec, 0x3f, 0xaf, 0x6a, 0xd7, 0x60, 0xb7, 0xba, 0xd1, 0xdb, 0x4b, 0xa3, 0x48, 0x5e, 0x8a, 0x94, 0xdc, 0x25, 0x0a, 0xe3, 0xfd, 0xb4, 0x1e, 0xd1, 0x5f, 0xb6, 0xa8, 0xe5, 0xeb, 0xa0, 0xfc, 0x3d, 0xd6, 0x0b, 0xc8, 0xe3, 0x0c, 0x5c, 0x42, 0x87, 0xe5, 0x38, 0x05, 0xdb, 0x05, 0x9a, 0xe0, 0x64, 0x8d, 0xb2, 0xf6, 0x42, 0x64, 0xed, 0x5e, 0x39, 0xbe, 0x2e, 0x20, 0xd8, 0x2d, 0xf5, 0x66, 0xda, 0x8d, 0xd5, 0x99, 0x8c, 0xca, 0xbd, 0xae, 0x05, 0x30, 0x60, 0xae, 0x6c, 0x7b, 0x43, 0x78, 0xe8, 0x46, 0xd2, 0x9f, 0x37, 0xed, 0x7b, 0x4e, 0xa9, 0xec, 0x5d, 0x82, 0xe7, 0x96, 0x1b, 0x7f, 0x25, 0xa9, 0x32, 0x38, 0x51, 0xf6, 0x81, 0xd5, 0x82, 0x36, 0x3a, 0xa5, 0xf8, 0x99, 0x37, 0xf5, 0xa6, 0x72, 0x58, 0xbf, 0x63, 0xad, 0x6f, 0x1a, 0x0b, 0x1d, 0x96, 0xdb, 0xd4, 0xfa, 0xdd, 0xfc, 0xef, 0xc5, 0x26, 0x6b, 0xa6, 0x61, 0x17, 0x22, 0x39, 0x5c, 0x90, 0x65, 0x56, 0xbe, 0x52, 0xaf, 0xe3, 0xf5, 0x65, 0x63, 0x6a, 0xd1, 0xb1, 0x7d, 0x50, 0x8b, 0x73, 0xd8, 0x74, 0x3e, 0xeb, 0x52, 0x4b, 0xe2, 0x2b, 0x3d, 0xcb, 0xc2, 0xc7, 0x46, 0x8d, 0x54, 0x11, 0x9c, 0x74, 0x68, 0x44, 0x9a, 0x13, 0xd8, 0xe3, 0xb9, 0x58, 0x11, 0xa1, 0x98, 0xf3, 0x49, 0x1d, 0xe3, 0xe7, 0xfe, 0x94, 0x2b, 0x33, 0x04, 0x07, 0xab, 0xf8, 0x2a, 0x4e, 0xd7, 0xc1, 0xb3, 0x11, 0x66, 0x3a, 0xc6, 0x98, 0x90, 0xf4, 0x15, 0x70, 0x15, 0x85, 0x3d, 0x91, 0xe9, 0x23, 0x03, 0x7c, 0x22, 0x7a, 0x33, 0xcd, 0xd5, 0xec, 0x28, 0x1c, 0xa3, 0xf7, 0x9c, 0x44, 0x54, 0x6b, 0x9d, 0x90, 0xca, 0x00, 0xf0, 0x64, 0xc9, 0x9e, 0x3d, 0xd9, 0x79, 0x11, 0xd3, 0x9f, 0xe9, 0xc5, 0xd0, 0xb2, 0x3a, 0x22, 0x9a, 0x23, 0x4c, 0xb3, 0x61, 0x86, 0xc4, 0x81, 0x9e, 0x8b, 0x9c, 0x59, 0x27, 0x72, 0x66, 0x32, 0x29, 0x1d, 0x6a, 0x41, 0x82, 0x11, 0xcc, 0x29, 0x62, 0xe2, 0x0f, 0xe4, 0x7f, 0xeb, 0x3e, 0xdf, 0x33, 0x0f, 0x2c, 0x60, 0x3a, 0x9d, 0x48, 0xc0, 0xfc, 0xb5, 0x69, 0x9d, 0xbf, 0xe5, 0x89, 0x64, 0x25, 0xc5, 0xba, 0xc4, 0xae, 0xe8, 0x2e, 0x57, 0xa8, 0x5a, 0xaf, 0x4e, 0x25, 0x13, 0xe4, 0xf0, 0x57, 0x96, 0xb0, 0x7b, 0xa2, 0xee, 0x47, 0xd8, 0x05, 0x06, 0xf8, 0xd2, 0xc2, 0x5e, 0x50, 0xfd, 0x14, 0xde, 0x71, 0xe6, 0xc4, 0x18, 0x55, 0x93, 0x02, 0xf9, 0x39, 0xb0, 0xe1, 0xab, 0xd5, 0x76, 0xf2, 0x79, 0xc4, 0xb2, 0xe0, 0xfe, 0xb8, 0x5c, 0x1f, 0x28, 0xff, 0x18, 0xf5, 0x88, 0x91, 0xff, 0xef, 0x13, 0x2e, 0xef, 0x2f, 0xa0, 0x93, 0x46, 0xae, 0xe3, 0x3c, 0x28, 0xeb, 0x13, 0x0f, 0xf2, 0x8f, 0x5b, 0x76, 0x69, 0x53, 0x33, 0x41, 0x13, 0x21, 0x19, 0x96, 0xd2, 0x00, 0x11, 0xa1, 0x98, 0xe3, 0xfc, 0x43, 0x3f, 0x9f, 0x25, 0x41, 0x01, 0x0a, 0xe1, 0x7c, 0x1b, 0xf2, 0x02, 0x58, 0x0f, 0x60, 0x47, 0x47, 0x2f, 0xb3, 0x68, 0x57, 0xfe, 0x84, 0x3b, 0x19, 0xf5, 0x98, 0x40, 0x09, 0xdd, 0xc3, 0x24, 0x04, 0x4e, 0x84, 0x7a, 0x4f, 0x4a, 0x0a, 0xb3, 0x4f, 0x71, 0x95, 0x95, 0xde, 0x37, 0x25, 0x2d, 0x62, 0x35, 0x36, 0x5e, 0x9b, 0x84, 0x39, 0x2b, 0x06, 0x10, 0x85, 0x34, 0x9d, 0x73, 0x20, 0x3a, 0x4a, 0x13, 0xe9, 0x6f, 0x54, 0x32, 0xec, 0x0f, 0xd4, 0xa1, 0xee, 0x65, 0xac, 0xcd, 0xd5, 0xe3, 0x90, 0x4d, 0xf5, 0x4c, 0x1d, 0xa5, 0x10, 0xb0, 0xff, 0x20, 0xdc, 0xc0, 0xc7, 0x7f, 0xcb, 0x2c, 0x0e, 0x0e, 0xb6, 0x05, 0xcb, 0x05, 0x04, 0xdb, 0x87, 0x63, 0x2c, 0xf3, 0xd8, 0xb4, 0xda, 0xe6, 0xe7, 0x05, 0x76, 0x9d, 0x1d, 0xe3, 0x54, 0x27, 0x01, 0x23, 0xcb, 0x11, 0x45, 0x0e, 0xfc, 0x60, 0xac, 0x47, 0x68, 0x3d, 0x7b, 0x8d, 0x0f, 0x81, 0x13, 0x65, 0x56, 0x5f, 0xd9, 0x8c, 0x4c, 0x8e, 0xb9, 0x36, 0xbc, 0xab, 0x8d, 0x06, 0x9f, 0xc3, 0x3b, 0xd8, 0x01, 0xb0, 0x3a, 0xde, 0xa2, 0xe1, 0xfb, 0xc5, 0xaa, 0x46, 0x3d, 0x08, 0xca, 0x19, 0x89, 0x6d, 0x2b, 0xf5, 0x9a, 0x07, 0x1b, 0x85, 0x1e, 0x6c, 0x23, 0x90, 0x52, 0x17, 0x2f, 0x29, 0x6b, 0xfb, 0x5e, 0x72, 0x40, 0x47, 0x90, 0xa2, 0x18, 0x10, 0x14, 0xf3, 0xb9, 0x4a, 0x4e, 0x97, 0xd1, 0x17, 0xb4, 0x38, 0x13, 0x03, 0x68, 0xcc, 0x39, 0xdb, 0xb2, 0xd1, 0x98, 0x06, 0x5a, 0xe3, 0x98, 0x65, 0x47, 0x92, 0x6c, 0xd2, 0x16, 0x2f, 0x40, 0xa2, 0x9f, 0x0c, 0x3c, 0x87, 0x45, 0xc0, 0xf5, 0x0f, 0xba, 0x38, 0x52, 0xe5, 0x66, 0xd4, 0x45, 0x75, 0xc2, 0x9d, 0x39, 0xa0, 0x3f, 0x0c, 0xda, 0x72, 0x19, 0x84, 0xb6, 0xf4, 0x40, 0x59, 0x1f, 0x35, 0x5e, 0x12, 0xd4, 0x39, 0xff, 0x15, 0x0a, 0xab, 0x76, 0x13, 0x49, 0x9d, 0xbd, 0x49, 0xad, 0xab, 0xc8, 0x67, 0x6e, 0xef, 0x02, 0x3b, 0x15, 0xb6, 0x5b, 0xfc, 0x5c, 0xa0, 0x69, 0x48, 0x10, 0x9f, 0x23, 0xf3, 0x50, 0xdb, 0x82, 0x12, 0x35, 0x35, 0xeb, 0x8a, 0x74, 0x33, 0xbd, 0xab, 0xcb, 0x90, 0x92, 0x71, 0xa6, 0xec, 0xbc, 0xb5, 0x8b, 0x93, 0x6a, 0x88, 0xcd, 0x4e, 0x8f, 0x2e, 0x6f, 0xf5, 0x80, 0x01, 0x75, 0xf1, 0x13, 0x25, 0x3d, 0x8f, 0xa9, 0xca, 0x88, 0x85, 0xc2, 0xf5, 0x52, 0xe6, 0x57, 0xdc, 0x60, 0x3f, 0x25, 0x2e, 0x1a, 0x8e, 0x30, 0x8f, 0x76, 0xf0, 0xbe, 0x79, 0xe2, 0xfb, 0x8f, 0x5d, 0x5f, 0xbb, 0xe2, 0xe3, 0x0e, 0xca, 0xdd, 0x22, 0x07, 0x23, 0xc8, 0xc0, 0xae, 0xa8, 0x07, 0x8c, 0xdf, 0xcb, 0x38, 0x68, 0x26, 0x3f, 0xf8, 0xf0, 0x94, 0x00, 0x54, 0xda, 0x48, 0x78, 0x18, 0x93, 0xa7, 0xe4, 0x9a, 0xd5, 0xaf, 0xf4, 0xaf, 0x30, 0x0c, 0xd8, 0x04, 0xa6, 0xb6, 0x27, 0x9a, 0xb3, 0xff, 0x3a, 0xfb, 0x64, 0x49, 0x1c, 0x85, 0x19, 0x4a, 0xab, 0x76, 0x0d, 0x58, 0xa6, 0x06, 0x65, 0x4f, 0x9f, 0x44, 0x00, 0xe8, 0xb3, 0x85, 0x91, 0x35, 0x6f, 0xbf, 0x64, 0x25, 0xac, 0xa2, 0x6d, 0xc8, 0x52, 0x44, 0x25, 0x9f, 0xf2, 0xb1, 0x9c, 0x41, 0xb9, 0xf9, 0x6f, 0x3c, 0xa9, 0xec, 0x1d, 0xde, 0x43, 0x4d, 0xa7, 0xd2, 0xd3, 0x92, 0xb9, 0x05, 0xdd, 0xf3, 0xd1, 0xf9, 0xaf, 0x93, 0xd1, 0xaf, 0x59, 0x50, 0xbd, 0x49, 0x3f, 0x5a, 0xa7, 0x31, 0xb4, 0x05, 0x6d, 0xf3, 0x1b, 0xd2, 0x67, 0xb6, 0xb9, 0x0a, 0x07, 0x98, 0x31, 0xaa, 0xf5, 0x79, 0xbe, 0x0a, 0x39, 0x01, 0x31, 0x37, 0xaa, 0xc6, 0xd4, 0x04, 0xf5, 0x18, 0xcf, 0xd4, 0x68, 0x40, 0x64, 0x7e, 0x78, 0xbf, 0xe7, 0x06, 0xca, 0x4c, 0xf5, 0xe9, 0xc5, 0x45, 0x3e, 0x9f, 0x7c, 0xfd, 0x2b, 0x8b, 0x4c, 0x8d, 0x16, 0x9a, 0x44, 0xe5, 0x5c, 0x88, 0xd4, 0xa9, 0xa7, 0xf9, 0x47, 0x42, 0x41, 0xe2, 0x21, 0xaf, 0x44, 0x86, 0x00, 0x18, 0xab, 0x08, 0x56, 0x97, 0x2e, 0x19, 0x4c, 0xd9, 0x34, ]; assert_eq!(&buf, PROTECTED); let (header, payload) = buf.split_at_mut(header_len); let (first, rest) = header.split_at_mut(1); let sample = &payload[..sample_len]; let server_keys = Keys::initial(Version::V1, &CONNECTION_ID, Side::Server); server_keys .remote .header .decrypt_in_place(sample, &mut first[0], &mut rest[17..21]) .unwrap(); let payload = server_keys .remote .packet .decrypt_in_place(PACKET_NUMBER, &*header, payload) .unwrap(); assert_eq!(&payload[..PAYLOAD.len()], PAYLOAD); assert_eq!(payload.len(), buf.len() - header_len - tag_len); } #[test] fn test_quic_exporter() { for &kt in ALL_KEY_TYPES.iter() { let client_config = make_client_config_with_versions(kt, &[&rustls::version::TLS13]); let server_config = make_server_config_with_versions(kt, &[&rustls::version::TLS13]); do_exporter_test(client_config, server_config); } } } // mod test_quic #[test] fn test_client_does_not_offer_sha1() { use rustls::internal::msgs::{ codec::Reader, handshake::HandshakePayload, message::MessagePayload, message::OpaqueMessage, }; use rustls::HandshakeType; for kt in ALL_KEY_TYPES.iter() { for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(*kt, &[version]); let (mut client, _) = make_pair_for_configs(client_config, make_server_config(*kt)); assert!(client.wants_write()); let mut buf = [0u8; 262144]; let sz = client .write_tls(&mut buf.as_mut()) .unwrap(); let msg = OpaqueMessage::read(&mut Reader::init(&buf[..sz])).unwrap(); let msg = Message::try_from(msg.into_plain_message()).unwrap(); assert!(msg.is_handshake_type(HandshakeType::ClientHello)); let client_hello = match msg.payload { MessagePayload::Handshake { parsed, .. } => match parsed.payload { HandshakePayload::ClientHello(ch) => ch, _ => unreachable!(), }, _ => unreachable!(), }; let sigalgs = client_hello .get_sigalgs_extension() .unwrap(); assert!( !sigalgs.contains(&SignatureScheme::RSA_PKCS1_SHA1), "sha1 unexpectedly offered" ); } } } #[test] fn test_client_config_keyshare() { let client_config = make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); do_handshake_until_error(&mut client, &mut server).unwrap(); } #[test] fn test_client_config_keyshare_mismatch() { let client_config = make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); assert!(do_handshake_until_error(&mut client, &mut server).is_err()); } #[cfg(feature = "tls12")] #[test] fn test_client_sends_helloretryrequest() { // client sends a secp384r1 key share let mut client_config = make_client_config_with_kx_groups( KeyType::Rsa, &[&rustls::kx_group::SECP384R1, &rustls::kx_group::X25519], ); let storage = Arc::new(ClientStorage::new()); client_config.resumption = Resumption::store(storage.clone()); // but server only accepts x25519, so a HRR is required let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); let (mut client, mut server) = make_pair_for_configs(client_config, server_config); // client sends hello { let mut pipe = OtherSession::new(&mut server); let wrlen = client.write_tls(&mut pipe).unwrap(); assert!(wrlen > 200); assert_eq!(pipe.writevs.len(), 1); assert!(pipe.writevs[0].len() == 1); } // server sends HRR { let mut pipe = OtherSession::new(&mut client); let wrlen = server.write_tls(&mut pipe).unwrap(); assert!(wrlen < 100); // just the hello retry request assert_eq!(pipe.writevs.len(), 1); // only one writev assert!(pipe.writevs[0].len() == 2); // hello retry request and CCS } // client sends fixed hello { let mut pipe = OtherSession::new(&mut server); let wrlen = client.write_tls(&mut pipe).unwrap(); assert!(wrlen > 200); // just the client hello retry assert_eq!(pipe.writevs.len(), 1); // only one writev assert!(pipe.writevs[0].len() == 2); // only a CCS & client hello retry } // server completes handshake { let mut pipe = OtherSession::new(&mut client); let wrlen = server.write_tls(&mut pipe).unwrap(); assert!(wrlen > 200); assert_eq!(pipe.writevs.len(), 1); assert!(pipe.writevs[0].len() == 5); // server hello / encrypted exts / cert / cert-verify / finished } do_handshake_until_error(&mut client, &mut server).unwrap(); // client only did following storage queries: println!("storage {:#?}", storage.ops()); assert_eq!(storage.ops().len(), 9); assert!(matches!( storage.ops()[0], ClientStorageOp::TakeTls13Ticket(_, false) )); assert!(matches!( storage.ops()[1], ClientStorageOp::GetTls12Session(_, false) )); assert!(matches!( storage.ops()[2], ClientStorageOp::GetKxHint(_, None) )); assert!(matches!( storage.ops()[3], ClientStorageOp::SetKxHint(_, rustls::NamedGroup::X25519) )); assert!(matches!( storage.ops()[4], ClientStorageOp::RemoveTls12Session(_) )); // server sends 4 tickets by default assert!(matches!( storage.ops()[5], ClientStorageOp::InsertTls13Ticket(_) )); assert!(matches!( storage.ops()[6], ClientStorageOp::InsertTls13Ticket(_) )); assert!(matches!( storage.ops()[7], ClientStorageOp::InsertTls13Ticket(_) )); assert!(matches!( storage.ops()[8], ClientStorageOp::InsertTls13Ticket(_) )); } #[test] fn test_client_rejects_hrr_with_varied_session_id() { use rustls::internal::msgs::handshake::SessionId; let different_session_id = SessionId::random().unwrap(); let assert_client_sends_hello_with_secp384 = |msg: &mut Message| -> Altered { if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { let keyshares = ch .get_keyshare_extension() .expect("missing key share extension"); assert_eq!(keyshares.len(), 1); assert_eq!(keyshares[0].group, rustls::NamedGroup::secp384r1); ch.session_id = different_session_id; *encoded = Payload::new(parsed.get_encoding()); } } Altered::InPlace }; let assert_server_requests_retry_and_echoes_session_id = |msg: &mut Message| -> Altered { if let MessagePayload::Handshake { parsed, .. } = &mut msg.payload { if let HandshakePayload::HelloRetryRequest(hrr) = &mut parsed.payload { let group = hrr.get_requested_key_share_group(); assert_eq!(group, Some(rustls::NamedGroup::X25519)); assert_eq!(hrr.session_id, different_session_id); } } Altered::InPlace }; // client prefers a secp384r1 key share, server only accepts x25519 let client_config = make_client_config_with_kx_groups( KeyType::Rsa, &[&rustls::kx_group::SECP384R1, &rustls::kx_group::X25519], ); let server_config = make_server_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); let (client, server) = make_pair_for_configs(client_config, server_config); let (mut client, mut server) = (client.into(), server.into()); transfer_altered( &mut client, assert_client_sends_hello_with_secp384, &mut server, ); server.process_new_packets().unwrap(); transfer_altered( &mut server, assert_server_requests_retry_and_echoes_session_id, &mut client, ); assert_eq!( client.process_new_packets(), Err(Error::PeerMisbehaved( PeerMisbehaved::IllegalHelloRetryRequestWithWrongSessionId )) ); } #[cfg(feature = "tls12")] #[test] fn test_client_attempts_to_use_unsupported_kx_group() { // common to both client configs let shared_storage = Arc::new(ClientStorage::new()); // first, client sends a x25519 and server agrees. x25519 is inserted // into kx group cache. let mut client_config_1 = make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::X25519]); client_config_1.resumption = Resumption::store(shared_storage.clone()); // second, client only supports secp-384 and so kx group cache // contains an unusable value. let mut client_config_2 = make_client_config_with_kx_groups(KeyType::Rsa, &[&rustls::kx_group::SECP384R1]); client_config_2.resumption = Resumption::store(shared_storage.clone()); let server_config = make_server_config(KeyType::Rsa); // first handshake let (mut client_1, mut server) = make_pair_for_configs(client_config_1, server_config.clone()); do_handshake_until_error(&mut client_1, &mut server).unwrap(); let ops = shared_storage.ops(); println!("storage {:#?}", ops); assert_eq!(ops.len(), 9); assert!(matches!( ops[3], ClientStorageOp::SetKxHint(_, rustls::NamedGroup::X25519) )); // second handshake let (mut client_2, mut server) = make_pair_for_configs(client_config_2, server_config); do_handshake_until_error(&mut client_2, &mut server).unwrap(); let ops = shared_storage.ops(); println!("storage {:?} {:#?}", ops.len(), ops); assert_eq!(ops.len(), 17); assert!(matches!(ops[9], ClientStorageOp::TakeTls13Ticket(_, true))); assert!(matches!( ops[10], ClientStorageOp::GetKxHint(_, Some(rustls::NamedGroup::X25519)) )); assert!(matches!( ops[11], ClientStorageOp::SetKxHint(_, rustls::NamedGroup::secp384r1) )); } #[cfg(feature = "tls12")] #[test] fn test_tls13_client_resumption_does_not_reuse_tickets() { let shared_storage = Arc::new(ClientStorage::new()); let mut client_config = make_client_config(KeyType::Rsa); client_config.resumption = Resumption::store(shared_storage.clone()); let client_config = Arc::new(client_config); let mut server_config = make_server_config(KeyType::Rsa); server_config.send_tls13_tickets = 5; let server_config = Arc::new(server_config); // first handshake: client obtains 5 tickets from server. let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake_until_error(&mut client, &mut server).unwrap(); let ops = shared_storage.ops_and_reset(); println!("storage {:#?}", ops); assert_eq!(ops.len(), 10); assert!(matches!(ops[5], ClientStorageOp::InsertTls13Ticket(_))); assert!(matches!(ops[6], ClientStorageOp::InsertTls13Ticket(_))); assert!(matches!(ops[7], ClientStorageOp::InsertTls13Ticket(_))); assert!(matches!(ops[8], ClientStorageOp::InsertTls13Ticket(_))); assert!(matches!(ops[9], ClientStorageOp::InsertTls13Ticket(_))); // 5 subsequent handshakes: all are resumptions // Note: we don't do complete the handshakes, because that means // we get five additional tickets per connection which is unhelpful // in this test. It also acts to record a "Happy Eyeballs"-type use // case, where a client speculatively makes many connection attempts // in parallel without knowledge of which will work due to underlying // connectivity uncertainty. for _ in 0..5 { let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); let ops = shared_storage.ops_and_reset(); assert!(matches!(ops[0], ClientStorageOp::TakeTls13Ticket(_, true))); } // 6th subsequent handshake: cannot be resumed; we ran out of tickets let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); let ops = shared_storage.ops_and_reset(); println!("last {:?}", ops); assert!(matches!(ops[0], ClientStorageOp::TakeTls13Ticket(_, false))); } #[test] fn test_client_mtu_reduction() { struct CollectWrites { writevs: Vec>, } impl io::Write for CollectWrites { fn write(&mut self, _: &[u8]) -> io::Result { panic!() } fn flush(&mut self) -> io::Result<()> { panic!() } fn write_vectored<'b>(&mut self, b: &[io::IoSlice<'b>]) -> io::Result { let writes = b .iter() .map(|slice| slice.len()) .collect::>(); let len = writes.iter().sum(); self.writevs.push(writes); Ok(len) } } fn collect_write_lengths(client: &mut ClientConnection) -> Vec { let mut collector = CollectWrites { writevs: vec![] }; client .write_tls(&mut collector) .unwrap(); assert_eq!(collector.writevs.len(), 1); collector.writevs[0].clone() } for kt in ALL_KEY_TYPES.iter() { let mut client_config = make_client_config(*kt); client_config.max_fragment_size = Some(64); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); let writes = collect_write_lengths(&mut client); println!("writes at mtu=64: {:?}", writes); assert!(writes.iter().all(|x| *x <= 64)); assert!(writes.len() > 1); } } #[test] fn test_server_mtu_reduction() { let mut server_config = make_server_config(KeyType::Rsa); server_config.max_fragment_size = Some(64); server_config.send_half_rtt_data = true; let (mut client, mut server) = make_pair_for_configs(make_client_config(KeyType::Rsa), server_config); let big_data = [0u8; 2048]; server .writer() .write_all(&big_data) .unwrap(); let encryption_overhead = 20; // FIXME: see issue #991 transfer(&mut client, &mut server); server.process_new_packets().unwrap(); { let mut pipe = OtherSession::new(&mut client); server.write_tls(&mut pipe).unwrap(); assert_eq!(pipe.writevs.len(), 1); assert!(pipe.writevs[0] .iter() .all(|x| *x <= 64 + encryption_overhead)); } client.process_new_packets().unwrap(); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); { let mut pipe = OtherSession::new(&mut client); server.write_tls(&mut pipe).unwrap(); assert_eq!(pipe.writevs.len(), 1); assert!(pipe.writevs[0] .iter() .all(|x| *x <= 64 + encryption_overhead)); } client.process_new_packets().unwrap(); check_read(&mut client.reader(), &big_data); } fn check_client_max_fragment_size(size: usize) -> Option { let mut client_config = make_client_config(KeyType::Ed25519); client_config.max_fragment_size = Some(size); ClientConnection::new(Arc::new(client_config), dns_name("localhost")).err() } #[test] fn bad_client_max_fragment_sizes() { assert_eq!( check_client_max_fragment_size(31), Some(Error::BadMaxFragmentSize) ); assert_eq!(check_client_max_fragment_size(32), None); assert_eq!(check_client_max_fragment_size(64), None); assert_eq!(check_client_max_fragment_size(1460), None); assert_eq!(check_client_max_fragment_size(0x4000), None); assert_eq!(check_client_max_fragment_size(0x4005), None); assert_eq!( check_client_max_fragment_size(0x4006), Some(Error::BadMaxFragmentSize) ); assert_eq!( check_client_max_fragment_size(0xffff), Some(Error::BadMaxFragmentSize) ); } fn assert_lt(left: usize, right: usize) { if left >= right { panic!("expected {} < {}", left, right); } } #[test] fn connection_types_are_not_huge() { // Arbitrary sizes assert_lt(mem::size_of::(), 1600); assert_lt(mem::size_of::(), 1600); } use rustls::internal::msgs::{ handshake::ClientExtension, handshake::HandshakePayload, message::Message, message::MessagePayload, }; #[test] fn test_server_rejects_duplicate_sni_names() { fn duplicate_sni_payload(msg: &mut Message) -> Altered { if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { for mut ext in ch.extensions.iter_mut() { if let ClientExtension::ServerName(snr) = &mut ext { snr.push(snr[0].clone()); } } } *encoded = Payload::new(parsed.get_encoding()); } Altered::InPlace } let (client, server) = make_pair(KeyType::Rsa); let (mut client, mut server) = (client.into(), server.into()); transfer_altered(&mut client, duplicate_sni_payload, &mut server); assert_eq!( server.process_new_packets(), Err(Error::PeerMisbehaved( PeerMisbehaved::DuplicateServerNameTypes )) ); } #[test] fn test_server_rejects_empty_sni_extension() { fn empty_sni_payload(msg: &mut Message) -> Altered { if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { for mut ext in ch.extensions.iter_mut() { if let ClientExtension::ServerName(snr) = &mut ext { snr.clear(); } } } *encoded = Payload::new(parsed.get_encoding()); } Altered::InPlace } let (client, server) = make_pair(KeyType::Rsa); let (mut client, mut server) = (client.into(), server.into()); transfer_altered(&mut client, empty_sni_payload, &mut server); assert_eq!( server.process_new_packets(), Err(Error::PeerMisbehaved( PeerMisbehaved::ServerNameMustContainOneHostName )) ); } #[test] fn test_server_rejects_clients_without_any_kx_group_overlap() { fn different_kx_group(msg: &mut Message) -> Altered { if let MessagePayload::Handshake { parsed, encoded } = &mut msg.payload { if let HandshakePayload::ClientHello(ch) = &mut parsed.payload { for mut ext in ch.extensions.iter_mut() { if let ClientExtension::NamedGroups(ngs) = &mut ext { ngs.clear(); } if let ClientExtension::KeyShare(ks) = &mut ext { ks.clear(); } } } *encoded = Payload::new(parsed.get_encoding()); } Altered::InPlace } let (client, server) = make_pair(KeyType::Rsa); let (mut client, mut server) = (client.into(), server.into()); transfer_altered(&mut client, different_kx_group, &mut server); assert_eq!( server.process_new_packets(), Err(Error::PeerIncompatible( PeerIncompatible::NoKxGroupsInCommon )) ); } #[test] fn test_client_rejects_illegal_tls13_ccs() { fn corrupt_ccs(msg: &mut Message) -> Altered { if let MessagePayload::ChangeCipherSpec(_) = &mut msg.payload { println!("seen CCS {:?}", msg); return Altered::Raw(vec![0x14, 0x03, 0x03, 0x00, 0x02, 0x01, 0x02]); } Altered::InPlace } let (mut client, mut server) = make_pair(KeyType::Rsa); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); let (mut server, mut client) = (server.into(), client.into()); transfer_altered(&mut server, corrupt_ccs, &mut client); assert_eq!( client.process_new_packets(), Err(Error::PeerMisbehaved( PeerMisbehaved::IllegalMiddleboxChangeCipherSpec )) ); } /// https://github.com/rustls/rustls/issues/797 #[cfg(feature = "tls12")] #[test] fn test_client_tls12_no_resume_after_server_downgrade() { let mut client_config = common::make_client_config(KeyType::Ed25519); let client_storage = Arc::new(ClientStorage::new()); client_config.resumption = Resumption::store(client_storage.clone()); let client_config = Arc::new(client_config); let server_config_1 = Arc::new(common::finish_server_config( KeyType::Ed25519, ServerConfig::builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS13]) .unwrap(), )); let mut server_config_2 = common::finish_server_config( KeyType::Ed25519, ServerConfig::builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(&[&rustls::version::TLS12]) .unwrap(), ); server_config_2.session_storage = Arc::new(rustls::server::NoServerSessionStorage {}); dbg!("handshake 1"); let mut client_1 = ClientConnection::new(client_config.clone(), "localhost".try_into().unwrap()).unwrap(); let mut server_1 = ServerConnection::new(server_config_1).unwrap(); common::do_handshake(&mut client_1, &mut server_1); assert_eq!(client_storage.ops().len(), 9); println!("hs1 storage ops: {:#?}", client_storage.ops()); assert!(matches!( client_storage.ops()[3], ClientStorageOp::SetKxHint(_, _) )); assert!(matches!( client_storage.ops()[4], ClientStorageOp::RemoveTls12Session(_) )); assert!(matches!( client_storage.ops()[5], ClientStorageOp::InsertTls13Ticket(_) )); dbg!("handshake 2"); let mut client_2 = ClientConnection::new(client_config, "localhost".try_into().unwrap()).unwrap(); let mut server_2 = ServerConnection::new(Arc::new(server_config_2)).unwrap(); common::do_handshake(&mut client_2, &mut server_2); println!("hs2 storage ops: {:#?}", client_storage.ops()); assert_eq!(client_storage.ops().len(), 11); // attempt consumes a TLS1.3 ticket assert!(matches!( client_storage.ops()[9], ClientStorageOp::TakeTls13Ticket(_, true) )); // but ends up with TLS1.2 assert_eq!( client_2.protocol_version(), Some(rustls::ProtocolVersion::TLSv1_2) ); } #[test] fn test_acceptor() { use rustls::server::Acceptor; let client_config = Arc::new(make_client_config(KeyType::Ed25519)); let mut client = ClientConnection::new(client_config, dns_name("localhost")).unwrap(); let mut buf = Vec::new(); client.write_tls(&mut buf).unwrap(); let server_config = Arc::new(make_server_config(KeyType::Ed25519)); let mut acceptor = Acceptor::default(); acceptor .read_tls(&mut buf.as_slice()) .unwrap(); let accepted = acceptor.accept().unwrap().unwrap(); let ch = accepted.client_hello(); assert_eq!(ch.server_name(), Some("localhost")); let server = accepted .into_connection(server_config) .unwrap(); assert!(server.wants_write()); // Reusing an acceptor is not allowed assert_eq!( acceptor .read_tls(&mut [0u8].as_ref()) .err() .unwrap() .kind(), io::ErrorKind::Other, ); assert_eq!( acceptor.accept().err(), Some(Error::General("Acceptor polled after completion".into())) ); let mut acceptor = Acceptor::default(); assert!(acceptor.accept().unwrap().is_none()); acceptor .read_tls(&mut &buf[..3]) .unwrap(); // incomplete message assert!(acceptor.accept().unwrap().is_none()); acceptor .read_tls(&mut [0x80, 0x00].as_ref()) .unwrap(); // invalid message (len = 32k bytes) assert!(acceptor.accept().is_err()); let mut acceptor = Acceptor::default(); // Minimal valid 1-byte application data message is not a handshake message acceptor .read_tls(&mut [0x17, 0x03, 0x03, 0x00, 0x01, 0x00].as_ref()) .unwrap(); assert!(acceptor.accept().is_err()); let mut acceptor = Acceptor::default(); // Minimal 1-byte ClientHello message is not a legal handshake message acceptor .read_tls(&mut [0x16, 0x03, 0x03, 0x00, 0x05, 0x01, 0x00, 0x00, 0x01, 0x00].as_ref()) .unwrap(); assert!(acceptor.accept().is_err()); } #[derive(Default, Debug)] struct LogCounts { trace: usize, debug: usize, info: usize, warn: usize, error: usize, } impl LogCounts { fn new() -> Self { Self { ..Default::default() } } fn reset(&mut self) { *self = Self::new(); } fn add(&mut self, level: log::Level) { match level { log::Level::Trace => self.trace += 1, log::Level::Debug => self.debug += 1, log::Level::Info => self.info += 1, log::Level::Warn => self.warn += 1, log::Level::Error => self.error += 1, } } } thread_local!(static COUNTS: RefCell = RefCell::new(LogCounts::new())); struct CountingLogger; static LOGGER: CountingLogger = CountingLogger; impl CountingLogger { fn install() { log::set_logger(&LOGGER).unwrap(); log::set_max_level(log::LevelFilter::Trace); } fn reset() { COUNTS.with(|c| { c.borrow_mut().reset(); }); } } impl log::Log for CountingLogger { fn enabled(&self, _metadata: &log::Metadata) -> bool { true } fn log(&self, record: &log::Record) { println!("logging at {:?}: {:?}", record.level(), record.args()); COUNTS.with(|c| { c.borrow_mut().add(record.level()); }); } fn flush(&self) {} } #[test] fn test_no_warning_logging_during_successful_sessions() { CountingLogger::install(); CountingLogger::reset(); for kt in ALL_KEY_TYPES.iter() { for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(*kt, &[version]); let (mut client, mut server) = make_pair_for_configs(client_config, make_server_config(*kt)); do_handshake(&mut client, &mut server); } } if cfg!(feature = "logging") { COUNTS.with(|c| { println!("After tests: {:?}", c.borrow()); assert_eq!(c.borrow().warn, 0); assert_eq!(c.borrow().error, 0); assert_eq!(c.borrow().info, 0); assert!(c.borrow().trace > 0); assert!(c.borrow().debug > 0); }); } else { COUNTS.with(|c| { println!("After tests: {:?}", c.borrow()); assert_eq!(c.borrow().warn, 0); assert_eq!(c.borrow().error, 0); assert_eq!(c.borrow().info, 0); assert_eq!(c.borrow().trace, 0); assert_eq!(c.borrow().debug, 0); }); } } /// Test that secrets can be extracted and used for encryption/decryption. #[cfg(feature = "secret_extraction")] #[test] fn test_secret_extraction_enabled() { // Normally, secret extraction would be used to configure kTLS (TLS offload // to the kernel). We want this test to run on any platform, though, so // instead we just compare secrets for equality. // TLS 1.2 and 1.3 have different mechanisms for key exchange and handshake, // and secrets are stored/extracted differently, so we want to test them both. // We support 3 different AEAD algorithms (AES-128-GCM mode, AES-256-GCM, and // Chacha20Poly1305), so that's 2*3 = 6 combinations to test. let kt = KeyType::Rsa; for suite in [ rustls::cipher_suite::TLS13_AES_128_GCM_SHA256, rustls::cipher_suite::TLS13_AES_256_GCM_SHA384, rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, rustls::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, rustls::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, ] { let version = suite.version(); println!("Testing suite {:?}", suite.suite().as_str()); // Only offer the cipher suite (and protocol version) that we're testing let mut server_config = ServerConfig::builder() .with_cipher_suites(&[suite]) .with_safe_default_kx_groups() .with_protocol_versions(&[version]) .unwrap() .with_no_client_auth() .with_single_cert(kt.get_chain(), kt.get_key()) .unwrap(); // Opt into secret extraction from both sides server_config.enable_secret_extraction = true; let server_config = Arc::new(server_config); let mut client_config = make_client_config(kt); client_config.enable_secret_extraction = true; let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); // The handshake is finished, we're now able to extract traffic secrets let client_secrets = client.extract_secrets().unwrap(); let server_secrets = server.extract_secrets().unwrap(); // Comparing secrets for equality is something you should never have to // do in production code, so ConnectionTrafficSecrets doesn't implement // PartialEq/Eq on purpose. Instead, we have to get creative. fn explode_secrets(s: &ConnectionTrafficSecrets) -> (&[u8], &[u8], &[u8]) { match s { ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv } => (key, salt, iv), ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv } => (key, salt, iv), ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv } => (key, &[], iv), _ => panic!("unexpected secret type"), } } fn assert_secrets_equal( (l_seq, l_sec): (u64, ConnectionTrafficSecrets), (r_seq, r_sec): (u64, ConnectionTrafficSecrets), ) { assert_eq!(l_seq, r_seq); assert_eq!(explode_secrets(&l_sec), explode_secrets(&r_sec)); } assert_secrets_equal(client_secrets.tx, server_secrets.rx); assert_secrets_equal(client_secrets.rx, server_secrets.tx); } } /// Test that secrets cannot be extracted unless explicitly enabled, and until /// the handshake is done. #[cfg(feature = "secret_extraction")] #[test] fn test_secret_extraction_disabled_or_too_early() { let suite = rustls::cipher_suite::TLS13_AES_128_GCM_SHA256; let kt = KeyType::Rsa; for (server_enable, client_enable) in [(true, false), (false, true)] { let mut server_config = ServerConfig::builder() .with_cipher_suites(&[suite]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .unwrap() .with_no_client_auth() .with_single_cert(kt.get_chain(), kt.get_key()) .unwrap(); server_config.enable_secret_extraction = server_enable; let server_config = Arc::new(server_config); let mut client_config = make_client_config(kt); client_config.enable_secret_extraction = client_enable; let client_config = Arc::new(client_config); let (client, server) = make_pair_for_arc_configs(&client_config, &server_config); assert!( client.extract_secrets().is_err(), "extraction should fail until handshake completes" ); assert!( server.extract_secrets().is_err(), "extraction should fail until handshake completes" ); let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); assert_eq!(server_enable, server.extract_secrets().is_ok()); assert_eq!(client_enable, client.extract_secrets().is_ok()); } } #[test] fn test_received_plaintext_backpressure() { let suite = rustls::cipher_suite::TLS13_AES_128_GCM_SHA256; let kt = KeyType::Rsa; let server_config = Arc::new( ServerConfig::builder() .with_cipher_suites(&[suite]) .with_safe_default_kx_groups() .with_safe_default_protocol_versions() .unwrap() .with_no_client_auth() .with_single_cert(kt.get_chain(), kt.get_key()) .unwrap(), ); let client_config = Arc::new(make_client_config(kt)); let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); // Fill the server's received plaintext buffer with 16k bytes let client_buf = [0; 16_385]; dbg!(client .writer() .write(&client_buf) .unwrap()); let mut network_buf = Vec::with_capacity(32_768); let sent = dbg!(client .write_tls(&mut network_buf) .unwrap()); let mut read = 0; while read < sent { let new = dbg!(server .read_tls(&mut &network_buf[read..sent]) .unwrap()); if new == 4096 { read += new; } else { break; } } server.process_new_packets().unwrap(); // Send two more bytes from client to server dbg!(client .writer() .write(&client_buf[..2]) .unwrap()); let sent = dbg!(client .write_tls(&mut network_buf) .unwrap()); // Get an error because the received plaintext buffer is full assert!(server .read_tls(&mut &network_buf[..sent]) .is_err()); // Read out some of the plaintext server .reader() .read_exact(&mut [0; 2]) .unwrap(); // Now there's room again in the plaintext buffer assert_eq!( server .read_tls(&mut &network_buf[..sent]) .unwrap(), 24 ); } #[test] fn test_debug_server_name_from_ip() { assert_eq!( format!( "{:?}", rustls::ServerName::IpAddress("127.0.0.1".parse().unwrap()) ), "IpAddress(127.0.0.1)" ) } #[test] fn test_debug_server_name_from_string() { assert_eq!( format!("{:?}", rustls::ServerName::try_from("a.com").unwrap()), "DnsName(\"a.com\")" ) } #[cfg(feature = "tls12")] #[test] fn test_client_removes_tls12_session_if_server_sends_undecryptable_first_message() { fn inject_corrupt_finished_message(msg: &mut Message) -> Altered { if let MessagePayload::ChangeCipherSpec(_) = msg.payload { // interdict "real" ChangeCipherSpec with its encoding, plus a faulty encrypted Finished. let mut raw_change_cipher_spec = [0x14u8, 0x03, 0x03, 0x00, 0x01, 0x01].to_vec(); let mut corrupt_finished = [0x16, 0x03, 0x03, 0x00, 0x28].to_vec(); corrupt_finished.extend([0u8; 0x28]); let mut both = vec![]; both.append(&mut raw_change_cipher_spec); both.append(&mut corrupt_finished); Altered::Raw(both) } else { Altered::InPlace } } let mut client_config = make_client_config_with_versions(KeyType::Rsa, &[&rustls::version::TLS12]); let storage = Arc::new(ClientStorage::new()); client_config.resumption = Resumption::store(storage.clone()); let client_config = Arc::new(client_config); let server_config = Arc::new(make_server_config(KeyType::Rsa)); // successful handshake to allow resumption let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); do_handshake(&mut client, &mut server); // resumption let (mut client, mut server) = make_pair_for_arc_configs(&client_config, &server_config); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); let mut client = client.into(); transfer_altered( &mut server.into(), inject_corrupt_finished_message, &mut client, ); // discard storage operations up to this point, to observe the one we want to test for. storage.ops_and_reset(); // client cannot decrypt faulty Finished, and deletes saved session in case // server resumption is buggy. assert_eq!( Some(Error::DecryptError), client.process_new_packets().err() ); assert!(matches!( storage.ops()[0], ClientStorageOp::RemoveTls12Session(_) )); } rustls-v-0.21.10/rustls/tests/bogo.rs000066400000000000000000000007701453461710000174510ustar00rootroot00000000000000// Runs the bogo test suite, in the form of a rust test. // Note that bogo requires a golang environment to build // and run. #[test] #[cfg(all(coverage, feature = "quic", feature = "dangerous_configuration"))] fn run_bogo_tests() { use std::process::Command; let rc = Command::new("./runme") .current_dir("../bogo") .spawn() .expect("cannot run bogo/runme") .wait() .expect("cannot wait for bogo"); assert!(rc.success(), "bogo exited non-zero"); } rustls-v-0.21.10/rustls/tests/client_cert_verifier.rs000066400000000000000000000157001453461710000227100ustar00rootroot00000000000000//! Tests for configuring and using a [`ClientCertVerifier`] for a server. #![cfg(feature = "dangerous_configuration")] mod common; use crate::common::{ dns_name, do_handshake_until_both_error, do_handshake_until_error, get_client_root_store, make_client_config_with_versions, make_client_config_with_versions_with_auth, make_pair_for_arc_configs, ErrorFromPeer, KeyType, ALL_KEY_TYPES, }; use rustls::client::WebPkiVerifier; use rustls::internal::msgs::handshake::DistinguishedName; use rustls::server::{ClientCertVerified, ClientCertVerifier}; use rustls::{ AlertDescription, Certificate, ClientConnection, Error, InvalidMessage, ServerConfig, ServerConnection, SignatureScheme, }; use std::sync::Arc; // Client is authorized! fn ver_ok() -> Result { Ok(rustls::server::ClientCertVerified::assertion()) } // Use when we shouldn't even attempt verification fn ver_unreachable() -> Result { unreachable!() } // Verifier that returns an error that we can expect fn ver_err() -> Result { Err(Error::General("test err".to_string())) } fn server_config_with_verifier( kt: KeyType, client_cert_verifier: MockClientVerifier, ) -> ServerConfig { ServerConfig::builder() .with_safe_defaults() .with_client_cert_verifier(Arc::new(client_cert_verifier)) .with_single_cert(kt.get_chain(), kt.get_key()) .unwrap() } #[test] // Happy path, we resolve to a root, it is verified OK, should be able to connect fn client_verifier_works() { for kt in ALL_KEY_TYPES.iter() { let client_verifier = MockClientVerifier { verified: ver_ok, subjects: get_client_root_store(*kt) .roots .iter() .map(|r| r.subject().clone()) .collect(), mandatory: true, offered_schemes: None, }; let server_config = server_config_with_verifier(*kt, client_verifier); let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config.clone()), &server_config); let err = do_handshake_until_error(&mut client, &mut server); assert_eq!(err, Ok(())); } } } // Server offers no verification schemes #[test] fn client_verifier_no_schemes() { for kt in ALL_KEY_TYPES.iter() { let client_verifier = MockClientVerifier { verified: ver_ok, subjects: get_client_root_store(*kt) .roots .iter() .map(|r| r.subject().clone()) .collect(), mandatory: true, offered_schemes: Some(vec![]), }; let server_config = server_config_with_verifier(*kt, client_verifier); let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config.clone()), &server_config); let err = do_handshake_until_error(&mut client, &mut server); assert_eq!( err, Err(ErrorFromPeer::Client(Error::InvalidMessage( InvalidMessage::NoSignatureSchemes, ))), ); } } } // If we do have a root, we must do auth #[test] fn client_verifier_no_auth_yes_root() { for kt in ALL_KEY_TYPES.iter() { let client_verifier = MockClientVerifier { verified: ver_unreachable, subjects: get_client_root_store(*kt) .roots .iter() .map(|r| r.subject().clone()) .collect(), mandatory: true, offered_schemes: None, }; let server_config = server_config_with_verifier(*kt, client_verifier); let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(*kt, &[version]); let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); let errs = do_handshake_until_both_error(&mut client, &mut server); assert_eq!( errs, Err(vec![ ErrorFromPeer::Server(Error::NoCertificatesPresented), ErrorFromPeer::Client(Error::AlertReceived( AlertDescription::CertificateRequired )) ]) ); } } } #[test] // Triple checks we propagate the rustls::Error through fn client_verifier_fails_properly() { for kt in ALL_KEY_TYPES.iter() { let client_verifier = MockClientVerifier { verified: ver_err, subjects: get_client_root_store(*kt) .roots .iter() .map(|r| r.subject().clone()) .collect(), mandatory: true, offered_schemes: None, }; let server_config = server_config_with_verifier(*kt, client_verifier); let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions_with_auth(*kt, &[version]); let mut server = ServerConnection::new(Arc::clone(&server_config)).unwrap(); let mut client = ClientConnection::new(Arc::new(client_config), dns_name("localhost")).unwrap(); let err = do_handshake_until_error(&mut client, &mut server); assert_eq!( err, Err(ErrorFromPeer::Server(Error::General("test err".into()))) ); } } } pub struct MockClientVerifier { pub verified: fn() -> Result, pub subjects: Vec, pub mandatory: bool, pub offered_schemes: Option>, } impl ClientCertVerifier for MockClientVerifier { fn client_auth_mandatory(&self) -> bool { self.mandatory } fn client_auth_root_subjects(&self) -> &[DistinguishedName] { &self.subjects } fn verify_client_cert( &self, _end_entity: &Certificate, _intermediates: &[Certificate], _now: std::time::SystemTime, ) -> Result { (self.verified)() } fn supported_verify_schemes(&self) -> Vec { if let Some(schemes) = &self.offered_schemes { schemes.clone() } else { WebPkiVerifier::verification_schemes() } } } rustls-v-0.21.10/rustls/tests/common/000077500000000000000000000000001453461710000174415ustar00rootroot00000000000000rustls-v-0.21.10/rustls/tests/common/mod.rs000066400000000000000000000402371453461710000205740ustar00rootroot00000000000000#![allow(dead_code)] use std::io; use std::ops::{Deref, DerefMut}; use std::sync::Arc; use rustls::internal::msgs::codec::Reader; use rustls::internal::msgs::message::{Message, OpaqueMessage, PlainMessage}; use rustls::server::{ AllowAnyAnonymousOrAuthenticatedClient, AllowAnyAuthenticatedClient, UnparsedCertRevocationList, }; use rustls::Connection; use rustls::Error; use rustls::RootCertStore; use rustls::{Certificate, PrivateKey}; use rustls::{ClientConfig, ClientConnection}; use rustls::{ConnectionCommon, ServerConfig, ServerConnection, SideData}; macro_rules! embed_files { ( $( ($name:ident, $keytype:expr, $path:expr); )+ ) => { $( const $name: &'static [u8] = include_bytes!( concat!("../../../test-ca/", $keytype, "/", $path)); )+ pub fn bytes_for(keytype: &str, path: &str) -> &'static [u8] { match (keytype, path) { $( ($keytype, $path) => $name, )+ _ => panic!("unknown keytype {} with path {}", keytype, path), } } } } embed_files! { (ECDSA_CA_CERT, "ecdsa", "ca.cert"); (ECDSA_CA_DER, "ecdsa", "ca.der"); (ECDSA_CA_KEY, "ecdsa", "ca.key"); (ECDSA_CLIENT_CERT, "ecdsa", "client.cert"); (ECDSA_CLIENT_CHAIN, "ecdsa", "client.chain"); (ECDSA_CLIENT_FULLCHAIN, "ecdsa", "client.fullchain"); (ECDSA_CLIENT_KEY, "ecdsa", "client.key"); (ECDSA_CLIENT_REQ, "ecdsa", "client.req"); (ECDSA_CLIENT_CRL_PEM, "ecdsa", "client.revoked.crl.pem"); (ECDSA_END_CERT, "ecdsa", "end.cert"); (ECDSA_END_CHAIN, "ecdsa", "end.chain"); (ECDSA_END_FULLCHAIN, "ecdsa", "end.fullchain"); (ECDSA_END_KEY, "ecdsa", "end.key"); (ECDSA_END_REQ, "ecdsa", "end.req"); (ECDSA_INTER_CERT, "ecdsa", "inter.cert"); (ECDSA_INTER_KEY, "ecdsa", "inter.key"); (ECDSA_INTER_REQ, "ecdsa", "inter.req"); (ECDSA_NISTP256_PEM, "ecdsa", "nistp256.pem"); (ECDSA_NISTP384_PEM, "ecdsa", "nistp384.pem"); (EDDSA_CA_CERT, "eddsa", "ca.cert"); (EDDSA_CA_DER, "eddsa", "ca.der"); (EDDSA_CA_KEY, "eddsa", "ca.key"); (EDDSA_CLIENT_CERT, "eddsa", "client.cert"); (EDDSA_CLIENT_CHAIN, "eddsa", "client.chain"); (EDDSA_CLIENT_FULLCHAIN, "eddsa", "client.fullchain"); (EDDSA_CLIENT_KEY, "eddsa", "client.key"); (EDDSA_CLIENT_REQ, "eddsa", "client.req"); (EDDSA_CLIENT_CRL_PEM, "eddsa", "client.revoked.crl.pem"); (EDDSA_END_CERT, "eddsa", "end.cert"); (EDDSA_END_CHAIN, "eddsa", "end.chain"); (EDDSA_END_FULLCHAIN, "eddsa", "end.fullchain"); (EDDSA_END_KEY, "eddsa", "end.key"); (EDDSA_END_REQ, "eddsa", "end.req"); (EDDSA_INTER_CERT, "eddsa", "inter.cert"); (EDDSA_INTER_KEY, "eddsa", "inter.key"); (EDDSA_INTER_REQ, "eddsa", "inter.req"); (RSA_CA_CERT, "rsa", "ca.cert"); (RSA_CA_DER, "rsa", "ca.der"); (RSA_CA_KEY, "rsa", "ca.key"); (RSA_CLIENT_CERT, "rsa", "client.cert"); (RSA_CLIENT_CHAIN, "rsa", "client.chain"); (RSA_CLIENT_FULLCHAIN, "rsa", "client.fullchain"); (RSA_CLIENT_KEY, "rsa", "client.key"); (RSA_CLIENT_REQ, "rsa", "client.req"); (RSA_CLIENT_RSA, "rsa", "client.rsa"); (RSA_CLIENT_CRL_PEM, "rsa", "client.revoked.crl.pem"); (RSA_END_CERT, "rsa", "end.cert"); (RSA_END_CHAIN, "rsa", "end.chain"); (RSA_END_FULLCHAIN, "rsa", "end.fullchain"); (RSA_END_KEY, "rsa", "end.key"); (RSA_END_REQ, "rsa", "end.req"); (RSA_END_RSA, "rsa", "end.rsa"); (RSA_INTER_CERT, "rsa", "inter.cert"); (RSA_INTER_KEY, "rsa", "inter.key"); (RSA_INTER_REQ, "rsa", "inter.req"); } pub fn transfer( left: &mut (impl DerefMut + Deref>), right: &mut (impl DerefMut + Deref>), ) -> usize { let mut buf = [0u8; 262144]; let mut total = 0; while left.wants_write() { let sz = { let into_buf: &mut dyn io::Write = &mut &mut buf[..]; left.write_tls(into_buf).unwrap() }; total += sz; if sz == 0 { return total; } let mut offs = 0; loop { let from_buf: &mut dyn io::Read = &mut &buf[offs..sz]; offs += right.read_tls(from_buf).unwrap(); if sz == offs { break; } } } total } pub fn transfer_eof(conn: &mut (impl DerefMut + Deref>)) { let empty_buf = [0u8; 0]; let empty_cursor: &mut dyn io::Read = &mut &empty_buf[..]; let sz = conn.read_tls(empty_cursor).unwrap(); assert_eq!(sz, 0); } pub enum Altered { /// message has been edited in-place (or is unchanged) InPlace, /// send these raw bytes instead of the message. Raw(Vec), } pub fn transfer_altered(left: &mut Connection, filter: F, right: &mut Connection) -> usize where F: Fn(&mut Message) -> Altered, { let mut buf = [0u8; 262144]; let mut total = 0; while left.wants_write() { let sz = { let into_buf: &mut dyn io::Write = &mut &mut buf[..]; left.write_tls(into_buf).unwrap() }; total += sz; if sz == 0 { return total; } let mut reader = Reader::init(&buf[..sz]); while reader.any_left() { let message = OpaqueMessage::read(&mut reader).unwrap(); // this is a bit of a falsehood: we don't know whether message // is encrypted. it is quite unlikely that a genuine encrypted // message can be decoded by `Message::try_from`. let plain = message.into_plain_message(); let message_enc = match Message::try_from(plain.clone()) { Ok(mut message) => match filter(&mut message) { Altered::InPlace => PlainMessage::from(message) .into_unencrypted_opaque() .encode(), Altered::Raw(data) => data, }, // pass through encrypted/undecodable messages Err(_) => plain.into_unencrypted_opaque().encode(), }; let message_enc_reader: &mut dyn io::Read = &mut &message_enc[..]; let len = right .read_tls(message_enc_reader) .unwrap(); assert_eq!(len, message_enc.len()); } } total } #[derive(Clone, Copy, Debug, PartialEq)] pub enum KeyType { Rsa, Ecdsa, Ed25519, } pub static ALL_KEY_TYPES: [KeyType; 3] = [KeyType::Rsa, KeyType::Ecdsa, KeyType::Ed25519]; impl KeyType { fn bytes_for(&self, part: &str) -> &'static [u8] { match self { Self::Rsa => bytes_for("rsa", part), Self::Ecdsa => bytes_for("ecdsa", part), Self::Ed25519 => bytes_for("eddsa", part), } } pub fn get_chain(&self) -> Vec { rustls_pemfile::certs(&mut io::BufReader::new(self.bytes_for("end.fullchain"))) .unwrap() .iter() .map(|v| Certificate(v.clone())) .collect() } pub fn get_key(&self) -> PrivateKey { PrivateKey( rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new(self.bytes_for("end.key"))) .unwrap()[0] .clone(), ) } pub fn get_client_chain(&self) -> Vec { rustls_pemfile::certs(&mut io::BufReader::new(self.bytes_for("client.fullchain"))) .unwrap() .iter() .map(|v| Certificate(v.clone())) .collect() } pub fn client_crl(&self) -> UnparsedCertRevocationList { UnparsedCertRevocationList( rustls_pemfile::crls(&mut io::BufReader::new( self.bytes_for("client.revoked.crl.pem"), )) .unwrap() .into_iter() .next() // We only expect one CRL. .unwrap(), ) } fn get_client_key(&self) -> PrivateKey { PrivateKey( rustls_pemfile::pkcs8_private_keys(&mut io::BufReader::new( self.bytes_for("client.key"), )) .unwrap()[0] .clone(), ) } } pub fn finish_server_config( kt: KeyType, conf: rustls::ConfigBuilder, ) -> ServerConfig { conf.with_no_client_auth() .with_single_cert(kt.get_chain(), kt.get_key()) .unwrap() } pub fn make_server_config(kt: KeyType) -> ServerConfig { finish_server_config(kt, ServerConfig::builder().with_safe_defaults()) } pub fn make_server_config_with_versions( kt: KeyType, versions: &[&'static rustls::SupportedProtocolVersion], ) -> ServerConfig { finish_server_config( kt, ServerConfig::builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(versions) .unwrap(), ) } pub fn make_server_config_with_kx_groups( kt: KeyType, kx_groups: &[&'static rustls::SupportedKxGroup], ) -> ServerConfig { finish_server_config( kt, ServerConfig::builder() .with_safe_default_cipher_suites() .with_kx_groups(kx_groups) .with_safe_default_protocol_versions() .unwrap(), ) } pub fn get_client_root_store(kt: KeyType) -> RootCertStore { let mut roots = kt.get_chain(); // drop server cert roots.drain(0..1); let mut client_auth_roots = RootCertStore::empty(); for root in roots { client_auth_roots.add(&root).unwrap(); } client_auth_roots } pub fn make_server_config_with_mandatory_client_auth_crls( kt: KeyType, crls: Vec, ) -> ServerConfig { let client_auth_roots = get_client_root_store(kt); let client_auth = AllowAnyAuthenticatedClient::new(client_auth_roots) .with_crls(crls) .unwrap(); ServerConfig::builder() .with_safe_defaults() .with_client_cert_verifier(Arc::new(client_auth)) .with_single_cert(kt.get_chain(), kt.get_key()) .unwrap() } pub fn make_server_config_with_mandatory_client_auth(kt: KeyType) -> ServerConfig { make_server_config_with_mandatory_client_auth_crls(kt, Vec::new()) } pub fn make_server_config_with_optional_client_auth( kt: KeyType, crls: Vec, ) -> ServerConfig { let client_auth_roots = get_client_root_store(kt); let client_auth = AllowAnyAnonymousOrAuthenticatedClient::new(client_auth_roots) .with_crls(crls) .unwrap(); ServerConfig::builder() .with_safe_defaults() .with_client_cert_verifier(Arc::new(client_auth)) .with_single_cert(kt.get_chain(), kt.get_key()) .unwrap() } pub fn finish_client_config( kt: KeyType, config: rustls::ConfigBuilder, ) -> ClientConfig { let mut root_store = RootCertStore::empty(); let mut rootbuf = io::BufReader::new(kt.bytes_for("ca.cert")); root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut rootbuf).unwrap()); config .with_root_certificates(root_store) .with_no_client_auth() } pub fn finish_client_config_with_creds( kt: KeyType, config: rustls::ConfigBuilder, ) -> ClientConfig { let mut root_store = RootCertStore::empty(); let mut rootbuf = io::BufReader::new(kt.bytes_for("ca.cert")); root_store.add_parsable_certificates(&rustls_pemfile::certs(&mut rootbuf).unwrap()); config .with_root_certificates(root_store) .with_client_auth_cert(kt.get_client_chain(), kt.get_client_key()) .unwrap() } pub fn make_client_config(kt: KeyType) -> ClientConfig { finish_client_config(kt, ClientConfig::builder().with_safe_defaults()) } pub fn make_client_config_with_kx_groups( kt: KeyType, kx_groups: &[&'static rustls::SupportedKxGroup], ) -> ClientConfig { let builder = ClientConfig::builder() .with_safe_default_cipher_suites() .with_kx_groups(kx_groups) .with_safe_default_protocol_versions() .unwrap(); finish_client_config(kt, builder) } pub fn make_client_config_with_versions( kt: KeyType, versions: &[&'static rustls::SupportedProtocolVersion], ) -> ClientConfig { let builder = ClientConfig::builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(versions) .unwrap(); finish_client_config(kt, builder) } pub fn make_client_config_with_auth(kt: KeyType) -> ClientConfig { finish_client_config_with_creds(kt, ClientConfig::builder().with_safe_defaults()) } pub fn make_client_config_with_versions_with_auth( kt: KeyType, versions: &[&'static rustls::SupportedProtocolVersion], ) -> ClientConfig { let builder = ClientConfig::builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_protocol_versions(versions) .unwrap(); finish_client_config_with_creds(kt, builder) } pub fn make_pair(kt: KeyType) -> (ClientConnection, ServerConnection) { make_pair_for_configs(make_client_config(kt), make_server_config(kt)) } pub fn make_pair_for_configs( client_config: ClientConfig, server_config: ServerConfig, ) -> (ClientConnection, ServerConnection) { make_pair_for_arc_configs(&Arc::new(client_config), &Arc::new(server_config)) } pub fn make_pair_for_arc_configs( client_config: &Arc, server_config: &Arc, ) -> (ClientConnection, ServerConnection) { ( ClientConnection::new(Arc::clone(client_config), dns_name("localhost")).unwrap(), ServerConnection::new(Arc::clone(server_config)).unwrap(), ) } pub fn do_handshake( client: &mut (impl DerefMut + Deref>), server: &mut (impl DerefMut + Deref>), ) -> (usize, usize) { let (mut to_client, mut to_server) = (0, 0); while server.is_handshaking() || client.is_handshaking() { to_server += transfer(client, server); server.process_new_packets().unwrap(); to_client += transfer(server, client); client.process_new_packets().unwrap(); } (to_server, to_client) } #[derive(PartialEq, Debug)] pub enum ErrorFromPeer { Client(Error), Server(Error), } pub fn do_handshake_until_error( client: &mut ClientConnection, server: &mut ServerConnection, ) -> Result<(), ErrorFromPeer> { while server.is_handshaking() || client.is_handshaking() { transfer(client, server); server .process_new_packets() .map_err(ErrorFromPeer::Server)?; transfer(server, client); client .process_new_packets() .map_err(ErrorFromPeer::Client)?; } Ok(()) } pub fn do_handshake_until_both_error( client: &mut ClientConnection, server: &mut ServerConnection, ) -> Result<(), Vec> { match do_handshake_until_error(client, server) { Err(server_err @ ErrorFromPeer::Server(_)) => { let mut errors = vec![server_err]; transfer(server, client); let client_err = client .process_new_packets() .map_err(ErrorFromPeer::Client) .expect_err("client didn't produce error after server error"); errors.push(client_err); Err(errors) } Err(client_err @ ErrorFromPeer::Client(_)) => { let mut errors = vec![client_err]; transfer(client, server); let server_err = server .process_new_packets() .map_err(ErrorFromPeer::Server) .expect_err("server didn't produce error after client error"); errors.push(server_err); Err(errors) } Ok(()) => Ok(()), } } pub fn dns_name(name: &'static str) -> rustls::ServerName { name.try_into().unwrap() } pub struct FailsReads { errkind: io::ErrorKind, } impl FailsReads { pub fn new(errkind: io::ErrorKind) -> Self { Self { errkind } } } impl io::Read for FailsReads { fn read(&mut self, _b: &mut [u8]) -> io::Result { Err(io::Error::from(self.errkind)) } } rustls-v-0.21.10/rustls/tests/key_log_file_env.rs000066400000000000000000000074551453461710000220320ustar00rootroot00000000000000//! Tests of [`rustls::KeyLogFile`] that require us to set environment variables. //! //! vvvv //! Every test you add to this file MUST execute through `serialized()`. //! ^^^^ //! //! See https://github.com/rust-lang/rust/issues/90308; despite not being marked //! `unsafe`, `env::var::set_var` is an unsafe function. These tests are separated //! from the rest of the tests so that their use of `set_ver` is less likely to //! affect them; as of the time these tests were moved to this file, Cargo will //! compile each test suite file to a separate executable, so these will be run //! in a completely separate process. This way, executing every test through //! `serialized()` will cause them to be run one at a time. //! //! Note: If/when we add new constructors to `KeyLogFile` to allow constructing //! one from a path directly (without using an environment variable), then those //! tests SHOULD NOT go in this file. //! //! XXX: These tests don't actually test the functionality; they just ensure //! the code coverage doesn't complain it isn't covered. TODO: Verify that the //! file was created successfully, with the right permissions, etc., and that it //! contains something like what we expect. #[allow(dead_code)] mod common; use crate::common::{ do_handshake, make_client_config_with_versions, make_pair_for_arc_configs, make_server_config, transfer, KeyType, }; use std::{ env, io::Write, sync::{Arc, Mutex, Once}, }; /// Approximates `#[serial]` from the `serial_test` crate. /// /// No attempt is made to recover from a poisoned mutex, which will /// happen when `f` panics. In other words, all the tests that use /// `serialized` will start failing after one test panics. fn serialized(f: impl FnOnce()) { // Ensure every test is run serialized // TODO: Use `std::sync::Lazy` once that is stable. static mut MUTEX: Option> = None; static ONCE: Once = Once::new(); ONCE.call_once(|| unsafe { MUTEX = Some(Mutex::new(())); }); let mutex = unsafe { MUTEX.as_mut() }; let _guard = mutex.unwrap().lock().unwrap(); // XXX: NOT thread safe. env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); f() } #[test] fn exercise_key_log_file_for_client() { serialized(|| { let server_config = Arc::new(make_server_config(KeyType::Rsa)); env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); for version in rustls::ALL_VERSIONS { let mut client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); client_config.key_log = Arc::new(rustls::KeyLogFile::new()); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); assert_eq!(5, client.writer().write(b"hello").unwrap()); do_handshake(&mut client, &mut server); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); } }) } #[test] fn exercise_key_log_file_for_server() { serialized(|| { let mut server_config = make_server_config(KeyType::Rsa); env::set_var("SSLKEYLOGFILE", "./sslkeylogfile.txt"); server_config.key_log = Arc::new(rustls::KeyLogFile::new()); let server_config = Arc::new(server_config); for version in rustls::ALL_VERSIONS { let client_config = make_client_config_with_versions(KeyType::Rsa, &[version]); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); assert_eq!(5, client.writer().write(b"hello").unwrap()); do_handshake(&mut client, &mut server); transfer(&mut client, &mut server); server.process_new_packets().unwrap(); } }) } rustls-v-0.21.10/rustls/tests/server_cert_verifier.rs000066400000000000000000000220071453461710000227360ustar00rootroot00000000000000//! Tests for configuring and using a [`ServerCertVerifier`] for a client. #![cfg(feature = "dangerous_configuration")] mod common; use crate::common::{ do_handshake, do_handshake_until_both_error, make_client_config_with_versions, make_pair_for_arc_configs, make_server_config, ErrorFromPeer, ALL_KEY_TYPES, }; use rustls::client::{ HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier, WebPkiVerifier, }; use rustls::DigitallySignedStruct; use rustls::{AlertDescription, Certificate, Error, InvalidMessage, SignatureScheme}; use std::sync::Arc; #[test] fn client_can_override_certificate_verification() { for kt in ALL_KEY_TYPES.iter() { let verifier = Arc::new(MockServerVerifier::accepts_anything()); let server_config = Arc::new(make_server_config(*kt)); for version in rustls::ALL_VERSIONS { let mut client_config = make_client_config_with_versions(*kt, &[version]); client_config .dangerous() .set_certificate_verifier(verifier.clone()); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); do_handshake(&mut client, &mut server); } } } #[test] fn client_can_override_certificate_verification_and_reject_certificate() { for kt in ALL_KEY_TYPES.iter() { let verifier = Arc::new(MockServerVerifier::rejects_certificate( Error::InvalidMessage(InvalidMessage::HandshakePayloadTooLarge), )); let server_config = Arc::new(make_server_config(*kt)); for version in rustls::ALL_VERSIONS { let mut client_config = make_client_config_with_versions(*kt, &[version]); client_config .dangerous() .set_certificate_verifier(verifier.clone()); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); let errs = do_handshake_until_both_error(&mut client, &mut server); assert_eq!( errs, Err(vec![ ErrorFromPeer::Client(Error::InvalidMessage( InvalidMessage::HandshakePayloadTooLarge, )), ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::HandshakeFailure)), ]), ); } } } #[cfg(feature = "tls12")] #[test] fn client_can_override_certificate_verification_and_reject_tls12_signatures() { for kt in ALL_KEY_TYPES.iter() { let mut client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS12]); let verifier = Arc::new(MockServerVerifier::rejects_tls12_signatures( Error::InvalidMessage(InvalidMessage::HandshakePayloadTooLarge), )); client_config .dangerous() .set_certificate_verifier(verifier); let server_config = Arc::new(make_server_config(*kt)); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); let errs = do_handshake_until_both_error(&mut client, &mut server); assert_eq!( errs, Err(vec![ ErrorFromPeer::Client(Error::InvalidMessage( InvalidMessage::HandshakePayloadTooLarge, )), ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::HandshakeFailure)), ]), ); } } #[test] fn client_can_override_certificate_verification_and_reject_tls13_signatures() { for kt in ALL_KEY_TYPES.iter() { let mut client_config = make_client_config_with_versions(*kt, &[&rustls::version::TLS13]); let verifier = Arc::new(MockServerVerifier::rejects_tls13_signatures( Error::InvalidMessage(InvalidMessage::HandshakePayloadTooLarge), )); client_config .dangerous() .set_certificate_verifier(verifier); let server_config = Arc::new(make_server_config(*kt)); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); let errs = do_handshake_until_both_error(&mut client, &mut server); assert_eq!( errs, Err(vec![ ErrorFromPeer::Client(Error::InvalidMessage( InvalidMessage::HandshakePayloadTooLarge, )), ErrorFromPeer::Server(Error::AlertReceived(AlertDescription::HandshakeFailure)), ]), ); } } #[test] fn client_can_override_certificate_verification_and_offer_no_signature_schemes() { for kt in ALL_KEY_TYPES.iter() { let verifier = Arc::new(MockServerVerifier::offers_no_signature_schemes()); let server_config = Arc::new(make_server_config(*kt)); for version in rustls::ALL_VERSIONS { let mut client_config = make_client_config_with_versions(*kt, &[version]); client_config .dangerous() .set_certificate_verifier(verifier.clone()); let (mut client, mut server) = make_pair_for_arc_configs(&Arc::new(client_config), &server_config); let errs = do_handshake_until_both_error(&mut client, &mut server); assert_eq!( errs, Err(vec![ ErrorFromPeer::Server(Error::PeerIncompatible( rustls::PeerIncompatible::NoSignatureSchemesInCommon )), ErrorFromPeer::Client(Error::AlertReceived(AlertDescription::HandshakeFailure)), ]) ); } } } pub struct MockServerVerifier { cert_rejection_error: Option, tls12_signature_error: Option, tls13_signature_error: Option, wants_scts: bool, signature_schemes: Vec, } impl ServerCertVerifier for MockServerVerifier { fn verify_server_cert( &self, end_entity: &rustls::Certificate, intermediates: &[rustls::Certificate], server_name: &rustls::ServerName, scts: &mut dyn Iterator, oscp_response: &[u8], now: std::time::SystemTime, ) -> Result { let scts: Vec> = scts.map(|x| x.to_owned()).collect(); println!( "verify_server_cert({:?}, {:?}, {:?}, {:?}, {:?}, {:?})", end_entity, intermediates, server_name, scts, oscp_response, now ); if let Some(error) = &self.cert_rejection_error { Err(error.clone()) } else { Ok(ServerCertVerified::assertion()) } } fn verify_tls12_signature( &self, message: &[u8], cert: &Certificate, dss: &DigitallySignedStruct, ) -> Result { println!( "verify_tls12_signature({:?}, {:?}, {:?})", message, cert, dss ); if let Some(error) = &self.tls12_signature_error { Err(error.clone()) } else { Ok(HandshakeSignatureValid::assertion()) } } fn verify_tls13_signature( &self, message: &[u8], cert: &Certificate, dss: &DigitallySignedStruct, ) -> Result { println!( "verify_tls13_signature({:?}, {:?}, {:?})", message, cert, dss ); if let Some(error) = &self.tls13_signature_error { Err(error.clone()) } else { Ok(HandshakeSignatureValid::assertion()) } } fn supported_verify_schemes(&self) -> Vec { self.signature_schemes.clone() } fn request_scts(&self) -> bool { println!("request_scts? {:?}", self.wants_scts); self.wants_scts } } impl MockServerVerifier { pub fn accepts_anything() -> Self { MockServerVerifier { cert_rejection_error: None, ..Default::default() } } pub fn rejects_certificate(err: Error) -> Self { MockServerVerifier { cert_rejection_error: Some(err), ..Default::default() } } pub fn rejects_tls12_signatures(err: Error) -> Self { MockServerVerifier { tls12_signature_error: Some(err), ..Default::default() } } pub fn rejects_tls13_signatures(err: Error) -> Self { MockServerVerifier { tls13_signature_error: Some(err), ..Default::default() } } pub fn offers_no_signature_schemes() -> Self { MockServerVerifier { signature_schemes: vec![], ..Default::default() } } } impl Default for MockServerVerifier { fn default() -> Self { MockServerVerifier { cert_rejection_error: None, tls12_signature_error: None, tls13_signature_error: None, wants_scts: false, signature_schemes: WebPkiVerifier::verification_schemes(), } } } rustls-v-0.21.10/test-ca/000077500000000000000000000000001453461710000150135ustar00rootroot00000000000000rustls-v-0.21.10/test-ca/build-a-pki.sh000077500000000000000000000125721453461710000174570ustar00rootroot00000000000000#!/usr/bin/env bash set -xe rm -rf rsa/ ecdsa/ eddsa/ mkdir -p rsa/ ecdsa/ eddsa/ openssl req -nodes \ -x509 \ -days 3650 \ -newkey rsa:4096 \ -keyout rsa/ca.key \ -out rsa/ca.cert \ -sha256 \ -batch \ -subj "/CN=ponytown RSA CA" openssl req -nodes \ -newkey rsa:3072 \ -keyout rsa/inter.key \ -out rsa/inter.req \ -sha256 \ -batch \ -subj "/CN=ponytown RSA level 2 intermediate" openssl req -nodes \ -newkey rsa:2048 \ -keyout rsa/end.key \ -out rsa/end.req \ -sha256 \ -batch \ -subj "/CN=testserver.com" openssl rsa \ -in rsa/end.key \ -out rsa/end.rsa openssl req -nodes \ -newkey rsa:2048 \ -keyout rsa/client.key \ -out rsa/client.req \ -sha256 \ -batch \ -subj "/CN=ponytown client" openssl rsa \ -in rsa/client.key \ -out rsa/client.rsa # ecdsa openssl ecparam -name prime256v1 -out ecdsa/nistp256.pem openssl ecparam -name secp384r1 -out ecdsa/nistp384.pem openssl req -nodes \ -x509 \ -newkey ec:ecdsa/nistp384.pem \ -keyout ecdsa/ca.key \ -out ecdsa/ca.cert \ -sha256 \ -batch \ -days 3650 \ -subj "/CN=ponytown ECDSA CA" openssl req -nodes \ -newkey ec:ecdsa/nistp256.pem \ -keyout ecdsa/inter.key \ -out ecdsa/inter.req \ -sha256 \ -batch \ -days 3000 \ -subj "/CN=ponytown ECDSA level 2 intermediate" openssl req -nodes \ -newkey ec:ecdsa/nistp256.pem \ -keyout ecdsa/end.key \ -out ecdsa/end.req \ -sha256 \ -batch \ -days 2000 \ -subj "/CN=testserver.com" openssl req -nodes \ -newkey ec:ecdsa/nistp384.pem \ -keyout ecdsa/client.key \ -out ecdsa/client.req \ -sha256 \ -batch \ -days 2000 \ -subj "/CN=ponytown client" # eddsa # TODO: add support for Ed448 # openssl genpkey -algorithm Ed448 -out eddsa/ca.key openssl genpkey -algorithm Ed25519 -out eddsa/ca.key openssl req -nodes \ -x509 \ -key eddsa/ca.key \ -out eddsa/ca.cert \ -sha256 \ -batch \ -days 3650 \ -subj "/CN=ponytown EdDSA CA" openssl genpkey -algorithm Ed25519 -out eddsa/inter.key openssl req -nodes \ -new \ -key eddsa/inter.key \ -out eddsa/inter.req \ -sha256 \ -batch \ -subj "/CN=ponytown EdDSA level 2 intermediate" openssl genpkey -algorithm Ed25519 -out eddsa/end.key openssl req -nodes \ -new \ -key eddsa/end.key \ -out eddsa/end.req \ -sha256 \ -batch \ -subj "/CN=testserver.com" # TODO: add support for Ed448 # openssl genpkey -algorithm Ed448 -out eddsa/client.key openssl genpkey -algorithm Ed25519 -out eddsa/client.key openssl req -nodes \ -new \ -key eddsa/client.key \ -out eddsa/client.req \ -sha256 \ -batch \ -subj "/CN=ponytown client" for kt in rsa ecdsa eddsa ; do openssl x509 -req \ -in $kt/inter.req \ -out $kt/inter.cert \ -CA $kt/ca.cert \ -CAkey $kt/ca.key \ -sha256 \ -days 3650 \ -set_serial 123 \ -extensions v3_inter -extfile openssl.cnf openssl x509 -req \ -in $kt/end.req \ -out $kt/end.cert \ -CA $kt/inter.cert \ -CAkey $kt/inter.key \ -sha256 \ -days 2000 \ -set_serial 456 \ -extensions v3_end -extfile openssl.cnf openssl x509 -req \ -in $kt/client.req \ -out $kt/client.cert \ -CA $kt/inter.cert \ -CAkey $kt/inter.key \ -sha256 \ -days 2000 \ -set_serial 789 \ -extensions v3_client -extfile openssl.cnf # Overwrite the CA state for each revocation - this avoids an # "already revoked" error since we're re-using serial numbers across # key types. echo -n '' > index.txt echo '1000' > crlnumber # Revoke the certificate in the openssl CA index. This produces a CRL but # doesn't include the revoked certificate... openssl ca \ -config ./crl-openssl.cnf \ -keyfile $kt/inter.key \ -cert $kt/inter.cert \ -gencrl \ -crldays 7 \ -revoke $kt/client.cert \ -crl_reason keyCompromise \ -out $kt/client.revoked.crl.pem # Run -gencrl again to actually include the revoked certificate in the CRL. openssl ca \ -config ./crl-openssl.cnf \ -keyfile $kt/inter.key \ -cert $kt/inter.cert \ -gencrl \ -crldays 7 \ -out $kt/client.revoked.crl.pem cat $kt/inter.cert $kt/ca.cert > $kt/end.chain cat $kt/end.cert $kt/inter.cert $kt/ca.cert > $kt/end.fullchain cat $kt/inter.cert $kt/ca.cert > $kt/client.chain cat $kt/client.cert $kt/inter.cert $kt/ca.cert > $kt/client.fullchain openssl asn1parse -in $kt/ca.cert -out $kt/ca.der > /dev/null done # Tidy up openssl CA state. rm index.txt* || true rm crlnumber* || true rustls-v-0.21.10/test-ca/crl-openssl.cnf000066400000000000000000000004141453461710000177430ustar00rootroot00000000000000# The bare minimum OpenSSL config required to issue CRLs with 'openssl ca' [ ca ] default_ca = CA_default [ CA_default ] database = ./index.txt crlnumber = ./crlnumber default_md = default crl_extensions = crl_ext [ crl_ext ] authorityKeyIdentifier=keyid:always rustls-v-0.21.10/test-ca/ecdsa/000077500000000000000000000000001453461710000160725ustar00rootroot00000000000000rustls-v-0.21.10/test-ca/ecdsa/ca.cert000066400000000000000000000012501453461710000173320ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIByjCCAVCgAwIBAgIULO3+cmyE+k7ZGvmzLQIWYLxCNGUwCgYIKoZIzj0EAwIw HDEaMBgGA1UEAwwRcG9ueXRvd24gRUNEU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcN MzMwNjI0MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFQ0RTQSBDQTB2MBAG ByqGSM49AgEGBSuBBAAiA2IABBioWbxD28Pa4gwDrdJoGJhEkB6iHoJlYtHsrCer 0rWtuV/f36Sbp6twF3TfeLXOGXM2Sbw5RnEAWbpLeXDkd3rM8pTa4WcyCxWgPoKX 61DsZrOsRc2k2hHj+56Np/ZgEaNTMFEwHQYDVR0OBBYEFEfsl2VxOvnp9sSquj68 TDfNuT4rMB8GA1UdIwQYMBaAFEfsl2VxOvnp9sSquj68TDfNuT4rMA8GA1UdEwEB /wQFMAMBAf8wCgYIKoZIzj0EAwIDaAAwZQIwIFSvpx15SMa/hGsyB+B1cniBEZjt tXPZimZV13l0tkNRLMCnbJ2rtOmRAEBUlEhNAjEA/sYqju6nv4gHE+KDG19Xv0Ty 2rxX3fnlPbdybTqFnT188Rvq4igeJZkg2gEEUnKW -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/ecdsa/ca.der000066400000000000000000000007161453461710000171550ustar00rootroot0000000000000000P,rlN-`B4e0 *H=010U ponytown ECDSA CA0 230627201348Z 330624201348Z010U ponytown ECDSA CA0v0*H=+"bYC hDeb'ҵ_ߤptxs6I9FqYKypwzg2 >PfEͤ`S0Q0UGeq:Ī>L7͹>+0U#0Geq:Ī>L7͹>+0U00 *H=h0e0 TyHƿk2urxsيfUytCQ,l@THM1*_WDڼW=rm:=|(% Rrrustls-v-0.21.10/test-ca/ecdsa/ca.key000066400000000000000000000004621453461710000171710ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAfPEtZf6gtyHQ1sJhX fsM0meJ0xZcL+KdUg0wIIdvvt/6sBY4DKilNjFKCJ6rTjZKhZANiAAQYqFm8Q9vD 2uIMA63SaBiYRJAeoh6CZWLR7Kwnq9K1rblf39+km6ercBd033i1zhlzNkm8OUZx AFm6S3lw5Hd6zPKU2uFnMgsVoD6Cl+tQ7GazrEXNpNoR4/uejaf2YBE= -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/ecdsa/client.cert000066400000000000000000000013351453461710000202310ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB8TCCAZegAwIBAgICAxUwCgYIKoZIzj0EAwIwLjEsMCoGA1UEAwwjcG9ueXRv d24gRUNEU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwHhcNMjMwNjI3MjAxMzQ4WhcN MjgxMjE3MjAxMzQ4WjAaMRgwFgYDVQQDDA9wb255dG93biBjbGllbnQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAS9Lets4njbfbb2BY9fwKNB0ReQH3vV9u/M6Nygo2xG h2hvOqSm1XH8Od76hY+JVWOzzSahNHXHYchC08El9MnqoCXQWOijpMvBgDRfVytn 3Uaq7IlEzNP1+134cXrZtW+jgZswgZgwDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMC BsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFC+LrX+4QKTPQhgS LZEuIghR9Oy8MEQGA1UdIwQ9MDuAFCxwJ3fcyB99oWNB/MQ50XoWOLjhoSCkHjAc MRowGAYDVQQDDBFwb255dG93biBFQ0RTQSBDQYIBezAKBggqhkjOPQQDAgNIADBF AiEA5LHZT+lZj69DIcSMD7s60pED4o5oayRbzDYtiD9/YxUCIG+o4OrhLzMDyYg8 EPOMNriZlM49ZsLhIYFyUnREFO4S -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/ecdsa/client.chain000066400000000000000000000025441453461710000203610ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB2DCCAV6gAwIBAgIBezAKBggqhkjOPQQDAjAcMRowGAYDVQQDDBFwb255dG93 biBFQ0RTQSBDQTAeFw0yMzA2MjcyMDEzNDhaFw0zMzA2MjQyMDEzNDhaMC4xLDAq BgNVBAMMI3Bvbnl0b3duIEVDRFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEJevOmejkLmzS4CxKv0Jq9V2RzaZHcYcYpQGL j63QsxBpsK8Fdtv3G2v45F68m2fLG3dtMAbLPjlf4KlaCGQ0paN/MH0wHQYDVR0O BBYEFCxwJ3fcyB99oWNB/MQ50XoWOLjhMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAW gBRH7JdlcTr56fbEqro+vEw3zbk+KzAKBggqhkjOPQQDAgNoADBlAjBUq3F+eViV w6tddGnKFCI5C6R9As+ZxNnTBkam/z0PEoOA/JB9AR+nBemSFy112JQCMQD3Xz7/ e9HZWXzVGKUAFe/pXFYE1kaYGCAZ2I40A0tY5cSdewJBxvyAwyEqM2GG9wA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIByjCCAVCgAwIBAgIULO3+cmyE+k7ZGvmzLQIWYLxCNGUwCgYIKoZIzj0EAwIw HDEaMBgGA1UEAwwRcG9ueXRvd24gRUNEU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcN MzMwNjI0MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFQ0RTQSBDQTB2MBAG ByqGSM49AgEGBSuBBAAiA2IABBioWbxD28Pa4gwDrdJoGJhEkB6iHoJlYtHsrCer 0rWtuV/f36Sbp6twF3TfeLXOGXM2Sbw5RnEAWbpLeXDkd3rM8pTa4WcyCxWgPoKX 61DsZrOsRc2k2hHj+56Np/ZgEaNTMFEwHQYDVR0OBBYEFEfsl2VxOvnp9sSquj68 TDfNuT4rMB8GA1UdIwQYMBaAFEfsl2VxOvnp9sSquj68TDfNuT4rMA8GA1UdEwEB /wQFMAMBAf8wCgYIKoZIzj0EAwIDaAAwZQIwIFSvpx15SMa/hGsyB+B1cniBEZjt tXPZimZV13l0tkNRLMCnbJ2rtOmRAEBUlEhNAjEA/sYqju6nv4gHE+KDG19Xv0Ty 2rxX3fnlPbdybTqFnT188Rvq4igeJZkg2gEEUnKW -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/ecdsa/client.fullchain000066400000000000000000000041011453461710000212330ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB8TCCAZegAwIBAgICAxUwCgYIKoZIzj0EAwIwLjEsMCoGA1UEAwwjcG9ueXRv d24gRUNEU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwHhcNMjMwNjI3MjAxMzQ4WhcN MjgxMjE3MjAxMzQ4WjAaMRgwFgYDVQQDDA9wb255dG93biBjbGllbnQwdjAQBgcq hkjOPQIBBgUrgQQAIgNiAAS9Lets4njbfbb2BY9fwKNB0ReQH3vV9u/M6Nygo2xG h2hvOqSm1XH8Od76hY+JVWOzzSahNHXHYchC08El9MnqoCXQWOijpMvBgDRfVytn 3Uaq7IlEzNP1+134cXrZtW+jgZswgZgwDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMC BsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFC+LrX+4QKTPQhgS LZEuIghR9Oy8MEQGA1UdIwQ9MDuAFCxwJ3fcyB99oWNB/MQ50XoWOLjhoSCkHjAc MRowGAYDVQQDDBFwb255dG93biBFQ0RTQSBDQYIBezAKBggqhkjOPQQDAgNIADBF AiEA5LHZT+lZj69DIcSMD7s60pED4o5oayRbzDYtiD9/YxUCIG+o4OrhLzMDyYg8 EPOMNriZlM49ZsLhIYFyUnREFO4S -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB2DCCAV6gAwIBAgIBezAKBggqhkjOPQQDAjAcMRowGAYDVQQDDBFwb255dG93 biBFQ0RTQSBDQTAeFw0yMzA2MjcyMDEzNDhaFw0zMzA2MjQyMDEzNDhaMC4xLDAq BgNVBAMMI3Bvbnl0b3duIEVDRFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEJevOmejkLmzS4CxKv0Jq9V2RzaZHcYcYpQGL j63QsxBpsK8Fdtv3G2v45F68m2fLG3dtMAbLPjlf4KlaCGQ0paN/MH0wHQYDVR0O BBYEFCxwJ3fcyB99oWNB/MQ50XoWOLjhMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAW gBRH7JdlcTr56fbEqro+vEw3zbk+KzAKBggqhkjOPQQDAgNoADBlAjBUq3F+eViV w6tddGnKFCI5C6R9As+ZxNnTBkam/z0PEoOA/JB9AR+nBemSFy112JQCMQD3Xz7/ e9HZWXzVGKUAFe/pXFYE1kaYGCAZ2I40A0tY5cSdewJBxvyAwyEqM2GG9wA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIByjCCAVCgAwIBAgIULO3+cmyE+k7ZGvmzLQIWYLxCNGUwCgYIKoZIzj0EAwIw HDEaMBgGA1UEAwwRcG9ueXRvd24gRUNEU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcN MzMwNjI0MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFQ0RTQSBDQTB2MBAG ByqGSM49AgEGBSuBBAAiA2IABBioWbxD28Pa4gwDrdJoGJhEkB6iHoJlYtHsrCer 0rWtuV/f36Sbp6twF3TfeLXOGXM2Sbw5RnEAWbpLeXDkd3rM8pTa4WcyCxWgPoKX 61DsZrOsRc2k2hHj+56Np/ZgEaNTMFEwHQYDVR0OBBYEFEfsl2VxOvnp9sSquj68 TDfNuT4rMB8GA1UdIwQYMBaAFEfsl2VxOvnp9sSquj68TDfNuT4rMA8GA1UdEwEB /wQFMAMBAf8wCgYIKoZIzj0EAwIDaAAwZQIwIFSvpx15SMa/hGsyB+B1cniBEZjt tXPZimZV13l0tkNRLMCnbJ2rtOmRAEBUlEhNAjEA/sYqju6nv4gHE+KDG19Xv0Ty 2rxX3fnlPbdybTqFnT188Rvq4igeJZkg2gEEUnKW -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/ecdsa/client.key000066400000000000000000000004621453461710000200640ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDpP+leVyB54HTb9NfD W3ADGPF3i/rtiOhYwUAQPuu35fNWWMjS76S/RZUgIh6h0wihZANiAAS9Lets4njb fbb2BY9fwKNB0ReQH3vV9u/M6Nygo2xGh2hvOqSm1XH8Od76hY+JVWOzzSahNHXH YchC08El9MnqoCXQWOijpMvBgDRfVytn3Uaq7IlEzNP1+134cXrZtW8= -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/ecdsa/client.req000066400000000000000000000007001453461710000200560ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIIBEzCBmQIBADAaMRgwFgYDVQQDDA9wb255dG93biBjbGllbnQwdjAQBgcqhkjO PQIBBgUrgQQAIgNiAAS9Lets4njbfbb2BY9fwKNB0ReQH3vV9u/M6Nygo2xGh2hv OqSm1XH8Od76hY+JVWOzzSahNHXHYchC08El9MnqoCXQWOijpMvBgDRfVytn3Uaq 7IlEzNP1+134cXrZtW+gADAKBggqhkjOPQQDAgNpADBmAjEA9ZNAY7J6fkDQnNsX MZ9sp1eaGkC911T3bgxjQlS6DzRokH5m5S+HJ1VEhy4G54KgAjEA7lZxQ/sfneBb d7PQM7FJIfK2aDKUGrgYISWqJHYLWpbnQYCWAzs4Gp77roLN4JhG -----END CERTIFICATE REQUEST----- rustls-v-0.21.10/test-ca/ecdsa/client.revoked.crl.pem000066400000000000000000000006421453461710000222720ustar00rootroot00000000000000-----BEGIN X509 CRL----- MIIBDDCBtAIBATAKBggqhkjOPQQDAjAuMSwwKgYDVQQDDCNwb255dG93biBFQ0RT QSBsZXZlbCAyIGludGVybWVkaWF0ZRcNMjMwNjI3MjAxMzQ4WhcNMjMwNzA0MjAx MzQ4WjAjMCECAgMVFw0yMzA2MjcyMDEzNDhaMAwwCgYDVR0VBAMKAQGgMDAuMB8G A1UdIwQYMBaAFCxwJ3fcyB99oWNB/MQ50XoWOLjhMAsGA1UdFAQEAgIQATAKBggq hkjOPQQDAgNHADBEAiB2EMs2Nxmgs+u60tJcjvz6HQD6QY+ceh6ja6SDnov2/QIg UbHe7Wz9UwMMFOrHqGwArmispOqOVRRf0L58OE7fL9I= -----END X509 CRL----- rustls-v-0.21.10/test-ca/ecdsa/end.cert000066400000000000000000000013451453461710000175220ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB9zCCAZ6gAwIBAgICAcgwCgYIKoZIzj0EAwIwLjEsMCoGA1UEAwwjcG9ueXRv d24gRUNEU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwHhcNMjMwNjI3MjAxMzQ4WhcN MjgxMjE3MjAxMzQ4WjAZMRcwFQYDVQQDDA50ZXN0c2VydmVyLmNvbTBZMBMGByqG SM49AgEGCCqGSM49AwEHA0IABGnrR4cOWZShvEXPRxSWWPsb58nq2nW04OXX4SKM B3YHdgdbvFBSrVBYk9Oa1SYTvqwABz/+KuDr2QgqIgSDygqjgcAwgb0wDAYDVR0T AQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFKxlVrNnhfdS+3uOpnSJD8n8 QPCXMEQGA1UdIwQ9MDuAFCxwJ3fcyB99oWNB/MQ50XoWOLjhoSCkHjAcMRowGAYD VQQDDBFwb255dG93biBFQ0RTQSBDQYIBezA7BgNVHREENDAygg50ZXN0c2VydmVy LmNvbYIVc2Vjb25kLnRlc3RzZXJ2ZXIuY29tgglsb2NhbGhvc3QwCgYIKoZIzj0E AwIDRwAwRAIgXfnkEV0qiVx+Mi6XbUswZclU0U9AJPNW+Pf8gRtDa1ICIHYdiale PiC/sN27oopnJZiN9+4dXr+ZN+UoJa+vu4Wh -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/ecdsa/end.chain000066400000000000000000000025441453461710000176510ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB2DCCAV6gAwIBAgIBezAKBggqhkjOPQQDAjAcMRowGAYDVQQDDBFwb255dG93 biBFQ0RTQSBDQTAeFw0yMzA2MjcyMDEzNDhaFw0zMzA2MjQyMDEzNDhaMC4xLDAq BgNVBAMMI3Bvbnl0b3duIEVDRFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEJevOmejkLmzS4CxKv0Jq9V2RzaZHcYcYpQGL j63QsxBpsK8Fdtv3G2v45F68m2fLG3dtMAbLPjlf4KlaCGQ0paN/MH0wHQYDVR0O BBYEFCxwJ3fcyB99oWNB/MQ50XoWOLjhMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAW gBRH7JdlcTr56fbEqro+vEw3zbk+KzAKBggqhkjOPQQDAgNoADBlAjBUq3F+eViV w6tddGnKFCI5C6R9As+ZxNnTBkam/z0PEoOA/JB9AR+nBemSFy112JQCMQD3Xz7/ e9HZWXzVGKUAFe/pXFYE1kaYGCAZ2I40A0tY5cSdewJBxvyAwyEqM2GG9wA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIByjCCAVCgAwIBAgIULO3+cmyE+k7ZGvmzLQIWYLxCNGUwCgYIKoZIzj0EAwIw HDEaMBgGA1UEAwwRcG9ueXRvd24gRUNEU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcN MzMwNjI0MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFQ0RTQSBDQTB2MBAG ByqGSM49AgEGBSuBBAAiA2IABBioWbxD28Pa4gwDrdJoGJhEkB6iHoJlYtHsrCer 0rWtuV/f36Sbp6twF3TfeLXOGXM2Sbw5RnEAWbpLeXDkd3rM8pTa4WcyCxWgPoKX 61DsZrOsRc2k2hHj+56Np/ZgEaNTMFEwHQYDVR0OBBYEFEfsl2VxOvnp9sSquj68 TDfNuT4rMB8GA1UdIwQYMBaAFEfsl2VxOvnp9sSquj68TDfNuT4rMA8GA1UdEwEB /wQFMAMBAf8wCgYIKoZIzj0EAwIDaAAwZQIwIFSvpx15SMa/hGsyB+B1cniBEZjt tXPZimZV13l0tkNRLMCnbJ2rtOmRAEBUlEhNAjEA/sYqju6nv4gHE+KDG19Xv0Ty 2rxX3fnlPbdybTqFnT188Rvq4igeJZkg2gEEUnKW -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/ecdsa/end.fullchain000066400000000000000000000041111453461710000205240ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB9zCCAZ6gAwIBAgICAcgwCgYIKoZIzj0EAwIwLjEsMCoGA1UEAwwjcG9ueXRv d24gRUNEU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwHhcNMjMwNjI3MjAxMzQ4WhcN MjgxMjE3MjAxMzQ4WjAZMRcwFQYDVQQDDA50ZXN0c2VydmVyLmNvbTBZMBMGByqG SM49AgEGCCqGSM49AwEHA0IABGnrR4cOWZShvEXPRxSWWPsb58nq2nW04OXX4SKM B3YHdgdbvFBSrVBYk9Oa1SYTvqwABz/+KuDr2QgqIgSDygqjgcAwgb0wDAYDVR0T AQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFKxlVrNnhfdS+3uOpnSJD8n8 QPCXMEQGA1UdIwQ9MDuAFCxwJ3fcyB99oWNB/MQ50XoWOLjhoSCkHjAcMRowGAYD VQQDDBFwb255dG93biBFQ0RTQSBDQYIBezA7BgNVHREENDAygg50ZXN0c2VydmVy LmNvbYIVc2Vjb25kLnRlc3RzZXJ2ZXIuY29tgglsb2NhbGhvc3QwCgYIKoZIzj0E AwIDRwAwRAIgXfnkEV0qiVx+Mi6XbUswZclU0U9AJPNW+Pf8gRtDa1ICIHYdiale PiC/sN27oopnJZiN9+4dXr+ZN+UoJa+vu4Wh -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB2DCCAV6gAwIBAgIBezAKBggqhkjOPQQDAjAcMRowGAYDVQQDDBFwb255dG93 biBFQ0RTQSBDQTAeFw0yMzA2MjcyMDEzNDhaFw0zMzA2MjQyMDEzNDhaMC4xLDAq BgNVBAMMI3Bvbnl0b3duIEVDRFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEJevOmejkLmzS4CxKv0Jq9V2RzaZHcYcYpQGL j63QsxBpsK8Fdtv3G2v45F68m2fLG3dtMAbLPjlf4KlaCGQ0paN/MH0wHQYDVR0O BBYEFCxwJ3fcyB99oWNB/MQ50XoWOLjhMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAW gBRH7JdlcTr56fbEqro+vEw3zbk+KzAKBggqhkjOPQQDAgNoADBlAjBUq3F+eViV w6tddGnKFCI5C6R9As+ZxNnTBkam/z0PEoOA/JB9AR+nBemSFy112JQCMQD3Xz7/ e9HZWXzVGKUAFe/pXFYE1kaYGCAZ2I40A0tY5cSdewJBxvyAwyEqM2GG9wA= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIByjCCAVCgAwIBAgIULO3+cmyE+k7ZGvmzLQIWYLxCNGUwCgYIKoZIzj0EAwIw HDEaMBgGA1UEAwwRcG9ueXRvd24gRUNEU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcN MzMwNjI0MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFQ0RTQSBDQTB2MBAG ByqGSM49AgEGBSuBBAAiA2IABBioWbxD28Pa4gwDrdJoGJhEkB6iHoJlYtHsrCer 0rWtuV/f36Sbp6twF3TfeLXOGXM2Sbw5RnEAWbpLeXDkd3rM8pTa4WcyCxWgPoKX 61DsZrOsRc2k2hHj+56Np/ZgEaNTMFEwHQYDVR0OBBYEFEfsl2VxOvnp9sSquj68 TDfNuT4rMB8GA1UdIwQYMBaAFEfsl2VxOvnp9sSquj68TDfNuT4rMA8GA1UdEwEB /wQFMAMBAf8wCgYIKoZIzj0EAwIDaAAwZQIwIFSvpx15SMa/hGsyB+B1cniBEZjt tXPZimZV13l0tkNRLMCnbJ2rtOmRAEBUlEhNAjEA/sYqju6nv4gHE+KDG19Xv0Ty 2rxX3fnlPbdybTqFnT188Rvq4igeJZkg2gEEUnKW -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/ecdsa/end.key000066400000000000000000000003611453461710000173520ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgf6J7W1NE4YKpBCz3 iUpHUeK/ORhOnZmB05/avgbMslGhRANCAARp60eHDlmUobxFz0cUllj7G+fJ6tp1 tODl1+EijAd2B3YHW7xQUq1QWJPTmtUmE76sAAc//irg69kIKiIEg8oK -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/ecdsa/end.req000066400000000000000000000005531453461710000173540ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIHTMHsCAQAwGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAARp60eHDlmUobxFz0cUllj7G+fJ6tp1tODl1+EijAd2B3YH W7xQUq1QWJPTmtUmE76sAAc//irg69kIKiIEg8oKoAAwCgYIKoZIzj0EAwIDSAAw RQIgK9zvB6iucBJb1yzxW4paDF4upKZC0AlAhHHzu/Z9ZF8CIQCCMSB7g9DbL+R/ Lgcc3RgRFU3zrfUQVPfvI8spgPlLEw== -----END CERTIFICATE REQUEST----- rustls-v-0.21.10/test-ca/ecdsa/inter.cert000066400000000000000000000012741453461710000200760ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIB2DCCAV6gAwIBAgIBezAKBggqhkjOPQQDAjAcMRowGAYDVQQDDBFwb255dG93 biBFQ0RTQSBDQTAeFw0yMzA2MjcyMDEzNDhaFw0zMzA2MjQyMDEzNDhaMC4xLDAq BgNVBAMMI3Bvbnl0b3duIEVDRFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMFkwEwYH KoZIzj0CAQYIKoZIzj0DAQcDQgAEJevOmejkLmzS4CxKv0Jq9V2RzaZHcYcYpQGL j63QsxBpsK8Fdtv3G2v45F68m2fLG3dtMAbLPjlf4KlaCGQ0paN/MH0wHQYDVR0O BBYEFCxwJ3fcyB99oWNB/MQ50XoWOLjhMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMB BggrBgEFBQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAW gBRH7JdlcTr56fbEqro+vEw3zbk+KzAKBggqhkjOPQQDAgNoADBlAjBUq3F+eViV w6tddGnKFCI5C6R9As+ZxNnTBkam/z0PEoOA/JB9AR+nBemSFy112JQCMQD3Xz7/ e9HZWXzVGKUAFe/pXFYE1kaYGCAZ2I40A0tY5cSdewJBxvyAwyEqM2GG9wA= -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/ecdsa/inter.key000066400000000000000000000003611453461710000177250ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgWschVMQWGSJpkQZi rn/lAmhuIXvXtVGHMMPxnmD65nShRANCAAQl686Z6OQubNLgLEq/Qmr1XZHNpkdx hxilAYuPrdCzEGmwrwV22/cba/jkXrybZ8sbd20wBss+OV/gqVoIZDSl -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/ecdsa/inter.req000066400000000000000000000006071453461710000177270ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIHpMIGQAgEAMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVDRFNBIGxldmVsIDIgaW50 ZXJtZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJevOmejkLmzS4CxK v0Jq9V2RzaZHcYcYpQGLj63QsxBpsK8Fdtv3G2v45F68m2fLG3dtMAbLPjlf4Kla CGQ0paAAMAoGCCqGSM49BAMCA0gAMEUCIQCFPA0cyGppad9WspJ7gcjFY0dSZaXz ENNTIi74UZlDTAIgFbXyX3vaXvE68GA8DT2juwp62EfvQmlkmQPyD9/dU1Y= -----END CERTIFICATE REQUEST----- rustls-v-0.21.10/test-ca/ecdsa/nistp256.pem000066400000000000000000000001131453461710000201620ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BggqhkjOPQMBBw== -----END EC PARAMETERS----- rustls-v-0.21.10/test-ca/ecdsa/nistp384.pem000066400000000000000000000001071453461710000201670ustar00rootroot00000000000000-----BEGIN EC PARAMETERS----- BgUrgQQAIg== -----END EC PARAMETERS----- rustls-v-0.21.10/test-ca/eddsa/000077500000000000000000000000001453461710000160735ustar00rootroot00000000000000rustls-v-0.21.10/test-ca/eddsa/ca.cert000066400000000000000000000007751453461710000173460ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBTDCB/6ADAgECAhQC8ReNmcRk7uwJS9qD5HHOUnqejDAFBgMrZXAwHDEaMBgG A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0 MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh ANdeKJZRGeQQeoXP7VzFUR5IsigrEV2n9j64ULKW2lxvo1MwUTAdBgNVHQ4EFgQU V0M7GNkxTnhMXtnDlcrc1FgwdKswHwYDVR0jBBgwFoAUV0M7GNkxTnhMXtnDlcrc 1FgwdKswDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQDyZPQbhCIHnXU+/PXxg+34 ZK8BbCJ26SSU6i2hIfy6JZ077SUH+KBD8ziM16dHLj8snQPNol/IvNaYotZxkG8L -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/eddsa/ca.der000066400000000000000000000005201453461710000171470ustar00rootroot000000000000000L0d KڃqRz0+ep010U ponytown EdDSA CA0 230627201348Z 330624201348Z010U ponytown EdDSA CA0*0+ep!^(Qz\QH(+]>P\oS0Q0UWC;1NxL^ÕX0t0U#0WC;1NxL^ÕX0t0U00+epAd"u>dl"v$-!%;%C8קG.?,͢_ȼ֘qo rustls-v-0.21.10/test-ca/eddsa/ca.key000066400000000000000000000001671453461710000171740ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIIJaffMh+ZRQEWd6ClKFbIqtNox5iHKFrEpJxdWj934i -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/eddsa/client.cert000066400000000000000000000011371453461710000202320ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBlDCCAUagAwIBAgICAxUwBQYDK2VwMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVk RFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMDYyNzIwMTM0OFoXDTI4MTIx NzIwMTM0OFowGjEYMBYGA1UEAwwPcG9ueXRvd24gY2xpZW50MCowBQYDK2VwAyEA ikIM+JUu4rDHSg8gW9TSWaH6PD4/iqiwLtdNfv092jOjgZswgZgwDAYDVR0TAQH/ BAIwADALBgNVHQ8EBAMCBsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwHQYDVR0O BBYEFEDbO62mMOmhbgLp8e4kvSlhCD1uMEQGA1UdIwQ9MDuAFPW1B1HSYqhldaIu a+c7DGfwaYnwoSCkHjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQYIBezAF BgMrZXADQQBopkbWPM31tMKFg9W5+K2UhLqgCZIkXIqPgxkIkZCWjiJj0vHjHdYE M0u+zg8K4OOd1Hzz8jq+NanP6DH+IhID -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/eddsa/client.chain000066400000000000000000000020671453461710000203620ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBeDCCASqgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE U0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAuMSwwKgYDVQQD DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh APqLwTwcUvvu6UR71UT47ZlbXCjLbRQIFeq88fxMO31Go38wfTAdBgNVHQ4EFgQU 9bUHUdJiqGV1oi5r5zsMZ/BpifAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MB8GA1UdIwQYMBaAFFdD OxjZMU54TF7Zw5XK3NRYMHSrMAUGAytlcANBAO3DlgUfIZ0628+9BLTRRlMVfsE8 83okxDWnViuZK1AXiDsVEooDbjZUdg9esGOcC98QD5FpPDioAgwAv/OojQE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBTDCB/6ADAgECAhQC8ReNmcRk7uwJS9qD5HHOUnqejDAFBgMrZXAwHDEaMBgG A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0 MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh ANdeKJZRGeQQeoXP7VzFUR5IsigrEV2n9j64ULKW2lxvo1MwUTAdBgNVHQ4EFgQU V0M7GNkxTnhMXtnDlcrc1FgwdKswHwYDVR0jBBgwFoAUV0M7GNkxTnhMXtnDlcrc 1FgwdKswDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQDyZPQbhCIHnXU+/PXxg+34 ZK8BbCJ26SSU6i2hIfy6JZ077SUH+KBD8ziM16dHLj8snQPNol/IvNaYotZxkG8L -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/eddsa/client.fullchain000066400000000000000000000032261453461710000212430ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBlDCCAUagAwIBAgICAxUwBQYDK2VwMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVk RFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMDYyNzIwMTM0OFoXDTI4MTIx NzIwMTM0OFowGjEYMBYGA1UEAwwPcG9ueXRvd24gY2xpZW50MCowBQYDK2VwAyEA ikIM+JUu4rDHSg8gW9TSWaH6PD4/iqiwLtdNfv092jOjgZswgZgwDAYDVR0TAQH/ BAIwADALBgNVHQ8EBAMCBsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwHQYDVR0O BBYEFEDbO62mMOmhbgLp8e4kvSlhCD1uMEQGA1UdIwQ9MDuAFPW1B1HSYqhldaIu a+c7DGfwaYnwoSCkHjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQYIBezAF BgMrZXADQQBopkbWPM31tMKFg9W5+K2UhLqgCZIkXIqPgxkIkZCWjiJj0vHjHdYE M0u+zg8K4OOd1Hzz8jq+NanP6DH+IhID -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBeDCCASqgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE U0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAuMSwwKgYDVQQD DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh APqLwTwcUvvu6UR71UT47ZlbXCjLbRQIFeq88fxMO31Go38wfTAdBgNVHQ4EFgQU 9bUHUdJiqGV1oi5r5zsMZ/BpifAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MB8GA1UdIwQYMBaAFFdD OxjZMU54TF7Zw5XK3NRYMHSrMAUGAytlcANBAO3DlgUfIZ0628+9BLTRRlMVfsE8 83okxDWnViuZK1AXiDsVEooDbjZUdg9esGOcC98QD5FpPDioAgwAv/OojQE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBTDCB/6ADAgECAhQC8ReNmcRk7uwJS9qD5HHOUnqejDAFBgMrZXAwHDEaMBgG A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0 MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh ANdeKJZRGeQQeoXP7VzFUR5IsigrEV2n9j64ULKW2lxvo1MwUTAdBgNVHQ4EFgQU V0M7GNkxTnhMXtnDlcrc1FgwdKswHwYDVR0jBBgwFoAUV0M7GNkxTnhMXtnDlcrc 1FgwdKswDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQDyZPQbhCIHnXU+/PXxg+34 ZK8BbCJ26SSU6i2hIfy6JZ077SUH+KBD8ziM16dHLj8snQPNol/IvNaYotZxkG8L -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/eddsa/client.key000066400000000000000000000001671453461710000200670ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIP0ZM+0WkJlPg4HAOZoeUuzwNwJcYnd8xPJz+AquHXHk -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/eddsa/client.req000066400000000000000000000004321453461710000200610ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIGZME0CAQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gY2xpZW50MCowBQYDK2VwAyEA ikIM+JUu4rDHSg8gW9TSWaH6PD4/iqiwLtdNfv092jOgADAFBgMrZXADQQAjDOWl I+TmdeaDKr4TIc68ysA9LcGhAJ9wKk7jmkKazUjyZOgH1aBZjOr/sfgZFOIzJAUQ EtFhyeisIjNEyVUI -----END CERTIFICATE REQUEST----- rustls-v-0.21.10/test-ca/eddsa/client.revoked.crl.pem000066400000000000000000000006121453461710000222700ustar00rootroot00000000000000-----BEGIN X509 CRL----- MIH8MIGvAgEBMAUGAytlcDAuMSwwKgYDVQQDDCNwb255dG93biBFZERTQSBsZXZl bCAyIGludGVybWVkaWF0ZRcNMjMwNjI3MjAxMzQ4WhcNMjMwNzA0MjAxMzQ4WjAj MCECAgMVFw0yMzA2MjcyMDEzNDhaMAwwCgYDVR0VBAMKAQGgMDAuMB8GA1UdIwQY MBaAFPW1B1HSYqhldaIua+c7DGfwaYnwMAsGA1UdFAQEAgIQATAFBgMrZXADQQDD WUkRgsBscZItMH33ZpTYfFLb7nW7WHaJOZLQKc+qUb3gvHog8EzS5ODMyFWf9JTS 9sLL/xIkGKy3YhOYb50M -----END X509 CRL----- rustls-v-0.21.10/test-ca/eddsa/end.cert000066400000000000000000000012201453461710000175130ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBuDCCAWqgAwIBAgICAcgwBQYDK2VwMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVk RFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMDYyNzIwMTM0OFoXDTI4MTIx NzIwMTM0OFowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wKjAFBgMrZXADIQAJ EKUfnKRgXyH1rpH1pWbLrOlb3qtEPwJN3bNTC9s65KOBwDCBvTAMBgNVHRMBAf8E AjAAMAsGA1UdDwQEAwIGwDAdBgNVHQ4EFgQUvHn2rUm6gXRtnKlkf5sL7+rLQNMw RAYDVR0jBD0wO4AU9bUHUdJiqGV1oi5r5zsMZ/BpifChIKQeMBwxGjAYBgNVBAMM EXBvbnl0b3duIEVkRFNBIENBggF7MDsGA1UdEQQ0MDKCDnRlc3RzZXJ2ZXIuY29t ghVzZWNvbmQudGVzdHNlcnZlci5jb22CCWxvY2FsaG9zdDAFBgMrZXADQQCIz753 0RKNgM9pJTltnqZY/7jT0Sp6lSwLfxbbTztkOya1uDdYuyc7QbiCzBTPGW1PR4BT u+AP7l+DrZ9noX0D -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/eddsa/end.chain000066400000000000000000000020671453461710000176520ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBeDCCASqgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE U0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAuMSwwKgYDVQQD DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh APqLwTwcUvvu6UR71UT47ZlbXCjLbRQIFeq88fxMO31Go38wfTAdBgNVHQ4EFgQU 9bUHUdJiqGV1oi5r5zsMZ/BpifAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MB8GA1UdIwQYMBaAFFdD OxjZMU54TF7Zw5XK3NRYMHSrMAUGAytlcANBAO3DlgUfIZ0628+9BLTRRlMVfsE8 83okxDWnViuZK1AXiDsVEooDbjZUdg9esGOcC98QD5FpPDioAgwAv/OojQE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBTDCB/6ADAgECAhQC8ReNmcRk7uwJS9qD5HHOUnqejDAFBgMrZXAwHDEaMBgG A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0 MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh ANdeKJZRGeQQeoXP7VzFUR5IsigrEV2n9j64ULKW2lxvo1MwUTAdBgNVHQ4EFgQU V0M7GNkxTnhMXtnDlcrc1FgwdKswHwYDVR0jBBgwFoAUV0M7GNkxTnhMXtnDlcrc 1FgwdKswDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQDyZPQbhCIHnXU+/PXxg+34 ZK8BbCJ26SSU6i2hIfy6JZ077SUH+KBD8ziM16dHLj8snQPNol/IvNaYotZxkG8L -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/eddsa/end.fullchain000066400000000000000000000033071453461710000205330ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBuDCCAWqgAwIBAgICAcgwBQYDK2VwMC4xLDAqBgNVBAMMI3Bvbnl0b3duIEVk RFNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMDYyNzIwMTM0OFoXDTI4MTIx NzIwMTM0OFowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wKjAFBgMrZXADIQAJ EKUfnKRgXyH1rpH1pWbLrOlb3qtEPwJN3bNTC9s65KOBwDCBvTAMBgNVHRMBAf8E AjAAMAsGA1UdDwQEAwIGwDAdBgNVHQ4EFgQUvHn2rUm6gXRtnKlkf5sL7+rLQNMw RAYDVR0jBD0wO4AU9bUHUdJiqGV1oi5r5zsMZ/BpifChIKQeMBwxGjAYBgNVBAMM EXBvbnl0b3duIEVkRFNBIENBggF7MDsGA1UdEQQ0MDKCDnRlc3RzZXJ2ZXIuY29t ghVzZWNvbmQudGVzdHNlcnZlci5jb22CCWxvY2FsaG9zdDAFBgMrZXADQQCIz753 0RKNgM9pJTltnqZY/7jT0Sp6lSwLfxbbTztkOya1uDdYuyc7QbiCzBTPGW1PR4BT u+AP7l+DrZ9noX0D -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBeDCCASqgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE U0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAuMSwwKgYDVQQD DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh APqLwTwcUvvu6UR71UT47ZlbXCjLbRQIFeq88fxMO31Go38wfTAdBgNVHQ4EFgQU 9bUHUdJiqGV1oi5r5zsMZ/BpifAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MB8GA1UdIwQYMBaAFFdD OxjZMU54TF7Zw5XK3NRYMHSrMAUGAytlcANBAO3DlgUfIZ0628+9BLTRRlMVfsE8 83okxDWnViuZK1AXiDsVEooDbjZUdg9esGOcC98QD5FpPDioAgwAv/OojQE= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBTDCB/6ADAgECAhQC8ReNmcRk7uwJS9qD5HHOUnqejDAFBgMrZXAwHDEaMBgG A1UEAwwRcG9ueXRvd24gRWREU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0 MjAxMzQ4WjAcMRowGAYDVQQDDBFwb255dG93biBFZERTQSBDQTAqMAUGAytlcAMh ANdeKJZRGeQQeoXP7VzFUR5IsigrEV2n9j64ULKW2lxvo1MwUTAdBgNVHQ4EFgQU V0M7GNkxTnhMXtnDlcrc1FgwdKswHwYDVR0jBBgwFoAUV0M7GNkxTnhMXtnDlcrc 1FgwdKswDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQDyZPQbhCIHnXU+/PXxg+34 ZK8BbCJ26SSU6i2hIfy6JZ077SUH+KBD8ziM16dHLj8snQPNol/IvNaYotZxkG8L -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/eddsa/end.key000066400000000000000000000001671453461710000173570ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEILOqj5i5ZysyaAOtFkr018UPAoTCTr0eHNxlHz5Vu1Re -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/eddsa/end.req000066400000000000000000000004321453461710000173510ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIGYMEwCAQAwGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wKjAFBgMrZXADIQAJ EKUfnKRgXyH1rpH1pWbLrOlb3qtEPwJN3bNTC9s65KAAMAUGAytlcANBAL2hZOV2 2DtY/kLIqPXfLBjfVMJ+HXaAK5vmWwkFGyb7BOChfxHuZY9xKFJB/sW5RaRvdrGV gM4ITLs3RUISrws= -----END CERTIFICATE REQUEST----- rustls-v-0.21.10/test-ca/eddsa/inter.cert000066400000000000000000000010721453461710000200730ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBeDCCASqgAwIBAgIBezAFBgMrZXAwHDEaMBgGA1UEAwwRcG9ueXRvd24gRWRE U0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAuMSwwKgYDVQQD DCNwb255dG93biBFZERTQSBsZXZlbCAyIGludGVybWVkaWF0ZTAqMAUGAytlcAMh APqLwTwcUvvu6UR71UT47ZlbXCjLbRQIFeq88fxMO31Go38wfTAdBgNVHQ4EFgQU 9bUHUdJiqGV1oi5r5zsMZ/BpifAwIAYDVR0lAQH/BBYwFAYIKwYBBQUHAwEGCCsG AQUFBwMCMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQDAgH+MB8GA1UdIwQYMBaAFFdD OxjZMU54TF7Zw5XK3NRYMHSrMAUGAytlcANBAO3DlgUfIZ0628+9BLTRRlMVfsE8 83okxDWnViuZK1AXiDsVEooDbjZUdg9esGOcC98QD5FpPDioAgwAv/OojQE= -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/eddsa/inter.key000066400000000000000000000001671453461710000177320ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MC4CAQAwBQYDK2VwBCIEIC5GhQvbhmZMF9lb2IjzMsmXWvoct49j6E6Md35o42js -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/eddsa/inter.req000066400000000000000000000004661453461710000177330ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIGtMGECAQAwLjEsMCoGA1UEAwwjcG9ueXRvd24gRWREU0EgbGV2ZWwgMiBpbnRl cm1lZGlhdGUwKjAFBgMrZXADIQD6i8E8HFL77ulEe9VE+O2ZW1woy20UCBXqvPH8 TDt9RqAAMAUGAytlcANBACchnHnDs9zkmQUfatIS1jmQvANCJC0xHWVUHICWNgXg WhQ1zzySOKoFzxH+rxiX13LlkWEokQJFdLALyU0PCgc= -----END CERTIFICATE REQUEST----- rustls-v-0.21.10/test-ca/openssl.cnf000066400000000000000000000013711453461710000171700ustar00rootroot00000000000000 [ v3_end ] basicConstraints = critical,CA:false keyUsage = nonRepudiation, digitalSignature subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always subjectAltName = @alt_names [ v3_client ] basicConstraints = critical,CA:false keyUsage = nonRepudiation, digitalSignature extendedKeyUsage = critical, clientAuth subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always [ v3_inter ] subjectKeyIdentifier = hash extendedKeyUsage = critical, serverAuth, clientAuth basicConstraints = CA:true keyUsage = cRLSign, keyCertSign, digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment, keyAgreement, keyCertSign, cRLSign [ alt_names ] DNS.1 = testserver.com DNS.2 = second.testserver.com DNS.3 = localhost rustls-v-0.21.10/test-ca/rsa/000077500000000000000000000000001453461710000156005ustar00rootroot00000000000000rustls-v-0.21.10/test-ca/rsa/ca.cert000066400000000000000000000034361453461710000170500ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFFTCCAv2gAwIBAgIUGIGV3FDZXdNIPCe2s9FHmjTqeLYwDQYJKoZIhvcNAQEL BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTIzMDYyNzIwMTM0N1oX DTMzMDYyNDIwMTM0N1owGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9Dkdby/tuMYvV62TbVmz7CWASGq/ f/m7zZPlS8SSoMdqow1pr8mcWD0od39rIYFlGGoLHoBtqP3d6cV0KRpcJqDF4oDr HrMoZikpQAO3s50NvXWhkESxGzCUJD4XtvZkmK+gBdob/qrOn1uqYdkD8YM6rnqw R9VOz/GLWmguWMhd66mMAPvpfLD3wPtJmIzMQyrGRuLDenm9cigNNjYtCDFiHvbL H499UikqgYIVPIPal4nzDWO/iAo/ktC7zDI/cH+q38eZJbKy6z1Yi+VTI4285r/M cex4DTJVfdTRYt2lRKzLhCFwdPED7CZS1pVhNh+C4DCPIw/jreBmfq1rSKnPqVqA BWm7B+WVKAOOPbIQtXHbIfjRzkjF/37I5zWvLHaLlfPaEpjIlNAZTjQgYaOCMI0+ HPHvWVklE4CY8jq44N2K4bPAvr6NpLkiqsaNvfOwmLdnmfDoytmOSbvl0bSauLkg WDasorR7Z4k2Q157Mmictv1CSSo4PvZB44l0nC2Xzd731DgUjxiAAjOcgFXUNLPp ALQBI+5xkHhnoqcFe6LWlZkRbdfWHVXVRnNKRADyXS0bwbSmVOsnvBPQFCbL+0X6 3m8Wvk/2RymALARIQ1zIl+Wpt03YZU9XXevNsHa7xFeNRY3NinxI68mIux80C2Fc rdFKgNxfhjVhi7UCAwEAAaNTMFEwHQYDVR0OBBYEFDoLyGBbOF6+Uo0/z++0JGLK T3R9MB8GA1UdIwQYMBaAFDoLyGBbOF6+Uo0/z++0JGLKT3R9MA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQELBQADggIBANFjC5Ry/i+A38YrDIGSRAf0ePZj3tjc Bh/SV75cgIJUGGS+KCX2+K7P5/9XxH/fwb5kZZyfZsT7oPiv0nqoXutljcoqfb/V Cx7SJD600JhJsPu4HJsbF4IP660gNSnSyNt4ESx8RIECW3o9iO/cgKpGkValT1cC HKSrv80l+whwnRRKHV2yvl3N9RkVXlAcFOP8zhRjQsrMNZSIz1Ux9KsJG68s52tX SSqK00bQQMMFiznF+xvN31GL8nQrtgPvbbz3EI6EjdBhXtwHSZXzUXM5IYWD/GzO a0Td7TFGQlZckq6/rxT0Qp4qzYlEx1JQi14Mv9wQoAXkew706s6oGBCd9xg+UVu/ cny2l7gal8kJ2rcOmiXY04IpiXlQQuovAntB6XHpgc2Vgh7Ao93DpBxmRfFTXI2r O0C6DMzd/oHDbSNkxONuk6V0usvGnFLSbtPDJsJegpSjzSA+CWR9es0PAqsf92Be unCoUEx+Vzz87/g+shQKkWw+Bw1VKmTGmtXK0x9r/Nawmj19YRfp/CYhdJT3xj3L 5c1Aw5EVM3Ti6ABSi3Lk8dO6XewcR8dgr2wxGE6eSL4XJ1e7GwaSt+F3KbTeAY7c KcWhobyFAXIyXmjhNYgZA+atnRuD2Cx4w/kO7fzn8C3c0aVZYuv2cXCeqFlFBbas EhGAHWy7QFZ+ -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/rsa/ca.der000066400000000000000000000024311453461710000166570ustar00rootroot0000000000000000P]H<'G4x0  *H  010U ponytown RSA CA0 230627201347Z 330624201347Z010U ponytown RSA CA0"0  *H 0 9o//WmY%Hj͓KĒj iɜX=(wk!ej mt)\&(f))@ uD0$>dΟ[a:zGNZh.X]멌|IC*Fzyr( 66-1b}R)*<ڗ c ?л2?pǙ%=XS#qx 2U}bݥD˄!pt&R֕a60#f~kHϩZi(=q!H~5,vȔN4 a0>YY%:݊"ƍ󰘷gَIѴ X6{g6C^{2hBI*8>At-83U4#qxg{֕mUFsJD]-T'&EoOG),HC\ȗ婷MeOW]ͰvWE͊|HɈ4 a\J_5aS0Q0U: `[8^R?$bOt}0U#0: `[8^R?$bOt}0U00  *H  c r/+ DxcW\Td(%Wdefz^e*} $>ИI 5)x,|D[z=܀FVOW%pJ]]^PcB5U1 ,kWI*F@9Qt+ma^IQs9!lkD1FBV\B*͉DRP^ {Ψ>Q[r| ڷ%ӂ)yPB/{Aq͕äfES\;@ m#dntƜRn&^ > d}z`^pPL~W<> l> U*dƚkְ=}a&!t=@Ñ3tRrӺ]G`l1NH'Ww))šr2^h5歝,x-ѥYbqpYEl@V~rustls-v-0.21.10/test-ca/rsa/ca.key000066400000000000000000000063041453461710000167000ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQD0OR1vL+24xi9X rZNtWbPsJYBIar9/+bvNk+VLxJKgx2qjDWmvyZxYPSh3f2shgWUYagsegG2o/d3p xXQpGlwmoMXigOsesyhmKSlAA7eznQ29daGQRLEbMJQkPhe29mSYr6AF2hv+qs6f W6ph2QPxgzquerBH1U7P8YtaaC5YyF3rqYwA++l8sPfA+0mYjMxDKsZG4sN6eb1y KA02Ni0IMWIe9ssfj31SKSqBghU8g9qXifMNY7+ICj+S0LvMMj9wf6rfx5klsrLr PViL5VMjjbzmv8xx7HgNMlV91NFi3aVErMuEIXB08QPsJlLWlWE2H4LgMI8jD+Ot 4GZ+rWtIqc+pWoAFabsH5ZUoA449shC1cdsh+NHOSMX/fsjnNa8sdouV89oSmMiU 0BlONCBho4IwjT4c8e9ZWSUTgJjyOrjg3Yrhs8C+vo2kuSKqxo2987CYt2eZ8OjK 2Y5Ju+XRtJq4uSBYNqyitHtniTZDXnsyaJy2/UJJKjg+9kHjiXScLZfN3vfUOBSP GIACM5yAVdQ0s+kAtAEj7nGQeGeipwV7otaVmRFt19YdVdVGc0pEAPJdLRvBtKZU 6ye8E9AUJsv7Rfrebxa+T/ZHKYAsBEhDXMiX5am3TdhlT1dd682wdrvEV41Fjc2K fEjryYi7HzQLYVyt0UqA3F+GNWGLtQIDAQABAoICAAdaA/2c2Il/YPcN511oHd2c VpUKrmKqOdg7MEo5Mjcn/Mwu7MeF4iO/c40yILkMrbMwCs8+pNs5b4l7kCUzASMi I9LPRRFsUAMDQ8kEuge5UPiRc4bMPcIu+PnX6w7VS+65gRYSaSIfy8IWsei2h6l1 fqBR9FlO0OVUxN64oOyIDr7q7UDHIVHHlS2rlgOP+XYfWE8GwUVAKBvCz0lnSBby Pzaymlq3QkAYgFcPSDErwIcsEYAnSIfn097iuarj64gpAuCWbMQqi1UMruWtkyfq B42xDsGlkXEt2rT2+xAznw36LAYsm4RpqbYqHfd0d7PeLvctfwfz90tjCrLPHABj Ti/Bg6fOS28oGW9kJ8B/06u/3Alg50EAmg5AnDprb3k74TfsEx3Hm5deVrKIYdYS Z8dFxpGueOP2sCXpXk06R1Nh1xWyh2K08cGrjiZRaaSDguOxysigL508EsbIGIoR mqLb/YLGnFg4i+nWBUleCWRbmL9VUrA+/Fjvq389PcupINrDBClUpPUCxPY6XQX0 sdclRagSjwXgd/xQYfbRIAOGXBphZ2+56wtS8Iiqm1o/d+cxfDolP2sH6NLF6vF8 35BQKm5Tne0r/ZFv+wJhUkUdQn12O9WG+Vofh9LeML3BYc3OUJSwn8KiBTmeitYQ RCJBHxx5F+Uobz8H5FrhAoIBAQD88oMCUekOfL7WcyP1G1+ec/U5KEumsC7XEXJX 5ErM8r7gFBl1fBGObw5usR0mTyYkEXorNpySRbBfhtkofoQji/kTUesoHxummzT/ CAiUDnBS51X90SihoKc9xOOVtvb31adaqIzE/AMXYyzU5sN//8dC2JBnjQjwVuEn syPX7N2dydYrPvP/rllh3CfUj/EBBk65y2wJQlJDs2WfDJNjO9s9qQ9SubT2MJJ/ 6+LW3nv8VS3H6qDzl4CdVuTWVvH1WcyjhCJKk2VBlDG4a6XBCd/GtB1r4Oo4xhgP MnSyrllGoZo5rZvEq/jZesYz0dBk3yqwl5sjTmvIsSXdHBgzAoIBAQD3K6ZHivRy ffD7v0DJoPqTYfHM+DsACbTZHsu3SOpPyHy5cc1nImIP/DojyT8Vjim28neVLVwC Gx8q6glbFgtk29ILuBa5r+gV6hqI66zXxVV4ytErkBuXS8u4b/U+kCgcSf2diZpT SIxK9kj8rWzAbxDOhlBcJDrRePEdFkLQ2dingrff4MxkOPDRYAnMC3r4Bd+n5XOg e0jorziBIabYLsI9xxHp7AbFrFYnNvzYUWfv/N2ed6oCdtAH+CYXxj01QSIBMwmh x/gOBxAna2uKRTxoCfOiT3ngRduQ3WKGg1GDn8Wchp41w4IKbYt0VPGXlLTSpJSg IUQqJ+fTyIR3AoIBAEhdJMe8IT2IyJvXUtkjXKabK/OPKJ1mV/AlSJ4GbLPXWm4G sgXfWbJy6SEXwGweRp4Y9ed49zANidi6XlPsZec5eydgzzKqO6HdUzsG1FVvEAlX r00u0j3zFQVh124UavEaCYexIpyUMFo3gDLkVde/mATyqdVGDuGbKUzPPhje5cPn Y0L5/poOCfoqHqb8CwmtAUa8AIthkuFVaGQpF91S2XT5ca3L/Q5VdQPtuvaXrcbR o4hHAobNt/jLTCpZs1zqtNWuzpShOF2bhOHqwf/I0GErVCNxs/BME8P9Pk+D+3xu bQ3FMgQA4u9s5Vkb1E+XXMIqjTJ7k/BVZaytBesCggEAGbmkS8vtl0D+ZOVJ8/Ja Qh6ukPvBAEcCWJq47zGamYUvXgm3LCXK+QjycCkQ9MhgFRd1VMRs0BdMjiXfpWhM 9UlfujKFwvvI9wbvjhKhYa+7LqBFVvhftsZ/xIl6h/FvC0q0J8JbmpFxcJfjjtDq AblNkYEvOffXW1fwGGvptl0GDKExTA7UlxXKErChNGh5evj5hzr9ZtWOCBG8mswK 1nM/ajie567WIZrHOLujY0xNug+ibUzdF/aPvlSYel76neFSjbdnKDxs1+DqUIAA qFp+aAGpJtqIv8vlh1VTXNasFDv70Ee+ja/0h+tQ2WHB51nl3AqfIW907cJLgaJc DwKCAQArWCadaAPle8GwOuBjl1n+cwPOdEg37Aab8AD9wcjEG+blevijPAwt2kQd tFAZOtj1Sp4sAeGpZfbVaYSAvjQi5gkitPm8ZEkHpVzF6Xbp3fyfq4B4F78X9fgV 2/ZA8sH30KAZsr/+PKvLP2dC4s2ZlOMySM5Ag8mGDtJDTd49XDJf3HDoKiivO+NR uajuBJrFlCbilOwdL8i7eQ48UPBv87gUR2nSVlr2UxSHqXdEg4wZE7QskjG8/vud 7F3nLLQk14Qqv9AuojIIugRNeOQeJpBaY+iTZwrKEFActErRN4x+DbnouBuJESc8 jJsEX0b+CuJuF8UXlH85H3kiG/Tl -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/rsa/client.cert000066400000000000000000000025671453461710000177470ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIID3DCCAkSgAwIBAgICAxUwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMDYyNzIwMTM0OFoX DTI4MTIxNzIwMTM0OFowGjEYMBYGA1UEAwwPcG9ueXRvd24gY2xpZW50MIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3pPIalsU/g+B0hjSuj/f9JuW6tMe ioqeTC5B1LCzSY9RS/PiSUfTgRyZ1e6cv7wlASeoj2rpaqPnHxUTz89OPR1nHOEK BytX42YBrm0D9BQPz95Wzg62fVL8d4V6rh4AvDZA90N1f/W0pkGsmygB0aHQO5h5 rM1nTNhvm6Uuz+rQqts67KPDE9He16Q4oYK/djmlRE2D0sBL1YKsyO1K9pCCHoKV +loYwn4unKvvCuhntC7LFQaB+3SdbHVW0VjCXF6iKHalJww2sI90pYDYYh8J4Iws mJ6WytEh45SIg65ZHsz3bNPVBUPHUODBN4nutYJnVeZUIDbd2HfOvADpWwIDAQAB o4GZMIGWMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgbAMBYGA1UdJQEB/wQMMAoG CCsGAQUFBwMCMB0GA1UdDgQWBBQQZNmo6prWzRHju+orTZeCDSSnoTBCBgNVHSME OzA5gBQrYSNFxVz2xpuhaMyTwFvsTvWcLKEepBwwGjEYMBYGA1UEAwwPcG9ueXRv d24gUlNBIENBggF7MA0GCSqGSIb3DQEBCwUAA4IBgQAl7MDSv/BElk0e3ke2WGOa f6Y3WRFciWC603sr3vSoYPoD2A8Q4ug/a/Bnhs7VlS6YChsk3IT1rpjgJIgLDUUc dK8TmE+ibSsWYj0zGXr3UhNNZKoZl0JT7OxJfsqYY2aCjCtsLhRS+kpCr0+e/zMT OcsI0iN9F2AyFFT9eFQCOS/IKpldIj8eB+Bhx6so3/qkX/Hg1CJqRmVbznNY3OCN I4k/87sze2e0fdU3bH8275zRSfONb35BdceKn8VpZywWgxm/eRrEv0U9Yqi/Gdv6 elrbRSNw5uJXwlmi4k4+OnbOznzBsrteCwigUBrTcJRHs/8eRLyRRNkRysQG4Flb mh+KDsj/f+Odjg1diQOwPMSC4ESmZdZgSEn9Zcd4Oy66+OSMdfctO6e6v6vkZddJ /jcTUZEPsT9y+SCqtCy+9NHHN4VVMOSQhhCj5GiPqfuEe/slzlUlS4xg2+9s9yqH Z+liOu6o2++JVbXDeYYFx8v0ZhttMYaXlLw1q+s4IyM= -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/rsa/client.chain000066400000000000000000000067121453461710000200700ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEwDCCAqigAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 dG93biBSU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAsMSow KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC4cHjqDpD9JPmZUzQ6VRraIaxPysbc Iu6JgHYuFZeFGi0dU4DkCjpySiqF0r6Ym3ZprweJdsX0WMHYgcn/L+0GcgXbxZKv emyeHS1XSFnhJUwNHdPzz7YUL7x5n6ucZlU89XB7yzjpm8KF8XEltM5n63TGvVm2 xstJu9YE5tIXFOo59R3GM0xaSexNhKTTaY4Q4kvLURHYhHB0WSrngJTW77u65JRp mO9y+SOtHlpuOrlf7/PD6sQk8Fb0UZHJDlNVK3ScVQ/i4eHl2+VKl77UoavI/SYG luPQwy2SllYHPnvXryTIDsO4CAhtHe1kBqgEe4gnQqkKBifnom1oexaKtOqP5msw 9+P+DqjOu08qGLUS8UB05cLXtqnMp68/6cPT3sE+1tm7iEYZwqxSLSS3DOPdBr3H bBq820O4aypi4dEPTAnWkYUj3FG7hfOyBFNtNkY2wEX1K/ylo32d2kOP6oRrBubs xYT61q1cVIvcjrA0Ko6XRDHqCPEloGlB0mUCAwEAAaN/MH0wHQYDVR0OBBYEFCth I0XFXPbGm6FozJPAW+xO9ZwsMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAWgBQ6C8hg WzhevlKNP8/vtCRiyk90fTANBgkqhkiG9w0BAQsFAAOCAgEAnjpQF9FTwFQD75aA 1xL15XR5l6DrjDzZfq13gr/StaCQJ44OtmJvjzdgfPI5sRmpiUgU7bK4rOhKLK6C 3NUpq+Zg+5D2TzDHwyBNb0uViTgr75/P+HHBJUHwdvKbenDkn1QfPlx8nOtyyyFD Jw3HEVGIAzGX3rWUkyZhwLQ1JUC6tmckNGg/9OVxKnr0f1fxct/F1Hc3Hd806Wqc /D2QdDDTCtA9qZt53ED+SaLI1mzfvm67pyRZ43V5BvkAj1xiumGFHqLheK7hdC9V WXHgPQobGJgyhOCAnQru1iKKnld+VIDfkZHu6fchsJg9ty/526QfyKRGfT7ak3Ng 0VSRsBj9zRPBiKrK4SFcmmWVIbj+lyN0xJWJFJ0ZrxFnLE/fjzF6smyTZxRYC15L NCq+xy4yAvFRvcLOCjhmWkDJeAa/Y2cg50xrHpK/Y6FtPT2Bg34N1/fY9FP1r6AO QMSrFGWpRl8Nsm6EfmJMJR1vfX52H7u0rla6Ay86yL3JMAfW7zFMYrRXx4bxq9hF Rv4z5nj1RVR3+iNeOIWNx7YtyxvYvd+zPXY2LlkAr9QAjScvsiCKWi/5z9eC8aSX VJcQoaKWoX2/SwjRuTSsI9P7rHeGNavUQCVL97slkdx//Xvw6ruP3bOQ+XzYvPAO /DUNNf2nkPD7DKj8pFV8Ia8p910= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCAv2gAwIBAgIUGIGV3FDZXdNIPCe2s9FHmjTqeLYwDQYJKoZIhvcNAQEL BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTIzMDYyNzIwMTM0N1oX DTMzMDYyNDIwMTM0N1owGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9Dkdby/tuMYvV62TbVmz7CWASGq/ f/m7zZPlS8SSoMdqow1pr8mcWD0od39rIYFlGGoLHoBtqP3d6cV0KRpcJqDF4oDr HrMoZikpQAO3s50NvXWhkESxGzCUJD4XtvZkmK+gBdob/qrOn1uqYdkD8YM6rnqw R9VOz/GLWmguWMhd66mMAPvpfLD3wPtJmIzMQyrGRuLDenm9cigNNjYtCDFiHvbL H499UikqgYIVPIPal4nzDWO/iAo/ktC7zDI/cH+q38eZJbKy6z1Yi+VTI4285r/M cex4DTJVfdTRYt2lRKzLhCFwdPED7CZS1pVhNh+C4DCPIw/jreBmfq1rSKnPqVqA BWm7B+WVKAOOPbIQtXHbIfjRzkjF/37I5zWvLHaLlfPaEpjIlNAZTjQgYaOCMI0+ HPHvWVklE4CY8jq44N2K4bPAvr6NpLkiqsaNvfOwmLdnmfDoytmOSbvl0bSauLkg WDasorR7Z4k2Q157Mmictv1CSSo4PvZB44l0nC2Xzd731DgUjxiAAjOcgFXUNLPp ALQBI+5xkHhnoqcFe6LWlZkRbdfWHVXVRnNKRADyXS0bwbSmVOsnvBPQFCbL+0X6 3m8Wvk/2RymALARIQ1zIl+Wpt03YZU9XXevNsHa7xFeNRY3NinxI68mIux80C2Fc rdFKgNxfhjVhi7UCAwEAAaNTMFEwHQYDVR0OBBYEFDoLyGBbOF6+Uo0/z++0JGLK T3R9MB8GA1UdIwQYMBaAFDoLyGBbOF6+Uo0/z++0JGLKT3R9MA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQELBQADggIBANFjC5Ry/i+A38YrDIGSRAf0ePZj3tjc Bh/SV75cgIJUGGS+KCX2+K7P5/9XxH/fwb5kZZyfZsT7oPiv0nqoXutljcoqfb/V Cx7SJD600JhJsPu4HJsbF4IP660gNSnSyNt4ESx8RIECW3o9iO/cgKpGkValT1cC HKSrv80l+whwnRRKHV2yvl3N9RkVXlAcFOP8zhRjQsrMNZSIz1Ux9KsJG68s52tX SSqK00bQQMMFiznF+xvN31GL8nQrtgPvbbz3EI6EjdBhXtwHSZXzUXM5IYWD/GzO a0Td7TFGQlZckq6/rxT0Qp4qzYlEx1JQi14Mv9wQoAXkew706s6oGBCd9xg+UVu/ cny2l7gal8kJ2rcOmiXY04IpiXlQQuovAntB6XHpgc2Vgh7Ao93DpBxmRfFTXI2r O0C6DMzd/oHDbSNkxONuk6V0usvGnFLSbtPDJsJegpSjzSA+CWR9es0PAqsf92Be unCoUEx+Vzz87/g+shQKkWw+Bw1VKmTGmtXK0x9r/Nawmj19YRfp/CYhdJT3xj3L 5c1Aw5EVM3Ti6ABSi3Lk8dO6XewcR8dgr2wxGE6eSL4XJ1e7GwaSt+F3KbTeAY7c KcWhobyFAXIyXmjhNYgZA+atnRuD2Cx4w/kO7fzn8C3c0aVZYuv2cXCeqFlFBbas EhGAHWy7QFZ+ -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/rsa/client.fullchain000066400000000000000000000115011453461710000207430ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIID3DCCAkSgAwIBAgICAxUwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMDYyNzIwMTM0OFoX DTI4MTIxNzIwMTM0OFowGjEYMBYGA1UEAwwPcG9ueXRvd24gY2xpZW50MIIBIjAN BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3pPIalsU/g+B0hjSuj/f9JuW6tMe ioqeTC5B1LCzSY9RS/PiSUfTgRyZ1e6cv7wlASeoj2rpaqPnHxUTz89OPR1nHOEK BytX42YBrm0D9BQPz95Wzg62fVL8d4V6rh4AvDZA90N1f/W0pkGsmygB0aHQO5h5 rM1nTNhvm6Uuz+rQqts67KPDE9He16Q4oYK/djmlRE2D0sBL1YKsyO1K9pCCHoKV +loYwn4unKvvCuhntC7LFQaB+3SdbHVW0VjCXF6iKHalJww2sI90pYDYYh8J4Iws mJ6WytEh45SIg65ZHsz3bNPVBUPHUODBN4nutYJnVeZUIDbd2HfOvADpWwIDAQAB o4GZMIGWMAwGA1UdEwEB/wQCMAAwCwYDVR0PBAQDAgbAMBYGA1UdJQEB/wQMMAoG CCsGAQUFBwMCMB0GA1UdDgQWBBQQZNmo6prWzRHju+orTZeCDSSnoTBCBgNVHSME OzA5gBQrYSNFxVz2xpuhaMyTwFvsTvWcLKEepBwwGjEYMBYGA1UEAwwPcG9ueXRv d24gUlNBIENBggF7MA0GCSqGSIb3DQEBCwUAA4IBgQAl7MDSv/BElk0e3ke2WGOa f6Y3WRFciWC603sr3vSoYPoD2A8Q4ug/a/Bnhs7VlS6YChsk3IT1rpjgJIgLDUUc dK8TmE+ibSsWYj0zGXr3UhNNZKoZl0JT7OxJfsqYY2aCjCtsLhRS+kpCr0+e/zMT OcsI0iN9F2AyFFT9eFQCOS/IKpldIj8eB+Bhx6so3/qkX/Hg1CJqRmVbznNY3OCN I4k/87sze2e0fdU3bH8275zRSfONb35BdceKn8VpZywWgxm/eRrEv0U9Yqi/Gdv6 elrbRSNw5uJXwlmi4k4+OnbOznzBsrteCwigUBrTcJRHs/8eRLyRRNkRysQG4Flb mh+KDsj/f+Odjg1diQOwPMSC4ESmZdZgSEn9Zcd4Oy66+OSMdfctO6e6v6vkZddJ /jcTUZEPsT9y+SCqtCy+9NHHN4VVMOSQhhCj5GiPqfuEe/slzlUlS4xg2+9s9yqH Z+liOu6o2++JVbXDeYYFx8v0ZhttMYaXlLw1q+s4IyM= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEwDCCAqigAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 dG93biBSU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAsMSow KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC4cHjqDpD9JPmZUzQ6VRraIaxPysbc Iu6JgHYuFZeFGi0dU4DkCjpySiqF0r6Ym3ZprweJdsX0WMHYgcn/L+0GcgXbxZKv emyeHS1XSFnhJUwNHdPzz7YUL7x5n6ucZlU89XB7yzjpm8KF8XEltM5n63TGvVm2 xstJu9YE5tIXFOo59R3GM0xaSexNhKTTaY4Q4kvLURHYhHB0WSrngJTW77u65JRp mO9y+SOtHlpuOrlf7/PD6sQk8Fb0UZHJDlNVK3ScVQ/i4eHl2+VKl77UoavI/SYG luPQwy2SllYHPnvXryTIDsO4CAhtHe1kBqgEe4gnQqkKBifnom1oexaKtOqP5msw 9+P+DqjOu08qGLUS8UB05cLXtqnMp68/6cPT3sE+1tm7iEYZwqxSLSS3DOPdBr3H bBq820O4aypi4dEPTAnWkYUj3FG7hfOyBFNtNkY2wEX1K/ylo32d2kOP6oRrBubs xYT61q1cVIvcjrA0Ko6XRDHqCPEloGlB0mUCAwEAAaN/MH0wHQYDVR0OBBYEFCth I0XFXPbGm6FozJPAW+xO9ZwsMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAWgBQ6C8hg WzhevlKNP8/vtCRiyk90fTANBgkqhkiG9w0BAQsFAAOCAgEAnjpQF9FTwFQD75aA 1xL15XR5l6DrjDzZfq13gr/StaCQJ44OtmJvjzdgfPI5sRmpiUgU7bK4rOhKLK6C 3NUpq+Zg+5D2TzDHwyBNb0uViTgr75/P+HHBJUHwdvKbenDkn1QfPlx8nOtyyyFD Jw3HEVGIAzGX3rWUkyZhwLQ1JUC6tmckNGg/9OVxKnr0f1fxct/F1Hc3Hd806Wqc /D2QdDDTCtA9qZt53ED+SaLI1mzfvm67pyRZ43V5BvkAj1xiumGFHqLheK7hdC9V WXHgPQobGJgyhOCAnQru1iKKnld+VIDfkZHu6fchsJg9ty/526QfyKRGfT7ak3Ng 0VSRsBj9zRPBiKrK4SFcmmWVIbj+lyN0xJWJFJ0ZrxFnLE/fjzF6smyTZxRYC15L NCq+xy4yAvFRvcLOCjhmWkDJeAa/Y2cg50xrHpK/Y6FtPT2Bg34N1/fY9FP1r6AO QMSrFGWpRl8Nsm6EfmJMJR1vfX52H7u0rla6Ay86yL3JMAfW7zFMYrRXx4bxq9hF Rv4z5nj1RVR3+iNeOIWNx7YtyxvYvd+zPXY2LlkAr9QAjScvsiCKWi/5z9eC8aSX VJcQoaKWoX2/SwjRuTSsI9P7rHeGNavUQCVL97slkdx//Xvw6ruP3bOQ+XzYvPAO /DUNNf2nkPD7DKj8pFV8Ia8p910= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCAv2gAwIBAgIUGIGV3FDZXdNIPCe2s9FHmjTqeLYwDQYJKoZIhvcNAQEL BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTIzMDYyNzIwMTM0N1oX DTMzMDYyNDIwMTM0N1owGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9Dkdby/tuMYvV62TbVmz7CWASGq/ f/m7zZPlS8SSoMdqow1pr8mcWD0od39rIYFlGGoLHoBtqP3d6cV0KRpcJqDF4oDr HrMoZikpQAO3s50NvXWhkESxGzCUJD4XtvZkmK+gBdob/qrOn1uqYdkD8YM6rnqw R9VOz/GLWmguWMhd66mMAPvpfLD3wPtJmIzMQyrGRuLDenm9cigNNjYtCDFiHvbL H499UikqgYIVPIPal4nzDWO/iAo/ktC7zDI/cH+q38eZJbKy6z1Yi+VTI4285r/M cex4DTJVfdTRYt2lRKzLhCFwdPED7CZS1pVhNh+C4DCPIw/jreBmfq1rSKnPqVqA BWm7B+WVKAOOPbIQtXHbIfjRzkjF/37I5zWvLHaLlfPaEpjIlNAZTjQgYaOCMI0+ HPHvWVklE4CY8jq44N2K4bPAvr6NpLkiqsaNvfOwmLdnmfDoytmOSbvl0bSauLkg WDasorR7Z4k2Q157Mmictv1CSSo4PvZB44l0nC2Xzd731DgUjxiAAjOcgFXUNLPp ALQBI+5xkHhnoqcFe6LWlZkRbdfWHVXVRnNKRADyXS0bwbSmVOsnvBPQFCbL+0X6 3m8Wvk/2RymALARIQ1zIl+Wpt03YZU9XXevNsHa7xFeNRY3NinxI68mIux80C2Fc rdFKgNxfhjVhi7UCAwEAAaNTMFEwHQYDVR0OBBYEFDoLyGBbOF6+Uo0/z++0JGLK T3R9MB8GA1UdIwQYMBaAFDoLyGBbOF6+Uo0/z++0JGLKT3R9MA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQELBQADggIBANFjC5Ry/i+A38YrDIGSRAf0ePZj3tjc Bh/SV75cgIJUGGS+KCX2+K7P5/9XxH/fwb5kZZyfZsT7oPiv0nqoXutljcoqfb/V Cx7SJD600JhJsPu4HJsbF4IP660gNSnSyNt4ESx8RIECW3o9iO/cgKpGkValT1cC HKSrv80l+whwnRRKHV2yvl3N9RkVXlAcFOP8zhRjQsrMNZSIz1Ux9KsJG68s52tX SSqK00bQQMMFiznF+xvN31GL8nQrtgPvbbz3EI6EjdBhXtwHSZXzUXM5IYWD/GzO a0Td7TFGQlZckq6/rxT0Qp4qzYlEx1JQi14Mv9wQoAXkew706s6oGBCd9xg+UVu/ cny2l7gal8kJ2rcOmiXY04IpiXlQQuovAntB6XHpgc2Vgh7Ao93DpBxmRfFTXI2r O0C6DMzd/oHDbSNkxONuk6V0usvGnFLSbtPDJsJegpSjzSA+CWR9es0PAqsf92Be unCoUEx+Vzz87/g+shQKkWw+Bw1VKmTGmtXK0x9r/Nawmj19YRfp/CYhdJT3xj3L 5c1Aw5EVM3Ti6ABSi3Lk8dO6XewcR8dgr2wxGE6eSL4XJ1e7GwaSt+F3KbTeAY7c KcWhobyFAXIyXmjhNYgZA+atnRuD2Cx4w/kO7fzn8C3c0aVZYuv2cXCeqFlFBbas EhGAHWy7QFZ+ -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/rsa/client.key000066400000000000000000000032541453461710000175740ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDek8hqWxT+D4HS GNK6P9/0m5bq0x6Kip5MLkHUsLNJj1FL8+JJR9OBHJnV7py/vCUBJ6iPaulqo+cf FRPPz049HWcc4QoHK1fjZgGubQP0FA/P3lbODrZ9Uvx3hXquHgC8NkD3Q3V/9bSm QaybKAHRodA7mHmszWdM2G+bpS7P6tCq2zrso8MT0d7XpDihgr92OaVETYPSwEvV gqzI7Ur2kIIegpX6WhjCfi6cq+8K6Ge0LssVBoH7dJ1sdVbRWMJcXqIodqUnDDaw j3SlgNhiHwngjCyYnpbK0SHjlIiDrlkezPds09UFQ8dQ4ME3ie61gmdV5lQgNt3Y d868AOlbAgMBAAECggEACzCHHFIiPRgwl+GiXuAbTiWh2NdZRBr8eDGksQtbFy9Y 7Kn52LgNhJ77+Rq5OhTZEBEwnXWdjTxMTmc5QHnfflZ/6NdDoy9oz2+IORtcenbB uzAmQyRBNn+ZXjUYgTANSGkBnTdWCX/APCdEEx7Jt0mjwJiTtO/fRlMBNWQdH/hY Pk//WQ3gbDa+8yqDg/3JGEXhzeTyDO+vXDdpkrGQMMsYVkPrqPnVeXokeKsemtap tSTITyU6+WDYxQSdwuBrZn9VVO3vWjfZ+KX1ADD61W2wog4+ny4p7piJgxqFrels M6M3Ppdcao89+QRpMaOL+/OsLpfW7ST01k/G4zZvbQKBgQD5xEv5mAr/miewZS10 CzeCyrxJXm4DYXMRdMQeqaiofgFh6VcH3asCu+KXMnK/6Rfg+o7QeHVG5MGP54Qs JLEOvkc1uXLEcGZ5cVAfo7suxl6ZiJ3D70MyUD6ntrXj29UvOVXv28vRRtYXR5Ks cPSDBmeyKeIT5kA3N6fAFEKKNQKBgQDkIcdMioiHxv9rKMXJpVTThRp1RpcV1H9n TggxOlPMqiB0HgexmC8sj4B3F+17qUbVfBrC+JUoiBCSEIEmJ8qQJ2h7dyhBCEbr /yD8vJ7gFU/CqRgaSiXg8DmxOBg9dlLpKK6QY8Iu7OOwnKVwPNvjqngQARO4Zj6M /gOAMoeXTwKBgQC6o9oWOGy3li1kXib6GUuw++h5dwwEkLSY7cWEGEnFJuvHi8OS SC37TAVF8NfY2skSQImp9OnGQTj3XQzio8R/fObfmaXObyPUSj2SdxpwGKImXvVt rgRru5UmZJ1FGUgUEudJ5thGmYVwPfa3z2yX4JhqhWvAbQW9fWRoX3tdpQKBgQDh n0asvJYrMvSJ1tlGhO1QBOQV+KqUPIWEdfhEN5uJXviZ3tldG1YMjCBRqKiHFPOp UARnr9JVM7yvuQMB6Xi8+TysXzzAlJ8P6FOHokS++lTYAMSFu6+at/tW+lN+9fcq AcIjq4XxQvgtQ7+bMZWHpKD5sxb92KEkcFSmBVN0oQKBgQCnnd/zoBTAjoSPNK0N wgEe6gwsOkQbl8ojpIbaaoek5Mbf07cCfH5Rwv0BbMOWjBr0OQM4HxaKOflCeEad 1C4BaPmQhzH/vVjVWOzpuJvPgiINqGVMRcckFdRhYyzQ3dGK7IvV3FbJZWJbAmZ1 /xrdnX4iuU7if5wqPARxrnaP4A== -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/rsa/client.req000066400000000000000000000016031453461710000175670ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIICXzCCAUcCAQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gY2xpZW50MIIBIjANBgkq hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3pPIalsU/g+B0hjSuj/f9JuW6tMeioqe TC5B1LCzSY9RS/PiSUfTgRyZ1e6cv7wlASeoj2rpaqPnHxUTz89OPR1nHOEKBytX 42YBrm0D9BQPz95Wzg62fVL8d4V6rh4AvDZA90N1f/W0pkGsmygB0aHQO5h5rM1n TNhvm6Uuz+rQqts67KPDE9He16Q4oYK/djmlRE2D0sBL1YKsyO1K9pCCHoKV+loY wn4unKvvCuhntC7LFQaB+3SdbHVW0VjCXF6iKHalJww2sI90pYDYYh8J4IwsmJ6W ytEh45SIg65ZHsz3bNPVBUPHUODBN4nutYJnVeZUIDbd2HfOvADpWwIDAQABoAAw DQYJKoZIhvcNAQELBQADggEBAMm+d8mxXOpcdc/MkfZ72TIjZdUY1bl34foajqG3 +tB+CbtwZ6MqfVIsrhkdyMsrNkapzvjnTDl9VEmvuUv31s1AwhsKJvaoByEyCGAj O//YY9M+x17mcMxsq3RJ9cSCpLpeumC+lvthpZrGfc5J8hMgw6gWy3eK3jRFxZcE vGv/up0y006Fqsf9Dh/rPLq7oZ01xhKbBSXY4NYmtXSPEMLzdi3IGj15S5oXW1EQ 1KGY87YROicdIjbM2thMRYgjV5HEcWBp8cWTD38CJBzudJaF3zjlVUD8q3oJeX92 ND3GmjqrCBKz8mN4bnhJzbb524l0ZyO10BVwXGXLoU4ILOs= -----END CERTIFICATE REQUEST----- rustls-v-0.21.10/test-ca/rsa/client.revoked.crl.pem000066400000000000000000000015251453461710000220010ustar00rootroot00000000000000-----BEGIN X509 CRL----- MIICTDCBtQIBATANBgkqhkiG9w0BAQsFADAsMSowKAYDVQQDDCFwb255dG93biBS U0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUXDTIzMDYyNzIwMTM0OFoXDTIzMDcwNDIw MTM0OFowIzAhAgIDFRcNMjMwNjI3MjAxMzQ4WjAMMAoGA1UdFQQDCgEBoDAwLjAf BgNVHSMEGDAWgBQrYSNFxVz2xpuhaMyTwFvsTvWcLDALBgNVHRQEBAICEAEwDQYJ KoZIhvcNAQELBQADggGBACMSTKV9hVED6ld7Hv6nunnJjodpQxFMjaRZtTMN6cK9 KLpIs/kBTZLTtny3msVtpfgXyEG3did+rZy7nEY+vn6xnnVXjpCpqiRXUqD3PFyQ rHSPmAhL13SwblKbJpK+R2c3U3UrtgsPhUALGXhB/lwCh0PGJ+UGeBDynNi41GS8 lvHfuux6K5dI3A6lNTFW1u2Pih6QN0cmX9FLuzgK3eAtsdCzNXKnquyOTcjercXL tJ+T7JGXK1jFAZg6yG7v5Qb2Y0IhxBqJsuF3cRKt9SiV+XHV70Gcn5mmhgyRQjGA WNEyIamFO/SF1ycFxy2m6EsD8XlqYW25RtR8W3VAVEjBd6u2uKPa6Lj9HLb+ower fqWuSyqYFUBdomvlfOzOoBG02vy6E6uj/xye+Th1WqNDpDoYATsJSepdWrT6cJwS NPIs2H60BQubLzRjvn+9ed2M+p4YUYJs4GcH9NwKbUrhm2rKvH7Zn5C6jb3CeCjQ J4fCVm0lITEl1BXPsC+6+w== -----END X509 CRL----- rustls-v-0.21.10/test-ca/rsa/client.rsa000066400000000000000000000032541453461710000175710ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDek8hqWxT+D4HS GNK6P9/0m5bq0x6Kip5MLkHUsLNJj1FL8+JJR9OBHJnV7py/vCUBJ6iPaulqo+cf FRPPz049HWcc4QoHK1fjZgGubQP0FA/P3lbODrZ9Uvx3hXquHgC8NkD3Q3V/9bSm QaybKAHRodA7mHmszWdM2G+bpS7P6tCq2zrso8MT0d7XpDihgr92OaVETYPSwEvV gqzI7Ur2kIIegpX6WhjCfi6cq+8K6Ge0LssVBoH7dJ1sdVbRWMJcXqIodqUnDDaw j3SlgNhiHwngjCyYnpbK0SHjlIiDrlkezPds09UFQ8dQ4ME3ie61gmdV5lQgNt3Y d868AOlbAgMBAAECggEACzCHHFIiPRgwl+GiXuAbTiWh2NdZRBr8eDGksQtbFy9Y 7Kn52LgNhJ77+Rq5OhTZEBEwnXWdjTxMTmc5QHnfflZ/6NdDoy9oz2+IORtcenbB uzAmQyRBNn+ZXjUYgTANSGkBnTdWCX/APCdEEx7Jt0mjwJiTtO/fRlMBNWQdH/hY Pk//WQ3gbDa+8yqDg/3JGEXhzeTyDO+vXDdpkrGQMMsYVkPrqPnVeXokeKsemtap tSTITyU6+WDYxQSdwuBrZn9VVO3vWjfZ+KX1ADD61W2wog4+ny4p7piJgxqFrels M6M3Ppdcao89+QRpMaOL+/OsLpfW7ST01k/G4zZvbQKBgQD5xEv5mAr/miewZS10 CzeCyrxJXm4DYXMRdMQeqaiofgFh6VcH3asCu+KXMnK/6Rfg+o7QeHVG5MGP54Qs JLEOvkc1uXLEcGZ5cVAfo7suxl6ZiJ3D70MyUD6ntrXj29UvOVXv28vRRtYXR5Ks cPSDBmeyKeIT5kA3N6fAFEKKNQKBgQDkIcdMioiHxv9rKMXJpVTThRp1RpcV1H9n TggxOlPMqiB0HgexmC8sj4B3F+17qUbVfBrC+JUoiBCSEIEmJ8qQJ2h7dyhBCEbr /yD8vJ7gFU/CqRgaSiXg8DmxOBg9dlLpKK6QY8Iu7OOwnKVwPNvjqngQARO4Zj6M /gOAMoeXTwKBgQC6o9oWOGy3li1kXib6GUuw++h5dwwEkLSY7cWEGEnFJuvHi8OS SC37TAVF8NfY2skSQImp9OnGQTj3XQzio8R/fObfmaXObyPUSj2SdxpwGKImXvVt rgRru5UmZJ1FGUgUEudJ5thGmYVwPfa3z2yX4JhqhWvAbQW9fWRoX3tdpQKBgQDh n0asvJYrMvSJ1tlGhO1QBOQV+KqUPIWEdfhEN5uJXviZ3tldG1YMjCBRqKiHFPOp UARnr9JVM7yvuQMB6Xi8+TysXzzAlJ8P6FOHokS++lTYAMSFu6+at/tW+lN+9fcq AcIjq4XxQvgtQ7+bMZWHpKD5sxb92KEkcFSmBVN0oQKBgQCnnd/zoBTAjoSPNK0N wgEe6gwsOkQbl8ojpIbaaoek5Mbf07cCfH5Rwv0BbMOWjBr0OQM4HxaKOflCeEad 1C4BaPmQhzH/vVjVWOzpuJvPgiINqGVMRcckFdRhYyzQ3dGK7IvV3FbJZWJbAmZ1 /xrdnX4iuU7if5wqPARxrnaP4A== -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/rsa/end.cert000066400000000000000000000026501453461710000172300ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEADCCAmigAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMDYyNzIwMTM0OFoX DTI4MTIxNzIwMTM0OFowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYz8pM3z09XnaAqOvsuCRluyaPGuUN I5j/72LTYXdnHXNJMjskj4DYjzuo6VtjupNMPE2o9jvVNzeuKZ56ID/mWFM77V0g IY5pjdgZg5Qi9+dlnraeQvBIhO6fvnzbWlqVUH9ag90bLj8RrHb3W4XkPOFgvR8g OGUFg4X6GiWT78KHo6QZuwFDXPqqfjWSexZnZQWCc1BVM4927uzuzbFFB/KCe7nc OrZ0RUu5eeNIZdsmoDDKEV3wWKE5qe58KtXcSF9y3AI1+/oBeobtNwT3egaevWZ3 xq0yVQJEEXsbTTuJKpp5XF/FDflTHpSdjfhXmu2Am9eNaEsQ5O+r2ElDAgMBAAGj gb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFAby13i/ B82QxYu8FxZzC9l0lnMWMEIGA1UdIwQ7MDmAFCthI0XFXPbGm6FozJPAW+xO9Zws oR6kHDAaMRgwFgYDVQQDDA9wb255dG93biBSU0EgQ0GCAXswOwYDVR0RBDQwMoIO dGVzdHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJbG9jYWxob3N0 MA0GCSqGSIb3DQEBCwUAA4IBgQBMUj//Ygtodu95Ig3UHkYXPjMLhPDAS5EN1hez MvnP+X9W8q+FURACP2FAAJ4M70tUpyORpgmcKvnpT8jS79MGo4bvqUXRQG5vlisL S01PdKoC2asPNhd0BYsrBHaXd5Jyu6pcDw1UnjjI9qWXcCtj5clileemyYPgERI/ /yXXxb+wzTsmbHVEt3+sw8wPFXXNXPdr8MZW2e/XBSdmhMyd6oGuEgvjLCO2kFgW /oTBWNQ/5xRNE5jYqkVe2+oAKTHQCLKVbWWFAwbdCGW3jUI3+zhs+wv56J9kMTXC uJwsbPd9eAJYBb759sdtH/koCDcUi7RqSbgdeIIFAGtab9D8Qwo+0BH2LVYqMOeP OxhX2DFnJepUVUzHO2gtSW4qBqD+rn4s/CvJFrnNu/djF2lFljPuGZuPXHrJZRjD btdkqd5idSriu3Rtm3jMjCMwlCxXhm3561mGPsk5oYkNK4V1yeDOGk0CkdEs9Mk9 89VKAjQ7foQbG7TnR3V0J8S3QBc= -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/rsa/end.chain000066400000000000000000000067121453461710000173600ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEwDCCAqigAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 dG93biBSU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAsMSow KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC4cHjqDpD9JPmZUzQ6VRraIaxPysbc Iu6JgHYuFZeFGi0dU4DkCjpySiqF0r6Ym3ZprweJdsX0WMHYgcn/L+0GcgXbxZKv emyeHS1XSFnhJUwNHdPzz7YUL7x5n6ucZlU89XB7yzjpm8KF8XEltM5n63TGvVm2 xstJu9YE5tIXFOo59R3GM0xaSexNhKTTaY4Q4kvLURHYhHB0WSrngJTW77u65JRp mO9y+SOtHlpuOrlf7/PD6sQk8Fb0UZHJDlNVK3ScVQ/i4eHl2+VKl77UoavI/SYG luPQwy2SllYHPnvXryTIDsO4CAhtHe1kBqgEe4gnQqkKBifnom1oexaKtOqP5msw 9+P+DqjOu08qGLUS8UB05cLXtqnMp68/6cPT3sE+1tm7iEYZwqxSLSS3DOPdBr3H bBq820O4aypi4dEPTAnWkYUj3FG7hfOyBFNtNkY2wEX1K/ylo32d2kOP6oRrBubs xYT61q1cVIvcjrA0Ko6XRDHqCPEloGlB0mUCAwEAAaN/MH0wHQYDVR0OBBYEFCth I0XFXPbGm6FozJPAW+xO9ZwsMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAWgBQ6C8hg WzhevlKNP8/vtCRiyk90fTANBgkqhkiG9w0BAQsFAAOCAgEAnjpQF9FTwFQD75aA 1xL15XR5l6DrjDzZfq13gr/StaCQJ44OtmJvjzdgfPI5sRmpiUgU7bK4rOhKLK6C 3NUpq+Zg+5D2TzDHwyBNb0uViTgr75/P+HHBJUHwdvKbenDkn1QfPlx8nOtyyyFD Jw3HEVGIAzGX3rWUkyZhwLQ1JUC6tmckNGg/9OVxKnr0f1fxct/F1Hc3Hd806Wqc /D2QdDDTCtA9qZt53ED+SaLI1mzfvm67pyRZ43V5BvkAj1xiumGFHqLheK7hdC9V WXHgPQobGJgyhOCAnQru1iKKnld+VIDfkZHu6fchsJg9ty/526QfyKRGfT7ak3Ng 0VSRsBj9zRPBiKrK4SFcmmWVIbj+lyN0xJWJFJ0ZrxFnLE/fjzF6smyTZxRYC15L NCq+xy4yAvFRvcLOCjhmWkDJeAa/Y2cg50xrHpK/Y6FtPT2Bg34N1/fY9FP1r6AO QMSrFGWpRl8Nsm6EfmJMJR1vfX52H7u0rla6Ay86yL3JMAfW7zFMYrRXx4bxq9hF Rv4z5nj1RVR3+iNeOIWNx7YtyxvYvd+zPXY2LlkAr9QAjScvsiCKWi/5z9eC8aSX VJcQoaKWoX2/SwjRuTSsI9P7rHeGNavUQCVL97slkdx//Xvw6ruP3bOQ+XzYvPAO /DUNNf2nkPD7DKj8pFV8Ia8p910= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCAv2gAwIBAgIUGIGV3FDZXdNIPCe2s9FHmjTqeLYwDQYJKoZIhvcNAQEL BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTIzMDYyNzIwMTM0N1oX DTMzMDYyNDIwMTM0N1owGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9Dkdby/tuMYvV62TbVmz7CWASGq/ f/m7zZPlS8SSoMdqow1pr8mcWD0od39rIYFlGGoLHoBtqP3d6cV0KRpcJqDF4oDr HrMoZikpQAO3s50NvXWhkESxGzCUJD4XtvZkmK+gBdob/qrOn1uqYdkD8YM6rnqw R9VOz/GLWmguWMhd66mMAPvpfLD3wPtJmIzMQyrGRuLDenm9cigNNjYtCDFiHvbL H499UikqgYIVPIPal4nzDWO/iAo/ktC7zDI/cH+q38eZJbKy6z1Yi+VTI4285r/M cex4DTJVfdTRYt2lRKzLhCFwdPED7CZS1pVhNh+C4DCPIw/jreBmfq1rSKnPqVqA BWm7B+WVKAOOPbIQtXHbIfjRzkjF/37I5zWvLHaLlfPaEpjIlNAZTjQgYaOCMI0+ HPHvWVklE4CY8jq44N2K4bPAvr6NpLkiqsaNvfOwmLdnmfDoytmOSbvl0bSauLkg WDasorR7Z4k2Q157Mmictv1CSSo4PvZB44l0nC2Xzd731DgUjxiAAjOcgFXUNLPp ALQBI+5xkHhnoqcFe6LWlZkRbdfWHVXVRnNKRADyXS0bwbSmVOsnvBPQFCbL+0X6 3m8Wvk/2RymALARIQ1zIl+Wpt03YZU9XXevNsHa7xFeNRY3NinxI68mIux80C2Fc rdFKgNxfhjVhi7UCAwEAAaNTMFEwHQYDVR0OBBYEFDoLyGBbOF6+Uo0/z++0JGLK T3R9MB8GA1UdIwQYMBaAFDoLyGBbOF6+Uo0/z++0JGLKT3R9MA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQELBQADggIBANFjC5Ry/i+A38YrDIGSRAf0ePZj3tjc Bh/SV75cgIJUGGS+KCX2+K7P5/9XxH/fwb5kZZyfZsT7oPiv0nqoXutljcoqfb/V Cx7SJD600JhJsPu4HJsbF4IP660gNSnSyNt4ESx8RIECW3o9iO/cgKpGkValT1cC HKSrv80l+whwnRRKHV2yvl3N9RkVXlAcFOP8zhRjQsrMNZSIz1Ux9KsJG68s52tX SSqK00bQQMMFiznF+xvN31GL8nQrtgPvbbz3EI6EjdBhXtwHSZXzUXM5IYWD/GzO a0Td7TFGQlZckq6/rxT0Qp4qzYlEx1JQi14Mv9wQoAXkew706s6oGBCd9xg+UVu/ cny2l7gal8kJ2rcOmiXY04IpiXlQQuovAntB6XHpgc2Vgh7Ao93DpBxmRfFTXI2r O0C6DMzd/oHDbSNkxONuk6V0usvGnFLSbtPDJsJegpSjzSA+CWR9es0PAqsf92Be unCoUEx+Vzz87/g+shQKkWw+Bw1VKmTGmtXK0x9r/Nawmj19YRfp/CYhdJT3xj3L 5c1Aw5EVM3Ti6ABSi3Lk8dO6XewcR8dgr2wxGE6eSL4XJ1e7GwaSt+F3KbTeAY7c KcWhobyFAXIyXmjhNYgZA+atnRuD2Cx4w/kO7fzn8C3c0aVZYuv2cXCeqFlFBbas EhGAHWy7QFZ+ -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/rsa/end.fullchain000066400000000000000000000115621453461710000202420ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEADCCAmigAwIBAgICAcgwDQYJKoZIhvcNAQELBQAwLDEqMCgGA1UEAwwhcG9u eXRvd24gUlNBIGxldmVsIDIgaW50ZXJtZWRpYXRlMB4XDTIzMDYyNzIwMTM0OFoX DTI4MTIxNzIwMTM0OFowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYz8pM3z09XnaAqOvsuCRluyaPGuUN I5j/72LTYXdnHXNJMjskj4DYjzuo6VtjupNMPE2o9jvVNzeuKZ56ID/mWFM77V0g IY5pjdgZg5Qi9+dlnraeQvBIhO6fvnzbWlqVUH9ag90bLj8RrHb3W4XkPOFgvR8g OGUFg4X6GiWT78KHo6QZuwFDXPqqfjWSexZnZQWCc1BVM4927uzuzbFFB/KCe7nc OrZ0RUu5eeNIZdsmoDDKEV3wWKE5qe58KtXcSF9y3AI1+/oBeobtNwT3egaevWZ3 xq0yVQJEEXsbTTuJKpp5XF/FDflTHpSdjfhXmu2Am9eNaEsQ5O+r2ElDAgMBAAGj gb4wgbswDAYDVR0TAQH/BAIwADALBgNVHQ8EBAMCBsAwHQYDVR0OBBYEFAby13i/ B82QxYu8FxZzC9l0lnMWMEIGA1UdIwQ7MDmAFCthI0XFXPbGm6FozJPAW+xO9Zws oR6kHDAaMRgwFgYDVQQDDA9wb255dG93biBSU0EgQ0GCAXswOwYDVR0RBDQwMoIO dGVzdHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJbG9jYWxob3N0 MA0GCSqGSIb3DQEBCwUAA4IBgQBMUj//Ygtodu95Ig3UHkYXPjMLhPDAS5EN1hez MvnP+X9W8q+FURACP2FAAJ4M70tUpyORpgmcKvnpT8jS79MGo4bvqUXRQG5vlisL S01PdKoC2asPNhd0BYsrBHaXd5Jyu6pcDw1UnjjI9qWXcCtj5clileemyYPgERI/ /yXXxb+wzTsmbHVEt3+sw8wPFXXNXPdr8MZW2e/XBSdmhMyd6oGuEgvjLCO2kFgW /oTBWNQ/5xRNE5jYqkVe2+oAKTHQCLKVbWWFAwbdCGW3jUI3+zhs+wv56J9kMTXC uJwsbPd9eAJYBb759sdtH/koCDcUi7RqSbgdeIIFAGtab9D8Qwo+0BH2LVYqMOeP OxhX2DFnJepUVUzHO2gtSW4qBqD+rn4s/CvJFrnNu/djF2lFljPuGZuPXHrJZRjD btdkqd5idSriu3Rtm3jMjCMwlCxXhm3561mGPsk5oYkNK4V1yeDOGk0CkdEs9Mk9 89VKAjQ7foQbG7TnR3V0J8S3QBc= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIEwDCCAqigAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 dG93biBSU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAsMSow KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC4cHjqDpD9JPmZUzQ6VRraIaxPysbc Iu6JgHYuFZeFGi0dU4DkCjpySiqF0r6Ym3ZprweJdsX0WMHYgcn/L+0GcgXbxZKv emyeHS1XSFnhJUwNHdPzz7YUL7x5n6ucZlU89XB7yzjpm8KF8XEltM5n63TGvVm2 xstJu9YE5tIXFOo59R3GM0xaSexNhKTTaY4Q4kvLURHYhHB0WSrngJTW77u65JRp mO9y+SOtHlpuOrlf7/PD6sQk8Fb0UZHJDlNVK3ScVQ/i4eHl2+VKl77UoavI/SYG luPQwy2SllYHPnvXryTIDsO4CAhtHe1kBqgEe4gnQqkKBifnom1oexaKtOqP5msw 9+P+DqjOu08qGLUS8UB05cLXtqnMp68/6cPT3sE+1tm7iEYZwqxSLSS3DOPdBr3H bBq820O4aypi4dEPTAnWkYUj3FG7hfOyBFNtNkY2wEX1K/ylo32d2kOP6oRrBubs xYT61q1cVIvcjrA0Ko6XRDHqCPEloGlB0mUCAwEAAaN/MH0wHQYDVR0OBBYEFCth I0XFXPbGm6FozJPAW+xO9ZwsMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAWgBQ6C8hg WzhevlKNP8/vtCRiyk90fTANBgkqhkiG9w0BAQsFAAOCAgEAnjpQF9FTwFQD75aA 1xL15XR5l6DrjDzZfq13gr/StaCQJ44OtmJvjzdgfPI5sRmpiUgU7bK4rOhKLK6C 3NUpq+Zg+5D2TzDHwyBNb0uViTgr75/P+HHBJUHwdvKbenDkn1QfPlx8nOtyyyFD Jw3HEVGIAzGX3rWUkyZhwLQ1JUC6tmckNGg/9OVxKnr0f1fxct/F1Hc3Hd806Wqc /D2QdDDTCtA9qZt53ED+SaLI1mzfvm67pyRZ43V5BvkAj1xiumGFHqLheK7hdC9V WXHgPQobGJgyhOCAnQru1iKKnld+VIDfkZHu6fchsJg9ty/526QfyKRGfT7ak3Ng 0VSRsBj9zRPBiKrK4SFcmmWVIbj+lyN0xJWJFJ0ZrxFnLE/fjzF6smyTZxRYC15L NCq+xy4yAvFRvcLOCjhmWkDJeAa/Y2cg50xrHpK/Y6FtPT2Bg34N1/fY9FP1r6AO QMSrFGWpRl8Nsm6EfmJMJR1vfX52H7u0rla6Ay86yL3JMAfW7zFMYrRXx4bxq9hF Rv4z5nj1RVR3+iNeOIWNx7YtyxvYvd+zPXY2LlkAr9QAjScvsiCKWi/5z9eC8aSX VJcQoaKWoX2/SwjRuTSsI9P7rHeGNavUQCVL97slkdx//Xvw6ruP3bOQ+XzYvPAO /DUNNf2nkPD7DKj8pFV8Ia8p910= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIFFTCCAv2gAwIBAgIUGIGV3FDZXdNIPCe2s9FHmjTqeLYwDQYJKoZIhvcNAQEL BQAwGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMB4XDTIzMDYyNzIwMTM0N1oX DTMzMDYyNDIwMTM0N1owGjEYMBYGA1UEAwwPcG9ueXRvd24gUlNBIENBMIICIjAN BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9Dkdby/tuMYvV62TbVmz7CWASGq/ f/m7zZPlS8SSoMdqow1pr8mcWD0od39rIYFlGGoLHoBtqP3d6cV0KRpcJqDF4oDr HrMoZikpQAO3s50NvXWhkESxGzCUJD4XtvZkmK+gBdob/qrOn1uqYdkD8YM6rnqw R9VOz/GLWmguWMhd66mMAPvpfLD3wPtJmIzMQyrGRuLDenm9cigNNjYtCDFiHvbL H499UikqgYIVPIPal4nzDWO/iAo/ktC7zDI/cH+q38eZJbKy6z1Yi+VTI4285r/M cex4DTJVfdTRYt2lRKzLhCFwdPED7CZS1pVhNh+C4DCPIw/jreBmfq1rSKnPqVqA BWm7B+WVKAOOPbIQtXHbIfjRzkjF/37I5zWvLHaLlfPaEpjIlNAZTjQgYaOCMI0+ HPHvWVklE4CY8jq44N2K4bPAvr6NpLkiqsaNvfOwmLdnmfDoytmOSbvl0bSauLkg WDasorR7Z4k2Q157Mmictv1CSSo4PvZB44l0nC2Xzd731DgUjxiAAjOcgFXUNLPp ALQBI+5xkHhnoqcFe6LWlZkRbdfWHVXVRnNKRADyXS0bwbSmVOsnvBPQFCbL+0X6 3m8Wvk/2RymALARIQ1zIl+Wpt03YZU9XXevNsHa7xFeNRY3NinxI68mIux80C2Fc rdFKgNxfhjVhi7UCAwEAAaNTMFEwHQYDVR0OBBYEFDoLyGBbOF6+Uo0/z++0JGLK T3R9MB8GA1UdIwQYMBaAFDoLyGBbOF6+Uo0/z++0JGLKT3R9MA8GA1UdEwEB/wQF MAMBAf8wDQYJKoZIhvcNAQELBQADggIBANFjC5Ry/i+A38YrDIGSRAf0ePZj3tjc Bh/SV75cgIJUGGS+KCX2+K7P5/9XxH/fwb5kZZyfZsT7oPiv0nqoXutljcoqfb/V Cx7SJD600JhJsPu4HJsbF4IP660gNSnSyNt4ESx8RIECW3o9iO/cgKpGkValT1cC HKSrv80l+whwnRRKHV2yvl3N9RkVXlAcFOP8zhRjQsrMNZSIz1Ux9KsJG68s52tX SSqK00bQQMMFiznF+xvN31GL8nQrtgPvbbz3EI6EjdBhXtwHSZXzUXM5IYWD/GzO a0Td7TFGQlZckq6/rxT0Qp4qzYlEx1JQi14Mv9wQoAXkew706s6oGBCd9xg+UVu/ cny2l7gal8kJ2rcOmiXY04IpiXlQQuovAntB6XHpgc2Vgh7Ao93DpBxmRfFTXI2r O0C6DMzd/oHDbSNkxONuk6V0usvGnFLSbtPDJsJegpSjzSA+CWR9es0PAqsf92Be unCoUEx+Vzz87/g+shQKkWw+Bw1VKmTGmtXK0x9r/Nawmj19YRfp/CYhdJT3xj3L 5c1Aw5EVM3Ti6ABSi3Lk8dO6XewcR8dgr2wxGE6eSL4XJ1e7GwaSt+F3KbTeAY7c KcWhobyFAXIyXmjhNYgZA+atnRuD2Cx4w/kO7fzn8C3c0aVZYuv2cXCeqFlFBbas EhGAHWy7QFZ+ -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/rsa/end.key000066400000000000000000000032501453461710000170600ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCYz8pM3z09XnaA qOvsuCRluyaPGuUNI5j/72LTYXdnHXNJMjskj4DYjzuo6VtjupNMPE2o9jvVNzeu KZ56ID/mWFM77V0gIY5pjdgZg5Qi9+dlnraeQvBIhO6fvnzbWlqVUH9ag90bLj8R rHb3W4XkPOFgvR8gOGUFg4X6GiWT78KHo6QZuwFDXPqqfjWSexZnZQWCc1BVM492 7uzuzbFFB/KCe7ncOrZ0RUu5eeNIZdsmoDDKEV3wWKE5qe58KtXcSF9y3AI1+/oB eobtNwT3egaevWZ3xq0yVQJEEXsbTTuJKpp5XF/FDflTHpSdjfhXmu2Am9eNaEsQ 5O+r2ElDAgMBAAECggEAF0R7BlBu19jPIhEBIfakiB7tJJi7lqVnHFUxZC6GNUZd MaB7M+UWgSLyD7/py+9ykobowO4ujG0PcS6MybCpD3mUbDQHXCdFMsTydL69qsNk 0ZV53fLNo7p7Rl8v+LWzGY17uWcJns61s2BiGZDZ0WJZuNajFiSwG8emeen1ndGF a38B0F3f1Hv6ByXGK4B9QRnZMoN1oTLovUKh1ryNI8cGSRgQx6qulepGU0Xkmti1 3cqXVb4zye9jIimVMQq+eW6TXQ13F1DcoVR174eojnxDrUFc/Ar+PIwx6a8Jd/+W S7E1zoaXeooVpqG2V1HHuagEAc1UnX5evqAkWVVcOQKBgQDUtVW5P0NWxyYg8FjZ 9OkGGB6t2EBl1D3p6EkHG2fWBmPV4+TJomN4W3ppGe0H3CqKe8QEEeMWS1oSGADO k38MZV0zFN19nxhdBSZgcZ0sAY7qMaT4Tq5SQ6VUVupxoASwx/H1ZBVLeD+hFz37 fTyxWzSz1/XLpeOLggxObgeCCQKBgQC36a58LOgwcVmwUEndRhkfbSElBKtGFv5T 98l004MJfsf5kpq0SYm1c3RB4F5nkxtjG8l/1/lbxnxezUG4XWq3/DMz+GqHA9x6 et/xPeiUDcKXFmDrP8CzOqnIwV28lPdWrqSkFLCxlDNJAb1Zju+Ly/MDCFoU+2Ev b79ftDNT6wKBgDk4Zs0kpZrMjAdEYMKRTbZj+qzNhdVe2SD5advNlYtPwL+jRMKx Oo0AHtfzL35zzcXfMYXewfYXYy2G44Cu0PimtAGv1T2b9NPhNMexCJTz/lwl6rkZ gW+D3w/nKb5TS6+6ue5HdCsPOB6/v97Ne+xCGtVefTLBd4rp+yGGG+LxAoGARLmU NF7rnT6eT16RW5iYRsAXBKhMAHMTMvmDVJ69dszjmYWJPhnE1gOAzCU14ep873ow wA9K5Vq0mxCEoIp4GKyrzZ3k4PM2bqaADLwfr0O9FYyNRxuZvOANFjH7/z6Ddubo K1B3/sPsrjlyModRSKI7+0QhtXmChaFymCbUj2UCgYBOt21zl/U2bXgoOT3PMRbO BYk2LUU8qco/o6VH5/ibvcTliuR+BGCDKOjD3pTaQweT4hNQDDFT5HntMtRFNa+M txWWbrV8/TlItkgf1AT9vv0NQJBfLjCA6hsYXDHyi6RJ9Ifbs3blBCx0g6OrLBbB ABrlUhuSHvRX3d2WY59flg== -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/rsa/end.req000066400000000000000000000016031453461710000170570ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIICXjCCAUYCAQAwGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20wggEiMA0GCSqG SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYz8pM3z09XnaAqOvsuCRluyaPGuUNI5j/ 72LTYXdnHXNJMjskj4DYjzuo6VtjupNMPE2o9jvVNzeuKZ56ID/mWFM77V0gIY5p jdgZg5Qi9+dlnraeQvBIhO6fvnzbWlqVUH9ag90bLj8RrHb3W4XkPOFgvR8gOGUF g4X6GiWT78KHo6QZuwFDXPqqfjWSexZnZQWCc1BVM4927uzuzbFFB/KCe7ncOrZ0 RUu5eeNIZdsmoDDKEV3wWKE5qe58KtXcSF9y3AI1+/oBeobtNwT3egaevWZ3xq0y VQJEEXsbTTuJKpp5XF/FDflTHpSdjfhXmu2Am9eNaEsQ5O+r2ElDAgMBAAGgADAN BgkqhkiG9w0BAQsFAAOCAQEAZO6NVv+/0DTSolXcL6UpCCA44rVu+Gti3MxaWAAm SuS9O762zaG+9TfOJifXTNIyohsF04edpW1Cxhje2u1TbrO2IKznaBwrvXIFhfNN SVnKhX3SltQKRDBQgkmS6L6bnzN2HipWtkqW1PTOMo+9Gw2RgR+1uJkemftjZ5tp +C7O6HXGucbGv7YpYb79l08cE9UxXI8AH/XlQNJeJ0dVM/ni2P+iS3vUurzgMhfG IuFQA8Fp+/0JXTD7/e/K9w8+wufV41FDROFt/63pf9XehO/pd5gsPUFdN1irbYzD izKAJW7zHwHHE3lEDx9suBd5GFtMq67SxDw7ARTo0rF28A== -----END CERTIFICATE REQUEST----- rustls-v-0.21.10/test-ca/rsa/end.rsa000066400000000000000000000032501453461710000170550ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCYz8pM3z09XnaA qOvsuCRluyaPGuUNI5j/72LTYXdnHXNJMjskj4DYjzuo6VtjupNMPE2o9jvVNzeu KZ56ID/mWFM77V0gIY5pjdgZg5Qi9+dlnraeQvBIhO6fvnzbWlqVUH9ag90bLj8R rHb3W4XkPOFgvR8gOGUFg4X6GiWT78KHo6QZuwFDXPqqfjWSexZnZQWCc1BVM492 7uzuzbFFB/KCe7ncOrZ0RUu5eeNIZdsmoDDKEV3wWKE5qe58KtXcSF9y3AI1+/oB eobtNwT3egaevWZ3xq0yVQJEEXsbTTuJKpp5XF/FDflTHpSdjfhXmu2Am9eNaEsQ 5O+r2ElDAgMBAAECggEAF0R7BlBu19jPIhEBIfakiB7tJJi7lqVnHFUxZC6GNUZd MaB7M+UWgSLyD7/py+9ykobowO4ujG0PcS6MybCpD3mUbDQHXCdFMsTydL69qsNk 0ZV53fLNo7p7Rl8v+LWzGY17uWcJns61s2BiGZDZ0WJZuNajFiSwG8emeen1ndGF a38B0F3f1Hv6ByXGK4B9QRnZMoN1oTLovUKh1ryNI8cGSRgQx6qulepGU0Xkmti1 3cqXVb4zye9jIimVMQq+eW6TXQ13F1DcoVR174eojnxDrUFc/Ar+PIwx6a8Jd/+W S7E1zoaXeooVpqG2V1HHuagEAc1UnX5evqAkWVVcOQKBgQDUtVW5P0NWxyYg8FjZ 9OkGGB6t2EBl1D3p6EkHG2fWBmPV4+TJomN4W3ppGe0H3CqKe8QEEeMWS1oSGADO k38MZV0zFN19nxhdBSZgcZ0sAY7qMaT4Tq5SQ6VUVupxoASwx/H1ZBVLeD+hFz37 fTyxWzSz1/XLpeOLggxObgeCCQKBgQC36a58LOgwcVmwUEndRhkfbSElBKtGFv5T 98l004MJfsf5kpq0SYm1c3RB4F5nkxtjG8l/1/lbxnxezUG4XWq3/DMz+GqHA9x6 et/xPeiUDcKXFmDrP8CzOqnIwV28lPdWrqSkFLCxlDNJAb1Zju+Ly/MDCFoU+2Ev b79ftDNT6wKBgDk4Zs0kpZrMjAdEYMKRTbZj+qzNhdVe2SD5advNlYtPwL+jRMKx Oo0AHtfzL35zzcXfMYXewfYXYy2G44Cu0PimtAGv1T2b9NPhNMexCJTz/lwl6rkZ gW+D3w/nKb5TS6+6ue5HdCsPOB6/v97Ne+xCGtVefTLBd4rp+yGGG+LxAoGARLmU NF7rnT6eT16RW5iYRsAXBKhMAHMTMvmDVJ69dszjmYWJPhnE1gOAzCU14ep873ow wA9K5Vq0mxCEoIp4GKyrzZ3k4PM2bqaADLwfr0O9FYyNRxuZvOANFjH7/z6Ddubo K1B3/sPsrjlyModRSKI7+0QhtXmChaFymCbUj2UCgYBOt21zl/U2bXgoOT3PMRbO BYk2LUU8qco/o6VH5/ibvcTliuR+BGCDKOjD3pTaQweT4hNQDDFT5HntMtRFNa+M txWWbrV8/TlItkgf1AT9vv0NQJBfLjCA6hsYXDHyi6RJ9Ifbs3blBCx0g6OrLBbB ABrlUhuSHvRX3d2WY59flg== -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/rsa/inter.cert000066400000000000000000000032541453461710000176040ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEwDCCAqigAwIBAgIBezANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9wb255 dG93biBSU0EgQ0EwHhcNMjMwNjI3MjAxMzQ4WhcNMzMwNjI0MjAxMzQ4WjAsMSow KAYDVQQDDCFwb255dG93biBSU0EgbGV2ZWwgMiBpbnRlcm1lZGlhdGUwggGiMA0G CSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQC4cHjqDpD9JPmZUzQ6VRraIaxPysbc Iu6JgHYuFZeFGi0dU4DkCjpySiqF0r6Ym3ZprweJdsX0WMHYgcn/L+0GcgXbxZKv emyeHS1XSFnhJUwNHdPzz7YUL7x5n6ucZlU89XB7yzjpm8KF8XEltM5n63TGvVm2 xstJu9YE5tIXFOo59R3GM0xaSexNhKTTaY4Q4kvLURHYhHB0WSrngJTW77u65JRp mO9y+SOtHlpuOrlf7/PD6sQk8Fb0UZHJDlNVK3ScVQ/i4eHl2+VKl77UoavI/SYG luPQwy2SllYHPnvXryTIDsO4CAhtHe1kBqgEe4gnQqkKBifnom1oexaKtOqP5msw 9+P+DqjOu08qGLUS8UB05cLXtqnMp68/6cPT3sE+1tm7iEYZwqxSLSS3DOPdBr3H bBq820O4aypi4dEPTAnWkYUj3FG7hfOyBFNtNkY2wEX1K/ylo32d2kOP6oRrBubs xYT61q1cVIvcjrA0Ko6XRDHqCPEloGlB0mUCAwEAAaN/MH0wHQYDVR0OBBYEFCth I0XFXPbGm6FozJPAW+xO9ZwsMCAGA1UdJQEB/wQWMBQGCCsGAQUFBwMBBggrBgEF BQcDAjAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB/jAfBgNVHSMEGDAWgBQ6C8hg WzhevlKNP8/vtCRiyk90fTANBgkqhkiG9w0BAQsFAAOCAgEAnjpQF9FTwFQD75aA 1xL15XR5l6DrjDzZfq13gr/StaCQJ44OtmJvjzdgfPI5sRmpiUgU7bK4rOhKLK6C 3NUpq+Zg+5D2TzDHwyBNb0uViTgr75/P+HHBJUHwdvKbenDkn1QfPlx8nOtyyyFD Jw3HEVGIAzGX3rWUkyZhwLQ1JUC6tmckNGg/9OVxKnr0f1fxct/F1Hc3Hd806Wqc /D2QdDDTCtA9qZt53ED+SaLI1mzfvm67pyRZ43V5BvkAj1xiumGFHqLheK7hdC9V WXHgPQobGJgyhOCAnQru1iKKnld+VIDfkZHu6fchsJg9ty/526QfyKRGfT7ak3Ng 0VSRsBj9zRPBiKrK4SFcmmWVIbj+lyN0xJWJFJ0ZrxFnLE/fjzF6smyTZxRYC15L NCq+xy4yAvFRvcLOCjhmWkDJeAa/Y2cg50xrHpK/Y6FtPT2Bg34N1/fY9FP1r6AO QMSrFGWpRl8Nsm6EfmJMJR1vfX52H7u0rla6Ay86yL3JMAfW7zFMYrRXx4bxq9hF Rv4z5nj1RVR3+iNeOIWNx7YtyxvYvd+zPXY2LlkAr9QAjScvsiCKWi/5z9eC8aSX VJcQoaKWoX2/SwjRuTSsI9P7rHeGNavUQCVL97slkdx//Xvw6ruP3bOQ+XzYvPAO /DUNNf2nkPD7DKj8pFV8Ia8p910= -----END CERTIFICATE----- rustls-v-0.21.10/test-ca/rsa/inter.key000066400000000000000000000046641453461710000174450ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQC4cHjqDpD9JPmZ UzQ6VRraIaxPysbcIu6JgHYuFZeFGi0dU4DkCjpySiqF0r6Ym3ZprweJdsX0WMHY gcn/L+0GcgXbxZKvemyeHS1XSFnhJUwNHdPzz7YUL7x5n6ucZlU89XB7yzjpm8KF 8XEltM5n63TGvVm2xstJu9YE5tIXFOo59R3GM0xaSexNhKTTaY4Q4kvLURHYhHB0 WSrngJTW77u65JRpmO9y+SOtHlpuOrlf7/PD6sQk8Fb0UZHJDlNVK3ScVQ/i4eHl 2+VKl77UoavI/SYGluPQwy2SllYHPnvXryTIDsO4CAhtHe1kBqgEe4gnQqkKBifn om1oexaKtOqP5msw9+P+DqjOu08qGLUS8UB05cLXtqnMp68/6cPT3sE+1tm7iEYZ wqxSLSS3DOPdBr3HbBq820O4aypi4dEPTAnWkYUj3FG7hfOyBFNtNkY2wEX1K/yl o32d2kOP6oRrBubsxYT61q1cVIvcjrA0Ko6XRDHqCPEloGlB0mUCAwEAAQKCAYBI Hxr5E2cYxgugLAwBP2Q3pfE2ZmmqjTJPrF8KGEFet+SqUgvVoDZImL3WBJmpHSmJ m/rLgxlXOhna6q2tTvVVjuLBlJmOasXsciZXuiADTU1W17IY5cEiVaRSvuAhUVbF dohcsBP6LYE8VTRUdUY9FrJcQJDDSysVExFWa1f91Jzeuv3AkjCqIbv4eATn8p+t 9H+E6pea3fcHWBLR4dLR1X7ITzfFrxr7D3cm6/aaofX5EOB2XOgENcMa2Ia0YxgC IJe7OT9gs6N74HZshk1B9j2eVxQfQFRaIMDr8LSLOXsd4puvhGmCmcp4lvUvwQn8 qPt3ee/swFXucHKbR7N8iWQikD0RS37hhWM+fI571r8REnOwr9ZdbeerIrBogNFQ l5LxPJg23ut4fziY78erqLQLEhPdp4Da2KuooTY0OK1NGnHHlwNJAa88hJp7GkLN e53DafMWpCZr72Ie3IESVzvv+yJi2hcSdo9anRYE00kqTVmc54wJ1ofDEmmTi+UC gcEAxBOvZu9EVI0JlNsbdQQUBz30ZJMz3NllaSyiKPzFQ0PsK/ABhauRl5Z5qMvh GwwPWXYPH8JuYlek/PqgtXDxeyjkVTqAmihMoYpAVuISOwlOLFChmyJnzWr70I2d pEpLr9E/I6GuFcL69o4WXp0xHJ8GuNxIn54YPatJGnFwmX1wGTCF+ytdWQDPIXu5 YH3jvb9E2mWKZINciElQOt9iyconvmpWU6ALjraXnEq6yhae9DZU2m0opuHrNtej xN03AoHBAPDOTyo4OijrEI/beYoCX2Oi1YEyT1yIOVKrSD8UFNjRCBcYnh5Vo8v1 rXh/BdWyvqaoApRjZUDRTEGrfsjGDIYz+wBhGVWfv/0GdpgyS11Z/oXVlkc+C7OD sxbHtdATSfm1YsVuy5L/x0W9+EvOMylssrLDpY6fYkMnzXOkNSRq06SBjwFC3Sky wXag/7F3btvdJScX7Zith5b0uUbSzQvZjczgeDQ/f2P6RET0KceLhFexndwJFX7d IAd5+mH7QwKBwQC5CLKf+u+KssX1+YdBuCWGaAr31oo8wdMXm400DMXDIpf/JrDp Ce2NFe2dQzkdIxZhIC5JlFxC5d7G9WUvlHPt+7ruSxUNZTZbw3HQC+uUVsW0wCqh kahPi8QzHVFEtvAR7O8emvcDhkr63T9y7fhowBHB5e+K4dCScc+86oyN7Hga7VWi n1uqID9Xo8BetK50Y8mAKA6fp+9slXLm++Pn9aPn58WriP8fIGSWk1cOWqaKY7NT pWuVgOFNkdX0c6UCgcEAv6OwpOzyfDX2jEYiR47z0xt3xsX/Gqje1ceyS2Dz5kkU oyzYSVPmcx8l2stcHWGPEJqM0wL3RcpLYcfVsnrK5NLhYr/jpZzo8bj/EMiV6ckB IgmE+1WJgmfBUtPFAb8YFD4iSPWP1YDxWbOBsvJ7DPCQlmvVideWH9PBUdLQ6BaM MFNbN6m60FqwVHR0iQt/kkJAmwgT8nnHen9wI8kHnfKZQv8xKoOOIka9phKaXU/P FusnskEYdkoMf2a3uNp5AoHAGCu4pLMqKs3vwFOfXkdtiMs2KnK5dOHbHgomwrn+ c401dixykuPcooSQu2y6xCBNx7iSo7QYtQrRVNN3ZyAdj/zT03JY6dXN7gHNeB8c VBA+Ab32rmsrTGRwg9V/zHFbfyYIx/wvYRF0SZyIuhVqTHohl0mQiDkWtipXtSwW o+ynJ99r6Nf14bcQSauvF3ZijLSYgcNhYG+Kz1tEcYnBUUR+N75dyYju856VTM00 wxQL0Be6/MFzazp/MydSgPsk -----END PRIVATE KEY----- rustls-v-0.21.10/test-ca/rsa/inter.req000066400000000000000000000023651453461710000174400ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIIDcTCCAdkCAQAwLDEqMCgGA1UEAwwhcG9ueXRvd24gUlNBIGxldmVsIDIgaW50 ZXJtZWRpYXRlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAuHB46g6Q /ST5mVM0OlUa2iGsT8rG3CLuiYB2LhWXhRotHVOA5Ao6ckoqhdK+mJt2aa8HiXbF 9FjB2IHJ/y/tBnIF28WSr3psnh0tV0hZ4SVMDR3T88+2FC+8eZ+rnGZVPPVwe8s4 6ZvChfFxJbTOZ+t0xr1ZtsbLSbvWBObSFxTqOfUdxjNMWknsTYSk02mOEOJLy1ER 2IRwdFkq54CU1u+7uuSUaZjvcvkjrR5abjq5X+/zw+rEJPBW9FGRyQ5TVSt0nFUP 4uHh5dvlSpe+1KGryP0mBpbj0MMtkpZWBz57168kyA7DuAgIbR3tZAaoBHuIJ0Kp CgYn56JtaHsWirTqj+ZrMPfj/g6ozrtPKhi1EvFAdOXC17apzKevP+nD097BPtbZ u4hGGcKsUi0ktwzj3Qa9x2wavNtDuGsqYuHRD0wJ1pGFI9xRu4XzsgRTbTZGNsBF 9Sv8paN9ndpDj+qEawbm7MWE+tatXFSL3I6wNCqOl0Qx6gjxJaBpQdJlAgMBAAGg ADANBgkqhkiG9w0BAQsFAAOCAYEAbMl/5VVUiyqDPN9iiMdKIn2fhyKOGG1psZm7 KXKz2LksxjKL/4GPkR5pUOyncBYgszwV3+RcOcKaXASShlGBogV7aJG09jbJWzQH o4AlvQAzRfU5qx5oZm3IrvJi8YPpkWWL5tn/uvf8+Ia4hClzURi/MRdKd+XYX5m3 NHzt39oObHxVVSzvJH6kA7I0ImbvYKXdcGBKcu9l3tNSobOKX+CwndA/ZdJ5E4RH y6DXHkHiU1cGdpC7w6v/TQQYsKqGsqiAB1WH1eAPfTriWSdeyr9PyMniZYKFBwXT TI5dKkpKeh0U/gKPmvCokzRxobaVkRN/witTC9rqfiLDfp3aeOM6Hz561mE6hhZn ByQ8H48oDRyWW6N4IbHHzxCjYS6WzCQbtKz63X/W+ZwUUbB6e7omnpSWJrYC3oo7 wjWYrBoUpWcdIkyf2euBBtLF4O3fcmTLreeFJmyJD656EBddcLsDfqASxW9HKIVn 1rcIiIoEoTyVcTQu0by0qwdu8OFI -----END CERTIFICATE REQUEST-----