summaryrefslogtreecommitdiffstats
path: root/vendor/native-tls
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:24 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:24 +0000
commit023939b627b7dc93b01471f7d41fb8553ddb4ffa (patch)
tree60fc59477c605c72b0a1051409062ddecc43f877 /vendor/native-tls
parentAdding debian version 1.72.1+dfsg1-1. (diff)
downloadrustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.tar.xz
rustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/native-tls')
-rw-r--r--vendor/native-tls/.cargo-checksum.json1
-rw-r--r--vendor/native-tls/CHANGELOG.md139
-rw-r--r--vendor/native-tls/Cargo.lock447
-rw-r--r--vendor/native-tls/Cargo.toml66
-rw-r--r--vendor/native-tls/LICENSE-APACHE202
-rw-r--r--vendor/native-tls/LICENSE-MIT19
-rw-r--r--vendor/native-tls/README.md95
-rw-r--r--vendor/native-tls/build.rs19
-rw-r--r--vendor/native-tls/examples/google-connect.rs17
-rw-r--r--vendor/native-tls/examples/simple-server-pkcs8.rs45
-rw-r--r--vendor/native-tls/examples/simple-server.rs37
-rw-r--r--vendor/native-tls/src/imp/openssl.rs483
-rw-r--r--vendor/native-tls/src/imp/schannel.rs562
-rw-r--r--vendor/native-tls/src/imp/security_framework.rs632
-rw-r--r--vendor/native-tls/src/lib.rs721
-rw-r--r--vendor/native-tls/src/test.rs573
16 files changed, 4058 insertions, 0 deletions
diff --git a/vendor/native-tls/.cargo-checksum.json b/vendor/native-tls/.cargo-checksum.json
new file mode 100644
index 000000000..9af8ee82c
--- /dev/null
+++ b/vendor/native-tls/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"3ec2dc79aba726b64c4b30dfbfc832acf1dbcb22a91fbcf9989d24b27d42ed87","Cargo.lock":"9a694aa99425505811f81513a1ab786514a9d418be87d05e1de1053a0d3dddca","Cargo.toml":"71f6d31fc79fd032f3920999e255f62020554bae57022fd44d444afdf131b988","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"f2ad7982ddbfa8c45eb965315718c55b70b9cc311b49afacb50d5fe84173ae2c","README.md":"265b94051f44c7a12669864d75ab8c80a676070cb32e2209f74a320d84b38736","build.rs":"46cfae159ca20d37b04f4250eb538e60dc1981c39133f98a3e7691f002a18b91","examples/google-connect.rs":"339a8cb9c9b8c472f8cac96711950114528c8700e5e48d6f61d59b636b69eb0c","examples/simple-server-pkcs8.rs":"e7749791e5d15334a8d54a86df11fbe0167f3a4a6d2faa44560d26f92211cf23","examples/simple-server.rs":"f26fdcca641d03ecb7881fbc94ed1b5fe5db38531c1e8b4cd4a6bed3e3653ee8","src/imp/openssl.rs":"a5f46146e76325bfa2cdb03c6f600b2bd30417a3d05ea6cd7e36de4954e051e4","src/imp/schannel.rs":"c5a986eace90d5e020d19452f9a7a34693b4a137492a5290ce5a76388fd3fcbc","src/imp/security_framework.rs":"a4f70acc9f52c8126c212aea3e53d7dd62e637ab9ef8358486ba6f4583ea275a","src/lib.rs":"ab2e057f0fdfb01f12100ed7459ae192a64376759dccdc6a91b632ddbcfce98e","src/test.rs":"5cac53231672ef2a329e7a862abe7a9c1ba6f02bacbd0a57998e5453ad29d098"},"package":"07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"} \ No newline at end of file
diff --git a/vendor/native-tls/CHANGELOG.md b/vendor/native-tls/CHANGELOG.md
new file mode 100644
index 000000000..40c4ddcd3
--- /dev/null
+++ b/vendor/native-tls/CHANGELOG.md
@@ -0,0 +1,139 @@
+# Change Log
+
+## [Unreleased]
+
+## [v0.2.11]
+
+### Fixed
+
+* Removed an unused build dependency.
+
+## [v0.2.10]
+
+### Fixed
+
+* Fixed the build for iOS.
+
+## [v0.2.9]
+
+### Added
+
+* Added `Identity::from_pkcs8`.
+
+## [v0.2.8]
+
+### Fixed
+
+* Fixed an off by one error in the schannel backend's handling of max_protocol_version.
+
+## [v0.2.7]
+
+### Added
+
+* Added support for ALPN in client APIs flagged under the `alpn` Cargo feature.
+
+## [v0.2.6]
+
+### Fixed
+
+* Fixed compilation on iOS.
+
+## [v0.2.5]
+
+### Added
+
+* Added `TlsConnectorBuilder::disable_built_in_roots` to only trust root certificates explicitly
+ added to the builder.
+
+### Updated
+
+* Updated security-framework to 2.0.
+
+## [v0.2.4]
+
+### Added
+
+* Added a `Clone` implementation for `Identity`.
+
+### Updated
+
+* Updated security-framework to 0.4.
+
+## [v0.2.3]
+
+### Fixed
+
+* Adding an already-trusted certificate to the root certificate set no longer triggers an error
+ with OpenSSL.
+
+### Updated
+
+* Updated security-framework to 0.3.
+
+## [v0.2.2]
+
+### Fixed
+
+* Failure to load a root certificate on Android now logs a message rather than producing an error.
+* Fixed ordering of the certificate chain in the OpenSSL backend.
+
+## [v0.2.1]
+
+### Added
+
+* The `vendored` Cargo feature will cause the crate to compile and statically link to a vendored
+ copy of OpenSSL on platforms that use that backend.
+
+## [v0.2.0]
+
+### Added
+
+* The `openssl_probe` crate is now used with the OpenSSL backend so that trusted root certificates
+ will automatically be detected when statically linking to OpenSSL.
+* Root certificates are now automatically loaded from the Android trust root.
+* Added `Certificate::to_der` to serialize an X509 certificate to DER.
+* Added `TlsConnectorBuilder::danger_accept_invalid_certs` to disable certificate verification.
+* Added `TlsAcceptor::new` and `TlsConnector::new` to easily create an acceptor/connector with
+ default settings.
+* Added `TlsStream::peer_certificate` to obtain the peer's leaf certificate.
+* Added `TlsStream::tls_server_end_point` to retrieve RFC 5929 tls-server-end-point channel binding
+ data.
+
+### Changed
+
+* Upgraded to `openssl` 0.10 and `security-framework` 0.2.
+* `Pkcs12` has been renamed to `Identity`, and `Pkcs12::from_der` has been renamed to
+ `Identity::from_pkcs12`.
+* `HandshakeError::Interrupted` has been renamed to `HandshakeError::WouldBlock`.
+* `TlsConnectorBuilder` and `TlsAcceptorBuilder` are now "traditional"-style builders. Their methods
+ are now infallible and return `&mut Self` to allow them to be chained together.
+* `supported_protocols` has been replaced by `min_protocol_version` and `max_protocol_version` on
+ `TlsConnectorBuilder` and `TlsAcceptorBuilder`.
+* SNI and hostname verification are now configured separately via `TlsConnectorBuilder::use_sni` and
+ `TlsConnectorBuilder::danger_accept_invalid_hostnames`. They replace the
+ `TlsConnector::danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication`
+ method, which has been removed.
+
+### Removed
+
+* The backend-specific extension traits have been removed. We want to avoid exposing the specific
+ version of the backend library in the public API to provide more flexibility.
+
+## Older
+
+Look at the [release tags] for information about older releases.
+
+[Unreleased]: https://github.com/sfackler/rust-native-tls/compare/v0.2.11...master
+[v0.2.11]: https://github.com/sfackler/rust-native-tls/compare/v0.2.10...v0.2.11
+[v0.2.10]: https://github.com/sfackler/rust-native-tls/compare/v0.2.9...v0.2.10
+[v0.2.9]: https://github.com/sfackler/rust-native-tls/compare/v0.2.8...v0.2.9
+[v0.2.8]: https://github.com/sfackler/rust-native-tls/compare/v0.2.7...v0.2.8
+[v0.2.7]: https://github.com/sfackler/rust-native-tls/compare/v0.2.6...v0.2.7
+[v0.2.6]: https://github.com/sfackler/rust-native-tls/compare/v0.2.5...v0.2.6
+[v0.2.5]: https://github.com/sfackler/rust-native-tls/compare/v0.2.4...v0.2.5
+[v0.2.4]: https://github.com/sfackler/rust-native-tls/compare/v0.2.3...v0.2.4
+[v0.2.3]: https://github.com/sfackler/rust-native-tls/compare/v0.2.2...v0.2.3
+[v0.2.2]: https://github.com/sfackler/rust-native-tls/compare/v0.2.1...v0.2.2
+[v0.2.1]: https://github.com/sfackler/rust-native-tls/compare/v0.2.0...v0.2.1
+[v0.2.0]: https://github.com/sfackler/rust-native-tls/compare/v0.1.5...v0.2.0
+[release tags]: https://github.com/sfackler/rust-native-tls/releases
diff --git a/vendor/native-tls/Cargo.lock b/vendor/native-tls/Cargo.lock
new file mode 100644
index 000000000..97c920af0
--- /dev/null
+++ b/vendor/native-tls/Cargo.lock
@@ -0,0 +1,447 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "base64"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cc"
+version = "1.0.74"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
+
+[[package]]
+name = "fastrand"
+version = "1.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
+dependencies = [
+ "instant",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "fuchsia-cprng"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.137"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+
+[[package]]
+name = "log"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "native-tls"
+version = "0.2.11"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "log",
+ "openssl",
+ "openssl-probe",
+ "openssl-sys",
+ "schannel",
+ "security-framework",
+ "security-framework-sys",
+ "tempfile",
+ "test-cert-gen",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+
+[[package]]
+name = "openssl"
+version = "0.10.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "foreign-types",
+ "libc",
+ "once_cell",
+ "openssl-macros",
+ "openssl-sys",
+]
+
+[[package]]
+name = "openssl-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "openssl-probe"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
+
+[[package]]
+name = "openssl-src"
+version = "111.24.0+1.1.1s"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3498f259dab01178c6228c6b00dcef0ed2a2d5e20d648c017861227773ea4abd"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "openssl-sys"
+version = "0.9.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a"
+dependencies = [
+ "autocfg",
+ "cc",
+ "libc",
+ "openssl-src",
+ "pkg-config",
+ "vcpkg",
+]
+
+[[package]]
+name = "pem"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd56cbd21fea48d0c440b41cd69c589faacade08c992d9a54e471b79d0fd13eb"
+dependencies = [
+ "base64",
+ "once_cell",
+ "regex",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
+dependencies = [
+ "fuchsia-cprng",
+ "libc",
+ "rand_core 0.3.1",
+ "rdrand",
+ "winapi",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
+dependencies = [
+ "rand_core 0.4.2",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
+
+[[package]]
+name = "rdrand"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
+dependencies = [
+ "rand_core 0.3.1",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+dependencies = [
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.27"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "schannel"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
+dependencies = [
+ "lazy_static",
+ "windows-sys",
+]
+
+[[package]]
+name = "security-framework"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-foundation-sys",
+ "libc",
+ "security-framework-sys",
+]
+
+[[package]]
+name = "security-framework-sys"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "syn"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "tempdir"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
+dependencies = [
+ "rand",
+ "remove_dir_all",
+]
+
+[[package]]
+name = "tempfile"
+version = "3.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "libc",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "test-cert-gen"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3208d0ae2e3736d4ac2f6ba2229c4d9bbd54080e228e662a7684eabcf13ff419"
+dependencies = [
+ "pem",
+ "tempdir",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+dependencies = [
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
diff --git a/vendor/native-tls/Cargo.toml b/vendor/native-tls/Cargo.toml
new file mode 100644
index 000000000..a0592366c
--- /dev/null
+++ b/vendor/native-tls/Cargo.toml
@@ -0,0 +1,66 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+name = "native-tls"
+version = "0.2.11"
+authors = ["Steven Fackler <sfackler@gmail.com>"]
+description = "A wrapper over a platform's native TLS implementation"
+readme = "README.md"
+license = "MIT/Apache-2.0"
+repository = "https://github.com/sfackler/rust-native-tls"
+
+[package.metadata.docs.rs]
+features = ["alpn"]
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+]
+
+[dev-dependencies.tempfile]
+version = "3.0"
+
+[dev-dependencies.test-cert-gen]
+version = "0.7"
+
+[features]
+alpn = ["security-framework/alpn"]
+vendored = ["openssl/vendored"]
+
+[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.lazy_static]
+version = "1.4.0"
+
+[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.libc]
+version = "0.2"
+
+[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.security-framework]
+version = "2.0.0"
+
+[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.security-framework-sys]
+version = "2.0.0"
+
+[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.tempfile]
+version = "3.1.0"
+
+[target."cfg(not(any(target_os = \"windows\", target_os = \"macos\", target_os = \"ios\")))".dependencies.log]
+version = "0.4.5"
+
+[target."cfg(not(any(target_os = \"windows\", target_os = \"macos\", target_os = \"ios\")))".dependencies.openssl]
+version = "0.10.29"
+
+[target."cfg(not(any(target_os = \"windows\", target_os = \"macos\", target_os = \"ios\")))".dependencies.openssl-probe]
+version = "0.1"
+
+[target."cfg(not(any(target_os = \"windows\", target_os = \"macos\", target_os = \"ios\")))".dependencies.openssl-sys]
+version = "0.9.55"
+
+[target."cfg(target_os = \"windows\")".dependencies.schannel]
+version = "0.1.17"
diff --git a/vendor/native-tls/LICENSE-APACHE b/vendor/native-tls/LICENSE-APACHE
new file mode 100644
index 000000000..8f71f43fe
--- /dev/null
+++ b/vendor/native-tls/LICENSE-APACHE
@@ -0,0 +1,202 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/vendor/native-tls/LICENSE-MIT b/vendor/native-tls/LICENSE-MIT
new file mode 100644
index 000000000..981a42dc9
--- /dev/null
+++ b/vendor/native-tls/LICENSE-MIT
@@ -0,0 +1,19 @@
+Copyright (c) 2016 The rust-native-tls Developers
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/native-tls/README.md b/vendor/native-tls/README.md
new file mode 100644
index 000000000..fe5d04b84
--- /dev/null
+++ b/vendor/native-tls/README.md
@@ -0,0 +1,95 @@
+# rust-native-tls
+
+[Documentation](https://docs.rs/native-tls)
+
+An abstraction over platform-specific TLS implementations.
+
+Specifically, this crate uses SChannel on Windows (via the [`schannel`] crate),
+Secure Transport on macOS (via the [`security-framework`] crate), and OpenSSL (via
+the [`openssl`] crate) on all other platforms.
+
+[`schannel`]: https://crates.io/crates/schannel
+[`security-framework`]: https://crates.io/crates/security-framework
+[`openssl`]: https://crates.io/crates/openssl
+
+## Installation
+
+```toml
+# Cargo.toml
+[dependencies]
+native-tls = "0.2"
+```
+
+## Usage
+
+An example client looks like:
+
+```rust,ignore
+extern crate native_tls;
+
+use native_tls::TlsConnector;
+use std::io::{Read, Write};
+use std::net::TcpStream;
+
+fn main() {
+ let connector = TlsConnector::new().unwrap();
+
+ let stream = TcpStream::connect("google.com:443").unwrap();
+ let mut stream = connector.connect("google.com", stream).unwrap();
+
+ stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
+ let mut res = vec![];
+ stream.read_to_end(&mut res).unwrap();
+ println!("{}", String::from_utf8_lossy(&res));
+}
+```
+
+To accept connections as a server from remote clients:
+
+```rust,ignore
+extern crate native_tls;
+
+use native_tls::{Identity, TlsAcceptor, TlsStream};
+use std::fs::File;
+use std::io::{Read};
+use std::net::{TcpListener, TcpStream};
+use std::sync::Arc;
+use std::thread;
+
+fn main() {
+ let mut file = File::open("identity.pfx").unwrap();
+ let mut identity = vec![];
+ file.read_to_end(&mut identity).unwrap();
+ let identity = Identity::from_pkcs12(&identity, "hunter2").unwrap();
+
+ let acceptor = TlsAcceptor::new(identity).unwrap();
+ let acceptor = Arc::new(acceptor);
+
+ let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
+
+ fn handle_client(stream: TlsStream<TcpStream>) {
+ // ...
+ }
+
+ for stream in listener.incoming() {
+ match stream {
+ Ok(stream) => {
+ let acceptor = acceptor.clone();
+ thread::spawn(move || {
+ let stream = acceptor.accept(stream).unwrap();
+ handle_client(stream);
+ });
+ }
+ Err(e) => { /* connection failed */ }
+ }
+ }
+}
+```
+
+# License
+
+`rust-native-tls` is primarily distributed under the terms of both the MIT
+license and the Apache License (Version 2.0), with portions covered by various
+BSD-like licenses.
+
+See LICENSE-APACHE, and LICENSE-MIT for details.
diff --git a/vendor/native-tls/build.rs b/vendor/native-tls/build.rs
new file mode 100644
index 000000000..cbac306a5
--- /dev/null
+++ b/vendor/native-tls/build.rs
@@ -0,0 +1,19 @@
+use std::env;
+
+fn main() {
+ if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") {
+ let version = u64::from_str_radix(&version, 16).unwrap();
+
+ if version >= 0x1_01_00_00_0 {
+ println!("cargo:rustc-cfg=have_min_max_version");
+ }
+ }
+
+ if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") {
+ let version = u64::from_str_radix(&version, 16).unwrap();
+
+ if version >= 0x2_06_01_00_0 {
+ println!("cargo:rustc-cfg=have_min_max_version");
+ }
+ }
+}
diff --git a/vendor/native-tls/examples/google-connect.rs b/vendor/native-tls/examples/google-connect.rs
new file mode 100644
index 000000000..bcf454245
--- /dev/null
+++ b/vendor/native-tls/examples/google-connect.rs
@@ -0,0 +1,17 @@
+extern crate native_tls;
+
+use native_tls::TlsConnector;
+use std::io::{Read, Write};
+use std::net::TcpStream;
+
+fn main() {
+ let connector = TlsConnector::new().unwrap();
+
+ let stream = TcpStream::connect("google.com:443").unwrap();
+ let mut stream = connector.connect("google.com", stream).unwrap();
+
+ stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
+ let mut res = vec![];
+ stream.read_to_end(&mut res).unwrap();
+ println!("{}", String::from_utf8_lossy(&res));
+}
diff --git a/vendor/native-tls/examples/simple-server-pkcs8.rs b/vendor/native-tls/examples/simple-server-pkcs8.rs
new file mode 100644
index 000000000..df9c95da0
--- /dev/null
+++ b/vendor/native-tls/examples/simple-server-pkcs8.rs
@@ -0,0 +1,45 @@
+extern crate native_tls;
+
+use native_tls::{Identity, TlsAcceptor, TlsStream};
+use std::fs::File;
+use std::io::{Read, Write};
+use std::net::{TcpListener, TcpStream};
+use std::sync::Arc;
+use std::thread;
+
+fn main() {
+ let mut cert_file = File::open("test/cert.pem").unwrap();
+ let mut certs = vec![];
+ cert_file.read_to_end(&mut certs).unwrap();
+ let mut key_file = File::open("test/key.pem").unwrap();
+ let mut key = vec![];
+ key_file.read_to_end(&mut key).unwrap();
+ let pkcs8 = Identity::from_pkcs8(&certs, &key).unwrap();
+
+ let acceptor = TlsAcceptor::new(pkcs8).unwrap();
+ let acceptor = Arc::new(acceptor);
+
+ let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
+
+ fn handle_client(mut stream: TlsStream<TcpStream>) {
+ let mut buf = [0; 1024];
+ let read = stream.read(&mut buf).unwrap();
+ let received = std::str::from_utf8(&buf[0..read]).unwrap();
+ stream
+ .write_all(format!("received '{}'", received).as_bytes())
+ .unwrap();
+ }
+
+ for stream in listener.incoming() {
+ match stream {
+ Ok(stream) => {
+ let acceptor = acceptor.clone();
+ thread::spawn(move || {
+ let stream = acceptor.accept(stream).unwrap();
+ handle_client(stream);
+ });
+ }
+ Err(_e) => { /* connection failed */ }
+ }
+ }
+}
diff --git a/vendor/native-tls/examples/simple-server.rs b/vendor/native-tls/examples/simple-server.rs
new file mode 100644
index 000000000..483be948c
--- /dev/null
+++ b/vendor/native-tls/examples/simple-server.rs
@@ -0,0 +1,37 @@
+extern crate native_tls;
+
+use native_tls::{Identity, TlsAcceptor, TlsStream};
+use std::fs::File;
+use std::io::Read;
+use std::net::{TcpListener, TcpStream};
+use std::sync::Arc;
+use std::thread;
+
+fn main() {
+ let mut file = File::open("identity.pfx").unwrap();
+ let mut pkcs12 = vec![];
+ file.read_to_end(&mut pkcs12).unwrap();
+ let pkcs12 = Identity::from_pkcs12(&pkcs12, "hunter2").unwrap();
+
+ let acceptor = TlsAcceptor::new(pkcs12).unwrap();
+ let acceptor = Arc::new(acceptor);
+
+ let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
+
+ fn handle_client(_stream: TlsStream<TcpStream>) {
+ // ...
+ }
+
+ for stream in listener.incoming() {
+ match stream {
+ Ok(stream) => {
+ let acceptor = acceptor.clone();
+ thread::spawn(move || {
+ let stream = acceptor.accept(stream).unwrap();
+ handle_client(stream);
+ });
+ }
+ Err(_e) => { /* connection failed */ }
+ }
+ }
+}
diff --git a/vendor/native-tls/src/imp/openssl.rs b/vendor/native-tls/src/imp/openssl.rs
new file mode 100644
index 000000000..389caa5e5
--- /dev/null
+++ b/vendor/native-tls/src/imp/openssl.rs
@@ -0,0 +1,483 @@
+extern crate openssl;
+extern crate openssl_probe;
+
+use self::openssl::error::ErrorStack;
+use self::openssl::hash::MessageDigest;
+use self::openssl::nid::Nid;
+use self::openssl::pkcs12::Pkcs12;
+use self::openssl::pkey::{PKey, Private};
+use self::openssl::ssl::{
+ self, MidHandshakeSslStream, SslAcceptor, SslConnector, SslContextBuilder, SslMethod,
+ SslVerifyMode,
+};
+use self::openssl::x509::{store::X509StoreBuilder, X509VerifyResult, X509};
+use std::error;
+use std::fmt;
+use std::io;
+use std::sync::Once;
+
+use {Protocol, TlsAcceptorBuilder, TlsConnectorBuilder};
+
+#[cfg(have_min_max_version)]
+fn supported_protocols(
+ min: Option<Protocol>,
+ max: Option<Protocol>,
+ ctx: &mut SslContextBuilder,
+) -> Result<(), ErrorStack> {
+ use self::openssl::ssl::SslVersion;
+
+ fn cvt(p: Protocol) -> SslVersion {
+ match p {
+ Protocol::Sslv3 => SslVersion::SSL3,
+ Protocol::Tlsv10 => SslVersion::TLS1,
+ Protocol::Tlsv11 => SslVersion::TLS1_1,
+ Protocol::Tlsv12 => SslVersion::TLS1_2,
+ Protocol::__NonExhaustive => unreachable!(),
+ }
+ }
+
+ ctx.set_min_proto_version(min.map(cvt))?;
+ ctx.set_max_proto_version(max.map(cvt))?;
+
+ Ok(())
+}
+
+#[cfg(not(have_min_max_version))]
+fn supported_protocols(
+ min: Option<Protocol>,
+ max: Option<Protocol>,
+ ctx: &mut SslContextBuilder,
+) -> Result<(), ErrorStack> {
+ use self::openssl::ssl::SslOptions;
+
+ let no_ssl_mask = SslOptions::NO_SSLV2
+ | SslOptions::NO_SSLV3
+ | SslOptions::NO_TLSV1
+ | SslOptions::NO_TLSV1_1
+ | SslOptions::NO_TLSV1_2;
+
+ ctx.clear_options(no_ssl_mask);
+ let mut options = SslOptions::empty();
+ options |= match min {
+ None => SslOptions::empty(),
+ Some(Protocol::Sslv3) => SslOptions::NO_SSLV2,
+ Some(Protocol::Tlsv10) => SslOptions::NO_SSLV2 | SslOptions::NO_SSLV3,
+ Some(Protocol::Tlsv11) => {
+ SslOptions::NO_SSLV2 | SslOptions::NO_SSLV3 | SslOptions::NO_TLSV1
+ }
+ Some(Protocol::Tlsv12) => {
+ SslOptions::NO_SSLV2
+ | SslOptions::NO_SSLV3
+ | SslOptions::NO_TLSV1
+ | SslOptions::NO_TLSV1_1
+ }
+ Some(Protocol::__NonExhaustive) => unreachable!(),
+ };
+ options |= match max {
+ None | Some(Protocol::Tlsv12) => SslOptions::empty(),
+ Some(Protocol::Tlsv11) => SslOptions::NO_TLSV1_2,
+ Some(Protocol::Tlsv10) => SslOptions::NO_TLSV1_1 | SslOptions::NO_TLSV1_2,
+ Some(Protocol::Sslv3) => {
+ SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1 | SslOptions::NO_TLSV1_2
+ }
+ Some(Protocol::__NonExhaustive) => unreachable!(),
+ };
+
+ ctx.set_options(options);
+
+ Ok(())
+}
+
+fn init_trust() {
+ static ONCE: Once = Once::new();
+ ONCE.call_once(openssl_probe::init_ssl_cert_env_vars);
+}
+
+#[cfg(target_os = "android")]
+fn load_android_root_certs(connector: &mut SslContextBuilder) -> Result<(), Error> {
+ use std::fs;
+
+ if let Ok(dir) = fs::read_dir("/system/etc/security/cacerts") {
+ let certs = dir
+ .filter_map(|r| r.ok())
+ .filter_map(|e| fs::read(e.path()).ok())
+ .filter_map(|b| X509::from_pem(&b).ok());
+ for cert in certs {
+ if let Err(err) = connector.cert_store_mut().add_cert(cert) {
+ debug!("load_android_root_certs error: {:?}", err);
+ }
+ }
+ }
+
+ Ok(())
+}
+
+#[derive(Debug)]
+pub enum Error {
+ Normal(ErrorStack),
+ Ssl(ssl::Error, X509VerifyResult),
+ EmptyChain,
+ NotPkcs8,
+}
+
+impl error::Error for Error {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ Error::Normal(ref e) => error::Error::source(e),
+ Error::Ssl(ref e, _) => error::Error::source(e),
+ Error::EmptyChain => None,
+ Error::NotPkcs8 => None,
+ }
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Error::Normal(ref e) => fmt::Display::fmt(e, fmt),
+ Error::Ssl(ref e, X509VerifyResult::OK) => fmt::Display::fmt(e, fmt),
+ Error::Ssl(ref e, v) => write!(fmt, "{} ({})", e, v),
+ Error::EmptyChain => write!(
+ fmt,
+ "at least one certificate must be provided to create an identity"
+ ),
+ Error::NotPkcs8 => write!(fmt, "expected PKCS#8 PEM"),
+ }
+ }
+}
+
+impl From<ErrorStack> for Error {
+ fn from(err: ErrorStack) -> Error {
+ Error::Normal(err)
+ }
+}
+
+#[derive(Clone)]
+pub struct Identity {
+ pkey: PKey<Private>,
+ cert: X509,
+ chain: Vec<X509>,
+}
+
+impl Identity {
+ pub fn from_pkcs12(buf: &[u8], pass: &str) -> Result<Identity, Error> {
+ let pkcs12 = Pkcs12::from_der(buf)?;
+ let parsed = pkcs12.parse(pass)?;
+ Ok(Identity {
+ pkey: parsed.pkey,
+ cert: parsed.cert,
+ // > The stack is the reverse of what you might expect due to the way
+ // > PKCS12_parse is implemented, so we need to load it backwards.
+ // > https://github.com/sfackler/rust-native-tls/commit/05fb5e583be589ab63d9f83d986d095639f8ec44
+ chain: parsed.chain.into_iter().flatten().rev().collect(),
+ })
+ }
+
+ pub fn from_pkcs8(buf: &[u8], key: &[u8]) -> Result<Identity, Error> {
+ if !key.starts_with(b"-----BEGIN PRIVATE KEY-----") {
+ return Err(Error::NotPkcs8);
+ }
+
+ let pkey = PKey::private_key_from_pem(key)?;
+ let mut cert_chain = X509::stack_from_pem(buf)?.into_iter();
+ let cert = cert_chain.next().ok_or(Error::EmptyChain)?;
+ let chain = cert_chain.collect();
+ Ok(Identity { pkey, cert, chain })
+ }
+}
+
+#[derive(Clone)]
+pub struct Certificate(X509);
+
+impl Certificate {
+ pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
+ let cert = X509::from_der(buf)?;
+ Ok(Certificate(cert))
+ }
+
+ pub fn from_pem(buf: &[u8]) -> Result<Certificate, Error> {
+ let cert = X509::from_pem(buf)?;
+ Ok(Certificate(cert))
+ }
+
+ pub fn to_der(&self) -> Result<Vec<u8>, Error> {
+ let der = self.0.to_der()?;
+ Ok(der)
+ }
+}
+
+pub struct MidHandshakeTlsStream<S>(MidHandshakeSslStream<S>);
+
+impl<S> fmt::Debug for MidHandshakeTlsStream<S>
+where
+ S: fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl<S> MidHandshakeTlsStream<S> {
+ pub fn get_ref(&self) -> &S {
+ self.0.get_ref()
+ }
+
+ pub fn get_mut(&mut self) -> &mut S {
+ self.0.get_mut()
+ }
+}
+
+impl<S> MidHandshakeTlsStream<S>
+where
+ S: io::Read + io::Write,
+{
+ pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
+ match self.0.handshake() {
+ Ok(s) => Ok(TlsStream(s)),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+pub enum HandshakeError<S> {
+ Failure(Error),
+ WouldBlock(MidHandshakeTlsStream<S>),
+}
+
+impl<S> From<ssl::HandshakeError<S>> for HandshakeError<S> {
+ fn from(e: ssl::HandshakeError<S>) -> HandshakeError<S> {
+ match e {
+ ssl::HandshakeError::SetupFailure(e) => HandshakeError::Failure(e.into()),
+ ssl::HandshakeError::Failure(e) => {
+ let v = e.ssl().verify_result();
+ HandshakeError::Failure(Error::Ssl(e.into_error(), v))
+ }
+ ssl::HandshakeError::WouldBlock(s) => {
+ HandshakeError::WouldBlock(MidHandshakeTlsStream(s))
+ }
+ }
+ }
+}
+
+impl<S> From<ErrorStack> for HandshakeError<S> {
+ fn from(e: ErrorStack) -> HandshakeError<S> {
+ HandshakeError::Failure(e.into())
+ }
+}
+
+#[derive(Clone)]
+pub struct TlsConnector {
+ connector: SslConnector,
+ use_sni: bool,
+ accept_invalid_hostnames: bool,
+ accept_invalid_certs: bool,
+}
+
+impl TlsConnector {
+ pub fn new(builder: &TlsConnectorBuilder) -> Result<TlsConnector, Error> {
+ init_trust();
+
+ let mut connector = SslConnector::builder(SslMethod::tls())?;
+ if let Some(ref identity) = builder.identity {
+ connector.set_certificate(&identity.0.cert)?;
+ connector.set_private_key(&identity.0.pkey)?;
+ for cert in identity.0.chain.iter() {
+ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_extra_chain_cert.html
+ // specifies that "When sending a certificate chain, extra chain certificates are
+ // sent in order following the end entity certificate."
+ connector.add_extra_chain_cert(cert.to_owned())?;
+ }
+ }
+ supported_protocols(builder.min_protocol, builder.max_protocol, &mut connector)?;
+
+ if builder.disable_built_in_roots {
+ connector.set_cert_store(X509StoreBuilder::new()?.build());
+ }
+
+ for cert in &builder.root_certificates {
+ if let Err(err) = connector.cert_store_mut().add_cert((cert.0).0.clone()) {
+ debug!("add_cert error: {:?}", err);
+ }
+ }
+
+ #[cfg(feature = "alpn")]
+ {
+ if !builder.alpn.is_empty() {
+ // Wire format is each alpn preceded by its length as a byte.
+ let mut alpn_wire_format = Vec::with_capacity(
+ builder
+ .alpn
+ .iter()
+ .map(|s| s.as_bytes().len())
+ .sum::<usize>()
+ + builder.alpn.len(),
+ );
+ for alpn in builder.alpn.iter().map(|s| s.as_bytes()) {
+ alpn_wire_format.push(alpn.len() as u8);
+ alpn_wire_format.extend(alpn);
+ }
+ connector.set_alpn_protos(&alpn_wire_format)?;
+ }
+ }
+
+ #[cfg(target_os = "android")]
+ load_android_root_certs(&mut connector)?;
+
+ Ok(TlsConnector {
+ connector: connector.build(),
+ use_sni: builder.use_sni,
+ accept_invalid_hostnames: builder.accept_invalid_hostnames,
+ accept_invalid_certs: builder.accept_invalid_certs,
+ })
+ }
+
+ pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
+ where
+ S: io::Read + io::Write,
+ {
+ let mut ssl = self
+ .connector
+ .configure()?
+ .use_server_name_indication(self.use_sni)
+ .verify_hostname(!self.accept_invalid_hostnames);
+ if self.accept_invalid_certs {
+ ssl.set_verify(SslVerifyMode::NONE);
+ }
+
+ let s = ssl.connect(domain, stream)?;
+ Ok(TlsStream(s))
+ }
+}
+
+impl fmt::Debug for TlsConnector {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.debug_struct("TlsConnector")
+ // n.b. SslConnector is a newtype on SslContext which implements a noop Debug so it's omitted
+ .field("use_sni", &self.use_sni)
+ .field("accept_invalid_hostnames", &self.accept_invalid_hostnames)
+ .field("accept_invalid_certs", &self.accept_invalid_certs)
+ .finish()
+ }
+}
+
+#[derive(Clone)]
+pub struct TlsAcceptor(SslAcceptor);
+
+impl TlsAcceptor {
+ pub fn new(builder: &TlsAcceptorBuilder) -> Result<TlsAcceptor, Error> {
+ let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls())?;
+ acceptor.set_private_key(&builder.identity.0.pkey)?;
+ acceptor.set_certificate(&builder.identity.0.cert)?;
+ for cert in builder.identity.0.chain.iter() {
+ // https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_extra_chain_cert.html
+ // specifies that "When sending a certificate chain, extra chain certificates are
+ // sent in order following the end entity certificate."
+ acceptor.add_extra_chain_cert(cert.to_owned())?;
+ }
+ supported_protocols(builder.min_protocol, builder.max_protocol, &mut acceptor)?;
+
+ Ok(TlsAcceptor(acceptor.build()))
+ }
+
+ pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
+ where
+ S: io::Read + io::Write,
+ {
+ let s = self.0.accept(stream)?;
+ Ok(TlsStream(s))
+ }
+}
+
+pub struct TlsStream<S>(ssl::SslStream<S>);
+
+impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl<S> TlsStream<S> {
+ pub fn get_ref(&self) -> &S {
+ self.0.get_ref()
+ }
+
+ pub fn get_mut(&mut self) -> &mut S {
+ self.0.get_mut()
+ }
+}
+
+impl<S: io::Read + io::Write> TlsStream<S> {
+ pub fn buffered_read_size(&self) -> Result<usize, Error> {
+ Ok(self.0.ssl().pending())
+ }
+
+ pub fn peer_certificate(&self) -> Result<Option<Certificate>, Error> {
+ Ok(self.0.ssl().peer_certificate().map(Certificate))
+ }
+
+ #[cfg(feature = "alpn")]
+ pub fn negotiated_alpn(&self) -> Result<Option<Vec<u8>>, Error> {
+ Ok(self
+ .0
+ .ssl()
+ .selected_alpn_protocol()
+ .map(|alpn| alpn.to_vec()))
+ }
+
+ pub fn tls_server_end_point(&self) -> Result<Option<Vec<u8>>, Error> {
+ let cert = if self.0.ssl().is_server() {
+ self.0.ssl().certificate().map(|x| x.to_owned())
+ } else {
+ self.0.ssl().peer_certificate()
+ };
+
+ let cert = match cert {
+ Some(cert) => cert,
+ None => return Ok(None),
+ };
+
+ let algo_nid = cert.signature_algorithm().object().nid();
+ let signature_algorithms = match algo_nid.signature_algorithms() {
+ Some(algs) => algs,
+ None => return Ok(None),
+ };
+
+ let md = match signature_algorithms.digest {
+ Nid::MD5 | Nid::SHA1 => MessageDigest::sha256(),
+ nid => match MessageDigest::from_nid(nid) {
+ Some(md) => md,
+ None => return Ok(None),
+ },
+ };
+
+ let digest = cert.digest(md)?;
+
+ Ok(Some(digest.to_vec()))
+ }
+
+ pub fn shutdown(&mut self) -> io::Result<()> {
+ match self.0.shutdown() {
+ Ok(_) => Ok(()),
+ Err(ref e) if e.code() == ssl::ErrorCode::ZERO_RETURN => Ok(()),
+ Err(e) => Err(e
+ .into_io_error()
+ .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))),
+ }
+ }
+}
+
+impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+}
+
+impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.0.flush()
+ }
+}
diff --git a/vendor/native-tls/src/imp/schannel.rs b/vendor/native-tls/src/imp/schannel.rs
new file mode 100644
index 000000000..62e5042f0
--- /dev/null
+++ b/vendor/native-tls/src/imp/schannel.rs
@@ -0,0 +1,562 @@
+extern crate schannel;
+
+use self::schannel::cert_context::{CertContext, HashAlgorithm, KeySpec};
+use self::schannel::cert_store::{CertAdd, CertStore, Memory, PfxImportOptions};
+use self::schannel::crypt_prov::{AcquireOptions, ProviderType};
+use self::schannel::schannel_cred::{Direction, Protocol, SchannelCred};
+use self::schannel::tls_stream;
+use std::error;
+use std::fmt;
+use std::io;
+use std::str;
+
+use {TlsAcceptorBuilder, TlsConnectorBuilder};
+
+const SEC_E_NO_CREDENTIALS: u32 = 0x8009030E;
+
+static PROTOCOLS: &'static [Protocol] = &[
+ Protocol::Ssl3,
+ Protocol::Tls10,
+ Protocol::Tls11,
+ Protocol::Tls12,
+];
+
+fn convert_protocols(min: Option<::Protocol>, max: Option<::Protocol>) -> &'static [Protocol] {
+ let mut protocols = PROTOCOLS;
+ if let Some(p) = max.and_then(|max| protocols.get(..=max as usize)) {
+ protocols = p;
+ }
+ if let Some(p) = min.and_then(|min| protocols.get(min as usize..)) {
+ protocols = p;
+ }
+ protocols
+}
+
+pub struct Error(io::Error);
+
+impl error::Error for Error {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ error::Error::source(&self.0)
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, fmt)
+ }
+}
+
+impl fmt::Debug for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl From<io::Error> for Error {
+ fn from(error: io::Error) -> Error {
+ Error(error)
+ }
+}
+
+#[derive(Clone)]
+pub struct Identity {
+ cert: CertContext,
+}
+
+impl Identity {
+ pub fn from_pkcs12(buf: &[u8], pass: &str) -> Result<Identity, Error> {
+ let store = PfxImportOptions::new().password(pass).import(buf)?;
+ let mut identity = None;
+
+ for cert in store.certs() {
+ if cert
+ .private_key()
+ .silent(true)
+ .compare_key(true)
+ .acquire()
+ .is_ok()
+ {
+ identity = Some(cert);
+ break;
+ }
+ }
+
+ let identity = match identity {
+ Some(identity) => identity,
+ None => {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "No identity found in PKCS #12 archive",
+ )
+ .into());
+ }
+ };
+
+ Ok(Identity { cert: identity })
+ }
+
+ pub fn from_pkcs8(pem: &[u8], key: &[u8]) -> Result<Identity, Error> {
+ if !key.starts_with(b"-----BEGIN PRIVATE KEY-----") {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput, "not a PKCS#8 key").into());
+ }
+
+ let mut store = Memory::new()?.into_store();
+ let mut cert_iter = pem::PemBlock::new(pem).into_iter();
+ let leaf = cert_iter.next().ok_or_else(|| {
+ io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "at least one certificate must be provided to create an identity",
+ )
+ })?;
+ let cert = CertContext::from_pem(std::str::from_utf8(leaf).map_err(|_| {
+ io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "leaf cert contains invalid utf8",
+ )
+ })?)?;
+
+ let name = gen_container_name();
+ let mut options = AcquireOptions::new();
+ options.container(&name);
+ let type_ = ProviderType::rsa_full();
+
+ let mut container = match options.acquire(type_) {
+ Ok(container) => container,
+ Err(_) => options.new_keyset(true).acquire(type_)?,
+ };
+ container.import().import_pkcs8_pem(&key)?;
+
+ cert.set_key_prov_info()
+ .container(&name)
+ .type_(type_)
+ .keep_open(true)
+ .key_spec(KeySpec::key_exchange())
+ .set()?;
+ let mut context = store.add_cert(&cert, CertAdd::Always)?;
+
+ for int_cert in cert_iter {
+ let certificate = Certificate::from_pem(int_cert)?;
+ context = store.add_cert(&certificate.0, CertAdd::Always)?;
+ }
+ Ok(Identity { cert: context })
+ }
+}
+
+// The name of the container must be unique to have multiple active keys.
+fn gen_container_name() -> String {
+ use std::sync::atomic::{AtomicUsize, Ordering};
+ static COUNTER: AtomicUsize = AtomicUsize::new(0);
+ format!("native-tls-{}", COUNTER.fetch_add(1, Ordering::Relaxed))
+}
+
+#[derive(Clone)]
+pub struct Certificate(CertContext);
+
+impl Certificate {
+ pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
+ let cert = CertContext::new(buf)?;
+ Ok(Certificate(cert))
+ }
+
+ pub fn from_pem(buf: &[u8]) -> Result<Certificate, Error> {
+ match str::from_utf8(buf) {
+ Ok(s) => {
+ let cert = CertContext::from_pem(s)?;
+ Ok(Certificate(cert))
+ }
+ Err(_) => Err(io::Error::new(
+ io::ErrorKind::InvalidInput,
+ "PEM representation contains non-UTF-8 bytes",
+ )
+ .into()),
+ }
+ }
+
+ pub fn to_der(&self) -> Result<Vec<u8>, Error> {
+ Ok(self.0.to_der().to_vec())
+ }
+}
+
+pub struct MidHandshakeTlsStream<S>(tls_stream::MidHandshakeTlsStream<S>);
+
+impl<S> fmt::Debug for MidHandshakeTlsStream<S>
+where
+ S: fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl<S> MidHandshakeTlsStream<S> {
+ pub fn get_ref(&self) -> &S {
+ self.0.get_ref()
+ }
+
+ pub fn get_mut(&mut self) -> &mut S {
+ self.0.get_mut()
+ }
+}
+
+impl<S> MidHandshakeTlsStream<S>
+where
+ S: io::Read + io::Write,
+{
+ pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
+ match self.0.handshake() {
+ Ok(s) => Ok(TlsStream(s)),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+pub enum HandshakeError<S> {
+ Failure(Error),
+ WouldBlock(MidHandshakeTlsStream<S>),
+}
+
+impl<S> From<tls_stream::HandshakeError<S>> for HandshakeError<S> {
+ fn from(e: tls_stream::HandshakeError<S>) -> HandshakeError<S> {
+ match e {
+ tls_stream::HandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
+ tls_stream::HandshakeError::Interrupted(s) => {
+ HandshakeError::WouldBlock(MidHandshakeTlsStream(s))
+ }
+ }
+ }
+}
+
+impl<S> From<io::Error> for HandshakeError<S> {
+ fn from(e: io::Error) -> HandshakeError<S> {
+ HandshakeError::Failure(e.into())
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct TlsConnector {
+ cert: Option<CertContext>,
+ roots: CertStore,
+ min_protocol: Option<::Protocol>,
+ max_protocol: Option<::Protocol>,
+ use_sni: bool,
+ accept_invalid_hostnames: bool,
+ accept_invalid_certs: bool,
+ disable_built_in_roots: bool,
+ #[cfg(feature = "alpn")]
+ alpn: Vec<String>,
+}
+
+impl TlsConnector {
+ pub fn new(builder: &TlsConnectorBuilder) -> Result<TlsConnector, Error> {
+ let cert = builder.identity.as_ref().map(|i| i.0.cert.clone());
+ let mut roots = Memory::new()?.into_store();
+ for cert in &builder.root_certificates {
+ roots.add_cert(&(cert.0).0, CertAdd::ReplaceExisting)?;
+ }
+
+ Ok(TlsConnector {
+ cert,
+ roots,
+ min_protocol: builder.min_protocol,
+ max_protocol: builder.max_protocol,
+ use_sni: builder.use_sni,
+ accept_invalid_hostnames: builder.accept_invalid_hostnames,
+ accept_invalid_certs: builder.accept_invalid_certs,
+ disable_built_in_roots: builder.disable_built_in_roots,
+ #[cfg(feature = "alpn")]
+ alpn: builder.alpn.clone(),
+ })
+ }
+
+ pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
+ where
+ S: io::Read + io::Write,
+ {
+ let mut builder = SchannelCred::builder();
+ builder.enabled_protocols(convert_protocols(self.min_protocol, self.max_protocol));
+ if let Some(cert) = self.cert.as_ref() {
+ builder.cert(cert.clone());
+ }
+ let cred = builder.acquire(Direction::Outbound)?;
+ let mut builder = tls_stream::Builder::new();
+ builder
+ .cert_store(self.roots.clone())
+ .domain(domain)
+ .use_sni(self.use_sni)
+ .accept_invalid_hostnames(self.accept_invalid_hostnames);
+ if self.accept_invalid_certs {
+ builder.verify_callback(|_| Ok(()));
+ } else if self.disable_built_in_roots {
+ let roots_copy = self.roots.clone();
+ builder.verify_callback(move |res| {
+ if let Err(err) = res.result() {
+ // Propagate previous error encountered during normal cert validation.
+ return Err(err);
+ }
+
+ if let Some(chain) = res.chain() {
+ if chain
+ .certificates()
+ .any(|cert| roots_copy.certs().any(|root_cert| root_cert == cert))
+ {
+ return Ok(());
+ }
+ }
+
+ Err(io::Error::new(
+ io::ErrorKind::Other,
+ "unable to find any user-specified roots in the final cert chain",
+ ))
+ });
+ }
+ #[cfg(feature = "alpn")]
+ {
+ if !self.alpn.is_empty() {
+ builder.request_application_protocols(
+ &self.alpn.iter().map(|s| s.as_bytes()).collect::<Vec<_>>(),
+ );
+ }
+ }
+ match builder.connect(cred, stream) {
+ Ok(s) => Ok(TlsStream(s)),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct TlsAcceptor {
+ cert: CertContext,
+ min_protocol: Option<::Protocol>,
+ max_protocol: Option<::Protocol>,
+}
+
+impl TlsAcceptor {
+ pub fn new(builder: &TlsAcceptorBuilder) -> Result<TlsAcceptor, Error> {
+ Ok(TlsAcceptor {
+ cert: builder.identity.0.cert.clone(),
+ min_protocol: builder.min_protocol,
+ max_protocol: builder.max_protocol,
+ })
+ }
+
+ pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
+ where
+ S: io::Read + io::Write,
+ {
+ let mut builder = SchannelCred::builder();
+ builder.enabled_protocols(convert_protocols(self.min_protocol, self.max_protocol));
+ builder.cert(self.cert.clone());
+ // FIXME we're probably missing the certificate chain?
+ let cred = builder.acquire(Direction::Inbound)?;
+ match tls_stream::Builder::new().accept(cred, stream) {
+ Ok(s) => Ok(TlsStream(s)),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+pub struct TlsStream<S>(tls_stream::TlsStream<S>);
+
+impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl<S> TlsStream<S> {
+ pub fn get_ref(&self) -> &S {
+ self.0.get_ref()
+ }
+
+ pub fn get_mut(&mut self) -> &mut S {
+ self.0.get_mut()
+ }
+}
+
+impl<S: io::Read + io::Write> TlsStream<S> {
+ pub fn buffered_read_size(&self) -> Result<usize, Error> {
+ Ok(self.0.get_buf().len())
+ }
+
+ pub fn peer_certificate(&self) -> Result<Option<Certificate>, Error> {
+ match self.0.peer_certificate() {
+ Ok(cert) => Ok(Some(Certificate(cert))),
+ Err(ref e) if e.raw_os_error() == Some(SEC_E_NO_CREDENTIALS as i32) => Ok(None),
+ Err(e) => Err(Error(e)),
+ }
+ }
+
+ #[cfg(feature = "alpn")]
+ pub fn negotiated_alpn(&self) -> Result<Option<Vec<u8>>, Error> {
+ Ok(self.0.negotiated_application_protocol()?)
+ }
+
+ pub fn tls_server_end_point(&self) -> Result<Option<Vec<u8>>, Error> {
+ let cert = if self.0.is_server() {
+ self.0.certificate()
+ } else {
+ self.0.peer_certificate()
+ };
+
+ let cert = match cert {
+ Ok(cert) => cert,
+ Err(ref e) if e.raw_os_error() == Some(SEC_E_NO_CREDENTIALS as i32) => return Ok(None),
+ Err(e) => return Err(Error(e)),
+ };
+
+ let signature_algorithms = cert.sign_hash_algorithms()?;
+ let hash = match signature_algorithms.rsplit('/').next().unwrap() {
+ "MD5" | "SHA1" | "SHA256" => HashAlgorithm::sha256(),
+ "SHA384" => HashAlgorithm::sha384(),
+ "SHA512" => HashAlgorithm::sha512(),
+ _ => return Ok(None),
+ };
+
+ let digest = cert.fingerprint(hash)?;
+ Ok(Some(digest))
+ }
+
+ pub fn shutdown(&mut self) -> io::Result<()> {
+ self.0.shutdown()?;
+ Ok(())
+ }
+}
+
+impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+}
+
+impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.0.flush()
+ }
+}
+
+mod pem {
+ /// Split data by PEM guard lines
+ pub struct PemBlock<'a> {
+ pem_block: &'a str,
+ cur_end: usize,
+ }
+
+ impl<'a> PemBlock<'a> {
+ pub fn new(data: &'a [u8]) -> PemBlock<'a> {
+ let s = ::std::str::from_utf8(data).unwrap();
+ PemBlock {
+ pem_block: s,
+ cur_end: s.find("-----BEGIN").unwrap_or(s.len()),
+ }
+ }
+ }
+
+ impl<'a> Iterator for PemBlock<'a> {
+ type Item = &'a [u8];
+ fn next(&mut self) -> Option<Self::Item> {
+ let last = self.pem_block.len();
+ if self.cur_end >= last {
+ return None;
+ }
+ let begin = self.cur_end;
+ let pos = self.pem_block[begin + 1..].find("-----BEGIN");
+ self.cur_end = match pos {
+ Some(end) => end + begin + 1,
+ None => last,
+ };
+ return Some(&self.pem_block[begin..self.cur_end].as_bytes());
+ }
+ }
+
+ #[test]
+ fn test_split() {
+ // Split three certs, CRLF line terminators.
+ assert_eq!(
+ PemBlock::new(
+ b"-----BEGIN FIRST-----\r\n-----END FIRST-----\r\n\
+ -----BEGIN SECOND-----\r\n-----END SECOND\r\n\
+ -----BEGIN THIRD-----\r\n-----END THIRD\r\n"
+ )
+ .collect::<Vec<&[u8]>>(),
+ vec![
+ b"-----BEGIN FIRST-----\r\n-----END FIRST-----\r\n" as &[u8],
+ b"-----BEGIN SECOND-----\r\n-----END SECOND\r\n",
+ b"-----BEGIN THIRD-----\r\n-----END THIRD\r\n"
+ ]
+ );
+ // Split three certs, CRLF line terminators except at EOF.
+ assert_eq!(
+ PemBlock::new(
+ b"-----BEGIN FIRST-----\r\n-----END FIRST-----\r\n\
+ -----BEGIN SECOND-----\r\n-----END SECOND-----\r\n\
+ -----BEGIN THIRD-----\r\n-----END THIRD-----"
+ )
+ .collect::<Vec<&[u8]>>(),
+ vec![
+ b"-----BEGIN FIRST-----\r\n-----END FIRST-----\r\n" as &[u8],
+ b"-----BEGIN SECOND-----\r\n-----END SECOND-----\r\n",
+ b"-----BEGIN THIRD-----\r\n-----END THIRD-----"
+ ]
+ );
+ // Split two certs, LF line terminators.
+ assert_eq!(
+ PemBlock::new(
+ b"-----BEGIN FIRST-----\n-----END FIRST-----\n\
+ -----BEGIN SECOND-----\n-----END SECOND\n"
+ )
+ .collect::<Vec<&[u8]>>(),
+ vec![
+ b"-----BEGIN FIRST-----\n-----END FIRST-----\n" as &[u8],
+ b"-----BEGIN SECOND-----\n-----END SECOND\n"
+ ]
+ );
+ // Split two certs, CR line terminators.
+ assert_eq!(
+ PemBlock::new(
+ b"-----BEGIN FIRST-----\r-----END FIRST-----\r\
+ -----BEGIN SECOND-----\r-----END SECOND\r"
+ )
+ .collect::<Vec<&[u8]>>(),
+ vec![
+ b"-----BEGIN FIRST-----\r-----END FIRST-----\r" as &[u8],
+ b"-----BEGIN SECOND-----\r-----END SECOND\r"
+ ]
+ );
+ // Split two certs, LF line terminators except at EOF.
+ assert_eq!(
+ PemBlock::new(
+ b"-----BEGIN FIRST-----\n-----END FIRST-----\n\
+ -----BEGIN SECOND-----\n-----END SECOND"
+ )
+ .collect::<Vec<&[u8]>>(),
+ vec![
+ b"-----BEGIN FIRST-----\n-----END FIRST-----\n" as &[u8],
+ b"-----BEGIN SECOND-----\n-----END SECOND"
+ ]
+ );
+ // Split a single cert, LF line terminators.
+ assert_eq!(
+ PemBlock::new(b"-----BEGIN FIRST-----\n-----END FIRST-----\n").collect::<Vec<&[u8]>>(),
+ vec![b"-----BEGIN FIRST-----\n-----END FIRST-----\n" as &[u8]]
+ );
+ // Split a single cert, LF line terminators except at EOF.
+ assert_eq!(
+ PemBlock::new(b"-----BEGIN FIRST-----\n-----END FIRST-----").collect::<Vec<&[u8]>>(),
+ vec![b"-----BEGIN FIRST-----\n-----END FIRST-----" as &[u8]]
+ );
+ // (Don't) split garbage.
+ assert_eq!(
+ PemBlock::new(b"junk").collect::<Vec<&[u8]>>(),
+ Vec::<&[u8]>::new()
+ );
+ assert_eq!(
+ PemBlock::new(b"junk-----BEGIN garbage").collect::<Vec<&[u8]>>(),
+ vec![b"-----BEGIN garbage" as &[u8]]
+ );
+ }
+}
diff --git a/vendor/native-tls/src/imp/security_framework.rs b/vendor/native-tls/src/imp/security_framework.rs
new file mode 100644
index 000000000..0b4177228
--- /dev/null
+++ b/vendor/native-tls/src/imp/security_framework.rs
@@ -0,0 +1,632 @@
+extern crate libc;
+extern crate security_framework;
+extern crate security_framework_sys;
+extern crate tempfile;
+
+use self::security_framework::base;
+use self::security_framework::certificate::SecCertificate;
+use self::security_framework::identity::SecIdentity;
+use self::security_framework::import_export::{ImportedIdentity, Pkcs12ImportOptions};
+use self::security_framework::random::SecRandom;
+use self::security_framework::secure_transport::{
+ self, ClientBuilder, SslConnectionType, SslContext, SslProtocol, SslProtocolSide,
+};
+use self::security_framework_sys::base::{errSecIO, errSecParam};
+use self::tempfile::TempDir;
+use std::error;
+use std::fmt;
+use std::io;
+use std::str;
+use std::sync::Mutex;
+use std::sync::Once;
+
+#[cfg(not(target_os = "ios"))]
+use self::security_framework::os::macos::certificate::{PropertyType, SecCertificateExt};
+#[cfg(not(target_os = "ios"))]
+use self::security_framework::os::macos::certificate_oids::CertificateOid;
+#[cfg(not(target_os = "ios"))]
+use self::security_framework::os::macos::identity::SecIdentityExt;
+#[cfg(not(target_os = "ios"))]
+use self::security_framework::os::macos::import_export::{
+ ImportOptions, Pkcs12ImportOptionsExt, SecItems,
+};
+#[cfg(not(target_os = "ios"))]
+use self::security_framework::os::macos::keychain::{self, KeychainSettings, SecKeychain};
+
+use {Protocol, TlsAcceptorBuilder, TlsConnectorBuilder};
+
+static SET_AT_EXIT: Once = Once::new();
+
+#[cfg(not(target_os = "ios"))]
+lazy_static! {
+ static ref TEMP_KEYCHAIN: Mutex<Option<(SecKeychain, TempDir)>> = Mutex::new(None);
+}
+
+fn convert_protocol(protocol: Protocol) -> SslProtocol {
+ match protocol {
+ Protocol::Sslv3 => SslProtocol::SSL3,
+ Protocol::Tlsv10 => SslProtocol::TLS1,
+ Protocol::Tlsv11 => SslProtocol::TLS11,
+ Protocol::Tlsv12 => SslProtocol::TLS12,
+ Protocol::__NonExhaustive => unreachable!(),
+ }
+}
+
+pub struct Error(base::Error);
+
+impl error::Error for Error {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ error::Error::source(&self.0)
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, fmt)
+ }
+}
+
+impl fmt::Debug for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl From<base::Error> for Error {
+ fn from(error: base::Error) -> Error {
+ Error(error)
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Identity {
+ identity: SecIdentity,
+ chain: Vec<SecCertificate>,
+}
+
+impl Identity {
+ #[cfg(target_os = "ios")]
+ pub fn from_pkcs8(_: &[u8], _: &[u8]) -> Result<Identity, Error> {
+ panic!("Not implemented on iOS");
+ }
+
+ #[cfg(not(target_os = "ios"))]
+ pub fn from_pkcs8(pem: &[u8], key: &[u8]) -> Result<Identity, Error> {
+ if !key.starts_with(b"-----BEGIN PRIVATE KEY-----") {
+ return Err(Error(base::Error::from(errSecParam)));
+ }
+
+ let dir = TempDir::new().map_err(|_| Error(base::Error::from(errSecIO)))?;
+ let keychain = keychain::CreateOptions::new()
+ .password(&random_password()?)
+ .create(dir.path().join("identity.keychain"))?;
+
+ let mut items = SecItems::default();
+
+ ImportOptions::new()
+ .filename("key.pem")
+ .items(&mut items)
+ .keychain(&keychain)
+ .import(&key)?;
+
+ ImportOptions::new()
+ .filename("chain.pem")
+ .items(&mut items)
+ .keychain(&keychain)
+ .import(&pem)?;
+
+ let cert = items
+ .certificates
+ .get(0)
+ .ok_or_else(|| Error(base::Error::from(errSecParam)))?;
+ let ident = SecIdentity::with_certificate(&[keychain], cert)?;
+ Ok(Identity {
+ identity: ident,
+ chain: items.certificates,
+ })
+ }
+
+ pub fn from_pkcs12(buf: &[u8], pass: &str) -> Result<Identity, Error> {
+ let mut imports = Identity::import_options(buf, pass)?;
+ let import = imports.pop().unwrap();
+
+ let identity = import
+ .identity
+ .expect("Pkcs12 files must include an identity");
+
+ // FIXME: Compare the certificates for equality using CFEqual
+ let identity_cert = identity.certificate()?.to_der();
+
+ Ok(Identity {
+ identity,
+ chain: import
+ .cert_chain
+ .unwrap_or(vec![])
+ .into_iter()
+ .filter(|c| c.to_der() != identity_cert)
+ .collect(),
+ })
+ }
+
+ #[cfg(not(target_os = "ios"))]
+ fn import_options(buf: &[u8], pass: &str) -> Result<Vec<ImportedIdentity>, Error> {
+ SET_AT_EXIT.call_once(|| {
+ extern "C" fn atexit() {
+ *TEMP_KEYCHAIN.lock().unwrap() = None;
+ }
+ unsafe {
+ libc::atexit(atexit);
+ }
+ });
+
+ let keychain = match *TEMP_KEYCHAIN.lock().unwrap() {
+ Some((ref keychain, _)) => keychain.clone(),
+ ref mut lock @ None => {
+ let dir = TempDir::new().map_err(|_| Error(base::Error::from(errSecIO)))?;
+
+ let mut keychain = keychain::CreateOptions::new()
+ .password(pass)
+ .create(dir.path().join("tmp.keychain"))?;
+ keychain.set_settings(&KeychainSettings::new())?;
+
+ *lock = Some((keychain.clone(), dir));
+ keychain
+ }
+ };
+ let mut import_opts = Pkcs12ImportOptions::new();
+ // Method shadowed by deprecated method.
+ <Pkcs12ImportOptions as Pkcs12ImportOptionsExt>::keychain(&mut import_opts, keychain);
+ let imports = import_opts.passphrase(pass).import(buf)?;
+ Ok(imports)
+ }
+
+ #[cfg(target_os = "ios")]
+ fn import_options(buf: &[u8], pass: &str) -> Result<Vec<ImportedIdentity>, Error> {
+ let imports = Pkcs12ImportOptions::new().passphrase(pass).import(buf)?;
+ Ok(imports)
+ }
+}
+
+fn random_password() -> Result<String, Error> {
+ use std::fmt::Write;
+ let mut bytes = [0_u8; 10];
+ SecRandom::default()
+ .copy_bytes(&mut bytes)
+ .map_err(|_| Error(base::Error::from(errSecIO)))?;
+ let mut s = String::with_capacity(2 * bytes.len());
+ for byte in bytes {
+ write!(s, "{:02X}", byte).map_err(|_| Error(base::Error::from(errSecIO)))?;
+ }
+ Ok(s)
+}
+
+#[derive(Clone)]
+pub struct Certificate(SecCertificate);
+
+impl Certificate {
+ pub fn from_der(buf: &[u8]) -> Result<Certificate, Error> {
+ let cert = SecCertificate::from_der(buf)?;
+ Ok(Certificate(cert))
+ }
+
+ #[cfg(not(target_os = "ios"))]
+ pub fn from_pem(buf: &[u8]) -> Result<Certificate, Error> {
+ let mut items = SecItems::default();
+ ImportOptions::new().items(&mut items).import(buf)?;
+ if items.certificates.len() == 1 && items.identities.is_empty() && items.keys.is_empty() {
+ Ok(Certificate(items.certificates.pop().unwrap()))
+ } else {
+ Err(Error(base::Error::from(errSecParam)))
+ }
+ }
+
+ #[cfg(target_os = "ios")]
+ pub fn from_pem(_: &[u8]) -> Result<Certificate, Error> {
+ panic!("Not implemented on iOS");
+ }
+
+ pub fn to_der(&self) -> Result<Vec<u8>, Error> {
+ Ok(self.0.to_der())
+ }
+}
+
+pub enum HandshakeError<S> {
+ WouldBlock(MidHandshakeTlsStream<S>),
+ Failure(Error),
+}
+
+impl<S> From<secure_transport::ClientHandshakeError<S>> for HandshakeError<S> {
+ fn from(e: secure_transport::ClientHandshakeError<S>) -> HandshakeError<S> {
+ match e {
+ secure_transport::ClientHandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
+ secure_transport::ClientHandshakeError::Interrupted(s) => {
+ HandshakeError::WouldBlock(MidHandshakeTlsStream::Client(s))
+ }
+ }
+ }
+}
+
+impl<S> From<base::Error> for HandshakeError<S> {
+ fn from(e: base::Error) -> HandshakeError<S> {
+ HandshakeError::Failure(e.into())
+ }
+}
+
+pub enum MidHandshakeTlsStream<S> {
+ Server(
+ secure_transport::MidHandshakeSslStream<S>,
+ Option<SecCertificate>,
+ ),
+ Client(secure_transport::MidHandshakeClientBuilder<S>),
+}
+
+impl<S> fmt::Debug for MidHandshakeTlsStream<S>
+where
+ S: fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ MidHandshakeTlsStream::Server(ref s, _) => s.fmt(fmt),
+ MidHandshakeTlsStream::Client(ref s) => s.fmt(fmt),
+ }
+ }
+}
+
+impl<S> MidHandshakeTlsStream<S> {
+ pub fn get_ref(&self) -> &S {
+ match *self {
+ MidHandshakeTlsStream::Server(ref s, _) => s.get_ref(),
+ MidHandshakeTlsStream::Client(ref s) => s.get_ref(),
+ }
+ }
+
+ pub fn get_mut(&mut self) -> &mut S {
+ match *self {
+ MidHandshakeTlsStream::Server(ref mut s, _) => s.get_mut(),
+ MidHandshakeTlsStream::Client(ref mut s) => s.get_mut(),
+ }
+ }
+}
+
+impl<S> MidHandshakeTlsStream<S>
+where
+ S: io::Read + io::Write,
+{
+ pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
+ match self {
+ MidHandshakeTlsStream::Server(s, cert) => match s.handshake() {
+ Ok(stream) => Ok(TlsStream { stream, cert }),
+ Err(secure_transport::HandshakeError::Failure(e)) => {
+ Err(HandshakeError::Failure(Error(e)))
+ }
+ Err(secure_transport::HandshakeError::Interrupted(s)) => Err(
+ HandshakeError::WouldBlock(MidHandshakeTlsStream::Server(s, cert)),
+ ),
+ },
+ MidHandshakeTlsStream::Client(s) => match s.handshake() {
+ Ok(stream) => Ok(TlsStream { stream, cert: None }),
+ Err(e) => Err(e.into()),
+ },
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct TlsConnector {
+ identity: Option<Identity>,
+ min_protocol: Option<Protocol>,
+ max_protocol: Option<Protocol>,
+ roots: Vec<SecCertificate>,
+ use_sni: bool,
+ danger_accept_invalid_hostnames: bool,
+ danger_accept_invalid_certs: bool,
+ disable_built_in_roots: bool,
+ #[cfg(feature = "alpn")]
+ alpn: Vec<String>,
+}
+
+impl TlsConnector {
+ pub fn new(builder: &TlsConnectorBuilder) -> Result<TlsConnector, Error> {
+ Ok(TlsConnector {
+ identity: builder.identity.as_ref().map(|i| i.0.clone()),
+ min_protocol: builder.min_protocol,
+ max_protocol: builder.max_protocol,
+ roots: builder
+ .root_certificates
+ .iter()
+ .map(|c| (c.0).0.clone())
+ .collect(),
+ use_sni: builder.use_sni,
+ danger_accept_invalid_hostnames: builder.accept_invalid_hostnames,
+ danger_accept_invalid_certs: builder.accept_invalid_certs,
+ disable_built_in_roots: builder.disable_built_in_roots,
+ #[cfg(feature = "alpn")]
+ alpn: builder.alpn.clone(),
+ })
+ }
+
+ pub fn connect<S>(&self, domain: &str, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
+ where
+ S: io::Read + io::Write,
+ {
+ let mut builder = ClientBuilder::new();
+ if let Some(min) = self.min_protocol {
+ builder.protocol_min(convert_protocol(min));
+ }
+ if let Some(max) = self.max_protocol {
+ builder.protocol_max(convert_protocol(max));
+ }
+ if let Some(identity) = self.identity.as_ref() {
+ builder.identity(&identity.identity, &identity.chain);
+ }
+ builder.anchor_certificates(&self.roots);
+ builder.use_sni(self.use_sni);
+ builder.danger_accept_invalid_hostnames(self.danger_accept_invalid_hostnames);
+ builder.danger_accept_invalid_certs(self.danger_accept_invalid_certs);
+ builder.trust_anchor_certificates_only(self.disable_built_in_roots);
+
+ #[cfg(feature = "alpn")]
+ {
+ if !self.alpn.is_empty() {
+ builder.alpn_protocols(&self.alpn.iter().map(String::as_str).collect::<Vec<_>>());
+ }
+ }
+
+ match builder.handshake(domain, stream) {
+ Ok(stream) => Ok(TlsStream { stream, cert: None }),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct TlsAcceptor {
+ identity: Identity,
+ min_protocol: Option<Protocol>,
+ max_protocol: Option<Protocol>,
+}
+
+impl TlsAcceptor {
+ pub fn new(builder: &TlsAcceptorBuilder) -> Result<TlsAcceptor, Error> {
+ Ok(TlsAcceptor {
+ identity: builder.identity.0.clone(),
+ min_protocol: builder.min_protocol,
+ max_protocol: builder.max_protocol,
+ })
+ }
+
+ pub fn accept<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
+ where
+ S: io::Read + io::Write,
+ {
+ let mut ctx = SslContext::new(SslProtocolSide::SERVER, SslConnectionType::STREAM)?;
+
+ if let Some(min) = self.min_protocol {
+ ctx.set_protocol_version_min(convert_protocol(min))?;
+ }
+ if let Some(max) = self.max_protocol {
+ ctx.set_protocol_version_max(convert_protocol(max))?;
+ }
+ ctx.set_certificate(&self.identity.identity, &self.identity.chain)?;
+ let cert = Some(self.identity.identity.certificate()?);
+ match ctx.handshake(stream) {
+ Ok(stream) => Ok(TlsStream { stream, cert }),
+ Err(secure_transport::HandshakeError::Failure(e)) => {
+ Err(HandshakeError::Failure(Error(e)))
+ }
+ Err(secure_transport::HandshakeError::Interrupted(s)) => Err(
+ HandshakeError::WouldBlock(MidHandshakeTlsStream::Server(s, cert)),
+ ),
+ }
+ }
+}
+
+pub struct TlsStream<S> {
+ stream: secure_transport::SslStream<S>,
+ cert: Option<SecCertificate>,
+}
+
+impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.stream, fmt)
+ }
+}
+
+impl<S> TlsStream<S> {
+ pub fn get_ref(&self) -> &S {
+ self.stream.get_ref()
+ }
+
+ pub fn get_mut(&mut self) -> &mut S {
+ self.stream.get_mut()
+ }
+}
+
+impl<S: io::Read + io::Write> TlsStream<S> {
+ pub fn buffered_read_size(&self) -> Result<usize, Error> {
+ Ok(self.stream.context().buffered_read_size()?)
+ }
+
+ #[allow(deprecated)]
+ pub fn peer_certificate(&self) -> Result<Option<Certificate>, Error> {
+ let trust = match self.stream.context().peer_trust2()? {
+ Some(trust) => trust,
+ None => return Ok(None),
+ };
+ trust.evaluate()?;
+
+ Ok(trust.certificate_at_index(0).map(Certificate))
+ }
+
+ #[cfg(feature = "alpn")]
+ pub fn negotiated_alpn(&self) -> Result<Option<Vec<u8>>, Error> {
+ match self.stream.context().alpn_protocols() {
+ Ok(protocols) => {
+ // Per RFC7301, "ProtocolNameList" MUST contain exactly one "ProtocolName".
+ assert!(protocols.len() < 2);
+
+ if protocols.is_empty() {
+ // Not sure this is actually possible.
+ Ok(None)
+ } else {
+ Ok(Some(protocols.into_iter().next().unwrap().into_bytes()))
+ }
+ }
+ // The macOS API appears to return `errSecParam` whenever no ALPN was negotiated, both
+ // when it isn't attempted and when it isn't successful.
+ Err(e) if e.code() == errSecParam => Ok(None),
+ Err(other) => Err(Error::from(other)),
+ }
+ }
+
+ #[cfg(target_os = "ios")]
+ pub fn tls_server_end_point(&self) -> Result<Option<Vec<u8>>, Error> {
+ Ok(None)
+ }
+
+ #[cfg(not(target_os = "ios"))]
+ pub fn tls_server_end_point(&self) -> Result<Option<Vec<u8>>, Error> {
+ let cert = match self.cert {
+ Some(ref cert) => cert.clone(),
+ None => match self.peer_certificate()? {
+ Some(cert) => cert.0,
+ None => return Ok(None),
+ },
+ };
+
+ let property = match cert
+ .properties(Some(&[CertificateOid::x509_v1_signature_algorithm()]))
+ .ok()
+ .and_then(|p| p.get(CertificateOid::x509_v1_signature_algorithm()))
+ {
+ Some(property) => property,
+ None => return Ok(None),
+ };
+
+ let section = match property.get() {
+ PropertyType::Section(section) => section,
+ _ => return Ok(None),
+ };
+
+ let algorithm = match section
+ .iter()
+ .filter(|p| p.label().to_string() == "Algorithm")
+ .next()
+ {
+ Some(property) => property,
+ None => return Ok(None),
+ };
+
+ let algorithm = match algorithm.get() {
+ PropertyType::String(algorithm) => algorithm,
+ _ => return Ok(None),
+ };
+
+ let digest = match &*algorithm.to_string() {
+ // MD5
+ "1.2.840.113549.2.5" | "1.2.840.113549.1.1.4" | "1.3.14.3.2.3" => Digest::Sha256,
+ // SHA-1
+ "1.3.14.3.2.26"
+ | "1.3.14.3.2.15"
+ | "1.2.840.113549.1.1.5"
+ | "1.3.14.3.2.29"
+ | "1.2.840.10040.4.3"
+ | "1.3.14.3.2.13"
+ | "1.2.840.10045.4.1" => Digest::Sha256,
+ // SHA-224
+ "2.16.840.1.101.3.4.2.4"
+ | "1.2.840.113549.1.1.14"
+ | "2.16.840.1.101.3.4.3.1"
+ | "1.2.840.10045.4.3.1" => Digest::Sha224,
+ // SHA-256
+ "2.16.840.1.101.3.4.2.1" | "1.2.840.113549.1.1.11" | "1.2.840.10045.4.3.2" => {
+ Digest::Sha256
+ }
+ // SHA-384
+ "2.16.840.1.101.3.4.2.2" | "1.2.840.113549.1.1.12" | "1.2.840.10045.4.3.3" => {
+ Digest::Sha384
+ }
+ // SHA-512
+ "2.16.840.1.101.3.4.2.3" | "1.2.840.113549.1.1.13" | "1.2.840.10045.4.3.4" => {
+ Digest::Sha512
+ }
+ _ => return Ok(None),
+ };
+
+ let der = cert.to_der();
+ Ok(Some(digest.hash(&der)))
+ }
+
+ pub fn shutdown(&mut self) -> io::Result<()> {
+ self.stream.close()?;
+ Ok(())
+ }
+}
+
+impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.stream.read(buf)
+ }
+}
+
+impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.stream.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.stream.flush()
+ }
+}
+
+enum Digest {
+ Sha224,
+ Sha256,
+ Sha384,
+ Sha512,
+}
+
+impl Digest {
+ fn hash(&self, data: &[u8]) -> Vec<u8> {
+ unsafe {
+ assert!(data.len() <= CC_LONG::max_value() as usize);
+ match *self {
+ Digest::Sha224 => {
+ let mut buf = [0; CC_SHA224_DIGEST_LENGTH];
+ CC_SHA224(data.as_ptr(), data.len() as CC_LONG, buf.as_mut_ptr());
+ buf.to_vec()
+ }
+ Digest::Sha256 => {
+ let mut buf = [0; CC_SHA256_DIGEST_LENGTH];
+ CC_SHA256(data.as_ptr(), data.len() as CC_LONG, buf.as_mut_ptr());
+ buf.to_vec()
+ }
+ Digest::Sha384 => {
+ let mut buf = [0; CC_SHA384_DIGEST_LENGTH];
+ CC_SHA384(data.as_ptr(), data.len() as CC_LONG, buf.as_mut_ptr());
+ buf.to_vec()
+ }
+ Digest::Sha512 => {
+ let mut buf = [0; CC_SHA512_DIGEST_LENGTH];
+ CC_SHA512(data.as_ptr(), data.len() as CC_LONG, buf.as_mut_ptr());
+ buf.to_vec()
+ }
+ }
+ }
+ }
+}
+
+// FIXME ideally we'd pull these in from elsewhere
+const CC_SHA224_DIGEST_LENGTH: usize = 28;
+const CC_SHA256_DIGEST_LENGTH: usize = 32;
+const CC_SHA384_DIGEST_LENGTH: usize = 48;
+const CC_SHA512_DIGEST_LENGTH: usize = 64;
+#[allow(non_camel_case_types)]
+type CC_LONG = u32;
+
+extern "C" {
+ fn CC_SHA224(data: *const u8, len: CC_LONG, md: *mut u8) -> *mut u8;
+ fn CC_SHA256(data: *const u8, len: CC_LONG, md: *mut u8) -> *mut u8;
+ fn CC_SHA384(data: *const u8, len: CC_LONG, md: *mut u8) -> *mut u8;
+ fn CC_SHA512(data: *const u8, len: CC_LONG, md: *mut u8) -> *mut u8;
+}
diff --git a/vendor/native-tls/src/lib.rs b/vendor/native-tls/src/lib.rs
new file mode 100644
index 000000000..8b7415394
--- /dev/null
+++ b/vendor/native-tls/src/lib.rs
@@ -0,0 +1,721 @@
+//! An abstraction over platform-specific TLS implementations.
+//!
+//! Many applications require TLS/SSL communication in one form or another as
+//! part of their implementation, but finding a library for this isn't always
+//! trivial! The purpose of this crate is to provide a seamless integration
+//! experience on all platforms with a cross-platform API that deals with all
+//! the underlying details for you.
+//!
+//! # How is this implemented?
+//!
+//! This crate uses SChannel on Windows (via the `schannel` crate), Secure
+//! Transport on OSX (via the `security-framework` crate), and OpenSSL (via the
+//! `openssl` crate) on all other platforms. Future features may also enable
+//! other TLS frameworks as well, but these initial libraries are likely to
+//! remain as the defaults.
+//!
+//! Note that this crate also strives to be secure-by-default. For example when
+//! using OpenSSL it will configure validation callbacks to ensure that
+//! hostnames match certificates, use strong ciphers, etc. This implies that
+//! this crate is *not* just a thin abstraction around the underlying libraries,
+//! but also an implementation that strives to strike reasonable defaults.
+//!
+//! # Supported features
+//!
+//! This crate supports the following features out of the box:
+//!
+//! * TLS/SSL client communication
+//! * TLS/SSL server communication
+//! * PKCS#12 encoded identities
+//! * X.509/PKCS#8 encoded identities
+//! * Secure-by-default for client and server
+//! * Includes hostname verification for clients
+//! * Supports asynchronous I/O for both the server and the client
+//!
+//! # Cargo Features
+//!
+//! * `vendored` - If enabled, the crate will compile and statically link to a
+//! vendored copy of OpenSSL. This feature has no effect on Windows and
+//! macOS, where OpenSSL is not used.
+//!
+//! # Examples
+//!
+//! To connect as a client to a remote server:
+//!
+//! ```rust
+//! use native_tls::TlsConnector;
+//! use std::io::{Read, Write};
+//! use std::net::TcpStream;
+//!
+//! let connector = TlsConnector::new().unwrap();
+//!
+//! let stream = TcpStream::connect("google.com:443").unwrap();
+//! let mut stream = connector.connect("google.com", stream).unwrap();
+//!
+//! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
+//! let mut res = vec![];
+//! stream.read_to_end(&mut res).unwrap();
+//! println!("{}", String::from_utf8_lossy(&res));
+//! ```
+//!
+//! To accept connections as a server from remote clients:
+//!
+//! ```rust,no_run
+//! use native_tls::{Identity, TlsAcceptor, TlsStream};
+//! use std::fs::File;
+//! use std::io::{Read};
+//! use std::net::{TcpListener, TcpStream};
+//! use std::sync::Arc;
+//! use std::thread;
+//!
+//! let mut file = File::open("identity.pfx").unwrap();
+//! let mut identity = vec![];
+//! file.read_to_end(&mut identity).unwrap();
+//! let identity = Identity::from_pkcs12(&identity, "hunter2").unwrap();
+//!
+//! let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
+//! let acceptor = TlsAcceptor::new(identity).unwrap();
+//! let acceptor = Arc::new(acceptor);
+//!
+//! fn handle_client(stream: TlsStream<TcpStream>) {
+//! // ...
+//! }
+//!
+//! for stream in listener.incoming() {
+//! match stream {
+//! Ok(stream) => {
+//! let acceptor = acceptor.clone();
+//! thread::spawn(move || {
+//! let stream = acceptor.accept(stream).unwrap();
+//! handle_client(stream);
+//! });
+//! }
+//! Err(e) => { /* connection failed */ }
+//! }
+//! }
+//! ```
+#![doc(html_root_url = "https://docs.rs/native-tls/0.2")]
+#![warn(missing_docs)]
+#![cfg_attr(docsrs, feature(doc_cfg))]
+
+#[macro_use]
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+extern crate lazy_static;
+
+use std::any::Any;
+use std::error;
+use std::fmt;
+use std::io;
+use std::result;
+
+#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
+#[macro_use]
+extern crate log;
+#[cfg(any(target_os = "macos", target_os = "ios"))]
+#[path = "imp/security_framework.rs"]
+mod imp;
+#[cfg(target_os = "windows")]
+#[path = "imp/schannel.rs"]
+mod imp;
+#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))]
+#[path = "imp/openssl.rs"]
+mod imp;
+
+#[cfg(test)]
+mod test;
+
+/// A typedef of the result-type returned by many methods.
+pub type Result<T> = result::Result<T, Error>;
+
+/// An error returned from the TLS implementation.
+pub struct Error(imp::Error);
+
+impl error::Error for Error {
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ error::Error::source(&self.0)
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.0, fmt)
+ }
+}
+
+impl fmt::Debug for Error {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl From<imp::Error> for Error {
+ fn from(err: imp::Error) -> Error {
+ Error(err)
+ }
+}
+
+/// A cryptographic identity.
+///
+/// An identity is an X509 certificate along with its corresponding private key and chain of certificates to a trusted
+/// root.
+#[derive(Clone)]
+pub struct Identity(imp::Identity);
+
+impl Identity {
+ /// Parses a DER-formatted PKCS #12 archive, using the specified password to decrypt the key.
+ ///
+ /// The archive should contain a leaf certificate and its private key, as well any intermediate
+ /// certificates that should be sent to clients to allow them to build a chain to a trusted
+ /// root. The chain certificates should be in order from the leaf certificate towards the root.
+ ///
+ /// PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can be created
+ /// with the OpenSSL `pkcs12` tool:
+ ///
+ /// ```bash
+ /// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
+ /// ```
+ pub fn from_pkcs12(der: &[u8], password: &str) -> Result<Identity> {
+ let identity = imp::Identity::from_pkcs12(der, password)?;
+ Ok(Identity(identity))
+ }
+
+ /// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first.
+ /// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate.
+ ///
+ /// The certificate chain should contain any intermediate cerficates that should be sent to
+ /// clients to allow them to build a chain to a trusted root.
+ ///
+ /// A certificate chain here means a series of PEM encoded certificates concatenated together.
+ pub fn from_pkcs8(pem: &[u8], key: &[u8]) -> Result<Identity> {
+ let identity = imp::Identity::from_pkcs8(pem, key)?;
+ Ok(Identity(identity))
+ }
+}
+
+/// An X509 certificate.
+#[derive(Clone)]
+pub struct Certificate(imp::Certificate);
+
+impl Certificate {
+ /// Parses a DER-formatted X509 certificate.
+ pub fn from_der(der: &[u8]) -> Result<Certificate> {
+ let cert = imp::Certificate::from_der(der)?;
+ Ok(Certificate(cert))
+ }
+
+ /// Parses a PEM-formatted X509 certificate.
+ pub fn from_pem(pem: &[u8]) -> Result<Certificate> {
+ let cert = imp::Certificate::from_pem(pem)?;
+ Ok(Certificate(cert))
+ }
+
+ /// Returns the DER-encoded representation of this certificate.
+ pub fn to_der(&self) -> Result<Vec<u8>> {
+ let der = self.0.to_der()?;
+ Ok(der)
+ }
+}
+
+/// A TLS stream which has been interrupted midway through the handshake process.
+pub struct MidHandshakeTlsStream<S>(imp::MidHandshakeTlsStream<S>);
+
+impl<S> fmt::Debug for MidHandshakeTlsStream<S>
+where
+ S: fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl<S> MidHandshakeTlsStream<S> {
+ /// Returns a shared reference to the inner stream.
+ pub fn get_ref(&self) -> &S {
+ self.0.get_ref()
+ }
+
+ /// Returns a mutable reference to the inner stream.
+ pub fn get_mut(&mut self) -> &mut S {
+ self.0.get_mut()
+ }
+}
+
+impl<S> MidHandshakeTlsStream<S>
+where
+ S: io::Read + io::Write,
+{
+ /// Restarts the handshake process.
+ ///
+ /// If the handshake completes successfully then the negotiated stream is
+ /// returned. If there is a problem, however, then an error is returned.
+ /// Note that the error may not be fatal. For example if the underlying
+ /// stream is an asynchronous one then `HandshakeError::WouldBlock` may
+ /// just mean to wait for more I/O to happen later.
+ pub fn handshake(self) -> result::Result<TlsStream<S>, HandshakeError<S>> {
+ match self.0.handshake() {
+ Ok(s) => Ok(TlsStream(s)),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+/// An error returned from `ClientBuilder::handshake`.
+#[derive(Debug)]
+pub enum HandshakeError<S> {
+ /// A fatal error.
+ Failure(Error),
+
+ /// A stream interrupted midway through the handshake process due to a
+ /// `WouldBlock` error.
+ ///
+ /// Note that this is not a fatal error and it should be safe to call
+ /// `handshake` at a later time once the stream is ready to perform I/O
+ /// again.
+ WouldBlock(MidHandshakeTlsStream<S>),
+}
+
+impl<S> error::Error for HandshakeError<S>
+where
+ S: Any + fmt::Debug,
+{
+ fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+ match *self {
+ HandshakeError::Failure(ref e) => Some(e),
+ HandshakeError::WouldBlock(_) => None,
+ }
+ }
+}
+
+impl<S> fmt::Display for HandshakeError<S>
+where
+ S: Any + fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ HandshakeError::Failure(ref e) => fmt::Display::fmt(e, fmt),
+ HandshakeError::WouldBlock(_) => fmt.write_str("the handshake process was interrupted"),
+ }
+ }
+}
+
+impl<S> From<imp::HandshakeError<S>> for HandshakeError<S> {
+ fn from(e: imp::HandshakeError<S>) -> HandshakeError<S> {
+ match e {
+ imp::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
+ imp::HandshakeError::WouldBlock(s) => {
+ HandshakeError::WouldBlock(MidHandshakeTlsStream(s))
+ }
+ }
+ }
+}
+
+/// SSL/TLS protocol versions.
+#[derive(Debug, Copy, Clone)]
+pub enum Protocol {
+ /// The SSL 3.0 protocol.
+ ///
+ /// # Warning
+ ///
+ /// SSL 3.0 has severe security flaws, and should not be used unless absolutely necessary. If
+ /// you are not sure if you need to enable this protocol, you should not.
+ Sslv3,
+ /// The TLS 1.0 protocol.
+ Tlsv10,
+ /// The TLS 1.1 protocol.
+ Tlsv11,
+ /// The TLS 1.2 protocol.
+ Tlsv12,
+ #[doc(hidden)]
+ __NonExhaustive,
+}
+
+/// A builder for `TlsConnector`s.
+pub struct TlsConnectorBuilder {
+ identity: Option<Identity>,
+ min_protocol: Option<Protocol>,
+ max_protocol: Option<Protocol>,
+ root_certificates: Vec<Certificate>,
+ accept_invalid_certs: bool,
+ accept_invalid_hostnames: bool,
+ use_sni: bool,
+ disable_built_in_roots: bool,
+ #[cfg(feature = "alpn")]
+ alpn: Vec<String>,
+}
+
+impl TlsConnectorBuilder {
+ /// Sets the identity to be used for client certificate authentication.
+ pub fn identity(&mut self, identity: Identity) -> &mut TlsConnectorBuilder {
+ self.identity = Some(identity);
+ self
+ }
+
+ /// Sets the minimum supported protocol version.
+ ///
+ /// A value of `None` enables support for the oldest protocols supported by the implementation.
+ ///
+ /// Defaults to `Some(Protocol::Tlsv10)`.
+ pub fn min_protocol_version(&mut self, protocol: Option<Protocol>) -> &mut TlsConnectorBuilder {
+ self.min_protocol = protocol;
+ self
+ }
+
+ /// Sets the maximum supported protocol version.
+ ///
+ /// A value of `None` enables support for the newest protocols supported by the implementation.
+ ///
+ /// Defaults to `None`.
+ pub fn max_protocol_version(&mut self, protocol: Option<Protocol>) -> &mut TlsConnectorBuilder {
+ self.max_protocol = protocol;
+ self
+ }
+
+ /// Adds a certificate to the set of roots that the connector will trust.
+ ///
+ /// The connector will use the system's trust root by default. This method can be used to add
+ /// to that set when communicating with servers not trusted by the system.
+ ///
+ /// Defaults to an empty set.
+ pub fn add_root_certificate(&mut self, cert: Certificate) -> &mut TlsConnectorBuilder {
+ self.root_certificates.push(cert);
+ self
+ }
+
+ /// Controls the use of built-in system certificates during certificate validation.
+ ///
+ /// Defaults to `false` -- built-in system certs will be used.
+ pub fn disable_built_in_roots(&mut self, disable: bool) -> &mut TlsConnectorBuilder {
+ self.disable_built_in_roots = disable;
+ self
+ }
+
+ /// Request specific protocols through ALPN (Application-Layer Protocol Negotiation).
+ ///
+ /// Defaults to no protocols.
+ #[cfg(feature = "alpn")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "alpn")))]
+ pub fn request_alpns(&mut self, protocols: &[&str]) -> &mut TlsConnectorBuilder {
+ self.alpn = protocols.iter().map(|s| (*s).to_owned()).collect();
+ self
+ }
+
+ /// Controls the use of certificate validation.
+ ///
+ /// Defaults to `false`.
+ ///
+ /// # Warning
+ ///
+ /// You should think very carefully before using this method. If invalid certificates are trusted, *any*
+ /// certificate for *any* site will be trusted for use. This includes expired certificates. This introduces
+ /// significant vulnerabilities, and should only be used as a last resort.
+ pub fn danger_accept_invalid_certs(
+ &mut self,
+ accept_invalid_certs: bool,
+ ) -> &mut TlsConnectorBuilder {
+ self.accept_invalid_certs = accept_invalid_certs;
+ self
+ }
+
+ /// Controls the use of Server Name Indication (SNI).
+ ///
+ /// Defaults to `true`.
+ pub fn use_sni(&mut self, use_sni: bool) -> &mut TlsConnectorBuilder {
+ self.use_sni = use_sni;
+ self
+ }
+
+ /// Controls the use of hostname verification.
+ ///
+ /// Defaults to `false`.
+ ///
+ /// # Warning
+ ///
+ /// You should think very carefully before using this method. If invalid hostnames are trusted, *any* valid
+ /// certificate for *any* site will be trusted for use. This introduces significant vulnerabilities, and should
+ /// only be used as a last resort.
+ pub fn danger_accept_invalid_hostnames(
+ &mut self,
+ accept_invalid_hostnames: bool,
+ ) -> &mut TlsConnectorBuilder {
+ self.accept_invalid_hostnames = accept_invalid_hostnames;
+ self
+ }
+
+ /// Creates a new `TlsConnector`.
+ pub fn build(&self) -> Result<TlsConnector> {
+ let connector = imp::TlsConnector::new(self)?;
+ Ok(TlsConnector(connector))
+ }
+}
+
+/// A builder for client-side TLS connections.
+///
+/// # Examples
+///
+/// ```rust
+/// use native_tls::TlsConnector;
+/// use std::io::{Read, Write};
+/// use std::net::TcpStream;
+///
+/// let connector = TlsConnector::new().unwrap();
+///
+/// let stream = TcpStream::connect("google.com:443").unwrap();
+/// let mut stream = connector.connect("google.com", stream).unwrap();
+///
+/// stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
+/// let mut res = vec![];
+/// stream.read_to_end(&mut res).unwrap();
+/// println!("{}", String::from_utf8_lossy(&res));
+/// ```
+#[derive(Clone, Debug)]
+pub struct TlsConnector(imp::TlsConnector);
+
+impl TlsConnector {
+ /// Returns a new connector with default settings.
+ pub fn new() -> Result<TlsConnector> {
+ TlsConnector::builder().build()
+ }
+
+ /// Returns a new builder for a `TlsConnector`.
+ pub fn builder() -> TlsConnectorBuilder {
+ TlsConnectorBuilder {
+ identity: None,
+ min_protocol: Some(Protocol::Tlsv10),
+ max_protocol: None,
+ root_certificates: vec![],
+ use_sni: true,
+ accept_invalid_certs: false,
+ accept_invalid_hostnames: false,
+ disable_built_in_roots: false,
+ #[cfg(feature = "alpn")]
+ alpn: vec![],
+ }
+ }
+
+ /// Initiates a TLS handshake.
+ ///
+ /// The provided domain will be used for both SNI and certificate hostname
+ /// validation.
+ ///
+ /// If the socket is nonblocking and a `WouldBlock` error is returned during
+ /// the handshake, a `HandshakeError::WouldBlock` error will be returned
+ /// which can be used to restart the handshake when the socket is ready
+ /// again.
+ ///
+ /// The domain is ignored if both SNI and hostname verification are
+ /// disabled.
+ pub fn connect<S>(
+ &self,
+ domain: &str,
+ stream: S,
+ ) -> result::Result<TlsStream<S>, HandshakeError<S>>
+ where
+ S: io::Read + io::Write,
+ {
+ let s = self.0.connect(domain, stream)?;
+ Ok(TlsStream(s))
+ }
+}
+
+/// A builder for `TlsAcceptor`s.
+pub struct TlsAcceptorBuilder {
+ identity: Identity,
+ min_protocol: Option<Protocol>,
+ max_protocol: Option<Protocol>,
+}
+
+impl TlsAcceptorBuilder {
+ /// Sets the minimum supported protocol version.
+ ///
+ /// A value of `None` enables support for the oldest protocols supported by the implementation.
+ ///
+ /// Defaults to `Some(Protocol::Tlsv10)`.
+ pub fn min_protocol_version(&mut self, protocol: Option<Protocol>) -> &mut TlsAcceptorBuilder {
+ self.min_protocol = protocol;
+ self
+ }
+
+ /// Sets the maximum supported protocol version.
+ ///
+ /// A value of `None` enables support for the newest protocols supported by the implementation.
+ ///
+ /// Defaults to `None`.
+ pub fn max_protocol_version(&mut self, protocol: Option<Protocol>) -> &mut TlsAcceptorBuilder {
+ self.max_protocol = protocol;
+ self
+ }
+
+ /// Creates a new `TlsAcceptor`.
+ pub fn build(&self) -> Result<TlsAcceptor> {
+ let acceptor = imp::TlsAcceptor::new(self)?;
+ Ok(TlsAcceptor(acceptor))
+ }
+}
+
+/// A builder for server-side TLS connections.
+///
+/// # Examples
+///
+/// ```rust,no_run
+/// use native_tls::{Identity, TlsAcceptor, TlsStream};
+/// use std::fs::File;
+/// use std::io::{Read};
+/// use std::net::{TcpListener, TcpStream};
+/// use std::sync::Arc;
+/// use std::thread;
+///
+/// let mut file = File::open("identity.pfx").unwrap();
+/// let mut identity = vec![];
+/// file.read_to_end(&mut identity).unwrap();
+/// let identity = Identity::from_pkcs12(&identity, "hunter2").unwrap();
+///
+/// let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
+/// let acceptor = TlsAcceptor::new(identity).unwrap();
+/// let acceptor = Arc::new(acceptor);
+///
+/// fn handle_client(stream: TlsStream<TcpStream>) {
+/// // ...
+/// }
+///
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// let acceptor = acceptor.clone();
+/// thread::spawn(move || {
+/// let stream = acceptor.accept(stream).unwrap();
+/// handle_client(stream);
+/// });
+/// }
+/// Err(e) => { /* connection failed */ }
+/// }
+/// }
+/// ```
+#[derive(Clone)]
+pub struct TlsAcceptor(imp::TlsAcceptor);
+
+impl TlsAcceptor {
+ /// Creates a acceptor with default settings.
+ ///
+ /// The identity acts as the server's private key/certificate chain.
+ pub fn new(identity: Identity) -> Result<TlsAcceptor> {
+ TlsAcceptor::builder(identity).build()
+ }
+
+ /// Returns a new builder for a `TlsAcceptor`.
+ ///
+ /// The identity acts as the server's private key/certificate chain.
+ pub fn builder(identity: Identity) -> TlsAcceptorBuilder {
+ TlsAcceptorBuilder {
+ identity,
+ min_protocol: Some(Protocol::Tlsv10),
+ max_protocol: None,
+ }
+ }
+
+ /// Initiates a TLS handshake.
+ ///
+ /// If the socket is nonblocking and a `WouldBlock` error is returned during
+ /// the handshake, a `HandshakeError::WouldBlock` error will be returned
+ /// which can be used to restart the handshake when the socket is ready
+ /// again.
+ pub fn accept<S>(&self, stream: S) -> result::Result<TlsStream<S>, HandshakeError<S>>
+ where
+ S: io::Read + io::Write,
+ {
+ match self.0.accept(stream) {
+ Ok(s) => Ok(TlsStream(s)),
+ Err(e) => Err(e.into()),
+ }
+ }
+}
+
+/// A stream managing a TLS session.
+pub struct TlsStream<S>(imp::TlsStream<S>);
+
+impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.0, fmt)
+ }
+}
+
+impl<S> TlsStream<S> {
+ /// Returns a shared reference to the inner stream.
+ pub fn get_ref(&self) -> &S {
+ self.0.get_ref()
+ }
+
+ /// Returns a mutable reference to the inner stream.
+ pub fn get_mut(&mut self) -> &mut S {
+ self.0.get_mut()
+ }
+}
+
+impl<S: io::Read + io::Write> TlsStream<S> {
+ /// Returns the number of bytes that can be read without resulting in any
+ /// network calls.
+ pub fn buffered_read_size(&self) -> Result<usize> {
+ Ok(self.0.buffered_read_size()?)
+ }
+
+ /// Returns the peer's leaf certificate, if available.
+ pub fn peer_certificate(&self) -> Result<Option<Certificate>> {
+ Ok(self.0.peer_certificate()?.map(Certificate))
+ }
+
+ /// Returns the tls-server-end-point channel binding data as defined in [RFC 5929].
+ ///
+ /// [RFC 5929]: https://tools.ietf.org/html/rfc5929
+ pub fn tls_server_end_point(&self) -> Result<Option<Vec<u8>>> {
+ Ok(self.0.tls_server_end_point()?)
+ }
+
+ /// Returns the negotiated ALPN protocol.
+ #[cfg(feature = "alpn")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "alpn")))]
+ pub fn negotiated_alpn(&self) -> Result<Option<Vec<u8>>> {
+ Ok(self.0.negotiated_alpn()?)
+ }
+
+ /// Shuts down the TLS session.
+ pub fn shutdown(&mut self) -> io::Result<()> {
+ self.0.shutdown()?;
+ Ok(())
+ }
+}
+
+impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+}
+
+impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.0.flush()
+ }
+}
+
+fn _check_kinds() {
+ use std::net::TcpStream;
+
+ fn is_sync<T: Sync>() {}
+ fn is_send<T: Send>() {}
+ is_sync::<Error>();
+ is_send::<Error>();
+ is_sync::<TlsConnectorBuilder>();
+ is_send::<TlsConnectorBuilder>();
+ is_sync::<TlsConnector>();
+ is_send::<TlsConnector>();
+ is_sync::<TlsAcceptorBuilder>();
+ is_send::<TlsAcceptorBuilder>();
+ is_sync::<TlsAcceptor>();
+ is_send::<TlsAcceptor>();
+ is_sync::<TlsStream<TcpStream>>();
+ is_send::<TlsStream<TcpStream>>();
+ is_sync::<MidHandshakeTlsStream<TcpStream>>();
+ is_send::<MidHandshakeTlsStream<TcpStream>>();
+}
diff --git a/vendor/native-tls/src/test.rs b/vendor/native-tls/src/test.rs
new file mode 100644
index 000000000..d29f0d264
--- /dev/null
+++ b/vendor/native-tls/src/test.rs
@@ -0,0 +1,573 @@
+use std::fs;
+use std::io::{Read, Write};
+use std::net::{TcpListener, TcpStream};
+use std::process::{Command, Stdio};
+use std::string::String;
+use std::thread;
+
+use super::*;
+
+macro_rules! p {
+ ($e:expr) => {
+ match $e {
+ Ok(r) => r,
+ Err(e) => panic!("{:?}", e),
+ }
+ };
+}
+
+#[test]
+fn connect_google() {
+ let builder = p!(TlsConnector::new());
+ let s = p!(TcpStream::connect("google.com:443"));
+ let mut socket = p!(builder.connect("google.com", s));
+
+ p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
+ let mut result = vec![];
+ p!(socket.read_to_end(&mut result));
+
+ println!("{}", String::from_utf8_lossy(&result));
+ assert!(result.starts_with(b"HTTP/1.0"));
+ assert!(result.ends_with(b"</HTML>\r\n") || result.ends_with(b"</html>"));
+}
+
+#[test]
+fn connect_bad_hostname() {
+ let builder = p!(TlsConnector::new());
+ let s = p!(TcpStream::connect("google.com:443"));
+ builder.connect("goggle.com", s).unwrap_err();
+}
+
+#[test]
+fn connect_bad_hostname_ignored() {
+ let builder = p!(TlsConnector::builder()
+ .danger_accept_invalid_hostnames(true)
+ .build());
+ let s = p!(TcpStream::connect("google.com:443"));
+ builder.connect("goggle.com", s).unwrap();
+}
+
+#[test]
+fn connect_no_root_certs() {
+ let builder = p!(TlsConnector::builder().disable_built_in_roots(true).build());
+ let s = p!(TcpStream::connect("google.com:443"));
+ assert!(builder.connect("google.com", s).is_err());
+}
+
+#[test]
+fn server_no_root_certs() {
+ let keys = test_cert_gen::keys();
+
+ let identity = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let builder = p!(TlsAcceptor::new(identity));
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let mut socket = p!(builder.accept(socket));
+
+ let mut buf = [0; 5];
+ p!(socket.read_exact(&mut buf));
+ assert_eq!(&buf, b"hello");
+
+ p!(socket.write_all(b"world"));
+ });
+
+ let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let builder = p!(TlsConnector::builder()
+ .disable_built_in_roots(true)
+ .add_root_certificate(root_ca)
+ .build());
+ let mut socket = p!(builder.connect("localhost", socket));
+
+ p!(socket.write_all(b"hello"));
+ let mut buf = vec![];
+ p!(socket.read_to_end(&mut buf));
+ assert_eq!(buf, b"world");
+
+ p!(j.join());
+}
+
+#[test]
+fn server() {
+ let keys = test_cert_gen::keys();
+
+ let identity = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let builder = p!(TlsAcceptor::new(identity));
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let mut socket = p!(builder.accept(socket));
+
+ let mut buf = [0; 5];
+ p!(socket.read_exact(&mut buf));
+ assert_eq!(&buf, b"hello");
+
+ p!(socket.write_all(b"world"));
+ });
+
+ let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let builder = p!(TlsConnector::builder()
+ .add_root_certificate(root_ca)
+ .build());
+ let mut socket = p!(builder.connect("localhost", socket));
+
+ p!(socket.write_all(b"hello"));
+ let mut buf = vec![];
+ p!(socket.read_to_end(&mut buf));
+ assert_eq!(buf, b"world");
+
+ p!(j.join());
+}
+
+#[test]
+fn certificate_from_pem() {
+ let dir = tempfile::tempdir().unwrap();
+ let keys = test_cert_gen::keys();
+
+ let der_path = dir.path().join("cert.der");
+ fs::write(&der_path, &keys.client.ca.get_der()).unwrap();
+ let output = Command::new("openssl")
+ .arg("x509")
+ .arg("-in")
+ .arg(der_path)
+ .arg("-inform")
+ .arg("der")
+ .stderr(Stdio::piped())
+ .output()
+ .unwrap();
+
+ assert!(output.status.success());
+
+ let cert = Certificate::from_pem(&output.stdout).unwrap();
+ assert_eq!(cert.to_der().unwrap(), keys.client.ca.get_der());
+}
+
+#[test]
+fn peer_certificate() {
+ let keys = test_cert_gen::keys();
+
+ let identity = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let builder = p!(TlsAcceptor::new(identity));
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let socket = p!(builder.accept(socket));
+ assert!(socket.peer_certificate().unwrap().is_none());
+ });
+
+ let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let builder = p!(TlsConnector::builder()
+ .add_root_certificate(root_ca)
+ .build());
+ let socket = p!(builder.connect("localhost", socket));
+
+ let cert = socket.peer_certificate().unwrap().unwrap();
+ assert_eq!(
+ cert.to_der().unwrap(),
+ keys.server.cert_and_key.cert.get_der()
+ );
+
+ p!(j.join());
+}
+
+#[test]
+fn server_tls11_only() {
+ let keys = test_cert_gen::keys();
+
+ let identity = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let builder = p!(TlsAcceptor::builder(identity)
+ .min_protocol_version(Some(Protocol::Tlsv12))
+ .max_protocol_version(Some(Protocol::Tlsv12))
+ .build());
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let mut socket = p!(builder.accept(socket));
+
+ let mut buf = [0; 5];
+ p!(socket.read_exact(&mut buf));
+ assert_eq!(&buf, b"hello");
+
+ p!(socket.write_all(b"world"));
+ });
+
+ let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let builder = p!(TlsConnector::builder()
+ .add_root_certificate(root_ca)
+ .min_protocol_version(Some(Protocol::Tlsv12))
+ .max_protocol_version(Some(Protocol::Tlsv12))
+ .build());
+ let mut socket = p!(builder.connect("localhost", socket));
+
+ p!(socket.write_all(b"hello"));
+ let mut buf = vec![];
+ p!(socket.read_to_end(&mut buf));
+ assert_eq!(buf, b"world");
+
+ p!(j.join());
+}
+
+#[test]
+fn server_no_shared_protocol() {
+ let keys = test_cert_gen::keys();
+
+ let identity = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let builder = p!(TlsAcceptor::builder(identity)
+ .min_protocol_version(Some(Protocol::Tlsv12))
+ .build());
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ assert!(builder.accept(socket).is_err());
+ });
+
+ let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let builder = p!(TlsConnector::builder()
+ .add_root_certificate(root_ca)
+ .min_protocol_version(Some(Protocol::Tlsv11))
+ .max_protocol_version(Some(Protocol::Tlsv11))
+ .build());
+ assert!(builder.connect("localhost", socket).is_err());
+
+ p!(j.join());
+}
+
+#[test]
+fn server_untrusted() {
+ let keys = test_cert_gen::keys();
+
+ let identity = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let builder = p!(TlsAcceptor::new(identity));
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ // FIXME should assert error
+ // https://github.com/steffengy/schannel-rs/issues/20
+ let _ = builder.accept(socket);
+ });
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let builder = p!(TlsConnector::new());
+ builder.connect("localhost", socket).unwrap_err();
+
+ p!(j.join());
+}
+
+#[test]
+fn server_untrusted_unverified() {
+ let keys = test_cert_gen::keys();
+
+ let identity = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let builder = p!(TlsAcceptor::new(identity));
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let mut socket = p!(builder.accept(socket));
+
+ let mut buf = [0; 5];
+ p!(socket.read_exact(&mut buf));
+ assert_eq!(&buf, b"hello");
+
+ p!(socket.write_all(b"world"));
+ });
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let builder = p!(TlsConnector::builder()
+ .danger_accept_invalid_certs(true)
+ .build());
+ let mut socket = p!(builder.connect("localhost", socket));
+
+ p!(socket.write_all(b"hello"));
+ let mut buf = vec![];
+ p!(socket.read_to_end(&mut buf));
+ assert_eq!(buf, b"world");
+
+ p!(j.join());
+}
+
+#[test]
+fn import_same_identity_multiple_times() {
+ let keys = test_cert_gen::keys();
+
+ let _ = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let _ = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+
+ let cert = keys.server.cert_and_key.cert.to_pem().into_bytes();
+ let key = rsa_to_pkcs8(&keys.server.cert_and_key.key.to_pem_incorrect()).into_bytes();
+ let _ = p!(Identity::from_pkcs8(&cert, &key));
+ let _ = p!(Identity::from_pkcs8(&cert, &key));
+}
+
+#[test]
+fn from_pkcs8_rejects_rsa_key() {
+ let keys = test_cert_gen::keys();
+ let cert = keys.server.cert_and_key.cert.to_pem().into_bytes();
+ let rsa_key = keys.server.cert_and_key.key.to_pem_incorrect();
+ assert!(Identity::from_pkcs8(&cert, rsa_key.as_bytes()).is_err());
+ let pkcs8_key = rsa_to_pkcs8(&rsa_key);
+ assert!(Identity::from_pkcs8(&cert, pkcs8_key.as_bytes()).is_ok());
+}
+
+#[test]
+fn shutdown() {
+ let keys = test_cert_gen::keys();
+
+ let identity = p!(Identity::from_pkcs12(
+ &keys.server.cert_and_key_pkcs12.pkcs12.0,
+ &keys.server.cert_and_key_pkcs12.password
+ ));
+ let builder = p!(TlsAcceptor::new(identity));
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let mut socket = p!(builder.accept(socket));
+
+ let mut buf = [0; 5];
+ p!(socket.read_exact(&mut buf));
+ assert_eq!(&buf, b"hello");
+
+ assert_eq!(p!(socket.read(&mut buf)), 0);
+ p!(socket.shutdown());
+ });
+
+ let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let builder = p!(TlsConnector::builder()
+ .add_root_certificate(root_ca)
+ .build());
+ let mut socket = p!(builder.connect("localhost", socket));
+
+ p!(socket.write_all(b"hello"));
+ p!(socket.shutdown());
+
+ p!(j.join());
+}
+
+#[test]
+#[cfg(feature = "alpn")]
+fn alpn_google_h2() {
+ let builder = p!(TlsConnector::builder().request_alpns(&["h2"]).build());
+ let s = p!(TcpStream::connect("google.com:443"));
+ let socket = p!(builder.connect("google.com", s));
+ let alpn = p!(socket.negotiated_alpn());
+ assert_eq!(alpn, Some(b"h2".to_vec()));
+}
+
+#[test]
+#[cfg(feature = "alpn")]
+fn alpn_google_invalid() {
+ let builder = p!(TlsConnector::builder().request_alpns(&["h2c"]).build());
+ let s = p!(TcpStream::connect("google.com:443"));
+ let socket = p!(builder.connect("google.com", s));
+ let alpn = p!(socket.negotiated_alpn());
+ assert_eq!(alpn, None);
+}
+
+#[test]
+#[cfg(feature = "alpn")]
+fn alpn_google_none() {
+ let builder = p!(TlsConnector::new());
+ let s = p!(TcpStream::connect("google.com:443"));
+ let socket = p!(builder.connect("google.com", s));
+ let alpn = p!(socket.negotiated_alpn());
+ assert_eq!(alpn, None);
+}
+
+#[test]
+fn server_pkcs8() {
+ let keys = test_cert_gen::keys();
+ let cert = keys.server.cert_and_key.cert.to_pem().into_bytes();
+ let key = rsa_to_pkcs8(&keys.server.cert_and_key.key.to_pem_incorrect()).into_bytes();
+
+ let ident = Identity::from_pkcs8(&cert, &key).unwrap();
+ let ident2 = ident.clone();
+ let builder = p!(TlsAcceptor::new(ident));
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let mut socket = p!(builder.accept(socket));
+
+ let mut buf = [0; 5];
+ p!(socket.read_exact(&mut buf));
+ assert_eq!(&buf, b"hello");
+
+ p!(socket.write_all(b"world"));
+ });
+
+ let root_ca = Certificate::from_der(keys.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let mut builder = TlsConnector::builder();
+ // FIXME
+ // This checks that we can successfully add a certificate on the client side.
+ // Unfortunately, we can not request client certificates through the API of this library,
+ // otherwise we could check in the server thread that
+ // socket.peer_certificate().unwrap().is_some()
+ builder.identity(ident2);
+
+ builder.add_root_certificate(root_ca);
+ let builder = p!(builder.build());
+ let mut socket = p!(builder.connect("localhost", socket));
+
+ p!(socket.write_all(b"hello"));
+ let mut buf = vec![];
+ p!(socket.read_to_end(&mut buf));
+ assert_eq!(buf, b"world");
+
+ p!(j.join());
+}
+
+#[test]
+fn two_servers() {
+ let keys1 = test_cert_gen::gen_keys();
+ let cert = keys1.server.cert_and_key.cert.to_pem().into_bytes();
+ let key = rsa_to_pkcs8(&keys1.server.cert_and_key.key.to_pem_incorrect()).into_bytes();
+ let identity = p!(Identity::from_pkcs8(&cert, &key));
+ let builder = TlsAcceptor::builder(identity);
+ let builder = p!(builder.build());
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port = p!(listener.local_addr()).port();
+
+ let j = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let mut socket = p!(builder.accept(socket));
+
+ let mut buf = [0; 5];
+ p!(socket.read_exact(&mut buf));
+ assert_eq!(&buf, b"hello");
+
+ p!(socket.write_all(b"world"));
+ });
+
+ let keys2 = test_cert_gen::gen_keys();
+ let cert = keys2.server.cert_and_key.cert.to_pem().into_bytes();
+ let key = rsa_to_pkcs8(&keys2.server.cert_and_key.key.to_pem_incorrect()).into_bytes();
+ let identity = p!(Identity::from_pkcs8(&cert, &key));
+ let builder = TlsAcceptor::builder(identity);
+ let builder = p!(builder.build());
+
+ let listener = p!(TcpListener::bind("0.0.0.0:0"));
+ let port2 = p!(listener.local_addr()).port();
+
+ let j2 = thread::spawn(move || {
+ let socket = p!(listener.accept()).0;
+ let mut socket = p!(builder.accept(socket));
+
+ let mut buf = [0; 5];
+ p!(socket.read_exact(&mut buf));
+ assert_eq!(&buf, b"hello");
+
+ p!(socket.write_all(b"world"));
+ });
+
+ let root_ca = Certificate::from_der(keys1.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port)));
+ let mut builder = TlsConnector::builder();
+ builder.add_root_certificate(root_ca);
+ let builder = p!(builder.build());
+ let mut socket = p!(builder.connect("localhost", socket));
+
+ p!(socket.write_all(b"hello"));
+ let mut buf = vec![];
+ p!(socket.read_to_end(&mut buf));
+ assert_eq!(buf, b"world");
+
+ let root_ca = Certificate::from_der(keys2.client.ca.get_der()).unwrap();
+
+ let socket = p!(TcpStream::connect(("localhost", port2)));
+ let mut builder = TlsConnector::builder();
+ builder.add_root_certificate(root_ca);
+ let builder = p!(builder.build());
+ let mut socket = p!(builder.connect("localhost", socket));
+
+ p!(socket.write_all(b"hello"));
+ let mut buf = vec![];
+ p!(socket.read_to_end(&mut buf));
+ assert_eq!(buf, b"world");
+
+ p!(j.join());
+ p!(j2.join());
+}
+
+fn rsa_to_pkcs8(pem: &str) -> String {
+ let mut child = Command::new("openssl")
+ .arg("pkcs8")
+ .arg("-topk8")
+ .arg("-nocrypt")
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .spawn()
+ .unwrap();
+ {
+ let child_stdin = child.stdin.as_mut().unwrap();
+ child_stdin.write_all(pem.as_bytes()).unwrap();
+ }
+ String::from_utf8(child.wait_with_output().unwrap().stdout).unwrap()
+}