diff -Nru rust-openssl-0.10.16/build.rs rust-openssl-0.10.23/build.rs --- rust-openssl-0.10.16/build.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/build.rs 2019-05-09 01:41:17.000000000 +0000 @@ -46,6 +46,10 @@ println!("cargo:rustc-cfg=libressl270"); } + if version >= 0x2_07_01_00_0 { + println!("cargo:rustc-cfg=libressl271"); + } + if version >= 0x2_07_03_00_0 { println!("cargo:rustc-cfg=libressl273"); } @@ -53,5 +57,9 @@ if version >= 0x2_08_00_00_0 { println!("cargo:rustc-cfg=libressl280"); } + + if version >= 0x2_09_01_00_0 { + println!("cargo:rustc-cfg=libressl291"); + } } } diff -Nru rust-openssl-0.10.16/Cargo.toml rust-openssl-0.10.23/Cargo.toml --- rust-openssl-0.10.16/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rust-openssl-0.10.23/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -12,7 +12,7 @@ [package] name = "openssl" -version = "0.10.16" +version = "0.10.23" authors = ["Steven Fackler "] description = "OpenSSL bindings" readme = "README.md" @@ -36,10 +36,7 @@ version = "0.2" [dependencies.openssl-sys] -version = "0.9.40" -[dev-dependencies.data-encoding] -version = "2.0" - +version = "0.9.47" [dev-dependencies.hex] version = "0.3" diff -Nru rust-openssl-0.10.16/Cargo.toml.orig rust-openssl-0.10.23/Cargo.toml.orig --- rust-openssl-0.10.16/Cargo.toml.orig 2018-12-16 17:03:40.000000000 +0000 +++ rust-openssl-0.10.23/Cargo.toml.orig 1970-01-01 00:00:00.000000000 +0000 @@ -1,33 +1,51 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + [package] name = "openssl" -version = "0.10.16" +version = "0.10.23" authors = ["Steven Fackler "] -license = "Apache-2.0" description = "OpenSSL bindings" -repository = "https://github.com/sfackler/rust-openssl" readme = "README.md" keywords = ["crypto", "tls", "ssl", "dtls"] categories = ["cryptography", "api-bindings"] +license = "Apache-2.0" +repository = "https://github.com/sfackler/rust-openssl" +[dependencies.bitflags] +version = "1.0" + +[dependencies.cfg-if] +version = "0.1" + +[dependencies.foreign-types] +version = "0.3.1" + +[dependencies.lazy_static] +version = "1" + +[dependencies.libc] +version = "0.2" + +[dependencies.openssl-sys] +version = "0.9.47" +[dev-dependencies.hex] +version = "0.3" + +[dev-dependencies.tempdir] +version = "0.3" -# these are deprecated and don't do anything anymore [features] v101 = [] v102 = [] v110 = [] v111 = [] - -vendored = ['openssl-sys/vendored'] - -[dependencies] -bitflags = "1.0" -cfg-if = "0.1" -foreign-types = "0.3.1" -lazy_static = "1" -libc = "0.2" - -openssl-sys = { version = "0.9.40", path = "../openssl-sys" } - -[dev-dependencies] -tempdir = "0.3" -hex = "0.3" -data-encoding = "2.0" +vendored = ["openssl-sys/vendored"] diff -Nru rust-openssl-0.10.16/.cargo_vcs_info.json rust-openssl-0.10.23/.cargo_vcs_info.json --- rust-openssl-0.10.16/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 +++ rust-openssl-0.10.23/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +1,5 @@ { "git": { - "sha1": "57e02abb505bd4b3a87dbc06478c4ede40e35516" + "sha1": "3b064fdb022912bbb98f5b8d9d111aeb6fec8f79" } } diff -Nru rust-openssl-0.10.16/CHANGELOG.md rust-openssl-0.10.23/CHANGELOG.md --- rust-openssl-0.10.16/CHANGELOG.md 1970-01-01 00:00:00.000000000 +0000 +++ rust-openssl-0.10.23/CHANGELOG.md 2019-05-18 19:13:26.000000000 +0000 @@ -0,0 +1,397 @@ +# Change Log + +## [Unreleased] + +## [v0.10.23] + +### Fixed + +* Fixed session callbacks when an `Ssl`'s context is replaced. + +### Added + +* Added `SslContextBuilder::add_client_ca`. + +## [v0.10.22] + +### Added + +* Added support for the LibreSSL 2.9.x series. + +## [v0.10.21] - 2019-04-30 + +### Fixed + +* Fixed overly conservatifve buffer size checks in `Crypter` when using stream ciphers. + +### Added + +* Added bindings to envelope encryption APIs. +* Added `PkeyRef::size`. + +## [v0.10.20] - 2019-03-20 + +### Added + +* Added `CmsContentInfo::from_der` and `CmsContentInfo::encrypt`. +* Added `X509Ref::verify` and `X509ReqRef::verify`. +* Implemented `PartialEq` and `Eq` for `MessageDigest`. +* Added `MessageDigest::type_` and `EcGroupRef::curve_name`. + +## [v0.10.19] - 2019-03-01 + +### Added + +* The openssl-sys build script now logs the values of environment variables. +* Added `ERR_PACK` to openssl-sys. +* The `ERR_*` functions in openssl-sys are const functions when building against newer Rust versions. +* Implemented `Clone` for `Dsa`. +* Added `SslContextRef::add_session` and `SslContextRef::remove_session`. +* Added `SslSessionRef::time`, `SslSessionRef::timeout`, and `SslSessionRef::protocol_version`. +* Added `SslContextBuilder::set_session_cache_size` and `SslContextRef::session_cache_size`. + +## [v0.10.18] - 2019-02-22 + +### Fixed + +* Fixed the return type of `ssl::cipher_name`. + +## [v0.10.17] - 2019-02-22 + +### Added + +* Implemented `AsRef` and `AsRef<[u8]>` for `OpenSslString`. +* Added `Asn1Integer::from_bn`. +* Added `RsaRef::check_key`. +* Added `Asn1Time::from_str` and `Asn1Time::from_str_x509`. +* Added `Rsa::generate_with_e`. +* Added `Cipher::des_ede3_cfb64`. +* Added `SslCipherRef::standard_name` and `ssl::cipher_name`. + +## [v0.10.16] - 2018-12-16 + +### Added + +* Added SHA3 and SHAKE to `MessageDigest`. +* Added `rand::keep_random_devices_open`. +* Added support for LibreSSL 2.9.0. + +## [v0.10.15] - 2018-10-22 + +### Added + +* Implemented `DoubleEndedIterator` for stack iterators. + +## [v0.10.14] - 2018-10-18 + +### Fixed + +* Made some accidentally exposed internal functions private. + +### Added + +* Added support for LibreSSL 2.8. + +### Changed + +* The OpenSSL version used with the `vendored` feature has been upgraded from 1.1.0 to 1.1.1. + +## [v0.10.13] - 2018-10-14 + +### Fixed + +* Fixed a double-free in the `SslContextBuilder::set_get_session_callback` API. + +### Added + +* Added `SslContextBuilder::set_client_hello_callback`. +* Added support for LibreSSL 2.8.1. +* Added `EcdsaSig::from_der` and `EcdsaSig::to_der`. +* Added PKCS#7 support. + +## [v0.10.12] - 2018-09-13 + +### Fixed + +* Fixed handling of SNI callbacks during renegotiation. + +### Added + +* Added `SslRef::get_shutdown` and `SslRef::set_shutdown`. +* Added support for SRTP in DTLS sessions. +* Added support for LibreSSL 2.8.0. + +## [v0.10.11] - 2018-08-04 + +### Added + +* The new `vendored` cargo feature will cause openssl-sys to compile and statically link to a + vendored copy of OpenSSL. +* Added `SslContextBuilder::set_psk_server_callback`. +* Added `DsaRef::pub_key` and `DsaRef::priv_key`. +* Added `Dsa::from_private_components` and `Dsa::from_public_components`. +* Added `X509NameRef::entries`. + +### Deprecated + +* `SslContextBuilder::set_psk_callback` has been renamed to + `SslContextBuilder::set_psk_client_callback` and deprecated. + +## [v0.10.10] - 2018-06-06 + +### Added + +* Added `SslRef::set_alpn_protos`. +* Added `SslContextBuilder::set_ciphersuites`. + +## [v0.10.9] - 2018-06-01 + +### Fixed + +* Fixed a use-after-free in `CmsContentInfo::sign`. +* `SslRef::servername` now returns `None` rather than panicking on a non-UTF8 name. + +### Added + +* Added `MessageDigest::from_nid`. +* Added `Nid::signature_algorithms`, `Nid::long_name`, and `Nid::short_name`. +* Added early data and early keying material export support for TLS 1.3. +* Added `SslRef::verified_chain`. +* Added `SslRef::servername_raw` which returns a `&[u8]` rather than `&str`. +* Added `SslRef::finished` and `SslRef::peer_finished`. +* Added `X509Ref::digest` to replace `X509Ref::fingerprint`. +* `X509StoreBuilder` and `X509Store` now implement `Sync` and `Send`. + +### Deprecated + +* `X509Ref::fingerprint` has been deprecated in favor of `X509Ref::digest`. + +## [v0.10.8] - 2018-05-20 + +### Fixed + +* `openssl-sys` will now detect Homebrew-installed OpenSSL when installed to a non-default + directory. +* The `X509_V_ERR_INVALID_CALL`, `X509_V_ERR_STORE_LOOKUP`, and + `X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION` constants in `openssl-sys` are now only present when + building against 1.1.0g and up rather than 1.1.0. +* `SslContextBuilder::max_proto_version` and `SslContextBuilder::min_proto_version` are only present + when building against 1.1.0g and up rather than 1.1.0. + +### Added + +* Added `CmsContentInfo::sign`. +* Added `Clone` and `ToOwned` implementations to `Rsa` and `RsaRef` respectively. +* The `min_proto_version` and `max_proto_version` methods are available when linking against + LibreSSL 2.6.1 and up in addition to OpenSSL. +* `X509VerifyParam` is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* ALPN support is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* `Stack` and `StackRef` are now `Sync` and `Send`. + +## [v0.10.7] - 2018-04-30 + +### Added + +* Added `X509Req::public_key` and `X509Req::extensions`. +* Added `RsaPrivateKeyBuilder` to allow control over initialization of optional components of an RSA + private key. +* Added DER encode/decode support to `SslSession`. +* openssl-sys now provides the `DEP_OPENSSL_VERSION_NUMBER` and + `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER` environment variables to downstream build scripts which + contains the hex-encoded version number of the OpenSSL or LibreSSL distribution being built + against. The other variables are deprecated. + +## [v0.10.6] - 2018-03-05 + +### Added + +* Added `SslOptions::ENABLE_MIDDLEBOX_COMPAT`. +* Added more `Sync` and `Send` implementations. +* Added `PKeyRef::id`. +* Added `Padding::PKCS1_PSS`. +* Added `Signer::set_rsa_pss_saltlen`, `Signer::set_rsa_mgf1_md`, `Signer::set_rsa_pss_saltlen`, and + `Signer::set_rsa_mgf1_md` +* Added `X509StoreContextRef::verify` to directly verify certificates. +* Added low level ECDSA support. +* Added support for TLSv1.3 custom extensions. (OpenSSL 1.1.1 only) +* Added AES-CCM support. +* Added `EcKey::from_private_components`. +* Added CMAC support. +* Added support for LibreSSL 2.7. +* Added `X509Ref::serial_number`. +* Added `Asn1IntegerRef::to_bn`. +* Added support for TLSv1.3 stateless handshakes. (OpenSSL 1.1.1 only) + +### Changed + +* The Cargo features previously used to gate access to version-specific OpenSSL APIs have been + removed. Those APIs will be available automatically when building against an appropriate OpenSSL + version. +* Fixed `PKey::private_key_from_der` to return a `PKey` rather than a `PKey`. This + is technically a breaking change but the function was pretty useless previously. + +### Deprecated + +* `X509CheckFlags::FLAG_NO_WILDCARDS` has been renamed to `X509CheckFlags::NO_WILDCARDS` and the old + name deprecated. + +## [v0.10.5] - 2018-02-28 + +### Fixed + +* `ErrorStack`'s `Display` implementation no longer writes an empty string if it contains no errors. + +### Added + +* Added `SslRef::version2`. +* Added `Cipher::des_ede3_cbc`. +* Added `SslRef::export_keying_material`. +* Added the ability to push an `Error` or `ErrorStack` back onto OpenSSL's error stack. Various + callback bindings use this to propagate errors properly. +* Added `SslContextBuilder::set_cookie_generate_cb` and `SslContextBuilder::set_cookie_verify_cb`. +* Added `SslContextBuilder::set_max_proto_version`, `SslContextBuilder::set_min_proto_version`, + `SslContextBuilder::max_proto_version`, and `SslContextBuilder::min_proto_version`. + +### Changed + +* Updated `SslConnector`'s default cipher list to match Python's. + +### Deprecated + +* `SslRef::version` has been deprecated. Use `SslRef::version_str` instead. + +## [v0.10.4] - 2018-02-18 + +### Added + +* Added OpenSSL 1.1.1 support. +* Added `Rsa::public_key_from_pem_pkcs1`. +* Added `SslOptions::NO_TLSV1_3`. (OpenSSL 1.1.1 only) +* Added `SslVersion`. +* Added `SslSessionCacheMode` and `SslContextBuilder::set_session_cache_mode`. +* Added `SslContextBuilder::set_new_session_callback`, + `SslContextBuilder::set_remove_session_callback`, and + `SslContextBuilder::set_get_session_callback`. +* Added `SslContextBuilder::set_keylog_callback`. (OpenSSL 1.1.1 only) +* Added `SslRef::client_random` and `SslRef::server_random`. (OpenSSL 1.1.0+ only) + +### Fixed + +* The `SslAcceptorBuilder::mozilla_modern` constructor now disables TLSv1.0 and TLSv1.1 in + accordance with Mozilla's recommendations. + +## [v0.10.3] - 2018-02-12 + +### Added + +* OpenSSL is now automatically detected on FreeBSD systems. +* Added `GeneralName` accessors for `rfc822Name` and `uri` variants. +* Added DES-EDE3 support. + +### Fixed + +* Fixed a memory leak in `X509StoreBuilder::add_cert`. + +## [v0.10.2] - 2018-01-11 + +### Added + +* Added `ConnectConfiguration::set_use_server_name_indication` and + `ConnectConfiguration::set_verify_hostname` for use in contexts where you don't have ownership + of the `ConnectConfiguration`. + +## [v0.10.1] - 2018-01-10 + +### Added + +* Added a `From for ssl::Error` implementation. + +## [v0.10.0] - 2018-01-10 + +### Compatibility + +* openssl 0.10 still uses openssl-sys 0.9, so openssl 0.9 and 0.10 can coexist without issue. + +### Added + +* The `ssl::select_next_proto` function can be used to easily implement the ALPN selection callback + in a "standard" way. +* FIPS mode support is available in the `fips` module. +* Accessors for the Issuer and Issuer Alternative Name fields of X509 certificates have been added. +* The `X509VerifyResult` can now be set in the certificate verification callback via + `X509StoreContextRef::set_error`. + +### Changed + +* All constants have been moved to associated constants of their type. For example, `bn::MSB_ONE` + is now `bn::MsbOption::ONE`. +* Asymmetric key types are now parameterized over what they contain. In OpenSSL, the same type is + used for key parameters, public keys, and private keys. Unfortunately, some APIs simply assume + that certain components are present and will segfault trying to use things that aren't there. + + The `pkey` module contains new tag types named `Params`, `Public`, and `Private`, and the + `Dh`, `Dsa`, `EcKey`, `Rsa`, and `PKey` have a type parameter set to one of those values. This + allows the `Signer` constructor to indicate that it requires a private key at compile time for + example. Previously, `Signer` would simply segfault if provided a key without private + components. +* ALPN support has been changed to more directly model OpenSSL's own APIs. Instead of a single + method used for both the server and client sides which performed everything automatically, the + `SslContextBuilder::set_alpn_protos` and `SslContextBuilder::set_alpn_select_callback` handle + the client and server sides respectively. +* `SslConnector::danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication` + has been removed in favor of new methods which provide more control. The + `ConnectConfiguration::use_server_name_indication` method controls the use of Server Name + Indication (SNI), and the `ConnectConfiguration::verify_hostname` method controls the use of + hostname verification. These can be controlled independently, and if both are disabled, the + domain argument to `ConnectConfiguration::connect` is ignored. +* Shared secret derivation is now handled by the new `derive::Deriver` type rather than + `pkey::PKeyContext`, which has been removed. +* `ssl::Error` is now no longer an enum, and provides more direct access to the relevant state. +* `SslConnectorBuilder::new` has been moved and renamed to `SslConnector::builder`. +* `SslAcceptorBuilder::mozilla_intermediate` and `SslAcceptorBuilder::mozilla_modern` have been + moved to `SslAcceptor` and no longer take the private key and certificate chain. Install those + manually after creating the builder. +* `X509VerifyError` is now `X509VerifyResult` and can now have the "ok" value in addition to error + values. +* `x509::X509FileType` is now `ssl::SslFiletype`. +* Asymmetric key serialization and deserialization methods now document the formats that they + correspond to, and some have been renamed to better indicate that. + +### Removed + +* All deprecated APIs have been removed. +* NPN support has been removed. It has been supersceded by ALPN, and is hopefully no longer being + used in practice. If you still depend on it, please file an issue! +* `SslRef::compression` has been removed. +* Some `ssl::SslOptions` flags have been removed as they no longer do anything. + +## Older + +Look at the [release tags] for information about older releases. + +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.23...master +[v0.10.23]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.22...openssl-v0.10.23 +[v0.10.22]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.21...openssl-v0.10.22 +[v0.10.21]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.20...openssl-v0.10.21 +[v0.10.20]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.19...openssl-v0.10.20 +[v0.10.19]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.18...openssl-v0.10.19 +[v0.10.18]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.17...openssl-v0.10.18 +[v0.10.17]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.16...openssl-v0.10.17 +[v0.10.16]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.15...openssl-v0.10.16 +[v0.10.15]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.14...openssl-v0.10.15 +[v0.10.14]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.13...openssl-v0.10.14 +[v0.10.13]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.12...openssl-v0.10.13 +[v0.10.12]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.11...openssl-v0.10.12 +[v0.10.11]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.10...openssl-v0.10.11 +[v0.10.10]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.9...openssl-v0.10.10 +[v0.10.9]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...openssl-v0.10.9 +[v0.10.8]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.7...openssl-v0.10.8 +[v0.10.7]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.6...openssl-v0.10.7 +[v0.10.6]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.5...openssl-v0.10.6 +[v0.10.5]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.4...openssl-v0.10.5 +[v0.10.4]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.3...openssl-v0.10.4 +[v0.10.3]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.2...openssl-v0.10.3 +[v0.10.2]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.1...openssl-v0.10.2 +[v0.10.1]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.0...openssl-v0.10.1 +[v0.10.0]: https://github.com/sfackler/rust-openssl/compare/v0.9.23...openssl-v0.10.0 +[release tags]: https://github.com/sfackler/rust-openssl/releases diff -Nru rust-openssl-0.10.16/debian/changelog rust-openssl-0.10.23/debian/changelog --- rust-openssl-0.10.16/debian/changelog 2018-12-26 23:25:15.000000000 +0000 +++ rust-openssl-0.10.23/debian/changelog 2019-05-31 04:59:26.000000000 +0000 @@ -1,3 +1,9 @@ +rust-openssl (0.10.23-1) unstable; urgency=medium + + * Package openssl 0.10.23 from crates.io using debcargo 2.2.10 + + -- Ximin Luo Thu, 30 May 2019 21:59:26 -0700 + rust-openssl (0.10.16-1) unstable; urgency=medium * Package openssl 0.10.16 from crates.io using debcargo 2.2.9 diff -Nru rust-openssl-0.10.16/debian/control rust-openssl-0.10.23/debian/control --- rust-openssl-0.10.16/debian/control 2018-12-26 23:25:15.000000000 +0000 +++ rust-openssl-0.10.23/debian/control 2019-05-31 04:59:26.000000000 +0000 @@ -2,7 +2,7 @@ Section: rust Priority: optional Build-Depends: debhelper (>= 11), - dh-cargo (>= 10), + dh-cargo (>= 15), cargo:native , rustc:native , libstd-rust-dev , @@ -11,7 +11,7 @@ librust-foreign-types-0.3+default-dev (>= 0.3.1-~~) , librust-lazy-static-1+default-dev , librust-libc-0.2+default-dev , - librust-openssl-sys-0.9+default-dev (>= 0.9.40-~~) + librust-openssl-sys-0.9+default-dev (>= 0.9.47-~~) Maintainer: Debian Rust Maintainers Uploaders: Ximin Luo @@ -29,7 +29,7 @@ librust-foreign-types-0.3+default-dev (>= 0.3.1-~~), librust-lazy-static-1+default-dev, librust-libc-0.2+default-dev, - librust-openssl-sys-0.9+default-dev (>= 0.9.40-~~) + librust-openssl-sys-0.9+default-dev (>= 0.9.47-~~) Provides: librust-openssl+default-dev (= ${binary:Version}), librust-openssl+v101-dev (= ${binary:Version}), @@ -51,13 +51,13 @@ librust-openssl-0.10+v110-dev (= ${binary:Version}), librust-openssl-0.10+v111-dev (= ${binary:Version}), librust-openssl-0.10+vendored-dev (= ${binary:Version}), - librust-openssl-0.10.16-dev (= ${binary:Version}), - librust-openssl-0.10.16+default-dev (= ${binary:Version}), - librust-openssl-0.10.16+v101-dev (= ${binary:Version}), - librust-openssl-0.10.16+v102-dev (= ${binary:Version}), - librust-openssl-0.10.16+v110-dev (= ${binary:Version}), - librust-openssl-0.10.16+v111-dev (= ${binary:Version}), - librust-openssl-0.10.16+vendored-dev (= ${binary:Version}) + librust-openssl-0.10.23-dev (= ${binary:Version}), + librust-openssl-0.10.23+default-dev (= ${binary:Version}), + librust-openssl-0.10.23+v101-dev (= ${binary:Version}), + librust-openssl-0.10.23+v102-dev (= ${binary:Version}), + librust-openssl-0.10.23+v110-dev (= ${binary:Version}), + librust-openssl-0.10.23+v111-dev (= ${binary:Version}), + librust-openssl-0.10.23+vendored-dev (= ${binary:Version}) Description: OpenSSL bindings - Rust source code This package contains the source for the Rust openssl crate, packaged by debcargo for use with cargo and dh-cargo. diff -Nru rust-openssl-0.10.16/debian/copyright.debcargo.hint rust-openssl-0.10.23/debian/copyright.debcargo.hint --- rust-openssl-0.10.16/debian/copyright.debcargo.hint 2018-12-26 23:25:15.000000000 +0000 +++ rust-openssl-0.10.23/debian/copyright.debcargo.hint 2019-05-31 04:59:26.000000000 +0000 @@ -21,8 +21,8 @@ Files: debian/* Copyright: - 2018 Debian Rust Maintainers - 2018 Ximin Luo + 2018-2019 Debian Rust Maintainers + 2018-2019 Ximin Luo License: Apache-2.0 License: Apache-2.0 diff -Nru rust-openssl-0.10.16/examples/mk_certs.rs rust-openssl-0.10.23/examples/mk_certs.rs --- rust-openssl-0.10.16/examples/mk_certs.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/examples/mk_certs.rs 2019-05-01 04:45:44.000000000 +0000 @@ -9,9 +9,11 @@ use openssl::hash::MessageDigest; use openssl::pkey::{PKey, PKeyRef, Private}; use openssl::rsa::Rsa; -use openssl::x509::{X509, X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult}; -use openssl::x509::extension::{AuthorityKeyIdentifier, BasicConstraints, KeyUsage, - SubjectAlternativeName, SubjectKeyIdentifier}; +use openssl::x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; +use openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509}; /// Make a CA certificate and private key fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> { @@ -42,11 +44,13 @@ cert_builder.set_not_after(¬_after)?; cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?; - cert_builder.append_extension(KeyUsage::new() - .critical() - .key_cert_sign() - .crl_sign() - .build()?)?; + cert_builder.append_extension( + KeyUsage::new() + .critical() + .key_cert_sign() + .crl_sign() + .build()?, + )?; let subject_key_identifier = SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?; @@ -104,12 +108,14 @@ cert_builder.append_extension(BasicConstraints::new().build()?)?; - cert_builder.append_extension(KeyUsage::new() - .critical() - .non_repudiation() - .digital_signature() - .key_encipherment() - .build()?)?; + cert_builder.append_extension( + KeyUsage::new() + .critical() + .non_repudiation() + .digital_signature() + .key_encipherment() + .build()?, + )?; let subject_key_identifier = SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?; diff -Nru rust-openssl-0.10.16/src/asn1.rs rust-openssl-0.10.23/src/asn1.rs --- rust-openssl-0.10.16/src/asn1.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/asn1.rs 2019-05-09 01:40:48.000000000 +0000 @@ -27,13 +27,14 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_long}; +use std::ffi::CString; use std::fmt; use std::ptr; use std::slice; use std::str; use bio::MemBio; -use bn::BigNum; +use bn::{BigNum, BigNumRef}; use error::ErrorStack; use nid::Nid; use string::OpensslString; @@ -105,6 +106,15 @@ } impl Asn1Time { + fn new() -> Result { + ffi::init(); + + unsafe { + let handle = cvt_p(ffi::ASN1_TIME_new())?; + Ok(Asn1Time::from_ptr(handle)) + } + } + fn from_period(period: c_long) -> Result { ffi::init(); @@ -118,6 +128,41 @@ pub fn days_from_now(days: u32) -> Result { Asn1Time::from_period(days as c_long * 60 * 60 * 24) } + + /// Creates a new time corresponding to the specified ASN1 time string. + /// + /// This corresponds to [`ASN1_TIME_set_string`]. + /// + /// [`ASN1_TIME_set_string`]: https://www.openssl.org/docs/manmaster/man3/ASN1_TIME_set_string.html + pub fn from_str(s: &str) -> Result { + unsafe { + let s = CString::new(s).unwrap(); + + let time = Asn1Time::new()?; + cvt(ffi::ASN1_TIME_set_string(time.as_ptr(), s.as_ptr()))?; + + Ok(time) + } + } + + /// Creates a new time corresponding to the specified X509 time string. + /// + /// This corresponds to [`ASN1_TIME_set_string_X509`]. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// [`ASN1_TIME_set_string_X509`]: https://www.openssl.org/docs/manmaster/man3/ASN1_TIME_set_string.html + #[cfg(ossl111)] + pub fn from_str_x509(s: &str) -> Result { + unsafe { + let s = CString::new(s).unwrap(); + + let time = Asn1Time::new()?; + cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?; + + Ok(time) + } + } } foreign_type_and_impl_send_sync! { @@ -191,6 +236,19 @@ pub struct Asn1IntegerRef; } +impl Asn1Integer { + /// Converts a bignum to an `Asn1Integer`. + /// + /// Corresponds to [`BN_to_ASN1_INTEGER`]. Also see + /// [`BigNumRef::to_asn1_integer`]. + /// + /// [`BN_to_ASN1_INTEGER`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_to_ASN1_INTEGER.html + /// [`BigNumRef::to_asn1_integer`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer + pub fn from_bn(bn: &BigNumRef) -> Result { + bn.to_asn1_integer() + } +} + impl Asn1IntegerRef { #[allow(missing_docs)] #[deprecated(since = "0.10.6", note = "use to_bn instead")] @@ -306,3 +364,31 @@ } } } + +#[cfg(test)] +mod tests { + use super::*; + + use bn::BigNum; + + /// Tests conversion between BigNum and Asn1Integer. + #[test] + fn bn_cvt() { + fn roundtrip(bn: BigNum) { + let large = Asn1Integer::from_bn(&bn).unwrap(); + assert_eq!(large.to_bn().unwrap(), bn); + } + + roundtrip(BigNum::from_dec_str("1000000000000000000000000000000000").unwrap()); + roundtrip(-BigNum::from_dec_str("1000000000000000000000000000000000").unwrap()); + roundtrip(BigNum::from_u32(1234).unwrap()); + roundtrip(-BigNum::from_u32(1234).unwrap()); + } + + #[test] + fn time_from_str() { + Asn1Time::from_str("99991231235959Z").unwrap(); + #[cfg(ossl111)] + Asn1Time::from_str_x509("99991231235959Z").unwrap(); + } +} diff -Nru rust-openssl-0.10.16/src/bn.rs rust-openssl-0.10.23/src/bn.rs --- rust-openssl-0.10.16/src/bn.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/bn.rs 2019-05-01 04:45:44.000000000 +0000 @@ -120,7 +120,7 @@ /// Dynamically sized large number impelementation /// /// Perform large number mathematics. Create a new BigNum - /// with [`new`]. Perform stanard mathematics on large numbers using + /// with [`new`]. Perform standard mathematics on large numbers using /// methods from [`Dref`] /// /// OpenSSL documenation at [`BN_new`]. @@ -423,7 +423,8 @@ bits.into(), msb.0, odd as c_int, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -439,7 +440,8 @@ bits.into(), msb.0, odd as c_int, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -485,7 +487,8 @@ add.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()), rem.map(|n| n.as_ptr()).unwrap_or(ptr::null_mut()), ptr::null_mut(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -508,7 +511,8 @@ a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -532,7 +536,8 @@ a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -554,7 +559,8 @@ a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -577,7 +583,8 @@ a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -608,7 +615,8 @@ a.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -631,7 +639,8 @@ b.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -654,7 +663,8 @@ b.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -677,7 +687,8 @@ b.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -698,7 +709,8 @@ a.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -719,7 +731,8 @@ a.as_ptr(), p.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -742,7 +755,8 @@ p.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -759,7 +773,8 @@ a.as_ptr(), n.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -780,7 +795,8 @@ a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -803,7 +819,8 @@ checks.into(), ctx.as_ptr(), ptr::null_mut(), - )).map(|r| r != 0) + )) + .map(|r| r != 0) } } @@ -833,7 +850,8 @@ ctx.as_ptr(), do_trial_division as c_int, ptr::null_mut(), - )).map(|r| r != 0) + )) + .map(|r| r != 0) } } @@ -1089,7 +1107,8 @@ n.as_ptr(), n.len() as c_int, ptr::null_mut(), - )).map(|p| BigNum::from_ptr(p)) + )) + .map(|p| BigNum::from_ptr(p)) } } } diff -Nru rust-openssl-0.10.16/src/cms.rs rust-openssl-0.10.23/src/cms.rs --- rust-openssl-0.10.16/src/cms.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/cms.rs 2019-05-01 04:45:44.000000000 +0000 @@ -14,7 +14,8 @@ use libc::c_uint; use pkey::{HasPrivate, PKeyRef}; use stack::StackRef; -use x509::{X509, X509Ref}; +use x509::{X509Ref, X509}; +use symm::Cipher; use {cvt, cvt_p}; bitflags! { @@ -122,6 +123,17 @@ } } + from_der! { + /// Deserializes a DER-encoded ContentInfo structure. + /// + /// This corresponds to [`d2i_CMS_ContentInfo`]. + /// + /// [`d2i_CMS_ContentInfo`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html + from_der, + CmsContentInfo, + ffi::d2i_CMS_ContentInfo + } + /// Given a signing cert `signcert`, private key `pkey`, a certificate stack `certs`, /// data `data` and flags `flags`, create a CmsContentInfo struct. /// @@ -161,4 +173,67 @@ Ok(CmsContentInfo::from_ptr(cms)) } } + + /// Given a certificate stack `certs`, data `data`, cipher `cipher` and flags `flags`, + /// create a CmsContentInfo struct. + /// + /// OpenSSL documentation at [`CMS_encrypt`] + /// + /// [`CMS_encrypt`]: https://www.openssl.org/docs/manmaster/man3/CMS_encrypt.html + pub fn encrypt( + certs: &StackRef, + data: &[u8], + cipher: Cipher, + flags: CMSOptions, + ) -> Result + { + unsafe { + let data_bio = MemBioSlice::new(data)?; + + let cms = cvt_p(ffi::CMS_encrypt( + certs.as_ptr(), + data_bio.as_ptr(), + cipher.as_ptr(), + flags.bits(), + ))?; + + Ok(CmsContentInfo::from_ptr(cms)) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use stack::Stack; + use x509::X509; + use pkcs12::Pkcs12; + + #[test] + fn cms_encrypt_decrypt() { + // load cert with public key only + let pub_cert_bytes = include_bytes!("../test/cms_pubkey.der"); + let pub_cert = X509::from_der(pub_cert_bytes).expect("failed to load pub cert"); + + // load cert with private key + let priv_cert_bytes = include_bytes!("../test/cms.p12"); + let priv_cert = Pkcs12::from_der(priv_cert_bytes).expect("failed to load priv cert"); + let priv_cert = priv_cert.parse("mypass").expect("failed to parse priv cert"); + + // encrypt cms message using public key cert + let input = String::from("My Message"); + let mut cert_stack = Stack::new().expect("failed to create stack"); + cert_stack.push(pub_cert).expect("failed to add pub cert to stack"); + + let encrypt = CmsContentInfo::encrypt(&cert_stack, &input.as_bytes(), Cipher::des_ede3_cbc(), CMSOptions::empty()) + .expect("failed create encrypted cms"); + let encrypt = encrypt.to_der().expect("failed to create der from cms"); + + // decrypt cms message using private key cert + let decrypt = CmsContentInfo::from_der(&encrypt).expect("failed read cms from der"); + let decrypt = decrypt.decrypt(&priv_cert.pkey, &priv_cert.cert).expect("failed to decrypt cms"); + let decrypt = String::from_utf8(decrypt).expect("failed to create string from cms content"); + + assert_eq!(input, decrypt); + } } diff -Nru rust-openssl-0.10.16/src/derive.rs rust-openssl-0.10.23/src/derive.rs --- rust-openssl-0.10.16/src/derive.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/derive.rs 2019-05-01 04:45:44.000000000 +0000 @@ -1,12 +1,12 @@ //! Shared secret derivation. use ffi; +use foreign_types::ForeignTypeRef; use std::marker::PhantomData; use std::ptr; -use foreign_types::ForeignTypeRef; -use {cvt, cvt_p}; use error::ErrorStack; use pkey::{HasPrivate, HasPublic, PKeyRef}; +use {cvt, cvt_p}; /// A type used to derive a shared secret between two keys. pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>); @@ -72,7 +72,8 @@ self.0, buf.as_mut_ptr() as *mut _, &mut len, - )).map(|_| len) + )) + .map(|_| len) } } diff -Nru rust-openssl-0.10.16/src/dh.rs rust-openssl-0.10.23/src/dh.rs --- rust-openssl-0.10.16/src/dh.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/dh.rs 2019-05-01 04:45:44.000000000 +0000 @@ -164,7 +164,8 @@ ).unwrap(); let q = BigNum::from_hex_str( "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", - ).unwrap(); + ) + .unwrap(); let dh = Dh::from_params(p, g, q).unwrap(); ctx.set_tmp_dh(&dh).unwrap(); } diff -Nru rust-openssl-0.10.16/src/dsa.rs rust-openssl-0.10.23/src/dsa.rs --- rust-openssl-0.10.16/src/dsa.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/dsa.rs 2019-05-01 04:45:44.000000000 +0000 @@ -9,8 +9,8 @@ use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; -use std::ptr; use std::mem; +use std::ptr; use bn::{BigNum, BigNumRef}; use error::ErrorStack; @@ -59,6 +59,23 @@ pub struct DsaRef; } +impl Clone for Dsa { + fn clone(&self) -> Dsa { + (**self).to_owned() + } +} + +impl ToOwned for DsaRef { + type Owned = Dsa; + + fn to_owned(&self) -> Dsa { + unsafe { + ffi::DSA_up_ref(self.as_ptr()); + Dsa::from_ptr(self.as_ptr()) + } + } +} + impl DsaRef where T: HasPublic, @@ -321,9 +338,9 @@ mod test { use super::*; use bn::BigNumContext; - use sign::{Signer, Verifier}; use hash::MessageDigest; use pkey::PKey; + use sign::{Signer, Verifier}; #[test] pub fn test_generate() { @@ -390,14 +407,18 @@ BigNumRef::to_owned(q).unwrap(), BigNumRef::to_owned(g).unwrap(), BigNumRef::to_owned(priv_key).unwrap(), - BigNumRef::to_owned(pub_key).unwrap()).unwrap(); + BigNumRef::to_owned(pub_key).unwrap(), + ) + .unwrap(); let priv_key = PKey::from_dsa(priv_key).unwrap(); let pub_key = Dsa::from_public_components( BigNumRef::to_owned(p).unwrap(), BigNumRef::to_owned(q).unwrap(), BigNumRef::to_owned(g).unwrap(), - BigNumRef::to_owned(pub_key).unwrap()).unwrap(); + BigNumRef::to_owned(pub_key).unwrap(), + ) + .unwrap(); let pub_key = PKey::from_dsa(pub_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); @@ -408,4 +429,10 @@ verifier.update(TEST_DATA).unwrap(); assert!(verifier.verify(&signature[..]).unwrap()); } + + #[test] + fn clone() { + let key = Dsa::generate(2048).unwrap(); + drop(key.clone()); + } } diff -Nru rust-openssl-0.10.16/src/ecdsa.rs rust-openssl-0.10.23/src/ecdsa.rs --- rust-openssl-0.10.16/src/ecdsa.rs 2018-10-02 03:45:18.000000000 +0000 +++ rust-openssl-0.10.23/src/ecdsa.rs 2019-05-09 01:40:48.000000000 +0000 @@ -73,7 +73,8 @@ data.len() as c_int, self.as_ptr(), eckey.as_ptr(), - )).map(|x| x == 1) + )) + .map(|x| x == 1) } } @@ -106,21 +107,25 @@ from_der! { /// Decodes a DER-encoded ECDSA signature. /// - /// This corresponds to [`d2i_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_ECDSA_SIG.html + /// This corresponds to [`d2i_ECDSA_SIG`]. + /// + /// [`d2i_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_ECDSA_SIG.html from_der, EcdsaSig, ffi::d2i_ECDSA_SIG - } + } } impl EcdsaSigRef { to_der! { /// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure. /// - /// This corresponds to [`i2d_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_ECDSA_SIG.html + /// This corresponds to [`i2d_ECDSA_SIG`]. + /// + /// [`i2d_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_ECDSA_SIG.html to_der, ffi::i2d_ECDSA_SIG - } + } } cfg_if! { diff -Nru rust-openssl-0.10.16/src/ec.rs rust-openssl-0.10.23/src/ec.rs --- rust-openssl-0.10.16/src/ec.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/ec.rs 2019-05-01 04:45:44.000000000 +0000 @@ -163,7 +163,8 @@ a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -192,7 +193,8 @@ a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -220,7 +222,8 @@ self.as_ptr(), order.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -234,6 +237,16 @@ ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0); } } + + /// Returns the name of the curve, if a name is associated. + /// + /// OpenSSL documentation at [`EC_GROUP_get_curve_name`] + /// + /// [`EC_GROUP_get_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_name.html + pub fn curve_name(&self) -> Option { + let nid = unsafe { ffi::EC_GROUP_get_curve_name(self.as_ptr()) }; + if nid > 0 { Some(Nid::from_raw(nid)) } else { None } + } } foreign_type_and_impl_send_sync! { @@ -272,7 +285,8 @@ a.as_ptr(), b.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -296,7 +310,8 @@ q.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -315,7 +330,8 @@ ptr::null(), ptr::null(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -336,7 +352,8 @@ q.as_ptr(), m.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -351,7 +368,8 @@ group.as_ptr(), self.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -437,7 +455,8 @@ x.as_ptr(), y.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -462,7 +481,8 @@ x.as_ptr(), y.as_ptr(), ctx.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } } @@ -688,7 +708,8 @@ cvt(ffi::EC_KEY_set_public_key( key.as_ptr(), public_key.as_ptr(), - )).map(|_| key) + )) + .map(|_| key) }) } } @@ -710,7 +731,8 @@ key.as_ptr(), x.as_ptr(), y.as_ptr(), - )).map(|_| key) + )) + .map(|_| key) }) } } @@ -745,13 +767,15 @@ cvt(ffi::EC_KEY_set_private_key( key.as_ptr(), private_number.as_ptr(), - )).map(|_| key) + )) + .map(|_| key) }) .and_then(|key| { cvt(ffi::EC_KEY_set_public_key( key.as_ptr(), public_key.as_ptr(), - )).map(|_| key) + )) + .map(|_| key) }) } } @@ -803,9 +827,10 @@ #[cfg(test)] mod test { + use hex::FromHex; + use super::*; use bn::{BigNum, BigNumContext}; - use data_encoding::BASE64URL_NOPAD; use nid::Nid; #[test] @@ -889,11 +914,9 @@ #[test] fn key_from_affine_coordinates() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let x = BASE64URL_NOPAD - .decode("MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4".as_bytes()) + let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") .unwrap(); - let y = BASE64URL_NOPAD - .decode("4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM".as_bytes()) + let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") .unwrap(); let xbn = BigNum::from_slice(&x).unwrap(); @@ -906,11 +929,9 @@ #[test] fn get_affine_coordinates() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); - let x = BASE64URL_NOPAD - .decode("MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4".as_bytes()) + let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") .unwrap(); - let y = BASE64URL_NOPAD - .decode("4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM".as_bytes()) + let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") .unwrap(); let xbn = BigNum::from_slice(&x).unwrap(); diff -Nru rust-openssl-0.10.16/src/envelope.rs rust-openssl-0.10.23/src/envelope.rs --- rust-openssl-0.10.16/src/envelope.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-openssl-0.10.23/src/envelope.rs 2019-05-01 04:45:44.000000000 +0000 @@ -0,0 +1,282 @@ +//! Envelope encryption. +//! +//! # Example +//! +//! ```rust +//! +//! extern crate openssl; +//! +//! use openssl::rsa::Rsa; +//! use openssl::envelope::Seal; +//! use openssl::pkey::PKey; +//! use openssl::symm::Cipher; +//! +//! fn main() { +//! let rsa = Rsa::generate(2048).unwrap(); +//! let key = PKey::from_rsa(rsa).unwrap(); +//! +//! let cipher = Cipher::aes_256_cbc(); +//! let mut seal = Seal::new(cipher, &[key]).unwrap(); +//! +//! let secret = b"My secret message"; +//! let mut encrypted = vec![0; secret.len() + cipher.block_size()]; +//! +//! let mut enc_len = seal.update(secret, &mut encrypted).unwrap(); +//! enc_len += seal.finalize(&mut encrypted[enc_len..]).unwrap(); +//! encrypted.truncate(enc_len); +//! } +//! ``` +use error::ErrorStack; +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use pkey::{HasPrivate, HasPublic, PKey, PKeyRef}; +use std::cmp; +use std::ptr; +use symm::Cipher; +use {cvt, cvt_p}; + +/// Represents an EVP_Seal context. +pub struct Seal { + ctx: *mut ffi::EVP_CIPHER_CTX, + block_size: usize, + iv: Option>, + enc_keys: Vec>, +} + +impl Seal { + /// Creates a new `Seal`. + pub fn new(cipher: Cipher, pub_keys: &[PKey]) -> Result + where + T: HasPublic, + { + unsafe { + assert!(pub_keys.len() <= c_int::max_value() as usize); + + let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?; + let mut enc_key_ptrs = vec![]; + let mut pub_key_ptrs = vec![]; + let mut enc_keys = vec![]; + for key in pub_keys { + let mut enc_key = vec![0; key.size()]; + let enc_key_ptr = enc_key.as_mut_ptr(); + enc_keys.push(enc_key); + enc_key_ptrs.push(enc_key_ptr); + pub_key_ptrs.push(key.as_ptr()); + } + let mut iv = cipher.iv_len().map(|len| Vec::with_capacity(len)); + let iv_ptr = iv.as_mut().map_or(ptr::null_mut(), |v| v.as_mut_ptr()); + let mut enc_key_lens = vec![0; enc_keys.len()]; + + cvt(ffi::EVP_SealInit( + ctx, + cipher.as_ptr(), + enc_key_ptrs.as_mut_ptr(), + enc_key_lens.as_mut_ptr(), + iv_ptr, + pub_key_ptrs.as_mut_ptr(), + pub_key_ptrs.len() as c_int, + ))?; + + for (buf, len) in enc_keys.iter_mut().zip(&enc_key_lens) { + buf.truncate(*len as usize); + } + + Ok(Seal { + ctx, + block_size: cipher.block_size(), + iv, + enc_keys, + }) + } + } + + /// Returns the initialization vector, if the cipher uses one. + pub fn iv(&self) -> Option<&[u8]> { + self.iv.as_ref().map(|v| &**v) + } + + /// Returns the encrypted keys. + pub fn encrypted_keys(&self) -> &[Vec] { + &self.enc_keys + } + + /// Feeds data from `input` through the cipher, writing encrypted bytes into `output`. + /// + /// The number of bytes written to `output` is returned. Note that this may + /// not be equal to the length of `input`. + /// + /// # Panics + /// + /// Panics if `output.len() < input.len() + block_size` where `block_size` is + /// the block size of the cipher (see `Cipher::block_size`), or if + /// `output.len() > c_int::max_value()`. + pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { + unsafe { + assert!(output.len() >= input.len() + self.block_size); + assert!(output.len() <= c_int::max_value() as usize); + let mut outl = output.len() as c_int; + let inl = input.len() as c_int; + cvt(ffi::EVP_EncryptUpdate( + self.ctx, + output.as_mut_ptr(), + &mut outl, + input.as_ptr(), + inl, + ))?; + Ok(outl as usize) + } + } + + /// Finishes the encryption process, writing any remaining data to `output`. + /// + /// The number of bytes written to `output` is returned. + /// + /// `update` should not be called after this method. + /// + /// # Panics + /// + /// Panics if `output` is less than the cipher's block size. + pub fn finalize(&mut self, output: &mut [u8]) -> Result { + unsafe { + assert!(output.len() >= self.block_size); + let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int; + + cvt(ffi::EVP_SealFinal(self.ctx, output.as_mut_ptr(), &mut outl))?; + + Ok(outl as usize) + } + } +} + +impl Drop for Seal { + fn drop(&mut self) { + unsafe { + ffi::EVP_CIPHER_CTX_free(self.ctx); + } + } +} + +/// Represents an EVP_Open context. +pub struct Open { + ctx: *mut ffi::EVP_CIPHER_CTX, + block_size: usize, +} + +impl Open { + /// Creates a new `Open`. + pub fn new( + cipher: Cipher, + priv_key: &PKeyRef, + iv: Option<&[u8]>, + encrypted_key: &[u8], + ) -> Result + where + T: HasPrivate, + { + unsafe { + assert!(encrypted_key.len() <= c_int::max_value() as usize); + assert!(cipher.iv_len().is_none() || iv.is_some()); + + let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?; + cvt(ffi::EVP_OpenInit( + ctx, + cipher.as_ptr(), + encrypted_key.as_ptr(), + encrypted_key.len() as c_int, + iv.map_or(ptr::null(), |v| v.as_ptr()), + priv_key.as_ptr(), + ))?; + Ok(Open { + ctx, + block_size: cipher.block_size(), + }) + } + } + + /// Feeds data from `input` through the cipher, writing decrypted bytes into `output`. + /// + /// The number of bytes written to `output` is returned. Note that this may + /// not be equal to the length of `input`. + /// + /// # Panics + /// + /// Panics if `output.len() < input.len() + block_size` where + /// `block_size` is the block size of the cipher (see `Cipher::block_size`), + /// or if `output.len() > c_int::max_value()`. + pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { + unsafe { + assert!(output.len() >= input.len() + self.block_size); + assert!(output.len() <= c_int::max_value() as usize); + let mut outl = output.len() as c_int; + let inl = input.len() as c_int; + cvt(ffi::EVP_DecryptUpdate( + self.ctx, + output.as_mut_ptr(), + &mut outl, + input.as_ptr(), + inl, + ))?; + Ok(outl as usize) + } + } + + /// Finishes the decryption process, writing any remaining data to `output`. + /// + /// The number of bytes written to `output` is returned. + /// + /// `update` should not be called after this method. + /// + /// # Panics + /// + /// Panics if `output` is less than the cipher's block size. + pub fn finalize(&mut self, output: &mut [u8]) -> Result { + unsafe { + assert!(output.len() >= self.block_size); + let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int; + + cvt(ffi::EVP_OpenFinal(self.ctx, output.as_mut_ptr(), &mut outl))?; + + Ok(outl as usize) + } + } +} + +impl Drop for Open { + fn drop(&mut self) { + unsafe { + ffi::EVP_CIPHER_CTX_free(self.ctx); + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use pkey::PKey; + use symm::Cipher; + + #[test] + fn public_encrypt_private_decrypt() { + let private_pem = include_bytes!("../test/rsa.pem"); + let public_pem = include_bytes!("../test/rsa.pem.pub"); + let private_key = PKey::private_key_from_pem(private_pem).unwrap(); + let public_key = PKey::public_key_from_pem(public_pem).unwrap(); + let cipher = Cipher::aes_256_cbc(); + let secret = b"My secret message"; + + let mut seal = Seal::new(cipher, &[public_key]).unwrap(); + let mut encrypted = vec![0; secret.len() + cipher.block_size()]; + let mut enc_len = seal.update(secret, &mut encrypted).unwrap(); + enc_len += seal.finalize(&mut encrypted[enc_len..]).unwrap(); + let iv = seal.iv(); + let encrypted_key = &seal.encrypted_keys()[0]; + + let mut open = Open::new(cipher, &private_key, iv, &encrypted_key).unwrap(); + let mut decrypted = vec![0; enc_len + cipher.block_size()]; + let mut dec_len = open.update(&encrypted[..enc_len], &mut decrypted).unwrap(); + dec_len += open.finalize(&mut decrypted[dec_len..]).unwrap(); + + assert_eq!(&secret[..], &decrypted[..dec_len]); + } +} diff -Nru rust-openssl-0.10.16/src/error.rs rust-openssl-0.10.23/src/error.rs --- rust-openssl-0.10.16/src/error.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/error.rs 2019-05-01 04:45:44.000000000 +0000 @@ -16,13 +16,13 @@ //! } //! ``` use libc::{c_char, c_int, c_ulong}; -use std::fmt; +use std::borrow::Cow; use std::error; use std::ffi::CStr; +use std::fmt; use std::io; -use std::str; use std::ptr; -use std::borrow::Cow; +use std::str; use ffi; diff -Nru rust-openssl-0.10.16/src/hash.rs rust-openssl-0.10.23/src/hash.rs --- rust-openssl-0.10.16/src/hash.rs 2018-12-16 16:20:07.000000000 +0000 +++ rust-openssl-0.10.23/src/hash.rs 2019-05-01 04:45:44.000000000 +0000 @@ -16,7 +16,7 @@ } } -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq, Eq)] pub struct MessageDigest(*const ffi::EVP_MD); impl MessageDigest { @@ -106,6 +106,11 @@ pub fn size(&self) -> usize { unsafe { ffi::EVP_MD_size(self.0) as usize } } + + /// The name of the digest + pub fn type_(&self) -> Nid { + Nid::from_raw(unsafe { ffi::EVP_MD_type(self.0) }) + } } unsafe impl Sync for MessageDigest {} @@ -254,7 +259,7 @@ /// Writes the hash of the data into the supplied buf and resets the XOF hasher. /// The hash will be as long as the buf. #[cfg(ossl111)] - pub fn finish_xof(&mut self, buf: &mut[u8]) -> Result<(), ErrorStack> { + pub fn finish_xof(&mut self, buf: &mut [u8]) -> Result<(), ErrorStack> { if self.state == Finalized { self.init()?; } @@ -366,7 +371,7 @@ /// Computes the hash of the `data` with the XOF hasher `t` and stores it in `buf`. #[cfg(ossl111)] -pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut[u8]) -> Result<(), ErrorStack> { +pub fn hash_xof(t: MessageDigest, data: &[u8], buf: &mut [u8]) -> Result<(), ErrorStack> { let mut h = Hasher::new(t)?; h.update(data)?; h.finish_xof(buf) @@ -388,7 +393,12 @@ fn hash_xof_test(hashtype: MessageDigest, hashtest: &(&str, &str)) { let expected = Vec::from_hex(hashtest.1).unwrap(); let mut buf = vec![0; expected.len()]; - hash_xof(hashtype, &Vec::from_hex(hashtest.0).unwrap(), buf.as_mut_slice()).unwrap(); + hash_xof( + hashtype, + &Vec::from_hex(hashtest.0).unwrap(), + buf.as_mut_slice(), + ) + .unwrap(); assert_eq!(buf, expected); } @@ -499,8 +509,9 @@ #[cfg(ossl111)] #[test] fn test_sha3_224() { - let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", - "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913" + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913", )]; for test in tests.iter() { @@ -511,8 +522,9 @@ #[cfg(ossl111)] #[test] fn test_sha3_256() { - let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", - "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61" + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61", )]; for test in tests.iter() { @@ -549,8 +561,9 @@ #[cfg(ossl111)] #[test] fn test_shake_128() { - let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", - "49d0697ff508111d8b84f15e46daf135" + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "49d0697ff508111d8b84f15e46daf135", )]; for test in tests.iter() { @@ -561,8 +574,9 @@ #[cfg(ossl111)] #[test] fn test_shake_256() { - let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", - "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697" + let tests = [( + "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", + "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697", )]; for test in tests.iter() { diff -Nru rust-openssl-0.10.16/src/lib.rs rust-openssl-0.10.23/src/lib.rs --- rust-openssl-0.10.16/src/lib.rs 2018-12-16 16:20:07.000000000 +0000 +++ rust-openssl-0.10.23/src/lib.rs 2019-05-18 01:16:12.000000000 +0000 @@ -1,51 +1,51 @@ //! Bindings to OpenSSL -//! +//! //! This crate provides a safe interface to the popular OpenSSL cryptography library. OpenSSL versions 1.0.1 through //! 1.1.1 and LibreSSL versions 2.5 through 2.8 are supported. -//! +//! //! # Building -//! +//! //! Both OpenSSL libraries and headers are required to build this crate. There are multiple options available to locate //! OpenSSL. -//! +//! //! ## Vendored -//! +//! //! If the `vendored` Cargo feature is enabled, the `openssl-src` crate will be used to compile and statically link to //! a copy of OpenSSL. The build process requires a C compiler, perl, and make. The OpenSSL version will generally track //! the newest OpenSSL release, and changes to the version are *not* considered breaking changes. -//! +//! //! ```toml //! [dependencies] //! openssl = { version = "0.10", features = ["vendored"] } //! ``` -//! +//! //! The vendored copy will not be configured to automatically find the system's root certificates, but the //! `openssl-probe` crate can be used to do that instead. -//! +//! //! ## Automatic -//! +//! //! The `openssl-sys` crate will automatically detect OpenSSL installations via Homebrew on macOS and vcpkg on Windows. //! Additionally, it will use `pkg-config` on Unix-like systems to find the system installation. -//! +//! //! ```not_rust //! # macOS //! $ brew install openssl@1.1 -//! +//! //! # Arch Linux //! $ sudo pacman -S pkg-config openssl -//! +//! //! # Debian and Ubuntu //! $ sudo apt-get install pkg-config libssl-dev -//! +//! //! # Fedora //! $ sudo dnf install pkg-config openssl-devel //! ``` -//! +//! //! ## Manual -//! +//! //! A set of environment variables can be used to point `openssl-sys` towards an OpenSSL installation. They will //! override the automatic detection logic. -//! +//! //! * `OPENSSL_DIR` - If specified, the directory of an OpenSSL installation. The directory should contain `lib` and //! `include` subdirectories containing the libraries and headers respectively. //! * `OPENSSL_LIB_DIR` and `OPENSSL_INCLUDE_DIR` - If specified, the directories containing the OpenSSL libraries and @@ -56,53 +56,53 @@ //! //! Additionally, these variables can be prefixed with the upper-cased target architecture (e.g. //! `X86_64_UNKNOWN_LINUX_GNU_OPENSSL_DIR`), which can be useful when cross compiling. -//! +//! //! # Feature Detection -//! +//! //! APIs have been added to and removed from the various supported OpenSSL versions, and this library exposes the //! functionality available in the version being linked against. This means that methods, constants, and even modules //! will be present when building against one version of OpenSSL but not when building against another! APIs will //! document any version-specific availability restrictions. -//! +//! //! A build script can be used to detect the OpenSSL or LibreSSL version at compile time if needed. The `openssl-sys` //! crate propagates the version via the `DEP_OPENSSL_VERSION_NUMBER` and `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER` //! environment variables to build scripts. The version format is a hex-encoding of the OpenSSL release version: //! `0xMNNFFPPS`. For example, version 1.0.2g's encoding is `0x1_00_02_07_0`. -//! +//! //! For example, let's say we want to adjust the TLSv1.3 cipher suites used by a client, but also want to compile //! against OpenSSL versions that don't support TLSv1.3: -//! +//! //! Cargo.toml: -//! +//! //! ```toml //! [dependencies] //! openssl-sys = "0.9" //! openssl = "0.10" //! ``` -//! +//! //! build.rs: -//! +//! //! ``` //! use std::env; -//! +//! //! fn main() { //! if let Ok(v) = env::var("DEP_OPENSSL_VERSION_NUMBER") { //! let version = u64::from_str_radix(&v, 16).unwrap(); -//! +//! //! if version >= 0x1_01_01_00_0 { //! println!("cargo:rustc-cfg=openssl111"); //! } //! } //! } //! ``` -//! +//! //! lib.rs: -//! +//! //! ``` //! use openssl::ssl::{SslConnector, SslMethod}; -//! +//! //! let mut ctx = SslConnector::builder(SslMethod::tls()).unwrap(); -//! +//! //! // set_ciphersuites was added in OpenSSL 1.1.1, so we can only call it when linking against that version //! #[cfg(openssl111)] //! ctx.set_ciphersuites("TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256").unwrap(); @@ -121,8 +121,6 @@ extern crate openssl_sys as ffi; #[cfg(test)] -extern crate data_encoding; -#[cfg(test)] extern crate hex; #[cfg(test)] extern crate tempdir; @@ -151,6 +149,7 @@ pub mod dsa; pub mod ec; pub mod ecdsa; +pub mod envelope; pub mod error; pub mod ex_data; #[cfg(not(libressl))] diff -Nru rust-openssl-0.10.16/src/memcmp.rs rust-openssl-0.10.23/src/memcmp.rs --- rust-openssl-0.10.16/src/memcmp.rs 2018-08-30 03:36:12.000000000 +0000 +++ rust-openssl-0.10.23/src/memcmp.rs 2019-05-01 04:45:44.000000000 +0000 @@ -29,8 +29,8 @@ //! assert!(!eq(&a, &b)); //! assert!(!eq(&a, &c)); //! ``` -use libc::size_t; use ffi; +use libc::size_t; /// Returns `true` iff `a` and `b` contain the same bytes. /// diff -Nru rust-openssl-0.10.16/src/ocsp.rs rust-openssl-0.10.23/src/ocsp.rs --- rust-openssl-0.10.16/src/ocsp.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/ocsp.rs 2019-05-01 04:45:44.000000000 +0000 @@ -1,16 +1,16 @@ use ffi; use foreign_types::ForeignTypeRef; use libc::{c_int, c_long, c_ulong}; -use std::ptr; use std::mem; +use std::ptr; -use {cvt, cvt_p}; use asn1::Asn1GeneralizedTimeRef; use error::ErrorStack; use hash::MessageDigest; use stack::StackRef; use x509::store::X509StoreRef; -use x509::{X509, X509Ref}; +use x509::{X509Ref, X509}; +use {cvt, cvt_p}; bitflags! { pub struct OcspFlag: c_ulong { @@ -130,7 +130,8 @@ self.next_update.as_ptr(), nsec as c_long, maxsec.map(|n| n as c_long).unwrap_or(-1), - )).map(|_| ()) + )) + .map(|_| ()) } } } @@ -160,7 +161,8 @@ certs.as_ptr(), store.as_ptr(), flags.bits(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -222,7 +224,8 @@ digest.as_ptr(), subject.as_ptr(), issuer.as_ptr(), - )).map(OcspCertId) + )) + .map(OcspCertId) } } } @@ -249,7 +252,8 @@ cvt_p(ffi::OCSP_response_create( status.as_raw(), body.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut()), - )).map(OcspResponse) + )) + .map(OcspResponse) } } diff -Nru rust-openssl-0.10.16/src/pkcs12.rs rust-openssl-0.10.23/src/pkcs12.rs --- rust-openssl-0.10.16/src/pkcs12.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/pkcs12.rs 2019-05-01 04:45:44.000000000 +0000 @@ -10,7 +10,7 @@ use nid::Nid; use pkey::{HasPrivate, PKey, PKeyRef, Private}; use stack::Stack; -use x509::{X509, X509Ref}; +use x509::{X509Ref, X509}; use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { @@ -196,7 +196,8 @@ self.iter, self.mac_iter, keytype, - )).map(Pkcs12) + )) + .map(Pkcs12) } } } @@ -211,7 +212,7 @@ use pkey::PKey; use rsa::Rsa; use x509::extension::KeyUsage; - use x509::{X509, X509Name}; + use x509::{X509Name, X509}; use super::*; diff -Nru rust-openssl-0.10.16/src/pkcs5.rs rust-openssl-0.10.23/src/pkcs5.rs --- rust-openssl-0.10.16/src/pkcs5.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/pkcs5.rs 2019-05-01 04:45:44.000000000 +0000 @@ -1,11 +1,11 @@ +use ffi; use libc::c_int; use std::ptr; -use ffi; use cvt; +use error::ErrorStack; use hash::MessageDigest; use symm::Cipher; -use error::ErrorStack; #[derive(Clone, Eq, PartialEq, Hash, Debug)] pub struct KeyIvPair { @@ -59,7 +59,8 @@ ))?; let mut key = vec![0; len as usize]; - let iv_ptr = iv.as_mut() + let iv_ptr = iv + .as_mut() .map(|v| v.as_mut_ptr()) .unwrap_or(ptr::null_mut()); @@ -101,7 +102,8 @@ hash.as_ptr(), key.len() as c_int, key.as_mut_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -131,7 +133,8 @@ maxmem, key.as_mut_ptr() as *mut _, key.len(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -161,7 +164,8 @@ 80000, MessageDigest::sha256(), &mut buf, - ).unwrap(); + ) + .unwrap(); assert_eq!( buf, &[ @@ -198,7 +202,8 @@ 1, MessageDigest::sha512(), &mut buf, - ).unwrap(); + ) + .unwrap(); assert_eq!( &buf[..], &[ @@ -219,7 +224,8 @@ 50, MessageDigest::sha512(), &mut buf, - ).unwrap(); + ) + .unwrap(); assert_eq!( &buf[..], &[ @@ -262,7 +268,8 @@ &data, Some(&salt), 1, - ).unwrap(), + ) + .unwrap(), super::KeyIvPair { key: expected_key, iv: Some(expected_iv), @@ -290,7 +297,8 @@ 1, 0, &mut actual, - ).unwrap(); + ) + .unwrap(); assert_eq!(hex::encode(&actual[..]), expected); } } diff -Nru rust-openssl-0.10.16/src/pkcs7.rs rust-openssl-0.10.23/src/pkcs7.rs --- rust-openssl-0.10.16/src/pkcs7.rs 2018-10-11 05:25:30.000000000 +0000 +++ rust-openssl-0.10.23/src/pkcs7.rs 2019-05-01 04:45:44.000000000 +0000 @@ -110,7 +110,8 @@ input_bio.as_ptr(), cipher.as_ptr(), flags.bits, - )).map(Pkcs7) + )) + .map(Pkcs7) } } @@ -142,7 +143,8 @@ certs.as_ptr(), input_bio.as_ptr(), flags.bits, - )).map(Pkcs7) + )) + .map(Pkcs7) } } } @@ -162,7 +164,8 @@ self.as_ptr(), input_bio.as_ptr(), flags.bits, - )).map(|_| output.get_buf().to_owned()) + )) + .map(|_| output.get_buf().to_owned()) } } @@ -206,7 +209,8 @@ cert.as_ptr(), output.as_ptr(), flags.bits, - )).map(|_| output.get_buf().to_owned()) + )) + .map(|_| output.get_buf().to_owned()) } } @@ -244,7 +248,8 @@ indata_bio_ptr, out_bio.as_ptr(), flags.bits, - )).map(|_| ())? + )) + .map(|_| ())? } if let Some(data) = out { @@ -328,7 +333,8 @@ Some(message.as_bytes()), Some(&mut output), flags, - ).expect("should succeed"); + ) + .expect("should succeed"); assert_eq!(message.clone().into_bytes(), output); assert_eq!( diff -Nru rust-openssl-0.10.16/src/pkey.rs rust-openssl-0.10.23/src/pkey.rs --- rust-openssl-0.10.16/src/pkey.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/pkey.rs 2019-05-01 04:45:44.000000000 +0000 @@ -45,21 +45,21 @@ //! } //! ``` -use libc::c_int; -use std::ptr; -use std::mem; -use std::ffi::CString; use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::c_int; +use std::ffi::CString; +use std::mem; +use std::ptr; -use {cvt, cvt_p}; use bio::MemBioSlice; use dh::Dh; use dsa::Dsa; use ec::EcKey; -use rsa::Rsa; use error::ErrorStack; +use rsa::Rsa; use util::{invoke_passwd_cb, CallbackState}; +use {cvt, cvt_p}; /// A tag type indicating that a key only has parameters. pub enum Params {} @@ -97,22 +97,14 @@ unsafe impl HasParams for Params {} -unsafe impl HasParams for T -where - T: HasPublic, -{ -} +unsafe impl HasParams for T where T: HasPublic {} /// A trait indicating that a key has public components. pub unsafe trait HasPublic {} unsafe impl HasPublic for Public {} -unsafe impl HasPublic for T -where - T: HasPrivate, -{ -} +unsafe impl HasPublic for T where T: HasPrivate {} /// A trait indicating that a key has private components. pub unsafe trait HasPrivate {} @@ -186,6 +178,15 @@ pub fn id(&self) -> Id { unsafe { Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr())) } } + + /// Returns the maximum size of a signature in bytes. + /// + /// This corresponds to [`EVP_PKEY_size`]. + /// + /// [`EVP_PKEY_size`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_size.html + pub fn size(&self) -> usize { + unsafe { ffi::EVP_PKEY_size(self.as_ptr()) as usize } + } } impl PKeyRef @@ -488,7 +489,8 @@ ptr::null_mut(), Some(invoke_passwd_cb::), &mut cb as *mut _ as *mut _, - )).map(|p| PKey::from_ptr(p)) + )) + .map(|p| PKey::from_ptr(p)) } } @@ -511,7 +513,8 @@ ptr::null_mut(), None, passphrase.as_ptr() as *const _ as *mut _, - )).map(|p| PKey::from_ptr(p)) + )) + .map(|p| PKey::from_ptr(p)) } } } @@ -544,12 +547,12 @@ #[cfg(test)] mod tests { - use symm::Cipher; use dh::Dh; use dsa::Dsa; use ec::EcKey; - use rsa::Rsa; use nid::Nid; + use rsa::Rsa; + use symm::Cipher; use super::*; @@ -557,7 +560,8 @@ fn test_to_password() { let rsa = Rsa::generate(2048).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); - let pem = pkey.private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar") + let pem = pkey + .private_key_to_pem_pkcs8_passphrase(Cipher::aes_128_cbc(), b"foobar") .unwrap(); PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); @@ -577,7 +581,8 @@ password_queried = true; password[..6].copy_from_slice(b"mypass"); Ok(6) - }).unwrap(); + }) + .unwrap(); assert!(password_queried); } diff -Nru rust-openssl-0.10.16/src/rand.rs rust-openssl-0.10.23/src/rand.rs --- rust-openssl-0.10.16/src/rand.rs 2018-12-16 16:20:07.000000000 +0000 +++ rust-openssl-0.10.23/src/rand.rs 2019-05-09 01:40:48.000000000 +0000 @@ -31,7 +31,7 @@ /// rand_bytes(&mut buf).unwrap(); /// ``` /// -/// [`RAND_bytes`](https://www.openssl.org/docs/man1.1.0/crypto/RAND_bytes.html) +/// [`RAND_bytes`]: https://www.openssl.org/docs/man1.1.0/crypto/RAND_bytes.html pub fn rand_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> { unsafe { ffi::init(); diff -Nru rust-openssl-0.10.16/src/rsa.rs rust-openssl-0.10.23/src/rsa.rs --- rust-openssl-0.10.16/src/rsa.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/rsa.rs 2019-05-01 04:45:44.000000000 +0000 @@ -278,6 +278,22 @@ } } } + + /// Validates RSA parameters for correctness + /// + /// This corresponds to [`RSA_check_key`]. + /// + /// [`RSA_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_check_key.html + pub fn check_key(&self) -> Result { + unsafe { + let result = ffi::RSA_check_key(self.as_ptr()) as i32; + if result == -1 { + Err(ErrorStack::get()) + } else { + Ok(result == 1) + } + } + } } impl RsaRef @@ -582,11 +598,25 @@ /// Generates a public/private key pair with the specified size. /// /// The public exponent will be 65537. + /// + /// This corresponds to [`RSA_generate_key_ex`]. + /// + /// [`RSA_generate_key_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key_ex.html pub fn generate(bits: u32) -> Result, ErrorStack> { - ffi::init(); + let e = BigNum::from_u32(ffi::RSA_F4 as u32)?; + Rsa::generate_with_e(bits, &e) + } + + /// Generates a public/private key pair with the specified size and a custom exponent. + /// + /// Unless you have specific needs and know what you're doing, use `Rsa::generate` instead. + /// + /// This corresponds to [`RSA_generate_key_ex`]. + /// + /// [`RSA_generate_key_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_generate_key_ex.html + pub fn generate_with_e(bits: u32, e: &BigNumRef) -> Result, ErrorStack> { unsafe { let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?); - let e = BigNum::from_u32(ffi::RSA_F4 as u32)?; cvt(ffi::RSA_generate_key_ex( rsa.0, bits as c_int, @@ -759,7 +789,8 @@ password_queried = true; password[..6].copy_from_slice(b"mypass"); Ok(6) - }).unwrap(); + }) + .unwrap(); assert!(password_queried); } @@ -904,4 +935,10 @@ let key = Rsa::generate(2048).unwrap(); drop(key.clone()); } + + #[test] + fn generate_with_e() { + let e = BigNum::from_u32(0x10001).unwrap(); + Rsa::generate_with_e(2048, &e).unwrap(); + } } diff -Nru rust-openssl-0.10.16/src/sha.rs rust-openssl-0.10.23/src/sha.rs --- rust-openssl-0.10.16/src/sha.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/sha.rs 2019-05-01 04:45:44.000000000 +0000 @@ -16,15 +16,15 @@ //! ```rust //! extern crate openssl; //! extern crate hex; -//! +//! //! use openssl::sha; -//! +//! //! fn main() { //! let mut hasher = sha::Sha256::new(); -//! +//! //! hasher.update(b"Hello, "); //! hasher.update(b"world"); -//! +//! //! let hash = hasher.finish(); //! println!("Hashed \"Hello, world\" to {}", hex::encode(hash)); //! } @@ -45,8 +45,8 @@ //! println!("Hash = {}", hex::encode(hash)); //! } //! ``` -use libc::c_void; use ffi; +use libc::c_void; use std::mem; /// Computes the SHA1 hash of some data. @@ -347,16 +347,18 @@ #[test] fn standalone_384() { let data = b"abc"; - let expected = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ - 7cc2358baeca134c825a7"; + let expected = + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ + 7cc2358baeca134c825a7"; assert_eq!(hex::encode(&sha384(data)[..]), expected); } #[test] fn struct_384() { - let expected = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ - 7cc2358baeca134c825a7"; + let expected = + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ + 7cc2358baeca134c825a7"; let mut hasher = Sha384::new(); hasher.update(b"a"); @@ -367,16 +369,18 @@ #[test] fn standalone_512() { let data = b"abc"; - let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ - fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + let expected = + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ + fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; assert_eq!(hex::encode(&sha512(data)[..]), expected); } #[test] fn struct_512() { - let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ - fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + let expected = + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ + fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; let mut hasher = Sha512::new(); hasher.update(b"a"); diff -Nru rust-openssl-0.10.16/src/sign.rs rust-openssl-0.10.23/src/sign.rs --- rust-openssl-0.10.16/src/sign.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/sign.rs 2019-05-01 04:45:44.000000000 +0000 @@ -208,7 +208,8 @@ cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( self.pctx, padding.as_raw(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -224,7 +225,8 @@ cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( self.pctx, len.as_raw(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -240,7 +242,8 @@ cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( self.pctx, md.as_ptr() as *mut _, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -255,7 +258,8 @@ self.md_ctx, buf.as_ptr() as *const _, buf.len(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -403,7 +407,8 @@ cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( self.pctx, padding.as_raw(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -419,7 +424,8 @@ cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( self.pctx, len.as_raw(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -435,7 +441,8 @@ cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( self.pctx, md.as_ptr() as *mut _, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -450,7 +457,8 @@ self.md_ctx, buf.as_ptr() as *const _, buf.len(), - )).map(|_| ()) + )) + .map(|_| ()) } } diff -Nru rust-openssl-0.10.16/src/ssl/callbacks.rs rust-openssl-0.10.23/src/ssl/callbacks.rs --- rust-openssl-0.10.16/src/ssl/callbacks.rs 2018-09-18 01:09:23.000000000 +0000 +++ rust-openssl-0.10.23/src/ssl/callbacks.rs 2019-05-18 19:09:02.000000000 +0000 @@ -23,8 +23,8 @@ #[cfg(any(ossl102, libressl261))] use ssl::AlpnError; #[cfg(ossl111)] -use ssl::{ExtensionContext, ClientHelloResponse}; -use ssl::{SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, SslSessionRef}; +use ssl::{ClientHelloResponse, ExtensionContext}; +use ssl::{SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, SslSessionRef, SESSION_CTX_INDEX}; #[cfg(ossl111)] use x509::X509Ref; use x509::{X509StoreContext, X509StoreContextRef}; @@ -353,7 +353,8 @@ { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl - .ssl_context() + .ex_data(*SESSION_CTX_INDEX) + .expect("BUG: session context missing") .ex_data(SslContext::cached_ex_index::()) .expect("BUG: new session callback missing") as *const F; let session = SslSession::from_ptr(session); @@ -398,7 +399,8 @@ { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl - .ssl_context() + .ex_data(*SESSION_CTX_INDEX) + .expect("BUG: session context missing") .ex_data(SslContext::cached_ex_index::()) .expect("BUG: get session callback missing") as *const F; let data = slice::from_raw_parts(data as *const u8, len as usize); diff -Nru rust-openssl-0.10.16/src/ssl/error.rs rust-openssl-0.10.23/src/ssl/error.rs --- rust-openssl-0.10.16/src/ssl/error.rs 2018-09-17 01:48:48.000000000 +0000 +++ rust-openssl-0.10.23/src/ssl/error.rs 2019-05-01 04:45:44.000000000 +0000 @@ -42,7 +42,7 @@ pub const SSL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SSL); /// The client hello callback indicated that it needed to be retried. - /// + /// /// Requires OpenSSL 1.1.1 or newer. #[cfg(ossl111)] pub const WANT_CLIENT_HELLO_CB: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_CLIENT_HELLO_CB); diff -Nru rust-openssl-0.10.16/src/ssl/mod.rs rust-openssl-0.10.23/src/ssl/mod.rs --- rust-openssl-0.10.16/src/ssl/mod.rs 2018-10-19 00:53:07.000000000 +0000 +++ rust-openssl-0.10.23/src/ssl/mod.rs 2019-05-18 19:09:02.000000000 +0000 @@ -113,6 +113,26 @@ #[cfg(test)] mod test; +/// Returns the OpenSSL name of a cipher corresponding to an RFC-standard cipher name. +/// +/// If the cipher has no corresponding OpenSSL name, the string `(NONE)` is returned. +/// +/// Requires OpenSSL 1.1.1 or newer. +/// +/// This corresponds to [`OPENSSL_cipher_name`] +/// +/// [`OPENSSL_cipher_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html +#[cfg(ossl111)] +pub fn cipher_name(std_name: &str) -> &'static str { + unsafe { + ffi::init(); + + let s = CString::new(std_name).unwrap(); + let ptr = ffi::OPENSSL_cipher_name(s.as_ptr()); + CStr::from_ptr(ptr).to_str().unwrap() + } +} + bitflags! { /// Options controlling the behavior of an `SslContext`. pub struct SslOptions: c_ulong { @@ -466,6 +486,8 @@ lazy_static! { static ref INDEXES: Mutex> = Mutex::new(HashMap::new()); static ref SSL_INDEXES: Mutex> = Mutex::new(HashMap::new()); + + static ref SESSION_CTX_INDEX: Index = Ssl::new_ex_index().unwrap(); } unsafe extern "C" fn free_data_box( @@ -830,7 +852,8 @@ self.as_ptr(), file.as_ptr() as *const _, ptr::null(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -849,6 +872,23 @@ } } + /// Add the provided CA certificate to the list sent by the server to the client when + /// requesting client-side TLS authentication. + /// + /// This corresponds to [`SSL_CTX_add_client_CA`]. + /// + /// [`SSL_CTX_add_client_CA`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_client_CA_list.html + #[cfg(not(libressl))] + pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_CTX_add_client_CA( + self.as_ptr(), + cacert.as_ptr() + )) + .map(|_| ()) + } + } + /// Set the context identifier for sessions. /// /// This value identifies the server's session cache to clients, telling them when they're @@ -868,7 +908,8 @@ self.as_ptr(), sid_ctx.as_ptr(), sid_ctx.len() as c_uint, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -892,7 +933,8 @@ self.as_ptr(), file.as_ptr() as *const _, file_type.as_raw(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -914,7 +956,8 @@ cvt(ffi::SSL_CTX_use_certificate_chain_file( self.as_ptr(), file.as_ptr() as *const _, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -961,7 +1004,8 @@ self.as_ptr(), file.as_ptr() as *const _, file_type.as_raw(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -993,7 +1037,8 @@ cvt(ffi::SSL_CTX_set_cipher_list( self.as_ptr(), cipher_list.as_ptr() as *const _, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -1016,7 +1061,8 @@ cvt(ffi::SSL_CTX_set_ciphersuites( self.as_ptr(), cipher_list.as_ptr() as *const _, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -1083,7 +1129,8 @@ cvt(ffi::SSL_CTX_set_min_proto_version( self.as_ptr(), version.map_or(0, |v| v.0 as _), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -1103,7 +1150,8 @@ cvt(ffi::SSL_CTX_set_max_proto_version( self.as_ptr(), version.map_or(0, |v| v.0 as _), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -1282,7 +1330,8 @@ cvt( ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(raw_tlsext_status::)) as c_int, - ).map(|_| ()) + ) + .map(|_| ()) } } @@ -1309,10 +1358,7 @@ } } - #[deprecated( - since = "0.10.10", - note = "renamed to `set_psk_client_callback`" - )] + #[deprecated(since = "0.10.10", note = "renamed to `set_psk_client_callback`")] #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub fn set_psk_callback(&mut self, callback: F) where @@ -1564,14 +1610,21 @@ parse_cb: ParseFn, ) -> Result<(), ErrorStack> where - AddFn: Fn(&mut SslRef, ExtensionContext, Option<(usize, &X509Ref)>) - -> Result, SslAlert> + AddFn: Fn( + &mut SslRef, + ExtensionContext, + Option<(usize, &X509Ref)>, + ) -> Result, SslAlert> + 'static + Sync + Send, T: AsRef<[u8]> + 'static + Sync + Send, - ParseFn: Fn(&mut SslRef, ExtensionContext, &[u8], Option<(usize, &X509Ref)>) - -> Result<(), SslAlert> + ParseFn: Fn( + &mut SslRef, + ExtensionContext, + &[u8], + Option<(usize, &X509Ref)>, + ) -> Result<(), SslAlert> + 'static + Sync + Send, @@ -1617,9 +1670,9 @@ } /// Sets a callback which will be invoked just after the client's hello message is received. - /// + /// /// Requires OpenSSL 1.1.1 or newer. - /// + /// /// This corresponds to [`SSL_CTX_set_client_hello_cb`]. /// /// [`SSL_CTX_set_client_hello_cb`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html @@ -1641,6 +1694,17 @@ } } + /// Sets the context's session cache size limit, returning the previous limit. + /// + /// A value of 0 means that the cache size is unbounded. + /// + /// This corresponds to [`SSL_CTX_sess_get_cache_size`]. + /// + /// [`SSL_CTX_sess_get_cache_size`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_sess_set_cache_size.html + pub fn set_session_cache_size(&mut self, size: i32) -> i64 { + unsafe { ffi::SSL_CTX_sess_set_cache_size(self.as_ptr(), size.into()).into() } + } + /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.0 @@ -1807,6 +1871,49 @@ pub fn max_early_data(&self) -> u32 { unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) } } + + /// Adds a session to the context's cache. + /// + /// Returns `true` if the session was successfully added to the cache, and `false` if it was already present. + /// + /// This corresponds to [`SSL_CTX_add_session`]. + /// + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session has never been used with another + /// `SslContext` than this one. + /// + /// [`SSL_CTX_add_session`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_remove_session.html + pub unsafe fn add_session(&self, session: &SslSessionRef) -> bool { + ffi::SSL_CTX_add_session(self.as_ptr(), session.as_ptr()) != 0 + } + + /// Removes a session from the context's cache and marks it as non-resumable. + /// + /// Returns `true` if the session was successfully found and removed, and `false` otherwise. + /// + /// This corresponds to [`SSL_CTX_remove_session`]. + /// + /// # Safety + /// + /// The caller of this method is responsible for ensuring that the session has never been used with another + /// `SslContext` than this one. + /// + /// [`SSL_CTX_remove_session`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_remove_session.html + pub unsafe fn remove_session(&self, session: &SslSessionRef) -> bool { + ffi::SSL_CTX_remove_session(self.as_ptr(), session.as_ptr()) != 0 + } + + /// Returns the context's session cache size limit. + /// + /// A value of 0 means that the cache size is unbounded. + /// + /// This corresponds to [`SSL_CTX_sess_get_cache_size`]. + /// + /// [`SSL_CTX_sess_get_cache_size`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_sess_set_cache_size.html + pub fn session_cache_size(&self) -> i64 { + unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()).into() } + } } /// Information about the state of a cipher. @@ -1866,12 +1973,29 @@ /// /// [`SSL_CIPHER_get_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html pub fn name(&self) -> &'static str { - let name = unsafe { + unsafe { let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr()); - CStr::from_ptr(ptr as *const _) - }; + CStr::from_ptr(ptr).to_str().unwrap() + } + } - str::from_utf8(name.to_bytes()).unwrap() + /// Returns the RFC-standard name of the cipher, if one exists. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CIPHER_standard_name`]. + /// + /// [`SSL_CIPHER_standard_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html + #[cfg(ossl111)] + pub fn standard_name(&self) -> Option<&'static str> { + unsafe { + let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(CStr::from_ptr(ptr).to_str().unwrap()) + } + } } /// Returns the SSL/TLS protocol version that first defined the cipher. @@ -2046,6 +2170,41 @@ unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) } } + /// Returns the time at which the session was established, in seconds since the Unix epoch. + /// + /// This corresponds to [`SSL_SESSION_get_time`]. + /// + /// [`SSL_SESSION_get_time`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_time.html + pub fn time(&self) -> i64 { + unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()).into() } + } + + /// Returns the sessions timeout, in seconds. + /// + /// A session older than this time should not be used for session resumption. + /// + /// This corresponds to [`SSL_SESSION_get_timeout`]. + /// + /// [`SSL_SESSION_get_timeout`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_time.html + pub fn timeout(&self) -> i64 { + unsafe { ffi::SSL_SESSION_get_timeout(self.as_ptr()).into() } + } + + /// Returns the session's TLS protocol version. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// This corresponds to [`SSL_SESSION_get_protocol_version`]. + /// + /// [`SSL_SESSION_get_protocol_version`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_time.html + #[cfg(ossl110)] + pub fn protocol_version(&self) -> SslVersion { + unsafe { + let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr()); + SslVersion(version) + } + } + to_der! { /// Serializes the session into a DER-encoded structure. /// @@ -2121,10 +2280,14 @@ /// This corresponds to [`SSL_new`]. /// /// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html + // FIXME should take &SslContextRef pub fn new(ctx: &SslContext) -> Result { unsafe { - let ssl = cvt_p(ffi::SSL_new(ctx.as_ptr()))?; - Ok(Ssl::from_ptr(ssl)) + let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?; + let mut ssl = Ssl::from_ptr(ptr); + ssl.set_ex_data(*SESSION_CTX_INDEX, ctx.clone()); + + Ok(ssl) } } @@ -2753,7 +2916,8 @@ context, contextlen, use_context, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -2783,7 +2947,8 @@ label.len(), context.as_ptr() as *const c_uchar, context.len(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -2861,7 +3026,8 @@ self.as_ptr(), p as *mut c_uchar, response.len() as c_long, - ) as c_int).map(|_| ()) + ) as c_int) + .map(|_| ()) } } @@ -2977,29 +3143,27 @@ } /// Determines if the client's hello message is in the SSLv2 format. - /// + /// /// This can only be used inside of the client hello callback. Otherwise, `false` is returned. - /// + /// /// Requires OpenSSL 1.1.1 or newer. - /// + /// /// This corresponds to [`SSL_client_hello_isv2`]. - /// + /// /// [`SSL_client_hello_isv2`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_isv2(&self) -> bool { - unsafe { - ffi::SSL_client_hello_isv2(self.as_ptr()) != 0 - } + unsafe { ffi::SSL_client_hello_isv2(self.as_ptr()) != 0 } } /// Returns the legacy version field of the client's hello message. - /// + /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. - /// + /// /// Requires OpenSSL 1.1.1 or newer. - /// + /// /// This corresponds to [`SSL_client_hello_get0_legacy_version`]. - /// + /// /// [`SSL_client_hello_get0_legacy_version`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_legacy_version(&self) -> Option { @@ -3014,13 +3178,13 @@ } /// Returns the random field of the client's hello message. - /// + /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. - /// + /// /// Requires OpenSSL 1.1.1 or newer. - /// + /// /// This corresponds to [`SSL_client_hello_get0_random`]. - /// + /// /// [`SSL_client_hello_get0_random`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_random(&self) -> Option<&[u8]> { @@ -3036,13 +3200,13 @@ } /// Returns the session ID field of the client's hello message. - /// + /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. - /// + /// /// Requires OpenSSL 1.1.1 or newer. - /// + /// /// This corresponds to [`SSL_client_hello_get0_session_id`]. - /// + /// /// [`SSL_client_hello_get0_session_id`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_session_id(&self) -> Option<&[u8]> { @@ -3058,13 +3222,13 @@ } /// Returns the ciphers field of the client's hello message. - /// + /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. - /// + /// /// Requires OpenSSL 1.1.1 or newer. - /// + /// /// This corresponds to [`SSL_client_hello_get0_ciphers`]. - /// + /// /// [`SSL_client_hello_get0_ciphers`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_ciphers(&self) -> Option<&[u8]> { @@ -3080,13 +3244,13 @@ } /// Returns the compression methods field of the client's hello message. - /// + /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returend. - /// + /// /// Requires OpenSSL 1.1.1 or newer. - /// + /// /// This corresponds to [`SSL_client_hello_get0_compression_methods`]. - /// + /// /// [`SSL_client_hello_get0_compression_methods`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_client_hello_cb.html #[cfg(ossl111)] pub fn client_hello_compression_methods(&self) -> Option<&[u8]> { @@ -3363,13 +3527,13 @@ Ok(n) => return Ok(n), Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => return Ok(0), Err(ref e) if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() => { - return Ok(0) + return Ok(0); } Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} Err(e) => { return Err(e .into_io_error() - .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))) + .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))); } } } @@ -3385,7 +3549,7 @@ Err(e) => { return Err(e .into_io_error() - .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))) + .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))); } } } @@ -3690,9 +3854,14 @@ } cfg_if! { - if #[cfg(ossl110)] { + if #[cfg(any(ossl110, libressl291))] { use ffi::{TLS_method, DTLS_method}; - + } else { + use ffi::{SSLv23_method as TLS_method, DTLSv1_method as DTLS_method}; + } +} +cfg_if! { + if #[cfg(ossl110)] { unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { ffi::CRYPTO_get_ex_new_index( ffi::CRYPTO_EX_INDEX_SSL_CTX, @@ -3715,8 +3884,6 @@ ) } } else { - use ffi::{SSLv23_method as TLS_method, DTLSv1_method as DTLS_method}; - unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) } diff -Nru rust-openssl-0.10.16/src/ssl/test/mod.rs rust-openssl-0.10.23/src/ssl/test/mod.rs --- rust-openssl-0.10.16/src/ssl/test/mod.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-openssl-0.10.23/src/ssl/test/mod.rs 2019-05-18 19:09:02.000000000 +0000 @@ -0,0 +1,1413 @@ +#![allow(unused_imports)] + +use hex; +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::io::{self, BufReader}; +use std::iter; +use std::mem; +use std::net::UdpSocket; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::path::Path; +use std::process::{Child, ChildStdin, Command, Stdio}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::Duration; +use tempdir::TempDir; + +use dh::Dh; +use hash::MessageDigest; +use ocsp::{OcspResponse, OcspResponseStatus}; +use pkey::PKey; +use srtp::SrtpProfileId; +use ssl; +use ssl::test::server::Server; +#[cfg(any(ossl110, ossl111, libressl261))] +use ssl::SslVersion; +#[cfg(ossl111)] +use ssl::{ClientHelloResponse, ExtensionContext}; +use ssl::{ + Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, ShutdownState, Ssl, SslAcceptor, + SslConnector, SslContext, SslFiletype, SslMethod, SslOptions, SslSessionCacheMode, SslStream, + SslVerifyMode, StatusType, SslContextBuilder +}; +#[cfg(ossl102)] +use x509::store::X509StoreBuilder; +#[cfg(ossl102)] +use x509::verify::X509CheckFlags; +use x509::{X509Name, X509StoreContext, X509VerifyResult, X509}; + +mod server; + +static ROOT_CERT: &'static [u8] = include_bytes!("../../../test/root-ca.pem"); +static CERT: &'static [u8] = include_bytes!("../../../test/cert.pem"); +static KEY: &'static [u8] = include_bytes!("../../../test/key.pem"); + +#[test] +fn verify_untrusted() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_verify(SslVerifyMode::PEER); + + client.connect_err(); +} + +#[test] +fn verify_trusted() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + + client.connect(); +} + +#[test] +#[cfg(ossl102)] +fn verify_trusted_with_set_cert() { + let server = Server::builder().build(); + + let mut store = X509StoreBuilder::new().unwrap(); + let x509 = X509::from_pem(ROOT_CERT).unwrap(); + store.add_cert(x509).unwrap(); + + let mut client = server.client(); + client.ctx().set_verify(SslVerifyMode::PEER); + client.ctx().set_verify_cert_store(store.build()).unwrap(); + + client.connect(); +} + +#[test] +fn verify_untrusted_callback_override_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_untrusted_callback_override_bad() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, _| false); + + client.connect_err(); +} + +#[test] +fn verify_trusted_callback_override_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_callback_override_bad() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, _| false); + + client.connect_err(); +} + +#[test] +fn verify_callback_load_certs() { + let server = Server::builder().build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert!(x509.current_cert().is_some()); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_get_error_ok() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert_eq!(x509.error(), X509VerifyResult::OK); + true + }); + + client.connect(); +} + +#[test] +fn verify_trusted_get_error_err() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, |_, x509| { + assert_ne!(x509.error(), X509VerifyResult::OK); + false + }); + + client.connect_err(); +} + +#[test] +fn verify_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let server = Server::builder().build(); + + let mut client = server.client(); + let expected = "59172d9313e84459bcff27f967e79e6e9217e584"; + client + .ctx() + .set_verify_callback(SslVerifyMode::PEER, move |_, x509| { + CALLED_BACK.store(true, Ordering::SeqCst); + let cert = x509.current_cert().unwrap(); + let digest = cert.digest(MessageDigest::sha1()).unwrap(); + assert_eq!(hex::encode(&digest), expected); + true + }); + + client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn ssl_verify_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let server = Server::builder().build(); + + let mut client = server.client().build().builder(); + let expected = "59172d9313e84459bcff27f967e79e6e9217e584"; + client + .ssl() + .set_verify_callback(SslVerifyMode::PEER, move |_, x509| { + CALLED_BACK.store(true, Ordering::SeqCst); + let cert = x509.current_cert().unwrap(); + let digest = cert.digest(MessageDigest::sha1()).unwrap(); + assert_eq!(hex::encode(&digest), expected); + true + }); + + client.connect(); + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn get_ctx_options() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.options(); +} + +#[test] +fn set_ctx_options() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let opts = ctx.set_options(SslOptions::NO_TICKET); + assert!(opts.contains(SslOptions::NO_TICKET)); +} + +#[test] +fn clear_ctx_options() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_options(SslOptions::ALL); + let opts = ctx.clear_options(SslOptions::ALL); + assert!(!opts.contains(SslOptions::ALL)); +} + +#[test] +fn zero_length_buffers() { + let server = Server::builder().build(); + + let mut s = server.client().connect(); + assert_eq!(s.write(&[]).unwrap(), 0); + assert_eq!(s.read(&mut []).unwrap(), 0); +} + +#[test] +fn peer_certificate() { + let server = Server::builder().build(); + + let s = server.client().connect(); + let cert = s.ssl().peer_certificate().unwrap(); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); + assert_eq!( + hex::encode(fingerprint), + "59172d9313e84459bcff27f967e79e6e9217e584" + ); +} + +#[test] +fn pending() { + let mut server = Server::builder(); + server.io_cb(|mut s| s.write_all(&[0; 10]).unwrap()); + let server = server.build(); + + let mut s = server.client().connect(); + s.read_exact(&mut [0]).unwrap(); + + assert_eq!(s.ssl().pending(), 9); + assert_eq!(s.read(&mut [0; 10]).unwrap(), 9); +} + +#[test] +fn state() { + let server = Server::builder().build(); + + let s = server.client().connect(); + assert_eq!(s.ssl().state_string(), "SSLOK "); + assert_eq!( + s.ssl().state_string_long(), + "SSL negotiation finished successfully" + ); +} + +/// Tests that when both the client as well as the server use SRTP and their +/// lists of supported protocols have an overlap -- with only ONE protocol +/// being valid for both. +#[test] +#[cfg_attr(libressl291, ignore)] +fn test_connect_with_srtp_ctx() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + ctx.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) + .unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + + let mut buf = [0; 60]; + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + ctx.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 60]; + { + let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); + assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); + assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); + } + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .expect("extract"); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf[..], buf2[..]); +} + +/// Tests that when both the client as well as the server use SRTP and their +/// lists of supported protocols have an overlap -- with only ONE protocol +/// being valid for both. +#[test] +#[cfg_attr(libressl291, ignore)] +fn test_connect_with_srtp_ssl() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) + .unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + let mut profilenames = String::new(); + for profile in ssl.srtp_profiles().unwrap() { + if profilenames.len() > 0 { + profilenames.push(':'); + } + profilenames += profile.name(); + } + assert_eq!( + "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", + profilenames + ); + let mut stream = ssl.accept(stream).unwrap(); + + let mut buf = [0; 60]; + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let ctx = SslContext::builder(SslMethod::dtls()).unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") + .unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 60]; + { + let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); + assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); + assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); + } + stream + .ssl() + .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) + .expect("extract"); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf[..], buf2[..]); +} + +/// Tests that when the `SslStream` is created as a server stream, the protocols +/// are correctly advertised to the client. +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_advertise_multiple() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) + }); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x08spdy/3.1").unwrap(); + let s = client.connect(); + assert_eq!(s.ssl().selected_alpn_protocol(), Some(&b"spdy/3.1"[..])); +} + +#[test] +#[cfg(any(ossl110))] +fn test_alpn_server_select_none_fatal() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client) + .ok_or(ssl::AlpnError::ALERT_FATAL) + }); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + client.connect_err(); +} + +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_select_none() { + let mut server = Server::builder(); + server.ctx().set_alpn_select_callback(|_, client| { + ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) + }); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + let s = client.connect(); + assert_eq!(None, s.ssl().selected_alpn_protocol()); +} + +#[test] +#[cfg(any(ossl102, libressl261))] +fn test_alpn_server_unilateral() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_alpn_protos(b"\x06http/2").unwrap(); + let s = client.connect(); + assert_eq!(None, s.ssl().selected_alpn_protocol()); +} + +#[test] +#[should_panic(expected = "blammo")] +fn write_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + } + + impl Write for ExplodingStream { + fn write(&mut self, _: &[u8]) -> io::Result { + panic!("blammo"); + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +#[should_panic(expected = "blammo")] +fn read_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, _: &mut [u8]) -> io::Result { + panic!("blammo"); + } + } + + impl Write for ExplodingStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.0.flush() + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +#[should_panic(expected = "blammo")] +fn flush_panic() { + struct ExplodingStream(TcpStream); + + impl Read for ExplodingStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + } + + impl Write for ExplodingStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + panic!("blammo"); + } + } + + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let stream = ExplodingStream(server.connect_tcp()); + + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); +} + +#[test] +fn refcount_ssl_context() { + let mut ssl = { + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ssl::Ssl::new(&ctx.build()).unwrap() + }; + + { + let new_ctx_a = SslContext::builder(SslMethod::tls()).unwrap().build(); + let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a); + } +} + +#[test] +#[cfg_attr(libressl250, ignore)] +#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] +fn default_verify_paths() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_default_verify_paths().unwrap(); + ctx.set_verify(SslVerifyMode::PEER); + let ctx = ctx.build(); + let s = TcpStream::connect("google.com:443").unwrap(); + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl.set_hostname("google.com").unwrap(); + let mut socket = ssl.connect(s).unwrap(); + + socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); + let mut result = vec![]; + socket.read_to_end(&mut result).unwrap(); + + println!("{}", String::from_utf8_lossy(&result)); + assert!(result.starts_with(b"HTTP/1.0")); + assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); +} + +#[test] +fn add_extra_chain_cert() { + let cert = X509::from_pem(CERT).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.add_extra_chain_cert(cert).unwrap(); +} + +#[test] +#[cfg(ossl102)] +fn verify_valid_hostname() { + let server = Server::builder().build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + let mut client = client.build().builder(); + client + .ssl() + .param_mut() + .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + client.ssl().param_mut().set_host("foobar.com").unwrap(); + client.connect(); +} + +#[test] +#[cfg(ossl102)] +fn verify_invalid_hostname() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_ca_file("test/root-ca.pem").unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + let mut client = client.build().builder(); + client + .ssl() + .param_mut() + .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + client.ssl().param_mut().set_host("bogus.com").unwrap(); + client.connect_err(); +} + +#[test] +fn connector_valid_hostname() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + let mut s = connector.build().connect("foobar.com", s).unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_invalid_hostname() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + connector.build().connect("bogus.com", s).unwrap_err(); +} + +#[test] +fn connector_invalid_no_hostname_verification() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + let mut s = connector + .build() + .configure() + .unwrap() + .verify_hostname(false) + .connect("bogus.com", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_no_hostname_still_verifies() { + let mut server = Server::builder(); + server.should_error(); + let server = server.build(); + + let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); + + let s = server.connect_tcp(); + assert!(connector + .configure() + .unwrap() + .verify_hostname(false) + .connect("fizzbuzz.com", s) + .is_err()); +} + +#[test] +fn connector_no_hostname_can_disable_verify() { + let server = Server::builder().build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_verify(SslVerifyMode::NONE); + let connector = connector.build(); + + let s = server.connect_tcp(); + let mut s = connector + .configure() + .unwrap() + .verify_hostname(false) + .connect("foobar.com", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); +} + +#[test] +fn connector_client_server_mozilla_intermediate() { + let listener = TcpListener::bind("127.0.0.1:1234").unwrap(); + let port = listener.local_addr().unwrap().port(); + + let t = thread::spawn(move || { + let key = PKey::private_key_from_pem(KEY).unwrap(); + let cert = X509::from_pem(CERT).unwrap(); + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + acceptor.set_private_key(&key).unwrap(); + acceptor.set_certificate(&cert).unwrap(); + let acceptor = acceptor.build(); + let stream = listener.accept().unwrap().0; + let mut stream = acceptor.accept(stream).unwrap(); + + stream.write_all(b"hello").unwrap(); + }); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + let connector = connector.build(); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut stream = connector.connect("foobar.com", stream).unwrap(); + + let mut buf = [0; 5]; + stream.read_exact(&mut buf).unwrap(); + assert_eq!(b"hello", &buf); + + t.join().unwrap(); +} + +#[test] +fn connector_client_server_mozilla_modern() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + let t = thread::spawn(move || { + let key = PKey::private_key_from_pem(KEY).unwrap(); + let cert = X509::from_pem(CERT).unwrap(); + let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); + acceptor.set_private_key(&key).unwrap(); + acceptor.set_certificate(&cert).unwrap(); + let acceptor = acceptor.build(); + let stream = listener.accept().unwrap().0; + let mut stream = acceptor.accept(stream).unwrap(); + + stream.write_all(b"hello").unwrap(); + }); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + let connector = connector.build(); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut stream = connector.connect("foobar.com", stream).unwrap(); + + let mut buf = [0; 5]; + stream.read_exact(&mut buf).unwrap(); + assert_eq!(b"hello", &buf); + + t.join().unwrap(); +} + +#[test] +fn shutdown() { + let mut server = Server::builder(); + server.io_cb(|mut s| { + assert_eq!(s.read(&mut [0]).unwrap(), 0); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Received); + }); + let server = server.build(); + + let mut s = server.client().connect(); + + assert_eq!(s.get_shutdown(), ShutdownState::empty()); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Sent); + assert_eq!(s.get_shutdown(), ShutdownState::SENT); + assert_eq!(s.shutdown().unwrap(), ShutdownResult::Received); + assert_eq!( + s.get_shutdown(), + ShutdownState::SENT | ShutdownState::RECEIVED + ); +} + +#[test] +fn client_ca_list() { + let names = X509Name::load_client_ca_file("test/root-ca.pem").unwrap(); + assert_eq!(names.len(), 1); + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_client_ca_list(names); +} + +#[test] +fn cert_store() { + let server = Server::builder().build(); + + let mut client = server.client(); + let cert = X509::from_pem(ROOT_CERT).unwrap(); + client.ctx().cert_store_mut().add_cert(cert).unwrap(); + client.ctx().set_verify(SslVerifyMode::PEER); + + client.connect(); +} + +#[test] +fn tmp_dh_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::params_from_pem(dh) + }); + + let server = server.build(); + + let mut client = server.client(); + // TLS 1.3 has no DH suites, so make sure we don't pick that version + #[cfg(ossl111)] + client.ctx().set_options(super::SslOptions::NO_TLSV1_3); + client.ctx().set_cipher_list("EDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(all(ossl101, not(ossl110)))] +fn tmp_ecdh_callback() { + use ec::EcKey; + use nid::Nid; + + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::from_curve_name(Nid::X9_62_PRIME256V1) + }); + + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_cipher_list("ECDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn tmp_dh_callback_ssl() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ssl_cb(|ssl| { + ssl.set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::params_from_pem(dh) + }); + }); + + let server = server.build(); + + let mut client = server.client(); + // TLS 1.3 has no DH suites, so make sure we don't pick that version + #[cfg(ossl111)] + client.ctx().set_options(super::SslOptions::NO_TLSV1_3); + client.ctx().set_cipher_list("EDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(all(ossl101, not(ossl110)))] +fn tmp_ecdh_callback_ssl() { + use ec::EcKey; + use nid::Nid; + + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ssl_cb(|ssl| { + ssl.set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::from_curve_name(Nid::X9_62_PRIME256V1) + }); + }); + + let server = server.build(); + + let mut client = server.client(); + client.ctx().set_cipher_list("ECDH").unwrap(); + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn idle_session() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.session().is_none()); +} + +#[test] +fn active_session() { + let server = Server::builder().build(); + + let s = server.client().connect(); + + let session = s.ssl().session().unwrap(); + let len = session.master_key_len(); + let mut buf = vec![0; len - 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, buf.len()); + let mut buf = vec![0; len + 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, len); +} + +#[test] +fn status_callbacks() { + static CALLED_BACK_SERVER: AtomicBool = AtomicBool::new(false); + static CALLED_BACK_CLIENT: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server + .ctx() + .set_status_callback(|ssl| { + CALLED_BACK_SERVER.store(true, Ordering::SeqCst); + let response = OcspResponse::create(OcspResponseStatus::UNAUTHORIZED, None).unwrap(); + let response = response.to_der().unwrap(); + ssl.set_ocsp_status(&response).unwrap(); + Ok(true) + }) + .unwrap(); + + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_status_callback(|ssl| { + CALLED_BACK_CLIENT.store(true, Ordering::SeqCst); + let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); + assert_eq!(response.status(), OcspResponseStatus::UNAUTHORIZED); + Ok(true) + }) + .unwrap(); + + let mut client = client.build().builder(); + client.ssl().set_status_type(StatusType::OCSP).unwrap(); + + client.connect(); + + assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst)); + assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst)); +} + +#[test] +fn new_session_callback() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_session_id_context(b"foo").unwrap(); + + let server = server.build(); + + let mut client = server.client(); + + client + .ctx() + .set_session_cache_mode(SslSessionCacheMode::CLIENT | SslSessionCacheMode::NO_INTERNAL); + client + .ctx() + .set_new_session_callback(|_, _| CALLED_BACK.store(true, Ordering::SeqCst)); + + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn new_session_callback_swapped_ctx() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_session_id_context(b"foo").unwrap(); + + let server = server.build(); + + let mut client = server.client(); + + client + .ctx() + .set_session_cache_mode(SslSessionCacheMode::CLIENT | SslSessionCacheMode::NO_INTERNAL); + client + .ctx() + .set_new_session_callback(|_, _| CALLED_BACK.store(true, Ordering::SeqCst)); + + let mut client = client.build().builder(); + + let ctx = SslContextBuilder::new(SslMethod::tls()).unwrap().build(); + client.ssl().set_ssl_context(&ctx).unwrap(); + + client.connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn keying_export() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + + let label = "EXPERIMENTAL test"; + let context = b"my context"; + + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) + .unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.accept(stream).unwrap(); + + let mut buf = [0; 32]; + stream + .ssl() + .export_keying_material(&mut buf, label, Some(context)) + .unwrap(); + + stream.write_all(&[0]).unwrap(); + + buf + }); + + let stream = TcpStream::connect(addr).unwrap(); + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + let mut stream = ssl.connect(stream).unwrap(); + + let mut buf = [1; 32]; + stream + .ssl() + .export_keying_material(&mut buf, label, Some(context)) + .unwrap(); + + stream.read_exact(&mut [0]).unwrap(); + + let buf2 = guard.join().unwrap(); + + assert_eq!(buf, buf2); +} + +#[test] +#[cfg(any(ossl110, libressl261))] +fn no_version_overlap() { + let mut server = Server::builder(); + server.ctx().set_min_proto_version(None).unwrap(); + server + .ctx() + .set_max_proto_version(Some(SslVersion::TLS1_1)) + .unwrap(); + #[cfg(any(ossl110g, libressl270))] + assert_eq!(server.ctx().max_proto_version(), Some(SslVersion::TLS1_1)); + server.should_error(); + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .set_min_proto_version(Some(SslVersion::TLS1_2)) + .unwrap(); + #[cfg(ossl110g)] + assert_eq!(client.ctx().min_proto_version(), Some(SslVersion::TLS1_2)); + client.ctx().set_max_proto_version(None).unwrap(); + + client.connect_err(); +} + +#[test] +#[cfg(ossl111)] +fn custom_extensions() { + static FOUND_EXTENSION: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server + .ctx() + .add_custom_ext( + 12345, + ExtensionContext::CLIENT_HELLO, + |_, _, _| -> Result, _> { unreachable!() }, + |_, _, data, _| { + FOUND_EXTENSION.store(data == b"hello", Ordering::SeqCst); + Ok(()) + }, + ) + .unwrap(); + + let server = server.build(); + + let mut client = server.client(); + client + .ctx() + .add_custom_ext( + 12345, + ssl::ExtensionContext::CLIENT_HELLO, + |_, _, _| Ok(Some(b"hello")), + |_, _, _, _| unreachable!(), + ) + .unwrap(); + + client.connect(); + + assert!(FOUND_EXTENSION.load(Ordering::SeqCst)); +} + +fn _check_kinds() { + fn is_send() {} + fn is_sync() {} + + is_send::>(); + is_sync::>(); +} + +#[test] +#[cfg(ossl111)] +fn stateless() { + use super::SslOptions; + + #[derive(Debug)] + struct MemoryStream { + incoming: io::Cursor>, + outgoing: Vec, + } + + impl MemoryStream { + pub fn new() -> Self { + Self { + incoming: io::Cursor::new(Vec::new()), + outgoing: Vec::new(), + } + } + + pub fn extend_incoming(&mut self, data: &[u8]) { + self.incoming.get_mut().extend_from_slice(data); + } + + pub fn take_outgoing(&mut self) -> Outgoing { + Outgoing(&mut self.outgoing) + } + } + + impl Read for MemoryStream { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let n = self.incoming.read(buf)?; + if self.incoming.position() == self.incoming.get_ref().len() as u64 { + self.incoming.set_position(0); + self.incoming.get_mut().clear(); + } + if n == 0 { + return Err(io::Error::new( + io::ErrorKind::WouldBlock, + "no data available", + )); + } + Ok(n) + } + } + + impl Write for MemoryStream { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.outgoing.write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + pub struct Outgoing<'a>(&'a mut Vec); + + impl<'a> Drop for Outgoing<'a> { + fn drop(&mut self) { + self.0.clear(); + } + } + + impl<'a> ::std::ops::Deref for Outgoing<'a> { + type Target = [u8]; + fn deref(&self) -> &[u8] { + &self.0 + } + } + + impl<'a> AsRef<[u8]> for Outgoing<'a> { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + fn send(from: &mut MemoryStream, to: &mut MemoryStream) { + to.extend_incoming(&from.take_outgoing()); + } + + fn hs( + stream: Result, HandshakeError>, + ) -> Result, MidHandshakeSslStream> { + match stream { + Ok(stream) => Ok(stream), + Err(HandshakeError::WouldBlock(stream)) => Err(stream), + Err(e) => panic!("unexpected error: {:?}", e), + } + } + + // + // Setup + // + + let mut client_ctx = SslContext::builder(SslMethod::tls()).unwrap(); + client_ctx.clear_options(SslOptions::ENABLE_MIDDLEBOX_COMPAT); + let client_stream = Ssl::new(&client_ctx.build()).unwrap(); + + let mut server_ctx = SslContext::builder(SslMethod::tls()).unwrap(); + server_ctx + .set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) + .unwrap(); + server_ctx + .set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) + .unwrap(); + const COOKIE: &[u8] = b"chocolate chip"; + server_ctx.set_stateless_cookie_generate_cb(|_tls, buf| { + buf[0..COOKIE.len()].copy_from_slice(COOKIE); + Ok(COOKIE.len()) + }); + server_ctx.set_stateless_cookie_verify_cb(|_tls, buf| buf == COOKIE); + let mut server_stream = + ssl::SslStreamBuilder::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new()); + + // + // Handshake + // + + // Initial ClientHello + let mut client_stream = hs(client_stream.connect(MemoryStream::new())).unwrap_err(); + send(client_stream.get_mut(), server_stream.get_mut()); + // HelloRetryRequest + assert!(!server_stream.stateless().unwrap()); + send(server_stream.get_mut(), client_stream.get_mut()); + // Second ClientHello + let mut client_stream = hs(client_stream.handshake()).unwrap_err(); + send(client_stream.get_mut(), server_stream.get_mut()); + // OldServerHello + assert!(server_stream.stateless().unwrap()); + let mut server_stream = hs(server_stream.accept()).unwrap_err(); + send(server_stream.get_mut(), client_stream.get_mut()); + // Finished + let mut client_stream = hs(client_stream.handshake()).unwrap(); + send(client_stream.get_mut(), server_stream.get_mut()); + hs(server_stream.handshake()).unwrap(); +} + +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +#[test] +fn psk_ciphers() { + const CIPHER: &'static str = "PSK-AES128-CBC-SHA"; + const PSK: &[u8] = b"thisisaverysecurekey"; + const CLIENT_IDENT: &[u8] = b"thisisaclient"; + static CLIENT_CALLED: AtomicBool = AtomicBool::new(false); + static SERVER_CALLED: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_cipher_list(CIPHER).unwrap(); + server.ctx().set_psk_server_callback(|_, identity, psk| { + assert!(identity.unwrap_or(&[]) == CLIENT_IDENT); + psk[..PSK.len()].copy_from_slice(PSK); + SERVER_CALLED.store(true, Ordering::SeqCst); + Ok(PSK.len()) + }); + + let server = server.build(); + + let mut client = server.client(); + // This test relies on TLS 1.2 suites + #[cfg(ossl111)] + client.ctx().set_options(super::SslOptions::NO_TLSV1_3); + client.ctx().set_cipher_list(CIPHER).unwrap(); + client + .ctx() + .set_psk_client_callback(move |_, _, identity, psk| { + identity[..CLIENT_IDENT.len()].copy_from_slice(&CLIENT_IDENT); + identity[CLIENT_IDENT.len()] = 0; + psk[..PSK.len()].copy_from_slice(PSK); + CLIENT_CALLED.store(true, Ordering::SeqCst); + Ok(PSK.len()) + }); + + client.connect(); + + assert!(CLIENT_CALLED.load(Ordering::SeqCst) && SERVER_CALLED.load(Ordering::SeqCst)); +} + +#[test] +fn sni_callback_swapped_ctx() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_servername_callback(|_, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(()) + }); + + let keyed_ctx = mem::replace(server.ctx(), ctx).build(); + server.ssl_cb(move |ssl| ssl.set_ssl_context(&keyed_ctx).unwrap()); + + let server = server.build(); + + server.client().connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(ossl111)] +fn client_hello() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut server = Server::builder(); + server.ctx().set_client_hello_callback(|ssl, _| { + assert!(!ssl.client_hello_isv2()); + assert_eq!(ssl.client_hello_legacy_version(), Some(SslVersion::TLS1_2)); + assert!(ssl.client_hello_random().is_some()); + assert!(ssl.client_hello_session_id().is_some()); + assert!(ssl.client_hello_ciphers().is_some()); + assert!(ssl.client_hello_compression_methods().is_some()); + + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(ClientHelloResponse::SUCCESS) + }); + + let server = server.build(); + server.client().connect(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(ossl111)] +fn openssl_cipher_name() { + assert_eq!( + super::cipher_name("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"), + "ECDHE-RSA-AES256-SHA384", + ); + + assert_eq!(super::cipher_name("asdf"), "(NONE)"); +} + +#[test] +fn session_cache_size() { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_session_cache_size(1234); + let ctx = ctx.build(); + assert_eq!(ctx.session_cache_size(), 1234); +} diff -Nru rust-openssl-0.10.16/src/ssl/test/server.rs rust-openssl-0.10.23/src/ssl/test/server.rs --- rust-openssl-0.10.16/src/ssl/test/server.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-openssl-0.10.23/src/ssl/test/server.rs 2019-05-01 04:45:44.000000000 +0000 @@ -0,0 +1,167 @@ +use std::io::{Read, Write}; +use std::net::{SocketAddr, TcpListener, TcpStream}; +use std::thread::{self, JoinHandle}; + +use ssl::{Ssl, SslContext, SslContextBuilder, SslFiletype, SslMethod, SslRef, SslStream}; + +pub struct Server { + handle: Option>, + addr: SocketAddr, +} + +impl Drop for Server { + fn drop(&mut self) { + if !thread::panicking() { + self.handle.take().unwrap().join().unwrap(); + } + } +} + +impl Server { + pub fn builder() -> Builder { + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_chain_file("test/cert.pem").unwrap(); + ctx.set_private_key_file("test/key.pem", SslFiletype::PEM) + .unwrap(); + + Builder { + ctx, + ssl_cb: Box::new(|_| {}), + io_cb: Box::new(|_| {}), + should_error: false, + } + } + + pub fn client(&self) -> ClientBuilder { + ClientBuilder { + ctx: SslContext::builder(SslMethod::tls()).unwrap(), + addr: self.addr, + } + } + + pub fn connect_tcp(&self) -> TcpStream { + TcpStream::connect(self.addr).unwrap() + } +} + +pub struct Builder { + ctx: SslContextBuilder, + ssl_cb: Box, + io_cb: Box) + Send>, + should_error: bool, +} + +impl Builder { + pub fn ctx(&mut self) -> &mut SslContextBuilder { + &mut self.ctx + } + + pub fn ssl_cb(&mut self, cb: F) + where + F: 'static + FnMut(&mut SslRef) + Send, + { + self.ssl_cb = Box::new(cb); + } + + pub fn io_cb(&mut self, cb: F) + where + F: 'static + FnMut(SslStream) + Send, + { + self.io_cb = Box::new(cb); + } + + pub fn should_error(&mut self) { + self.should_error = true; + } + + pub fn build(self) -> Server { + let ctx = self.ctx.build(); + let socket = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = socket.local_addr().unwrap(); + let mut ssl_cb = self.ssl_cb; + let mut io_cb = self.io_cb; + let should_error = self.should_error; + + let handle = thread::spawn(move || { + let socket = socket.accept().unwrap().0; + let mut ssl = Ssl::new(&ctx).unwrap(); + ssl_cb(&mut ssl); + let r = ssl.accept(socket); + if should_error { + r.unwrap_err(); + } else { + let mut socket = r.unwrap(); + socket.write_all(&[0]).unwrap(); + io_cb(socket); + } + }); + + Server { + handle: Some(handle), + addr, + } + } +} + +pub struct ClientBuilder { + ctx: SslContextBuilder, + addr: SocketAddr, +} + +impl ClientBuilder { + pub fn ctx(&mut self) -> &mut SslContextBuilder { + &mut self.ctx + } + + pub fn build(self) -> Client { + Client { + ctx: self.ctx.build(), + addr: self.addr, + } + } + + pub fn connect(self) -> SslStream { + self.build().builder().connect() + } + + pub fn connect_err(self) { + self.build().builder().connect_err(); + } +} + +pub struct Client { + ctx: SslContext, + addr: SocketAddr, +} + +impl Client { + pub fn builder(&self) -> ClientSslBuilder { + ClientSslBuilder { + ssl: Ssl::new(&self.ctx).unwrap(), + addr: self.addr, + } + } +} + +pub struct ClientSslBuilder { + ssl: Ssl, + addr: SocketAddr, +} + +impl ClientSslBuilder { + pub fn ssl(&mut self) -> &mut SslRef { + &mut self.ssl + } + + pub fn connect(self) -> SslStream { + let socket = TcpStream::connect(self.addr).unwrap(); + let mut s = self.ssl.connect(socket).unwrap(); + s.read_exact(&mut [0]).unwrap(); + s + } + + pub fn connect_err(self) { + let socket = TcpStream::connect(self.addr).unwrap(); + self.ssl.connect(socket).unwrap_err(); + } +} diff -Nru rust-openssl-0.10.16/src/ssl/test.rs rust-openssl-0.10.23/src/ssl/test.rs --- rust-openssl-0.10.16/src/ssl/test.rs 2018-10-26 05:13:14.000000000 +0000 +++ rust-openssl-0.10.23/src/ssl/test.rs 1970-01-01 00:00:00.000000000 +0000 @@ -1,1841 +0,0 @@ -#![allow(unused_imports)] - -use std::env; -use std::fs::File; -use std::io::prelude::*; -use std::io::{self, BufReader}; -use std::iter; -use std::mem; -use std::net::{SocketAddr, TcpListener, TcpStream}; -use std::path::Path; -use std::process::{Child, ChildStdin, Command, Stdio}; -use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT}; -use std::thread; -use std::time::Duration; -use tempdir::TempDir; - -use dh::Dh; -use hash::MessageDigest; -use ocsp::{OcspResponse, OcspResponseStatus}; -use pkey::PKey; -use srtp::SrtpProfileId; -use ssl; -#[cfg(any(ossl110, ossl111, libressl261))] -use ssl::SslVersion; -use ssl::{ - Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, ShutdownState, Ssl, SslAcceptor, - SslConnector, SslContext, SslFiletype, SslMethod, SslSessionCacheMode, SslStream, - SslVerifyMode, StatusType, -}; -#[cfg(any(ossl102, ossl110))] -use x509::verify::X509CheckFlags; -use x509::{X509, X509Name, X509StoreContext, X509VerifyResult}; - -use std::net::UdpSocket; - -static ROOT_CERT: &'static [u8] = include_bytes!("../../test/root-ca.pem"); -static CERT: &'static [u8] = include_bytes!("../../test/cert.pem"); -static KEY: &'static [u8] = include_bytes!("../../test/key.pem"); - -fn next_addr() -> SocketAddr { - use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; - static PORT: AtomicUsize = ATOMIC_USIZE_INIT; - let port = 15411 + PORT.fetch_add(1, Ordering::SeqCst); - - format!("127.0.0.1:{}", port).parse().unwrap() -} - -struct Server { - p: Child, - _temp: TempDir, -} - -impl Server { - fn spawn(args: &[&str], input: Option>) -> (Server, SocketAddr) { - let td = TempDir::new("openssl").unwrap(); - let cert = td.path().join("cert.pem"); - let key = td.path().join("key.pem"); - File::create(&cert).unwrap().write_all(CERT).unwrap(); - File::create(&key).unwrap().write_all(KEY).unwrap(); - - let addr = next_addr(); - let mut child = Command::new("openssl") - .arg("s_server") - .arg("-accept") - .arg(addr.port().to_string()) - .args(args) - .arg("-cert") - .arg(&cert) - .arg("-key") - .arg(&key) - .arg("-no_dhe") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .stdin(Stdio::piped()) - .spawn() - .unwrap(); - let stdin = child.stdin.take().unwrap(); - if let Some(mut input) = input { - thread::spawn(move || input(stdin)); - } - ( - Server { - p: child, - _temp: td, - }, - addr, - ) - } - - fn new_tcp(args: &[&str]) -> (Server, TcpStream) { - let (mut server, addr) = Server::spawn(args, None); - for _ in 0..20 { - match TcpStream::connect(&addr) { - Ok(s) => return (server, s), - Err(ref e) if e.kind() == io::ErrorKind::ConnectionRefused => { - if let Some(exit_status) = server.p.try_wait().expect("try_wait") { - panic!("server exited: {}", exit_status); - } - thread::sleep(Duration::from_millis(100)); - } - Err(e) => panic!("wut: {}", e), - } - } - panic!("server never came online"); - } - - fn new() -> (Server, TcpStream) { - Server::new_tcp(&["-www"]) - } - - #[allow(dead_code)] - fn new_alpn() -> (Server, TcpStream) { - Server::new_tcp(&[ - "-www", - "-nextprotoneg", - "http/1.1,spdy/3.1", - "-alpn", - "http/1.1,spdy/3.1", - ]) - } -} - -impl Drop for Server { - fn drop(&mut self) { - let _ = self.p.kill(); - let _ = self.p.wait(); - } -} - -macro_rules! run_test( - ($module:ident, $blk:expr) => ( - #[cfg(test)] - mod $module { - use std::io; - use std::io::prelude::*; - use std::path::Path; - use std::net::UdpSocket; - use std::net::TcpStream; - use ssl; - use ssl::SslMethod; - use ssl::{SslContext, Ssl, SslStream, SslVerifyMode, SslOptions}; - use hash::MessageDigest; - use x509::{X509StoreContext, X509VerifyResult}; - #[cfg(any(ossl102, ossl110))] - use x509::X509; - #[cfg(any(ossl102, ossl110))] - use x509::store::X509StoreBuilder; - use hex::FromHex; - use foreign_types::ForeignTypeRef; - use super::Server; - #[cfg(any(ossl102, ossl110))] - use super::ROOT_CERT; - - #[test] - fn sslv23() { - let (_s, stream) = Server::new(); - $blk(SslMethod::tls(), stream); - } - } - ); -); - -run_test!(new_ctx, |method, _| { - SslContext::builder(method).unwrap(); -}); - -run_test!(verify_untrusted, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => panic!("expected failure"), - Err(err) => println!("error {:?}", err), - } -}); - -run_test!(verify_trusted, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -#[cfg(any(ossl102, ossl110))] -run_test!(verify_trusted_with_set_cert, |method, stream| { - let x509 = X509::from_pem(ROOT_CERT).unwrap(); - let mut store = X509StoreBuilder::new().unwrap(); - store.add_cert(x509).unwrap(); - - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - - match ctx.set_verify_cert_store(store.build()) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -run_test!(verify_untrusted_callback_override_ok, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SslVerifyMode::PEER, |_, _| true); - - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -run_test!(verify_untrusted_callback_override_bad, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SslVerifyMode::PEER, |_, _| false); - - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err()); -}); - -run_test!(verify_trusted_callback_override_ok, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SslVerifyMode::PEER, |_, _| true); - - match ctx.set_ca_file(&Path::new("test/cert.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -run_test!(verify_trusted_callback_override_bad, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SslVerifyMode::PEER, |_, _| false); - - match ctx.set_ca_file(&Path::new("test/cert.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err()); -}); - -run_test!(verify_callback_load_certs, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SslVerifyMode::PEER, |_, x509_ctx| { - assert!(x509_ctx.current_cert().is_some()); - true - }); - - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_ok()); -}); - -run_test!(verify_trusted_get_error_ok, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SslVerifyMode::PEER, |_, x509_ctx| { - assert!(x509_ctx.error() == X509VerifyResult::OK); - true - }); - - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_ok()); -}); - -run_test!(verify_trusted_get_error_err, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_verify_callback(SslVerifyMode::PEER, |_, x509_ctx| { - assert_ne!(x509_ctx.error(), X509VerifyResult::OK); - false - }); - - assert!(Ssl::new(&ctx.build()).unwrap().connect(stream).is_err()); -}); - -run_test!(verify_callback_data, |method, stream| { - let mut ctx = SslContext::builder(method).unwrap(); - - // Node id was generated as SHA256 hash of certificate "test/cert.pem" - // in DER format. - // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 - // Please update if "test/cert.pem" will ever change - let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = Vec::from_hex(node_hash_str).unwrap(); - ctx.set_verify_callback(SslVerifyMode::PEER, move |_preverify_ok, x509_ctx| { - let cert = x509_ctx.current_cert(); - match cert { - None => false, - Some(cert) => { - let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); - node_id == &*fingerprint - } - } - }); - ctx.set_verify_depth(1); - - match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } -}); - -run_test!(ssl_verify_callback, |method, stream| { - use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; - - static CHECKED: AtomicUsize = ATOMIC_USIZE_INIT; - - let ctx = SslContext::builder(method).unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - - let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = Vec::from_hex(node_hash_str).unwrap(); - ssl.set_verify_callback(SslVerifyMode::PEER, move |_, x509| { - CHECKED.store(1, Ordering::SeqCst); - match x509.current_cert() { - None => false, - Some(cert) => { - let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); - node_id == &*fingerprint - } - } - }); - - match ssl.connect(stream) { - Ok(_) => (), - Err(err) => panic!("Expected success, got {:?}", err), - } - - assert_eq!(CHECKED.load(Ordering::SeqCst), 1); -}); - -// Make sure every write call translates to a write call to the underlying socket. -#[test] -fn test_write_hits_stream() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - - let guard = thread::spawn(move || { - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let stream = TcpStream::connect(addr).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - - stream.write_all(b"hello").unwrap(); - stream - }); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - let stream = listener.accept().unwrap().0; - let mut stream = Ssl::new(&ctx.build()).unwrap().accept(stream).unwrap(); - - let mut buf = [0; 5]; - assert_eq!(5, stream.read(&mut buf).unwrap()); - assert_eq!(&b"hello"[..], &buf[..]); - guard.join().unwrap(); -} - -#[test] -fn test_set_certificate_and_private_key() { - let key = include_bytes!("../../test/key.pem"); - let key = PKey::private_key_from_pem(key).unwrap(); - let cert = include_bytes!("../../test/cert.pem"); - let cert = X509::from_pem(cert).unwrap(); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_private_key(&key).unwrap(); - ctx.set_certificate(&cert).unwrap(); - - assert!(ctx.check_private_key().is_ok()); -} - -run_test!(get_ctx_options, |method, _| { - let ctx = SslContext::builder(method).unwrap(); - ctx.options(); -}); - -run_test!(set_ctx_options, |method, _| { - let mut ctx = SslContext::builder(method).unwrap(); - let opts = ctx.set_options(SslOptions::NO_TICKET); - assert!(opts.contains(SslOptions::NO_TICKET)); -}); - -run_test!(clear_ctx_options, |method, _| { - let mut ctx = SslContext::builder(method).unwrap(); - ctx.set_options(SslOptions::ALL); - let opts = ctx.clear_options(SslOptions::ALL); - assert!(!opts.contains(SslOptions::ALL)); -}); - -#[test] -fn test_write() { - let (_s, stream) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - stream.write_all("hello".as_bytes()).unwrap(); - stream.flush().unwrap(); - stream.write_all(" there".as_bytes()).unwrap(); - stream.flush().unwrap(); -} - -#[test] -fn zero_length_buffers() { - let (_s, stream) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - - assert_eq!(stream.write(b"").unwrap(), 0); - assert_eq!(stream.read(&mut []).unwrap(), 0); -} - -run_test!(get_peer_certificate, |method, stream| { - let ctx = SslContext::builder(method).unwrap(); - let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - let cert = stream.ssl().peer_certificate().unwrap(); - let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); - let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = Vec::from_hex(node_hash_str).unwrap(); - assert_eq!(node_id, &*fingerprint) -}); - -#[test] -fn test_read() { - let (_s, tcp) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(tcp).unwrap(); - stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); - stream.flush().unwrap(); - io::copy(&mut stream, &mut io::sink()) - .ok() - .expect("read error"); -} - -#[test] -fn test_pending() { - let (_s, tcp) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(tcp).unwrap(); - stream.write_all("GET /\r\n\r\n".as_bytes()).unwrap(); - stream.flush().unwrap(); - - // wait for the response and read first byte... - let mut buf = [0u8; 16 * 1024]; - stream.read(&mut buf[..1]).unwrap(); - - let pending = stream.ssl().pending(); - let len = stream.read(&mut buf[1..]).unwrap(); - - assert_eq!(pending, len); - - stream.read(&mut buf[..1]).unwrap(); - - let pending = stream.ssl().pending(); - let len = stream.read(&mut buf[1..]).unwrap(); - assert_eq!(pending, len); -} - -#[test] -fn test_state() { - let (_s, tcp) = Server::new(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let stream = Ssl::new(&ctx.build()).unwrap().connect(tcp).unwrap(); - assert_eq!(stream.ssl().state_string(), "SSLOK "); - assert_eq!( - stream.ssl().state_string_long(), - "SSL negotiation finished successfully" - ); -} - -/// Tests that connecting with the client using ALPN, but the server not does not -/// break the existing connection behavior. -#[test] -#[cfg(any(ossl102, libressl261))] -fn test_connect_with_unilateral_alpn() { - let (_s, stream) = Server::new(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - ctx.set_alpn_protos(b"\x08http/1.1\x08spdy/3.1").unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // Since the socket to which we connected is not configured to use ALPN, - // there should be no selected protocol... - assert!(stream.ssl().selected_alpn_protocol().is_none()); -} - -/// Tests that when both the client as well as the server use ALPN and their -/// lists of supported protocols have an overlap, the correct protocol is chosen. -#[test] -#[cfg(any(ossl102, libressl261))] -fn test_connect_with_alpn_successful_multiple_matching() { - let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - ctx.set_alpn_protos(b"\x08http/1.1\x08spdy/3.1").unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // The server prefers "http/1.1", so that is chosen, even though the client - // would prefer "spdy/3.1" - assert_eq!(b"http/1.1", stream.ssl().selected_alpn_protocol().unwrap()); -} - -/// Tests that when both the client as well as the server use ALPN and their -/// lists of supported protocols have an overlap -- with only ONE protocol -/// being valid for both. -#[test] -#[cfg(any(ossl102, libressl261))] -fn test_connect_with_alpn_successful_single_match() { - let (_s, stream) = Server::new_alpn(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - ctx.set_alpn_protos(b"\x08spdy/3.1").unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - let stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // The client now only supports one of the server's protocols, so that one - // is used. - assert_eq!(b"spdy/3.1", stream.ssl().selected_alpn_protocol().unwrap()); -} - -/// Tests that when both the client as well as the server use SRTP and their -/// lists of supported protocols have an overlap -- with only ONE protocol -/// being valid for both. -#[test] -fn test_connect_with_srtp_ctx() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); - ctx.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") - .unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - - let mut buf = [0; 60]; - stream - .ssl() - .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) - .unwrap(); - - stream.write_all(&[0]).unwrap(); - - buf - }); - - let stream = TcpStream::connect(addr).unwrap(); - let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); - ctx.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") - .unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - - let mut buf = [1; 60]; - { - let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); - assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); - assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); - } - stream - .ssl() - .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) - .expect("extract"); - - stream.read_exact(&mut [0]).unwrap(); - - let buf2 = guard.join().unwrap(); - - assert_eq!(buf[..], buf2[..]); -} - -/// Tests that when both the client as well as the server use SRTP and their -/// lists of supported protocols have an overlap -- with only ONE protocol -/// being valid for both. -#[test] -fn test_connect_with_srtp_ssl() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") - .unwrap(); - let mut profilenames = String::new(); - for profile in ssl.srtp_profiles().unwrap() { - if profilenames.len() > 0 { - profilenames.push(':'); - } - profilenames += profile.name(); - } - assert_eq!( - "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", - profilenames - ); - let mut stream = ssl.accept(stream).unwrap(); - - let mut buf = [0; 60]; - stream - .ssl() - .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) - .unwrap(); - - stream.write_all(&[0]).unwrap(); - - buf - }); - - let stream = TcpStream::connect(addr).unwrap(); - let ctx = SslContext::builder(SslMethod::dtls()).unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") - .unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - - let mut buf = [1; 60]; - { - let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); - assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); - assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); - } - stream - .ssl() - .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) - .expect("extract"); - - stream.read_exact(&mut [0]).unwrap(); - - let buf2 = guard.join().unwrap(); - - assert_eq!(buf[..], buf2[..]); -} - -/// Tests that when the `SslStream` is created as a server stream, the protocols -/// are correctly advertised to the client. -#[test] -#[cfg(any(ossl102, libressl261))] -fn test_alpn_server_advertise_multiple() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let localhost = listener.local_addr().unwrap(); - // We create a different context instance for the server... - let listener_ctx = { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_alpn_select_callback(|_, client| { - ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) - }); - assert!( - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .is_ok() - ); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.build() - }; - // Have the listener wait on the connection in a different thread. - let guard = thread::spawn(move || { - let (stream, _) = listener.accept().unwrap(); - let mut stream = Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - ctx.set_alpn_protos(b"\x08spdy/3.1").unwrap(); - match ctx.set_ca_file(&Path::new("test/root-ca.pem")) { - Ok(_) => {} - Err(err) => panic!("Unexpected error {:?}", err), - } - // Now connect to the socket and make sure the protocol negotiation works... - let stream = TcpStream::connect(localhost).unwrap(); - let mut stream = match Ssl::new(&ctx.build()).unwrap().connect(stream) { - Ok(stream) => stream, - Err(err) => panic!("Expected success, got {:?}", err), - }; - // SPDY is selected since that's the only thing the client supports. - assert_eq!(b"spdy/3.1", stream.ssl().selected_alpn_protocol().unwrap()); - let mut buf = [0]; - stream.read_exact(&mut buf).unwrap(); - - guard.join().unwrap(); -} - -#[test] -#[cfg(any(ossl110))] -fn test_alpn_server_select_none_fatal() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let localhost = listener.local_addr().unwrap(); - // We create a different context instance for the server... - let listener_ctx = { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_alpn_select_callback(|_, client| { - ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client) - .ok_or(ssl::AlpnError::ALERT_FATAL) - }); - assert!( - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .is_ok() - ); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.build() - }; - // Have the listener wait on the connection in a different thread. - thread::spawn(move || { - let (stream, _) = listener.accept().unwrap(); - Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap_err(); - }); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - ctx.set_alpn_protos(b"\x06http/2").unwrap(); - ctx.set_ca_file(&Path::new("test/root-ca.pem")).unwrap(); - let stream = TcpStream::connect(localhost).unwrap(); - Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap_err(); -} - -#[test] -#[cfg(any(ossl102, libressl261))] -fn test_alpn_server_select_none() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let localhost = listener.local_addr().unwrap(); - // We create a different context instance for the server... - let listener_ctx = { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_alpn_select_callback(|_, client| { - ssl::select_next_proto(b"\x08http/1.1\x08spdy/3.1", client).ok_or(ssl::AlpnError::NOACK) - }); - assert!( - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .is_ok() - ); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.build() - }; - // Have the listener wait on the connection in a different thread. - let guard = thread::spawn(move || { - let (stream, _) = listener.accept().unwrap(); - let mut stream = Ssl::new(&listener_ctx).unwrap().accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - ctx.set_alpn_protos(b"\x06http/2").unwrap(); - ctx.set_ca_file(&Path::new("test/root-ca.pem")).unwrap(); - // Now connect to the socket and make sure the protocol negotiation works... - let stream = TcpStream::connect(localhost).unwrap(); - let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); - - // Since the protocols from the server and client don't overlap at all, no protocol is selected - assert_eq!(None, stream.ssl().selected_alpn_protocol()); - - let mut buf = [0]; - stream.read_exact(&mut buf).unwrap(); - - guard.join().unwrap(); -} - -#[test] -#[should_panic(expected = "blammo")] -fn write_panic() { - struct ExplodingStream(TcpStream); - - impl Read for ExplodingStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - } - - impl Write for ExplodingStream { - fn write(&mut self, _: &[u8]) -> io::Result { - panic!("blammo"); - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } - } - - let (_s, stream) = Server::new(); - let stream = ExplodingStream(stream); - - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); -} - -#[test] -#[should_panic(expected = "blammo")] -fn read_panic() { - struct ExplodingStream(TcpStream); - - impl Read for ExplodingStream { - fn read(&mut self, _: &mut [u8]) -> io::Result { - panic!("blammo"); - } - } - - impl Write for ExplodingStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() - } - } - - let (_s, stream) = Server::new(); - let stream = ExplodingStream(stream); - - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let _ = Ssl::new(&ctx.build()).unwrap().connect(stream); -} - -#[test] -#[should_panic(expected = "blammo")] -fn flush_panic() { - struct ExplodingStream(TcpStream); - - impl Read for ExplodingStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) - } - } - - impl Write for ExplodingStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - panic!("blammo"); - } - } - - let (_s, stream) = Server::new(); - let stream = ExplodingStream(stream); - - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let mut stream = Ssl::new(&ctx.build()) - .unwrap() - .connect(stream) - .ok() - .unwrap(); - let _ = stream.flush(); -} - -#[test] -fn refcount_ssl_context() { - let mut ssl = { - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ssl::Ssl::new(&ctx.build()).unwrap() - }; - - { - let new_ctx_a = SslContext::builder(SslMethod::tls()).unwrap().build(); - let _new_ctx_b = ssl.set_ssl_context(&new_ctx_a); - } -} - -#[test] -#[cfg_attr(libressl250, ignore)] -#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] -fn default_verify_paths() { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_default_verify_paths().unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - let ctx = ctx.build(); - let s = TcpStream::connect("google.com:443").unwrap(); - let mut ssl = Ssl::new(&ctx).unwrap(); - ssl.set_hostname("google.com").unwrap(); - let mut socket = ssl.connect(s).unwrap(); - - socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); - let mut result = vec![]; - socket.read_to_end(&mut result).unwrap(); - - println!("{}", String::from_utf8_lossy(&result)); - assert!(result.starts_with(b"HTTP/1.0")); - assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); -} - -#[test] -fn add_extra_chain_cert() { - let cert = include_bytes!("../../test/cert.pem"); - let cert = X509::from_pem(cert).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.add_extra_chain_cert(cert).unwrap(); -} - -#[test] -#[cfg(any(ossl102, ossl110))] -#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] -fn verify_valid_hostname() { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_default_verify_paths().unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.param_mut() - .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); - ssl.param_mut().set_host("google.com").unwrap(); - ssl.set_hostname("google.com").unwrap(); - - let s = TcpStream::connect("google.com:443").unwrap(); - let mut socket = ssl.connect(s).unwrap(); - - socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); - let mut result = vec![]; - socket.read_to_end(&mut result).unwrap(); - - println!("{}", String::from_utf8_lossy(&result)); - assert!(result.starts_with(b"HTTP/1.0")); - assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); -} - -#[test] -#[cfg(any(ossl102, ossl110))] -fn verify_invalid_hostname() { - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_default_verify_paths().unwrap(); - ctx.set_verify(SslVerifyMode::PEER); - - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.param_mut() - .set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); - ssl.param_mut().set_host("foobar.com").unwrap(); - - let s = TcpStream::connect("google.com:443").unwrap(); - assert!(ssl.connect(s).is_err()); -} - -#[test] -#[cfg_attr(libressl250, ignore)] -#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] -fn connector_valid_hostname() { - let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); - - let s = TcpStream::connect("google.com:443").unwrap(); - let mut socket = connector.connect("google.com", s).unwrap(); - - socket.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); - let mut result = vec![]; - socket.read_to_end(&mut result).unwrap(); - - println!("{}", String::from_utf8_lossy(&result)); - assert!(result.starts_with(b"HTTP/1.0")); - assert!(result.ends_with(b"\r\n") || result.ends_with(b"")); -} - -#[test] -#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] -fn connector_invalid_hostname() { - let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); - - let s = TcpStream::connect("google.com:443").unwrap(); - assert!(connector.connect("foobar.com", s).is_err()); -} - -#[test] -#[cfg_attr(libressl250, ignore)] -#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] -fn connector_invalid_no_hostname_verification() { - let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); - - let s = TcpStream::connect("google.com:443").unwrap(); - connector - .configure() - .unwrap() - .verify_hostname(false) - .connect("foobar.com", s) - .unwrap(); -} - -#[test] -fn connector_no_hostname_still_verifies() { - let (_s, tcp) = Server::new(); - - let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); - - assert!( - connector - .configure() - .unwrap() - .verify_hostname(false) - .connect("fizzbuzz.com", tcp) - .is_err() - ); -} - -#[test] -fn connector_no_hostname_can_disable_verify() { - let (_s, tcp) = Server::new(); - - let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); - connector.set_verify(SslVerifyMode::NONE); - let connector = connector.build(); - - connector - .configure() - .unwrap() - .verify_hostname(false) - .connect("foobar.com", tcp) - .unwrap(); -} - -#[test] -fn connector_client_server_mozilla_intermediate() { - let listener = TcpListener::bind("127.0.0.1:1234").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let t = thread::spawn(move || { - let key = PKey::private_key_from_pem(KEY).unwrap(); - let cert = X509::from_pem(CERT).unwrap(); - let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - acceptor.set_private_key(&key).unwrap(); - acceptor.set_certificate(&cert).unwrap(); - let acceptor = acceptor.build(); - let stream = listener.accept().unwrap().0; - let mut stream = acceptor.accept(stream).unwrap(); - - stream.write_all(b"hello").unwrap(); - }); - - let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); - connector.set_ca_file("test/root-ca.pem").unwrap(); - let connector = connector.build(); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut stream = connector.connect("foobar.com", stream).unwrap(); - - let mut buf = [0; 5]; - stream.read_exact(&mut buf).unwrap(); - assert_eq!(b"hello", &buf); - - t.join().unwrap(); -} - -#[test] -fn connector_client_server_mozilla_modern() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let t = thread::spawn(move || { - let key = PKey::private_key_from_pem(KEY).unwrap(); - let cert = X509::from_pem(CERT).unwrap(); - let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - acceptor.set_private_key(&key).unwrap(); - acceptor.set_certificate(&cert).unwrap(); - let acceptor = acceptor.build(); - let stream = listener.accept().unwrap().0; - let mut stream = acceptor.accept(stream).unwrap(); - - stream.write_all(b"hello").unwrap(); - }); - - let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); - connector.set_ca_file("test/root-ca.pem").unwrap(); - let connector = connector.build(); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut stream = connector.connect("foobar.com", stream).unwrap(); - - let mut buf = [0; 5]; - stream.read_exact(&mut buf).unwrap(); - assert_eq!(b"hello", &buf); - - t.join().unwrap(); -} - -#[test] -fn shutdown() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - - stream.write_all(b"hello").unwrap(); - let mut buf = [0; 1]; - assert_eq!(stream.read(&mut buf).unwrap(), 0); - assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - - let mut buf = [0; 5]; - stream.read_exact(&mut buf).unwrap(); - assert_eq!(b"hello", &buf); - - assert_eq!(stream.get_shutdown(), ShutdownState::empty()); - assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Sent); - assert_eq!(stream.get_shutdown(), ShutdownState::SENT); - assert_eq!(stream.shutdown().unwrap(), ShutdownResult::Received); - assert_eq!( - stream.get_shutdown(), - ShutdownState::SENT | ShutdownState::RECEIVED - ); - - guard.join().unwrap(); -} - -#[test] -fn client_ca_list() { - let names = X509Name::load_client_ca_file("test/root-ca.pem").unwrap(); - assert_eq!(names.len(), 1); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_client_ca_list(names); -} - -#[test] -fn cert_store() { - let (_s, tcp) = Server::new(); - - let cert = X509::from_pem(ROOT_CERT).unwrap(); - - let mut ctx = SslConnector::builder(SslMethod::tls()).unwrap(); - ctx.cert_store_mut().add_cert(cert).unwrap(); - let ctx = ctx.build(); - - ctx.connect("foobar.com", tcp).unwrap(); -} - -#[test] -fn tmp_dh_callback() { - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_tmp_dh_callback(|_, _, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - let dh = include_bytes!("../../test/dhparams.pem"); - Dh::params_from_pem(dh) - }); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - // TLS 1.3 has no DH suites, so make sure we don't pick that version - #[cfg(ossl111)] - ctx.set_options(super::SslOptions::NO_TLSV1_3); - ctx.set_cipher_list("EDH").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - - stream.read_exact(&mut [0]).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} - -#[test] -#[cfg(all(ossl101, not(ossl110)))] -fn tmp_ecdh_callback() { - use ec::EcKey; - use nid::Nid; - - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_tmp_ecdh_callback(|_, _, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - EcKey::from_curve_name(Nid::X9_62_PRIME256V1) - }); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("ECDH").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - stream.read_exact(&mut [0]).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} - -#[test] -fn tmp_dh_callback_ssl() { - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.set_tmp_dh_callback(|_, _, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - let dh = include_bytes!("../../test/dhparams.pem"); - Dh::params_from_pem(dh) - }); - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - // TLS 1.3 has no DH suites, so make sure we don't pick that version - #[cfg(ossl111)] - ctx.set_options(super::SslOptions::NO_TLSV1_3); - ctx.set_cipher_list("EDH").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - stream.read_exact(&mut [0]).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} - -#[test] -#[cfg(all(ossl101, not(ossl110)))] -fn tmp_ecdh_callback_ssl() { - use ec::EcKey; - use nid::Nid; - - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.set_tmp_ecdh_callback(|_, _, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - EcKey::from_curve_name(Nid::X9_62_PRIME256V1) - }); - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("ECDH").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - stream.read_exact(&mut [0]).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} - -#[test] -fn idle_session() { - let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); - let ssl = Ssl::new(&ctx).unwrap(); - assert!(ssl.session().is_none()); -} - -#[test] -#[cfg_attr(libressl250, ignore)] -#[cfg_attr(all(target_os = "macos", feature = "vendored"), ignore)] -fn active_session() { - let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); - - let s = TcpStream::connect("google.com:443").unwrap(); - let socket = connector.connect("google.com", s).unwrap(); - let session = socket.ssl().session().unwrap(); - let len = session.master_key_len(); - let mut buf = vec![0; len - 1]; - let copied = session.master_key(&mut buf); - assert_eq!(copied, buf.len()); - let mut buf = vec![0; len + 1]; - let copied = session.master_key(&mut buf); - assert_eq!(copied, len); -} - -#[test] -fn status_callbacks() { - static CALLED_BACK_SERVER: AtomicBool = ATOMIC_BOOL_INIT; - static CALLED_BACK_CLIENT: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:12345").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_status_callback(|ssl| { - CALLED_BACK_SERVER.store(true, Ordering::SeqCst); - let response = OcspResponse::create(OcspResponseStatus::UNAUTHORIZED, None).unwrap(); - let response = response.to_der().unwrap(); - ssl.set_ocsp_status(&response).unwrap(); - Ok(true) - }).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_status_callback(|ssl| { - CALLED_BACK_CLIENT.store(true, Ordering::SeqCst); - let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); - assert_eq!(response.status(), OcspResponseStatus::UNAUTHORIZED); - Ok(true) - }).unwrap(); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.set_status_type(StatusType::OCSP).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - let mut buf = [0]; - stream.read_exact(&mut buf).unwrap(); - - assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst)); - assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} - -#[test] -fn new_session_callback() { - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_session_id_context(b"foo").unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_session_cache_mode(SslSessionCacheMode::CLIENT | SslSessionCacheMode::NO_INTERNAL); - ctx.set_new_session_callback(|_, _| CALLED_BACK.store(true, Ordering::SeqCst)); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - stream.read_exact(&mut [0]).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} - -#[test] -fn keying_export() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - - let label = "EXPERIMENTAL test"; - let context = b"my context"; - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - - let mut buf = [0; 32]; - stream - .ssl() - .export_keying_material(&mut buf, label, Some(context)) - .unwrap(); - - stream.write_all(&[0]).unwrap(); - - buf - }); - - let stream = TcpStream::connect(addr).unwrap(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - - let mut buf = [1; 32]; - stream - .ssl() - .export_keying_material(&mut buf, label, Some(context)) - .unwrap(); - - stream.read_exact(&mut [0]).unwrap(); - - let buf2 = guard.join().unwrap(); - - assert_eq!(buf, buf2); -} - -#[test] -#[cfg(any(ossl110, libressl261))] -fn no_version_overlap() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_max_proto_version(Some(SslVersion::TLS1_1)).unwrap(); - #[cfg(ossl110g)] - assert_eq!(ctx.min_proto_version(), None); - #[cfg(any(ossl110g, libressl270))] - assert_eq!(ctx.max_proto_version(), Some(SslVersion::TLS1_1)); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap_err(); - }); - - let stream = TcpStream::connect(addr).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_min_proto_version(Some(SslVersion::TLS1_2)).unwrap(); - #[cfg(any(ossl110g, libressl270))] - assert_eq!(ctx.min_proto_version(), Some(SslVersion::TLS1_2)); - #[cfg(ossl110g)] - assert_eq!(ctx.max_proto_version(), None); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap_err(); - - guard.join().unwrap(); -} - -#[test] -#[cfg(ossl111)] -fn custom_extensions() { - static FOUND_EXTENSION: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.add_custom_ext( - 12345, - ssl::ExtensionContext::CLIENT_HELLO, - |_, _, _| -> Result, _> { unreachable!() }, - |_, _, data, _| { - FOUND_EXTENSION.store(data == b"hello", Ordering::SeqCst); - Ok(()) - }, - ).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let stream = TcpStream::connect(addr).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.add_custom_ext( - 12345, - ssl::ExtensionContext::CLIENT_HELLO, - |_, _, _| Ok(Some(b"hello")), - |_, _, _, _| unreachable!(), - ).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.connect(stream).unwrap(); - stream.read_exact(&mut [0]).unwrap(); - - guard.join().unwrap(); - assert!(FOUND_EXTENSION.load(Ordering::SeqCst)); -} - -fn _check_kinds() { - fn is_send() {} - fn is_sync() {} - - is_send::>(); - is_sync::>(); -} - -#[test] -#[cfg(ossl111)] -fn stateless() { - use super::SslOptions; - - #[derive(Debug)] - struct MemoryStream { - incoming: io::Cursor>, - outgoing: Vec, - } - - impl MemoryStream { - pub fn new() -> Self { - Self { - incoming: io::Cursor::new(Vec::new()), - outgoing: Vec::new(), - } - } - - pub fn extend_incoming(&mut self, data: &[u8]) { - self.incoming.get_mut().extend_from_slice(data); - } - - pub fn take_outgoing(&mut self) -> Outgoing { - Outgoing(&mut self.outgoing) - } - } - - impl Read for MemoryStream { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let n = self.incoming.read(buf)?; - if self.incoming.position() == self.incoming.get_ref().len() as u64 { - self.incoming.set_position(0); - self.incoming.get_mut().clear(); - } - if n == 0 { - return Err(io::Error::new( - io::ErrorKind::WouldBlock, - "no data available", - )); - } - Ok(n) - } - } - - impl Write for MemoryStream { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.outgoing.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - } - - pub struct Outgoing<'a>(&'a mut Vec); - - impl<'a> Drop for Outgoing<'a> { - fn drop(&mut self) { - self.0.clear(); - } - } - - impl<'a> ::std::ops::Deref for Outgoing<'a> { - type Target = [u8]; - fn deref(&self) -> &[u8] { - &self.0 - } - } - - impl<'a> AsRef<[u8]> for Outgoing<'a> { - fn as_ref(&self) -> &[u8] { - &self.0 - } - } - - fn send(from: &mut MemoryStream, to: &mut MemoryStream) { - to.extend_incoming(&from.take_outgoing()); - } - - fn hs( - stream: Result, HandshakeError>, - ) -> Result, MidHandshakeSslStream> { - match stream { - Ok(stream) => Ok(stream), - Err(HandshakeError::WouldBlock(stream)) => Err(stream), - Err(e) => panic!("unexpected error: {:?}", e), - } - } - - // - // Setup - // - - let mut client_ctx = SslContext::builder(SslMethod::tls()).unwrap(); - client_ctx.clear_options(SslOptions::ENABLE_MIDDLEBOX_COMPAT); - let client_stream = Ssl::new(&client_ctx.build()).unwrap(); - - let mut server_ctx = SslContext::builder(SslMethod::tls()).unwrap(); - server_ctx - .set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - server_ctx - .set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - const COOKIE: &[u8] = b"chocolate chip"; - server_ctx.set_stateless_cookie_generate_cb(|_tls, buf| { - buf[0..COOKIE.len()].copy_from_slice(COOKIE); - Ok(COOKIE.len()) - }); - server_ctx.set_stateless_cookie_verify_cb(|_tls, buf| buf == COOKIE); - let mut server_stream = - ssl::SslStreamBuilder::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new()); - - // - // Handshake - // - - // Initial ClientHello - let mut client_stream = hs(client_stream.connect(MemoryStream::new())).unwrap_err(); - send(client_stream.get_mut(), server_stream.get_mut()); - // HelloRetryRequest - assert!(!server_stream.stateless().unwrap()); - send(server_stream.get_mut(), client_stream.get_mut()); - // Second ClientHello - let mut client_stream = hs(client_stream.handshake()).unwrap_err(); - send(client_stream.get_mut(), server_stream.get_mut()); - // ServerHello - assert!(server_stream.stateless().unwrap()); - let mut server_stream = hs(server_stream.accept()).unwrap_err(); - send(server_stream.get_mut(), client_stream.get_mut()); - // Finished - let mut client_stream = hs(client_stream.handshake()).unwrap(); - send(client_stream.get_mut(), server_stream.get_mut()); - hs(server_stream.handshake()).unwrap(); -} - -#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] -#[test] -fn psk_ciphers() { - const CIPHER: &'static str = "PSK-AES128-CBC-SHA"; - const PSK: &[u8] = b"thisisaverysecurekey"; - const CLIENT_IDENT: &[u8] = b"thisisaclient"; - static CLIENT_CALLED: AtomicBool = ATOMIC_BOOL_INIT; - static SERVER_CALLED: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list(CIPHER).unwrap(); - ctx.set_psk_server_callback(move |_, identity, psk| { - assert!(identity.unwrap_or(&[]) == CLIENT_IDENT); - psk[..PSK.len()].copy_from_slice(&PSK); - SERVER_CALLED.store(true, Ordering::SeqCst); - Ok(PSK.len()) - }); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.accept(stream).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - // TLS 1.3 has no DH suites, and openssl isn't happy if the max version has no suites :( - #[cfg(ossl111)] - { - ctx.set_options(super::SslOptions { - bits: ::ffi::SSL_OP_NO_TLSv1_3, - }); - } - ctx.set_cipher_list(CIPHER).unwrap(); - ctx.set_psk_client_callback(move |_, _, identity, psk| { - identity[..CLIENT_IDENT.len()].copy_from_slice(&CLIENT_IDENT); - identity[CLIENT_IDENT.len()] = 0; - psk[..PSK.len()].copy_from_slice(&PSK); - CLIENT_CALLED.store(true, Ordering::SeqCst); - Ok(PSK.len()) - }); - let ssl = Ssl::new(&ctx.build()).unwrap(); - ssl.connect(stream).unwrap(); - - assert!(CLIENT_CALLED.load(Ordering::SeqCst) && SERVER_CALLED.load(Ordering::SeqCst)); -} - -#[test] -fn sni_callback_swapped_ctx() { - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let port = listener.local_addr().unwrap().port(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_servername_callback(|_, _| { - CALLED_BACK.store(true, Ordering::SeqCst); - Ok(()) - }); - let mut ssl = Ssl::new(&ctx.build()).unwrap(); - - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ssl.set_ssl_context(&ctx.build()).unwrap(); - - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&[0]).unwrap(); - }); - - let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - - let mut stream = ssl.connect(stream).unwrap(); - stream.read_exact(&mut [0]).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} - -#[test] -#[cfg(ossl111)] -fn client_hello() { - use ssl::ClientHelloResponse; - - static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; - - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - - let guard = thread::spawn(move || { - let stream = listener.accept().unwrap().0; - let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) - .unwrap(); - ctx.set_client_hello_callback(|ssl, _| { - assert!(!ssl.client_hello_isv2()); - assert_eq!(ssl.client_hello_legacy_version(), Some(SslVersion::TLS1_2)); - assert!(ssl.client_hello_random().is_some()); - assert!(ssl.client_hello_session_id().is_some()); - assert!(ssl.client_hello_ciphers().is_some()); - assert!(ssl.client_hello_compression_methods().is_some()); - - CALLED_BACK.store(true, Ordering::SeqCst); - Ok(ClientHelloResponse::SUCCESS) - }); - - let ssl = Ssl::new(&ctx.build()).unwrap(); - let mut stream = ssl.accept(stream).unwrap(); - stream.write_all(&mut [0]).unwrap(); - }); - - let stream = TcpStream::connect(addr).unwrap(); - let ctx = SslContext::builder(SslMethod::tls()).unwrap(); - let ssl = Ssl::new(&ctx.build()).unwrap(); - - let mut stream = ssl.connect(stream).unwrap(); - stream.read_exact(&mut [0]).unwrap(); - - assert!(CALLED_BACK.load(Ordering::SeqCst)); - - guard.join().unwrap(); -} diff -Nru rust-openssl-0.10.16/src/string.rs rust-openssl-0.10.23/src/string.rs --- rust-openssl-0.10.16/src/string.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/string.rs 2019-05-01 04:45:44.000000000 +0000 @@ -1,8 +1,9 @@ use ffi; use foreign_types::ForeignTypeRef; use libc::{c_char, c_void}; -use std::fmt; +use std::convert::AsRef; use std::ffi::CStr; +use std::fmt; use std::ops::Deref; use std::str; @@ -32,6 +33,18 @@ type StackType = ffi::stack_st_OPENSSL_STRING; } +impl AsRef for OpensslString { + fn as_ref(&self) -> &str { + &**self + } +} + +impl AsRef<[u8]> for OpensslString { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + impl Deref for OpensslStringRef { type Target = str; @@ -43,6 +56,18 @@ } } +impl AsRef for OpensslStringRef { + fn as_ref(&self) -> &str { + &*self + } +} + +impl AsRef<[u8]> for OpensslStringRef { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + impl fmt::Display for OpensslStringRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) diff -Nru rust-openssl-0.10.16/src/symm.rs rust-openssl-0.10.23/src/symm.rs --- rust-openssl-0.10.16/src/symm.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/symm.rs 2019-05-09 01:40:48.000000000 +0000 @@ -194,6 +194,10 @@ unsafe { Cipher(ffi::EVP_des_ede3_cbc()) } } + pub fn des_ede3_cfb64() -> Cipher { + unsafe { Cipher(ffi::EVP_des_ede3_cfb64()) } + } + pub fn rc4() -> Cipher { unsafe { Cipher(ffi::EVP_rc4()) } } @@ -418,7 +422,8 @@ ffi::EVP_CTRL_GCM_SET_TAG, tag.len() as c_int, tag.as_ptr() as *mut _, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -435,7 +440,8 @@ ffi::EVP_CTRL_GCM_SET_TAG, tag_len as c_int, ptr::null_mut(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -453,7 +459,8 @@ &mut len, ptr::null_mut(), data_len as c_int, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -472,7 +479,8 @@ &mut len, input.as_ptr(), input.len() as c_int, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -484,12 +492,16 @@ /// /// # Panics /// - /// Panics if `output.len() < input.len() + block_size` where - /// `block_size` is the block size of the cipher (see `Cipher::block_size`), - /// or if `output.len() > c_int::max_value()`. + /// Panics for stream ciphers if `output.len() < input.len()`. + /// + /// Panics for block ciphers if `output.len() < input.len() + block_size`, + /// where `block_size` is the block size of the cipher (see `Cipher::block_size`). + /// + /// Panics if `output.len() > c_int::max_value()`. pub fn update(&mut self, input: &[u8], output: &mut [u8]) -> Result { unsafe { - assert!(output.len() >= input.len() + self.block_size); + let block_size = if self.block_size > 1 { self.block_size } else { 0 }; + assert!(output.len() >= input.len() + block_size); assert!(output.len() <= c_int::max_value() as usize); let mut outl = output.len() as c_int; let inl = input.len() as c_int; @@ -515,10 +527,11 @@ /// /// # Panics /// - /// Panics if `output` is less than the cipher's block size. + /// Panics for block ciphers if `output.len() < block_size`, + /// where `block_size` is the block size of the cipher (see `Cipher::block_size`). pub fn finalize(&mut self, output: &mut [u8]) -> Result { unsafe { - assert!(output.len() >= self.block_size); + if self.block_size > 1 { assert!(output.len() >= self.block_size); } let mut outl = cmp::min(output.len(), c_int::max_value() as usize) as c_int; cvt(ffi::EVP_CipherFinal( @@ -547,7 +560,8 @@ ffi::EVP_CTRL_GCM_GET_TAG, tag.len() as c_int, tag.as_mut_ptr() as *mut _, - )).map(|_| ()) + )) + .map(|_| ()) } } } @@ -744,6 +758,22 @@ use super::*; use hex::{self, FromHex}; + #[test] + fn test_stream_cipher_output() { + let key = [0u8; 16]; + let iv = [0u8; 16]; + let mut c = super::Crypter::new( + super::Cipher::aes_128_ctr(), + super::Mode::Encrypt, + &key, + Some(&iv), + ).unwrap(); + + assert_eq!(c.update(&[0u8; 15], &mut [0u8; 15]).unwrap(), 15); + assert_eq!(c.update(&[0u8; 1], &mut [0u8; 1]).unwrap(), 1); + assert_eq!(c.finalize(&mut [0u8; 0]).unwrap(), 0); + } + // Test vectors from FIPS-197: // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf #[test] @@ -766,7 +796,8 @@ super::Mode::Encrypt, &k0, None, - ).unwrap(); + ) + .unwrap(); c.pad(false); let mut r0 = vec![0; c0.len() + super::Cipher::aes_256_ecb().block_size()]; let count = c.update(&p0, &mut r0).unwrap(); @@ -779,7 +810,8 @@ super::Mode::Decrypt, &k0, None, - ).unwrap(); + ) + .unwrap(); c.pad(false); let mut p1 = vec![0; r0.len() + super::Cipher::aes_256_ecb().block_size()]; let count = c.update(&r0, &mut p1).unwrap(); @@ -808,7 +840,8 @@ super::Mode::Decrypt, &data, Some(&iv), - ).unwrap(); + ) + .unwrap(); cr.pad(false); let mut unciphered_data = vec![0; data.len() + super::Cipher::aes_256_cbc().block_size()]; let count = cr.update(&ciphered_data, &mut unciphered_data).unwrap(); @@ -1056,6 +1089,16 @@ } #[test] + fn test_des_ede3_cfb64() { + let pt = "2b1773784b5889dc788477367daa98ad"; + let ct = "6f2867cfefda048a4046ef7e556c7132"; + let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe"; + let iv = "0001020304050607"; + + cipher_test(super::Cipher::des_ede3_cfb64(), pt, ct, key, iv); + } + + #[test] fn test_aes128_gcm() { let key = "0e00c76561d2bd9b40c3c15427e2b08f"; let iv = "492cadaccd3ca3fbc9cf9f06eb3325c4e159850b0dbe98199b89b7af528806610b6f63998e1eae80c348e7\ @@ -1080,7 +1123,8 @@ &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, - ).unwrap(); + ) + .unwrap(); assert_eq!(ct, hex::encode(out)); assert_eq!(tag, hex::encode(actual_tag)); @@ -1091,7 +1135,8 @@ &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), - ).unwrap(); + ) + .unwrap(); assert_eq!(pt, hex::encode(out)); } @@ -1113,7 +1158,8 @@ &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, - ).unwrap(); + ) + .unwrap(); assert_eq!(ct, hex::encode(out)); assert_eq!(tag, hex::encode(actual_tag)); @@ -1125,7 +1171,8 @@ &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), - ).unwrap(); + ) + .unwrap(); assert_eq!(pt, hex::encode(out)); } @@ -1167,7 +1214,8 @@ &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, - ).unwrap(); + ) + .unwrap(); assert_eq!(ct, hex::encode(out)); assert_eq!(tag, hex::encode(actual_tag)); @@ -1179,7 +1227,8 @@ &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), - ).unwrap(); + ) + .unwrap(); assert_eq!(pt, hex::encode(out)); } @@ -1242,7 +1291,8 @@ &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, - ).unwrap(); + ) + .unwrap(); assert_eq!(ct, hex::encode(out)); assert_eq!(tag, hex::encode(actual_tag)); @@ -1253,7 +1303,8 @@ &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), - ).unwrap(); + ) + .unwrap(); assert_eq!(pt, hex::encode(out)); } } diff -Nru rust-openssl-0.10.16/src/version.rs rust-openssl-0.10.23/src/version.rs --- rust-openssl-0.10.16/src/version.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/version.rs 2019-05-09 01:41:17.000000000 +0000 @@ -14,7 +14,7 @@ use std::ffi::CStr; cfg_if! { - if #[cfg(ossl110)] { + if #[cfg(any(ossl110, libressl271))] { use ffi::{ OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, OpenSSL_version_num, OpenSSL_version, diff -Nru rust-openssl-0.10.16/src/x509/extension.rs rust-openssl-0.10.23/src/x509/extension.rs --- rust-openssl-0.10.16/src/x509/extension.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/x509/extension.rs 2019-05-01 04:45:44.000000000 +0000 @@ -1,4 +1,4 @@ -//! Add extensions to an `X509` certificate or certificate request. +//! Add extensions to an `X509` certificate or certificate request. //! //! The extensions defined for X.509 v3 certificates provide methods for //! associating additional attributes with users or public keys and for @@ -11,11 +11,11 @@ //! extern crate openssl; //! //! use openssl::x509::extension::BasicConstraints; -//! use openssl::x509::X509Extension; +//! use openssl::x509::X509Extension; //! //! fn main() { //! let mut bc = BasicConstraints::new(); -//! let bc = bc.critical().ca().pathlen(1); +//! let bc = bc.critical().ca().pathlen(1); //! //! let extension: X509Extension = bc.build().unwrap(); //! } diff -Nru rust-openssl-0.10.16/src/x509/mod.rs rust-openssl-0.10.23/src/x509/mod.rs --- rust-openssl-0.10.16/src/x509/mod.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/x509/mod.rs 2019-05-01 04:45:44.000000000 +0000 @@ -255,7 +255,8 @@ cvt(ffi::X509_set_serialNumber( self.0.as_ptr(), serial_number.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -265,7 +266,8 @@ cvt(ffi::X509_set_issuer_name( self.0.as_ptr(), issuer_name.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -292,7 +294,8 @@ cvt(ffi::X509_set_subject_name( self.0.as_ptr(), subject_name.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -528,6 +531,23 @@ } } + /// Check if the certificate is signed using the given public key. + /// + /// Only the signature is checked: no other checks (such as certificate chain validity) + /// are performed. + /// + /// Returns `true` if verification succeeds. + /// + /// This corresponds to [`X509_verify"]. + /// + /// [`X509_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify.html + pub fn verify(&self, key: &PKeyRef) -> Result + where + T: HasPublic, + { + unsafe { cvt_n(ffi::X509_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } + } + /// Returns this certificate's serial number. /// /// This corresponds to [`X509_get_serialNumber`]. @@ -756,7 +776,8 @@ value.len() as c_int, -1, 0, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -776,7 +797,8 @@ value.len() as c_int, -1, 0, - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -830,7 +852,7 @@ X509NameEntries { name: self, nid: None, - loc: -1 + loc: -1, } } } @@ -945,7 +967,8 @@ cvt(ffi::X509_REQ_set_subject_name( self.0.as_ptr(), subject_name.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -994,7 +1017,8 @@ cvt(ffi::X509_REQ_add_extensions( self.0.as_ptr(), extensions.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -1012,7 +1036,8 @@ self.0.as_ptr(), key.as_ptr(), hash.as_ptr(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -1120,6 +1145,20 @@ } } + /// Check if the certificate request is signed using the given public key. + /// + /// Returns `true` if verification succeeds. + /// + /// This corresponds to [`X509_REQ_verify"]. + /// + /// [`X509_REQ_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_verify.html + pub fn verify(&self, key: &PKeyRef) -> Result + where + T: HasPublic, + { + unsafe { cvt_n(ffi::X509_REQ_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } + } + /// Returns the extensions of the certificate request. /// /// This corresponds to [`X509_REQ_get_extensions"] diff -Nru rust-openssl-0.10.16/src/x509/tests.rs rust-openssl-0.10.23/src/x509/tests.rs --- rust-openssl-0.10.16/src/x509/tests.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/x509/tests.rs 2019-05-01 04:45:44.000000000 +0000 @@ -12,7 +12,7 @@ SubjectKeyIdentifier, }; use x509::store::X509StoreBuilder; -use x509::{X509, X509Name, X509Req, X509StoreContext, X509VerifyResult}; +use x509::{X509Name, X509Req, X509StoreContext, X509VerifyResult, X509}; fn pkey() -> PKey { let rsa = Rsa::generate(2048).unwrap(); @@ -87,7 +87,10 @@ let mut all_entries = subject.entries(); let email = all_entries.next().unwrap(); - assert_eq!(email.object().nid().as_raw(), Nid::PKCS9_EMAILADDRESS.as_raw()); + assert_eq!( + email.object().nid().as_raw(), + Nid::PKCS9_EMAILADDRESS.as_raw() + ); assert_eq!(email.data().as_slice(), b"test@example.com"); let cn = all_entries.next().unwrap(); @@ -222,6 +225,7 @@ let x509 = builder.build(); assert!(pkey.public_eq(&x509.public_key().unwrap())); + assert!(x509.verify(&pkey).unwrap()); let cn = x509 .subject_name() @@ -265,6 +269,7 @@ let req = builder.build(); assert!(req.public_key().unwrap().public_eq(&pkey)); assert_eq!(req.extensions().unwrap().len(), extensions.len()); + assert!(req.verify(&pkey).unwrap()); } #[test] @@ -334,16 +339,12 @@ let store = store_bldr.build(); let mut context = X509StoreContext::new().unwrap(); - assert!( - context - .init(&store, &cert, &chain, |c| c.verify_cert()) - .unwrap() - ); - assert!( - context - .init(&store, &cert, &chain, |c| c.verify_cert()) - .unwrap() - ); + assert!(context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); + assert!(context + .init(&store, &cert, &chain, |c| c.verify_cert()) + .unwrap()); } #[test] diff -Nru rust-openssl-0.10.16/src/x509/verify.rs rust-openssl-0.10.23/src/x509/verify.rs --- rust-openssl-0.10.16/src/x509/verify.rs 2018-09-17 01:48:46.000000000 +0000 +++ rust-openssl-0.10.23/src/x509/verify.rs 2019-05-01 04:45:44.000000000 +0000 @@ -56,7 +56,8 @@ self.as_ptr(), host.as_ptr() as *const _, host.len(), - )).map(|_| ()) + )) + .map(|_| ()) } } @@ -82,7 +83,8 @@ self.as_ptr(), buf.as_ptr() as *const _, len, - )).map(|_| ()) + )) + .map(|_| ()) } } } Binary files /tmp/tmpF5yT5X/ZaZRWUES3u/rust-openssl-0.10.16/test/cms.p12 and /tmp/tmpF5yT5X/8W6qHRBaB7/rust-openssl-0.10.23/test/cms.p12 differ Binary files /tmp/tmpF5yT5X/ZaZRWUES3u/rust-openssl-0.10.16/test/cms_pubkey.der and /tmp/tmpF5yT5X/8W6qHRBaB7/rust-openssl-0.10.23/test/cms_pubkey.der differ