openssl-0.10.23/CHANGELOG.md010064400017500001750000000357351347005452600134150ustar0000000000000000# 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 openssl-0.10.23/Cargo.toml.orig010064400017500001750000000012441347005441400144530ustar0000000000000000[package] name = "openssl" 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"] # 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.47", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" hex = "0.3" openssl-0.10.23/Cargo.toml0000644000000023640000000000000107240ustar00# 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.23" authors = ["Steven Fackler "] description = "OpenSSL bindings" 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" [features] v101 = [] v102 = [] v110 = [] v111 = [] vendored = ["openssl-sys/vendored"] openssl-0.10.23/Cargo.toml.orig0000644000000023650000000000000116640ustar00# 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.23" authors = ["Steven Fackler "] description = "OpenSSL bindings" 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" [features] v101 = [] v102 = [] v110 = [] v111 = [] vendored = ["openssl-sys/vendored"] openssl-0.10.23/LICENSE010064400017500001750000000011521346222217000125640ustar0000000000000000Copyright 2011-2017 Google Inc. 2013 Jack Lloyd 2013-2014 Steven Fackler Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. openssl-0.10.23/README.md010064400017500001750000000021011346222217000130310ustar0000000000000000# rust-openssl [![CircleCI](https://circleci.com/gh/sfackler/rust-openssl.svg?style=shield)](https://circleci.com/gh/sfackler/rust-openssl) [![Build status](https://ci.appveyor.com/api/projects/status/d1knobws948pyynk/branch/master?svg=true)](https://ci.appveyor.com/project/sfackler/rust-openssl/branch/master) [![crates.io](https://img.shields.io/crates/v/openssl.svg)](https://crates.io/crates/openssl) OpenSSL bindings for the Rust programming language. [Documentation](https://docs.rs/openssl). ## Release Support The current supported release is 0.10. New major versions will be published at most once per year. After a new release, the previous major version will be partially supported with bug fixes for 3 months, after which support will be dropped entirely. ### Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed under the terms of both the Apache License, Version 2.0 and the MIT license without any additional terms or conditions. openssl-0.10.23/build.rs010064400017500001750000000034351346470247500132470ustar0000000000000000use std::env; fn main() { if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { println!("cargo:rustc-cfg=libressl"); } if let Ok(v) = env::var("DEP_OPENSSL_LIBRESSL_VERSION") { println!("cargo:rustc-cfg=libressl{}", v); } if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { for var in vars.split(",") { println!("cargo:rustc-cfg=osslconf=\"{}\"", var); } } if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") { let version = u64::from_str_radix(&version, 16).unwrap(); if version >= 0x1_00_01_00_0 { println!("cargo:rustc-cfg=ossl101"); } if version >= 0x1_00_02_00_0 { println!("cargo:rustc-cfg=ossl102"); } if version >= 0x1_01_00_00_0 { println!("cargo:rustc-cfg=ossl110"); } if version >= 0x1_01_00_07_0 { println!("cargo:rustc-cfg=ossl110g"); } if version >= 0x1_01_01_00_0 { println!("cargo:rustc-cfg=ossl111"); } } if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { let version = u64::from_str_radix(&version, 16).unwrap(); if version >= 0x2_06_01_00_0 { println!("cargo:rustc-cfg=libressl261"); } if version >= 0x2_07_00_00_0 { 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"); } if version >= 0x2_08_00_00_0 { println!("cargo:rustc-cfg=libressl280"); } if version >= 0x2_09_01_00_0 { println!("cargo:rustc-cfg=libressl291"); } } } openssl-0.10.23/examples/mk_certs.rs010064400017500001750000000125611346222217000155600ustar0000000000000000//! A program that generates ca certs, certs verified by the ca, and public //! and private keys. extern crate openssl; use openssl::asn1::Asn1Time; use openssl::bn::{BigNum, MsbOption}; use openssl::error::ErrorStack; use openssl::hash::MessageDigest; use openssl::pkey::{PKey, PKeyRef, Private}; use openssl::rsa::Rsa; 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> { let rsa = Rsa::generate(2048)?; let privkey = PKey::from_rsa(rsa)?; let mut x509_name = X509NameBuilder::new()?; x509_name.append_entry_by_text("C", "US")?; x509_name.append_entry_by_text("ST", "TX")?; x509_name.append_entry_by_text("O", "Some CA organization")?; x509_name.append_entry_by_text("CN", "ca test")?; let x509_name = x509_name.build(); let mut cert_builder = X509::builder()?; cert_builder.set_version(2)?; let serial_number = { let mut serial = BigNum::new()?; serial.rand(159, MsbOption::MAYBE_ZERO, false)?; serial.to_asn1_integer()? }; cert_builder.set_serial_number(&serial_number)?; cert_builder.set_subject_name(&x509_name)?; cert_builder.set_issuer_name(&x509_name)?; cert_builder.set_pubkey(&privkey)?; let not_before = Asn1Time::days_from_now(0)?; cert_builder.set_not_before(¬_before)?; let not_after = Asn1Time::days_from_now(365)?; 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()?, )?; let subject_key_identifier = SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?; cert_builder.append_extension(subject_key_identifier)?; cert_builder.sign(&privkey, MessageDigest::sha256())?; let cert = cert_builder.build(); Ok((cert, privkey)) } /// Make a X509 request with the given private key fn mk_request(privkey: &PKey) -> Result { let mut req_builder = X509ReqBuilder::new()?; req_builder.set_pubkey(&privkey)?; let mut x509_name = X509NameBuilder::new()?; x509_name.append_entry_by_text("C", "US")?; x509_name.append_entry_by_text("ST", "TX")?; x509_name.append_entry_by_text("O", "Some organization")?; x509_name.append_entry_by_text("CN", "www.example.com")?; let x509_name = x509_name.build(); req_builder.set_subject_name(&x509_name)?; req_builder.sign(&privkey, MessageDigest::sha256())?; let req = req_builder.build(); Ok(req) } /// Make a certificate and private key signed by the given CA cert and private key fn mk_ca_signed_cert( ca_cert: &X509Ref, ca_privkey: &PKeyRef, ) -> Result<(X509, PKey), ErrorStack> { let rsa = Rsa::generate(2048)?; let privkey = PKey::from_rsa(rsa)?; let req = mk_request(&privkey)?; let mut cert_builder = X509::builder()?; cert_builder.set_version(2)?; let serial_number = { let mut serial = BigNum::new()?; serial.rand(159, MsbOption::MAYBE_ZERO, false)?; serial.to_asn1_integer()? }; cert_builder.set_serial_number(&serial_number)?; cert_builder.set_subject_name(req.subject_name())?; cert_builder.set_issuer_name(ca_cert.subject_name())?; cert_builder.set_pubkey(&privkey)?; let not_before = Asn1Time::days_from_now(0)?; cert_builder.set_not_before(¬_before)?; let not_after = Asn1Time::days_from_now(365)?; cert_builder.set_not_after(¬_after)?; cert_builder.append_extension(BasicConstraints::new().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))?; cert_builder.append_extension(subject_key_identifier)?; let auth_key_identifier = AuthorityKeyIdentifier::new() .keyid(false) .issuer(false) .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; cert_builder.append_extension(auth_key_identifier)?; let subject_alt_name = SubjectAlternativeName::new() .dns("*.example.com") .dns("hello.com") .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; cert_builder.append_extension(subject_alt_name)?; cert_builder.sign(&ca_privkey, MessageDigest::sha256())?; let cert = cert_builder.build(); Ok((cert, privkey)) } fn real_main() -> Result<(), ErrorStack> { let (ca_cert, ca_privkey) = mk_ca_cert()?; let (cert, _privkey) = mk_ca_signed_cert(&ca_cert, &ca_privkey)?; // Verify that this cert was issued by this ca match ca_cert.issued(&cert) { X509VerifyResult::OK => println!("Certificate verified!"), ver_err => println!("Failed to verify certificate: {}", ver_err), }; Ok(()) } fn main() { match real_main() { Ok(()) => println!("Finished."), Err(e) => println!("Error: {}", e), }; } openssl-0.10.23/src/aes.rs010064400017500001750000000136001346222217000134650ustar0000000000000000//! Low level AES IGE functionality //! //! AES ECB, CBC, XTS, CTR, CFB, GCM and other conventional symmetric encryption //! modes are found in [`symm`]. This is the implementation of AES IGE. //! //! Advanced Encryption Standard (AES) provides symmetric key cipher that //! the same key is used to encrypt and decrypt data. This implementation //! uses 128, 192, or 256 bit keys. This module provides functions to //! create a new key with [`new_encrypt`] and perform an encryption/decryption //! using that key with [`aes_ige`]. //! //! [`new_encrypt`]: struct.AesKey.html#method.new_encrypt //! [`aes_ige`]: fn.aes_ige.html //! //! The [`symm`] module should be used in preference to this module in most cases. //! The IGE block cypher is a non-traditional cipher mode. More traditional AES //! encryption methods are found in the [`Crypter`] and [`Cipher`] structs. //! //! [`symm`]: ../symm/index.html //! [`Crypter`]: ../symm/struct.Crypter.html //! [`Cipher`]: ../symm/struct.Cipher.html //! //! # Examples //! //! ```rust //! use openssl::aes::{AesKey, aes_ige}; //! use openssl::symm::Mode; //! //! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; //! let plaintext = b"\x12\x34\x56\x78\x90\x12\x34\x56\x12\x34\x56\x78\x90\x12\x34\x56"; //! let mut iv = *b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\ //! \x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F"; //! //! let key = AesKey::new_encrypt(key).unwrap(); //! let mut output = [0u8; 16]; //! aes_ige(plaintext, &mut output, &key, &mut iv, Mode::Encrypt); //! assert_eq!(output, *b"\xa6\xad\x97\x4d\x5c\xea\x1d\x36\xd2\xf3\x67\x98\x09\x07\xed\x32"); use ffi; use libc::c_int; use std::mem; use symm::Mode; /// Provides Error handling for parsing keys. #[derive(Debug)] pub struct KeyError(()); /// The key used to encrypt or decrypt cipher blocks. pub struct AesKey(ffi::AES_KEY); impl AesKey { /// Prepares a key for encryption. /// /// # Failure /// /// Returns an error if the key is not 128, 192, or 256 bits. pub fn new_encrypt(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize / 8); let mut aes_key = mem::uninitialized(); let r = ffi::AES_set_encrypt_key( key.as_ptr() as *const _, key.len() as c_int * 8, &mut aes_key, ); if r == 0 { Ok(AesKey(aes_key)) } else { Err(KeyError(())) } } } /// Prepares a key for decryption. /// /// # Failure /// /// Returns an error if the key is not 128, 192, or 256 bits. pub fn new_decrypt(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize / 8); let mut aes_key = mem::uninitialized(); let r = ffi::AES_set_decrypt_key( key.as_ptr() as *const _, key.len() as c_int * 8, &mut aes_key, ); if r == 0 { Ok(AesKey(aes_key)) } else { Err(KeyError(())) } } } } /// Performs AES IGE encryption or decryption /// /// AES IGE (Infinite Garble Extension) is a form of AES block cipher utilized in /// OpenSSL. Infinite Garble referes to propogating forward errors. IGE, like other /// block ciphers implemented for AES requires an initalization vector. The IGE mode /// allows a stream of blocks to be encrypted or decrypted without having the entire /// plaintext available. For more information, visit [AES IGE Encryption]. /// /// This block cipher uses 16 byte blocks. The rust implmentation will panic /// if the input or output does not meet this 16-byte boundry. Attention must /// be made in this low level implementation to pad the value to the 128-bit boundry. /// /// [AES IGE Encryption]: http://www.links.org/files/openssl-ige.pdf /// /// # Panics /// /// Panics if `in_` is not the same length as `out`, if that length is not a multiple of 16, or if /// `iv` is not at least 32 bytes. pub fn aes_ige(in_: &[u8], out: &mut [u8], key: &AesKey, iv: &mut [u8], mode: Mode) { unsafe { assert!(in_.len() == out.len()); assert!(in_.len() % ffi::AES_BLOCK_SIZE as usize == 0); assert!(iv.len() >= ffi::AES_BLOCK_SIZE as usize * 2); let mode = match mode { Mode::Encrypt => ffi::AES_ENCRYPT, Mode::Decrypt => ffi::AES_DECRYPT, }; ffi::AES_ige_encrypt( in_.as_ptr() as *const _, out.as_mut_ptr() as *mut _, in_.len(), &key.0, iv.as_mut_ptr() as *mut _, mode, ); } } #[cfg(test)] mod test { use hex::FromHex; use super::*; use symm::Mode; // From https://www.mgp25.com/AESIGE/ #[test] fn ige_vector_1() { let raw_key = "000102030405060708090A0B0C0D0E0F"; let raw_iv = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"; let raw_pt = "0000000000000000000000000000000000000000000000000000000000000000"; let raw_ct = "1A8519A6557BE652E9DA8E43DA4EF4453CF456B4CA488AA383C79C98B34797CB"; let key = AesKey::new_encrypt(&Vec::from_hex(raw_key).unwrap()).unwrap(); let mut iv = Vec::from_hex(raw_iv).unwrap(); let pt = Vec::from_hex(raw_pt).unwrap(); let ct = Vec::from_hex(raw_ct).unwrap(); let mut ct_actual = vec![0; ct.len()]; aes_ige(&pt, &mut ct_actual, &key, &mut iv, Mode::Encrypt); assert_eq!(ct_actual, ct); let key = AesKey::new_decrypt(&Vec::from_hex(raw_key).unwrap()).unwrap(); let mut iv = Vec::from_hex(raw_iv).unwrap(); let mut pt_actual = vec![0; pt.len()]; aes_ige(&ct, &mut pt_actual, &key, &mut iv, Mode::Decrypt); assert_eq!(pt_actual, pt); } } openssl-0.10.23/src/asn1.rs010064400017500001750000000313411346470244000135660ustar0000000000000000#![deny(missing_docs)] //! Defines the format of certificiates //! //! This module is used by [`x509`] and other certificate building functions //! to describe time, strings, and objects. //! //! Abstract Syntax Notation One is an interface description language. //! The specification comes from [X.208] by OSI, and rewritten in X.680. //! ASN.1 describes properties of an object with a type set. Those types //! can be atomic, structured, choice, and other (CHOICE and ANY). These //! types are expressed as a number and the assignment operator ::= gives //! the type a name. //! //! The implementation here provides a subset of the ASN.1 types that OpenSSL //! uses, especially in the properties of a certificate used in HTTPS. //! //! [X.208]: https://www.itu.int/rec/T-REC-X.208-198811-W/en //! [`x509`]: ../x509/struct.X509Builder.html //! //! ## Examples //! //! ``` //! use openssl::asn1::Asn1Time; //! let tomorrow = Asn1Time::days_from_now(1); //! ``` 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, BigNumRef}; use error::ErrorStack; use nid::Nid; use string::OpensslString; use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_GENERALIZEDTIME; fn drop = ffi::ASN1_GENERALIZEDTIME_free; /// Non-UTC representation of time /// /// If a time can be represented by UTCTime, UTCTime is used /// otherwise, ASN1_GENERALIZEDTIME is used. This would be, for /// example outside the year range of 1950-2049. /// /// [ASN1_GENERALIZEDTIME_set] documentation from OpenSSL provides /// further details of implmentation. Note: these docs are from the master /// branch as documentation on the 1.1.0 branch did not include this page. /// /// [ASN1_GENERALIZEDTIME_set]: https://www.openssl.org/docs/manmaster/man3/ASN1_GENERALIZEDTIME_set.html pub struct Asn1GeneralizedTime; /// Reference to a [`Asn1GeneralizedTime`] /// /// [`Asn1GeneralizedTime`]: struct.Asn1GeneralizedTime.html pub struct Asn1GeneralizedTimeRef; } impl fmt::Display for Asn1GeneralizedTimeRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { let mem_bio = MemBio::new()?; cvt(ffi::ASN1_GENERALIZEDTIME_print( mem_bio.as_ptr(), self.as_ptr(), ))?; write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) } } } foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_TIME; fn drop = ffi::ASN1_TIME_free; /// Time storage and comparison /// /// Asn1Time should be used to store and share time information /// using certificates. If Asn1Time is set using a string, it must /// be in either YYMMDDHHMMSSZ, YYYYMMDDHHMMSSZ, or another ASN.1 format. /// /// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementaiton /// used by OpenSSL. /// /// [ASN_TIME_set]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_set.html pub struct Asn1Time; /// Reference to an [`Asn1Time`] /// /// [`Asn1Time`]: struct.Asn1Time.html pub struct Asn1TimeRef; } impl fmt::Display for Asn1TimeRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { unsafe { let mem_bio = MemBio::new()?; cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr()))?; write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) } } } 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(); unsafe { let handle = cvt_p(ffi::X509_gmtime_adj(ptr::null_mut(), period))?; Ok(Asn1Time::from_ptr(handle)) } } /// Creates a new time on specified interval in days from now 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! { type CType = ffi::ASN1_STRING; fn drop = ffi::ASN1_STRING_free; /// Primary ASN.1 type used by OpenSSL /// /// Almost all ASN.1 types in OpenSSL are represented by ASN1_STRING /// structures. This implementation uses [ASN1_STRING-to_UTF8] to preserve /// compatibility with Rust's String. /// /// [ASN1_STRING-to_UTF8]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_STRING_to_UTF8.html pub struct Asn1String; /// Reference to [`Asn1String`] /// /// [`Asn1String`]: struct.Asn1String.html pub struct Asn1StringRef; } impl Asn1StringRef { /// Converts the ASN.1 underlying format to UTF8 /// /// ASN.1 strings may utilize UTF-16, ASCII, BMP, or UTF8. This is important to /// consume the string in a meaningful way without knowing the underlying /// format. pub fn as_utf8(&self) -> Result { unsafe { let mut ptr = ptr::null_mut(); let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr()); if len < 0 { return Err(ErrorStack::get()); } Ok(OpensslString::from_ptr(ptr as *mut c_char)) } } /// Return the string as an array of bytes /// /// The bytes do not directly corespond to UTF-8 encoding. To interact with /// strings in rust, it is preferable to use [`as_utf8`] /// /// [`as_utf8`]: struct.Asn1String.html#method.as_utf8 pub fn as_slice(&self) -> &[u8] { unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) } } /// Return the length of the Asn1String (number of bytes) pub fn len(&self) -> usize { unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize } } } foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_INTEGER; fn drop = ffi::ASN1_INTEGER_free; /// Numeric representation /// /// Integers in ASN.1 may include BigNum, int64 or uint64. BigNum implementation /// can be found within [`bn`] module. /// /// OpenSSL documentation includes [`ASN1_INTEGER_set`]. /// /// [`bn`]: ../bn/index.html /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html pub struct Asn1Integer; /// Reference to [`Asn1Integer`] /// /// [`Asn1Integer`]: struct.Asn1Integer.html 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")] pub fn get(&self) -> i64 { unsafe { ::ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 } } /// Converts the integer to a `BigNum`. /// /// This corresponds to [`ASN1_INTEGER_to_BN`]. /// /// [`ASN1_INTEGER_to_BN`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_get.html pub fn to_bn(&self) -> Result { unsafe { cvt_p(::ffi::ASN1_INTEGER_to_BN(self.as_ptr(), ptr::null_mut())) .map(|p| BigNum::from_ptr(p)) } } /// Sets the ASN.1 value to the value of a signed 32-bit integer, for larger numbers /// see [`bn`]. /// /// OpenSSL documentation at [`ASN1_INTEGER_set`] /// /// [`bn`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer /// [`ASN1_INTEGER_set`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_INTEGER_set.html pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> { unsafe { cvt(::ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } } } foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_BIT_STRING; fn drop = ffi::ASN1_BIT_STRING_free; /// Sequence of bytes /// /// Asn1BitString is used in [`x509`] certificates for the signature. /// The bit string acts as a collection of bytes. /// /// [`x509`]: ../x509/struct.X509.html#method.signature pub struct Asn1BitString; /// Reference to [`Asn1BitString`] /// /// [`Asn1BitString`]: struct.Asn1BitString.html pub struct Asn1BitStringRef; } impl Asn1BitStringRef { /// Returns the Asn1BitString as a slice pub fn as_slice(&self) -> &[u8] { unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } } /// Length of Asn1BitString in number of bytes. pub fn len(&self) -> usize { unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize } } } foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_OBJECT; fn drop = ffi::ASN1_OBJECT_free; /// Object Identifier /// /// Represents an ASN.1 Object. Typically, NIDs, or numeric identifiers /// are stored as a table within the [`Nid`] module. These constants are /// used to determine attributes of a certificate, such as mapping the /// attribute "CommonName" to "CN" which is represented as the OID of 13. /// This attribute is a constant in the [`nid::COMMONNAME`]. /// /// OpenSSL documentation at [`OBJ_nid2obj`] /// /// [`Nid`]: ../nid/index.html /// [`nid::COMMONNAME`]: ../nid/constant.COMMONNAME.html /// [`OBJ_nid2obj`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_obj2nid.html pub struct Asn1Object; /// Reference to [`Asn1Object`] /// /// [`Asn1Object`]: struct.Asn1Object.html pub struct Asn1ObjectRef; } impl Asn1ObjectRef { /// Returns the NID associated with this OID. pub fn nid(&self) -> Nid { unsafe { Nid::from_raw(ffi::OBJ_obj2nid(self.as_ptr())) } } } impl fmt::Display for Asn1ObjectRef { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { unsafe { let mut buf = [0; 80]; let len = ffi::OBJ_obj2txt( buf.as_mut_ptr() as *mut _, buf.len() as c_int, self.as_ptr(), 0, ); let s = str::from_utf8(&buf[..len as usize]).map_err(|_| fmt::Error)?; fmt.write_str(s) } } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::ASN1_STRING_get0_data; } else { #[allow(bad_style)] unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar { ffi::ASN1_STRING_data(s) } } } #[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(); } } openssl-0.10.23/src/bio.rs010064400017500001750000000034361346222217000134740ustar0000000000000000use ffi; use libc::c_int; use std::marker::PhantomData; use std::ptr; use std::slice; use cvt_p; use error::ErrorStack; pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>); impl<'a> Drop for MemBioSlice<'a> { fn drop(&mut self) { unsafe { ffi::BIO_free_all(self.0); } } } impl<'a> MemBioSlice<'a> { pub fn new(buf: &'a [u8]) -> Result, ErrorStack> { ffi::init(); assert!(buf.len() <= c_int::max_value() as usize); let bio = unsafe { cvt_p(BIO_new_mem_buf( buf.as_ptr() as *const _, buf.len() as c_int, ))? }; Ok(MemBioSlice(bio, PhantomData)) } pub fn as_ptr(&self) -> *mut ffi::BIO { self.0 } } pub struct MemBio(*mut ffi::BIO); impl Drop for MemBio { fn drop(&mut self) { unsafe { ffi::BIO_free_all(self.0); } } } impl MemBio { pub fn new() -> Result { ffi::init(); let bio = unsafe { cvt_p(ffi::BIO_new(ffi::BIO_s_mem()))? }; Ok(MemBio(bio)) } pub fn as_ptr(&self) -> *mut ffi::BIO { self.0 } pub fn get_buf(&self) -> &[u8] { unsafe { let mut ptr = ptr::null_mut(); let len = ffi::BIO_get_mem_data(self.0, &mut ptr); slice::from_raw_parts(ptr as *const _ as *const _, len as usize) } } pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBio { MemBio(bio) } } cfg_if! { if #[cfg(ossl102)] { use ffi::BIO_new_mem_buf; } else { #[allow(bad_style)] unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO { ffi::BIO_new_mem_buf(buf as *mut _, len) } } } openssl-0.10.23/src/bn.rs010064400017500001750000001300341346222217000133150ustar0000000000000000//! BigNum implementation //! //! Large numbers are important for a cryptographic library. OpenSSL implementation //! of BigNum uses dynamically assigned memory to store an array of bit chunks. This //! allows numbers of any size to be compared and mathematical functions performed. //! //! OpenSSL wiki describes the [`BIGNUM`] data structure. //! //! # Examples //! //! ``` //! use openssl::bn::BigNum; //! use openssl::error::ErrorStack; //! //! fn bignums() -> Result<(), ErrorStack> { //! let a = BigNum::new()?; // a = 0 //! let b = BigNum::from_dec_str("1234567890123456789012345")?; //! let c = &a * &b; //! assert_eq!(a, c); //! Ok(()) //! } //! # fn main() { //! # bignums(); //! # } //! ``` //! //! [`BIGNUM`]: https://wiki.openssl.org/index.php/Manual:Bn_internal(3) use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::cmp::Ordering; use std::ffi::CString; use std::ops::{Add, Deref, Div, Mul, Neg, Rem, Shl, Shr, Sub}; use std::{fmt, ptr}; use asn1::Asn1Integer; use error::ErrorStack; use string::OpensslString; use {cvt, cvt_n, cvt_p}; cfg_if! { if #[cfg(ossl110)] { use ffi::{ BN_get_rfc2409_prime_1024, BN_get_rfc2409_prime_768, BN_get_rfc3526_prime_1536, BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096, BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192, BN_is_negative, }; } else { use ffi::{ get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192, }; #[allow(bad_style)] unsafe fn BN_is_negative(bn: *const ffi::BIGNUM) -> c_int { (*bn).neg } } } /// Options for the most significant bits of a randomly generated `BigNum`. pub struct MsbOption(c_int); impl MsbOption { /// The most significant bit of the number may be 0. pub const MAYBE_ZERO: MsbOption = MsbOption(-1); /// The most significant bit of the number must be 1. pub const ONE: MsbOption = MsbOption(0); /// The most significant two bits of the number must be 1. /// /// The number of bits in the product of two such numbers will always be exactly twice the /// number of bits in the original numbers. pub const TWO_ONES: MsbOption = MsbOption(1); } foreign_type_and_impl_send_sync! { type CType = ffi::BN_CTX; fn drop = ffi::BN_CTX_free; /// Temporary storage for BigNums on the secure heap /// /// BigNum values are stored dynamically and therefore can be expensive /// to allocate. BigNumContext and the OpenSSL [`BN_CTX`] structure are used /// internally when passing BigNum values between subroutines. /// /// [`BN_CTX`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_CTX_new.html pub struct BigNumContext; /// Reference to [`BigNumContext`] /// /// [`BigNumContext`]: struct.BigNumContext.html pub struct BigNumContextRef; } impl BigNumContext { /// Returns a new `BigNumContext`. /// /// See OpenSSL documentation at [`BN_CTX_new`]. /// /// [`BN_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_CTX_new.html pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::BN_CTX_new()).map(BigNumContext) } } } foreign_type_and_impl_send_sync! { type CType = ffi::BIGNUM; fn drop = ffi::BN_free; /// Dynamically sized large number impelementation /// /// Perform large number mathematics. Create a new BigNum /// with [`new`]. Perform standard mathematics on large numbers using /// methods from [`Dref`] /// /// OpenSSL documenation at [`BN_new`]. /// /// [`new`]: struct.BigNum.html#method.new /// [`Dref`]: struct.BigNum.html#deref-methods /// [`BN_new`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_new.html /// /// # Examples /// ``` /// use openssl::bn::BigNum; /// # use openssl::error::ErrorStack; /// # fn bignums() -> Result< (), ErrorStack > { /// let little_big = BigNum::from_u32(std::u32::MAX)?; /// assert_eq!(*&little_big.num_bytes(), 4); /// # Ok(()) /// # } /// # fn main () { bignums(); } /// ``` pub struct BigNum; /// Reference to a [`BigNum`] /// /// [`BigNum`]: struct.BigNum.html pub struct BigNumRef; } impl BigNumRef { /// Erases the memory used by this `BigNum`, resetting its value to 0. /// /// This can be used to destroy sensitive data such as keys when they are no longer needed. /// /// OpenSSL documentation at [`BN_clear`] /// /// [`BN_clear`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_clear.html pub fn clear(&mut self) { unsafe { ffi::BN_clear(self.as_ptr()) } } /// Adds a `u32` to `self`. /// /// OpenSSL documentation at [`BN_add_word`] /// /// [`BN_add_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_add_word.html pub fn add_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_add_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } } /// Subtracts a `u32` from `self`. /// /// OpenSSL documentation at [`BN_sub_word`] /// /// [`BN_sub_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sub_word.html pub fn sub_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_sub_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } } /// Multiplies a `u32` by `self`. /// /// OpenSSL documentation at [`BN_mul_word`] /// /// [`BN_mul_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mul_word.html pub fn mul_word(&mut self, w: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mul_word(self.as_ptr(), w as ffi::BN_ULONG)).map(|_| ()) } } /// Divides `self` by a `u32`, returning the remainder. /// /// OpenSSL documentation at [`BN_div_word`] /// /// [`BN_div_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div_word.html pub fn div_word(&mut self, w: u32) -> Result { unsafe { let r = ffi::BN_div_word(self.as_ptr(), w.into()); if r == ffi::BN_ULONG::max_value() { Err(ErrorStack::get()) } else { Ok(r.into()) } } } /// Returns the result of `self` modulo `w`. /// /// OpenSSL documentation at [`BN_mod_word`] /// /// [`BN_mod_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_word.html pub fn mod_word(&self, w: u32) -> Result { unsafe { let r = ffi::BN_mod_word(self.as_ptr(), w.into()); if r == ffi::BN_ULONG::max_value() { Err(ErrorStack::get()) } else { Ok(r.into()) } } } /// Places a cryptographically-secure pseudo-random nonnegative /// number less than `self` in `rnd`. /// /// OpenSSL documentation at [`BN_rand_range`] /// /// [`BN_rand_range`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rand_range.html pub fn rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) } } /// The cryptographically weak counterpart to `rand_in_range`. /// /// OpenSSL documentation at [`BN_pseudo_rand_range`] /// /// [`BN_pseudo_rand_range`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_pseudo_rand_range.html pub fn pseudo_rand_range(&self, rnd: &mut BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_pseudo_rand_range(rnd.as_ptr(), self.as_ptr())).map(|_| ()) } } /// Sets bit `n`. Equivalent to `self |= (1 << n)`. /// /// When setting a bit outside of `self`, it is expanded. /// /// OpenSSL documentation at [`BN_set_bit`] /// /// [`BN_set_bit`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_set_bit.html pub fn set_bit(&mut self, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_set_bit(self.as_ptr(), n.into())).map(|_| ()) } } /// Clears bit `n`, setting it to 0. Equivalent to `self &= ~(1 << n)`. /// /// When clearing a bit outside of `self`, an error is returned. /// /// OpenSSL documentation at [`BN_clear_bit`] /// /// [`BN_clear_bit`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_clear_bit.html pub fn clear_bit(&mut self, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_clear_bit(self.as_ptr(), n.into())).map(|_| ()) } } /// Returns `true` if the `n`th bit of `self` is set to 1, `false` otherwise. /// /// OpenSSL documentation at [`BN_is_bit_set`] /// /// [`BN_is_bit_set`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_bit_set.html pub fn is_bit_set(&self, n: i32) -> bool { unsafe { ffi::BN_is_bit_set(self.as_ptr(), n.into()) == 1 } } /// Truncates `self` to the lowest `n` bits. /// /// An error occurs if `self` is already shorter than `n` bits. /// /// OpenSSL documentation at [`BN_mask_bits`] /// /// [`BN_mask_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mask_bits.html pub fn mask_bits(&mut self, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mask_bits(self.as_ptr(), n.into())).map(|_| ()) } } /// Places `a << 1` in `self`. Equivalent to `self * 2`. /// /// OpenSSL documentation at [`BN_lshift1`] /// /// [`BN_lshift1`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_lshift1.html pub fn lshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_lshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) } } /// Places `a >> 1` in `self`. Equivalent to `self / 2`. /// /// OpenSSL documentation at [`BN_rshift1`] /// /// [`BN_rshift1`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rshift1.html pub fn rshift1(&mut self, a: &BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_rshift1(self.as_ptr(), a.as_ptr())).map(|_| ()) } } /// Places `a + b` in `self`. [`core::ops::Add`] is also implemented for `BigNumRef`. /// /// OpenSSL documentation at [`BN_add`] /// /// [`core::ops::Add`]: struct.BigNumRef.html#method.add /// [`BN_add`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_add.html pub fn checked_add(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_add(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) } } /// Places `a - b` in `self`. [`core::ops::Sub`] is also implemented for `BigNumRef`. /// /// OpenSSL documentation at [`BN_sub`] /// /// [`core::ops::Sub`]: struct.BigNumRef.html#method.sub /// [`BN_sub`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sub.html pub fn checked_sub(&mut self, a: &BigNumRef, b: &BigNumRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_sub(self.as_ptr(), a.as_ptr(), b.as_ptr())).map(|_| ()) } } /// Places `a << n` in `self`. Equivalent to `a * 2 ^ n`. /// /// OpenSSL documentation at [`BN_lshift`] /// /// [`BN_lshift`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_lshift.html pub fn lshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_lshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) } } /// Places `a >> n` in `self`. Equivalent to `a / 2 ^ n`. /// /// OpenSSL documentation at [`BN_rshift`] /// /// [`BN_rshift`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rshift.html pub fn rshift(&mut self, a: &BigNumRef, n: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_rshift(self.as_ptr(), a.as_ptr(), n.into())).map(|_| ()) } } /// Creates a new BigNum with the same value. /// /// OpenSSL documentation at [`BN_dup`] /// /// [`BN_dup`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_dup.html pub fn to_owned(&self) -> Result { unsafe { cvt_p(ffi::BN_dup(self.as_ptr())).map(|b| BigNum::from_ptr(b)) } } /// Sets the sign of `self`. Pass true to set `self` to a negative. False sets /// `self` positive. pub fn set_negative(&mut self, negative: bool) { unsafe { ffi::BN_set_negative(self.as_ptr(), negative as c_int) } } /// Compare the absolute values of `self` and `oth`. /// /// OpenSSL documentation at [`BN_ucmp`] /// /// [`BN_ucmp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_ucmp.html /// /// # Examples /// /// ``` /// # use openssl::bn::BigNum; /// # use std::cmp::Ordering; /// let s = -BigNum::from_u32(8).unwrap(); /// let o = BigNum::from_u32(8).unwrap(); /// /// assert_eq!(s.ucmp(&o), Ordering::Equal); /// ``` pub fn ucmp(&self, oth: &BigNumRef) -> Ordering { unsafe { ffi::BN_ucmp(self.as_ptr(), oth.as_ptr()).cmp(&0) } } /// Returns `true` if `self` is negative. pub fn is_negative(&self) -> bool { unsafe { BN_is_negative(self.as_ptr()) == 1 } } /// Returns the number of significant bits in `self`. /// /// OpenSSL documentation at [`BN_num_bits`] /// /// [`BN_num_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_num_bits.html pub fn num_bits(&self) -> i32 { unsafe { ffi::BN_num_bits(self.as_ptr()) as i32 } } /// Returns the size of `self` in bytes. Implemented natively. pub fn num_bytes(&self) -> i32 { (self.num_bits() + 7) / 8 } /// Generates a cryptographically strong pseudo-random `BigNum`, placing it in `self`. /// /// # Parameters /// /// * `bits`: Length of the number in bits. /// * `msb`: The desired properties of the most significant bit. See [`constants`]. /// * `odd`: If `true`, the generated number will be odd. /// /// # Examples /// /// ``` /// use openssl::bn::{BigNum, MsbOption}; /// use openssl::error::ErrorStack; /// /// fn generate_random() -> Result< BigNum, ErrorStack > { /// let mut big = BigNum::new()?; /// /// // Generates a 128-bit odd random number /// big.rand(128, MsbOption::MAYBE_ZERO, true); /// Ok((big)) /// } /// ``` /// /// OpenSSL documentation at [`BN_rand`] /// /// [`constants`]: index.html#constants /// [`BN_rand`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_rand.html pub fn rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_rand( self.as_ptr(), bits.into(), msb.0, odd as c_int, )) .map(|_| ()) } } /// The cryptographically weak counterpart to `rand`. Not suitable for key generation. /// /// OpenSSL documentation at [`BN_psuedo_rand`] /// /// [`BN_psuedo_rand`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_pseudo_rand.html pub fn pseudo_rand(&mut self, bits: i32, msb: MsbOption, odd: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_pseudo_rand( self.as_ptr(), bits.into(), msb.0, odd as c_int, )) .map(|_| ()) } } /// Generates a prime number, placing it in `self`. /// /// # Parameters /// /// * `bits`: The length of the prime in bits (lower bound). /// * `safe`: If true, returns a "safe" prime `p` so that `(p-1)/2` is also prime. /// * `add`/`rem`: If `add` is set to `Some(add)`, `p % add == rem` will hold, where `p` is the /// generated prime and `rem` is `1` if not specified (`None`). /// /// # Examples /// /// ``` /// use openssl::bn::BigNum; /// use openssl::error::ErrorStack; /// /// fn generate_weak_prime() -> Result< BigNum, ErrorStack > { /// let mut big = BigNum::new()?; /// /// // Generates a 128-bit simple prime number /// big.generate_prime(128, false, None, None); /// Ok((big)) /// } /// ``` /// /// OpenSSL documentation at [`BN_generate_prime_ex`] /// /// [`BN_generate_prime_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_generate_prime_ex.html pub fn generate_prime( &mut self, bits: i32, safe: bool, add: Option<&BigNumRef>, rem: Option<&BigNumRef>, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_generate_prime_ex( self.as_ptr(), bits as c_int, safe as c_int, 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(|_| ()) } } /// Places the result of `a * b` in `self`. /// [`core::ops::Mul`] is also implemented for `BigNumRef`. /// /// OpenSSL documentation at [`BN_mul`] /// /// [`core::ops::Mul`]: struct.BigNumRef.html#method.mul /// [`BN_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mul.html pub fn checked_mul( &mut self, a: &BigNumRef, b: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mul( self.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `a / b` in `self`. The remainder is discarded. /// [`core::ops::Div`] is also implemented for `BigNumRef`. /// /// OpenSSL documentation at [`BN_div`] /// /// [`core::ops::Div`]: struct.BigNumRef.html#method.div /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html pub fn checked_div( &mut self, a: &BigNumRef, b: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_div( self.as_ptr(), ptr::null_mut(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `a % b` in `self`. /// /// OpenSSL documentation at [`BN_div`] /// /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html pub fn checked_rem( &mut self, a: &BigNumRef, b: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_div( ptr::null_mut(), self.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `a / b` in `self` and `a % b` in `rem`. /// /// OpenSSL documentation at [`BN_div`] /// /// [`BN_div`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_div.html pub fn div_rem( &mut self, rem: &mut BigNumRef, a: &BigNumRef, b: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_div( self.as_ptr(), rem.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `a²` in `self`. /// /// OpenSSL documentation at [`BN_sqr`] /// /// [`BN_sqr`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_sqr.html pub fn sqr(&mut self, a: &BigNumRef, ctx: &mut BigNumContextRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_sqr(self.as_ptr(), a.as_ptr(), ctx.as_ptr())).map(|_| ()) } } /// Places the result of `a mod m` in `self`. As opposed to `div_rem` /// the result is non-negative. /// /// OpenSSL documentation at [`BN_nnmod`] /// /// [`BN_nnmod`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_nnmod.html pub fn nnmod( &mut self, a: &BigNumRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_nnmod( self.as_ptr(), a.as_ptr(), m.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `(a + b) mod m` in `self`. /// /// OpenSSL documentation at [`BN_mod_add`] /// /// [`BN_mod_add`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_add.html pub fn mod_add( &mut self, a: &BigNumRef, b: &BigNumRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mod_add( self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `(a - b) mod m` in `self`. /// /// OpenSSL documentation at [`BN_mod_sub`] /// /// [`BN_mod_sub`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_sub.html pub fn mod_sub( &mut self, a: &BigNumRef, b: &BigNumRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mod_sub( self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `(a * b) mod m` in `self`. /// /// OpenSSL documentation at [`BN_mod_mul`] /// /// [`BN_mod_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_mul.html pub fn mod_mul( &mut self, a: &BigNumRef, b: &BigNumRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mod_mul( self.as_ptr(), a.as_ptr(), b.as_ptr(), m.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `a² mod m` in `self`. /// /// OpenSSL documentation at [`BN_mod_sqr`] /// /// [`BN_mod_sqr`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_sqr.html pub fn mod_sqr( &mut self, a: &BigNumRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mod_sqr( self.as_ptr(), a.as_ptr(), m.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `a^p` in `self`. /// /// OpenSSL documentation at [`BN_exp`] /// /// [`BN_exp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_exp.html pub fn exp( &mut self, a: &BigNumRef, p: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_exp( self.as_ptr(), a.as_ptr(), p.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `a^p mod m` in `self`. /// /// OpenSSL documentation at [`BN_mod_exp`] /// /// [`BN_mod_exp`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_mod_exp.html pub fn mod_exp( &mut self, a: &BigNumRef, p: &BigNumRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_mod_exp( self.as_ptr(), a.as_ptr(), p.as_ptr(), m.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the inverse of `a` modulo `n` in `self`. pub fn mod_inverse( &mut self, a: &BigNumRef, n: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt_p(ffi::BN_mod_inverse( self.as_ptr(), a.as_ptr(), n.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the greatest common denominator of `a` and `b` in `self`. /// /// OpenSSL documentation at [`BN_gcd`] /// /// [`BN_gcd`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_gcd.html pub fn gcd( &mut self, a: &BigNumRef, b: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::BN_gcd( self.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Checks whether `self` is prime. /// /// Performs a Miller-Rabin probabilistic primality test with `checks` iterations. /// /// OpenSSL documentation at [`BN_is_prime_ex`] /// /// [`BN_is_prime_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_prime_ex.html /// /// # Return Value /// /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. pub fn is_prime(&self, checks: i32, ctx: &mut BigNumContextRef) -> Result { unsafe { cvt_n(ffi::BN_is_prime_ex( self.as_ptr(), checks.into(), ctx.as_ptr(), ptr::null_mut(), )) .map(|r| r != 0) } } /// Checks whether `self` is prime with optional trial division. /// /// If `do_trial_division` is `true`, first performs trial division by a number of small primes. /// Then, like `is_prime`, performs a Miller-Rabin probabilistic primality test with `checks` /// iterations. /// /// OpenSSL documentation at [`BN_is_prime_fasttest_ex`] /// /// [`BN_is_prime_fasttest_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_is_prime_fasttest_ex.html /// /// # Return Value /// /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. pub fn is_prime_fasttest( &self, checks: i32, ctx: &mut BigNumContextRef, do_trial_division: bool, ) -> Result { unsafe { cvt_n(ffi::BN_is_prime_fasttest_ex( self.as_ptr(), checks.into(), ctx.as_ptr(), do_trial_division as c_int, ptr::null_mut(), )) .map(|r| r != 0) } } /// Returns a big-endian byte vector representation of the absolute value of `self`. /// /// `self` can be recreated by using `from_slice`. /// /// ``` /// # use openssl::bn::BigNum; /// let s = -BigNum::from_u32(4543).unwrap(); /// let r = BigNum::from_u32(4543).unwrap(); /// /// let s_vec = s.to_vec(); /// assert_eq!(BigNum::from_slice(&s_vec).unwrap(), r); /// ``` pub fn to_vec(&self) -> Vec { let size = self.num_bytes() as usize; let mut v = Vec::with_capacity(size); unsafe { ffi::BN_bn2bin(self.as_ptr(), v.as_mut_ptr()); v.set_len(size); } v } /// Returns a decimal string representation of `self`. /// /// ``` /// # use openssl::bn::BigNum; /// let s = -BigNum::from_u32(12345).unwrap(); /// /// assert_eq!(&**s.to_dec_str().unwrap(), "-12345"); /// ``` pub fn to_dec_str(&self) -> Result { unsafe { let buf = cvt_p(ffi::BN_bn2dec(self.as_ptr()))?; Ok(OpensslString::from_ptr(buf)) } } /// Returns a hexadecimal string representation of `self`. /// /// ``` /// # use openssl::bn::BigNum; /// let s = -BigNum::from_u32(0x99ff).unwrap(); /// /// assert_eq!(&**s.to_hex_str().unwrap(), "-99FF"); /// ``` pub fn to_hex_str(&self) -> Result { unsafe { let buf = cvt_p(ffi::BN_bn2hex(self.as_ptr()))?; Ok(OpensslString::from_ptr(buf)) } } /// Returns an `Asn1Integer` containing the value of `self`. pub fn to_asn1_integer(&self) -> Result { unsafe { cvt_p(ffi::BN_to_ASN1_INTEGER(self.as_ptr(), ptr::null_mut())) .map(|p| Asn1Integer::from_ptr(p)) } } } impl BigNum { /// Creates a new `BigNum` with the value 0. pub fn new() -> Result { unsafe { ffi::init(); let v = cvt_p(ffi::BN_new())?; Ok(BigNum::from_ptr(v)) } } /// Creates a new `BigNum` with the given value. /// /// OpenSSL documentation at [`BN_set_word`] /// /// [`BN_set_word`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_set_word.html pub fn from_u32(n: u32) -> Result { BigNum::new().and_then(|v| unsafe { cvt(ffi::BN_set_word(v.as_ptr(), n as ffi::BN_ULONG)).map(|_| v) }) } /// Creates a `BigNum` from a decimal string. /// /// OpenSSL documentation at [`BN_dec2bn`] /// /// [`BN_dec2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_dec2bn.html pub fn from_dec_str(s: &str) -> Result { unsafe { ffi::init(); let c_str = CString::new(s.as_bytes()).unwrap(); let mut bn = ptr::null_mut(); cvt(ffi::BN_dec2bn(&mut bn, c_str.as_ptr() as *const _))?; Ok(BigNum::from_ptr(bn)) } } /// Creates a `BigNum` from a hexadecimal string. /// /// OpenSSL documentation at [`BN_hex2bn`] /// /// [`BN_hex2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_hex2bn.html pub fn from_hex_str(s: &str) -> Result { unsafe { ffi::init(); let c_str = CString::new(s.as_bytes()).unwrap(); let mut bn = ptr::null_mut(); cvt(ffi::BN_hex2bn(&mut bn, c_str.as_ptr() as *const _))?; Ok(BigNum::from_ptr(bn)) } } /// Returns a constant used in IKE as defined in [`RFC 2409`]. This prime number is in /// the order of magnitude of `2 ^ 768`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled Oakley group id 1. /// /// OpenSSL documentation at [`BN_get_rfc2409_prime_768`] /// /// [`RFC 2409`]: https://tools.ietf.org/html/rfc2409#page-21 /// [`BN_get_rfc2409_prime_768`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc2409_prime_768.html pub fn get_rfc2409_prime_768() -> Result { unsafe { ffi::init(); cvt_p(BN_get_rfc2409_prime_768(ptr::null_mut())).map(BigNum) } } /// Returns a constant used in IKE as defined in [`RFC 2409`]. This prime number is in /// the order of magnitude of `2 ^ 1024`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled Oakly group 2. /// /// OpenSSL documentation at [`BN_get_rfc2409_prime_1024`] /// /// [`RFC 2409`]: https://tools.ietf.org/html/rfc2409#page-21 /// [`BN_get_rfc2409_prime_1024`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc2409_prime_1024.html pub fn get_rfc2409_prime_1024() -> Result { unsafe { ffi::init(); cvt_p(BN_get_rfc2409_prime_1024(ptr::null_mut())).map(BigNum) } } /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order /// of magnitude of `2 ^ 1536`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 5. /// /// OpenSSL documentation at [`BN_get_rfc3526_prime_1536`] /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-3 /// [`BN_get_rfc3526_prime_1536`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_1536.html pub fn get_rfc3526_prime_1536() -> Result { unsafe { ffi::init(); cvt_p(BN_get_rfc3526_prime_1536(ptr::null_mut())).map(BigNum) } } /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order /// of magnitude of `2 ^ 2048`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 14. /// /// OpenSSL documentation at [`BN_get_rfc3526_prime_2048`] /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-3 /// [`BN_get_rfc3526_prime_2048`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_2048.html pub fn get_rfc3526_prime_2048() -> Result { unsafe { ffi::init(); cvt_p(BN_get_rfc3526_prime_2048(ptr::null_mut())).map(BigNum) } } /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order /// of magnitude of `2 ^ 3072`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 15. /// /// OpenSSL documentation at [`BN_get_rfc3526_prime_3072`] /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-4 /// [`BN_get_rfc3526_prime_3072`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_3072.html pub fn get_rfc3526_prime_3072() -> Result { unsafe { ffi::init(); cvt_p(BN_get_rfc3526_prime_3072(ptr::null_mut())).map(BigNum) } } /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order /// of magnitude of `2 ^ 4096`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 16. /// /// OpenSSL documentation at [`BN_get_rfc3526_prime_4096`] /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-4 /// [`BN_get_rfc3526_prime_4096`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_4096.html pub fn get_rfc3526_prime_4096() -> Result { unsafe { ffi::init(); cvt_p(BN_get_rfc3526_prime_4096(ptr::null_mut())).map(BigNum) } } /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order /// of magnitude of `2 ^ 6144`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 17. /// /// OpenSSL documentation at [`BN_get_rfc3526_prime_6144`] /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-6 /// [`BN_get_rfc3526_prime_6144`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_6144.html pub fn get_rfc3526_prime_6144() -> Result { unsafe { ffi::init(); cvt_p(BN_get_rfc3526_prime_6144(ptr::null_mut())).map(BigNum) } } /// Returns a constant used in IKE as defined in [`RFC 3526`]. The prime is in the order /// of magnitude of `2 ^ 8192`. This number is used during calculated key /// exchanges such as Diffie-Hellman. This number is labeled MODP group 18. /// /// OpenSSL documentation at [`BN_get_rfc3526_prime_8192`] /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-6 /// [`BN_get_rfc3526_prime_8192`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_get_rfc3526_prime_8192.html pub fn get_rfc3526_prime_8192() -> Result { unsafe { ffi::init(); cvt_p(BN_get_rfc3526_prime_8192(ptr::null_mut())).map(BigNum) } } /// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length. /// /// OpenSSL documentation at [`BN_bin2bn`] /// /// [`BN_bin2bn`]: https://www.openssl.org/docs/man1.1.0/crypto/BN_bin2bn.html /// /// ``` /// # use openssl::bn::BigNum; /// let bignum = BigNum::from_slice(&[0x12, 0x00, 0x34]).unwrap(); /// /// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap()); /// ``` pub fn from_slice(n: &[u8]) -> Result { unsafe { ffi::init(); assert!(n.len() <= c_int::max_value() as usize); cvt_p(ffi::BN_bin2bn( n.as_ptr(), n.len() as c_int, ptr::null_mut(), )) .map(|p| BigNum::from_ptr(p)) } } } impl fmt::Debug for BigNumRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.to_dec_str() { Ok(s) => f.write_str(&s), Err(e) => Err(e.into()), } } } impl fmt::Debug for BigNum { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.to_dec_str() { Ok(s) => f.write_str(&s), Err(e) => Err(e.into()), } } } impl fmt::Display for BigNumRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.to_dec_str() { Ok(s) => f.write_str(&s), Err(e) => Err(e.into()), } } } impl fmt::Display for BigNum { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.to_dec_str() { Ok(s) => f.write_str(&s), Err(e) => Err(e.into()), } } } impl PartialEq for BigNumRef { fn eq(&self, oth: &BigNumRef) -> bool { self.cmp(oth) == Ordering::Equal } } impl PartialEq for BigNumRef { fn eq(&self, oth: &BigNum) -> bool { self.eq(oth.deref()) } } impl Eq for BigNumRef {} impl PartialEq for BigNum { fn eq(&self, oth: &BigNum) -> bool { self.deref().eq(oth) } } impl PartialEq for BigNum { fn eq(&self, oth: &BigNumRef) -> bool { self.deref().eq(oth) } } impl Eq for BigNum {} impl PartialOrd for BigNumRef { fn partial_cmp(&self, oth: &BigNumRef) -> Option { Some(self.cmp(oth)) } } impl PartialOrd for BigNumRef { fn partial_cmp(&self, oth: &BigNum) -> Option { Some(self.cmp(oth.deref())) } } impl Ord for BigNumRef { fn cmp(&self, oth: &BigNumRef) -> Ordering { unsafe { ffi::BN_cmp(self.as_ptr(), oth.as_ptr()).cmp(&0) } } } impl PartialOrd for BigNum { fn partial_cmp(&self, oth: &BigNum) -> Option { self.deref().partial_cmp(oth.deref()) } } impl PartialOrd for BigNum { fn partial_cmp(&self, oth: &BigNumRef) -> Option { self.deref().partial_cmp(oth) } } impl Ord for BigNum { fn cmp(&self, oth: &BigNum) -> Ordering { self.deref().cmp(oth.deref()) } } macro_rules! delegate { ($t:ident, $m:ident) => { impl<'a, 'b> $t<&'b BigNum> for &'a BigNumRef { type Output = BigNum; fn $m(self, oth: &BigNum) -> BigNum { $t::$m(self, oth.deref()) } } impl<'a, 'b> $t<&'b BigNumRef> for &'a BigNum { type Output = BigNum; fn $m(self, oth: &BigNumRef) -> BigNum { $t::$m(self.deref(), oth) } } impl<'a, 'b> $t<&'b BigNum> for &'a BigNum { type Output = BigNum; fn $m(self, oth: &BigNum) -> BigNum { $t::$m(self.deref(), oth.deref()) } } }; } impl<'a, 'b> Add<&'b BigNumRef> for &'a BigNumRef { type Output = BigNum; fn add(self, oth: &BigNumRef) -> BigNum { let mut r = BigNum::new().unwrap(); r.checked_add(self, oth).unwrap(); r } } delegate!(Add, add); impl<'a, 'b> Sub<&'b BigNumRef> for &'a BigNumRef { type Output = BigNum; fn sub(self, oth: &BigNumRef) -> BigNum { let mut r = BigNum::new().unwrap(); r.checked_sub(self, oth).unwrap(); r } } delegate!(Sub, sub); impl<'a, 'b> Mul<&'b BigNumRef> for &'a BigNumRef { type Output = BigNum; fn mul(self, oth: &BigNumRef) -> BigNum { let mut ctx = BigNumContext::new().unwrap(); let mut r = BigNum::new().unwrap(); r.checked_mul(self, oth, &mut ctx).unwrap(); r } } delegate!(Mul, mul); impl<'a, 'b> Div<&'b BigNumRef> for &'a BigNumRef { type Output = BigNum; fn div(self, oth: &'b BigNumRef) -> BigNum { let mut ctx = BigNumContext::new().unwrap(); let mut r = BigNum::new().unwrap(); r.checked_div(self, oth, &mut ctx).unwrap(); r } } delegate!(Div, div); impl<'a, 'b> Rem<&'b BigNumRef> for &'a BigNumRef { type Output = BigNum; fn rem(self, oth: &'b BigNumRef) -> BigNum { let mut ctx = BigNumContext::new().unwrap(); let mut r = BigNum::new().unwrap(); r.checked_rem(self, oth, &mut ctx).unwrap(); r } } delegate!(Rem, rem); impl<'a> Shl for &'a BigNumRef { type Output = BigNum; fn shl(self, n: i32) -> BigNum { let mut r = BigNum::new().unwrap(); r.lshift(self, n).unwrap(); r } } impl<'a> Shl for &'a BigNum { type Output = BigNum; fn shl(self, n: i32) -> BigNum { self.deref().shl(n) } } impl<'a> Shr for &'a BigNumRef { type Output = BigNum; fn shr(self, n: i32) -> BigNum { let mut r = BigNum::new().unwrap(); r.rshift(self, n).unwrap(); r } } impl<'a> Shr for &'a BigNum { type Output = BigNum; fn shr(self, n: i32) -> BigNum { self.deref().shr(n) } } impl<'a> Neg for &'a BigNumRef { type Output = BigNum; fn neg(self) -> BigNum { self.to_owned().unwrap().neg() } } impl<'a> Neg for &'a BigNum { type Output = BigNum; fn neg(self) -> BigNum { self.deref().neg() } } impl Neg for BigNum { type Output = BigNum; fn neg(mut self) -> BigNum { let negative = self.is_negative(); self.set_negative(!negative); self } } #[cfg(test)] mod tests { use bn::{BigNum, BigNumContext}; #[test] fn test_to_from_slice() { let v0 = BigNum::from_u32(10203004).unwrap(); let vec = v0.to_vec(); let v1 = BigNum::from_slice(&vec).unwrap(); assert!(v0 == v1); } #[test] fn test_negation() { let a = BigNum::from_u32(909829283).unwrap(); assert!(!a.is_negative()); assert!((-a).is_negative()); } #[test] fn test_shift() { let a = BigNum::from_u32(909829283).unwrap(); use std::ops::{Shl, Shr}; assert!(a == a.shl(1).shr(1)); } #[test] fn test_rand_range() { let range = BigNum::from_u32(909829283).unwrap(); let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap(); range.rand_range(&mut result).unwrap(); assert!(result >= BigNum::from_u32(0).unwrap() && result < range); } #[test] fn test_pseudo_rand_range() { let range = BigNum::from_u32(909829283).unwrap(); let mut result = BigNum::from_dec_str(&range.to_dec_str().unwrap()).unwrap(); range.pseudo_rand_range(&mut result).unwrap(); assert!(result >= BigNum::from_u32(0).unwrap() && result < range); } #[test] fn test_prime_numbers() { let a = BigNum::from_u32(19029017).unwrap(); let mut p = BigNum::new().unwrap(); p.generate_prime(128, true, None, Some(&a)).unwrap(); let mut ctx = BigNumContext::new().unwrap(); assert!(p.is_prime(100, &mut ctx).unwrap()); assert!(p.is_prime_fasttest(100, &mut ctx, true).unwrap()); } } openssl-0.10.23/src/cms.rs010064400017500001750000000201441346222217000135000ustar0000000000000000//! SMIME implementation using CMS //! //! CMS (PKCS#7) is an encyption standard. It allows signing and ecrypting data using //! X.509 certificates. The OpenSSL implementation of CMS is used in email encryption //! generated from a `Vec` of bytes. This `Vec` follows the smime protocol standards. //! Data accepted by this module will be smime type `enveloped-data`. use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use std::ptr; use bio::{MemBio, MemBioSlice}; use error::ErrorStack; use libc::c_uint; use pkey::{HasPrivate, PKeyRef}; use stack::StackRef; use x509::{X509Ref, X509}; use symm::Cipher; use {cvt, cvt_p}; bitflags! { pub struct CMSOptions : c_uint { const TEXT = ffi::CMS_TEXT; const CMS_NOCERTS = ffi::CMS_NOCERTS; const NO_CONTENT_VERIFY = ffi::CMS_NO_CONTENT_VERIFY; const NO_ATTR_VERIFY = ffi::CMS_NO_ATTR_VERIFY; const NOSIGS = ffi::CMS_NOSIGS; const NOINTERN = ffi::CMS_NOINTERN; const NO_SIGNER_CERT_VERIFY = ffi::CMS_NO_SIGNER_CERT_VERIFY; const NOVERIFY = ffi::CMS_NOVERIFY; const DETACHED = ffi::CMS_DETACHED; const BINARY = ffi::CMS_BINARY; const NOATTR = ffi::CMS_NOATTR; const NOSMIMECAP = ffi::CMS_NOSMIMECAP; const NOOLDMIMETYPE = ffi::CMS_NOOLDMIMETYPE; const CRLFEOL = ffi::CMS_CRLFEOL; const STREAM = ffi::CMS_STREAM; const NOCRL = ffi::CMS_NOCRL; const PARTIAL = ffi::CMS_PARTIAL; const REUSE_DIGEST = ffi::CMS_REUSE_DIGEST; const USE_KEYID = ffi::CMS_USE_KEYID; const DEBUG_DECRYPT = ffi::CMS_DEBUG_DECRYPT; #[cfg(all(not(libressl), not(ossl101)))] const KEY_PARAM = ffi::CMS_KEY_PARAM; #[cfg(all(not(libressl), not(ossl101), not(ossl102)))] const ASCIICRLF = ffi::CMS_ASCIICRLF; } } foreign_type_and_impl_send_sync! { type CType = ffi::CMS_ContentInfo; fn drop = ffi::CMS_ContentInfo_free; /// High level CMS wrapper /// /// CMS supports nesting various types of data, including signatures, certificates, /// encrypted data, smime messages (encrypted email), and data digest. The ContentInfo /// content type is the encapsulation of all those content types. [`RFC 5652`] describes /// CMS and OpenSSL follows this RFC's implmentation. /// /// [`RFC 5652`]: https://tools.ietf.org/html/rfc5652#page-6 pub struct CmsContentInfo; /// Reference to [`CMSContentInfo`] /// /// [`CMSContentInfo`]:struct.CmsContentInfo.html pub struct CmsContentInfoRef; } impl CmsContentInfoRef { /// Given the sender's private key, `pkey` and the recipient's certificiate, `cert`, /// decrypt the data in `self`. /// /// OpenSSL documentation at [`CMS_decrypt`] /// /// [`CMS_decrypt`]: https://www.openssl.org/docs/man1.1.0/crypto/CMS_decrypt.html pub fn decrypt(&self, pkey: &PKeyRef, cert: &X509) -> Result, ErrorStack> where T: HasPrivate, { unsafe { let pkey = pkey.as_ptr(); let cert = cert.as_ptr(); let out = MemBio::new()?; let flags: u32 = 0; cvt(ffi::CMS_decrypt( self.as_ptr(), pkey, cert, ptr::null_mut(), out.as_ptr(), flags.into(), ))?; Ok(out.get_buf().to_owned()) } } to_der! { /// Serializes this CmsContentInfo using DER. /// /// OpenSSL documentation at [`i2d_CMS_ContentInfo`] /// /// [`i2d_CMS_ContentInfo`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_CMS_ContentInfo.html to_der, ffi::i2d_CMS_ContentInfo } } impl CmsContentInfo { /// Parses a smime formatted `vec` of bytes into a `CmsContentInfo`. /// /// OpenSSL documentation at [`SMIME_read_CMS`] /// /// [`SMIME_read_CMS`]: https://www.openssl.org/docs/man1.0.2/crypto/SMIME_read_CMS.html pub fn smime_read_cms(smime: &[u8]) -> Result { unsafe { let bio = MemBioSlice::new(smime)?; let cms = cvt_p(ffi::SMIME_read_CMS(bio.as_ptr(), ptr::null_mut()))?; Ok(CmsContentInfo::from_ptr(cms)) } } 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. /// /// All arguments are optional. /// /// OpenSSL documentation at [`CMS_sign`] /// /// [`CMS_sign`]: https://www.openssl.org/docs/manmaster/man3/CMS_sign.html pub fn sign( signcert: Option<&X509Ref>, pkey: Option<&PKeyRef>, certs: Option<&StackRef>, data: Option<&[u8]>, flags: CMSOptions, ) -> Result where T: HasPrivate, { unsafe { let signcert = signcert.map_or(ptr::null_mut(), |p| p.as_ptr()); let pkey = pkey.map_or(ptr::null_mut(), |p| p.as_ptr()); let data_bio = match data { Some(data) => Some(MemBioSlice::new(data)?), None => None, }; let data_bio_ptr = data_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); let certs = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); let cms = cvt_p(ffi::CMS_sign( signcert, pkey, certs, data_bio_ptr, flags.bits(), ))?; 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); } } openssl-0.10.23/src/conf.rs010064400017500001750000000024241346222217000136440ustar0000000000000000//! Interface for processing OpenSSL configuration files. use ffi; use cvt_p; use error::ErrorStack; pub struct ConfMethod(*mut ffi::CONF_METHOD); impl ConfMethod { /// Retrieve handle to the default OpenSSL configuration file processing function. pub fn default() -> ConfMethod { unsafe { ffi::init(); // `NCONF` stands for "New Conf", as described in crypto/conf/conf_lib.c. This is // a newer API than the "CONF classic" functions. ConfMethod(ffi::NCONF_default()) } } /// Construct from raw pointer. pub unsafe fn from_ptr(ptr: *mut ffi::CONF_METHOD) -> ConfMethod { ConfMethod(ptr) } /// Convert to raw pointer. pub fn as_ptr(&self) -> *mut ffi::CONF_METHOD { self.0 } } foreign_type_and_impl_send_sync! { type CType = ffi::CONF; fn drop = ffi::NCONF_free; pub struct Conf; pub struct ConfRef; } impl Conf { /// Create a configuration parser. /// /// # Examples /// /// ``` /// use openssl::conf::{Conf, ConfMethod}; /// /// let conf = Conf::new(ConfMethod::default()); /// ``` pub fn new(method: ConfMethod) -> Result { unsafe { cvt_p(ffi::NCONF_new(method.as_ptr())).map(Conf) } } } openssl-0.10.23/src/derive.rs010064400017500001750000000100341346222217000141710ustar0000000000000000//! Shared secret derivation. use ffi; use foreign_types::ForeignTypeRef; use std::marker::PhantomData; use std::ptr; 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 ()>); unsafe impl<'a> Sync for Deriver<'a> {} unsafe impl<'a> Send for Deriver<'a> {} impl<'a> Deriver<'a> { /// Creates a new `Deriver` using the provided private key. /// /// This corresponds to [`EVP_PKEY_derive_init`]. /// /// [`EVP_PKEY_derive_init`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html pub fn new(key: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { unsafe { cvt_p(ffi::EVP_PKEY_CTX_new(key.as_ptr(), ptr::null_mut())) .map(|p| Deriver(p, PhantomData)) .and_then(|ctx| cvt(ffi::EVP_PKEY_derive_init(ctx.0)).map(|_| ctx)) } } /// Sets the peer key used for secret derivation. /// /// This corresponds to [`EVP_PKEY_derive_set_peer`]: /// /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html pub fn set_peer(&mut self, key: &'a PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, { unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) } } /// Returns the size of the shared secret. /// /// It can be used to size the buffer passed to [`Deriver::derive`]. /// /// This corresponds to [`EVP_PKEY_derive`]. /// /// [`Deriver::derive`]: #method.derive /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html pub fn len(&mut self) -> Result { unsafe { let mut len = 0; cvt(ffi::EVP_PKEY_derive(self.0, ptr::null_mut(), &mut len)).map(|_| len) } } /// Derives a shared secret between the two keys, writing it into the buffer. /// /// Returns the number of bytes written. /// /// This corresponds to [`EVP_PKEY_derive`]. /// /// [`EVP_PKEY_derive`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_PKEY_derive_init.html pub fn derive(&mut self, buf: &mut [u8]) -> Result { let mut len = buf.len(); unsafe { cvt(ffi::EVP_PKEY_derive( self.0, buf.as_mut_ptr() as *mut _, &mut len, )) .map(|_| len) } } /// A convenience function which derives a shared secret and returns it in a new buffer. /// /// This simply wraps [`Deriver::len`] and [`Deriver::derive`]. /// /// [`Deriver::len`]: #method.len /// [`Deriver::derive`]: #method.derive pub fn derive_to_vec(&mut self) -> Result, ErrorStack> { let len = self.len()?; let mut buf = vec![0; len]; let len = self.derive(&mut buf)?; buf.truncate(len); Ok(buf) } } #[cfg(test)] mod test { use super::*; use ec::{EcGroup, EcKey}; use nid::Nid; use pkey::PKey; #[test] fn derive_without_peer() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let ec_key = EcKey::generate(&group).unwrap(); let pkey = PKey::from_ec_key(ec_key).unwrap(); let mut deriver = Deriver::new(&pkey).unwrap(); deriver.derive_to_vec().unwrap_err(); } #[test] fn test_ec_key_derive() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let ec_key = EcKey::generate(&group).unwrap(); let ec_key2 = EcKey::generate(&group).unwrap(); let pkey = PKey::from_ec_key(ec_key).unwrap(); let pkey2 = PKey::from_ec_key(ec_key2).unwrap(); let mut deriver = Deriver::new(&pkey).unwrap(); deriver.set_peer(&pkey2).unwrap(); let shared = deriver.derive_to_vec().unwrap(); assert!(!shared.is_empty()); } } openssl-0.10.23/src/dh.rs010064400017500001750000000140461346222217000133150ustar0000000000000000use error::ErrorStack; use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use std::mem; use std::ptr; use bn::BigNum; use pkey::{HasParams, Params}; use {cvt, cvt_p}; generic_foreign_type_and_impl_send_sync! { type CType = ffi::DH; fn drop = ffi::DH_free; pub struct Dh; pub struct DhRef; } impl DhRef where T: HasParams, { to_pem! { /// Serializes the parameters into a PEM-encoded PKCS#3 DHparameter structure. /// /// The output will have a header of `-----BEGIN DH PARAMETERS-----`. /// /// This corresponds to [`PEM_write_bio_DHparams`]. /// /// [`PEM_write_bio_DHparams`]: https://www.openssl.org/docs/manmaster/man3/PEM_write_bio_DHparams.html params_to_pem, ffi::PEM_write_bio_DHparams } to_der! { /// Serializes the parameters into a DER-encoded PKCS#3 DHparameter structure. /// /// This corresponds to [`i2d_DHparams`]. /// /// [`i2d_DHparams`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_DHparams.html params_to_der, ffi::i2d_DHparams } } impl Dh { pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result, ErrorStack> { unsafe { let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); cvt(DH_set0_pqg(dh.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; mem::forget((p, g, q)); Ok(dh) } } from_pem! { /// Deserializes a PEM-encoded PKCS#3 DHpararameters structure. /// /// The input should have a header of `-----BEGIN DH PARAMETERS-----`. /// /// This corresponds to [`PEM_read_bio_DHparams`]. /// /// [`PEM_read_bio_DHparams`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_DHparams.html params_from_pem, Dh, ffi::PEM_read_bio_DHparams } from_der! { /// Deserializes a DER-encoded PKCS#3 DHparameters structure. /// /// This corresponds to [`d2i_DHparams`]. /// /// [`d2i_DHparams`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_DHparams.html params_from_der, Dh, ffi::d2i_DHparams } /// Requires OpenSSL 1.0.2 or newer. #[cfg(any(ossl102, ossl110))] pub fn get_1024_160() -> Result, ErrorStack> { unsafe { ffi::init(); cvt_p(ffi::DH_get_1024_160()).map(|p| Dh::from_ptr(p)) } } /// Requires OpenSSL 1.0.2 or newer. #[cfg(any(ossl102, ossl110))] pub fn get_2048_224() -> Result, ErrorStack> { unsafe { ffi::init(); cvt_p(ffi::DH_get_2048_224()).map(|p| Dh::from_ptr(p)) } } /// Requires OpenSSL 1.0.2 or newer. #[cfg(any(ossl102, ossl110))] pub fn get_2048_256() -> Result, ErrorStack> { unsafe { ffi::init(); cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p)) } } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::DH_set0_pqg; } else { #[allow(bad_style)] unsafe fn DH_set0_pqg( dh: *mut ffi::DH, p: *mut ffi::BIGNUM, q: *mut ffi::BIGNUM, g: *mut ffi::BIGNUM, ) -> ::libc::c_int { (*dh).p = p; (*dh).q = q; (*dh).g = g; 1 } } } #[cfg(test)] mod tests { use bn::BigNum; use dh::Dh; use ssl::{SslContext, SslMethod}; #[test] #[cfg(any(ossl102, ossl110))] fn test_dh_rfc5114() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); let dh1 = Dh::get_1024_160().unwrap(); ctx.set_tmp_dh(&dh1).unwrap(); let dh2 = Dh::get_2048_224().unwrap(); ctx.set_tmp_dh(&dh2).unwrap(); let dh3 = Dh::get_2048_256().unwrap(); ctx.set_tmp_dh(&dh3).unwrap(); } #[test] fn test_dh() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); let p = BigNum::from_hex_str( "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF\ 4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B47\ 58C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B6\ 3ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5\ 140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710\ C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", ).unwrap(); let g = BigNum::from_hex_str( "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED\ 4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A\ 57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5\ 045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E\ 052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67E\ B6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", ).unwrap(); let q = BigNum::from_hex_str( "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", ) .unwrap(); let dh = Dh::from_params(p, g, q).unwrap(); ctx.set_tmp_dh(&dh).unwrap(); } #[test] fn test_dh_from_pem() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); let params = include_bytes!("../test/dhparams.pem"); let dh = Dh::params_from_pem(params).unwrap(); ctx.set_tmp_dh(&dh).unwrap(); } #[test] fn test_dh_from_der() { let params = include_bytes!("../test/dhparams.pem"); let dh = Dh::params_from_pem(params).unwrap(); let der = dh.params_to_der().unwrap(); Dh::params_from_der(&der).unwrap(); } } openssl-0.10.23/src/dsa.rs010064400017500001750000000320551346222217000134710ustar0000000000000000//! Digital Signatures //! //! DSA ensures a message originated from a known sender, and was not modified. //! DSA uses asymetrical keys and an algorithm to output a signature of the message //! using the private key that can be validated with the public key but not be generated //! without the private key. use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; use std::mem; use std::ptr; use bn::{BigNum, BigNumRef}; use error::ErrorStack; use pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; use {cvt, cvt_p}; generic_foreign_type_and_impl_send_sync! { type CType = ffi::DSA; fn drop = ffi::DSA_free; /// Object representing DSA keys. /// /// A DSA object contains the parameters p, q, and g. There is a private /// and public key. The values p, g, and q are: /// /// * `p`: DSA prime parameter /// * `q`: DSA sub-prime parameter /// * `g`: DSA base parameter /// /// These values are used to calculate a pair of asymetrical keys used for /// signing. /// /// OpenSSL documentation at [`DSA_new`] /// /// [`DSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_new.html /// /// # Examples /// /// ``` /// use openssl::dsa::Dsa; /// use openssl::error::ErrorStack; /// use openssl::pkey::Private; /// /// fn create_dsa() -> Result, ErrorStack> { /// let sign = Dsa::generate(2048)?; /// Ok(sign) /// } /// # fn main() { /// # create_dsa(); /// # } /// ``` pub struct Dsa; /// Reference to [`Dsa`]. /// /// [`Dsa`]: struct.Dsa.html 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, { to_pem! { /// Serialies the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. /// /// This corresponds to [`PEM_write_bio_DSA_PUBKEY`]. /// /// [`PEM_write_bio_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_DSA_PUBKEY.html public_key_to_pem, ffi::PEM_write_bio_DSA_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. /// /// This corresponds to [`i2d_DSA_PUBKEY`]. /// /// [`i2d_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_DSA_PUBKEY.html public_key_to_der, ffi::i2d_DSA_PUBKEY } /// Returns a reference to the public key component of `self`. pub fn pub_key(&self) -> &BigNumRef { unsafe { let mut pub_key = ptr::null(); DSA_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut()); BigNumRef::from_ptr(pub_key as *mut _) } } } impl DsaRef where T: HasPrivate, { /// Returns a reference to the private key component of `self`. pub fn priv_key(&self) -> &BigNumRef { unsafe { let mut priv_key = ptr::null(); DSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key); BigNumRef::from_ptr(priv_key as *mut _) } } } impl DsaRef where T: HasParams, { /// Returns the maximum size of the signature output by `self` in bytes. /// /// OpenSSL documentation at [`DSA_size`] /// /// [`DSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_size.html pub fn size(&self) -> u32 { unsafe { ffi::DSA_size(self.as_ptr()) as u32 } } /// Returns the DSA prime parameter of `self`. pub fn p(&self) -> &BigNumRef { unsafe { let mut p = ptr::null(); DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); BigNumRef::from_ptr(p as *mut _) } } /// Returns the DSA sub-prime parameter of `self`. pub fn q(&self) -> &BigNumRef { unsafe { let mut q = ptr::null(); DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); BigNumRef::from_ptr(q as *mut _) } } /// Returns the DSA base parameter of `self`. pub fn g(&self) -> &BigNumRef { unsafe { let mut g = ptr::null(); DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); BigNumRef::from_ptr(g as *mut _) } } } impl Dsa { /// Generate a DSA key pair. /// /// Calls [`DSA_generate_parameters_ex`] to populate the `p`, `g`, and `q` values. /// These values are used to generate the key pair with [`DSA_generate_key`]. /// /// The `bits` parameter corresponds to the length of the prime `p`. /// /// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_parameters_ex.html /// [`DSA_generate_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DSA_generate_key.html pub fn generate(bits: u32) -> Result, ErrorStack> { ffi::init(); unsafe { let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); cvt(ffi::DSA_generate_parameters_ex( dsa.0, bits as c_int, ptr::null(), 0, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ))?; cvt(ffi::DSA_generate_key(dsa.0))?; Ok(dsa) } } /// Create a DSA key pair with the given parameters /// /// `p`, `q` and `g` are the common parameters. /// `priv_key` is the private component of the key pair. /// `pub_key` is the public component of the key. Can be computed via `g^(priv_key) mod p` pub fn from_private_components( p: BigNum, q: BigNum, g: BigNum, priv_key: BigNum, pub_key: BigNum, ) -> Result, ErrorStack> { ffi::init(); unsafe { let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; mem::forget((p, q, g)); cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), priv_key.as_ptr()))?; mem::forget((pub_key, priv_key)); Ok(dsa) } } } impl Dsa { from_pem! { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a DSA key. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. /// /// This corresponds to [`PEM_read_bio_DSA_PUBKEY`]. /// /// [`PEM_read_bio_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_DSA_PUBKEY.html public_key_from_pem, Dsa, ffi::PEM_read_bio_DSA_PUBKEY } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key. /// /// This corresponds to [`d2i_DSA_PUBKEY`]. /// /// [`d2i_DSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_DSA_PUBKEY.html public_key_from_der, Dsa, ffi::d2i_DSA_PUBKEY } /// Create a new DSA key with only public components. /// /// `p`, `q` and `g` are the common parameters. /// `pub_key` is the public component of the key. pub fn from_public_components( p: BigNum, q: BigNum, g: BigNum, pub_key: BigNum, ) -> Result, ErrorStack> { ffi::init(); unsafe { let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; mem::forget((p, q, g)); cvt(DSA_set0_key(dsa.0, pub_key.as_ptr(), ptr::null_mut()))?; mem::forget(pub_key); Ok(dsa) } } } impl fmt::Debug for Dsa { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "DSA") } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg}; } else { #[allow(bad_style)] unsafe fn DSA_get0_pqg( d: *mut ffi::DSA, p: *mut *const ffi::BIGNUM, q: *mut *const ffi::BIGNUM, g: *mut *const ffi::BIGNUM) { if !p.is_null() { *p = (*d).p; } if !q.is_null() { *q = (*d).q; } if !g.is_null() { *g = (*d).g; } } #[allow(bad_style)] unsafe fn DSA_get0_key( d: *mut ffi::DSA, pub_key: *mut *const ffi::BIGNUM, priv_key: *mut *const ffi::BIGNUM) { if !pub_key.is_null() { *pub_key = (*d).pub_key; } if !priv_key.is_null() { *priv_key = (*d).priv_key; } } #[allow(bad_style)] unsafe fn DSA_set0_key( d: *mut ffi::DSA, pub_key: *mut ffi::BIGNUM, priv_key: *mut ffi::BIGNUM) -> c_int { (*d).pub_key = pub_key; (*d).priv_key = priv_key; 1 } #[allow(bad_style)] unsafe fn DSA_set0_pqg( d: *mut ffi::DSA, p: *mut ffi::BIGNUM, q: *mut ffi::BIGNUM, g: *mut ffi::BIGNUM) -> c_int { (*d).p = p; (*d).q = q; (*d).g = g; 1 } } } #[cfg(test)] mod test { use super::*; use bn::BigNumContext; use hash::MessageDigest; use pkey::PKey; use sign::{Signer, Verifier}; #[test] pub fn test_generate() { Dsa::generate(1024).unwrap(); } #[test] fn test_pubkey_generation() { let dsa = Dsa::generate(1024).unwrap(); let p = dsa.p(); let g = dsa.g(); let priv_key = dsa.priv_key(); let pub_key = dsa.pub_key(); let mut ctx = BigNumContext::new().unwrap(); let mut calc = BigNum::new().unwrap(); calc.mod_exp(g, priv_key, p, &mut ctx).unwrap(); assert_eq!(&calc, pub_key) } #[test] fn test_priv_key_from_parts() { let p = BigNum::from_u32(283).unwrap(); let q = BigNum::from_u32(47).unwrap(); let g = BigNum::from_u32(60).unwrap(); let priv_key = BigNum::from_u32(15).unwrap(); let pub_key = BigNum::from_u32(207).unwrap(); let dsa = Dsa::from_private_components(p, q, g, priv_key, pub_key).unwrap(); assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); assert_eq!(dsa.priv_key(), &BigNum::from_u32(15).unwrap()); assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); } #[test] fn test_pub_key_from_parts() { let p = BigNum::from_u32(283).unwrap(); let q = BigNum::from_u32(47).unwrap(); let g = BigNum::from_u32(60).unwrap(); let pub_key = BigNum::from_u32(207).unwrap(); let dsa = Dsa::from_public_components(p, q, g, pub_key).unwrap(); assert_eq!(dsa.pub_key(), &BigNum::from_u32(207).unwrap()); assert_eq!(dsa.p(), &BigNum::from_u32(283).unwrap()); assert_eq!(dsa.q(), &BigNum::from_u32(47).unwrap()); assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); } #[test] fn test_signature() { const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let dsa_ref = Dsa::generate(1024).unwrap(); let p = dsa_ref.p(); let q = dsa_ref.q(); let g = dsa_ref.g(); let pub_key = dsa_ref.pub_key(); let priv_key = dsa_ref.priv_key(); let priv_key = Dsa::from_private_components( BigNumRef::to_owned(p).unwrap(), BigNumRef::to_owned(q).unwrap(), BigNumRef::to_owned(g).unwrap(), BigNumRef::to_owned(priv_key).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(); let pub_key = PKey::from_dsa(pub_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); signer.update(TEST_DATA).unwrap(); let signature = signer.sign_to_vec().unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); verifier.update(TEST_DATA).unwrap(); assert!(verifier.verify(&signature[..]).unwrap()); } #[test] fn clone() { let key = Dsa::generate(2048).unwrap(); drop(key.clone()); } } openssl-0.10.23/src/ec.rs010064400017500001750000000754041346222217000133160ustar0000000000000000//! Elliptic Curve //! //! Cryptology relies on the difficulty of solving mathematical problems, such as the factor //! of large integers composed of two large prime numbers and the discrete logarithm of a //! random eliptic curve. This module provides low-level features of the latter. //! Elliptic Curve protocols can provide the same security with smaller keys. //! //! There are 2 forms of elliptic curves, `Fp` and `F2^m`. These curves use irreducible //! trinomial or pentanomial . Being a generic interface to a wide range of algorithms, //! the cuves are generally referenced by [`EcGroup`]. There are many built in groups //! found in [`Nid`]. //! //! OpenSSL Wiki explains the fields and curves in detail at [Eliptic Curve Cryptography]. //! //! [`EcGroup`]: struct.EcGroup.html //! [`Nid`]: ../nid/struct.Nid.html //! [Eliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography //! //! # Examples //! //! ``` //! use openssl::ec::{EcGroup, EcPoint}; //! use openssl::nid::Nid; //! use openssl::error::ErrorStack; //! fn get_ec_point() -> Result { //! let group = EcGroup::from_curve_name(Nid::SECP224R1)?; //! let point = EcPoint::new(&group)?; //! Ok(point) //! } //! # fn main() { //! # let _ = get_ec_point(); //! # } //! ``` use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::ptr; use bn::{BigNumContextRef, BigNumRef}; use error::ErrorStack; use nid::Nid; use pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; use {cvt, cvt_n, cvt_p, init}; /// Compressed or Uncompressed conversion /// /// Conversion from the binary value of the point on the curve is performed in one of /// compressed, uncompressed, or hybrid conversions. The default is compressed, except /// for binary curves. /// /// Further documentation is available in the [X9.62] standard. /// /// [X9.62]: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf #[derive(Copy, Clone)] pub struct PointConversionForm(ffi::point_conversion_form_t); impl PointConversionForm { /// Compressed conversion from point value. pub const COMPRESSED: PointConversionForm = PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); /// Uncompressed conversion from point value. pub const UNCOMPRESSED: PointConversionForm = PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); /// Performs both compressed and uncompressed conversions. pub const HYBRID: PointConversionForm = PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); } /// Named Curve or Explicit /// /// This type acts as a boolean as to whether the `EcGroup` is named or explicit. #[derive(Copy, Clone)] pub struct Asn1Flag(c_int); impl Asn1Flag { /// Curve defined using polynomial parameters /// /// Most applications use a named EC_GROUP curve, however, support /// is included to explicitly define the curve used to calculate keys /// This information would need to be known by both endpoint to make communication /// effective. /// /// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1. /// Man page documents that 0 can be used in older versions. /// /// OpenSSL documentation at [`EC_GROUP`] /// /// [`EC_GROUP`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_seed_len.html pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0); /// Standard Curves /// /// Curves that make up the typical encryption use cases. The collection of curves /// are well known but extensible. /// /// OpenSSL documentation at [`EC_GROUP`] /// /// [`EC_GROUP`]: https://www.openssl.org/docs/manmaster/man3/EC_GROUP_order_bits.html pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE); } foreign_type_and_impl_send_sync! { type CType = ffi::EC_GROUP; fn drop = ffi::EC_GROUP_free; /// Describes the curve /// /// A curve can be of the named curve type. These curves can be discovered /// using openssl binary `openssl ecparam -list_curves`. Other operations /// are available in the [wiki]. These named curves are available in the /// [`Nid`] module. /// /// Curves can also be generated using prime field parameters or a binary field. /// /// Prime fields use the formula `y^2 mod p = x^3 + ax + b mod p`. Binary /// fields use the formula `y^2 + xy = x^3 + ax^2 + b`. Named curves have /// assured security. To prevent accidental vulnerabilities, they should /// be prefered. /// /// [wiki]: https://wiki.openssl.org/index.php/Command_Line_Elliptic_Curve_Operations /// [`Nid`]: ../nid/index.html pub struct EcGroup; /// Reference to [`EcGroup`] /// /// [`EcGroup`]: struct.EcGroup.html pub struct EcGroupRef; } impl EcGroup { /// Returns the group of a standard named curve. /// /// OpenSSL documentation at [`EC_GROUP_new`]. /// /// [`EC_GROUP_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_new.html pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) } } } impl EcGroupRef { /// Places the components of a curve over a prime field in the provided `BigNum`s. /// The components make up the formula `y^2 mod p = x^3 + ax + b mod p`. /// /// OpenSSL documentation available at [`EC_GROUP_get_curve_GFp`] /// /// [`EC_GROUP_get_curve_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GFp.html pub fn components_gfp( &self, p: &mut BigNumRef, a: &mut BigNumRef, b: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_GROUP_get_curve_GFp( self.as_ptr(), p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the components of a curve over a binary field in the provided `BigNum`s. /// The components make up the formula `y^2 + xy = x^3 + ax^2 + b`. /// /// In this form `p` relates to the irreducible polynomial. Each bit represents /// a term in the polynomial. It will be set to 3 `1`s or 5 `1`s depending on /// using a trinomial or pentanomial. /// /// OpenSSL documentation at [`EC_GROUP_get_curve_GF2m`]. /// /// [`EC_GROUP_get_curve_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_curve_GF2m.html #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] pub fn components_gf2m( &self, p: &mut BigNumRef, a: &mut BigNumRef, b: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_GROUP_get_curve_GF2m( self.as_ptr(), p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Returns the degree of the curve. /// /// OpenSSL documentation at [`EC_GROUP_get_degree`] /// /// [`EC_GROUP_get_degree`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_degree.html pub fn degree(&self) -> u32 { unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } } /// Places the order of the curve in the provided `BigNum`. /// /// OpenSSL documentation at [`EC_GROUP_get_order`] /// /// [`EC_GROUP_get_order`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_order.html pub fn order( &self, order: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_GROUP_get_order( self.as_ptr(), order.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Sets the flag determining if the group corresponds to a named curve or must be explicitly /// parameterized. /// /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL /// 1.1.0. pub fn set_asn1_flag(&mut self, flag: Asn1Flag) { unsafe { 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! { type CType = ffi::EC_POINT; fn drop = ffi::EC_POINT_free; /// Represents a point on the curve /// /// OpenSSL documentation at [`EC_POINT_new`] /// /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html pub struct EcPoint; /// Reference to [`EcPoint`] /// /// [`EcPoint`]: struct.EcPoint.html pub struct EcPointRef; } impl EcPointRef { /// Computes `a + b`, storing the result in `self`. /// /// OpenSSL documentation at [`EC_POINT_add`] /// /// [`EC_POINT_add`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_add.html pub fn add( &mut self, group: &EcGroupRef, a: &EcPointRef, b: &EcPointRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_add( group.as_ptr(), self.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Computes `q * m`, storing the result in `self`. /// /// OpenSSL documentation at [`EC_POINT_mul`] /// /// [`EC_POINT_mul`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_mul.html pub fn mul( &mut self, group: &EcGroupRef, q: &EcPointRef, m: &BigNumRef, ctx: &BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_mul( group.as_ptr(), self.as_ptr(), ptr::null(), q.as_ptr(), m.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Computes `generator * n`, storing the result ing `self`. pub fn mul_generator( &mut self, group: &EcGroupRef, n: &BigNumRef, ctx: &BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_mul( group.as_ptr(), self.as_ptr(), n.as_ptr(), ptr::null(), ptr::null(), ctx.as_ptr(), )) .map(|_| ()) } } /// Computes `generator * n + q * m`, storing the result in `self`. pub fn mul_full( &mut self, group: &EcGroupRef, n: &BigNumRef, q: &EcPointRef, m: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_mul( group.as_ptr(), self.as_ptr(), n.as_ptr(), q.as_ptr(), m.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Inverts `self`. /// /// OpenSSL documentation at [`EC_POINT_invert`] /// /// [`EC_POINT_invert`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_invert.html pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_invert( group.as_ptr(), self.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Serializes the point to a binary representation. /// /// OpenSSL documentation at [`EC_POINT_point2oct`] /// /// [`EC_POINT_point2oct`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_point2oct.html pub fn to_bytes( &self, group: &EcGroupRef, form: PointConversionForm, ctx: &mut BigNumContextRef, ) -> Result, ErrorStack> { unsafe { let len = ffi::EC_POINT_point2oct( group.as_ptr(), self.as_ptr(), form.0, ptr::null_mut(), 0, ctx.as_ptr(), ); if len == 0 { return Err(ErrorStack::get()); } let mut buf = vec![0; len]; let len = ffi::EC_POINT_point2oct( group.as_ptr(), self.as_ptr(), form.0, buf.as_mut_ptr(), len, ctx.as_ptr(), ); if len == 0 { Err(ErrorStack::get()) } else { Ok(buf) } } } /// Determines if this point is equal to another. /// /// OpenSSL doucmentation at [`EC_POINT_cmp`] /// /// [`EC_POINT_cmp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_cmp.html pub fn eq( &self, group: &EcGroupRef, other: &EcPointRef, ctx: &mut BigNumContextRef, ) -> Result { unsafe { let res = cvt_n(ffi::EC_POINT_cmp( group.as_ptr(), self.as_ptr(), other.as_ptr(), ctx.as_ptr(), ))?; Ok(res == 0) } } /// Place affine coordinates of a curve over a prime field in the provided /// `x` and `y` `BigNum`s /// /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GFp`] /// /// [`EC_POINT_get_affine_coordinates_GFp`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GFp.html pub fn affine_coordinates_gfp( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_get_affine_coordinates_GFp( group.as_ptr(), self.as_ptr(), x.as_ptr(), y.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Place affine coordinates of a curve over a binary field in the provided /// `x` and `y` `BigNum`s /// /// OpenSSL documentation at [`EC_POINT_get_affine_coordinates_GF2m`] /// /// [`EC_POINT_get_affine_coordinates_GF2m`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_get_affine_coordinates_GF2m.html #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] pub fn affine_coordinates_gf2m( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_get_affine_coordinates_GF2m( group.as_ptr(), self.as_ptr(), x.as_ptr(), y.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } } impl EcPoint { /// Creates a new point on the specified curve. /// /// OpenSSL documentation at [`EC_POINT_new`] /// /// [`EC_POINT_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_new.html pub fn new(group: &EcGroupRef) -> Result { unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } } /// Creates point from a binary representation /// /// OpenSSL documentation at [`EC_POINT_oct2point`] /// /// [`EC_POINT_oct2point`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_oct2point.html pub fn from_bytes( group: &EcGroupRef, buf: &[u8], ctx: &mut BigNumContextRef, ) -> Result { let point = EcPoint::new(group)?; unsafe { cvt(ffi::EC_POINT_oct2point( group.as_ptr(), point.as_ptr(), buf.as_ptr(), buf.len(), ctx.as_ptr(), ))?; } Ok(point) } } generic_foreign_type_and_impl_send_sync! { type CType = ffi::EC_KEY; fn drop = ffi::EC_KEY_free; /// Public and optional Private key on the given curve /// /// OpenSSL documentation at [`EC_KEY_new`] /// /// [`EC_KEY_new`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html pub struct EcKey; /// Reference to [`EcKey`] /// /// [`EcKey`]: struct.EcKey.html pub struct EcKeyRef; } impl EcKeyRef where T: HasPrivate, { private_key_to_pem! { /// Serializes the private key to a PEM-encoded ECPrivateKey structure. /// /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. /// /// This corresponds to [`PEM_write_bio_ECPrivateKey`]. /// /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html private_key_to_pem, /// Serializes the private key to a PEM-encoded encrypted ECPrivateKey structure. /// /// The output will have a header of `-----BEGIN EC PRIVATE KEY-----`. /// /// This corresponds to [`PEM_write_bio_ECPrivateKey`]. /// /// [`PEM_write_bio_ECPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_ECPrivateKey.html private_key_to_pem_passphrase, ffi::PEM_write_bio_ECPrivateKey } to_der! { /// Serializes the private key into a DER-encoded ECPrivateKey structure. /// /// This corresponds to [`i2d_ECPrivateKey`]. /// /// [`i2d_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html private_key_to_der, ffi::i2d_ECPrivateKey } /// Return [`EcPoint`] associated with the private key /// /// OpenSSL documentation at [`EC_KEY_get0_private_key`] /// /// [`EC_KEY_get0_private_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_private_key.html pub fn private_key(&self) -> &BigNumRef { unsafe { let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); BigNumRef::from_ptr(ptr as *mut _) } } } impl EcKeyRef where T: HasPublic, { /// Returns the public key. /// /// OpenSSL documentation at [`EC_KEY_get0_pubic_key`] /// /// [`EC_KEY_get0_pubic_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_public_key.html pub fn public_key(&self) -> &EcPointRef { unsafe { let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); EcPointRef::from_ptr(ptr as *mut _) } } } impl EcKeyRef where T: HasParams, { /// Return [`EcGroup`] of the `EcKey` /// /// OpenSSL documentation at [`EC_KEY_get0_group`] /// /// [`EC_KEY_get0_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_get0_group.html pub fn group(&self) -> &EcGroupRef { unsafe { let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); EcGroupRef::from_ptr(ptr as *mut _) } } /// Checks the key for validity. /// /// OpenSSL documenation at [`EC_KEY_check_key`] /// /// [`EC_KEY_check_key`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_check_key.html pub fn check_key(&self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } } } impl ToOwned for EcKeyRef { type Owned = EcKey; fn to_owned(&self) -> EcKey { unsafe { let r = ffi::EC_KEY_up_ref(self.as_ptr()); assert!(r == 1); EcKey::from_ptr(self.as_ptr()) } } } impl EcKey { /// Constructs an `EcKey` corresponding to a known curve. /// /// It will not have an associated public or private key. This kind of key is primarily useful /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. /// /// OpenSSL documenation at [`EC_KEY_new_by_curve_name`] /// /// [`EC_KEY_new_by_curve_name`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new_by_curve_name.html pub fn from_curve_name(nid: Nid) -> Result, ErrorStack> { unsafe { init(); cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(|p| EcKey::from_ptr(p)) } } /// Constructs an `EcKey` corresponding to a curve. /// /// This corresponds to [`EC_KEY_set_group`]. /// /// [`EC_KEY_set_group`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_KEY_new.html pub fn from_group(group: &EcGroupRef) -> Result, ErrorStack> { unsafe { cvt_p(ffi::EC_KEY_new()) .map(|p| EcKey::from_ptr(p)) .and_then(|key| { cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) }) } } } impl EcKey { /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key. /// /// This will only have the associated public_key. /// /// # Example /// /// ```no_run /// use openssl::bn::BigNumContext; /// use openssl::ec::*; /// use openssl::nid::Nid; /// use openssl::pkey::PKey; /// /// // get bytes from somewhere, i.e. this will not produce a valid key /// let public_key: Vec = vec![]; /// /// // create an EcKey from the binary form of a EcPoint /// let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); /// let mut ctx = BigNumContext::new().unwrap(); /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap(); /// let key = EcKey::from_public_key(&group, &point); /// ``` pub fn from_public_key( group: &EcGroupRef, public_key: &EcPointRef, ) -> Result, ErrorStack> { unsafe { cvt_p(ffi::EC_KEY_new()) .map(|p| EcKey::from_ptr(p)) .and_then(|key| { cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) }) .and_then(|key| { cvt(ffi::EC_KEY_set_public_key( key.as_ptr(), public_key.as_ptr(), )) .map(|_| key) }) } } /// Constructs a public key from its affine coordinates. pub fn from_public_key_affine_coordinates( group: &EcGroupRef, x: &BigNumRef, y: &BigNumRef, ) -> Result, ErrorStack> { unsafe { cvt_p(ffi::EC_KEY_new()) .map(|p| EcKey::from_ptr(p)) .and_then(|key| { cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) }) .and_then(|key| { cvt(ffi::EC_KEY_set_public_key_affine_coordinates( key.as_ptr(), x.as_ptr(), y.as_ptr(), )) .map(|_| key) }) } } } impl EcKey { /// Generates a new public/private key pair on the specified curve. pub fn generate(group: &EcGroupRef) -> Result, ErrorStack> { unsafe { cvt_p(ffi::EC_KEY_new()) .map(|p| EcKey::from_ptr(p)) .and_then(|key| { cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) }) .and_then(|key| cvt(ffi::EC_KEY_generate_key(key.as_ptr())).map(|_| key)) } } /// Constructs an public/private key pair given a curve, a private key and a public key point. pub fn from_private_components( group: &EcGroupRef, private_number: &BigNumRef, public_key: &EcPointRef, ) -> Result, ErrorStack> { unsafe { cvt_p(ffi::EC_KEY_new()) .map(|p| EcKey::from_ptr(p)) .and_then(|key| { cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr())).map(|_| key) }) .and_then(|key| { cvt(ffi::EC_KEY_set_private_key( key.as_ptr(), private_number.as_ptr(), )) .map(|_| key) }) .and_then(|key| { cvt(ffi::EC_KEY_set_public_key( key.as_ptr(), public_key.as_ptr(), )) .map(|_| key) }) } } private_key_from_pem! { /// Deserializes a private key from a PEM-encoded ECPrivateKey structure. /// /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. /// /// This corresponds to `PEM_read_bio_ECPrivateKey`. private_key_from_pem, /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. /// /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. /// /// This corresponds to `PEM_read_bio_ECPrivateKey`. private_key_from_pem_passphrase, /// Deserializes a private key from a PEM-encoded encrypted ECPrivateKey structure. /// /// The callback should fill the password into the provided buffer and return its length. /// /// The input should have a header of `-----BEGIN EC PRIVATE KEY-----`. /// /// This corresponds to `PEM_read_bio_ECPrivateKey`. private_key_from_pem_callback, EcKey, ffi::PEM_read_bio_ECPrivateKey } from_der! { /// Decodes a DER-encoded elliptic curve private key structure. /// /// This corresponds to [`d2i_ECPrivateKey`]. /// /// [`d2i_ECPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_ECPrivate_key.html private_key_from_der, EcKey, ffi::d2i_ECPrivateKey } } impl Clone for EcKey { fn clone(&self) -> EcKey { (**self).to_owned() } } #[cfg(test)] mod test { use hex::FromHex; use super::*; use bn::{BigNum, BigNumContext}; use nid::Nid; #[test] fn key_new_by_curve_name() { EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); } #[test] fn generate() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); EcKey::generate(&group).unwrap(); } #[test] fn dup() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); drop(key.clone()); } #[test] fn point_new() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); EcPoint::new(&group).unwrap(); } #[test] fn point_bytes() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let point = key.public_key(); let mut ctx = BigNumContext::new().unwrap(); let bytes = point .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) .unwrap(); let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); assert!(point.eq(&group, &point2, &mut ctx).unwrap()); } #[test] fn mul_generator() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let mut public_key = EcPoint::new(&group).unwrap(); public_key .mul_generator(&group, key.private_key(), &mut ctx) .unwrap(); assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap()); } #[test] fn key_from_public_key() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let bytes = key .public_key() .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) .unwrap(); drop(key); let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); let ec_key = EcKey::from_public_key(&group, &public_key).unwrap(); assert!(ec_key.check_key().is_ok()); } #[test] fn key_from_private_components() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let dup_key = EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); let res = dup_key.check_key().unwrap(); assert!(res == ()); assert!(key.private_key() == dup_key.private_key()); } #[test] fn key_from_affine_coordinates() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") .unwrap(); let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") .unwrap(); let xbn = BigNum::from_slice(&x).unwrap(); let ybn = BigNum::from_slice(&y).unwrap(); let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); assert!(ec_key.check_key().is_ok()); } #[test] fn get_affine_coordinates() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let x = Vec::from_hex("30a0424cd21c2944838a2d75c92b37e76ea20d9f00893a3b4eee8a3c0aafec3e") .unwrap(); let y = Vec::from_hex("e04b65e92456d9888b52b379bdfbd51ee869ef1f0fc65b6659695b6cce081723") .unwrap(); let xbn = BigNum::from_slice(&x).unwrap(); let ybn = BigNum::from_slice(&y).unwrap(); let ec_key = EcKey::from_public_key_affine_coordinates(&group, &xbn, &ybn).unwrap(); let mut xbn2 = BigNum::new().unwrap(); let mut ybn2 = BigNum::new().unwrap(); let mut ctx = BigNumContext::new().unwrap(); let ec_key_pk = ec_key.public_key(); ec_key_pk .affine_coordinates_gfp(&group, &mut xbn2, &mut ybn2, &mut ctx) .unwrap(); assert_eq!(xbn2, xbn); assert_eq!(ybn2, ybn); } } openssl-0.10.23/src/ecdsa.rs010064400017500001750000000174551346470244000140150ustar0000000000000000//! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions. use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::mem; use std::ptr; use bn::{BigNum, BigNumRef}; use ec::EcKeyRef; use error::ErrorStack; use pkey::{Private, Public}; use {cvt_n, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::ECDSA_SIG; fn drop = ffi::ECDSA_SIG_free; /// A low level interface to ECDSA /// /// OpenSSL documentation at [`ECDSA_sign`] /// /// [`ECDSA_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_sign.html pub struct EcdsaSig; /// Reference to [`EcdsaSig`] /// /// [`EcdsaSig`]: struct.EcdsaSig.html pub struct EcdsaSigRef; } impl EcdsaSig { /// Computes a digital signature of the hash value `data` using the private EC key eckey. /// /// OpenSSL documentation at [`ECDSA_do_sign`] /// /// [`ECDSA_do_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_sign.html pub fn sign(data: &[u8], eckey: &EcKeyRef) -> Result { unsafe { assert!(data.len() <= c_int::max_value() as usize); let sig = cvt_p(ffi::ECDSA_do_sign( data.as_ptr(), data.len() as c_int, eckey.as_ptr(), ))?; Ok(EcdsaSig::from_ptr(sig as *mut _)) } } /// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with a /// ECDSA signature. /// /// OpenSSL documentation at [`ECDSA_SIG_set0`] /// /// [`ECDSA_SIG_set0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_set0.html pub fn from_private_components(r: BigNum, s: BigNum) -> Result { unsafe { let sig = cvt_p(ffi::ECDSA_SIG_new())?; ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); mem::forget((r, s)); Ok(EcdsaSig::from_ptr(sig as *mut _)) } } /// Verifies if the signature is a valid ECDSA signature using the given public key. /// /// OpenSSL documentation at [`ECDSA_do_verify`] /// /// [`ECDSA_do_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_verify.html pub fn verify(&self, data: &[u8], eckey: &EcKeyRef) -> Result { unsafe { assert!(data.len() <= c_int::max_value() as usize); cvt_n(ffi::ECDSA_do_verify( data.as_ptr(), data.len() as c_int, self.as_ptr(), eckey.as_ptr(), )) .map(|x| x == 1) } } /// Returns internal component: `r` of a `EcdsaSig`. (See X9.62 or FIPS 186-2) /// /// OpenSSL documentation at [`ECDSA_SIG_get0`] /// /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html pub fn r(&self) -> &BigNumRef { unsafe { let mut r = ptr::null(); ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); BigNumRef::from_ptr(r as *mut _) } } /// Returns internal components: `s` of a `EcdsaSig`. (See X9.62 or FIPS 186-2) /// /// OpenSSL documentation at [`ECDSA_SIG_get0`] /// /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html pub fn s(&self) -> &BigNumRef { unsafe { let mut s = ptr::null(); ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); BigNumRef::from_ptr(s as *mut _) } } from_der! { /// Decodes a DER-encoded ECDSA signature. /// /// 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`]. /// /// [`i2d_ECDSA_SIG`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_ECDSA_SIG.html to_der, ffi::i2d_ECDSA_SIG } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; } else { #[allow(bad_style)] unsafe fn ECDSA_SIG_set0( sig: *mut ffi::ECDSA_SIG, r: *mut ffi::BIGNUM, s: *mut ffi::BIGNUM, ) -> c_int { (*sig).r = r; (*sig).s = s; 1 } #[allow(bad_style)] unsafe fn ECDSA_SIG_get0( sig: *const ffi::ECDSA_SIG, pr: *mut *const ffi::BIGNUM, ps: *mut *const ffi::BIGNUM) { if !pr.is_null() { (*pr) = (*sig).r; } if !ps.is_null() { (*ps) = (*sig).s; } } } } #[cfg(test)] mod test { use super::*; use ec::EcGroup; use ec::EcKey; use nid::Nid; fn get_public_key(group: &EcGroup, x: &EcKey) -> Result, ErrorStack> { let public_key_point = x.public_key(); Ok(EcKey::from_public_key(group, public_key_point)?) } #[test] #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] fn sign_and_verify() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME192V1).unwrap(); let private_key = EcKey::generate(&group).unwrap(); let public_key = get_public_key(&group, &private_key).unwrap(); let private_key2 = EcKey::generate(&group).unwrap(); let public_key2 = get_public_key(&group, &private_key2).unwrap(); let data = String::from("hello"); let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); // Signature can be verified using the correct data & correct public key let verification = res.verify(data.as_bytes(), &public_key).unwrap(); assert!(verification); // Signature will not be verified using the incorrect data but the correct public key let verification2 = res .verify(String::from("hello2").as_bytes(), &public_key) .unwrap(); assert!(verification2 == false); // Signature will not be verified using the correct data but the incorrect public key let verification3 = res.verify(data.as_bytes(), &public_key2).unwrap(); assert!(verification3 == false); } #[test] #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] fn check_private_components() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME192V1).unwrap(); let private_key = EcKey::generate(&group).unwrap(); let public_key = get_public_key(&group, &private_key).unwrap(); let data = String::from("hello"); let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); let verification = res.verify(data.as_bytes(), &public_key).unwrap(); assert!(verification); let r = res.r().to_owned().unwrap(); let s = res.s().to_owned().unwrap(); let res2 = EcdsaSig::from_private_components(r, s).unwrap(); let verification2 = res2.verify(data.as_bytes(), &public_key).unwrap(); assert!(verification2); } #[test] #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)] fn serialize_deserialize() { let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); let private_key = EcKey::generate(&group).unwrap(); let public_key = get_public_key(&group, &private_key).unwrap(); let data = String::from("hello"); let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap(); let der = res.to_der().unwrap(); let sig = EcdsaSig::from_der(&der).unwrap(); let verification = sig.verify(data.as_bytes(), &public_key).unwrap(); assert!(verification); } } openssl-0.10.23/src/envelope.rs010064400017500001750000000212741346222217000145400ustar0000000000000000//! 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]); } } openssl-0.10.23/src/error.rs010064400017500001750000000205661346222217000140570ustar0000000000000000//! Errors returned by OpenSSL library. //! //! OpenSSL errors are stored in an `ErrorStack`. Most methods in the crate //! returns a `Result` type. //! //! # Examples //! //! ``` //! use openssl::error::ErrorStack; //! use openssl::bn::BigNum; //! //! let an_error = BigNum::from_dec_str("Cannot parse letters"); //! match an_error { //! Ok(_) => (), //! Err(e) => println!("Parsing Error: {:?}", e), //! } //! ``` use libc::{c_char, c_int, c_ulong}; use std::borrow::Cow; use std::error; use std::ffi::CStr; use std::fmt; use std::io; use std::ptr; use std::str; use ffi; /// Collection of [`Error`]s from OpenSSL. /// /// [`Error`]: struct.Error.html #[derive(Debug, Clone)] pub struct ErrorStack(Vec); impl ErrorStack { /// Returns the contents of the OpenSSL error stack. pub fn get() -> ErrorStack { let mut vec = vec![]; while let Some(err) = Error::get() { vec.push(err); } ErrorStack(vec) } /// Pushes the errors back onto the OpenSSL error stack. pub fn put(&self) { for error in self.errors() { error.put(); } } } impl ErrorStack { /// Returns the errors in the stack. pub fn errors(&self) -> &[Error] { &self.0 } } impl fmt::Display for ErrorStack { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { if self.0.is_empty() { return fmt.write_str("OpenSSL error"); } let mut first = true; for err in &self.0 { if !first { fmt.write_str(", ")?; } write!(fmt, "{}", err)?; first = false; } Ok(()) } } impl error::Error for ErrorStack { fn description(&self) -> &str { "An OpenSSL error stack" } } impl From for io::Error { fn from(e: ErrorStack) -> io::Error { io::Error::new(io::ErrorKind::Other, e) } } impl From for fmt::Error { fn from(_: ErrorStack) -> fmt::Error { fmt::Error } } /// An error reported from OpenSSL. #[derive(Clone)] pub struct Error { code: c_ulong, file: *const c_char, line: c_int, data: Option>, } unsafe impl Sync for Error {} unsafe impl Send for Error {} impl Error { /// Returns the first error on the OpenSSL error stack. pub fn get() -> Option { unsafe { ffi::init(); let mut file = ptr::null(); let mut line = 0; let mut data = ptr::null(); let mut flags = 0; match ffi::ERR_get_error_line_data(&mut file, &mut line, &mut data, &mut flags) { 0 => None, code => { // The memory referenced by data is only valid until that slot is overwritten // in the error stack, so we'll need to copy it off if it's dynamic let data = if flags & ffi::ERR_TXT_STRING != 0 { let bytes = CStr::from_ptr(data as *const _).to_bytes(); let data = str::from_utf8(bytes).unwrap(); let data = if flags & ffi::ERR_TXT_MALLOCED != 0 { Cow::Owned(data.to_string()) } else { Cow::Borrowed(data) }; Some(data) } else { None }; Some(Error { code, file, line, data, }) } } } } /// Pushes the error back onto the OpenSSL error stack. pub fn put(&self) { unsafe { ffi::ERR_put_error( ffi::ERR_GET_LIB(self.code), ffi::ERR_GET_FUNC(self.code), ffi::ERR_GET_REASON(self.code), self.file, self.line, ); let data = match self.data { Some(Cow::Borrowed(data)) => Some((data.as_ptr() as *mut c_char, 0)), Some(Cow::Owned(ref data)) => { let ptr = ffi::CRYPTO_malloc( (data.len() + 1) as _, concat!(file!(), "\0").as_ptr() as _, line!() as _, ) as *mut c_char; if ptr.is_null() { None } else { ptr::copy_nonoverlapping(data.as_ptr(), ptr as *mut u8, data.len()); *ptr.offset(data.len() as isize) = 0; Some((ptr, ffi::ERR_TXT_MALLOCED)) } } None => None, }; if let Some((ptr, flags)) = data { ffi::ERR_set_error_data(ptr, flags | ffi::ERR_TXT_STRING); } } } /// Returns the raw OpenSSL error code for this error. pub fn code(&self) -> c_ulong { self.code } /// Returns the name of the library reporting the error, if available. pub fn library(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_lib_error_string(self.code); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } } /// Returns the name of the function reporting the error. pub fn function(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_func_error_string(self.code); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } } /// Returns the reason for the error. pub fn reason(&self) -> Option<&'static str> { unsafe { let cstr = ffi::ERR_reason_error_string(self.code); if cstr.is_null() { return None; } let bytes = CStr::from_ptr(cstr as *const _).to_bytes(); Some(str::from_utf8(bytes).unwrap()) } } /// Returns the name of the source file which encountered the error. pub fn file(&self) -> &'static str { unsafe { assert!(!self.file.is_null()); let bytes = CStr::from_ptr(self.file as *const _).to_bytes(); str::from_utf8(bytes).unwrap() } } /// Returns the line in the source file which encountered the error. pub fn line(&self) -> u32 { self.line as u32 } /// Returns additional data describing the error. pub fn data(&self) -> Option<&str> { self.data.as_ref().map(|s| &**s) } } impl fmt::Debug for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut builder = fmt.debug_struct("Error"); builder.field("code", &self.code()); if let Some(library) = self.library() { builder.field("library", &library); } if let Some(function) = self.function() { builder.field("function", &function); } if let Some(reason) = self.reason() { builder.field("reason", &reason); } builder.field("file", &self.file()); builder.field("line", &self.line()); if let Some(data) = self.data() { builder.field("data", &data); } builder.finish() } } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "error:{:08X}", self.code())?; match self.library() { Some(l) => write!(fmt, ":{}", l)?, None => write!(fmt, ":lib({})", ffi::ERR_GET_LIB(self.code()))?, } match self.function() { Some(f) => write!(fmt, ":{}", f)?, None => write!(fmt, ":func({})", ffi::ERR_GET_FUNC(self.code()))?, } match self.reason() { Some(r) => write!(fmt, ":{}", r)?, None => write!(fmt, ":reason({})", ffi::ERR_GET_FUNC(self.code()))?, } write!( fmt, ":{}:{}:{}", self.file(), self.line(), self.data().unwrap_or("") ) } } impl error::Error for Error { fn description(&self) -> &str { "an OpenSSL error" } } openssl-0.10.23/src/ex_data.rs010064400017500001750000000010771346222217000143270ustar0000000000000000use libc::c_int; use std::marker::PhantomData; /// A slot in a type's "extra data" structure. /// /// It is parameterized over the type containing the extra data as well as the /// type of the data in the slot. pub struct Index(c_int, PhantomData<(T, U)>); impl Copy for Index {} impl Clone for Index { fn clone(&self) -> Index { *self } } impl Index { pub unsafe fn from_raw(idx: c_int) -> Index { Index(idx, PhantomData) } pub fn as_raw(&self) -> c_int { self.0 } } openssl-0.10.23/src/fips.rs010064400017500001750000000011661346222217000136620ustar0000000000000000//! FIPS 140-2 support. //! //! See [OpenSSL's documentation] for details. //! //! [OpenSSL's documentation]: https://www.openssl.org/docs/fips/UserGuide-2.0.pdf use cvt; use error::ErrorStack; use ffi; /// Moves the library into or out of the FIPS 140-2 mode of operation. /// /// This corresponds to `FIPS_mode_set`. pub fn enable(enabled: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::FIPS_mode_set(enabled as _)).map(|_| ()) } } /// Determines if the library is running in the FIPS 140-2 mode of operation. /// /// This corresponds to `FIPS_mode`. pub fn enabled() -> bool { unsafe { ffi::FIPS_mode() != 0 } } openssl-0.10.23/src/hash.rs010064400017500001750000000376701346222217000136550ustar0000000000000000use ffi; use std::fmt; use std::io; use std::io::prelude::*; use std::ops::{Deref, DerefMut}; use error::ErrorStack; use nid::Nid; use {cvt, cvt_p}; cfg_if! { if #[cfg(ossl110)] { use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; } else { use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; } } #[derive(Copy, Clone, PartialEq, Eq)] pub struct MessageDigest(*const ffi::EVP_MD); impl MessageDigest { pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self { MessageDigest(x) } /// Returns the `MessageDigest` corresponding to an `Nid`. /// /// This corresponds to [`EVP_get_digestbynid`]. /// /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html pub fn from_nid(type_: Nid) -> Option { unsafe { let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); if ptr.is_null() { None } else { Some(MessageDigest(ptr)) } } } pub fn md5() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_md5()) } } pub fn sha1() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha1()) } } pub fn sha224() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha224()) } } pub fn sha256() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha256()) } } pub fn sha384() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha384()) } } pub fn sha512() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha512()) } } #[cfg(ossl111)] pub fn sha3_224() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha3_224()) } } #[cfg(ossl111)] pub fn sha3_256() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha3_256()) } } #[cfg(ossl111)] pub fn sha3_384() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha3_384()) } } #[cfg(ossl111)] pub fn sha3_512() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha3_512()) } } #[cfg(ossl111)] pub fn shake_128() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_shake128()) } } #[cfg(ossl111)] pub fn shake_256() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_shake256()) } } pub fn ripemd160() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_ripemd160()) } } pub fn as_ptr(&self) -> *const ffi::EVP_MD { self.0 } /// The size of the digest in bytes 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 {} unsafe impl Send for MessageDigest {} #[derive(PartialEq, Copy, Clone)] enum State { Reset, Updated, Finalized, } use self::State::*; /// Provides message digest (hash) computation. /// /// # Examples /// /// Calculate a hash in one go: /// /// ``` /// use openssl::hash::{hash, MessageDigest}; /// /// let data = b"\x42\xF4\x97\xE0"; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; /// let res = hash(MessageDigest::md5(), data).unwrap(); /// assert_eq!(&*res, spec); /// ``` /// /// Supply the input in chunks: /// /// ``` /// use openssl::hash::{Hasher, MessageDigest}; /// /// let data = [b"\x42\xF4", b"\x97\xE0"]; /// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2"; /// let mut h = Hasher::new(MessageDigest::md5()).unwrap(); /// h.update(data[0]).unwrap(); /// h.update(data[1]).unwrap(); /// let res = h.finish().unwrap(); /// assert_eq!(&*res, spec); /// ``` /// /// Use an XOF hasher (OpenSSL 1.1.1+): /// /// ``` /// #[cfg(ossl111)] /// { /// use openssl::hash::{hash_xof, MessageDigest}; /// /// let data = b"\x41\x6c\x6c\x20\x79\x6f\x75\x72\x20\x62\x61\x73\x65\x20\x61\x72\x65\x20\x62\x65\x6c\x6f\x6e\x67\x20\x74\x6f\x20\x75\x73"; /// let spec = b"\x49\xd0\x69\x7f\xf5\x08\x11\x1d\x8b\x84\xf1\x5e\x46\xda\xf1\x35"; /// let mut buf = vec![0; 16]; /// hash_xof(MessageDigest::shake_128(), data, buf.as_mut_slice()).unwrap(); /// assert_eq!(buf, spec); /// } /// ``` /// /// # Warning /// /// Don't actually use MD5 and SHA-1 hashes, they're not secure anymore. /// /// Don't ever hash passwords, use the functions in the `pkcs5` module or bcrypt/scrypt instead. /// /// For extendable output functions (XOFs, i.e. SHAKE128/SHAKE256), you must use finish_xof instead /// of finish and provide a buf to store the hash. The hash will be as long as the buf. pub struct Hasher { ctx: *mut ffi::EVP_MD_CTX, md: *const ffi::EVP_MD, type_: MessageDigest, state: State, } unsafe impl Sync for Hasher {} unsafe impl Send for Hasher {} impl Hasher { /// Creates a new `Hasher` with the specified hash type. pub fn new(ty: MessageDigest) -> Result { ffi::init(); let ctx = unsafe { cvt_p(EVP_MD_CTX_new())? }; let mut h = Hasher { ctx: ctx, md: ty.as_ptr(), type_: ty, state: Finalized, }; h.init()?; Ok(h) } fn init(&mut self) -> Result<(), ErrorStack> { match self.state { Reset => return Ok(()), Updated => { self.finish()?; } Finalized => (), } unsafe { cvt(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *mut _))?; } self.state = Reset; Ok(()) } /// Feeds data into the hasher. pub fn update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { if self.state == Finalized { self.init()?; } unsafe { cvt(ffi::EVP_DigestUpdate( self.ctx, data.as_ptr() as *mut _, data.len(), ))?; } self.state = Updated; Ok(()) } /// Returns the hash of the data written and resets the non-XOF hasher. pub fn finish(&mut self) -> Result { if self.state == Finalized { self.init()?; } unsafe { let mut len = ffi::EVP_MAX_MD_SIZE; let mut buf = [0; ffi::EVP_MAX_MD_SIZE as usize]; cvt(ffi::EVP_DigestFinal_ex( self.ctx, buf.as_mut_ptr(), &mut len, ))?; self.state = Finalized; Ok(DigestBytes { buf: buf, len: len as usize, }) } } /// 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> { if self.state == Finalized { self.init()?; } unsafe { cvt(ffi::EVP_DigestFinalXOF( self.ctx, buf.as_mut_ptr(), buf.len(), ))?; self.state = Finalized; Ok(()) } } } impl Write for Hasher { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.update(buf)?; Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } impl Clone for Hasher { fn clone(&self) -> Hasher { let ctx = unsafe { let ctx = EVP_MD_CTX_new(); assert!(!ctx.is_null()); let r = ffi::EVP_MD_CTX_copy_ex(ctx, self.ctx); assert_eq!(r, 1); ctx }; Hasher { ctx: ctx, md: self.md, type_: self.type_, state: self.state, } } } impl Drop for Hasher { fn drop(&mut self) { unsafe { if self.state != Finalized { drop(self.finish()); } EVP_MD_CTX_free(self.ctx); } } } /// The resulting bytes of a digest. /// /// This type derefs to a byte slice - it exists to avoid allocating memory to /// store the digest data. #[derive(Copy)] pub struct DigestBytes { pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], pub(crate) len: usize, } impl Clone for DigestBytes { #[inline] fn clone(&self) -> DigestBytes { *self } } impl Deref for DigestBytes { type Target = [u8]; #[inline] fn deref(&self) -> &[u8] { &self.buf[..self.len] } } impl DerefMut for DigestBytes { #[inline] fn deref_mut(&mut self) -> &mut [u8] { &mut self.buf[..self.len] } } impl AsRef<[u8]> for DigestBytes { #[inline] fn as_ref(&self) -> &[u8] { self.deref() } } impl fmt::Debug for DigestBytes { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, fmt) } } /// Computes the hash of the `data` with the non-XOF hasher `t`. pub fn hash(t: MessageDigest, data: &[u8]) -> Result { let mut h = Hasher::new(t)?; h.update(data)?; h.finish() } /// 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> { let mut h = Hasher::new(t)?; h.update(data)?; h.finish_xof(buf) } #[cfg(test)] mod tests { use hex::{self, FromHex}; use std::io::prelude::*; use super::*; fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) { let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap(); assert_eq!(hex::encode(res), hashtest.1); } #[cfg(ossl111)] 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(); assert_eq!(buf, expected); } fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) { let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap(); let res = h.finish().unwrap(); assert_eq!(hex::encode(res), hashtest.1); } // Test vectors from http://www.nsrl.nist.gov/testdata/ #[allow(non_upper_case_globals)] const md5_tests: [(&'static str, &'static str); 13] = [ ("", "d41d8cd98f00b204e9800998ecf8427e"), ("7F", "83acb6e67e50e31db6ed341dd2de1595"), ("EC9C", "0b07f0d4ca797d8ac58874f887cb0b68"), ("FEE57A", "e0d583171eb06d56198fc0ef22173907"), ("42F497E0", "7c430f178aefdf1487fee7144e9641e2"), ("C53B777F1C", "75ef141d64cb37ec423da2d9d440c925"), ("89D5B576327B", "ebbaf15eb0ed784c6faa9dc32831bf33"), ("5D4CCE781EB190", "ce175c4b08172019f05e6b5279889f2c"), ("81901FE94932D7B9", "cd4d2f62b8cdb3a0cf968a735a239281"), ("C9FFDEE7788EFB4EC9", "e0841a231ab698db30c6c0f3f246c014"), ("66AC4B7EBA95E53DC10B", "a3b3cea71910d9af56742aa0bb2fe329"), ("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), ( "AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1", ), ]; #[test] fn test_md5() { for test in md5_tests.iter() { hash_test(MessageDigest::md5(), test); } } #[test] fn test_md5_recycle() { let mut h = Hasher::new(MessageDigest::md5()).unwrap(); for test in md5_tests.iter() { hash_recycle_test(&mut h, test); } } #[test] fn test_finish_twice() { let mut h = Hasher::new(MessageDigest::md5()).unwrap(); h.write_all(&Vec::from_hex(md5_tests[6].0).unwrap()) .unwrap(); h.finish().unwrap(); let res = h.finish().unwrap(); let null = hash(MessageDigest::md5(), &[]).unwrap(); assert_eq!(&*res, &*null); } #[test] fn test_clone() { let i = 7; let inp = Vec::from_hex(md5_tests[i].0).unwrap(); assert!(inp.len() > 2); let p = inp.len() / 2; let h0 = Hasher::new(MessageDigest::md5()).unwrap(); println!("Clone a new hasher"); let mut h1 = h0.clone(); h1.write_all(&inp[..p]).unwrap(); { println!("Clone an updated hasher"); let mut h2 = h1.clone(); h2.write_all(&inp[p..]).unwrap(); let res = h2.finish().unwrap(); assert_eq!(hex::encode(res), md5_tests[i].1); } h1.write_all(&inp[p..]).unwrap(); let res = h1.finish().unwrap(); assert_eq!(hex::encode(res), md5_tests[i].1); println!("Clone a finished hasher"); let mut h3 = h1.clone(); h3.write_all(&Vec::from_hex(md5_tests[i + 1].0).unwrap()) .unwrap(); let res = h3.finish().unwrap(); assert_eq!(hex::encode(res), md5_tests[i + 1].1); } #[test] fn test_sha1() { let tests = [("616263", "a9993e364706816aba3e25717850c26c9cd0d89d")]; for test in tests.iter() { hash_test(MessageDigest::sha1(), test); } } #[test] fn test_sha256() { let tests = [( "616263", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", )]; for test in tests.iter() { hash_test(MessageDigest::sha256(), test); } } #[cfg(ossl111)] #[test] fn test_sha3_224() { let tests = [( "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913", )]; for test in tests.iter() { hash_test(MessageDigest::sha3_224(), test); } } #[cfg(ossl111)] #[test] fn test_sha3_256() { let tests = [( "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61", )]; for test in tests.iter() { hash_test(MessageDigest::sha3_256(), test); } } #[cfg(ossl111)] #[test] fn test_sha3_384() { let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\ ef2008ff16" )]; for test in tests.iter() { hash_test(MessageDigest::sha3_384(), test); } } #[cfg(ossl111)] #[test] fn test_sha3_512() { let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\ 807caee3a79f8eb02dcd61589fbbdf5f40c8787a72" )]; for test in tests.iter() { hash_test(MessageDigest::sha3_512(), test); } } #[cfg(ossl111)] #[test] fn test_shake_128() { let tests = [( "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "49d0697ff508111d8b84f15e46daf135", )]; for test in tests.iter() { hash_xof_test(MessageDigest::shake_128(), test); } } #[cfg(ossl111)] #[test] fn test_shake_256() { let tests = [( "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697", )]; for test in tests.iter() { hash_xof_test(MessageDigest::shake_256(), test); } } #[test] fn test_ripemd160() { let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")]; for test in tests.iter() { hash_test(MessageDigest::ripemd160(), test); } } #[test] fn from_nid() { assert_eq!( MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(), MessageDigest::sha256().as_ptr() ); } } openssl-0.10.23/src/lib.rs010064400017500001750000000133501346765633400135070ustar0000000000000000//! 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 //! headers respectively. This can be used if the OpenSSL installation is split in a nonstandard directory layout. //! * `OPENSSL_STATIC` - If set, the crate will statically link to OpenSSL rather than dynamically link. //! * `OPENSSL_LIBS` - If set, a `:`-separated list of library names to link to (e.g. `ssl:crypto`). This can be used //! if nonstandard library names were used for whatever reason. //! //! 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(); //! ``` #![doc(html_root_url = "https://docs.rs/openssl/0.10")] #[macro_use] extern crate bitflags; #[macro_use] extern crate cfg_if; #[macro_use] extern crate foreign_types; #[macro_use] extern crate lazy_static; extern crate libc; extern crate openssl_sys as ffi; #[cfg(test)] extern crate hex; #[cfg(test)] extern crate tempdir; #[doc(inline)] pub use ffi::init; use libc::c_int; use error::ErrorStack; #[macro_use] mod macros; mod bio; #[macro_use] mod util; pub mod aes; pub mod asn1; pub mod bn; #[cfg(not(libressl))] pub mod cms; pub mod conf; pub mod derive; pub mod dh; pub mod dsa; pub mod ec; pub mod ecdsa; pub mod envelope; pub mod error; pub mod ex_data; #[cfg(not(libressl))] pub mod fips; pub mod hash; pub mod memcmp; pub mod nid; pub mod ocsp; pub mod pkcs12; pub mod pkcs5; pub mod pkcs7; pub mod pkey; pub mod rand; pub mod rsa; pub mod sha; pub mod sign; pub mod srtp; pub mod ssl; pub mod stack; pub mod string; pub mod symm; pub mod version; pub mod x509; fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { Err(ErrorStack::get()) } else { Ok(r) } } fn cvt(r: c_int) -> Result { if r <= 0 { Err(ErrorStack::get()) } else { Ok(r) } } fn cvt_n(r: c_int) -> Result { if r < 0 { Err(ErrorStack::get()) } else { Ok(r) } } openssl-0.10.23/src/macros.rs010064400017500001750000000210401346222217000141760ustar0000000000000000macro_rules! private_key_from_pem { ($(#[$m:meta])* $n:ident, $(#[$m2:meta])* $n2:ident, $(#[$m3:meta])* $n3:ident, $t:ty, $f:path) => { from_pem!($(#[$m])* $n, $t, $f); $(#[$m2])* pub fn $n2(pem: &[u8], passphrase: &[u8]) -> Result<$t, ::error::ErrorStack> { unsafe { ffi::init(); let bio = try!(::bio::MemBioSlice::new(pem)); let passphrase = ::std::ffi::CString::new(passphrase).unwrap(); cvt_p($f(bio.as_ptr(), ptr::null_mut(), None, passphrase.as_ptr() as *const _ as *mut _)) .map(|p| ::foreign_types::ForeignType::from_ptr(p)) } } $(#[$m3])* pub fn $n3(pem: &[u8], callback: F) -> Result<$t, ::error::ErrorStack> where F: FnOnce(&mut [u8]) -> Result { unsafe { ffi::init(); let mut cb = ::util::CallbackState::new(callback); let bio = try!(::bio::MemBioSlice::new(pem)); cvt_p($f(bio.as_ptr(), ptr::null_mut(), Some(::util::invoke_passwd_cb::), &mut cb as *mut _ as *mut _)) .map(|p| ::foreign_types::ForeignType::from_ptr(p)) } } } } macro_rules! private_key_to_pem { ($(#[$m:meta])* $n:ident, $(#[$m2:meta])* $n2:ident, $f:path) => { $(#[$m])* pub fn $n(&self) -> Result, ::error::ErrorStack> { unsafe { let bio = try!(::bio::MemBio::new()); try!(cvt($f(bio.as_ptr(), self.as_ptr(), ptr::null(), ptr::null_mut(), -1, None, ptr::null_mut()))); Ok(bio.get_buf().to_owned()) } } $(#[$m2])* pub fn $n2( &self, cipher: ::symm::Cipher, passphrase: &[u8] ) -> Result, ::error::ErrorStack> { unsafe { let bio = try!(::bio::MemBio::new()); assert!(passphrase.len() <= ::libc::c_int::max_value() as usize); try!(cvt($f(bio.as_ptr(), self.as_ptr(), cipher.as_ptr(), passphrase.as_ptr() as *const _ as *mut _, passphrase.len() as ::libc::c_int, None, ptr::null_mut()))); Ok(bio.get_buf().to_owned()) } } } } macro_rules! to_pem { ($(#[$m:meta])* $n:ident, $f:path) => { $(#[$m])* pub fn $n(&self) -> Result, ::error::ErrorStack> { unsafe { let bio = try!(::bio::MemBio::new()); try!(cvt($f(bio.as_ptr(), self.as_ptr()))); Ok(bio.get_buf().to_owned()) } } } } macro_rules! to_der { ($(#[$m:meta])* $n:ident, $f:path) => { $(#[$m])* pub fn $n(&self) -> Result, ::error::ErrorStack> { unsafe { let len = try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), ptr::null_mut()))); let mut buf = vec![0; len as usize]; try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), &mut buf.as_mut_ptr()))); Ok(buf) } } }; } macro_rules! from_der { ($(#[$m:meta])* $n:ident, $t:ty, $f:path) => { $(#[$m])* pub fn $n(der: &[u8]) -> Result<$t, ::error::ErrorStack> { unsafe { ::ffi::init(); let len = ::std::cmp::min(der.len(), ::libc::c_long::max_value() as usize) as ::libc::c_long; ::cvt_p($f(::std::ptr::null_mut(), &mut der.as_ptr(), len)) .map(|p| ::foreign_types::ForeignType::from_ptr(p)) } } } } macro_rules! from_pem { ($(#[$m:meta])* $n:ident, $t:ty, $f:path) => { $(#[$m])* pub fn $n(pem: &[u8]) -> Result<$t, ::error::ErrorStack> { unsafe { ::init(); let bio = try!(::bio::MemBioSlice::new(pem)); cvt_p($f(bio.as_ptr(), ::std::ptr::null_mut(), None, ::std::ptr::null_mut())) .map(|p| ::foreign_types::ForeignType::from_ptr(p)) } } } } macro_rules! foreign_type_and_impl_send_sync { ( $(#[$impl_attr:meta])* type CType = $ctype:ty; fn drop = $drop:expr; $(fn clone = $clone:expr;)* $(#[$owned_attr:meta])* pub struct $owned:ident; $(#[$borrowed_attr:meta])* pub struct $borrowed:ident; ) => { foreign_type! { $(#[$impl_attr])* type CType = $ctype; fn drop = $drop; $(fn clone = $clone;)* $(#[$owned_attr])* pub struct $owned; $(#[$borrowed_attr])* pub struct $borrowed; } unsafe impl Send for $owned{} unsafe impl Send for $borrowed{} unsafe impl Sync for $owned{} unsafe impl Sync for $borrowed{} }; } macro_rules! generic_foreign_type_and_impl_send_sync { ( $(#[$impl_attr:meta])* type CType = $ctype:ty; fn drop = $drop:expr; $(fn clone = $clone:expr;)* $(#[$owned_attr:meta])* pub struct $owned:ident; $(#[$borrowed_attr:meta])* pub struct $borrowed:ident; ) => { $(#[$owned_attr])* pub struct $owned(*mut $ctype, ::std::marker::PhantomData); $(#[$impl_attr])* impl ::foreign_types::ForeignType for $owned { type CType = $ctype; type Ref = $borrowed; #[inline] unsafe fn from_ptr(ptr: *mut $ctype) -> $owned { $owned(ptr, ::std::marker::PhantomData) } #[inline] fn as_ptr(&self) -> *mut $ctype { self.0 } } impl Drop for $owned { #[inline] fn drop(&mut self) { unsafe { $drop(self.0) } } } $( impl Clone for $owned { #[inline] fn clone(&self) -> $owned { unsafe { let handle: *mut $ctype = $clone(self.0); ::foreign_types::ForeignType::from_ptr(handle) } } } impl ::std::borrow::ToOwned for $borrowed { type Owned = $owned; #[inline] fn to_owned(&self) -> $owned { unsafe { let handle: *mut $ctype = $clone(::foreign_types::ForeignTypeRef::as_ptr(self)); $crate::ForeignType::from_ptr(handle) } } } )* impl ::std::ops::Deref for $owned { type Target = $borrowed; #[inline] fn deref(&self) -> &$borrowed { unsafe { ::foreign_types::ForeignTypeRef::from_ptr(self.0) } } } impl ::std::ops::DerefMut for $owned { #[inline] fn deref_mut(&mut self) -> &mut $borrowed { unsafe { ::foreign_types::ForeignTypeRef::from_ptr_mut(self.0) } } } impl ::std::borrow::Borrow<$borrowed> for $owned { #[inline] fn borrow(&self) -> &$borrowed { &**self } } impl ::std::convert::AsRef<$borrowed> for $owned { #[inline] fn as_ref(&self) -> &$borrowed { &**self } } $(#[$borrowed_attr])* pub struct $borrowed(::foreign_types::Opaque, ::std::marker::PhantomData); $(#[$impl_attr])* impl ::foreign_types::ForeignTypeRef for $borrowed { type CType = $ctype; } unsafe impl Send for $owned{} unsafe impl Send for $borrowed{} unsafe impl Sync for $owned{} unsafe impl Sync for $borrowed{} }; } openssl-0.10.23/src/memcmp.rs010064400017500001750000000045351346222217000142020ustar0000000000000000//! Utilities to safely compare cryptographic values. //! //! Extra care must be taken when comparing values in //! cryptographic code. If done incorrectly, it can lead //! to a [timing attack](https://en.wikipedia.org/wiki/Timing_attack). //! By analyzing the time taken to execute parts of a cryptographic //! algorithm, and attacker can attempt to compromise the //! cryptosystem. //! //! The utilities in this module are designed to be resistant //! to this type of attack. //! //! # Examples //! //! To perform a constant-time comparision of two arrays of the same length but different //! values: //! //! ``` //! use openssl::memcmp::eq; //! //! // We want to compare `a` to `b` and `c`, without giving //! // away through timing analysis that `c` is more similar to `a` //! // than `b`. //! let a = [0, 0, 0]; //! let b = [1, 1, 1]; //! let c = [0, 0, 1]; //! //! // These statements will execute in the same amount of time. //! assert!(!eq(&a, &b)); //! assert!(!eq(&a, &c)); //! ``` use ffi; use libc::size_t; /// Returns `true` iff `a` and `b` contain the same bytes. /// /// This operation takes an amount of time dependent on the length of the two /// arrays given, but is independent of the contents of a and b. /// /// # Panics /// /// This function will panic the current task if `a` and `b` do not have the same /// length. /// /// # Examples /// /// To perform a constant-time comparision of two arrays of the same length but different /// values: /// /// ``` /// use openssl::memcmp::eq; /// /// // We want to compare `a` to `b` and `c`, without giving /// // away through timing analysis that `c` is more similar to `a` /// // than `b`. /// let a = [0, 0, 0]; /// let b = [1, 1, 1]; /// let c = [0, 0, 1]; /// /// // These statements will execute in the same amount of time. /// assert!(!eq(&a, &b)); /// assert!(!eq(&a, &c)); /// ``` pub fn eq(a: &[u8], b: &[u8]) -> bool { assert!(a.len() == b.len()); let ret = unsafe { ffi::CRYPTO_memcmp( a.as_ptr() as *const _, b.as_ptr() as *const _, a.len() as size_t, ) }; ret == 0 } #[cfg(test)] mod tests { use super::eq; #[test] fn test_eq() { assert!(eq(&[], &[])); assert!(eq(&[1], &[1])); assert!(!eq(&[1, 2, 3], &[1, 2, 4])); } #[test] #[should_panic] fn test_diff_lens() { eq(&[], &[1]); } } openssl-0.10.23/src/nid.rs010064400017500001750000002077051346222217000135020ustar0000000000000000//! A collection of numerical identifiers for OpenSSL objects. use ffi; use libc::{c_char, c_int}; use std::ffi::CStr; use std::str; use cvt_p; use error::ErrorStack; /// The digest and public-key algorithms associated with a signature. pub struct SignatureAlgorithms { /// The signature's digest. /// /// If the signature does not specify a digest, this will be `NID::UNDEF`. pub digest: Nid, /// The signature's public-key. pub pkey: Nid, } /// A numerical identifier for an OpenSSL object. /// /// Objects in OpenSSL can have a short name, a long name, and /// a numerical identifier (NID). For convenience, objects /// are usually represented in source code using these numeric /// identifiers. /// /// Users should generally not need to create new `Nid`s. /// /// # Examples /// /// To view the integer representation of a `Nid`: /// /// ``` /// use openssl::nid::Nid; /// /// assert!(Nid::AES_256_GCM.as_raw() == 901); /// ``` /// /// # External Documentation /// /// The following documentation provides context about `Nid`s and their usage /// in OpenSSL. /// /// - [Obj_nid2obj](https://www.openssl.org/docs/man1.1.0/crypto/OBJ_create.html) #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Nid(c_int); #[allow(non_snake_case)] impl Nid { /// Create a `Nid` from an integer representation. pub fn from_raw(raw: c_int) -> Nid { Nid(raw) } /// Return the integer representation of a `Nid`. pub fn as_raw(&self) -> c_int { self.0 } /// Returns the `Nid`s of the digest and public key algorithms associated with a signature ID. /// /// This corresponds to `OBJ_find_sigid_algs`. pub fn signature_algorithms(&self) -> Option { unsafe { let mut digest = 0; let mut pkey = 0; if ffi::OBJ_find_sigid_algs(self.0, &mut digest, &mut pkey) == 1 { Some(SignatureAlgorithms { digest: Nid(digest), pkey: Nid(pkey), }) } else { None } } } /// Return the string representation of a `Nid` (long) /// This corresponds to [`OBJ_nid2ln`] /// /// [`OBJ_nid2ln`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2ln.html pub fn long_name(&self) -> Result<&'static str, ErrorStack> { unsafe { cvt_p(ffi::OBJ_nid2ln(self.0) as *mut c_char) .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) } } /// Return the string representation of a `Nid` (short) /// This corresponds to [`OBJ_nid2sn`] /// /// [`OBJ_nid2sn`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2sn.html pub fn short_name(&self) -> Result<&'static str, ErrorStack> { unsafe { cvt_p(ffi::OBJ_nid2sn(self.0) as *mut c_char) .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) } } pub const UNDEF: Nid = Nid(ffi::NID_undef); pub const ITU_T: Nid = Nid(ffi::NID_itu_t); pub const CCITT: Nid = Nid(ffi::NID_ccitt); pub const ISO: Nid = Nid(ffi::NID_iso); pub const JOINT_ISO_ITU_T: Nid = Nid(ffi::NID_joint_iso_itu_t); pub const JOINT_ISO_CCITT: Nid = Nid(ffi::NID_joint_iso_ccitt); pub const MEMBER_BODY: Nid = Nid(ffi::NID_member_body); pub const IDENTIFIED_ORGANIZATION: Nid = Nid(ffi::NID_identified_organization); pub const HMAC_MD5: Nid = Nid(ffi::NID_hmac_md5); pub const HMAC_SHA1: Nid = Nid(ffi::NID_hmac_sha1); pub const CERTICOM_ARC: Nid = Nid(ffi::NID_certicom_arc); pub const INTERNATIONAL_ORGANIZATIONS: Nid = Nid(ffi::NID_international_organizations); pub const WAP: Nid = Nid(ffi::NID_wap); pub const WAP_WSG: Nid = Nid(ffi::NID_wap_wsg); pub const SELECTED_ATTRIBUTE_TYPES: Nid = Nid(ffi::NID_selected_attribute_types); pub const CLEARANCE: Nid = Nid(ffi::NID_clearance); pub const ISO_US: Nid = Nid(ffi::NID_ISO_US); pub const X9_57: Nid = Nid(ffi::NID_X9_57); pub const X9CM: Nid = Nid(ffi::NID_X9cm); pub const DSA: Nid = Nid(ffi::NID_dsa); pub const DSAWITHSHA1: Nid = Nid(ffi::NID_dsaWithSHA1); pub const ANSI_X9_62: Nid = Nid(ffi::NID_ansi_X9_62); pub const X9_62_PRIME_FIELD: Nid = Nid(ffi::NID_X9_62_prime_field); pub const X9_62_CHARACTERISTIC_TWO_FIELD: Nid = Nid(ffi::NID_X9_62_characteristic_two_field); pub const X9_62_ID_CHARACTERISTIC_TWO_BASIS: Nid = Nid(ffi::NID_X9_62_id_characteristic_two_basis); pub const X9_62_ONBASIS: Nid = Nid(ffi::NID_X9_62_onBasis); pub const X9_62_TPBASIS: Nid = Nid(ffi::NID_X9_62_tpBasis); pub const X9_62_PPBASIS: Nid = Nid(ffi::NID_X9_62_ppBasis); pub const X9_62_ID_ECPUBLICKEY: Nid = Nid(ffi::NID_X9_62_id_ecPublicKey); pub const X9_62_C2PNB163V1: Nid = Nid(ffi::NID_X9_62_c2pnb163v1); pub const X9_62_C2PNB163V2: Nid = Nid(ffi::NID_X9_62_c2pnb163v2); pub const X9_62_C2PNB163V3: Nid = Nid(ffi::NID_X9_62_c2pnb163v3); pub const X9_62_C2PNB176V1: Nid = Nid(ffi::NID_X9_62_c2pnb176v1); pub const X9_62_C2TNB191V1: Nid = Nid(ffi::NID_X9_62_c2tnb191v1); pub const X9_62_C2TNB191V2: Nid = Nid(ffi::NID_X9_62_c2tnb191v2); pub const X9_62_C2TNB191V3: Nid = Nid(ffi::NID_X9_62_c2tnb191v3); pub const X9_62_C2ONB191V4: Nid = Nid(ffi::NID_X9_62_c2onb191v4); pub const X9_62_C2ONB191V5: Nid = Nid(ffi::NID_X9_62_c2onb191v5); pub const X9_62_C2PNB208W1: Nid = Nid(ffi::NID_X9_62_c2pnb208w1); pub const X9_62_C2TNB239V1: Nid = Nid(ffi::NID_X9_62_c2tnb239v1); pub const X9_62_C2TNB239V2: Nid = Nid(ffi::NID_X9_62_c2tnb239v2); pub const X9_62_C2TNB239V3: Nid = Nid(ffi::NID_X9_62_c2tnb239v3); pub const X9_62_C2ONB239V4: Nid = Nid(ffi::NID_X9_62_c2onb239v4); pub const X9_62_C2ONB239V5: Nid = Nid(ffi::NID_X9_62_c2onb239v5); pub const X9_62_C2PNB272W1: Nid = Nid(ffi::NID_X9_62_c2pnb272w1); pub const X9_62_C2PNB304W1: Nid = Nid(ffi::NID_X9_62_c2pnb304w1); pub const X9_62_C2TNB359V1: Nid = Nid(ffi::NID_X9_62_c2tnb359v1); pub const X9_62_C2PNB368W1: Nid = Nid(ffi::NID_X9_62_c2pnb368w1); pub const X9_62_C2TNB431R1: Nid = Nid(ffi::NID_X9_62_c2tnb431r1); pub const X9_62_PRIME192V1: Nid = Nid(ffi::NID_X9_62_prime192v1); pub const X9_62_PRIME192V2: Nid = Nid(ffi::NID_X9_62_prime192v2); pub const X9_62_PRIME192V3: Nid = Nid(ffi::NID_X9_62_prime192v3); pub const X9_62_PRIME239V1: Nid = Nid(ffi::NID_X9_62_prime239v1); pub const X9_62_PRIME239V2: Nid = Nid(ffi::NID_X9_62_prime239v2); pub const X9_62_PRIME239V3: Nid = Nid(ffi::NID_X9_62_prime239v3); pub const X9_62_PRIME256V1: Nid = Nid(ffi::NID_X9_62_prime256v1); pub const ECDSA_WITH_SHA1: Nid = Nid(ffi::NID_ecdsa_with_SHA1); pub const ECDSA_WITH_RECOMMENDED: Nid = Nid(ffi::NID_ecdsa_with_Recommended); pub const ECDSA_WITH_SPECIFIED: Nid = Nid(ffi::NID_ecdsa_with_Specified); pub const ECDSA_WITH_SHA224: Nid = Nid(ffi::NID_ecdsa_with_SHA224); pub const ECDSA_WITH_SHA256: Nid = Nid(ffi::NID_ecdsa_with_SHA256); pub const ECDSA_WITH_SHA384: Nid = Nid(ffi::NID_ecdsa_with_SHA384); pub const ECDSA_WITH_SHA512: Nid = Nid(ffi::NID_ecdsa_with_SHA512); pub const SECP112R1: Nid = Nid(ffi::NID_secp112r1); pub const SECP112R2: Nid = Nid(ffi::NID_secp112r2); pub const SECP128R1: Nid = Nid(ffi::NID_secp128r1); pub const SECP128R2: Nid = Nid(ffi::NID_secp128r2); pub const SECP160K1: Nid = Nid(ffi::NID_secp160k1); pub const SECP160R1: Nid = Nid(ffi::NID_secp160r1); pub const SECP160R2: Nid = Nid(ffi::NID_secp160r2); pub const SECP192K1: Nid = Nid(ffi::NID_secp192k1); pub const SECP224K1: Nid = Nid(ffi::NID_secp224k1); pub const SECP224R1: Nid = Nid(ffi::NID_secp224r1); pub const SECP256K1: Nid = Nid(ffi::NID_secp256k1); pub const SECP384R1: Nid = Nid(ffi::NID_secp384r1); pub const SECP521R1: Nid = Nid(ffi::NID_secp521r1); pub const SECT113R1: Nid = Nid(ffi::NID_sect113r1); pub const SECT113R2: Nid = Nid(ffi::NID_sect113r2); pub const SECT131R1: Nid = Nid(ffi::NID_sect131r1); pub const SECT131R2: Nid = Nid(ffi::NID_sect131r2); pub const SECT163K1: Nid = Nid(ffi::NID_sect163k1); pub const SECT163R1: Nid = Nid(ffi::NID_sect163r1); pub const SECT163R2: Nid = Nid(ffi::NID_sect163r2); pub const SECT193R1: Nid = Nid(ffi::NID_sect193r1); pub const SECT193R2: Nid = Nid(ffi::NID_sect193r2); pub const SECT233K1: Nid = Nid(ffi::NID_sect233k1); pub const SECT233R1: Nid = Nid(ffi::NID_sect233r1); pub const SECT239K1: Nid = Nid(ffi::NID_sect239k1); pub const SECT283K1: Nid = Nid(ffi::NID_sect283k1); pub const SECT283R1: Nid = Nid(ffi::NID_sect283r1); pub const SECT409K1: Nid = Nid(ffi::NID_sect409k1); pub const SECT409R1: Nid = Nid(ffi::NID_sect409r1); pub const SECT571K1: Nid = Nid(ffi::NID_sect571k1); pub const SECT571R1: Nid = Nid(ffi::NID_sect571r1); pub const WAP_WSG_IDM_ECID_WTLS1: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls1); pub const WAP_WSG_IDM_ECID_WTLS3: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls3); pub const WAP_WSG_IDM_ECID_WTLS4: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls4); pub const WAP_WSG_IDM_ECID_WTLS5: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls5); pub const WAP_WSG_IDM_ECID_WTLS6: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls6); pub const WAP_WSG_IDM_ECID_WTLS7: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls7); pub const WAP_WSG_IDM_ECID_WTLS8: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls8); pub const WAP_WSG_IDM_ECID_WTLS9: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls9); pub const WAP_WSG_IDM_ECID_WTLS10: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls10); pub const WAP_WSG_IDM_ECID_WTLS11: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls11); pub const WAP_WSG_IDM_ECID_WTLS12: Nid = Nid(ffi::NID_wap_wsg_idm_ecid_wtls12); pub const CAST5_CBC: Nid = Nid(ffi::NID_cast5_cbc); pub const CAST5_ECB: Nid = Nid(ffi::NID_cast5_ecb); pub const CAST5_CFB64: Nid = Nid(ffi::NID_cast5_cfb64); pub const CAST5_OFB64: Nid = Nid(ffi::NID_cast5_ofb64); pub const PBEWITHMD5ANDCAST5_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndCast5_CBC); pub const ID_PASSWORDBASEDMAC: Nid = Nid(ffi::NID_id_PasswordBasedMAC); pub const ID_DHBASEDMAC: Nid = Nid(ffi::NID_id_DHBasedMac); pub const RSADSI: Nid = Nid(ffi::NID_rsadsi); pub const PKCS: Nid = Nid(ffi::NID_pkcs); pub const PKCS1: Nid = Nid(ffi::NID_pkcs1); pub const RSAENCRYPTION: Nid = Nid(ffi::NID_rsaEncryption); pub const MD2WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md2WithRSAEncryption); pub const MD4WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md4WithRSAEncryption); pub const MD5WITHRSAENCRYPTION: Nid = Nid(ffi::NID_md5WithRSAEncryption); pub const SHA1WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha1WithRSAEncryption); pub const RSAESOAEP: Nid = Nid(ffi::NID_rsaesOaep); pub const MGF1: Nid = Nid(ffi::NID_mgf1); pub const RSASSAPSS: Nid = Nid(ffi::NID_rsassaPss); pub const SHA256WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha256WithRSAEncryption); pub const SHA384WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha384WithRSAEncryption); pub const SHA512WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha512WithRSAEncryption); pub const SHA224WITHRSAENCRYPTION: Nid = Nid(ffi::NID_sha224WithRSAEncryption); pub const PKCS3: Nid = Nid(ffi::NID_pkcs3); pub const DHKEYAGREEMENT: Nid = Nid(ffi::NID_dhKeyAgreement); pub const PKCS5: Nid = Nid(ffi::NID_pkcs5); pub const PBEWITHMD2ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndDES_CBC); pub const PBEWITHMD5ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndDES_CBC); pub const PBEWITHMD2ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD2AndRC2_CBC); pub const PBEWITHMD5ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithMD5AndRC2_CBC); pub const PBEWITHSHA1ANDDES_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndDES_CBC); pub const PBEWITHSHA1ANDRC2_CBC: Nid = Nid(ffi::NID_pbeWithSHA1AndRC2_CBC); pub const ID_PBKDF2: Nid = Nid(ffi::NID_id_pbkdf2); pub const PBES2: Nid = Nid(ffi::NID_pbes2); pub const PBMAC1: Nid = Nid(ffi::NID_pbmac1); pub const PKCS7: Nid = Nid(ffi::NID_pkcs7); pub const PKCS7_DATA: Nid = Nid(ffi::NID_pkcs7_data); pub const PKCS7_SIGNED: Nid = Nid(ffi::NID_pkcs7_signed); pub const PKCS7_ENVELOPED: Nid = Nid(ffi::NID_pkcs7_enveloped); pub const PKCS7_SIGNEDANDENVELOPED: Nid = Nid(ffi::NID_pkcs7_signedAndEnveloped); pub const PKCS7_DIGEST: Nid = Nid(ffi::NID_pkcs7_digest); pub const PKCS7_ENCRYPTED: Nid = Nid(ffi::NID_pkcs7_encrypted); pub const PKCS9: Nid = Nid(ffi::NID_pkcs9); pub const PKCS9_EMAILADDRESS: Nid = Nid(ffi::NID_pkcs9_emailAddress); pub const PKCS9_UNSTRUCTUREDNAME: Nid = Nid(ffi::NID_pkcs9_unstructuredName); pub const PKCS9_CONTENTTYPE: Nid = Nid(ffi::NID_pkcs9_contentType); pub const PKCS9_MESSAGEDIGEST: Nid = Nid(ffi::NID_pkcs9_messageDigest); pub const PKCS9_SIGNINGTIME: Nid = Nid(ffi::NID_pkcs9_signingTime); pub const PKCS9_COUNTERSIGNATURE: Nid = Nid(ffi::NID_pkcs9_countersignature); pub const PKCS9_CHALLENGEPASSWORD: Nid = Nid(ffi::NID_pkcs9_challengePassword); pub const PKCS9_UNSTRUCTUREDADDRESS: Nid = Nid(ffi::NID_pkcs9_unstructuredAddress); pub const PKCS9_EXTCERTATTRIBUTES: Nid = Nid(ffi::NID_pkcs9_extCertAttributes); pub const EXT_REQ: Nid = Nid(ffi::NID_ext_req); pub const SMIMECAPABILITIES: Nid = Nid(ffi::NID_SMIMECapabilities); pub const SMIME: Nid = Nid(ffi::NID_SMIME); pub const ID_SMIME_MOD: Nid = Nid(ffi::NID_id_smime_mod); pub const ID_SMIME_CT: Nid = Nid(ffi::NID_id_smime_ct); pub const ID_SMIME_AA: Nid = Nid(ffi::NID_id_smime_aa); pub const ID_SMIME_ALG: Nid = Nid(ffi::NID_id_smime_alg); pub const ID_SMIME_CD: Nid = Nid(ffi::NID_id_smime_cd); pub const ID_SMIME_SPQ: Nid = Nid(ffi::NID_id_smime_spq); pub const ID_SMIME_CTI: Nid = Nid(ffi::NID_id_smime_cti); pub const ID_SMIME_MOD_CMS: Nid = Nid(ffi::NID_id_smime_mod_cms); pub const ID_SMIME_MOD_ESS: Nid = Nid(ffi::NID_id_smime_mod_ess); pub const ID_SMIME_MOD_OID: Nid = Nid(ffi::NID_id_smime_mod_oid); pub const ID_SMIME_MOD_MSG_V3: Nid = Nid(ffi::NID_id_smime_mod_msg_v3); pub const ID_SMIME_MOD_ETS_ESIGNATURE_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_88); pub const ID_SMIME_MOD_ETS_ESIGNATURE_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSignature_97); pub const ID_SMIME_MOD_ETS_ESIGPOLICY_88: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_88); pub const ID_SMIME_MOD_ETS_ESIGPOLICY_97: Nid = Nid(ffi::NID_id_smime_mod_ets_eSigPolicy_97); pub const ID_SMIME_CT_RECEIPT: Nid = Nid(ffi::NID_id_smime_ct_receipt); pub const ID_SMIME_CT_AUTHDATA: Nid = Nid(ffi::NID_id_smime_ct_authData); pub const ID_SMIME_CT_PUBLISHCERT: Nid = Nid(ffi::NID_id_smime_ct_publishCert); pub const ID_SMIME_CT_TSTINFO: Nid = Nid(ffi::NID_id_smime_ct_TSTInfo); pub const ID_SMIME_CT_TDTINFO: Nid = Nid(ffi::NID_id_smime_ct_TDTInfo); pub const ID_SMIME_CT_CONTENTINFO: Nid = Nid(ffi::NID_id_smime_ct_contentInfo); pub const ID_SMIME_CT_DVCSREQUESTDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSRequestData); pub const ID_SMIME_CT_DVCSRESPONSEDATA: Nid = Nid(ffi::NID_id_smime_ct_DVCSResponseData); pub const ID_SMIME_CT_COMPRESSEDDATA: Nid = Nid(ffi::NID_id_smime_ct_compressedData); pub const ID_CT_ASCIITEXTWITHCRLF: Nid = Nid(ffi::NID_id_ct_asciiTextWithCRLF); pub const ID_SMIME_AA_RECEIPTREQUEST: Nid = Nid(ffi::NID_id_smime_aa_receiptRequest); pub const ID_SMIME_AA_SECURITYLABEL: Nid = Nid(ffi::NID_id_smime_aa_securityLabel); pub const ID_SMIME_AA_MLEXPANDHISTORY: Nid = Nid(ffi::NID_id_smime_aa_mlExpandHistory); pub const ID_SMIME_AA_CONTENTHINT: Nid = Nid(ffi::NID_id_smime_aa_contentHint); pub const ID_SMIME_AA_MSGSIGDIGEST: Nid = Nid(ffi::NID_id_smime_aa_msgSigDigest); pub const ID_SMIME_AA_ENCAPCONTENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_encapContentType); pub const ID_SMIME_AA_CONTENTIDENTIFIER: Nid = Nid(ffi::NID_id_smime_aa_contentIdentifier); pub const ID_SMIME_AA_MACVALUE: Nid = Nid(ffi::NID_id_smime_aa_macValue); pub const ID_SMIME_AA_EQUIVALENTLABELS: Nid = Nid(ffi::NID_id_smime_aa_equivalentLabels); pub const ID_SMIME_AA_CONTENTREFERENCE: Nid = Nid(ffi::NID_id_smime_aa_contentReference); pub const ID_SMIME_AA_ENCRYPKEYPREF: Nid = Nid(ffi::NID_id_smime_aa_encrypKeyPref); pub const ID_SMIME_AA_SIGNINGCERTIFICATE: Nid = Nid(ffi::NID_id_smime_aa_signingCertificate); pub const ID_SMIME_AA_SMIMEENCRYPTCERTS: Nid = Nid(ffi::NID_id_smime_aa_smimeEncryptCerts); pub const ID_SMIME_AA_TIMESTAMPTOKEN: Nid = Nid(ffi::NID_id_smime_aa_timeStampToken); pub const ID_SMIME_AA_ETS_SIGPOLICYID: Nid = Nid(ffi::NID_id_smime_aa_ets_sigPolicyId); pub const ID_SMIME_AA_ETS_COMMITMENTTYPE: Nid = Nid(ffi::NID_id_smime_aa_ets_commitmentType); pub const ID_SMIME_AA_ETS_SIGNERLOCATION: Nid = Nid(ffi::NID_id_smime_aa_ets_signerLocation); pub const ID_SMIME_AA_ETS_SIGNERATTR: Nid = Nid(ffi::NID_id_smime_aa_ets_signerAttr); pub const ID_SMIME_AA_ETS_OTHERSIGCERT: Nid = Nid(ffi::NID_id_smime_aa_ets_otherSigCert); pub const ID_SMIME_AA_ETS_CONTENTTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_contentTimestamp); pub const ID_SMIME_AA_ETS_CERTIFICATEREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_CertificateRefs); pub const ID_SMIME_AA_ETS_REVOCATIONREFS: Nid = Nid(ffi::NID_id_smime_aa_ets_RevocationRefs); pub const ID_SMIME_AA_ETS_CERTVALUES: Nid = Nid(ffi::NID_id_smime_aa_ets_certValues); pub const ID_SMIME_AA_ETS_REVOCATIONVALUES: Nid = Nid(ffi::NID_id_smime_aa_ets_revocationValues); pub const ID_SMIME_AA_ETS_ESCTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_escTimeStamp); pub const ID_SMIME_AA_ETS_CERTCRLTIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_certCRLTimestamp); pub const ID_SMIME_AA_ETS_ARCHIVETIMESTAMP: Nid = Nid(ffi::NID_id_smime_aa_ets_archiveTimeStamp); pub const ID_SMIME_AA_SIGNATURETYPE: Nid = Nid(ffi::NID_id_smime_aa_signatureType); pub const ID_SMIME_AA_DVCS_DVC: Nid = Nid(ffi::NID_id_smime_aa_dvcs_dvc); pub const ID_SMIME_ALG_ESDHWITH3DES: Nid = Nid(ffi::NID_id_smime_alg_ESDHwith3DES); pub const ID_SMIME_ALG_ESDHWITHRC2: Nid = Nid(ffi::NID_id_smime_alg_ESDHwithRC2); pub const ID_SMIME_ALG_3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_3DESwrap); pub const ID_SMIME_ALG_RC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_RC2wrap); pub const ID_SMIME_ALG_ESDH: Nid = Nid(ffi::NID_id_smime_alg_ESDH); pub const ID_SMIME_ALG_CMS3DESWRAP: Nid = Nid(ffi::NID_id_smime_alg_CMS3DESwrap); pub const ID_SMIME_ALG_CMSRC2WRAP: Nid = Nid(ffi::NID_id_smime_alg_CMSRC2wrap); pub const ID_ALG_PWRI_KEK: Nid = Nid(ffi::NID_id_alg_PWRI_KEK); pub const ID_SMIME_CD_LDAP: Nid = Nid(ffi::NID_id_smime_cd_ldap); pub const ID_SMIME_SPQ_ETS_SQT_URI: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_uri); pub const ID_SMIME_SPQ_ETS_SQT_UNOTICE: Nid = Nid(ffi::NID_id_smime_spq_ets_sqt_unotice); pub const ID_SMIME_CTI_ETS_PROOFOFORIGIN: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfOrigin); pub const ID_SMIME_CTI_ETS_PROOFOFRECEIPT: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfReceipt); pub const ID_SMIME_CTI_ETS_PROOFOFDELIVERY: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfDelivery); pub const ID_SMIME_CTI_ETS_PROOFOFSENDER: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfSender); pub const ID_SMIME_CTI_ETS_PROOFOFAPPROVAL: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfApproval); pub const ID_SMIME_CTI_ETS_PROOFOFCREATION: Nid = Nid(ffi::NID_id_smime_cti_ets_proofOfCreation); pub const FRIENDLYNAME: Nid = Nid(ffi::NID_friendlyName); pub const LOCALKEYID: Nid = Nid(ffi::NID_localKeyID); pub const MS_CSP_NAME: Nid = Nid(ffi::NID_ms_csp_name); pub const LOCALKEYSET: Nid = Nid(ffi::NID_LocalKeySet); pub const X509CERTIFICATE: Nid = Nid(ffi::NID_x509Certificate); pub const SDSICERTIFICATE: Nid = Nid(ffi::NID_sdsiCertificate); pub const X509CRL: Nid = Nid(ffi::NID_x509Crl); pub const PBE_WITHSHA1AND128BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC4); pub const PBE_WITHSHA1AND40BITRC4: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC4); pub const PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And3_Key_TripleDES_CBC); pub const PBE_WITHSHA1AND2_KEY_TRIPLEDES_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And2_Key_TripleDES_CBC); pub const PBE_WITHSHA1AND128BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And128BitRC2_CBC); pub const PBE_WITHSHA1AND40BITRC2_CBC: Nid = Nid(ffi::NID_pbe_WithSHA1And40BitRC2_CBC); pub const KEYBAG: Nid = Nid(ffi::NID_keyBag); pub const PKCS8SHROUDEDKEYBAG: Nid = Nid(ffi::NID_pkcs8ShroudedKeyBag); pub const CERTBAG: Nid = Nid(ffi::NID_certBag); pub const CRLBAG: Nid = Nid(ffi::NID_crlBag); pub const SECRETBAG: Nid = Nid(ffi::NID_secretBag); pub const SAFECONTENTSBAG: Nid = Nid(ffi::NID_safeContentsBag); pub const MD2: Nid = Nid(ffi::NID_md2); pub const MD4: Nid = Nid(ffi::NID_md4); pub const MD5: Nid = Nid(ffi::NID_md5); pub const MD5_SHA1: Nid = Nid(ffi::NID_md5_sha1); pub const HMACWITHMD5: Nid = Nid(ffi::NID_hmacWithMD5); pub const HMACWITHSHA1: Nid = Nid(ffi::NID_hmacWithSHA1); pub const HMACWITHSHA224: Nid = Nid(ffi::NID_hmacWithSHA224); pub const HMACWITHSHA256: Nid = Nid(ffi::NID_hmacWithSHA256); pub const HMACWITHSHA384: Nid = Nid(ffi::NID_hmacWithSHA384); pub const HMACWITHSHA512: Nid = Nid(ffi::NID_hmacWithSHA512); pub const RC2_CBC: Nid = Nid(ffi::NID_rc2_cbc); pub const RC2_ECB: Nid = Nid(ffi::NID_rc2_ecb); pub const RC2_CFB64: Nid = Nid(ffi::NID_rc2_cfb64); pub const RC2_OFB64: Nid = Nid(ffi::NID_rc2_ofb64); pub const RC2_40_CBC: Nid = Nid(ffi::NID_rc2_40_cbc); pub const RC2_64_CBC: Nid = Nid(ffi::NID_rc2_64_cbc); pub const RC4: Nid = Nid(ffi::NID_rc4); pub const RC4_40: Nid = Nid(ffi::NID_rc4_40); pub const DES_EDE3_CBC: Nid = Nid(ffi::NID_des_ede3_cbc); pub const RC5_CBC: Nid = Nid(ffi::NID_rc5_cbc); pub const RC5_ECB: Nid = Nid(ffi::NID_rc5_ecb); pub const RC5_CFB64: Nid = Nid(ffi::NID_rc5_cfb64); pub const RC5_OFB64: Nid = Nid(ffi::NID_rc5_ofb64); pub const MS_EXT_REQ: Nid = Nid(ffi::NID_ms_ext_req); pub const MS_CODE_IND: Nid = Nid(ffi::NID_ms_code_ind); pub const MS_CODE_COM: Nid = Nid(ffi::NID_ms_code_com); pub const MS_CTL_SIGN: Nid = Nid(ffi::NID_ms_ctl_sign); pub const MS_SGC: Nid = Nid(ffi::NID_ms_sgc); pub const MS_EFS: Nid = Nid(ffi::NID_ms_efs); pub const MS_SMARTCARD_LOGIN: Nid = Nid(ffi::NID_ms_smartcard_login); pub const MS_UPN: Nid = Nid(ffi::NID_ms_upn); pub const IDEA_CBC: Nid = Nid(ffi::NID_idea_cbc); pub const IDEA_ECB: Nid = Nid(ffi::NID_idea_ecb); pub const IDEA_CFB64: Nid = Nid(ffi::NID_idea_cfb64); pub const IDEA_OFB64: Nid = Nid(ffi::NID_idea_ofb64); pub const BF_CBC: Nid = Nid(ffi::NID_bf_cbc); pub const BF_ECB: Nid = Nid(ffi::NID_bf_ecb); pub const BF_CFB64: Nid = Nid(ffi::NID_bf_cfb64); pub const BF_OFB64: Nid = Nid(ffi::NID_bf_ofb64); pub const ID_PKIX: Nid = Nid(ffi::NID_id_pkix); pub const ID_PKIX_MOD: Nid = Nid(ffi::NID_id_pkix_mod); pub const ID_PE: Nid = Nid(ffi::NID_id_pe); pub const ID_QT: Nid = Nid(ffi::NID_id_qt); pub const ID_KP: Nid = Nid(ffi::NID_id_kp); pub const ID_IT: Nid = Nid(ffi::NID_id_it); pub const ID_PKIP: Nid = Nid(ffi::NID_id_pkip); pub const ID_ALG: Nid = Nid(ffi::NID_id_alg); pub const ID_CMC: Nid = Nid(ffi::NID_id_cmc); pub const ID_ON: Nid = Nid(ffi::NID_id_on); pub const ID_PDA: Nid = Nid(ffi::NID_id_pda); pub const ID_ACA: Nid = Nid(ffi::NID_id_aca); pub const ID_QCS: Nid = Nid(ffi::NID_id_qcs); pub const ID_CCT: Nid = Nid(ffi::NID_id_cct); pub const ID_PPL: Nid = Nid(ffi::NID_id_ppl); pub const ID_AD: Nid = Nid(ffi::NID_id_ad); pub const ID_PKIX1_EXPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_explicit_88); pub const ID_PKIX1_IMPLICIT_88: Nid = Nid(ffi::NID_id_pkix1_implicit_88); pub const ID_PKIX1_EXPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_explicit_93); pub const ID_PKIX1_IMPLICIT_93: Nid = Nid(ffi::NID_id_pkix1_implicit_93); pub const ID_MOD_CRMF: Nid = Nid(ffi::NID_id_mod_crmf); pub const ID_MOD_CMC: Nid = Nid(ffi::NID_id_mod_cmc); pub const ID_MOD_KEA_PROFILE_88: Nid = Nid(ffi::NID_id_mod_kea_profile_88); pub const ID_MOD_KEA_PROFILE_93: Nid = Nid(ffi::NID_id_mod_kea_profile_93); pub const ID_MOD_CMP: Nid = Nid(ffi::NID_id_mod_cmp); pub const ID_MOD_QUALIFIED_CERT_88: Nid = Nid(ffi::NID_id_mod_qualified_cert_88); pub const ID_MOD_QUALIFIED_CERT_93: Nid = Nid(ffi::NID_id_mod_qualified_cert_93); pub const ID_MOD_ATTRIBUTE_CERT: Nid = Nid(ffi::NID_id_mod_attribute_cert); pub const ID_MOD_TIMESTAMP_PROTOCOL: Nid = Nid(ffi::NID_id_mod_timestamp_protocol); pub const ID_MOD_OCSP: Nid = Nid(ffi::NID_id_mod_ocsp); pub const ID_MOD_DVCS: Nid = Nid(ffi::NID_id_mod_dvcs); pub const ID_MOD_CMP2000: Nid = Nid(ffi::NID_id_mod_cmp2000); pub const INFO_ACCESS: Nid = Nid(ffi::NID_info_access); pub const BIOMETRICINFO: Nid = Nid(ffi::NID_biometricInfo); pub const QCSTATEMENTS: Nid = Nid(ffi::NID_qcStatements); pub const AC_AUDITENTITY: Nid = Nid(ffi::NID_ac_auditEntity); pub const AC_TARGETING: Nid = Nid(ffi::NID_ac_targeting); pub const AACONTROLS: Nid = Nid(ffi::NID_aaControls); pub const SBGP_IPADDRBLOCK: Nid = Nid(ffi::NID_sbgp_ipAddrBlock); pub const SBGP_AUTONOMOUSSYSNUM: Nid = Nid(ffi::NID_sbgp_autonomousSysNum); pub const SBGP_ROUTERIDENTIFIER: Nid = Nid(ffi::NID_sbgp_routerIdentifier); pub const AC_PROXYING: Nid = Nid(ffi::NID_ac_proxying); pub const SINFO_ACCESS: Nid = Nid(ffi::NID_sinfo_access); pub const PROXYCERTINFO: Nid = Nid(ffi::NID_proxyCertInfo); pub const ID_QT_CPS: Nid = Nid(ffi::NID_id_qt_cps); pub const ID_QT_UNOTICE: Nid = Nid(ffi::NID_id_qt_unotice); pub const TEXTNOTICE: Nid = Nid(ffi::NID_textNotice); pub const SERVER_AUTH: Nid = Nid(ffi::NID_server_auth); pub const CLIENT_AUTH: Nid = Nid(ffi::NID_client_auth); pub const CODE_SIGN: Nid = Nid(ffi::NID_code_sign); pub const EMAIL_PROTECT: Nid = Nid(ffi::NID_email_protect); pub const IPSECENDSYSTEM: Nid = Nid(ffi::NID_ipsecEndSystem); pub const IPSECTUNNEL: Nid = Nid(ffi::NID_ipsecTunnel); pub const IPSECUSER: Nid = Nid(ffi::NID_ipsecUser); pub const TIME_STAMP: Nid = Nid(ffi::NID_time_stamp); pub const OCSP_SIGN: Nid = Nid(ffi::NID_OCSP_sign); pub const DVCS: Nid = Nid(ffi::NID_dvcs); pub const ID_IT_CAPROTENCCERT: Nid = Nid(ffi::NID_id_it_caProtEncCert); pub const ID_IT_SIGNKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_signKeyPairTypes); pub const ID_IT_ENCKEYPAIRTYPES: Nid = Nid(ffi::NID_id_it_encKeyPairTypes); pub const ID_IT_PREFERREDSYMMALG: Nid = Nid(ffi::NID_id_it_preferredSymmAlg); pub const ID_IT_CAKEYUPDATEINFO: Nid = Nid(ffi::NID_id_it_caKeyUpdateInfo); pub const ID_IT_CURRENTCRL: Nid = Nid(ffi::NID_id_it_currentCRL); pub const ID_IT_UNSUPPORTEDOIDS: Nid = Nid(ffi::NID_id_it_unsupportedOIDs); pub const ID_IT_SUBSCRIPTIONREQUEST: Nid = Nid(ffi::NID_id_it_subscriptionRequest); pub const ID_IT_SUBSCRIPTIONRESPONSE: Nid = Nid(ffi::NID_id_it_subscriptionResponse); pub const ID_IT_KEYPAIRPARAMREQ: Nid = Nid(ffi::NID_id_it_keyPairParamReq); pub const ID_IT_KEYPAIRPARAMREP: Nid = Nid(ffi::NID_id_it_keyPairParamRep); pub const ID_IT_REVPASSPHRASE: Nid = Nid(ffi::NID_id_it_revPassphrase); pub const ID_IT_IMPLICITCONFIRM: Nid = Nid(ffi::NID_id_it_implicitConfirm); pub const ID_IT_CONFIRMWAITTIME: Nid = Nid(ffi::NID_id_it_confirmWaitTime); pub const ID_IT_ORIGPKIMESSAGE: Nid = Nid(ffi::NID_id_it_origPKIMessage); pub const ID_IT_SUPPLANGTAGS: Nid = Nid(ffi::NID_id_it_suppLangTags); pub const ID_REGCTRL: Nid = Nid(ffi::NID_id_regCtrl); pub const ID_REGINFO: Nid = Nid(ffi::NID_id_regInfo); pub const ID_REGCTRL_REGTOKEN: Nid = Nid(ffi::NID_id_regCtrl_regToken); pub const ID_REGCTRL_AUTHENTICATOR: Nid = Nid(ffi::NID_id_regCtrl_authenticator); pub const ID_REGCTRL_PKIPUBLICATIONINFO: Nid = Nid(ffi::NID_id_regCtrl_pkiPublicationInfo); pub const ID_REGCTRL_PKIARCHIVEOPTIONS: Nid = Nid(ffi::NID_id_regCtrl_pkiArchiveOptions); pub const ID_REGCTRL_OLDCERTID: Nid = Nid(ffi::NID_id_regCtrl_oldCertID); pub const ID_REGCTRL_PROTOCOLENCRKEY: Nid = Nid(ffi::NID_id_regCtrl_protocolEncrKey); pub const ID_REGINFO_UTF8PAIRS: Nid = Nid(ffi::NID_id_regInfo_utf8Pairs); pub const ID_REGINFO_CERTREQ: Nid = Nid(ffi::NID_id_regInfo_certReq); pub const ID_ALG_DES40: Nid = Nid(ffi::NID_id_alg_des40); pub const ID_ALG_NOSIGNATURE: Nid = Nid(ffi::NID_id_alg_noSignature); pub const ID_ALG_DH_SIG_HMAC_SHA1: Nid = Nid(ffi::NID_id_alg_dh_sig_hmac_sha1); pub const ID_ALG_DH_POP: Nid = Nid(ffi::NID_id_alg_dh_pop); pub const ID_CMC_STATUSINFO: Nid = Nid(ffi::NID_id_cmc_statusInfo); pub const ID_CMC_IDENTIFICATION: Nid = Nid(ffi::NID_id_cmc_identification); pub const ID_CMC_IDENTITYPROOF: Nid = Nid(ffi::NID_id_cmc_identityProof); pub const ID_CMC_DATARETURN: Nid = Nid(ffi::NID_id_cmc_dataReturn); pub const ID_CMC_TRANSACTIONID: Nid = Nid(ffi::NID_id_cmc_transactionId); pub const ID_CMC_SENDERNONCE: Nid = Nid(ffi::NID_id_cmc_senderNonce); pub const ID_CMC_RECIPIENTNONCE: Nid = Nid(ffi::NID_id_cmc_recipientNonce); pub const ID_CMC_ADDEXTENSIONS: Nid = Nid(ffi::NID_id_cmc_addExtensions); pub const ID_CMC_ENCRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_encryptedPOP); pub const ID_CMC_DECRYPTEDPOP: Nid = Nid(ffi::NID_id_cmc_decryptedPOP); pub const ID_CMC_LRAPOPWITNESS: Nid = Nid(ffi::NID_id_cmc_lraPOPWitness); pub const ID_CMC_GETCERT: Nid = Nid(ffi::NID_id_cmc_getCert); pub const ID_CMC_GETCRL: Nid = Nid(ffi::NID_id_cmc_getCRL); pub const ID_CMC_REVOKEREQUEST: Nid = Nid(ffi::NID_id_cmc_revokeRequest); pub const ID_CMC_REGINFO: Nid = Nid(ffi::NID_id_cmc_regInfo); pub const ID_CMC_RESPONSEINFO: Nid = Nid(ffi::NID_id_cmc_responseInfo); pub const ID_CMC_QUERYPENDING: Nid = Nid(ffi::NID_id_cmc_queryPending); pub const ID_CMC_POPLINKRANDOM: Nid = Nid(ffi::NID_id_cmc_popLinkRandom); pub const ID_CMC_POPLINKWITNESS: Nid = Nid(ffi::NID_id_cmc_popLinkWitness); pub const ID_CMC_CONFIRMCERTACCEPTANCE: Nid = Nid(ffi::NID_id_cmc_confirmCertAcceptance); pub const ID_ON_PERSONALDATA: Nid = Nid(ffi::NID_id_on_personalData); pub const ID_ON_PERMANENTIDENTIFIER: Nid = Nid(ffi::NID_id_on_permanentIdentifier); pub const ID_PDA_DATEOFBIRTH: Nid = Nid(ffi::NID_id_pda_dateOfBirth); pub const ID_PDA_PLACEOFBIRTH: Nid = Nid(ffi::NID_id_pda_placeOfBirth); pub const ID_PDA_GENDER: Nid = Nid(ffi::NID_id_pda_gender); pub const ID_PDA_COUNTRYOFCITIZENSHIP: Nid = Nid(ffi::NID_id_pda_countryOfCitizenship); pub const ID_PDA_COUNTRYOFRESIDENCE: Nid = Nid(ffi::NID_id_pda_countryOfResidence); pub const ID_ACA_AUTHENTICATIONINFO: Nid = Nid(ffi::NID_id_aca_authenticationInfo); pub const ID_ACA_ACCESSIDENTITY: Nid = Nid(ffi::NID_id_aca_accessIdentity); pub const ID_ACA_CHARGINGIDENTITY: Nid = Nid(ffi::NID_id_aca_chargingIdentity); pub const ID_ACA_GROUP: Nid = Nid(ffi::NID_id_aca_group); pub const ID_ACA_ROLE: Nid = Nid(ffi::NID_id_aca_role); pub const ID_ACA_ENCATTRS: Nid = Nid(ffi::NID_id_aca_encAttrs); pub const ID_QCS_PKIXQCSYNTAX_V1: Nid = Nid(ffi::NID_id_qcs_pkixQCSyntax_v1); pub const ID_CCT_CRS: Nid = Nid(ffi::NID_id_cct_crs); pub const ID_CCT_PKIDATA: Nid = Nid(ffi::NID_id_cct_PKIData); pub const ID_CCT_PKIRESPONSE: Nid = Nid(ffi::NID_id_cct_PKIResponse); pub const ID_PPL_ANYLANGUAGE: Nid = Nid(ffi::NID_id_ppl_anyLanguage); pub const ID_PPL_INHERITALL: Nid = Nid(ffi::NID_id_ppl_inheritAll); pub const INDEPENDENT: Nid = Nid(ffi::NID_Independent); pub const AD_OCSP: Nid = Nid(ffi::NID_ad_OCSP); pub const AD_CA_ISSUERS: Nid = Nid(ffi::NID_ad_ca_issuers); pub const AD_TIMESTAMPING: Nid = Nid(ffi::NID_ad_timeStamping); pub const AD_DVCS: Nid = Nid(ffi::NID_ad_dvcs); pub const CAREPOSITORY: Nid = Nid(ffi::NID_caRepository); pub const ID_PKIX_OCSP_BASIC: Nid = Nid(ffi::NID_id_pkix_OCSP_basic); pub const ID_PKIX_OCSP_NONCE: Nid = Nid(ffi::NID_id_pkix_OCSP_Nonce); pub const ID_PKIX_OCSP_CRLID: Nid = Nid(ffi::NID_id_pkix_OCSP_CrlID); pub const ID_PKIX_OCSP_ACCEPTABLERESPONSES: Nid = Nid(ffi::NID_id_pkix_OCSP_acceptableResponses); pub const ID_PKIX_OCSP_NOCHECK: Nid = Nid(ffi::NID_id_pkix_OCSP_noCheck); pub const ID_PKIX_OCSP_ARCHIVECUTOFF: Nid = Nid(ffi::NID_id_pkix_OCSP_archiveCutoff); pub const ID_PKIX_OCSP_SERVICELOCATOR: Nid = Nid(ffi::NID_id_pkix_OCSP_serviceLocator); pub const ID_PKIX_OCSP_EXTENDEDSTATUS: Nid = Nid(ffi::NID_id_pkix_OCSP_extendedStatus); pub const ID_PKIX_OCSP_VALID: Nid = Nid(ffi::NID_id_pkix_OCSP_valid); pub const ID_PKIX_OCSP_PATH: Nid = Nid(ffi::NID_id_pkix_OCSP_path); pub const ID_PKIX_OCSP_TRUSTROOT: Nid = Nid(ffi::NID_id_pkix_OCSP_trustRoot); pub const ALGORITHM: Nid = Nid(ffi::NID_algorithm); pub const MD5WITHRSA: Nid = Nid(ffi::NID_md5WithRSA); pub const DES_ECB: Nid = Nid(ffi::NID_des_ecb); pub const DES_CBC: Nid = Nid(ffi::NID_des_cbc); pub const DES_OFB64: Nid = Nid(ffi::NID_des_ofb64); pub const DES_CFB64: Nid = Nid(ffi::NID_des_cfb64); pub const RSASIGNATURE: Nid = Nid(ffi::NID_rsaSignature); pub const DSA_2: Nid = Nid(ffi::NID_dsa_2); pub const DSAWITHSHA: Nid = Nid(ffi::NID_dsaWithSHA); pub const SHAWITHRSAENCRYPTION: Nid = Nid(ffi::NID_shaWithRSAEncryption); pub const DES_EDE_ECB: Nid = Nid(ffi::NID_des_ede_ecb); pub const DES_EDE3_ECB: Nid = Nid(ffi::NID_des_ede3_ecb); pub const DES_EDE_CBC: Nid = Nid(ffi::NID_des_ede_cbc); pub const DES_EDE_CFB64: Nid = Nid(ffi::NID_des_ede_cfb64); pub const DES_EDE3_CFB64: Nid = Nid(ffi::NID_des_ede3_cfb64); pub const DES_EDE_OFB64: Nid = Nid(ffi::NID_des_ede_ofb64); pub const DES_EDE3_OFB64: Nid = Nid(ffi::NID_des_ede3_ofb64); pub const DESX_CBC: Nid = Nid(ffi::NID_desx_cbc); pub const SHA: Nid = Nid(ffi::NID_sha); pub const SHA1: Nid = Nid(ffi::NID_sha1); pub const DSAWITHSHA1_2: Nid = Nid(ffi::NID_dsaWithSHA1_2); pub const SHA1WITHRSA: Nid = Nid(ffi::NID_sha1WithRSA); pub const RIPEMD160: Nid = Nid(ffi::NID_ripemd160); pub const RIPEMD160WITHRSA: Nid = Nid(ffi::NID_ripemd160WithRSA); pub const SXNET: Nid = Nid(ffi::NID_sxnet); pub const X500: Nid = Nid(ffi::NID_X500); pub const X509: Nid = Nid(ffi::NID_X509); pub const COMMONNAME: Nid = Nid(ffi::NID_commonName); pub const SURNAME: Nid = Nid(ffi::NID_surname); pub const SERIALNUMBER: Nid = Nid(ffi::NID_serialNumber); pub const COUNTRYNAME: Nid = Nid(ffi::NID_countryName); pub const LOCALITYNAME: Nid = Nid(ffi::NID_localityName); pub const STATEORPROVINCENAME: Nid = Nid(ffi::NID_stateOrProvinceName); pub const STREETADDRESS: Nid = Nid(ffi::NID_streetAddress); pub const ORGANIZATIONNAME: Nid = Nid(ffi::NID_organizationName); pub const ORGANIZATIONALUNITNAME: Nid = Nid(ffi::NID_organizationalUnitName); pub const TITLE: Nid = Nid(ffi::NID_title); pub const DESCRIPTION: Nid = Nid(ffi::NID_description); pub const SEARCHGUIDE: Nid = Nid(ffi::NID_searchGuide); pub const BUSINESSCATEGORY: Nid = Nid(ffi::NID_businessCategory); pub const POSTALADDRESS: Nid = Nid(ffi::NID_postalAddress); pub const POSTALCODE: Nid = Nid(ffi::NID_postalCode); pub const POSTOFFICEBOX: Nid = Nid(ffi::NID_postOfficeBox); pub const PHYSICALDELIVERYOFFICENAME: Nid = Nid(ffi::NID_physicalDeliveryOfficeName); pub const TELEPHONENUMBER: Nid = Nid(ffi::NID_telephoneNumber); pub const TELEXNUMBER: Nid = Nid(ffi::NID_telexNumber); pub const TELETEXTERMINALIDENTIFIER: Nid = Nid(ffi::NID_teletexTerminalIdentifier); pub const FACSIMILETELEPHONENUMBER: Nid = Nid(ffi::NID_facsimileTelephoneNumber); pub const X121ADDRESS: Nid = Nid(ffi::NID_x121Address); pub const INTERNATIONALISDNNUMBER: Nid = Nid(ffi::NID_internationaliSDNNumber); pub const REGISTEREDADDRESS: Nid = Nid(ffi::NID_registeredAddress); pub const DESTINATIONINDICATOR: Nid = Nid(ffi::NID_destinationIndicator); pub const PREFERREDDELIVERYMETHOD: Nid = Nid(ffi::NID_preferredDeliveryMethod); pub const PRESENTATIONADDRESS: Nid = Nid(ffi::NID_presentationAddress); pub const SUPPORTEDAPPLICATIONCONTEXT: Nid = Nid(ffi::NID_supportedApplicationContext); pub const MEMBER: Nid = Nid(ffi::NID_member); pub const OWNER: Nid = Nid(ffi::NID_owner); pub const ROLEOCCUPANT: Nid = Nid(ffi::NID_roleOccupant); pub const SEEALSO: Nid = Nid(ffi::NID_seeAlso); pub const USERPASSWORD: Nid = Nid(ffi::NID_userPassword); pub const USERCERTIFICATE: Nid = Nid(ffi::NID_userCertificate); pub const CACERTIFICATE: Nid = Nid(ffi::NID_cACertificate); pub const AUTHORITYREVOCATIONLIST: Nid = Nid(ffi::NID_authorityRevocationList); pub const CERTIFICATEREVOCATIONLIST: Nid = Nid(ffi::NID_certificateRevocationList); pub const CROSSCERTIFICATEPAIR: Nid = Nid(ffi::NID_crossCertificatePair); pub const NAME: Nid = Nid(ffi::NID_name); pub const GIVENNAME: Nid = Nid(ffi::NID_givenName); pub const INITIALS: Nid = Nid(ffi::NID_initials); pub const GENERATIONQUALIFIER: Nid = Nid(ffi::NID_generationQualifier); pub const X500UNIQUEIDENTIFIER: Nid = Nid(ffi::NID_x500UniqueIdentifier); pub const DNQUALIFIER: Nid = Nid(ffi::NID_dnQualifier); pub const ENHANCEDSEARCHGUIDE: Nid = Nid(ffi::NID_enhancedSearchGuide); pub const PROTOCOLINFORMATION: Nid = Nid(ffi::NID_protocolInformation); pub const DISTINGUISHEDNAME: Nid = Nid(ffi::NID_distinguishedName); pub const UNIQUEMEMBER: Nid = Nid(ffi::NID_uniqueMember); pub const HOUSEIDENTIFIER: Nid = Nid(ffi::NID_houseIdentifier); pub const SUPPORTEDALGORITHMS: Nid = Nid(ffi::NID_supportedAlgorithms); pub const DELTAREVOCATIONLIST: Nid = Nid(ffi::NID_deltaRevocationList); pub const DMDNAME: Nid = Nid(ffi::NID_dmdName); pub const PSEUDONYM: Nid = Nid(ffi::NID_pseudonym); pub const ROLE: Nid = Nid(ffi::NID_role); pub const X500ALGORITHMS: Nid = Nid(ffi::NID_X500algorithms); pub const RSA: Nid = Nid(ffi::NID_rsa); pub const MDC2WITHRSA: Nid = Nid(ffi::NID_mdc2WithRSA); pub const MDC2: Nid = Nid(ffi::NID_mdc2); pub const ID_CE: Nid = Nid(ffi::NID_id_ce); pub const SUBJECT_DIRECTORY_ATTRIBUTES: Nid = Nid(ffi::NID_subject_directory_attributes); pub const SUBJECT_KEY_IDENTIFIER: Nid = Nid(ffi::NID_subject_key_identifier); pub const KEY_USAGE: Nid = Nid(ffi::NID_key_usage); pub const PRIVATE_KEY_USAGE_PERIOD: Nid = Nid(ffi::NID_private_key_usage_period); pub const SUBJECT_ALT_NAME: Nid = Nid(ffi::NID_subject_alt_name); pub const ISSUER_ALT_NAME: Nid = Nid(ffi::NID_issuer_alt_name); pub const BASIC_CONSTRAINTS: Nid = Nid(ffi::NID_basic_constraints); pub const CRL_NUMBER: Nid = Nid(ffi::NID_crl_number); pub const CRL_REASON: Nid = Nid(ffi::NID_crl_reason); pub const INVALIDITY_DATE: Nid = Nid(ffi::NID_invalidity_date); pub const DELTA_CRL: Nid = Nid(ffi::NID_delta_crl); pub const ISSUING_DISTRIBUTION_POINT: Nid = Nid(ffi::NID_issuing_distribution_point); pub const CERTIFICATE_ISSUER: Nid = Nid(ffi::NID_certificate_issuer); pub const NAME_CONSTRAINTS: Nid = Nid(ffi::NID_name_constraints); pub const CRL_DISTRIBUTION_POINTS: Nid = Nid(ffi::NID_crl_distribution_points); pub const CERTIFICATE_POLICIES: Nid = Nid(ffi::NID_certificate_policies); pub const ANY_POLICY: Nid = Nid(ffi::NID_any_policy); pub const POLICY_MAPPINGS: Nid = Nid(ffi::NID_policy_mappings); pub const AUTHORITY_KEY_IDENTIFIER: Nid = Nid(ffi::NID_authority_key_identifier); pub const POLICY_CONSTRAINTS: Nid = Nid(ffi::NID_policy_constraints); pub const EXT_KEY_USAGE: Nid = Nid(ffi::NID_ext_key_usage); pub const FRESHEST_CRL: Nid = Nid(ffi::NID_freshest_crl); pub const INHIBIT_ANY_POLICY: Nid = Nid(ffi::NID_inhibit_any_policy); pub const TARGET_INFORMATION: Nid = Nid(ffi::NID_target_information); pub const NO_REV_AVAIL: Nid = Nid(ffi::NID_no_rev_avail); pub const ANYEXTENDEDKEYUSAGE: Nid = Nid(ffi::NID_anyExtendedKeyUsage); pub const NETSCAPE: Nid = Nid(ffi::NID_netscape); pub const NETSCAPE_CERT_EXTENSION: Nid = Nid(ffi::NID_netscape_cert_extension); pub const NETSCAPE_DATA_TYPE: Nid = Nid(ffi::NID_netscape_data_type); pub const NETSCAPE_CERT_TYPE: Nid = Nid(ffi::NID_netscape_cert_type); pub const NETSCAPE_BASE_URL: Nid = Nid(ffi::NID_netscape_base_url); pub const NETSCAPE_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_revocation_url); pub const NETSCAPE_CA_REVOCATION_URL: Nid = Nid(ffi::NID_netscape_ca_revocation_url); pub const NETSCAPE_RENEWAL_URL: Nid = Nid(ffi::NID_netscape_renewal_url); pub const NETSCAPE_CA_POLICY_URL: Nid = Nid(ffi::NID_netscape_ca_policy_url); pub const NETSCAPE_SSL_SERVER_NAME: Nid = Nid(ffi::NID_netscape_ssl_server_name); pub const NETSCAPE_COMMENT: Nid = Nid(ffi::NID_netscape_comment); pub const NETSCAPE_CERT_SEQUENCE: Nid = Nid(ffi::NID_netscape_cert_sequence); pub const NS_SGC: Nid = Nid(ffi::NID_ns_sgc); pub const ORG: Nid = Nid(ffi::NID_org); pub const DOD: Nid = Nid(ffi::NID_dod); pub const IANA: Nid = Nid(ffi::NID_iana); pub const DIRECTORY: Nid = Nid(ffi::NID_Directory); pub const MANAGEMENT: Nid = Nid(ffi::NID_Management); pub const EXPERIMENTAL: Nid = Nid(ffi::NID_Experimental); pub const PRIVATE: Nid = Nid(ffi::NID_Private); pub const SECURITY: Nid = Nid(ffi::NID_Security); pub const SNMPV2: Nid = Nid(ffi::NID_SNMPv2); pub const MAIL: Nid = Nid(ffi::NID_Mail); pub const ENTERPRISES: Nid = Nid(ffi::NID_Enterprises); pub const DCOBJECT: Nid = Nid(ffi::NID_dcObject); pub const MIME_MHS: Nid = Nid(ffi::NID_mime_mhs); pub const MIME_MHS_HEADINGS: Nid = Nid(ffi::NID_mime_mhs_headings); pub const MIME_MHS_BODIES: Nid = Nid(ffi::NID_mime_mhs_bodies); pub const ID_HEX_PARTIAL_MESSAGE: Nid = Nid(ffi::NID_id_hex_partial_message); pub const ID_HEX_MULTIPART_MESSAGE: Nid = Nid(ffi::NID_id_hex_multipart_message); pub const ZLIB_COMPRESSION: Nid = Nid(ffi::NID_zlib_compression); pub const AES_128_ECB: Nid = Nid(ffi::NID_aes_128_ecb); pub const AES_128_CBC: Nid = Nid(ffi::NID_aes_128_cbc); pub const AES_128_OFB128: Nid = Nid(ffi::NID_aes_128_ofb128); pub const AES_128_CFB128: Nid = Nid(ffi::NID_aes_128_cfb128); pub const ID_AES128_WRAP: Nid = Nid(ffi::NID_id_aes128_wrap); pub const AES_128_GCM: Nid = Nid(ffi::NID_aes_128_gcm); pub const AES_128_CCM: Nid = Nid(ffi::NID_aes_128_ccm); pub const ID_AES128_WRAP_PAD: Nid = Nid(ffi::NID_id_aes128_wrap_pad); pub const AES_192_ECB: Nid = Nid(ffi::NID_aes_192_ecb); pub const AES_192_CBC: Nid = Nid(ffi::NID_aes_192_cbc); pub const AES_192_OFB128: Nid = Nid(ffi::NID_aes_192_ofb128); pub const AES_192_CFB128: Nid = Nid(ffi::NID_aes_192_cfb128); pub const ID_AES192_WRAP: Nid = Nid(ffi::NID_id_aes192_wrap); pub const AES_192_GCM: Nid = Nid(ffi::NID_aes_192_gcm); pub const AES_192_CCM: Nid = Nid(ffi::NID_aes_192_ccm); pub const ID_AES192_WRAP_PAD: Nid = Nid(ffi::NID_id_aes192_wrap_pad); pub const AES_256_ECB: Nid = Nid(ffi::NID_aes_256_ecb); pub const AES_256_CBC: Nid = Nid(ffi::NID_aes_256_cbc); pub const AES_256_OFB128: Nid = Nid(ffi::NID_aes_256_ofb128); pub const AES_256_CFB128: Nid = Nid(ffi::NID_aes_256_cfb128); pub const ID_AES256_WRAP: Nid = Nid(ffi::NID_id_aes256_wrap); pub const AES_256_GCM: Nid = Nid(ffi::NID_aes_256_gcm); pub const AES_256_CCM: Nid = Nid(ffi::NID_aes_256_ccm); pub const ID_AES256_WRAP_PAD: Nid = Nid(ffi::NID_id_aes256_wrap_pad); pub const AES_128_CFB1: Nid = Nid(ffi::NID_aes_128_cfb1); pub const AES_192_CFB1: Nid = Nid(ffi::NID_aes_192_cfb1); pub const AES_256_CFB1: Nid = Nid(ffi::NID_aes_256_cfb1); pub const AES_128_CFB8: Nid = Nid(ffi::NID_aes_128_cfb8); pub const AES_192_CFB8: Nid = Nid(ffi::NID_aes_192_cfb8); pub const AES_256_CFB8: Nid = Nid(ffi::NID_aes_256_cfb8); pub const AES_128_CTR: Nid = Nid(ffi::NID_aes_128_ctr); pub const AES_192_CTR: Nid = Nid(ffi::NID_aes_192_ctr); pub const AES_256_CTR: Nid = Nid(ffi::NID_aes_256_ctr); pub const AES_128_XTS: Nid = Nid(ffi::NID_aes_128_xts); pub const AES_256_XTS: Nid = Nid(ffi::NID_aes_256_xts); pub const DES_CFB1: Nid = Nid(ffi::NID_des_cfb1); pub const DES_CFB8: Nid = Nid(ffi::NID_des_cfb8); pub const DES_EDE3_CFB1: Nid = Nid(ffi::NID_des_ede3_cfb1); pub const DES_EDE3_CFB8: Nid = Nid(ffi::NID_des_ede3_cfb8); pub const SHA256: Nid = Nid(ffi::NID_sha256); pub const SHA384: Nid = Nid(ffi::NID_sha384); pub const SHA512: Nid = Nid(ffi::NID_sha512); pub const SHA224: Nid = Nid(ffi::NID_sha224); pub const DSA_WITH_SHA224: Nid = Nid(ffi::NID_dsa_with_SHA224); pub const DSA_WITH_SHA256: Nid = Nid(ffi::NID_dsa_with_SHA256); pub const HOLD_INSTRUCTION_CODE: Nid = Nid(ffi::NID_hold_instruction_code); pub const HOLD_INSTRUCTION_NONE: Nid = Nid(ffi::NID_hold_instruction_none); pub const HOLD_INSTRUCTION_CALL_ISSUER: Nid = Nid(ffi::NID_hold_instruction_call_issuer); pub const HOLD_INSTRUCTION_REJECT: Nid = Nid(ffi::NID_hold_instruction_reject); pub const DATA: Nid = Nid(ffi::NID_data); pub const PSS: Nid = Nid(ffi::NID_pss); pub const UCL: Nid = Nid(ffi::NID_ucl); pub const PILOT: Nid = Nid(ffi::NID_pilot); pub const PILOTATTRIBUTETYPE: Nid = Nid(ffi::NID_pilotAttributeType); pub const PILOTATTRIBUTESYNTAX: Nid = Nid(ffi::NID_pilotAttributeSyntax); pub const PILOTOBJECTCLASS: Nid = Nid(ffi::NID_pilotObjectClass); pub const PILOTGROUPS: Nid = Nid(ffi::NID_pilotGroups); pub const IA5STRINGSYNTAX: Nid = Nid(ffi::NID_iA5StringSyntax); pub const CASEIGNOREIA5STRINGSYNTAX: Nid = Nid(ffi::NID_caseIgnoreIA5StringSyntax); pub const PILOTOBJECT: Nid = Nid(ffi::NID_pilotObject); pub const PILOTPERSON: Nid = Nid(ffi::NID_pilotPerson); pub const ACCOUNT: Nid = Nid(ffi::NID_account); pub const DOCUMENT: Nid = Nid(ffi::NID_document); pub const ROOM: Nid = Nid(ffi::NID_room); pub const DOCUMENTSERIES: Nid = Nid(ffi::NID_documentSeries); pub const DOMAIN: Nid = Nid(ffi::NID_Domain); pub const RFC822LOCALPART: Nid = Nid(ffi::NID_rFC822localPart); pub const DNSDOMAIN: Nid = Nid(ffi::NID_dNSDomain); pub const DOMAINRELATEDOBJECT: Nid = Nid(ffi::NID_domainRelatedObject); pub const FRIENDLYCOUNTRY: Nid = Nid(ffi::NID_friendlyCountry); pub const SIMPLESECURITYOBJECT: Nid = Nid(ffi::NID_simpleSecurityObject); pub const PILOTORGANIZATION: Nid = Nid(ffi::NID_pilotOrganization); pub const PILOTDSA: Nid = Nid(ffi::NID_pilotDSA); pub const QUALITYLABELLEDDATA: Nid = Nid(ffi::NID_qualityLabelledData); pub const USERID: Nid = Nid(ffi::NID_userId); pub const TEXTENCODEDORADDRESS: Nid = Nid(ffi::NID_textEncodedORAddress); pub const RFC822MAILBOX: Nid = Nid(ffi::NID_rfc822Mailbox); pub const INFO: Nid = Nid(ffi::NID_info); pub const FAVOURITEDRINK: Nid = Nid(ffi::NID_favouriteDrink); pub const ROOMNUMBER: Nid = Nid(ffi::NID_roomNumber); pub const PHOTO: Nid = Nid(ffi::NID_photo); pub const USERCLASS: Nid = Nid(ffi::NID_userClass); pub const HOST: Nid = Nid(ffi::NID_host); pub const MANAGER: Nid = Nid(ffi::NID_manager); pub const DOCUMENTIDENTIFIER: Nid = Nid(ffi::NID_documentIdentifier); pub const DOCUMENTTITLE: Nid = Nid(ffi::NID_documentTitle); pub const DOCUMENTVERSION: Nid = Nid(ffi::NID_documentVersion); pub const DOCUMENTAUTHOR: Nid = Nid(ffi::NID_documentAuthor); pub const DOCUMENTLOCATION: Nid = Nid(ffi::NID_documentLocation); pub const HOMETELEPHONENUMBER: Nid = Nid(ffi::NID_homeTelephoneNumber); pub const SECRETARY: Nid = Nid(ffi::NID_secretary); pub const OTHERMAILBOX: Nid = Nid(ffi::NID_otherMailbox); pub const LASTMODIFIEDTIME: Nid = Nid(ffi::NID_lastModifiedTime); pub const LASTMODIFIEDBY: Nid = Nid(ffi::NID_lastModifiedBy); pub const DOMAINCOMPONENT: Nid = Nid(ffi::NID_domainComponent); pub const ARECORD: Nid = Nid(ffi::NID_aRecord); pub const PILOTATTRIBUTETYPE27: Nid = Nid(ffi::NID_pilotAttributeType27); pub const MXRECORD: Nid = Nid(ffi::NID_mXRecord); pub const NSRECORD: Nid = Nid(ffi::NID_nSRecord); pub const SOARECORD: Nid = Nid(ffi::NID_sOARecord); pub const CNAMERECORD: Nid = Nid(ffi::NID_cNAMERecord); pub const ASSOCIATEDDOMAIN: Nid = Nid(ffi::NID_associatedDomain); pub const ASSOCIATEDNAME: Nid = Nid(ffi::NID_associatedName); pub const HOMEPOSTALADDRESS: Nid = Nid(ffi::NID_homePostalAddress); pub const PERSONALTITLE: Nid = Nid(ffi::NID_personalTitle); pub const MOBILETELEPHONENUMBER: Nid = Nid(ffi::NID_mobileTelephoneNumber); pub const PAGERTELEPHONENUMBER: Nid = Nid(ffi::NID_pagerTelephoneNumber); pub const FRIENDLYCOUNTRYNAME: Nid = Nid(ffi::NID_friendlyCountryName); pub const ORGANIZATIONALSTATUS: Nid = Nid(ffi::NID_organizationalStatus); pub const JANETMAILBOX: Nid = Nid(ffi::NID_janetMailbox); pub const MAILPREFERENCEOPTION: Nid = Nid(ffi::NID_mailPreferenceOption); pub const BUILDINGNAME: Nid = Nid(ffi::NID_buildingName); pub const DSAQUALITY: Nid = Nid(ffi::NID_dSAQuality); pub const SINGLELEVELQUALITY: Nid = Nid(ffi::NID_singleLevelQuality); pub const SUBTREEMINIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMinimumQuality); pub const SUBTREEMAXIMUMQUALITY: Nid = Nid(ffi::NID_subtreeMaximumQuality); pub const PERSONALSIGNATURE: Nid = Nid(ffi::NID_personalSignature); pub const DITREDIRECT: Nid = Nid(ffi::NID_dITRedirect); pub const AUDIO: Nid = Nid(ffi::NID_audio); pub const DOCUMENTPUBLISHER: Nid = Nid(ffi::NID_documentPublisher); pub const ID_SET: Nid = Nid(ffi::NID_id_set); pub const SET_CTYPE: Nid = Nid(ffi::NID_set_ctype); pub const SET_MSGEXT: Nid = Nid(ffi::NID_set_msgExt); pub const SET_ATTR: Nid = Nid(ffi::NID_set_attr); pub const SET_POLICY: Nid = Nid(ffi::NID_set_policy); pub const SET_CERTEXT: Nid = Nid(ffi::NID_set_certExt); pub const SET_BRAND: Nid = Nid(ffi::NID_set_brand); pub const SETCT_PANDATA: Nid = Nid(ffi::NID_setct_PANData); pub const SETCT_PANTOKEN: Nid = Nid(ffi::NID_setct_PANToken); pub const SETCT_PANONLY: Nid = Nid(ffi::NID_setct_PANOnly); pub const SETCT_OIDATA: Nid = Nid(ffi::NID_setct_OIData); pub const SETCT_PI: Nid = Nid(ffi::NID_setct_PI); pub const SETCT_PIDATA: Nid = Nid(ffi::NID_setct_PIData); pub const SETCT_PIDATAUNSIGNED: Nid = Nid(ffi::NID_setct_PIDataUnsigned); pub const SETCT_HODINPUT: Nid = Nid(ffi::NID_setct_HODInput); pub const SETCT_AUTHRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthResBaggage); pub const SETCT_AUTHREVREQBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevReqBaggage); pub const SETCT_AUTHREVRESBAGGAGE: Nid = Nid(ffi::NID_setct_AuthRevResBaggage); pub const SETCT_CAPTOKENSEQ: Nid = Nid(ffi::NID_setct_CapTokenSeq); pub const SETCT_PINITRESDATA: Nid = Nid(ffi::NID_setct_PInitResData); pub const SETCT_PI_TBS: Nid = Nid(ffi::NID_setct_PI_TBS); pub const SETCT_PRESDATA: Nid = Nid(ffi::NID_setct_PResData); pub const SETCT_AUTHREQTBS: Nid = Nid(ffi::NID_setct_AuthReqTBS); pub const SETCT_AUTHRESTBS: Nid = Nid(ffi::NID_setct_AuthResTBS); pub const SETCT_AUTHRESTBSX: Nid = Nid(ffi::NID_setct_AuthResTBSX); pub const SETCT_AUTHTOKENTBS: Nid = Nid(ffi::NID_setct_AuthTokenTBS); pub const SETCT_CAPTOKENDATA: Nid = Nid(ffi::NID_setct_CapTokenData); pub const SETCT_CAPTOKENTBS: Nid = Nid(ffi::NID_setct_CapTokenTBS); pub const SETCT_ACQCARDCODEMSG: Nid = Nid(ffi::NID_setct_AcqCardCodeMsg); pub const SETCT_AUTHREVREQTBS: Nid = Nid(ffi::NID_setct_AuthRevReqTBS); pub const SETCT_AUTHREVRESDATA: Nid = Nid(ffi::NID_setct_AuthRevResData); pub const SETCT_AUTHREVRESTBS: Nid = Nid(ffi::NID_setct_AuthRevResTBS); pub const SETCT_CAPREQTBS: Nid = Nid(ffi::NID_setct_CapReqTBS); pub const SETCT_CAPREQTBSX: Nid = Nid(ffi::NID_setct_CapReqTBSX); pub const SETCT_CAPRESDATA: Nid = Nid(ffi::NID_setct_CapResData); pub const SETCT_CAPREVREQTBS: Nid = Nid(ffi::NID_setct_CapRevReqTBS); pub const SETCT_CAPREVREQTBSX: Nid = Nid(ffi::NID_setct_CapRevReqTBSX); pub const SETCT_CAPREVRESDATA: Nid = Nid(ffi::NID_setct_CapRevResData); pub const SETCT_CREDREQTBS: Nid = Nid(ffi::NID_setct_CredReqTBS); pub const SETCT_CREDREQTBSX: Nid = Nid(ffi::NID_setct_CredReqTBSX); pub const SETCT_CREDRESDATA: Nid = Nid(ffi::NID_setct_CredResData); pub const SETCT_CREDREVREQTBS: Nid = Nid(ffi::NID_setct_CredRevReqTBS); pub const SETCT_CREDREVREQTBSX: Nid = Nid(ffi::NID_setct_CredRevReqTBSX); pub const SETCT_CREDREVRESDATA: Nid = Nid(ffi::NID_setct_CredRevResData); pub const SETCT_PCERTREQDATA: Nid = Nid(ffi::NID_setct_PCertReqData); pub const SETCT_PCERTRESTBS: Nid = Nid(ffi::NID_setct_PCertResTBS); pub const SETCT_BATCHADMINREQDATA: Nid = Nid(ffi::NID_setct_BatchAdminReqData); pub const SETCT_BATCHADMINRESDATA: Nid = Nid(ffi::NID_setct_BatchAdminResData); pub const SETCT_CARDCINITRESTBS: Nid = Nid(ffi::NID_setct_CardCInitResTBS); pub const SETCT_MEAQCINITRESTBS: Nid = Nid(ffi::NID_setct_MeAqCInitResTBS); pub const SETCT_REGFORMRESTBS: Nid = Nid(ffi::NID_setct_RegFormResTBS); pub const SETCT_CERTREQDATA: Nid = Nid(ffi::NID_setct_CertReqData); pub const SETCT_CERTREQTBS: Nid = Nid(ffi::NID_setct_CertReqTBS); pub const SETCT_CERTRESDATA: Nid = Nid(ffi::NID_setct_CertResData); pub const SETCT_CERTINQREQTBS: Nid = Nid(ffi::NID_setct_CertInqReqTBS); pub const SETCT_ERRORTBS: Nid = Nid(ffi::NID_setct_ErrorTBS); pub const SETCT_PIDUALSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIDualSignedTBE); pub const SETCT_PIUNSIGNEDTBE: Nid = Nid(ffi::NID_setct_PIUnsignedTBE); pub const SETCT_AUTHREQTBE: Nid = Nid(ffi::NID_setct_AuthReqTBE); pub const SETCT_AUTHRESTBE: Nid = Nid(ffi::NID_setct_AuthResTBE); pub const SETCT_AUTHRESTBEX: Nid = Nid(ffi::NID_setct_AuthResTBEX); pub const SETCT_AUTHTOKENTBE: Nid = Nid(ffi::NID_setct_AuthTokenTBE); pub const SETCT_CAPTOKENTBE: Nid = Nid(ffi::NID_setct_CapTokenTBE); pub const SETCT_CAPTOKENTBEX: Nid = Nid(ffi::NID_setct_CapTokenTBEX); pub const SETCT_ACQCARDCODEMSGTBE: Nid = Nid(ffi::NID_setct_AcqCardCodeMsgTBE); pub const SETCT_AUTHREVREQTBE: Nid = Nid(ffi::NID_setct_AuthRevReqTBE); pub const SETCT_AUTHREVRESTBE: Nid = Nid(ffi::NID_setct_AuthRevResTBE); pub const SETCT_AUTHREVRESTBEB: Nid = Nid(ffi::NID_setct_AuthRevResTBEB); pub const SETCT_CAPREQTBE: Nid = Nid(ffi::NID_setct_CapReqTBE); pub const SETCT_CAPREQTBEX: Nid = Nid(ffi::NID_setct_CapReqTBEX); pub const SETCT_CAPRESTBE: Nid = Nid(ffi::NID_setct_CapResTBE); pub const SETCT_CAPREVREQTBE: Nid = Nid(ffi::NID_setct_CapRevReqTBE); pub const SETCT_CAPREVREQTBEX: Nid = Nid(ffi::NID_setct_CapRevReqTBEX); pub const SETCT_CAPREVRESTBE: Nid = Nid(ffi::NID_setct_CapRevResTBE); pub const SETCT_CREDREQTBE: Nid = Nid(ffi::NID_setct_CredReqTBE); pub const SETCT_CREDREQTBEX: Nid = Nid(ffi::NID_setct_CredReqTBEX); pub const SETCT_CREDRESTBE: Nid = Nid(ffi::NID_setct_CredResTBE); pub const SETCT_CREDREVREQTBE: Nid = Nid(ffi::NID_setct_CredRevReqTBE); pub const SETCT_CREDREVREQTBEX: Nid = Nid(ffi::NID_setct_CredRevReqTBEX); pub const SETCT_CREDREVRESTBE: Nid = Nid(ffi::NID_setct_CredRevResTBE); pub const SETCT_BATCHADMINREQTBE: Nid = Nid(ffi::NID_setct_BatchAdminReqTBE); pub const SETCT_BATCHADMINRESTBE: Nid = Nid(ffi::NID_setct_BatchAdminResTBE); pub const SETCT_REGFORMREQTBE: Nid = Nid(ffi::NID_setct_RegFormReqTBE); pub const SETCT_CERTREQTBE: Nid = Nid(ffi::NID_setct_CertReqTBE); pub const SETCT_CERTREQTBEX: Nid = Nid(ffi::NID_setct_CertReqTBEX); pub const SETCT_CERTRESTBE: Nid = Nid(ffi::NID_setct_CertResTBE); pub const SETCT_CRLNOTIFICATIONTBS: Nid = Nid(ffi::NID_setct_CRLNotificationTBS); pub const SETCT_CRLNOTIFICATIONRESTBS: Nid = Nid(ffi::NID_setct_CRLNotificationResTBS); pub const SETCT_BCIDISTRIBUTIONTBS: Nid = Nid(ffi::NID_setct_BCIDistributionTBS); pub const SETEXT_GENCRYPT: Nid = Nid(ffi::NID_setext_genCrypt); pub const SETEXT_MIAUTH: Nid = Nid(ffi::NID_setext_miAuth); pub const SETEXT_PINSECURE: Nid = Nid(ffi::NID_setext_pinSecure); pub const SETEXT_PINANY: Nid = Nid(ffi::NID_setext_pinAny); pub const SETEXT_TRACK2: Nid = Nid(ffi::NID_setext_track2); pub const SETEXT_CV: Nid = Nid(ffi::NID_setext_cv); pub const SET_POLICY_ROOT: Nid = Nid(ffi::NID_set_policy_root); pub const SETCEXT_HASHEDROOT: Nid = Nid(ffi::NID_setCext_hashedRoot); pub const SETCEXT_CERTTYPE: Nid = Nid(ffi::NID_setCext_certType); pub const SETCEXT_MERCHDATA: Nid = Nid(ffi::NID_setCext_merchData); pub const SETCEXT_CCERTREQUIRED: Nid = Nid(ffi::NID_setCext_cCertRequired); pub const SETCEXT_TUNNELING: Nid = Nid(ffi::NID_setCext_tunneling); pub const SETCEXT_SETEXT: Nid = Nid(ffi::NID_setCext_setExt); pub const SETCEXT_SETQUALF: Nid = Nid(ffi::NID_setCext_setQualf); pub const SETCEXT_PGWYCAPABILITIES: Nid = Nid(ffi::NID_setCext_PGWYcapabilities); pub const SETCEXT_TOKENIDENTIFIER: Nid = Nid(ffi::NID_setCext_TokenIdentifier); pub const SETCEXT_TRACK2DATA: Nid = Nid(ffi::NID_setCext_Track2Data); pub const SETCEXT_TOKENTYPE: Nid = Nid(ffi::NID_setCext_TokenType); pub const SETCEXT_ISSUERCAPABILITIES: Nid = Nid(ffi::NID_setCext_IssuerCapabilities); pub const SETATTR_CERT: Nid = Nid(ffi::NID_setAttr_Cert); pub const SETATTR_PGWYCAP: Nid = Nid(ffi::NID_setAttr_PGWYcap); pub const SETATTR_TOKENTYPE: Nid = Nid(ffi::NID_setAttr_TokenType); pub const SETATTR_ISSCAP: Nid = Nid(ffi::NID_setAttr_IssCap); pub const SET_ROOTKEYTHUMB: Nid = Nid(ffi::NID_set_rootKeyThumb); pub const SET_ADDPOLICY: Nid = Nid(ffi::NID_set_addPolicy); pub const SETATTR_TOKEN_EMV: Nid = Nid(ffi::NID_setAttr_Token_EMV); pub const SETATTR_TOKEN_B0PRIME: Nid = Nid(ffi::NID_setAttr_Token_B0Prime); pub const SETATTR_ISSCAP_CVM: Nid = Nid(ffi::NID_setAttr_IssCap_CVM); pub const SETATTR_ISSCAP_T2: Nid = Nid(ffi::NID_setAttr_IssCap_T2); pub const SETATTR_ISSCAP_SIG: Nid = Nid(ffi::NID_setAttr_IssCap_Sig); pub const SETATTR_GENCRYPTGRM: Nid = Nid(ffi::NID_setAttr_GenCryptgrm); pub const SETATTR_T2ENC: Nid = Nid(ffi::NID_setAttr_T2Enc); pub const SETATTR_T2CLEARTXT: Nid = Nid(ffi::NID_setAttr_T2cleartxt); pub const SETATTR_TOKICCSIG: Nid = Nid(ffi::NID_setAttr_TokICCsig); pub const SETATTR_SECDEVSIG: Nid = Nid(ffi::NID_setAttr_SecDevSig); pub const SET_BRAND_IATA_ATA: Nid = Nid(ffi::NID_set_brand_IATA_ATA); pub const SET_BRAND_DINERS: Nid = Nid(ffi::NID_set_brand_Diners); pub const SET_BRAND_AMERICANEXPRESS: Nid = Nid(ffi::NID_set_brand_AmericanExpress); pub const SET_BRAND_JCB: Nid = Nid(ffi::NID_set_brand_JCB); pub const SET_BRAND_VISA: Nid = Nid(ffi::NID_set_brand_Visa); pub const SET_BRAND_MASTERCARD: Nid = Nid(ffi::NID_set_brand_MasterCard); pub const SET_BRAND_NOVUS: Nid = Nid(ffi::NID_set_brand_Novus); pub const DES_CDMF: Nid = Nid(ffi::NID_des_cdmf); pub const RSAOAEPENCRYPTIONSET: Nid = Nid(ffi::NID_rsaOAEPEncryptionSET); pub const IPSEC3: Nid = Nid(ffi::NID_ipsec3); pub const IPSEC4: Nid = Nid(ffi::NID_ipsec4); pub const WHIRLPOOL: Nid = Nid(ffi::NID_whirlpool); pub const CRYPTOPRO: Nid = Nid(ffi::NID_cryptopro); pub const CRYPTOCOM: Nid = Nid(ffi::NID_cryptocom); pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001: Nid = Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001); pub const ID_GOSTR3411_94_WITH_GOSTR3410_94: Nid = Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94); pub const ID_GOSTR3411_94: Nid = Nid(ffi::NID_id_GostR3411_94); pub const ID_HMACGOSTR3411_94: Nid = Nid(ffi::NID_id_HMACGostR3411_94); pub const ID_GOSTR3410_2001: Nid = Nid(ffi::NID_id_GostR3410_2001); pub const ID_GOSTR3410_94: Nid = Nid(ffi::NID_id_GostR3410_94); pub const ID_GOST28147_89: Nid = Nid(ffi::NID_id_Gost28147_89); pub const GOST89_CNT: Nid = Nid(ffi::NID_gost89_cnt); pub const ID_GOST28147_89_MAC: Nid = Nid(ffi::NID_id_Gost28147_89_MAC); pub const ID_GOSTR3411_94_PRF: Nid = Nid(ffi::NID_id_GostR3411_94_prf); pub const ID_GOSTR3410_2001DH: Nid = Nid(ffi::NID_id_GostR3410_2001DH); pub const ID_GOSTR3410_94DH: Nid = Nid(ffi::NID_id_GostR3410_94DH); pub const ID_GOST28147_89_CRYPTOPRO_KEYMESHING: Nid = Nid(ffi::NID_id_Gost28147_89_CryptoPro_KeyMeshing); pub const ID_GOST28147_89_NONE_KEYMESHING: Nid = Nid(ffi::NID_id_Gost28147_89_None_KeyMeshing); pub const ID_GOSTR3411_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3411_94_TestParamSet); pub const ID_GOSTR3411_94_CRYPTOPROPARAMSET: Nid = Nid(ffi::NID_id_GostR3411_94_CryptoProParamSet); pub const ID_GOST28147_89_TESTPARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_TestParamSet); pub const ID_GOST28147_89_CRYPTOPRO_A_PARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_CryptoPro_A_ParamSet); pub const ID_GOST28147_89_CRYPTOPRO_B_PARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_CryptoPro_B_ParamSet); pub const ID_GOST28147_89_CRYPTOPRO_C_PARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_CryptoPro_C_ParamSet); pub const ID_GOST28147_89_CRYPTOPRO_D_PARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_CryptoPro_D_ParamSet); pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_1_PARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_1_ParamSet); pub const ID_GOST28147_89_CRYPTOPRO_OSCAR_1_0_PARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_CryptoPro_Oscar_1_0_ParamSet); pub const ID_GOST28147_89_CRYPTOPRO_RIC_1_PARAMSET: Nid = Nid(ffi::NID_id_Gost28147_89_CryptoPro_RIC_1_ParamSet); pub const ID_GOSTR3410_94_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_TestParamSet); pub const ID_GOSTR3410_94_CRYPTOPRO_A_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_CryptoPro_A_ParamSet); pub const ID_GOSTR3410_94_CRYPTOPRO_B_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_CryptoPro_B_ParamSet); pub const ID_GOSTR3410_94_CRYPTOPRO_C_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_CryptoPro_C_ParamSet); pub const ID_GOSTR3410_94_CRYPTOPRO_D_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_CryptoPro_D_ParamSet); pub const ID_GOSTR3410_94_CRYPTOPRO_XCHA_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchA_ParamSet); pub const ID_GOSTR3410_94_CRYPTOPRO_XCHB_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchB_ParamSet); pub const ID_GOSTR3410_94_CRYPTOPRO_XCHC_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_94_CryptoPro_XchC_ParamSet); pub const ID_GOSTR3410_2001_TESTPARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_TestParamSet); pub const ID_GOSTR3410_2001_CRYPTOPRO_A_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_CryptoPro_A_ParamSet); pub const ID_GOSTR3410_2001_CRYPTOPRO_B_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_CryptoPro_B_ParamSet); pub const ID_GOSTR3410_2001_CRYPTOPRO_C_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_CryptoPro_C_ParamSet); pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHA_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchA_ParamSet); pub const ID_GOSTR3410_2001_CRYPTOPRO_XCHB_PARAMSET: Nid = Nid(ffi::NID_id_GostR3410_2001_CryptoPro_XchB_ParamSet); pub const ID_GOSTR3410_94_A: Nid = Nid(ffi::NID_id_GostR3410_94_a); pub const ID_GOSTR3410_94_ABIS: Nid = Nid(ffi::NID_id_GostR3410_94_aBis); pub const ID_GOSTR3410_94_B: Nid = Nid(ffi::NID_id_GostR3410_94_b); pub const ID_GOSTR3410_94_BBIS: Nid = Nid(ffi::NID_id_GostR3410_94_bBis); pub const ID_GOST28147_89_CC: Nid = Nid(ffi::NID_id_Gost28147_89_cc); pub const ID_GOSTR3410_94_CC: Nid = Nid(ffi::NID_id_GostR3410_94_cc); pub const ID_GOSTR3410_2001_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_cc); pub const ID_GOSTR3411_94_WITH_GOSTR3410_94_CC: Nid = Nid(ffi::NID_id_GostR3411_94_with_GostR3410_94_cc); pub const ID_GOSTR3411_94_WITH_GOSTR3410_2001_CC: Nid = Nid(ffi::NID_id_GostR3411_94_with_GostR3410_2001_cc); pub const ID_GOSTR3410_2001_PARAMSET_CC: Nid = Nid(ffi::NID_id_GostR3410_2001_ParamSet_cc); pub const CAMELLIA_128_CBC: Nid = Nid(ffi::NID_camellia_128_cbc); pub const CAMELLIA_192_CBC: Nid = Nid(ffi::NID_camellia_192_cbc); pub const CAMELLIA_256_CBC: Nid = Nid(ffi::NID_camellia_256_cbc); pub const ID_CAMELLIA128_WRAP: Nid = Nid(ffi::NID_id_camellia128_wrap); pub const ID_CAMELLIA192_WRAP: Nid = Nid(ffi::NID_id_camellia192_wrap); pub const ID_CAMELLIA256_WRAP: Nid = Nid(ffi::NID_id_camellia256_wrap); pub const CAMELLIA_128_ECB: Nid = Nid(ffi::NID_camellia_128_ecb); pub const CAMELLIA_128_OFB128: Nid = Nid(ffi::NID_camellia_128_ofb128); pub const CAMELLIA_128_CFB128: Nid = Nid(ffi::NID_camellia_128_cfb128); pub const CAMELLIA_192_ECB: Nid = Nid(ffi::NID_camellia_192_ecb); pub const CAMELLIA_192_OFB128: Nid = Nid(ffi::NID_camellia_192_ofb128); pub const CAMELLIA_192_CFB128: Nid = Nid(ffi::NID_camellia_192_cfb128); pub const CAMELLIA_256_ECB: Nid = Nid(ffi::NID_camellia_256_ecb); pub const CAMELLIA_256_OFB128: Nid = Nid(ffi::NID_camellia_256_ofb128); pub const CAMELLIA_256_CFB128: Nid = Nid(ffi::NID_camellia_256_cfb128); pub const CAMELLIA_128_CFB1: Nid = Nid(ffi::NID_camellia_128_cfb1); pub const CAMELLIA_192_CFB1: Nid = Nid(ffi::NID_camellia_192_cfb1); pub const CAMELLIA_256_CFB1: Nid = Nid(ffi::NID_camellia_256_cfb1); pub const CAMELLIA_128_CFB8: Nid = Nid(ffi::NID_camellia_128_cfb8); pub const CAMELLIA_192_CFB8: Nid = Nid(ffi::NID_camellia_192_cfb8); pub const CAMELLIA_256_CFB8: Nid = Nid(ffi::NID_camellia_256_cfb8); pub const KISA: Nid = Nid(ffi::NID_kisa); pub const SEED_ECB: Nid = Nid(ffi::NID_seed_ecb); pub const SEED_CBC: Nid = Nid(ffi::NID_seed_cbc); pub const SEED_CFB128: Nid = Nid(ffi::NID_seed_cfb128); pub const SEED_OFB128: Nid = Nid(ffi::NID_seed_ofb128); pub const HMAC: Nid = Nid(ffi::NID_hmac); pub const CMAC: Nid = Nid(ffi::NID_cmac); pub const RC4_HMAC_MD5: Nid = Nid(ffi::NID_rc4_hmac_md5); pub const AES_128_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_128_cbc_hmac_sha1); pub const AES_192_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_192_cbc_hmac_sha1); pub const AES_256_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_256_cbc_hmac_sha1); } #[cfg(test)] mod test { use super::Nid; #[test] fn signature_digest() { let algs = Nid::SHA256WITHRSAENCRYPTION.signature_algorithms().unwrap(); assert_eq!(algs.digest, Nid::SHA256); assert_eq!(algs.pkey, Nid::RSAENCRYPTION); } #[test] fn test_long_name_conversion() { let common_name = Nid::COMMONNAME; let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; let ms_ctl_sign = Nid::MS_CTL_SIGN; let undefined_nid = Nid::from_raw(118); assert_eq!(common_name.long_name().unwrap(), "commonName"); assert_eq!( organizational_unit_name.long_name().unwrap(), "organizationalUnitName" ); assert_eq!( aes256_cbc_hmac_sha1.long_name().unwrap(), "aes-256-cbc-hmac-sha1" ); assert_eq!( id_cmc_lrapopwitness.long_name().unwrap(), "id-cmc-lraPOPWitness" ); assert_eq!( ms_ctl_sign.long_name().unwrap(), "Microsoft Trust List Signing" ); assert!( undefined_nid.long_name().is_err(), "undefined_nid should not return a valid value" ); } #[test] fn test_short_name_conversion() { let common_name = Nid::COMMONNAME; let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; let ms_ctl_sign = Nid::MS_CTL_SIGN; let undefined_nid = Nid::from_raw(118); assert_eq!(common_name.short_name().unwrap(), "CN"); assert_eq!(organizational_unit_name.short_name().unwrap(), "OU"); assert_eq!( aes256_cbc_hmac_sha1.short_name().unwrap(), "AES-256-CBC-HMAC-SHA1" ); assert_eq!( id_cmc_lrapopwitness.short_name().unwrap(), "id-cmc-lraPOPWitness" ); assert_eq!(ms_ctl_sign.short_name().unwrap(), "msCTLSign"); assert!( undefined_nid.short_name().is_err(), "undefined_nid should not return a valid value" ); } } openssl-0.10.23/src/ocsp.rs010064400017500001750000000261141346222217000136650ustar0000000000000000use ffi; use foreign_types::ForeignTypeRef; use libc::{c_int, c_long, c_ulong}; use std::mem; use std::ptr; use asn1::Asn1GeneralizedTimeRef; use error::ErrorStack; use hash::MessageDigest; use stack::StackRef; use x509::store::X509StoreRef; use x509::{X509Ref, X509}; use {cvt, cvt_p}; bitflags! { pub struct OcspFlag: c_ulong { const NO_CERTS = ffi::OCSP_NOCERTS; const NO_INTERN = ffi::OCSP_NOINTERN; const NO_CHAIN = ffi::OCSP_NOCHAIN; const NO_VERIFY = ffi::OCSP_NOVERIFY; const NO_EXPLICIT = ffi::OCSP_NOEXPLICIT; const NO_CA_SIGN = ffi::OCSP_NOCASIGN; const NO_DELEGATED = ffi::OCSP_NODELEGATED; const NO_CHECKS = ffi::OCSP_NOCHECKS; const TRUST_OTHER = ffi::OCSP_TRUSTOTHER; const RESPID_KEY = ffi::OCSP_RESPID_KEY; const NO_TIME = ffi::OCSP_NOTIME; } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct OcspResponseStatus(c_int); impl OcspResponseStatus { pub fn from_raw(raw: c_int) -> OcspResponseStatus { OcspResponseStatus(raw) } pub fn as_raw(&self) -> c_int { self.0 } pub const SUCCESSFUL: OcspResponseStatus = OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SUCCESSFUL); pub const MALFORMED_REQUEST: OcspResponseStatus = OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_MALFORMEDREQUEST); pub const INTERNAL_ERROR: OcspResponseStatus = OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_INTERNALERROR); pub const TRY_LATER: OcspResponseStatus = OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_TRYLATER); pub const SIG_REQUIRED: OcspResponseStatus = OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SIGREQUIRED); pub const UNAUTHORIZED: OcspResponseStatus = OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_UNAUTHORIZED); } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct OcspCertStatus(c_int); impl OcspCertStatus { pub fn from_raw(raw: c_int) -> OcspCertStatus { OcspCertStatus(raw) } pub fn as_raw(&self) -> c_int { self.0 } pub const GOOD: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_GOOD); pub const REVOKED: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_REVOKED); pub const UNKNOWN: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_UNKNOWN); } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct OcspRevokedStatus(c_int); impl OcspRevokedStatus { pub fn from_raw(raw: c_int) -> OcspRevokedStatus { OcspRevokedStatus(raw) } pub fn as_raw(&self) -> c_int { self.0 } pub const NO_STATUS: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_NOSTATUS); pub const UNSPECIFIED: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_UNSPECIFIED); pub const KEY_COMPROMISE: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_KEYCOMPROMISE); pub const CA_COMPROMISE: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CACOMPROMISE); pub const AFFILIATION_CHANGED: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_AFFILIATIONCHANGED); pub const STATUS_SUPERSEDED: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_SUPERSEDED); pub const STATUS_CESSATION_OF_OPERATION: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CESSATIONOFOPERATION); pub const STATUS_CERTIFICATE_HOLD: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CERTIFICATEHOLD); pub const REMOVE_FROM_CRL: OcspRevokedStatus = OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_REMOVEFROMCRL); } pub struct OcspStatus<'a> { /// The overall status of the response. pub status: OcspCertStatus, /// If `status` is `CERT_STATUS_REVOKED`, the reason for the revocation. pub reason: OcspRevokedStatus, /// If `status` is `CERT_STATUS_REVOKED`, the time at which the certificate was revoked. pub revocation_time: Option<&'a Asn1GeneralizedTimeRef>, /// The time that this revocation check was performed. pub this_update: &'a Asn1GeneralizedTimeRef, /// The time at which this revocation check expires. pub next_update: &'a Asn1GeneralizedTimeRef, } impl<'a> OcspStatus<'a> { /// Checks validity of the `this_update` and `next_update` fields. /// /// The `nsec` parameter specifies an amount of slack time that will be used when comparing /// those times with the current time to account for delays and clock skew. /// /// The `maxsec` parameter limits the maximum age of the `this_update` parameter to prohibit /// very old responses. pub fn check_validity(&self, nsec: u32, maxsec: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::OCSP_check_validity( self.this_update.as_ptr(), self.next_update.as_ptr(), nsec as c_long, maxsec.map(|n| n as c_long).unwrap_or(-1), )) .map(|_| ()) } } } foreign_type_and_impl_send_sync! { type CType = ffi::OCSP_BASICRESP; fn drop = ffi::OCSP_BASICRESP_free; pub struct OcspBasicResponse; pub struct OcspBasicResponseRef; } impl OcspBasicResponseRef { /// Verifies the validity of the response. /// /// The `certs` parameter contains a set of certificates that will be searched when locating the /// OCSP response signing certificate. Some responders do not include this in the response. pub fn verify( &self, certs: &StackRef, store: &X509StoreRef, flags: OcspFlag, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::OCSP_basic_verify( self.as_ptr(), certs.as_ptr(), store.as_ptr(), flags.bits(), )) .map(|_| ()) } } /// Looks up the status for the specified certificate ID. pub fn find_status<'a>(&'a self, id: &OcspCertIdRef) -> Option> { unsafe { let mut status = ffi::V_OCSP_CERTSTATUS_UNKNOWN; let mut reason = ffi::OCSP_REVOKED_STATUS_NOSTATUS; let mut revocation_time = ptr::null_mut(); let mut this_update = ptr::null_mut(); let mut next_update = ptr::null_mut(); let r = ffi::OCSP_resp_find_status( self.as_ptr(), id.as_ptr(), &mut status, &mut reason, &mut revocation_time, &mut this_update, &mut next_update, ); if r == 1 { let revocation_time = if revocation_time.is_null() { None } else { Some(Asn1GeneralizedTimeRef::from_ptr(revocation_time)) }; Some(OcspStatus { status: OcspCertStatus(status), reason: OcspRevokedStatus(status), revocation_time: revocation_time, this_update: Asn1GeneralizedTimeRef::from_ptr(this_update), next_update: Asn1GeneralizedTimeRef::from_ptr(next_update), }) } else { None } } } } foreign_type_and_impl_send_sync! { type CType = ffi::OCSP_CERTID; fn drop = ffi::OCSP_CERTID_free; pub struct OcspCertId; pub struct OcspCertIdRef; } impl OcspCertId { /// Constructs a certificate ID for certificate `subject`. pub fn from_cert( digest: MessageDigest, subject: &X509Ref, issuer: &X509Ref, ) -> Result { unsafe { cvt_p(ffi::OCSP_cert_to_id( digest.as_ptr(), subject.as_ptr(), issuer.as_ptr(), )) .map(OcspCertId) } } } foreign_type_and_impl_send_sync! { type CType = ffi::OCSP_RESPONSE; fn drop = ffi::OCSP_RESPONSE_free; pub struct OcspResponse; pub struct OcspResponseRef; } impl OcspResponse { /// Creates an OCSP response from the status and optional body. /// /// A body should only be provided if `status` is `RESPONSE_STATUS_SUCCESSFUL`. pub fn create( status: OcspResponseStatus, body: Option<&OcspBasicResponseRef>, ) -> Result { unsafe { ffi::init(); cvt_p(ffi::OCSP_response_create( status.as_raw(), body.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut()), )) .map(OcspResponse) } } from_der! { /// Deserializes a DER-encoded OCSP response. /// /// This corresponds to [`d2i_OCSP_RESPONSE`]. /// /// [`d2i_OCSP_RESPONSE`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_OCSP_RESPONSE.html from_der, OcspResponse, ffi::d2i_OCSP_RESPONSE } } impl OcspResponseRef { to_der! { /// Serializes the response to its standard DER encoding. /// /// This corresponds to [`i2d_OCSP_RESPONSE`]. /// /// [`i2d_OCSP_RESPONSE`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_OCSP_RESPONSE.html to_der, ffi::i2d_OCSP_RESPONSE } /// Returns the status of the response. pub fn status(&self) -> OcspResponseStatus { unsafe { OcspResponseStatus(ffi::OCSP_response_status(self.as_ptr())) } } /// Returns the basic response. /// /// This will only succeed if `status()` returns `RESPONSE_STATUS_SUCCESSFUL`. pub fn basic(&self) -> Result { unsafe { cvt_p(ffi::OCSP_response_get1_basic(self.as_ptr())).map(OcspBasicResponse) } } } foreign_type_and_impl_send_sync! { type CType = ffi::OCSP_REQUEST; fn drop = ffi::OCSP_REQUEST_free; pub struct OcspRequest; pub struct OcspRequestRef; } impl OcspRequest { pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::OCSP_REQUEST_new()).map(OcspRequest) } } from_der! { /// Deserializes a DER-encoded OCSP request. /// /// This corresponds to [`d2i_OCSP_REQUEST`]. /// /// [`d2i_OCSP_REQUEST`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_OCSP_REQUEST.html from_der, OcspRequest, ffi::d2i_OCSP_REQUEST } } impl OcspRequestRef { to_der! { /// Serializes the request to its standard DER encoding. /// /// This corresponds to [`i2d_OCSP_REQUEST`]. /// /// [`i2d_OCSP_REQUEST`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_OCSP_REQUEST.html to_der, ffi::i2d_OCSP_REQUEST } pub fn add_id(&mut self, id: OcspCertId) -> Result<&mut OcspOneReqRef, ErrorStack> { unsafe { let ptr = cvt_p(ffi::OCSP_request_add0_id(self.as_ptr(), id.as_ptr()))?; mem::forget(id); Ok(OcspOneReqRef::from_ptr_mut(ptr)) } } } foreign_type_and_impl_send_sync! { type CType = ffi::OCSP_ONEREQ; fn drop = ffi::OCSP_ONEREQ_free; pub struct OcspOneReq; pub struct OcspOneReqRef; } openssl-0.10.23/src/pkcs12.rs010064400017500001750000000202541346222217000140230ustar0000000000000000//! PKCS #12 archives. use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::ffi::CString; use std::ptr; use error::ErrorStack; use nid::Nid; use pkey::{HasPrivate, PKey, PKeyRef, Private}; use stack::Stack; use x509::{X509Ref, X509}; use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::PKCS12; fn drop = ffi::PKCS12_free; pub struct Pkcs12; pub struct Pkcs12Ref; } impl Pkcs12Ref { to_der! { /// Serializes the `Pkcs12` to its standard DER encoding. /// /// This corresponds to [`i2d_PKCS12`]. /// /// [`i2d_PKCS12`]: https://www.openssl.org/docs/manmaster/man3/i2d_PKCS12.html to_der, ffi::i2d_PKCS12 } /// Extracts the contents of the `Pkcs12`. pub fn parse(&self, pass: &str) -> Result { unsafe { let pass = CString::new(pass.as_bytes()).unwrap(); let mut pkey = ptr::null_mut(); let mut cert = ptr::null_mut(); let mut chain = ptr::null_mut(); cvt(ffi::PKCS12_parse( self.as_ptr(), pass.as_ptr(), &mut pkey, &mut cert, &mut chain, ))?; let pkey = PKey::from_ptr(pkey); let cert = X509::from_ptr(cert); let chain = if chain.is_null() { None } else { Some(Stack::from_ptr(chain)) }; Ok(ParsedPkcs12 { pkey: pkey, cert: cert, chain: chain, }) } } } impl Pkcs12 { from_der! { /// Deserializes a DER-encoded PKCS#12 archive. /// /// This corresponds to [`d2i_PKCS12`]. /// /// [`d2i_PKCS12`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PKCS12.html from_der, Pkcs12, ffi::d2i_PKCS12 } /// Creates a new builder for a protected pkcs12 certificate. /// /// This uses the defaults from the OpenSSL library: /// /// * `nid_key` - `nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` /// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC` /// * `iter` - `2048` /// * `mac_iter` - `2048` pub fn builder() -> Pkcs12Builder { ffi::init(); Pkcs12Builder { nid_key: Nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC, nid_cert: Nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC, iter: ffi::PKCS12_DEFAULT_ITER, mac_iter: ffi::PKCS12_DEFAULT_ITER, ca: None, } } } pub struct ParsedPkcs12 { pub pkey: PKey, pub cert: X509, pub chain: Option>, } pub struct Pkcs12Builder { nid_key: Nid, nid_cert: Nid, iter: c_int, mac_iter: c_int, ca: Option>, } impl Pkcs12Builder { /// The encryption algorithm that should be used for the key pub fn key_algorithm(&mut self, nid: Nid) -> &mut Self { self.nid_key = nid; self } /// The encryption algorithm that should be used for the cert pub fn cert_algorithm(&mut self, nid: Nid) -> &mut Self { self.nid_cert = nid; self } /// Key iteration count, default is 2048 as of this writing pub fn key_iter(&mut self, iter: u32) -> &mut Self { self.iter = iter as c_int; self } /// MAC iteration count, default is the same as key_iter. /// /// Old implementations don't understand MAC iterations greater than 1, (pre 1.0.1?), if such /// compatibility is required this should be set to 1. pub fn mac_iter(&mut self, mac_iter: u32) -> &mut Self { self.mac_iter = mac_iter as c_int; self } /// An additional set of certificates to include in the archive beyond the one provided to /// `build`. pub fn ca(&mut self, ca: Stack) -> &mut Self { self.ca = Some(ca); self } /// Builds the PKCS #12 object /// /// # Arguments /// /// * `password` - the password used to encrypt the key and certificate /// * `friendly_name` - user defined name for the certificate /// * `pkey` - key to store /// * `cert` - certificate to store pub fn build( self, password: &str, friendly_name: &str, pkey: &PKeyRef, cert: &X509Ref, ) -> Result where T: HasPrivate, { unsafe { let pass = CString::new(password).unwrap(); let friendly_name = CString::new(friendly_name).unwrap(); let pkey = pkey.as_ptr(); let cert = cert.as_ptr(); let ca = self .ca .as_ref() .map(|ca| ca.as_ptr()) .unwrap_or(ptr::null_mut()); let nid_key = self.nid_key.as_raw(); let nid_cert = self.nid_cert.as_raw(); // According to the OpenSSL docs, keytype is a non-standard extension for MSIE, // It's values are KEY_SIG or KEY_EX, see the OpenSSL docs for more information: // https://www.openssl.org/docs/man1.0.2/crypto/PKCS12_create.html let keytype = 0; cvt_p(ffi::PKCS12_create( pass.as_ptr() as *const _ as *mut _, friendly_name.as_ptr() as *const _ as *mut _, pkey, cert, ca, nid_key, nid_cert, self.iter, self.mac_iter, keytype, )) .map(Pkcs12) } } } #[cfg(test)] mod test { use hash::MessageDigest; use hex; use asn1::Asn1Time; use nid::Nid; use pkey::PKey; use rsa::Rsa; use x509::extension::KeyUsage; use x509::{X509Name, X509}; use super::*; #[test] fn parse() { let der = include_bytes!("../test/identity.p12"); let pkcs12 = Pkcs12::from_der(der).unwrap(); let parsed = pkcs12.parse("mypass").unwrap(); assert_eq!( hex::encode(parsed.cert.digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); let chain = parsed.chain.unwrap(); assert_eq!(chain.len(), 1); assert_eq!( hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } #[test] fn parse_empty_chain() { let der = include_bytes!("../test/keystore-empty-chain.p12"); let pkcs12 = Pkcs12::from_der(der).unwrap(); let parsed = pkcs12.parse("cassandra").unwrap(); assert!(parsed.chain.is_none()); } #[test] fn create() { let subject_name = "ns.example.com"; let rsa = Rsa::generate(2048).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); let mut name = X509Name::builder().unwrap(); name.append_entry_by_nid(Nid::COMMONNAME, subject_name) .unwrap(); let name = name.build(); let key_usage = KeyUsage::new().digital_signature().build().unwrap(); let mut builder = X509::builder().unwrap(); builder.set_version(2).unwrap(); builder .set_not_before(&Asn1Time::days_from_now(0).unwrap()) .unwrap(); builder .set_not_after(&Asn1Time::days_from_now(365).unwrap()) .unwrap(); builder.set_subject_name(&name).unwrap(); builder.set_issuer_name(&name).unwrap(); builder.append_extension(key_usage).unwrap(); builder.set_pubkey(&pkey).unwrap(); builder.sign(&pkey, MessageDigest::sha256()).unwrap(); let cert = builder.build(); let pkcs12_builder = Pkcs12::builder(); let pkcs12 = pkcs12_builder .build("mypass", subject_name, &pkey, &cert) .unwrap(); let der = pkcs12.to_der().unwrap(); let pkcs12 = Pkcs12::from_der(&der).unwrap(); let parsed = pkcs12.parse("mypass").unwrap(); assert_eq!( &*parsed.cert.digest(MessageDigest::sha1()).unwrap(), &*cert.digest(MessageDigest::sha1()).unwrap() ); assert!(parsed.pkey.public_eq(&pkey)); } } openssl-0.10.23/src/pkcs5.rs010064400017500001750000000225011346222217000137420ustar0000000000000000use ffi; use libc::c_int; use std::ptr; use cvt; use error::ErrorStack; use hash::MessageDigest; use symm::Cipher; #[derive(Clone, Eq, PartialEq, Hash, Debug)] pub struct KeyIvPair { pub key: Vec, pub iv: Option>, } /// Derives a key and an IV from various parameters. /// /// If specified, `salt` must be 8 bytes in length. /// /// If the total key and IV length is less than 16 bytes and MD5 is used then /// the algorithm is compatible with the key derivation algorithm from PKCS#5 /// v1.5 or PBKDF1 from PKCS#5 v2.0. /// /// New applications should not use this and instead use /// `pbkdf2_hmac` or another more modern key derivation algorithm. pub fn bytes_to_key( cipher: Cipher, digest: MessageDigest, data: &[u8], salt: Option<&[u8]>, count: i32, ) -> Result { unsafe { assert!(data.len() <= c_int::max_value() as usize); let salt_ptr = match salt { Some(salt) => { assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize); salt.as_ptr() } None => ptr::null(), }; ffi::init(); let mut iv = cipher.iv_len().map(|l| vec![0; l]); let cipher = cipher.as_ptr(); let digest = digest.as_ptr(); let len = cvt(ffi::EVP_BytesToKey( cipher, digest, salt_ptr, ptr::null(), data.len() as c_int, count.into(), ptr::null_mut(), ptr::null_mut(), ))?; let mut key = vec![0; len as usize]; let iv_ptr = iv .as_mut() .map(|v| v.as_mut_ptr()) .unwrap_or(ptr::null_mut()); cvt(ffi::EVP_BytesToKey( cipher, digest, salt_ptr, data.as_ptr(), data.len() as c_int, count as c_int, key.as_mut_ptr(), iv_ptr, ))?; Ok(KeyIvPair { key: key, iv: iv }) } } /// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function. pub fn pbkdf2_hmac( pass: &[u8], salt: &[u8], iter: usize, hash: MessageDigest, key: &mut [u8], ) -> Result<(), ErrorStack> { unsafe { assert!(pass.len() <= c_int::max_value() as usize); assert!(salt.len() <= c_int::max_value() as usize); assert!(key.len() <= c_int::max_value() as usize); ffi::init(); cvt(ffi::PKCS5_PBKDF2_HMAC( pass.as_ptr() as *const _, pass.len() as c_int, salt.as_ptr(), salt.len() as c_int, iter as c_int, hash.as_ptr(), key.len() as c_int, key.as_mut_ptr(), )) .map(|_| ()) } } /// Derives a key from a password and salt using the scrypt algorithm. /// /// Requires OpenSSL 1.1.0 or newer. #[cfg(any(ossl110))] pub fn scrypt( pass: &[u8], salt: &[u8], n: u64, r: u64, p: u64, maxmem: u64, key: &mut [u8], ) -> Result<(), ErrorStack> { unsafe { ffi::init(); cvt(ffi::EVP_PBE_scrypt( pass.as_ptr() as *const _, pass.len(), salt.as_ptr() as *const _, salt.len(), n, r, p, maxmem, key.as_mut_ptr() as *mut _, key.len(), )) .map(|_| ()) } } #[cfg(test)] mod tests { use hash::MessageDigest; use symm::Cipher; // Test vectors from // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c #[test] fn pbkdf2_hmac_sha256() { let mut buf = [0; 16]; super::pbkdf2_hmac(b"passwd", b"salt", 1, MessageDigest::sha256(), &mut buf).unwrap(); assert_eq!( buf, &[ 0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8, 0xec_u8, 0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8, ][..] ); super::pbkdf2_hmac( b"Password", b"NaCl", 80000, MessageDigest::sha256(), &mut buf, ) .unwrap(); assert_eq!( buf, &[ 0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8, 0x83_u8, 0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8, ][..] ); } // Test vectors from // https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c #[test] fn pbkdf2_hmac_sha512() { let mut buf = [0; 64]; super::pbkdf2_hmac(b"password", b"NaCL", 1, MessageDigest::sha512(), &mut buf).unwrap(); assert_eq!( &buf[..], &[ 0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8, 0x94_u8, 0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8, 0xd3_u8, 0xc7_u8, 0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8, 0xb3_u8, 0x90_u8, 0xed_u8, 0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8, 0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8, 0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8, 0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8, 0x1f_u8, 0xc6_u8, 0x33_u8, 0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8, 0x5e_u8, 0x9f_u8, 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8, 0x06_u8, ][..] ); super::pbkdf2_hmac( b"pass\0word", b"sa\0lt", 1, MessageDigest::sha512(), &mut buf, ) .unwrap(); assert_eq!( &buf[..], &[ 0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8, 0x8b_u8, 0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8, 0x2f_u8, 0x93_u8, 0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8, 0x0d_u8, 0x63_u8, 0xb8_u8, 0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8, 0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8, 0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8, 0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8, 0x79_u8, 0x09_u8, 0x96_u8, 0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8, 0x5a_u8, 0xb5_u8, 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8, 0xa7_u8, ][..] ); super::pbkdf2_hmac( b"passwordPASSWORDpassword", b"salt\0\0\0", 50, MessageDigest::sha512(), &mut buf, ) .unwrap(); assert_eq!( &buf[..], &[ 0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8, 0x85_u8, 0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8, 0x3b_u8, 0x30_u8, 0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8, 0xc8_u8, 0xc9_u8, 0x37_u8, 0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8, 0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8, 0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8, 0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8, 0x00_u8, 0x56_u8, 0xc6_u8, 0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8, 0x4b_u8, 0x1a_u8, 0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8, 0x39_u8, ][..] ); } #[test] fn bytes_to_key() { let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8]; let data = [ 143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8, ]; let expected_key = vec![ 249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8, 58_u8, 87_u8, 234_u8, 3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8, 98_u8, 245_u8, 246_u8, 238_u8, 177_u8, 229_u8, 161_u8, 183_u8, 224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8, ]; let expected_iv = vec![ 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, ]; assert_eq!( super::bytes_to_key( Cipher::aes_256_cbc(), MessageDigest::sha1(), &data, Some(&salt), 1, ) .unwrap(), super::KeyIvPair { key: expected_key, iv: Some(expected_iv), } ); } #[test] #[cfg(any(ossl110))] fn scrypt() { use hex; let pass = "pleaseletmein"; let salt = "SodiumChloride"; let expected = "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613\ f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887"; let mut actual = [0; 64]; super::scrypt( pass.as_bytes(), salt.as_bytes(), 16384, 8, 1, 0, &mut actual, ) .unwrap(); assert_eq!(hex::encode(&actual[..]), expected); } } openssl-0.10.23/src/pkcs7.rs010064400017500001750000000302631346222217000137500ustar0000000000000000use bio::{MemBio, MemBioSlice}; use error::ErrorStack; use ffi; use foreign_types::ForeignTypeRef; use libc::c_int; use pkey::{HasPrivate, PKeyRef}; use stack::StackRef; use std::ptr; use symm::Cipher; use x509::store::X509StoreRef; use x509::{X509Ref, X509}; use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::PKCS7; fn drop = ffi::PKCS7_free; /// A PKCS#7 structure. /// /// Contains signed and/or encrypted data. pub struct Pkcs7; /// Reference to `Pkcs7` pub struct Pkcs7Ref; } bitflags! { pub struct Pkcs7Flags: c_int { const TEXT = ffi::PKCS7_TEXT; const NOCERTS = ffi::PKCS7_NOCERTS; const NOSIGS = ffi::PKCS7_NOSIGS; const NOCHAIN = ffi::PKCS7_NOCHAIN; const NOINTERN = ffi::PKCS7_NOINTERN; const NOVERIFY = ffi::PKCS7_NOVERIFY; const DETACHED = ffi::PKCS7_DETACHED; const BINARY = ffi::PKCS7_BINARY; const NOATTR = ffi::PKCS7_NOATTR; const NOSMIMECAP = ffi::PKCS7_NOSMIMECAP; const NOOLDMIMETYPE = ffi::PKCS7_NOOLDMIMETYPE; const CRLFEOL = ffi::PKCS7_CRLFEOL; const STREAM = ffi::PKCS7_STREAM; const NOCRL = ffi::PKCS7_NOCRL; const PARTIAL = ffi::PKCS7_PARTIAL; const REUSE_DIGEST = ffi::PKCS7_REUSE_DIGEST; #[cfg(not(any(ossl101, ossl102, libressl)))] const NO_DUAL_CONTENT = ffi::PKCS7_NO_DUAL_CONTENT; } } impl Pkcs7 { from_pem! { /// Deserializes a PEM-encoded PKCS#7 signature /// /// The input should have a header of `-----BEGIN PKCS7-----`. /// /// This corresponds to [`PEM_read_bio_PKCS7`]. /// /// [`PEM_read_bio_PKCS7`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_PKCS7.html from_pem, Pkcs7, ffi::PEM_read_bio_PKCS7 } /// Parses a message in S/MIME format. /// /// Returns the loaded signature, along with the cleartext message (if /// available). /// /// This corresponds to [`SMIME_read_PKCS7`]. /// /// [`SMIME_read_PKCS7`]: https://www.openssl.org/docs/man1.1.0/crypto/SMIME_read_PKCS7.html pub fn from_smime(input: &[u8]) -> Result<(Pkcs7, Option>), ErrorStack> { ffi::init(); let input_bio = MemBioSlice::new(input)?; let mut bcont_bio = ptr::null_mut(); unsafe { let pkcs7 = cvt_p(ffi::SMIME_read_PKCS7(input_bio.as_ptr(), &mut bcont_bio)).map(Pkcs7)?; let out = if !bcont_bio.is_null() { let bcont_bio = MemBio::from_ptr(bcont_bio); Some(bcont_bio.get_buf().to_vec()) } else { None }; Ok((pkcs7, out)) } } /// Creates and returns a PKCS#7 `envelopedData` structure. /// /// `certs` is a list of recipient certificates. `input` is the content to be /// encrypted. `cipher` is the symmetric cipher to use. `flags` is an optional /// set of flags. /// /// This corresponds to [`PKCS7_encrypt`]. /// /// [`PKCS7_encrypt`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_encrypt.html pub fn encrypt( certs: &StackRef, input: &[u8], cipher: Cipher, flags: Pkcs7Flags, ) -> Result { let input_bio = MemBioSlice::new(input)?; unsafe { cvt_p(ffi::PKCS7_encrypt( certs.as_ptr(), input_bio.as_ptr(), cipher.as_ptr(), flags.bits, )) .map(Pkcs7) } } /// Creates and returns a PKCS#7 `signedData` structure. /// /// `signcert` is the certificate to sign with, `pkey` is the corresponding /// private key. `certs` is an optional additional set of certificates to /// include in the PKCS#7 structure (for example any intermediate CAs in the /// chain). /// /// This corresponds to [`PKCS7_sign`]. /// /// [`PKCS7_sign`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_sign.html pub fn sign( signcert: &X509Ref, pkey: &PKeyRef, certs: &StackRef, input: &[u8], flags: Pkcs7Flags, ) -> Result where PT: HasPrivate, { let input_bio = MemBioSlice::new(input)?; unsafe { cvt_p(ffi::PKCS7_sign( signcert.as_ptr(), pkey.as_ptr(), certs.as_ptr(), input_bio.as_ptr(), flags.bits, )) .map(Pkcs7) } } } impl Pkcs7Ref { /// Converts PKCS#7 structure to S/MIME format /// /// This corresponds to [`SMIME_write_PKCS7`]. /// /// [`SMIME_write_PKCS7`]: https://www.openssl.org/docs/man1.1.0/crypto/SMIME_write_PKCS7.html pub fn to_smime(&self, input: &[u8], flags: Pkcs7Flags) -> Result, ErrorStack> { let input_bio = MemBioSlice::new(input)?; let output = MemBio::new()?; unsafe { cvt(ffi::SMIME_write_PKCS7( output.as_ptr(), self.as_ptr(), input_bio.as_ptr(), flags.bits, )) .map(|_| output.get_buf().to_owned()) } } to_pem! { /// Serializes the data into a PEM-encoded PKCS#7 structure. /// /// The output will have a header of `-----BEGIN PKCS7-----`. /// /// This corresponds to [`PEM_write_bio_PKCS7`]. /// /// [`PEM_write_bio_PKCS7`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS7.html to_pem, ffi::PEM_write_bio_PKCS7 } /// Decrypts data using the provided private key. /// /// `pkey` is the recipient's private key, and `cert` is the recipient's /// certificate. /// /// Returns the decrypted message. /// /// This corresponds to [`PKCS7_decrypt`]. /// /// [`PKCS7_decrypt`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_decrypt.html pub fn decrypt( &self, pkey: &PKeyRef, cert: &X509Ref, flags: Pkcs7Flags, ) -> Result, ErrorStack> where PT: HasPrivate, { let output = MemBio::new()?; unsafe { cvt(ffi::PKCS7_decrypt( self.as_ptr(), pkey.as_ptr(), cert.as_ptr(), output.as_ptr(), flags.bits, )) .map(|_| output.get_buf().to_owned()) } } /// Verifies the PKCS#7 `signedData` structure contained by `&self`. /// /// `certs` is a set of certificates in which to search for the signer's /// certificate. `store` is a trusted certificate store (used for chain /// verification). `indata` is the signed data if the content is not present /// in `&self`. The content is written to `out` if it is not `None`. /// /// This corresponds to [`PKCS7_verify`]. /// /// [`PKCS7_verify`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_verify.html pub fn verify( &self, certs: &StackRef, store: &X509StoreRef, indata: Option<&[u8]>, out: Option<&mut Vec>, flags: Pkcs7Flags, ) -> Result<(), ErrorStack> { let out_bio = MemBio::new()?; let indata_bio = match indata { Some(data) => Some(MemBioSlice::new(data)?), None => None, }; let indata_bio_ptr = indata_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); unsafe { cvt(ffi::PKCS7_verify( self.as_ptr(), certs.as_ptr(), store.as_ptr(), indata_bio_ptr, out_bio.as_ptr(), flags.bits, )) .map(|_| ())? } if let Some(data) = out { data.clear(); data.extend_from_slice(out_bio.get_buf()); } Ok(()) } } #[cfg(test)] mod tests { use pkcs7::{Pkcs7, Pkcs7Flags}; use pkey::PKey; use stack::Stack; use symm::Cipher; use x509::store::X509StoreBuilder; use x509::X509; #[test] fn encrypt_decrypt_test() { let cert = include_bytes!("../test/certs.pem"); let cert = X509::from_pem(cert).unwrap(); let mut certs = Stack::new().unwrap(); certs.push(cert.clone()).unwrap(); let message: String = String::from("foo"); let cypher = Cipher::des_ede3_cbc(); let flags = Pkcs7Flags::STREAM; let pkey = include_bytes!("../test/key.pem"); let pkey = PKey::private_key_from_pem(pkey).unwrap(); let pkcs7 = Pkcs7::encrypt(&certs, message.as_bytes(), cypher, flags).expect("should succeed"); let encrypted = pkcs7 .to_smime(message.as_bytes(), flags) .expect("should succeed"); let (pkcs7_decoded, _) = Pkcs7::from_smime(encrypted.as_slice()).expect("should succeed"); let decoded = pkcs7_decoded .decrypt(&pkey, &cert, Pkcs7Flags::empty()) .expect("should succeed"); assert_eq!(decoded, message.into_bytes()); } #[test] fn sign_verify_test_detached() { let cert = include_bytes!("../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let certs = Stack::new().unwrap(); let message: String = String::from("foo"); let flags = Pkcs7Flags::STREAM | Pkcs7Flags::DETACHED; let pkey = include_bytes!("../test/key.pem"); let pkey = PKey::private_key_from_pem(pkey).unwrap(); let mut store_builder = X509StoreBuilder::new().expect("should succeed"); let root_ca = include_bytes!("../test/root-ca.pem"); let root_ca = X509::from_pem(root_ca).unwrap(); store_builder.add_cert(root_ca).expect("should succeed"); let store = store_builder.build(); let pkcs7 = Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed"); let signed = pkcs7 .to_smime(message.as_bytes(), flags) .expect("should succeed"); println!("{:?}", String::from_utf8(signed.clone()).unwrap()); let (pkcs7_decoded, content) = Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); let mut output = Vec::new(); pkcs7_decoded .verify( &certs, &store, Some(message.as_bytes()), Some(&mut output), flags, ) .expect("should succeed"); assert_eq!(message.clone().into_bytes(), output); assert_eq!( message.clone().into_bytes(), content.expect("should be non-empty") ); } #[test] fn sign_verify_test_normal() { let cert = include_bytes!("../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let certs = Stack::new().unwrap(); let message: String = String::from("foo"); let flags = Pkcs7Flags::STREAM; let pkey = include_bytes!("../test/key.pem"); let pkey = PKey::private_key_from_pem(pkey).unwrap(); let mut store_builder = X509StoreBuilder::new().expect("should succeed"); let root_ca = include_bytes!("../test/root-ca.pem"); let root_ca = X509::from_pem(root_ca).unwrap(); store_builder.add_cert(root_ca).expect("should succeed"); let store = store_builder.build(); let pkcs7 = Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed"); let signed = pkcs7 .to_smime(message.as_bytes(), flags) .expect("should succeed"); let (pkcs7_decoded, content) = Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); let mut output = Vec::new(); pkcs7_decoded .verify(&certs, &store, None, Some(&mut output), flags) .expect("should succeed"); assert_eq!(message.clone().into_bytes(), output); assert!(content.is_none()); } #[test] fn invalid_from_smime() { let input = String::from("Invalid SMIME Message"); let result = Pkcs7::from_smime(input.as_bytes()); assert_eq!(result.is_err(), true) } } openssl-0.10.23/src/pkey.rs010064400017500001750000000505021346222217000136670ustar0000000000000000//! Public/private key processing. //! //! Asymmetric public key algorithms solve the problem of establishing and sharing //! secret keys to securely send and receive messages. //! This system uses a pair of keys: a public key, which can be freely //! distributed, and a private key, which is kept to oneself. An entity may //! encrypt information using a user's public key. The encrypted information can //! only be deciphered using that user's private key. //! //! This module offers support for five popular algorithms: //! //! * RSA //! //! * DSA //! //! * Diffie-Hellman //! //! * Elliptic Curves //! //! * HMAC //! //! These algorithms rely on hard mathematical problems - namely integer factorization, //! discrete logarithms, and elliptic curve relationships - that currently do not //! yield efficient solutions. This property ensures the security of these //! cryptographic algorithms. //! //! # Example //! //! Generate a 2048-bit RSA public/private key pair and print the public key. //! //! ```rust //! //! extern crate openssl; //! //! use openssl::rsa::Rsa; //! use openssl::pkey::PKey; //! use std::str; //! //! fn main() { //! let rsa = Rsa::generate(2048).unwrap(); //! let pkey = PKey::from_rsa(rsa).unwrap(); //! //! let pub_key: Vec = pkey.public_key_to_pem().unwrap(); //! println!("{:?}", str::from_utf8(pub_key.as_slice()).unwrap()); //! } //! ``` use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::ffi::CString; use std::mem; use std::ptr; use bio::MemBioSlice; use dh::Dh; use dsa::Dsa; use ec::EcKey; 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 {} /// A tag type indicating that a key only has public components. pub enum Public {} /// A tag type indicating that a key has private components. pub enum Private {} /// An identifier of a kind of key. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Id(c_int); impl Id { /// Creates a `Id` from an integer representation. pub fn from_raw(value: c_int) -> Id { Id(value) } /// Returns the integer representation of the `Id`. pub fn as_raw(&self) -> c_int { self.0 } pub const RSA: Id = Id(ffi::EVP_PKEY_RSA); pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC); pub const DSA: Id = Id(ffi::EVP_PKEY_DSA); pub const DH: Id = Id(ffi::EVP_PKEY_DH); pub const EC: Id = Id(ffi::EVP_PKEY_EC); } /// A trait indicating that a key has parameters. pub unsafe trait HasParams {} unsafe impl HasParams for Params {} 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 {} /// A trait indicating that a key has private components. pub unsafe trait HasPrivate {} unsafe impl HasPrivate for Private {} generic_foreign_type_and_impl_send_sync! { type CType = ffi::EVP_PKEY; fn drop = ffi::EVP_PKEY_free; /// A public or private key. pub struct PKey; /// Reference to `PKey`. pub struct PKeyRef; } impl PKeyRef { /// Returns a copy of the internal RSA key. /// /// This corresponds to [`EVP_PKEY_get1_RSA`]. /// /// [`EVP_PKEY_get1_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_RSA.html pub fn rsa(&self) -> Result, ErrorStack> { unsafe { let rsa = cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))?; Ok(Rsa::from_ptr(rsa)) } } /// Returns a copy of the internal DSA key. /// /// This corresponds to [`EVP_PKEY_get1_DSA`]. /// /// [`EVP_PKEY_get1_DSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DSA.html pub fn dsa(&self) -> Result, ErrorStack> { unsafe { let dsa = cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))?; Ok(Dsa::from_ptr(dsa)) } } /// Returns a copy of the internal DH key. /// /// This corresponds to [`EVP_PKEY_get1_DH`]. /// /// [`EVP_PKEY_get1_DH`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_DH.html pub fn dh(&self) -> Result, ErrorStack> { unsafe { let dh = cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))?; Ok(Dh::from_ptr(dh)) } } /// Returns a copy of the internal elliptic curve key. /// /// This corresponds to [`EVP_PKEY_get1_EC_KEY`]. /// /// [`EVP_PKEY_get1_EC_KEY`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_get1_EC_KEY.html pub fn ec_key(&self) -> Result, ErrorStack> { unsafe { let ec_key = cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))?; Ok(EcKey::from_ptr(ec_key)) } } /// Returns the `Id` that represents the type of this key. /// /// This corresponds to [`EVP_PKEY_id`]. /// /// [`EVP_PKEY_id`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_id.html 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 where T: HasPublic, { to_pem! { /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. /// /// This corresponds to [`PEM_write_bio_PUBKEY`]. /// /// [`PEM_write_bio_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_PUBKEY.html public_key_to_pem, ffi::PEM_write_bio_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. /// /// This corresponds to [`i2d_PUBKEY`]. /// /// [`i2d_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_PUBKEY.html public_key_to_der, ffi::i2d_PUBKEY } /// Returns the size of the key. /// /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the /// group order for an elliptic curve key, for example. pub fn bits(&self) -> u32 { unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 } } /// Compares the public component of this key with another. pub fn public_eq(&self, other: &PKeyRef) -> bool where U: HasPublic, { unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } } } impl PKeyRef where T: HasPrivate, { private_key_to_pem! { /// Serializes the private key to a PEM-encoded PKCS#8 PrivateKeyInfo structure. /// /// The output will have a header of `-----BEGIN PRIVATE KEY-----`. /// /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`]. /// /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html private_key_to_pem_pkcs8, /// Serializes the private key to a PEM-encoded PKCS#8 EncryptedPrivateKeyInfo structure. /// /// The output will have a header of `-----BEGIN ENCRYPTED PRIVATE KEY-----`. /// /// This corresponds to [`PEM_write_bio_PKCS8PrivateKey`]. /// /// [`PEM_write_bio_PKCS8PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_PKCS8PrivateKey.html private_key_to_pem_pkcs8_passphrase, ffi::PEM_write_bio_PKCS8PrivateKey } to_der! { /// Serializes the private key to a DER-encoded key type specific format. /// /// This corresponds to [`i2d_PrivateKey`]. /// /// [`i2d_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_PrivateKey.html private_key_to_der, ffi::i2d_PrivateKey } } impl PKey { /// Creates a new `PKey` containing an RSA key. /// /// This corresponds to [`EVP_PKEY_assign_RSA`]. /// /// [`EVP_PKEY_assign_RSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_RSA.html pub fn from_rsa(rsa: Rsa) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); cvt(ffi::EVP_PKEY_assign( pkey.0, ffi::EVP_PKEY_RSA, rsa.as_ptr() as *mut _, ))?; mem::forget(rsa); Ok(pkey) } } /// Creates a new `PKey` containing a DSA key. /// /// This corresponds to [`EVP_PKEY_assign_DSA`]. /// /// [`EVP_PKEY_assign_DSA`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_DSA.html pub fn from_dsa(dsa: Dsa) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); cvt(ffi::EVP_PKEY_assign( pkey.0, ffi::EVP_PKEY_DSA, dsa.as_ptr() as *mut _, ))?; mem::forget(dsa); Ok(pkey) } } /// Creates a new `PKey` containing a Diffie-Hellman key. /// /// This corresponds to [`EVP_PKEY_assign_DH`]. /// /// [`EVP_PKEY_assign_DH`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_DH.html pub fn from_dh(dh: Dh) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); cvt(ffi::EVP_PKEY_assign( pkey.0, ffi::EVP_PKEY_DH, dh.as_ptr() as *mut _, ))?; mem::forget(dh); Ok(pkey) } } /// Creates a new `PKey` containing an elliptic curve key. /// /// This corresponds to [`EVP_PKEY_assign_EC_KEY`]. /// /// [`EVP_PKEY_assign_EC_KEY`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_assign_EC_KEY.html pub fn from_ec_key(ec_key: EcKey) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); cvt(ffi::EVP_PKEY_assign( pkey.0, ffi::EVP_PKEY_EC, ec_key.as_ptr() as *mut _, ))?; mem::forget(ec_key); Ok(pkey) } } } impl PKey { /// Creates a new `PKey` containing an HMAC key. /// /// # Note /// /// To compute HMAC values, use the `sign` module. pub fn hmac(key: &[u8]) -> Result, ErrorStack> { unsafe { assert!(key.len() <= c_int::max_value() as usize); let key = cvt_p(ffi::EVP_PKEY_new_mac_key( ffi::EVP_PKEY_HMAC, ptr::null_mut(), key.as_ptr() as *const _, key.len() as c_int, ))?; Ok(PKey::from_ptr(key)) } } /// Creates a new `PKey` containing a CMAC key. /// /// Requires OpenSSL 1.1.0 or newer. /// /// # Note /// /// To compute CMAC values, use the `sign` module. #[cfg(ossl110)] pub fn cmac(cipher: &::symm::Cipher, key: &[u8]) -> Result, ErrorStack> { unsafe { assert!(key.len() <= c_int::max_value() as usize); let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id( ffi::EVP_PKEY_CMAC, ptr::null_mut(), ))?; let ret = (|| { cvt(ffi::EVP_PKEY_keygen_init(kctx))?; // Set cipher for cmac cvt(ffi::EVP_PKEY_CTX_ctrl( kctx, -1, ffi::EVP_PKEY_OP_KEYGEN, ffi::EVP_PKEY_CTRL_CIPHER, 0, cipher.as_ptr() as *mut _, ))?; // Set the key data cvt(ffi::EVP_PKEY_CTX_ctrl( kctx, -1, ffi::EVP_PKEY_OP_KEYGEN, ffi::EVP_PKEY_CTRL_SET_MAC_KEY, key.len() as c_int, key.as_ptr() as *mut _, ))?; Ok(()) })(); if let Err(e) = ret { // Free memory ffi::EVP_PKEY_CTX_free(kctx); return Err(e); } // Generate key let mut key = ptr::null_mut(); let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key)); // Free memory ffi::EVP_PKEY_CTX_free(kctx); if let Err(e) = ret { return Err(e); } Ok(PKey::from_ptr(key)) } } private_key_from_pem! { /// Deserializes a private key from a PEM-encoded key type specific format. /// /// This corresponds to [`PEM_read_bio_PrivateKey`]. /// /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html private_key_from_pem, /// Deserializes a private key from a PEM-encoded encrypted key type specific format. /// /// This corresponds to [`PEM_read_bio_PrivateKey`]. /// /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html private_key_from_pem_passphrase, /// Deserializes a private key from a PEM-encoded encrypted key type specific format. /// /// The callback should fill the password into the provided buffer and return its length. /// /// This corresponds to [`PEM_read_bio_PrivateKey`]. /// /// [`PEM_read_bio_PrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_PrivateKey.html private_key_from_pem_callback, PKey, ffi::PEM_read_bio_PrivateKey } from_der! { /// Decodes a DER-encoded private key. /// /// This function will automatically attempt to detect the underlying key format, and /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific /// formats. /// /// This corresponds to [`d2i_AutoPrivateKey`]. /// /// [`d2i_AutoPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_AutoPrivateKey.html private_key_from_der, PKey, ffi::d2i_AutoPrivateKey } /// Deserializes a DER-formatted PKCS#8 private key, using a callback to retrieve the password /// if the key is encrpyted. /// /// The callback should copy the password into the provided buffer and return the number of /// bytes written. pub fn private_key_from_pkcs8_callback( der: &[u8], callback: F, ) -> Result, ErrorStack> where F: FnOnce(&mut [u8]) -> Result, { unsafe { ffi::init(); let mut cb = CallbackState::new(callback); let bio = MemBioSlice::new(der)?; cvt_p(ffi::d2i_PKCS8PrivateKey_bio( bio.as_ptr(), ptr::null_mut(), Some(invoke_passwd_cb::), &mut cb as *mut _ as *mut _, )) .map(|p| PKey::from_ptr(p)) } } /// Deserializes a DER-formatted PKCS#8 private key, using the supplied password if the key is /// encrypted. /// /// # Panics /// /// Panics if `passphrase` contains an embedded null. pub fn private_key_from_pkcs8_passphrase( der: &[u8], passphrase: &[u8], ) -> Result, ErrorStack> { unsafe { ffi::init(); let bio = MemBioSlice::new(der)?; let passphrase = CString::new(passphrase).unwrap(); cvt_p(ffi::d2i_PKCS8PrivateKey_bio( bio.as_ptr(), ptr::null_mut(), None, passphrase.as_ptr() as *const _ as *mut _, )) .map(|p| PKey::from_ptr(p)) } } } impl PKey { from_pem! { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. /// /// This corresponds to [`PEM_read_bio_PUBKEY`]. /// /// [`PEM_read_bio_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_PUBKEY.html public_key_from_pem, PKey, ffi::PEM_read_bio_PUBKEY } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure. /// /// This corresponds to [`d2i_PUBKEY`]. /// /// [`d2i_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_PUBKEY.html public_key_from_der, PKey, ffi::d2i_PUBKEY } } #[cfg(test)] mod tests { use dh::Dh; use dsa::Dsa; use ec::EcKey; use nid::Nid; use rsa::Rsa; use symm::Cipher; use super::*; #[test] 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") .unwrap(); PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); } #[test] fn test_encrypted_pkcs8_passphrase() { let key = include_bytes!("../test/pkcs8.der"); PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap(); } #[test] fn test_encrypted_pkcs8_callback() { let mut password_queried = false; let key = include_bytes!("../test/pkcs8.der"); PKey::private_key_from_pkcs8_callback(key, |password| { password_queried = true; password[..6].copy_from_slice(b"mypass"); Ok(6) }) .unwrap(); assert!(password_queried); } #[test] fn test_private_key_from_pem() { let key = include_bytes!("../test/key.pem"); PKey::private_key_from_pem(key).unwrap(); } #[test] fn test_public_key_from_pem() { let key = include_bytes!("../test/key.pem.pub"); PKey::public_key_from_pem(key).unwrap(); } #[test] fn test_public_key_from_der() { let key = include_bytes!("../test/key.der.pub"); PKey::public_key_from_der(key).unwrap(); } #[test] fn test_private_key_from_der() { let key = include_bytes!("../test/key.der"); PKey::private_key_from_der(key).unwrap(); } #[test] fn test_pem() { let key = include_bytes!("../test/key.pem"); let key = PKey::private_key_from_pem(key).unwrap(); let priv_key = key.private_key_to_pem_pkcs8().unwrap(); let pub_key = key.public_key_to_pem().unwrap(); // As a super-simple verification, just check that the buffers contain // the `PRIVATE KEY` or `PUBLIC KEY` strings. assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY")); assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY")); } #[test] fn test_rsa_accessor() { let rsa = Rsa::generate(2048).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); pkey.rsa().unwrap(); assert_eq!(pkey.id(), Id::RSA); assert!(pkey.dsa().is_err()); } #[test] fn test_dsa_accessor() { let dsa = Dsa::generate(2048).unwrap(); let pkey = PKey::from_dsa(dsa).unwrap(); pkey.dsa().unwrap(); assert_eq!(pkey.id(), Id::DSA); assert!(pkey.rsa().is_err()); } #[test] fn test_dh_accessor() { let dh = include_bytes!("../test/dhparams.pem"); let dh = Dh::params_from_pem(dh).unwrap(); let pkey = PKey::from_dh(dh).unwrap(); pkey.dh().unwrap(); assert_eq!(pkey.id(), Id::DH); assert!(pkey.rsa().is_err()); } #[test] fn test_ec_key_accessor() { let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let pkey = PKey::from_ec_key(ec_key).unwrap(); pkey.ec_key().unwrap(); assert_eq!(pkey.id(), Id::EC); assert!(pkey.rsa().is_err()); } } openssl-0.10.23/src/rand.rs010064400017500001750000000030241346470244000136450ustar0000000000000000//! Utilities for secure random number generation. //! //! # Examples //! //! To generate a buffer with cryptographically strong bytes: //! //! ``` //! use openssl::rand::rand_bytes; //! //! let mut buf = [0; 256]; //! rand_bytes(&mut buf).unwrap(); //! ``` use ffi; use libc::c_int; use cvt; use error::ErrorStack; /// Fill buffer with cryptographically strong pseudo-random bytes. /// /// This corresponds to [`RAND_bytes`]. /// /// # Examples /// /// To generate a buffer with cryptographically strong bytes: /// /// ``` /// use openssl::rand::rand_bytes; /// /// let mut buf = [0; 256]; /// rand_bytes(&mut buf).unwrap(); /// ``` /// /// [`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(); assert!(buf.len() <= c_int::max_value() as usize); cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as c_int)).map(|_| ()) } } /// Controls random device file descriptor behavior. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`RAND_keep_random_devices_open`]. /// /// [`RAND_keep_random_devices_open`]: https://www.openssl.org/docs/manmaster/man3/RAND_keep_random_devices_open.html #[cfg(ossl111)] pub fn keep_random_devices_open(keep: bool) { unsafe { ffi::RAND_keep_random_devices_open(keep as c_int); } } #[cfg(test)] mod tests { use super::rand_bytes; #[test] fn test_rand_bytes() { let mut buf = [0; 32]; rand_bytes(&mut buf).unwrap(); } } openssl-0.10.23/src/rsa.rs010064400017500001750000000733411346222217000135120ustar0000000000000000//! Rivest–Shamir–Adleman cryptosystem //! //! RSA is one of the earliest asymmetric public key encryption schemes. //! Like many other cryptosystems, RSA relies on the presumed difficulty of a hard //! mathematical problem, namely factorization of the product of two large prime //! numbers. At the moment there does not exist an algorithm that can factor such //! large numbers in reasonable time. RSA is used in a wide variety of //! applications including digital signatures and key exchanges such as //! establishing a TLS/SSL connection. //! //! The RSA acronym is derived from the first letters of the surnames of the //! algorithm's founding trio. //! //! # Example //! //! Generate a 2048-bit RSA key pair and use the public key to encrypt some data. //! //! ```rust //! //! extern crate openssl; //! //! use openssl::rsa::{Rsa, Padding}; //! //! fn main() { //! let rsa = Rsa::generate(2048).unwrap(); //! let data = b"foobar"; //! let mut buf = vec![0; rsa.size() as usize]; //! let encrypted_len = rsa.public_encrypt(data, &mut buf, Padding::PKCS1).unwrap(); //! } //! ``` use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; use std::mem; use std::ptr; use bn::{BigNum, BigNumRef}; use error::ErrorStack; use pkey::{HasPrivate, HasPublic, Private, Public}; use {cvt, cvt_n, cvt_p}; /// Type of encryption padding to use. /// /// Random length padding is primarily used to prevent attackers from /// predicting or knowing the exact length of a plaintext message that /// can possibly lead to breaking encryption. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Padding(c_int); impl Padding { /// Creates a `Padding` from an integer representation. pub fn from_raw(value: c_int) -> Padding { Padding(value) } /// Returns the integer representation of `Padding`. pub fn as_raw(&self) -> c_int { self.0 } pub const NONE: Padding = Padding(ffi::RSA_NO_PADDING); pub const PKCS1: Padding = Padding(ffi::RSA_PKCS1_PADDING); pub const PKCS1_OAEP: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING); pub const PKCS1_PSS: Padding = Padding(ffi::RSA_PKCS1_PSS_PADDING); } generic_foreign_type_and_impl_send_sync! { type CType = ffi::RSA; fn drop = ffi::RSA_free; /// An RSA key. pub struct Rsa; /// Reference to `RSA` pub struct RsaRef; } impl Clone for Rsa { fn clone(&self) -> Rsa { (**self).to_owned() } } impl ToOwned for RsaRef { type Owned = Rsa; fn to_owned(&self) -> Rsa { unsafe { ffi::RSA_up_ref(self.as_ptr()); Rsa::from_ptr(self.as_ptr()) } } } impl RsaRef where T: HasPrivate, { private_key_to_pem! { /// Serializes the private key to a PEM-encoded PKCS#1 RSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`. /// /// This corresponds to [`PEM_write_bio_RSAPrivateKey`]. /// /// [`PEM_write_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_RSAPrivateKey.html private_key_to_pem, /// Serializes the private key to a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN RSA PRIVATE KEY-----`. /// /// This corresponds to [`PEM_write_bio_RSAPrivateKey`]. /// /// [`PEM_write_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_RSAPrivateKey.html private_key_to_pem_passphrase, ffi::PEM_write_bio_RSAPrivateKey } to_der! { /// Serializes the private key to a DER-encoded PKCS#1 RSAPrivateKey structure. /// /// This corresponds to [`i2d_RSAPrivateKey`]. /// /// [`i2d_RSAPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_RSAPrivateKey.html private_key_to_der, ffi::i2d_RSAPrivateKey } /// Decrypts data using the private key, returning the number of decrypted bytes. /// /// # Panics /// /// Panics if `self` has no private components, or if `to` is smaller /// than `self.size()`. pub fn private_decrypt( &self, from: &[u8], to: &mut [u8], padding: Padding, ) -> Result { assert!(from.len() <= i32::max_value() as usize); assert!(to.len() >= self.size() as usize); unsafe { let len = cvt_n(ffi::RSA_private_decrypt( from.len() as c_int, from.as_ptr(), to.as_mut_ptr(), self.as_ptr(), padding.0, ))?; Ok(len as usize) } } /// Encrypts data using the private key, returning the number of encrypted bytes. /// /// # Panics /// /// Panics if `self` has no private components, or if `to` is smaller /// than `self.size()`. pub fn private_encrypt( &self, from: &[u8], to: &mut [u8], padding: Padding, ) -> Result { assert!(from.len() <= i32::max_value() as usize); assert!(to.len() >= self.size() as usize); unsafe { let len = cvt_n(ffi::RSA_private_encrypt( from.len() as c_int, from.as_ptr(), to.as_mut_ptr(), self.as_ptr(), padding.0, ))?; Ok(len as usize) } } /// Returns a reference to the private exponent of the key. /// /// This corresponds to [`RSA_get0_key`]. /// /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn d(&self) -> &BigNumRef { unsafe { let mut d = ptr::null(); RSA_get0_key(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut d); BigNumRef::from_ptr(d as *mut _) } } /// Returns a reference to the first factor of the exponent of the key. /// /// This corresponds to [`RSA_get0_factors`]. /// /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn p(&self) -> Option<&BigNumRef> { unsafe { let mut p = ptr::null(); RSA_get0_factors(self.as_ptr(), &mut p, ptr::null_mut()); if p.is_null() { None } else { Some(BigNumRef::from_ptr(p as *mut _)) } } } /// Returns a reference to the second factor of the exponent of the key. /// /// This corresponds to [`RSA_get0_factors`]. /// /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn q(&self) -> Option<&BigNumRef> { unsafe { let mut q = ptr::null(); RSA_get0_factors(self.as_ptr(), ptr::null_mut(), &mut q); if q.is_null() { None } else { Some(BigNumRef::from_ptr(q as *mut _)) } } } /// Returns a reference to the first exponent used for CRT calculations. /// /// This corresponds to [`RSA_get0_crt_params`]. /// /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn dmp1(&self) -> Option<&BigNumRef> { unsafe { let mut dp = ptr::null(); RSA_get0_crt_params(self.as_ptr(), &mut dp, ptr::null_mut(), ptr::null_mut()); if dp.is_null() { None } else { Some(BigNumRef::from_ptr(dp as *mut _)) } } } /// Returns a reference to the second exponent used for CRT calculations. /// /// This corresponds to [`RSA_get0_crt_params`]. /// /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn dmq1(&self) -> Option<&BigNumRef> { unsafe { let mut dq = ptr::null(); RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), &mut dq, ptr::null_mut()); if dq.is_null() { None } else { Some(BigNumRef::from_ptr(dq as *mut _)) } } } /// Returns a reference to the coefficient used for CRT calculations. /// /// This corresponds to [`RSA_get0_crt_params`]. /// /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn iqmp(&self) -> Option<&BigNumRef> { unsafe { let mut qi = ptr::null(); RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut qi); if qi.is_null() { None } else { Some(BigNumRef::from_ptr(qi as *mut _)) } } } /// 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 where T: HasPublic, { to_pem! { /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. /// /// This corresponds to [`PEM_write_bio_RSA_PUBKEY`]. /// /// [`PEM_write_bio_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/pem.html public_key_to_pem, ffi::PEM_write_bio_RSA_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. /// /// This corresponds to [`i2d_RSA_PUBKEY`]. /// /// [`i2d_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_RSA_PUBKEY.html public_key_to_der, ffi::i2d_RSA_PUBKEY } to_pem! { /// Serializes the public key into a PEM-encoded PKCS#1 RSAPublicKey structure. /// /// The output will have a header of `-----BEGIN RSA PUBLIC KEY-----`. /// /// This corresponds to [`PEM_write_bio_RSAPublicKey`]. /// /// [`PEM_write_bio_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/pem.html public_key_to_pem_pkcs1, ffi::PEM_write_bio_RSAPublicKey } to_der! { /// Serializes the public key into a DER-encoded PKCS#1 RSAPublicKey structure. /// /// This corresponds to [`i2d_RSAPublicKey`]. /// /// [`i2d_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_RSAPublicKey.html public_key_to_der_pkcs1, ffi::i2d_RSAPublicKey } /// Returns the size of the modulus in bytes. /// /// This corresponds to [`RSA_size`]. /// /// [`RSA_size`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_size.html pub fn size(&self) -> u32 { unsafe { ffi::RSA_size(self.as_ptr()) as u32 } } /// Decrypts data using the public key, returning the number of decrypted bytes. /// /// # Panics /// /// Panics if `to` is smaller than `self.size()`. pub fn public_decrypt( &self, from: &[u8], to: &mut [u8], padding: Padding, ) -> Result { assert!(from.len() <= i32::max_value() as usize); assert!(to.len() >= self.size() as usize); unsafe { let len = cvt_n(ffi::RSA_public_decrypt( from.len() as c_int, from.as_ptr(), to.as_mut_ptr(), self.as_ptr(), padding.0, ))?; Ok(len as usize) } } /// Encrypts data using the public key, returning the number of encrypted bytes. /// /// # Panics /// /// Panics if `to` is smaller than `self.size()`. pub fn public_encrypt( &self, from: &[u8], to: &mut [u8], padding: Padding, ) -> Result { assert!(from.len() <= i32::max_value() as usize); assert!(to.len() >= self.size() as usize); unsafe { let len = cvt_n(ffi::RSA_public_encrypt( from.len() as c_int, from.as_ptr(), to.as_mut_ptr(), self.as_ptr(), padding.0, ))?; Ok(len as usize) } } /// Returns a reference to the modulus of the key. /// /// This corresponds to [`RSA_get0_key`]. /// /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn n(&self) -> &BigNumRef { unsafe { let mut n = ptr::null(); RSA_get0_key(self.as_ptr(), &mut n, ptr::null_mut(), ptr::null_mut()); BigNumRef::from_ptr(n as *mut _) } } /// Returns a reference to the public exponent of the key. /// /// This corresponds to [`RSA_get0_key`]. /// /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn e(&self) -> &BigNumRef { unsafe { let mut e = ptr::null(); RSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut e, ptr::null_mut()); BigNumRef::from_ptr(e as *mut _) } } } impl Rsa { /// Creates a new RSA key with only public components. /// /// `n` is the modulus common to both public and private key. /// `e` is the public exponent. /// /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`]. /// /// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html pub fn from_public_components(n: BigNum, e: BigNum) -> Result, ErrorStack> { unsafe { let rsa = cvt_p(ffi::RSA_new())?; RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), ptr::null_mut()); mem::forget((n, e)); Ok(Rsa::from_ptr(rsa)) } } from_pem! { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing an RSA key. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. /// /// This corresponds to [`PEM_read_bio_RSA_PUBKEY`]. /// /// [`PEM_read_bio_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_RSA_PUBKEY.html public_key_from_pem, Rsa, ffi::PEM_read_bio_RSA_PUBKEY } from_pem! { /// Decodes a PEM-encoded PKCS#1 RSAPublicKey structure. /// /// The input should have a header of `-----BEGIN RSA PUBLIC KEY-----`. /// /// This corresponds to [`PEM_read_bio_RSAPublicKey`]. /// /// [`PEM_read_bio_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_RSAPublicKey.html public_key_from_pem_pkcs1, Rsa, ffi::PEM_read_bio_RSAPublicKey } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing an RSA key. /// /// This corresponds to [`d2i_RSA_PUBKEY`]. /// /// [`d2i_RSA_PUBKEY`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html public_key_from_der, Rsa, ffi::d2i_RSA_PUBKEY } from_der! { /// Decodes a DER-encoded PKCS#1 RSAPublicKey structure. /// /// This corresponds to [`d2i_RSAPublicKey`]. /// /// [`d2i_RSAPublicKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html public_key_from_der_pkcs1, Rsa, ffi::d2i_RSAPublicKey } } pub struct RsaPrivateKeyBuilder { rsa: Rsa, } impl RsaPrivateKeyBuilder { /// Creates a new `RsaPrivateKeyBuilder`. /// /// `n` is the modulus common to both public and private key. /// `e` is the public exponent and `d` is the private exponent. /// /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`]. /// /// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result { unsafe { let rsa = cvt_p(ffi::RSA_new())?; RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), d.as_ptr()); mem::forget((n, e, d)); Ok(RsaPrivateKeyBuilder { rsa: Rsa::from_ptr(rsa), }) } } /// Sets the factors of the Rsa key. /// /// `p` and `q` are the first and second factors of `n`. /// /// This correspond to [`RSA_set0_factors`]. /// /// [`RSA_set0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_factors.html // FIXME should be infallible pub fn set_factors(self, p: BigNum, q: BigNum) -> Result { unsafe { RSA_set0_factors(self.rsa.as_ptr(), p.as_ptr(), q.as_ptr()); mem::forget((p, q)); } Ok(self) } /// Sets the Chinese Remainder Theorem params of the Rsa key. /// /// `dmp1`, `dmq1`, and `iqmp` are the exponents and coefficient for /// CRT calculations which is used to speed up RSA operations. /// /// This correspond to [`RSA_set0_crt_params`]. /// /// [`RSA_set0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_crt_params.html // FIXME should be infallible pub fn set_crt_params( self, dmp1: BigNum, dmq1: BigNum, iqmp: BigNum, ) -> Result { unsafe { RSA_set0_crt_params( self.rsa.as_ptr(), dmp1.as_ptr(), dmq1.as_ptr(), iqmp.as_ptr(), ); mem::forget((dmp1, dmq1, iqmp)); } Ok(self) } /// Returns the Rsa key. pub fn build(self) -> Rsa { self.rsa } } impl Rsa { /// Creates a new RSA key with private components (public components are assumed). /// /// This a convenience method over /// `Rsa::build(n, e, d)?.set_factors(p, q)?.set_crt_params(dmp1, dmq1, iqmp)?.build()` pub fn from_private_components( n: BigNum, e: BigNum, d: BigNum, p: BigNum, q: BigNum, dmp1: BigNum, dmq1: BigNum, iqmp: BigNum, ) -> Result, ErrorStack> { Ok(RsaPrivateKeyBuilder::new(n, e, d)? .set_factors(p, q)? .set_crt_params(dmp1, dmq1, iqmp)? .build()) } /// 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> { 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())?); cvt(ffi::RSA_generate_key_ex( rsa.0, bits as c_int, e.as_ptr(), ptr::null_mut(), ))?; Ok(rsa) } } // FIXME these need to identify input formats private_key_from_pem! { /// Deserializes a private key from a PEM-encoded PKCS#1 RSAPrivateKey structure. /// /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. /// /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html private_key_from_pem, /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. /// /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. /// /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html private_key_from_pem_passphrase, /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. /// /// The callback should fill the password into the provided buffer and return its length. /// /// This corresponds to [`PEM_read_bio_RSAPrivateKey`]. /// /// [`PEM_read_bio_RSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_RSAPrivateKey.html private_key_from_pem_callback, Rsa, ffi::PEM_read_bio_RSAPrivateKey } from_der! { /// Decodes a DER-encoded PKCS#1 RSAPrivateKey structure. /// /// This corresponds to [`d2i_RSAPrivateKey`]. /// /// [`d2i_RSAPrivateKey`]: https://www.openssl.org/docs/man1.0.2/crypto/d2i_RSA_PUBKEY.html private_key_from_der, Rsa, ffi::d2i_RSAPrivateKey } } impl fmt::Debug for Rsa { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Rsa") } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{ RSA_get0_key, RSA_get0_factors, RSA_get0_crt_params, RSA_set0_key, RSA_set0_factors, RSA_set0_crt_params, }; } else { #[allow(bad_style)] unsafe fn RSA_get0_key( r: *const ffi::RSA, n: *mut *const ffi::BIGNUM, e: *mut *const ffi::BIGNUM, d: *mut *const ffi::BIGNUM, ) { if !n.is_null() { *n = (*r).n; } if !e.is_null() { *e = (*r).e; } if !d.is_null() { *d = (*r).d; } } #[allow(bad_style)] unsafe fn RSA_get0_factors( r: *const ffi::RSA, p: *mut *const ffi::BIGNUM, q: *mut *const ffi::BIGNUM, ) { if !p.is_null() { *p = (*r).p; } if !q.is_null() { *q = (*r).q; } } #[allow(bad_style)] unsafe fn RSA_get0_crt_params( r: *const ffi::RSA, dmp1: *mut *const ffi::BIGNUM, dmq1: *mut *const ffi::BIGNUM, iqmp: *mut *const ffi::BIGNUM, ) { if !dmp1.is_null() { *dmp1 = (*r).dmp1; } if !dmq1.is_null() { *dmq1 = (*r).dmq1; } if !iqmp.is_null() { *iqmp = (*r).iqmp; } } #[allow(bad_style)] unsafe fn RSA_set0_key( r: *mut ffi::RSA, n: *mut ffi::BIGNUM, e: *mut ffi::BIGNUM, d: *mut ffi::BIGNUM, ) -> c_int { (*r).n = n; (*r).e = e; (*r).d = d; 1 } #[allow(bad_style)] unsafe fn RSA_set0_factors( r: *mut ffi::RSA, p: *mut ffi::BIGNUM, q: *mut ffi::BIGNUM, ) -> c_int { (*r).p = p; (*r).q = q; 1 } #[allow(bad_style)] unsafe fn RSA_set0_crt_params( r: *mut ffi::RSA, dmp1: *mut ffi::BIGNUM, dmq1: *mut ffi::BIGNUM, iqmp: *mut ffi::BIGNUM, ) -> c_int { (*r).dmp1 = dmp1; (*r).dmq1 = dmq1; (*r).iqmp = iqmp; 1 } } } #[cfg(test)] mod test { use symm::Cipher; use super::*; #[test] fn test_from_password() { let key = include_bytes!("../test/rsa-encrypted.pem"); Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); } #[test] fn test_from_password_callback() { let mut password_queried = false; let key = include_bytes!("../test/rsa-encrypted.pem"); Rsa::private_key_from_pem_callback(key, |password| { password_queried = true; password[..6].copy_from_slice(b"mypass"); Ok(6) }) .unwrap(); assert!(password_queried); } #[test] fn test_to_password() { let key = Rsa::generate(2048).unwrap(); let pem = key .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") .unwrap(); Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); } #[test] fn test_public_encrypt_private_decrypt_with_padding() { let key = include_bytes!("../test/rsa.pem.pub"); let public_key = Rsa::public_key_from_pem(key).unwrap(); let mut result = vec![0; public_key.size() as usize]; let original_data = b"This is test"; let len = public_key .public_encrypt(original_data, &mut result, Padding::PKCS1) .unwrap(); assert_eq!(len, 256); let pkey = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(pkey).unwrap(); let mut dec_result = vec![0; private_key.size() as usize]; let len = private_key .private_decrypt(&result, &mut dec_result, Padding::PKCS1) .unwrap(); assert_eq!(&dec_result[..len], original_data); } #[test] fn test_private_encrypt() { let k0 = super::Rsa::generate(512).unwrap(); let k0pkey = k0.public_key_to_pem().unwrap(); let k1 = super::Rsa::public_key_from_pem(&k0pkey).unwrap(); let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; let mut emesg = vec![0; k0.size() as usize]; k0.private_encrypt(&msg, &mut emesg, Padding::PKCS1) .unwrap(); let mut dmesg = vec![0; k1.size() as usize]; let len = k1 .public_decrypt(&emesg, &mut dmesg, Padding::PKCS1) .unwrap(); assert_eq!(msg, &dmesg[..len]); } #[test] fn test_public_encrypt() { let k0 = super::Rsa::generate(512).unwrap(); let k0pkey = k0.private_key_to_pem().unwrap(); let k1 = super::Rsa::private_key_from_pem(&k0pkey).unwrap(); let msg = vec![0xdeu8, 0xadu8, 0xd0u8, 0x0du8]; let mut emesg = vec![0; k0.size() as usize]; k0.public_encrypt(&msg, &mut emesg, Padding::PKCS1).unwrap(); let mut dmesg = vec![0; k1.size() as usize]; let len = k1 .private_decrypt(&emesg, &mut dmesg, Padding::PKCS1) .unwrap(); assert_eq!(msg, &dmesg[..len]); } #[test] fn test_public_key_from_pem_pkcs1() { let key = include_bytes!("../test/pkcs1.pem.pub"); Rsa::public_key_from_pem_pkcs1(key).unwrap(); } #[test] #[should_panic] fn test_public_key_from_pem_pkcs1_file_panic() { let key = include_bytes!("../test/key.pem.pub"); Rsa::public_key_from_pem_pkcs1(key).unwrap(); } #[test] fn test_public_key_to_pem_pkcs1() { let keypair = super::Rsa::generate(512).unwrap(); let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); } #[test] #[should_panic] fn test_public_key_from_pem_pkcs1_generate_panic() { let keypair = super::Rsa::generate(512).unwrap(); let pubkey_pem = keypair.public_key_to_pem().unwrap(); super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); } #[test] fn test_pem_pkcs1_encrypt() { let keypair = super::Rsa::generate(2048).unwrap(); let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); let msg = "Hello, world!".as_bytes(); let mut encrypted = vec![0; pubkey.size() as usize]; let len = pubkey .public_encrypt(&msg, &mut encrypted, Padding::PKCS1) .unwrap(); assert!(len > msg.len()); let mut decrypted = vec![0; keypair.size() as usize]; let len = keypair .private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1) .unwrap(); assert_eq!(len, msg.len()); assert_eq!("Hello, world!", String::from_utf8_lossy(&decrypted[..len])); } #[test] fn test_pem_pkcs1_padding() { let keypair = super::Rsa::generate(2048).unwrap(); let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); let msg = "foo".as_bytes(); let mut encrypted1 = vec![0; pubkey.size() as usize]; let mut encrypted2 = vec![0; pubkey.size() as usize]; let len1 = pubkey .public_encrypt(&msg, &mut encrypted1, Padding::PKCS1) .unwrap(); let len2 = pubkey .public_encrypt(&msg, &mut encrypted2, Padding::PKCS1) .unwrap(); assert!(len1 > (msg.len() + 1)); assert_eq!(len1, len2); assert_ne!(encrypted1, encrypted2); } #[test] fn clone() { 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(); } } openssl-0.10.23/src/sha.rs010064400017500001750000000243261346222217000134770ustar0000000000000000//! The SHA family of hashes. //! //! SHA, or Secure Hash Algorithms, are a family of cryptographic hashing algorithms published by //! the National Institute of Standards and Technology (NIST). Hash algorithms such as those in //! the SHA family are used to map data of an arbitrary size to a fixed-size string of bytes. //! As cryptographic hashing algorithms, these mappings have the property of being irreversable. //! This property makes hash algorithms like these excellent for uses such as verifying the //! contents of a file- if you know the hash you expect beforehand, then you can verify that the //! data you have is correct if it hashes to the same value. //! //! # Examples //! //! When dealing with data that becomes available in chunks, such as while buffering data from IO, //! you can create a hasher that you can repeatedly update to add bytes to. //! //! ```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)); //! } //! ``` //! //! On the other hand, if you already have access to all of the data you woud like to hash, you //! may prefer to use the slightly simpler method of simply calling the hash function corresponding //! to the algorithm you want to use. //! //! ```rust //! extern crate openssl; //! extern crate hex; //! //! use openssl::sha::sha256; //! //! fn main() { //! let hash = sha256(b"your data or message"); //! println!("Hash = {}", hex::encode(hash)); //! } //! ``` use ffi; use libc::c_void; use std::mem; /// Computes the SHA1 hash of some data. /// /// # Warning /// /// SHA1 is known to be insecure - it should not be used unless required for /// compatibility with existing systems. #[inline] pub fn sha1(data: &[u8]) -> [u8; 20] { unsafe { let mut hash: [u8; 20] = mem::uninitialized(); ffi::SHA1(data.as_ptr(), data.len(), hash.as_mut_ptr()); hash } } /// Computes the SHA224 hash of some data. #[inline] pub fn sha224(data: &[u8]) -> [u8; 28] { unsafe { let mut hash: [u8; 28] = mem::uninitialized(); ffi::SHA224(data.as_ptr(), data.len(), hash.as_mut_ptr()); hash } } /// Computes the SHA256 hash of some data. #[inline] pub fn sha256(data: &[u8]) -> [u8; 32] { unsafe { let mut hash: [u8; 32] = mem::uninitialized(); ffi::SHA256(data.as_ptr(), data.len(), hash.as_mut_ptr()); hash } } /// Computes the SHA384 hash of some data. #[inline] pub fn sha384(data: &[u8]) -> [u8; 48] { unsafe { let mut hash: [u8; 48] = mem::uninitialized(); ffi::SHA384(data.as_ptr(), data.len(), hash.as_mut_ptr()); hash } } /// Computes the SHA512 hash of some data. #[inline] pub fn sha512(data: &[u8]) -> [u8; 64] { unsafe { let mut hash: [u8; 64] = mem::uninitialized(); ffi::SHA512(data.as_ptr(), data.len(), hash.as_mut_ptr()); hash } } /// An object which calculates a SHA1 hash of some data. /// /// # Warning /// /// SHA1 is known to be insecure - it should not be used unless required for /// compatibility with existing systems. pub struct Sha1(ffi::SHA_CTX); impl Sha1 { /// Creates a new hasher. #[inline] pub fn new() -> Sha1 { unsafe { let mut ctx = mem::uninitialized(); ffi::SHA1_Init(&mut ctx); Sha1(ctx) } } /// Feeds some data into the hasher. /// /// This can be called multiple times. #[inline] pub fn update(&mut self, buf: &[u8]) { unsafe { ffi::SHA1_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); } } /// Returns the hash of the data. #[inline] pub fn finish(mut self) -> [u8; 20] { unsafe { let mut hash: [u8; 20] = mem::uninitialized(); ffi::SHA1_Final(hash.as_mut_ptr(), &mut self.0); hash } } } /// An object which calculates a SHA224 hash of some data. pub struct Sha224(ffi::SHA256_CTX); impl Sha224 { /// Creates a new hasher. #[inline] pub fn new() -> Sha224 { unsafe { let mut ctx = mem::uninitialized(); ffi::SHA224_Init(&mut ctx); Sha224(ctx) } } /// Feeds some data into the hasher. /// /// This can be called multiple times. #[inline] pub fn update(&mut self, buf: &[u8]) { unsafe { ffi::SHA224_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); } } /// Returns the hash of the data. #[inline] pub fn finish(mut self) -> [u8; 28] { unsafe { let mut hash: [u8; 28] = mem::uninitialized(); ffi::SHA224_Final(hash.as_mut_ptr(), &mut self.0); hash } } } /// An object which calculates a SHA256 hash of some data. pub struct Sha256(ffi::SHA256_CTX); impl Sha256 { /// Creates a new hasher. #[inline] pub fn new() -> Sha256 { unsafe { let mut ctx = mem::uninitialized(); ffi::SHA256_Init(&mut ctx); Sha256(ctx) } } /// Feeds some data into the hasher. /// /// This can be called multiple times. #[inline] pub fn update(&mut self, buf: &[u8]) { unsafe { ffi::SHA256_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); } } /// Returns the hash of the data. #[inline] pub fn finish(mut self) -> [u8; 32] { unsafe { let mut hash: [u8; 32] = mem::uninitialized(); ffi::SHA256_Final(hash.as_mut_ptr(), &mut self.0); hash } } } /// An object which calculates a SHA384 hash of some data. pub struct Sha384(ffi::SHA512_CTX); impl Sha384 { /// Creates a new hasher. #[inline] pub fn new() -> Sha384 { unsafe { let mut ctx = mem::uninitialized(); ffi::SHA384_Init(&mut ctx); Sha384(ctx) } } /// Feeds some data into the hasher. /// /// This can be called multiple times. #[inline] pub fn update(&mut self, buf: &[u8]) { unsafe { ffi::SHA384_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); } } /// Returns the hash of the data. #[inline] pub fn finish(mut self) -> [u8; 48] { unsafe { let mut hash: [u8; 48] = mem::uninitialized(); ffi::SHA384_Final(hash.as_mut_ptr(), &mut self.0); hash } } } /// An object which calculates a SHA512 hash of some data. pub struct Sha512(ffi::SHA512_CTX); impl Sha512 { /// Creates a new hasher. #[inline] pub fn new() -> Sha512 { unsafe { let mut ctx = mem::uninitialized(); ffi::SHA512_Init(&mut ctx); Sha512(ctx) } } /// Feeds some data into the hasher. /// /// This can be called multiple times. #[inline] pub fn update(&mut self, buf: &[u8]) { unsafe { ffi::SHA512_Update(&mut self.0, buf.as_ptr() as *const c_void, buf.len()); } } /// Returns the hash of the data. #[inline] pub fn finish(mut self) -> [u8; 64] { unsafe { let mut hash: [u8; 64] = mem::uninitialized(); ffi::SHA512_Final(hash.as_mut_ptr(), &mut self.0); hash } } } #[cfg(test)] mod test { use hex; use super::*; #[test] fn standalone_1() { let data = b"abc"; let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; assert_eq!(hex::encode(sha1(data)), expected); } #[test] fn struct_1() { let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; let mut hasher = Sha1::new(); hasher.update(b"a"); hasher.update(b"bc"); assert_eq!(hex::encode(hasher.finish()), expected); } #[test] fn standalone_224() { let data = b"abc"; let expected = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; assert_eq!(hex::encode(sha224(data)), expected); } #[test] fn struct_224() { let expected = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; let mut hasher = Sha224::new(); hasher.update(b"a"); hasher.update(b"bc"); assert_eq!(hex::encode(hasher.finish()), expected); } #[test] fn standalone_256() { let data = b"abc"; let expected = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; assert_eq!(hex::encode(sha256(data)), expected); } #[test] fn struct_256() { let expected = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; let mut hasher = Sha256::new(); hasher.update(b"a"); hasher.update(b"bc"); assert_eq!(hex::encode(hasher.finish()), expected); } #[test] fn standalone_384() { let data = b"abc"; let expected = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ 7cc2358baeca134c825a7"; assert_eq!(hex::encode(&sha384(data)[..]), expected); } #[test] fn struct_384() { let expected = "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e\ 7cc2358baeca134c825a7"; let mut hasher = Sha384::new(); hasher.update(b"a"); hasher.update(b"bc"); assert_eq!(hex::encode(&hasher.finish()[..]), expected); } #[test] fn standalone_512() { let data = b"abc"; let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; assert_eq!(hex::encode(&sha512(data)[..]), expected); } #[test] fn struct_512() { let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274\ fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; let mut hasher = Sha512::new(); hasher.update(b"a"); hasher.update(b"bc"); assert_eq!(hex::encode(&hasher.finish()[..]), expected); } } openssl-0.10.23/src/sign.rs010064400017500001750000000575731346222217000136760ustar0000000000000000//! Message signatures. //! //! The `Signer` allows for the computation of cryptographic signatures of //! data given a private key. The `Verifier` can then be used with the //! corresponding public key to verify the integrity and authenticity of that //! data given the signature. //! //! # Examples //! //! Sign and verify data given an RSA keypair: //! //! ```rust //! use openssl::sign::{Signer, Verifier}; //! use openssl::rsa::Rsa; //! use openssl::pkey::PKey; //! use openssl::hash::MessageDigest; //! //! // Generate a keypair //! let keypair = Rsa::generate(2048).unwrap(); //! let keypair = PKey::from_rsa(keypair).unwrap(); //! //! let data = b"hello, world!"; //! let data2 = b"hola, mundo!"; //! //! // Sign the data //! let mut signer = Signer::new(MessageDigest::sha256(), &keypair).unwrap(); //! signer.update(data).unwrap(); //! signer.update(data2).unwrap(); //! let signature = signer.sign_to_vec().unwrap(); //! //! // Verify the data //! let mut verifier = Verifier::new(MessageDigest::sha256(), &keypair).unwrap(); //! verifier.update(data).unwrap(); //! verifier.update(data2).unwrap(); //! assert!(verifier.verify(&signature).unwrap()); //! ``` //! //! Compute an HMAC: //! //! ```rust //! use openssl::hash::MessageDigest; //! use openssl::memcmp; //! use openssl::pkey::PKey; //! use openssl::sign::Signer; //! //! // Create a PKey //! let key = PKey::hmac(b"my secret").unwrap(); //! //! let data = b"hello, world!"; //! let data2 = b"hola, mundo!"; //! //! // Compute the HMAC //! let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap(); //! signer.update(data).unwrap(); //! signer.update(data2).unwrap(); //! let hmac = signer.sign_to_vec().unwrap(); //! //! // `Verifier` cannot be used with HMACs; use the `memcmp::eq` function instead //! // //! // Do not simply check for equality with `==`! //! # let target = hmac.clone(); //! assert!(memcmp::eq(&hmac, &target)); //! ``` use ffi; use foreign_types::ForeignTypeRef; use libc::c_int; use std::io::{self, Write}; use std::marker::PhantomData; use std::ptr; use error::ErrorStack; use hash::MessageDigest; use pkey::{HasPrivate, HasPublic, PKeyRef}; use rsa::Padding; use {cvt, cvt_p}; cfg_if! { if #[cfg(ossl110)] { use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; } else { use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; } } /// Salt lengths that must be used with `set_rsa_pss_saltlen`. pub struct RsaPssSaltlen(c_int); impl RsaPssSaltlen { /// Returns the integer representation of `RsaPssSaltlen`. fn as_raw(&self) -> c_int { self.0 } /// Sets the salt length to the given value. pub fn custom(val: c_int) -> RsaPssSaltlen { RsaPssSaltlen(val) } /// The salt length is set to the digest length. /// Corresponds to the special value `-1`. pub const DIGEST_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-1); /// The salt length is set to the maximum permissible value. /// Corresponds to the special value `-2`. pub const MAXIMUM_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-2); } /// A type which computes cryptographic signatures of data. pub struct Signer<'a> { md_ctx: *mut ffi::EVP_MD_CTX, pctx: *mut ffi::EVP_PKEY_CTX, _p: PhantomData<&'a ()>, } unsafe impl<'a> Sync for Signer<'a> {} unsafe impl<'a> Send for Signer<'a> {} impl<'a> Drop for Signer<'a> { fn drop(&mut self) { // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. unsafe { EVP_MD_CTX_free(self.md_ctx); } } } impl<'a> Signer<'a> { /// Creates a new `Signer`. /// /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { Self::new_intern(Some(type_), pkey) } /// Creates a new `Signer` without a digest. /// /// This can be used to create a CMAC. /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { Self::new_intern(None, pkey) } pub fn new_intern( type_: Option, pkey: &'a PKeyRef, ) -> Result, ErrorStack> where T: HasPrivate, { unsafe { ffi::init(); let ctx = cvt_p(EVP_MD_CTX_new())?; let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut(); let r = ffi::EVP_DigestSignInit( ctx, &mut pctx, type_.map(|t| t.as_ptr()).unwrap_or(ptr::null()), ptr::null_mut(), pkey.as_ptr(), ); if r != 1 { EVP_MD_CTX_free(ctx); return Err(ErrorStack::get()); } assert!(!pctx.is_null()); Ok(Signer { md_ctx: ctx, pctx, _p: PhantomData, }) } } /// Returns the RSA padding mode in use. /// /// This is only useful for RSA keys. /// /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. pub fn rsa_padding(&self) -> Result { unsafe { let mut pad = 0; cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) .map(|_| Padding::from_raw(pad)) } } /// Sets the RSA padding mode. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. /// /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( self.pctx, padding.as_raw(), )) .map(|_| ()) } } /// Sets the RSA PSS salt length. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. /// /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( self.pctx, len.as_raw(), )) .map(|_| ()) } } /// Sets the RSA MGF1 algorithm. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. /// /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( self.pctx, md.as_ptr() as *mut _, )) .map(|_| ()) } } /// Feeds more data into the `Signer`. /// /// OpenSSL documentation at [`EVP_DigestUpdate`]. /// /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestUpdate( self.md_ctx, buf.as_ptr() as *const _, buf.len(), )) .map(|_| ()) } } /// Computes an upper bound on the signature length. /// /// The actual signature may be shorter than this value. Check the return value of /// `sign` to get the exact length. /// /// OpenSSL documentation at [`EVP_DigestSignFinal`]. /// /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html pub fn len(&self) -> Result { unsafe { let mut len = 0; cvt(ffi::EVP_DigestSignFinal( self.md_ctx, ptr::null_mut(), &mut len, ))?; Ok(len) } } /// Writes the signature into the provided buffer, returning the number of bytes written. /// /// This method will fail if the buffer is not large enough for the signature. Use the `len` /// method to get an upper bound on the required size. /// /// OpenSSL documentation at [`EVP_DigestSignFinal`]. /// /// [`EVP_DigestSignFinal`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestSignFinal.html pub fn sign(&self, buf: &mut [u8]) -> Result { unsafe { let mut len = buf.len(); cvt(ffi::EVP_DigestSignFinal( self.md_ctx, buf.as_mut_ptr() as *mut _, &mut len, ))?; Ok(len) } } /// Returns the signature. /// /// This is a simple convenience wrapper over `len` and `sign`. pub fn sign_to_vec(&self) -> Result, ErrorStack> { let mut buf = vec![0; self.len()?]; let len = self.sign(&mut buf)?; // The advertised length is not always equal to the real length for things like DSA buf.truncate(len); Ok(buf) } } impl<'a> Write for Signer<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { self.update(buf)?; Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } pub struct Verifier<'a> { md_ctx: *mut ffi::EVP_MD_CTX, pctx: *mut ffi::EVP_PKEY_CTX, pkey_pd: PhantomData<&'a ()>, } unsafe impl<'a> Sync for Verifier<'a> {} unsafe impl<'a> Send for Verifier<'a> {} impl<'a> Drop for Verifier<'a> { fn drop(&mut self) { // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. unsafe { EVP_MD_CTX_free(self.md_ctx); } } } /// A type which verifies cryptographic signatures of data. impl<'a> Verifier<'a> { /// Creates a new `Verifier`. /// /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. /// /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPublic, { unsafe { ffi::init(); let ctx = cvt_p(EVP_MD_CTX_new())?; let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut(); let r = ffi::EVP_DigestVerifyInit( ctx, &mut pctx, type_.as_ptr(), ptr::null_mut(), pkey.as_ptr(), ); if r != 1 { EVP_MD_CTX_free(ctx); return Err(ErrorStack::get()); } assert!(!pctx.is_null()); Ok(Verifier { md_ctx: ctx, pctx, pkey_pd: PhantomData, }) } } /// Returns the RSA padding mode in use. /// /// This is only useful for RSA keys. /// /// This corresponds to `EVP_PKEY_CTX_get_rsa_padding`. pub fn rsa_padding(&self) -> Result { unsafe { let mut pad = 0; cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.pctx, &mut pad)) .map(|_| Padding::from_raw(pad)) } } /// Sets the RSA padding mode. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_padding`]. /// /// [`EVP_PKEY_CTX_set_rsa_padding`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_padding.html pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( self.pctx, padding.as_raw(), )) .map(|_| ()) } } /// Sets the RSA PSS salt length. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]. /// /// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( self.pctx, len.as_raw(), )) .map(|_| ()) } } /// Sets the RSA MGF1 algorithm. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`]. /// /// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( self.pctx, md.as_ptr() as *mut _, )) .map(|_| ()) } } /// Feeds more data into the `Verifier`. /// /// OpenSSL documentation at [`EVP_DigestUpdate`]. /// /// [`EVP_DigestUpdate`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestInit.html pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestUpdate( self.md_ctx, buf.as_ptr() as *const _, buf.len(), )) .map(|_| ()) } } /// Determines if the data fed into the `Verifier` matches the provided signature. /// /// OpenSSL documentation at [`EVP_DigestVerifyFinal`]. /// /// [`EVP_DigestVerifyFinal`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyFinal.html pub fn verify(&self, signature: &[u8]) -> Result { unsafe { let r = EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *mut _, signature.len()); match r { 1 => Ok(true), 0 => { ErrorStack::get(); // discard error stack Ok(false) } _ => Err(ErrorStack::get()), } } } } impl<'a> Write for Verifier<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { self.update(buf)?; Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } #[cfg(not(ossl101))] use ffi::EVP_DigestVerifyFinal; #[cfg(ossl101)] #[allow(bad_style)] unsafe fn EVP_DigestVerifyFinal( ctx: *mut ffi::EVP_MD_CTX, sigret: *const ::libc::c_uchar, siglen: ::libc::size_t, ) -> ::libc::c_int { ffi::EVP_DigestVerifyFinal(ctx, sigret as *mut _, siglen) } #[cfg(test)] mod test { use hex::{self, FromHex}; use std::iter; use ec::{EcGroup, EcKey}; use hash::MessageDigest; use nid::Nid; use pkey::PKey; use rsa::{Padding, Rsa}; use sign::{RsaPssSaltlen, Signer, Verifier}; const INPUT: &'static str = "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ 654841694f6a457a4d4441344d546b7a4f44417344516f67496d6830644841364c79396c654746746347786c4c\ 6d4e76625339706331397962323930496a7030636e566c6651"; const SIGNATURE: &'static str = "702e218943e88fd11eb5d82dbf7845f34106ae1b81fff7731116add1717d83656d420afd3c96eedd73a2663e51\ 66687b000b87226e0187ed1073f945e582adfcef16d85a798ee8c66ddb3db8975b17d09402beedd5d9d9700710\ 8db28160d5f8040ca7445762b81fbe7ff9d92e0ae76f24f25b33bbe6f44ae61eb1040acb20044d3ef9128ed401\ 30795bd4bd3b41eecad066ab651981fde48df77f372dc38b9fafdd3befb18b5da3cc3c2eb02f9e3a41d612caad\ 15911273a05f23b9e838faaf849d698429ef5a1e88798236c3d40e604522a544c8f27a7a2db80663d16cf7caea\ 56de405cb2215a45b2c25566b55ac1a748a070dfc8a32a469543d019eefb47"; #[test] fn rsa_sign() { let key = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); assert_eq!(signer.rsa_padding().unwrap(), Padding::PKCS1); signer.set_rsa_padding(Padding::PKCS1).unwrap(); signer.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); let result = signer.sign_to_vec().unwrap(); assert_eq!(hex::encode(result), SIGNATURE); } #[test] fn rsa_verify_ok() { let key = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); assert_eq!(verifier.rsa_padding().unwrap(), Padding::PKCS1); verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); assert!(verifier.verify(&Vec::from_hex(SIGNATURE).unwrap()).unwrap()); } #[test] fn rsa_verify_invalid() { let key = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); verifier.update(b"foobar").unwrap(); assert!(!verifier.verify(&Vec::from_hex(SIGNATURE).unwrap()).unwrap()); } fn test_hmac(ty: MessageDigest, tests: &[(Vec, Vec, Vec)]) { for &(ref key, ref data, ref res) in tests.iter() { let pkey = PKey::hmac(key).unwrap(); let mut signer = Signer::new(ty, &pkey).unwrap(); signer.update(data).unwrap(); assert_eq!(signer.sign_to_vec().unwrap(), *res); } } #[test] fn hmac_md5() { // test vectors from RFC 2202 let tests: [(Vec, Vec, Vec); 7] = [ ( iter::repeat(0x0b_u8).take(16).collect(), b"Hi There".to_vec(), Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap(), ), ( b"Jefe".to_vec(), b"what do ya want for nothing?".to_vec(), Vec::from_hex("750c783e6ab0b503eaa86e310a5db738").unwrap(), ), ( iter::repeat(0xaa_u8).take(16).collect(), iter::repeat(0xdd_u8).take(50).collect(), Vec::from_hex("56be34521d144c88dbb8c733f0e8b3f6").unwrap(), ), ( Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(), iter::repeat(0xcd_u8).take(50).collect(), Vec::from_hex("697eaf0aca3a3aea3a75164746ffaa79").unwrap(), ), ( iter::repeat(0x0c_u8).take(16).collect(), b"Test With Truncation".to_vec(), Vec::from_hex("56461ef2342edc00f9bab995690efd4c").unwrap(), ), ( iter::repeat(0xaa_u8).take(80).collect(), b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(), Vec::from_hex("6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd").unwrap(), ), ( iter::repeat(0xaa_u8).take(80).collect(), b"Test Using Larger Than Block-Size Key \ and Larger Than One Block-Size Data" .to_vec(), Vec::from_hex("6f630fad67cda0ee1fb1f562db3aa53e").unwrap(), ), ]; test_hmac(MessageDigest::md5(), &tests); } #[test] fn hmac_sha1() { // test vectors from RFC 2202 let tests: [(Vec, Vec, Vec); 7] = [ ( iter::repeat(0x0b_u8).take(20).collect(), b"Hi There".to_vec(), Vec::from_hex("b617318655057264e28bc0b6fb378c8ef146be00").unwrap(), ), ( b"Jefe".to_vec(), b"what do ya want for nothing?".to_vec(), Vec::from_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79").unwrap(), ), ( iter::repeat(0xaa_u8).take(20).collect(), iter::repeat(0xdd_u8).take(50).collect(), Vec::from_hex("125d7342b9ac11cd91a39af48aa17b4f63f175d3").unwrap(), ), ( Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(), iter::repeat(0xcd_u8).take(50).collect(), Vec::from_hex("4c9007f4026250c6bc8414f9bf50c86c2d7235da").unwrap(), ), ( iter::repeat(0x0c_u8).take(20).collect(), b"Test With Truncation".to_vec(), Vec::from_hex("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04").unwrap(), ), ( iter::repeat(0xaa_u8).take(80).collect(), b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(), Vec::from_hex("aa4ae5e15272d00e95705637ce8a3b55ed402112").unwrap(), ), ( iter::repeat(0xaa_u8).take(80).collect(), b"Test Using Larger Than Block-Size Key \ and Larger Than One Block-Size Data" .to_vec(), Vec::from_hex("e8e99d0f45237d786d6bbaa7965c7808bbff1a91").unwrap(), ), ]; test_hmac(MessageDigest::sha1(), &tests); } #[test] #[cfg(ossl110)] fn test_cmac() { let cipher = ::symm::Cipher::aes_128_cbc(); let key = Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap(); let pkey = PKey::cmac(&cipher, &key).unwrap(); let mut signer = Signer::new_without_digest(&pkey).unwrap(); let data = b"Hi There"; signer.update(data as &[u8]).unwrap(); let expected = vec![ 136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19, ]; assert_eq!(signer.sign_to_vec().unwrap(), expected); } #[test] fn ec() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let key = PKey::from_ec_key(key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &key).unwrap(); signer.update(b"hello world").unwrap(); let signature = signer.sign_to_vec().unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &key).unwrap(); verifier.update(b"hello world").unwrap(); assert!(verifier.verify(&signature).unwrap()); } #[test] fn rsa_sign_verify() { let key = include_bytes!("../test/rsa.pem"); let private_key = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); signer.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); assert_eq!(signer.rsa_padding().unwrap(), Padding::PKCS1_PSS); signer .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH) .unwrap(); signer.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap(); signer.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); let signature = signer.sign_to_vec().unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); verifier .set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH) .unwrap(); verifier.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap(); verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap(); assert!(verifier.verify(&signature).unwrap()); } } openssl-0.10.23/src/srtp.rs010064400017500001750000000036121346222217000137070ustar0000000000000000use ffi; use foreign_types::ForeignTypeRef; use libc::c_ulong; use stack::Stackable; use std::ffi::CStr; use std::str; /// fake free method, since SRTP_PROTECTION_PROFILE is static unsafe fn free(_profile: *mut ffi::SRTP_PROTECTION_PROFILE) {} #[allow(unused_unsafe)] foreign_type_and_impl_send_sync! { type CType = ffi::SRTP_PROTECTION_PROFILE; fn drop = free; pub struct SrtpProtectionProfile; /// Reference to `SrtpProtectionProfile`. pub struct SrtpProtectionProfileRef; } impl Stackable for SrtpProtectionProfile { type StackType = ffi::stack_st_SRTP_PROTECTION_PROFILE; } impl SrtpProtectionProfileRef { pub fn id(&self) -> SrtpProfileId { SrtpProfileId::from_raw(unsafe { (*self.as_ptr()).id }) } pub fn name(&self) -> &'static str { unsafe { CStr::from_ptr((*self.as_ptr()).name as *const _) } .to_str() .expect("should be UTF-8") } } /// An identifier of an SRTP protection profile. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct SrtpProfileId(c_ulong); impl SrtpProfileId { /// Creates a `SrtpProfileId` from an integer representation. pub fn from_raw(value: c_ulong) -> SrtpProfileId { SrtpProfileId(value) } /// Returns the integer representation of `SrtpProfileId`. pub fn as_raw(&self) -> c_ulong { self.0 } pub const SRTP_AES128_CM_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_CM_SHA1_80); pub const SRTP_AES128_CM_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_CM_SHA1_32); pub const SRTP_AES128_F8_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_80); pub const SRTP_AES128_F8_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_32); pub const SRTP_NULL_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_80); pub const SRTP_NULL_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_32); } openssl-0.10.23/src/ssl/bio.rs010064400017500001750000000164661346222217000143040ustar0000000000000000use ffi::{ self, BIO_clear_retry_flags, BIO_new, BIO_set_retry_read, BIO_set_retry_write, BIO, BIO_CTRL_FLUSH, }; use libc::{c_char, c_int, c_long, c_void, strlen}; use std::any::Any; use std::io; use std::io::prelude::*; use std::mem; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::ptr; use std::slice; use cvt_p; use error::ErrorStack; pub struct StreamState { pub stream: S, pub error: Option, pub panic: Option>, } /// Safe wrapper for BIO_METHOD pub struct BioMethod(BIO_METHOD); impl BioMethod { fn new() -> BioMethod { BioMethod(BIO_METHOD::new::()) } } unsafe impl Sync for BioMethod {} unsafe impl Send for BioMethod {} pub fn new(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> { let method = BioMethod::new::(); let state = Box::new(StreamState { stream: stream, error: None, panic: None, }); unsafe { let bio = cvt_p(BIO_new(method.0.get()))?; BIO_set_data(bio, Box::into_raw(state) as *mut _); BIO_set_init(bio, 1); return Ok((bio, method)); } } pub unsafe fn take_error(bio: *mut BIO) -> Option { let state = state::(bio); state.error.take() } pub unsafe fn take_panic(bio: *mut BIO) -> Option> { let state = state::(bio); state.panic.take() } pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { let state: &'a StreamState = mem::transmute(BIO_get_data(bio)); &state.stream } pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { &mut state(bio).stream } unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { &mut *(BIO_get_data(bio) as *mut _) } unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); let buf = slice::from_raw_parts(buf as *const _, len as usize); match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) { Ok(Ok(len)) => len as c_int, Ok(Err(err)) => { if retriable_error(&err) { BIO_set_retry_write(bio); } state.error = Some(err); -1 } Err(err) => { state.panic = Some(err); -1 } } } unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize); match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) { Ok(Ok(len)) => len as c_int, Ok(Err(err)) => { if retriable_error(&err) { BIO_set_retry_read(bio); } state.error = Some(err); -1 } Err(err) => { state.panic = Some(err); -1 } } } fn retriable_error(err: &io::Error) -> bool { match err.kind() { io::ErrorKind::WouldBlock | io::ErrorKind::NotConnected => true, _ => false, } } unsafe extern "C" fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { bwrite::(bio, s, strlen(s) as c_int) } unsafe extern "C" fn ctrl( bio: *mut BIO, cmd: c_int, _num: c_long, _ptr: *mut c_void, ) -> c_long { if cmd == BIO_CTRL_FLUSH { let state = state::(bio); match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) { Ok(Ok(())) => 1, Ok(Err(err)) => { state.error = Some(err); 0 } Err(err) => { state.panic = Some(err); 0 } } } else { 0 } } unsafe extern "C" fn create(bio: *mut BIO) -> c_int { BIO_set_init(bio, 0); BIO_set_num(bio, 0); BIO_set_data(bio, ptr::null_mut()); BIO_set_flags(bio, 0); 1 } unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { if bio.is_null() { return 0; } let data = BIO_get_data(bio); assert!(!data.is_null()); Box::>::from_raw(data as *mut _); BIO_set_data(bio, ptr::null_mut()); BIO_set_init(bio, 0); 1 } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{BIO_get_data, BIO_set_data, BIO_set_flags, BIO_set_init}; #[allow(bad_style)] unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} #[allow(bad_style)] struct BIO_METHOD(*mut ffi::BIO_METHOD); impl BIO_METHOD { fn new() -> BIO_METHOD { unsafe { let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _); assert!(!ptr.is_null()); let ret = BIO_METHOD(ptr); assert!(ffi::BIO_meth_set_write(ptr, bwrite::) != 0); assert!(ffi::BIO_meth_set_read(ptr, bread::) != 0); assert!(ffi::BIO_meth_set_puts(ptr, bputs::) != 0); assert!(ffi::BIO_meth_set_ctrl(ptr, ctrl::) != 0); assert!(ffi::BIO_meth_set_create(ptr, create) != 0); assert!(ffi::BIO_meth_set_destroy(ptr, destroy::) != 0); return ret; } } fn get(&self) -> *mut ffi::BIO_METHOD { self.0 } } impl Drop for BIO_METHOD { fn drop(&mut self) { unsafe { ffi::BIO_meth_free(self.0); } } } } else { #[allow(bad_style)] struct BIO_METHOD(*mut ffi::BIO_METHOD); impl BIO_METHOD { fn new() -> BIO_METHOD { let ptr = Box::new(ffi::BIO_METHOD { type_: ffi::BIO_TYPE_NONE, name: b"rust\0".as_ptr() as *const _, bwrite: Some(bwrite::), bread: Some(bread::), bputs: Some(bputs::), bgets: None, ctrl: Some(ctrl::), create: Some(create), destroy: Some(destroy::), callback_ctrl: None, }); BIO_METHOD(Box::into_raw(ptr)) } fn get(&self) -> *mut ffi::BIO_METHOD { self.0 } } impl Drop for BIO_METHOD { fn drop(&mut self) { unsafe { Box::::from_raw(self.0); } } } #[allow(bad_style)] unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) { (*bio).init = init; } #[allow(bad_style)] unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) { (*bio).flags = flags; } #[allow(bad_style)] unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void { (*bio).ptr } #[allow(bad_style)] unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) { (*bio).ptr = data; } #[allow(bad_style)] unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) { (*bio).num = num; } } } openssl-0.10.23/src/ssl/callbacks.rs010064400017500001750000000461161347005411600154470ustar0000000000000000use ffi; use foreign_types::ForeignType; use foreign_types::ForeignTypeRef; #[cfg(any(ossl111, not(osslconf = "OPENSSL_NO_PSK")))] use libc::c_char; #[cfg(ossl111)] use libc::size_t; use libc::{c_int, c_uchar, c_uint, c_void}; #[cfg(any(ossl111, not(osslconf = "OPENSSL_NO_PSK")))] use std::ffi::CStr; use std::mem; use std::ptr; use std::slice; #[cfg(ossl111)] use std::str; use std::sync::Arc; use dh::Dh; #[cfg(all(ossl101, not(ossl110)))] use ec::EcKey; use error::ErrorStack; use pkey::Params; #[cfg(any(ossl102, libressl261))] use ssl::AlpnError; #[cfg(ossl111)] 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}; pub extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int where F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, { unsafe { let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx); let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing"); let verify_idx = SslContext::cached_ex_index::(); // raw pointer shenanigans to break the borrow of ctx // the callback can't mess with its own ex_data slot so this is safe let verify = ctx .ex_data(ssl_idx) .expect("BUG: store context missing ssl") .ssl_context() .ex_data(verify_idx) .expect("BUG: verify callback missing") as *const F; (*verify)(preverify_ok != 0, ctx) as c_int } } #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub extern "C" fn raw_client_psk( ssl: *mut ffi::SSL, hint: *const c_char, identity: *mut c_char, max_identity_len: c_uint, psk: *mut c_uchar, max_psk_len: c_uint, ) -> c_uint where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let callback_idx = SslContext::cached_ex_index::(); let callback = ssl .ssl_context() .ex_data(callback_idx) .expect("BUG: psk callback missing") as *const F; let hint = if !hint.is_null() { Some(CStr::from_ptr(hint).to_bytes()) } else { None }; // Give the callback mutable slices into which it can write the identity and psk. let identity_sl = slice::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize); let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); match (*callback)(ssl, hint, identity_sl, psk_sl) { Ok(psk_len) => psk_len as u32, Err(e) => { e.put(); 0 } } } } #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub extern "C" fn raw_server_psk( ssl: *mut ffi::SSL, identity: *const c_char, psk: *mut c_uchar, max_psk_len: c_uint, ) -> c_uint where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result + 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let callback_idx = SslContext::cached_ex_index::(); let callback = ssl .ssl_context() .ex_data(callback_idx) .expect("BUG: psk callback missing") as *const F; let identity = if identity != ptr::null() { Some(CStr::from_ptr(identity).to_bytes()) } else { None }; // Give the callback mutable slices into which it can write the psk. let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); match (*callback)(ssl, identity, psk_sl) { Ok(psk_len) => psk_len as u32, Err(e) => { e.put(); 0 } } } } pub extern "C" fn ssl_raw_verify( preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX, ) -> c_int where F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, { unsafe { let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx); let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing"); let callback_idx = Ssl::cached_ex_index::>(); let callback = ctx .ex_data(ssl_idx) .expect("BUG: store context missing ssl") .ex_data(callback_idx) .expect("BUG: ssl verify callback missing") .clone(); callback(preverify_ok != 0, ctx) as c_int } } pub extern "C" fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, arg: *mut c_void) -> c_int where F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let callback = arg as *const F; let mut alert = SslAlert(*al); let r = (*callback)(ssl, &mut alert); *al = alert.0; match r { Ok(()) => ffi::SSL_TLSEXT_ERR_OK, Err(e) => e.0, } } } #[cfg(any(ossl102, libressl261))] pub extern "C" fn raw_alpn_select( ssl: *mut ffi::SSL, out: *mut *const c_uchar, outlen: *mut c_uchar, inbuf: *const c_uchar, inlen: c_uint, _arg: *mut c_void, ) -> c_int where F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: alpn callback missing") as *const F; let protos = slice::from_raw_parts(inbuf as *const u8, inlen as usize); match (*callback)(ssl, protos) { Ok(proto) => { *out = proto.as_ptr() as *const c_uchar; *outlen = proto.len() as c_uchar; ffi::SSL_TLSEXT_ERR_OK } Err(e) => e.0, } } } pub unsafe extern "C" fn raw_tmp_dh( ssl: *mut ffi::SSL, is_export: c_int, keylength: c_int, ) -> *mut ffi::DH where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: tmp dh callback missing") as *const F; match (*callback)(ssl, is_export != 0, keylength as u32) { Ok(dh) => { let ptr = dh.as_ptr(); mem::forget(dh); ptr } Err(e) => { e.put(); ptr::null_mut() } } } #[cfg(all(ossl101, not(ossl110)))] pub unsafe extern "C" fn raw_tmp_ecdh( ssl: *mut ffi::SSL, is_export: c_int, keylength: c_int, ) -> *mut ffi::EC_KEY where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: tmp ecdh callback missing") as *const F; match (*callback)(ssl, is_export != 0, keylength as u32) { Ok(ec_key) => { let ptr = ec_key.as_ptr(); mem::forget(ec_key); ptr } Err(e) => { e.put(); ptr::null_mut() } } } pub unsafe extern "C" fn raw_tmp_dh_ssl( ssl: *mut ffi::SSL, is_export: c_int, keylength: c_int, ) -> *mut ffi::DH where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ex_data(Ssl::cached_ex_index::>()) .expect("BUG: ssl tmp dh callback missing") .clone(); match callback(ssl, is_export != 0, keylength as u32) { Ok(dh) => { let ptr = dh.as_ptr(); mem::forget(dh); ptr } Err(e) => { e.put(); ptr::null_mut() } } } #[cfg(all(ossl101, not(ossl110)))] pub unsafe extern "C" fn raw_tmp_ecdh_ssl( ssl: *mut ffi::SSL, is_export: c_int, keylength: c_int, ) -> *mut ffi::EC_KEY where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ex_data(Ssl::cached_ex_index::>()) .expect("BUG: ssl tmp ecdh callback missing") .clone(); match callback(ssl, is_export != 0, keylength as u32) { Ok(ec_key) => { let ptr = ec_key.as_ptr(); mem::forget(ec_key); ptr } Err(e) => { e.put(); ptr::null_mut() } } } pub unsafe extern "C" fn raw_tlsext_status(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int where F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: ocsp callback missing") as *const F; let ret = (*callback)(ssl); if ssl.is_server() { match ret { Ok(true) => ffi::SSL_TLSEXT_ERR_OK, Ok(false) => ffi::SSL_TLSEXT_ERR_NOACK, Err(e) => { e.put(); ffi::SSL_TLSEXT_ERR_ALERT_FATAL } } } else { match ret { Ok(true) => 1, Ok(false) => 0, Err(e) => { e.put(); -1 } } } } pub unsafe extern "C" fn raw_new_session( ssl: *mut ffi::SSL, session: *mut ffi::SSL_SESSION, ) -> c_int where F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .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); (*callback)(ssl, session); // the return code doesn't indicate error vs success, but whether or not we consumed the session 1 } pub unsafe extern "C" fn raw_remove_session( ctx: *mut ffi::SSL_CTX, session: *mut ffi::SSL_SESSION, ) where F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, { let ctx = SslContextRef::from_ptr(ctx); let callback = ctx .ex_data(SslContext::cached_ex_index::()) .expect("BUG: remove session callback missing"); let session = SslSessionRef::from_ptr(session); callback(ctx, session) } cfg_if! { if #[cfg(any(ossl110, libressl280))] { type DataPtr = *const c_uchar; } else { type DataPtr = *mut c_uchar; } } pub unsafe extern "C" fn raw_get_session( ssl: *mut ffi::SSL, data: DataPtr, len: c_int, copy: *mut c_int, ) -> *mut ffi::SSL_SESSION where F: Fn(&mut SslRef, &[u8]) -> Option + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .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); match (*callback)(ssl, data) { Some(session) => { let p = session.as_ptr(); mem::forget(session); *copy = 0; p } None => ptr::null_mut(), } } #[cfg(ossl111)] pub unsafe extern "C" fn raw_keylog(ssl: *const ffi::SSL, line: *const c_char) where F: Fn(&SslRef, &str) + 'static + Sync + Send, { let ssl = SslRef::from_ptr(ssl as *mut _); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: get session callback missing"); let line = CStr::from_ptr(line).to_bytes(); let line = str::from_utf8_unchecked(line); callback(ssl, line); } #[cfg(ossl111)] pub unsafe extern "C" fn raw_stateless_cookie_generate( ssl: *mut ffi::SSL, cookie: *mut c_uchar, cookie_len: *mut size_t, ) -> c_int where F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie generate callback missing") as *const F; let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize); match (*callback)(ssl, slice) { Ok(len) => { *cookie_len = len as size_t; 1 } Err(e) => { e.put(); 0 } } } #[cfg(ossl111)] pub unsafe extern "C" fn raw_stateless_cookie_verify( ssl: *mut ffi::SSL, cookie: *const c_uchar, cookie_len: size_t, ) -> c_int where F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie verify callback missing") as *const F; let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); (*callback)(ssl, slice) as c_int } pub extern "C" fn raw_cookie_generate( ssl: *mut ffi::SSL, cookie: *mut c_uchar, cookie_len: *mut c_uint, ) -> c_int where F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: cookie generate callback missing") as *const F; // We subtract 1 from DTLS1_COOKIE_LENGTH as the ostensible value, 256, is erroneous but retained for // compatibility. See comments in dtls1.h. let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1); match (*callback)(ssl, slice) { Ok(len) => { *cookie_len = len as c_uint; 1 } Err(e) => { e.put(); 0 } } } } cfg_if! { if #[cfg(any(ossl110, libressl280))] { type CookiePtr = *const c_uchar; } else { type CookiePtr = *mut c_uchar; } } pub extern "C" fn raw_cookie_verify( ssl: *mut ffi::SSL, cookie: CookiePtr, cookie_len: c_uint, ) -> c_int where F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: cookie verify callback missing") as *const F; let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); (*callback)(ssl, slice) as c_int } } #[cfg(ossl111)] pub struct CustomExtAddState(Option); #[cfg(ossl111)] pub extern "C" fn raw_custom_ext_add( ssl: *mut ffi::SSL, _: c_uint, context: c_uint, out: *mut *const c_uchar, outlen: *mut size_t, x: *mut ffi::X509, chainidx: size_t, al: *mut c_int, _: *mut c_void, ) -> c_int where F: Fn(&mut SslRef, ExtensionContext, Option<(usize, &X509Ref)>) -> Result, SslAlert> + 'static + Sync + Send, T: AsRef<[u8]> + 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: custom ext add callback missing") as *const F; let ectx = ExtensionContext::from_bits_truncate(context); let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) { Some((chainidx, X509Ref::from_ptr(x))) } else { None }; match (*callback)(ssl, ectx, cert) { Ok(None) => 0, Ok(Some(buf)) => { *outlen = buf.as_ref().len(); *out = buf.as_ref().as_ptr(); let idx = Ssl::cached_ex_index::>(); let mut buf = Some(buf); let new = match ssl.ex_data_mut(idx) { Some(state) => { state.0 = buf.take(); false } None => true, }; if new { ssl.set_ex_data(idx, CustomExtAddState(buf)); } 1 } Err(alert) => { *al = alert.0; -1 } } } } #[cfg(ossl111)] pub extern "C" fn raw_custom_ext_free( ssl: *mut ffi::SSL, _: c_uint, _: c_uint, _: *mut *const c_uchar, _: *mut c_void, ) where T: 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let idx = Ssl::cached_ex_index::>(); if let Some(state) = ssl.ex_data_mut(idx) { state.0 = None; } } } #[cfg(ossl111)] pub extern "C" fn raw_custom_ext_parse( ssl: *mut ffi::SSL, _: c_uint, context: c_uint, input: *const c_uchar, inlen: size_t, x: *mut ffi::X509, chainidx: size_t, al: *mut c_int, _: *mut c_void, ) -> c_int where F: Fn(&mut SslRef, ExtensionContext, &[u8], Option<(usize, &X509Ref)>) -> Result<(), SslAlert> + 'static + Sync + Send, { unsafe { let ssl = SslRef::from_ptr_mut(ssl); let callback = ssl .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: custom ext parse callback missing") as *const F; let ectx = ExtensionContext::from_bits_truncate(context); let slice = slice::from_raw_parts(input as *const u8, inlen as usize); let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) { Some((chainidx, X509Ref::from_ptr(x))) } else { None }; match (*callback)(ssl, ectx, slice, cert) { Ok(()) => 1, Err(alert) => { *al = alert.0; 0 } } } } #[cfg(ossl111)] pub unsafe extern "C" fn raw_client_hello( ssl: *mut ffi::SSL, al: *mut c_int, arg: *mut c_void, ) -> c_int where F: Fn(&mut SslRef, &mut SslAlert) -> Result + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); let callback = arg as *const F; let mut alert = SslAlert(*al); let r = (*callback)(ssl, &mut alert); *al = alert.0; match r { Ok(c) => c.0, Err(e) => { e.put(); ffi::SSL_CLIENT_HELLO_ERROR } } } openssl-0.10.23/src/ssl/connector.rs010064400017500001750000000431401346222217000155120ustar0000000000000000use std::io::{Read, Write}; use std::ops::{Deref, DerefMut}; use dh::Dh; use error::ErrorStack; use ssl::{ HandshakeError, Ssl, SslContext, SslContextBuilder, SslMethod, SslMode, SslOptions, SslRef, SslStream, SslVerifyMode, }; use version; fn ctx(method: SslMethod) -> Result { let mut ctx = SslContextBuilder::new(method)?; let mut opts = SslOptions::ALL | SslOptions::NO_COMPRESSION | SslOptions::NO_SSLV2 | SslOptions::NO_SSLV3 | SslOptions::SINGLE_DH_USE | SslOptions::SINGLE_ECDH_USE | SslOptions::CIPHER_SERVER_PREFERENCE; opts &= !SslOptions::DONT_INSERT_EMPTY_FRAGMENTS; ctx.set_options(opts); let mut mode = SslMode::AUTO_RETRY | SslMode::ACCEPT_MOVING_WRITE_BUFFER | SslMode::ENABLE_PARTIAL_WRITE; // This is quite a useful optimization for saving memory, but historically // caused CVEs in OpenSSL pre-1.0.1h, according to // https://bugs.python.org/issue25672 if version::number() >= 0x1_00_01_08_0 { mode |= SslMode::RELEASE_BUFFERS; } ctx.set_mode(mode); Ok(ctx) } /// A type which wraps client-side streams in a TLS session. /// /// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL /// structures, configuring cipher suites, session options, hostname verification, and more. /// /// OpenSSL's built in hostname verification is used when linking against OpenSSL 1.0.2 or 1.1.0, /// and a custom implementation is used when linking against OpenSSL 1.0.1. #[derive(Clone)] pub struct SslConnector(SslContext); impl SslConnector { /// Creates a new builder for TLS connections. /// /// The default configuration is subject to change, and is currently derived from Python. pub fn builder(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_default_verify_paths()?; ctx.set_cipher_list( "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK", )?; setup_verify(&mut ctx); Ok(SslConnectorBuilder(ctx)) } /// Initiates a client-side TLS session on a stream. /// /// The domain is used for SNI and hostname verification. pub fn connect(&self, domain: &str, stream: S) -> Result, HandshakeError> where S: Read + Write, { self.configure()?.connect(domain, stream) } /// Returns a structure allowing for configuration of a single TLS session before connection. pub fn configure(&self) -> Result { Ssl::new(&self.0).map(|ssl| ConnectConfiguration { ssl, sni: true, verify_hostname: true, }) } } /// A builder for `SslConnector`s. pub struct SslConnectorBuilder(SslContextBuilder); impl SslConnectorBuilder { /// Consumes the builder, returning an `SslConnector`. pub fn build(self) -> SslConnector { SslConnector(self.0.build()) } } impl Deref for SslConnectorBuilder { type Target = SslContextBuilder; fn deref(&self) -> &SslContextBuilder { &self.0 } } impl DerefMut for SslConnectorBuilder { fn deref_mut(&mut self) -> &mut SslContextBuilder { &mut self.0 } } /// A type which allows for configuration of a client-side TLS session before connection. pub struct ConnectConfiguration { ssl: Ssl, sni: bool, verify_hostname: bool, } impl ConnectConfiguration { /// A builder-style version of `set_use_server_name_indication`. pub fn use_server_name_indication(mut self, use_sni: bool) -> ConnectConfiguration { self.set_use_server_name_indication(use_sni); self } /// Configures the use of Server Name Indication (SNI) when connecting. /// /// Defaults to `true`. pub fn set_use_server_name_indication(&mut self, use_sni: bool) { self.sni = use_sni; } /// A builder-style version of `set_verify_hostname`. pub fn verify_hostname(mut self, verify_hostname: bool) -> ConnectConfiguration { self.set_verify_hostname(verify_hostname); self } /// Configures the use of hostname verification when connecting. /// /// Defaults to `true`. /// /// # Warning /// /// You should think very carefully before you use this method. If hostname verification is not /// used, *any* valid certificate for *any* site will be trusted for use from any other. This /// introduces a significant vulnerability to man-in-the-middle attacks. pub fn set_verify_hostname(&mut self, verify_hostname: bool) { self.verify_hostname = verify_hostname; } /// Initiates a client-side TLS session on a stream. /// /// The domain is used for SNI and hostname verification if enabled. pub fn connect(mut self, domain: &str, stream: S) -> Result, HandshakeError> where S: Read + Write, { if self.sni { self.ssl.set_hostname(domain)?; } if self.verify_hostname { setup_verify_hostname(&mut self.ssl, domain)?; } self.ssl.connect(stream) } } impl Deref for ConnectConfiguration { type Target = SslRef; fn deref(&self) -> &SslRef { &self.ssl } } impl DerefMut for ConnectConfiguration { fn deref_mut(&mut self) -> &mut SslRef { &mut self.ssl } } /// A type which wraps server-side streams in a TLS session. /// /// OpenSSL's default configuration is highly insecure. This connector manages the OpenSSL /// structures, configuring cipher suites, session options, and more. #[derive(Clone)] pub struct SslAcceptor(SslContext); impl SslAcceptor { /// Creates a new builder configured to connect to non-legacy clients. This should generally be /// considered a reasonable default choice. /// /// This corresponds to the intermediate configuration of Mozilla's server side TLS /// recommendations. See its [documentation][docs] for more details on specifics. /// /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS pub fn mozilla_intermediate(method: SslMethod) -> Result { let mut ctx = ctx(method)?; #[cfg(ossl111)] ctx.set_options(SslOptions::NO_TLSV1_3); let dh = Dh::params_from_pem( b" -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS----- ", )?; ctx.set_tmp_dh(&dh)?; setup_curves(&mut ctx)?; ctx.set_cipher_list( "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:\ ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:\ ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:\ ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:\ DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:\ EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:\ AES256-SHA:DES-CBC3-SHA:!DSS", )?; Ok(SslAcceptorBuilder(ctx)) } /// Creates a new builder configured to connect to modern clients. /// /// This corresponds to the modern configuration of Mozilla's server side TLS recommendations. /// See its [documentation][docs] for more details on specifics. /// /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS pub fn mozilla_modern(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_options(SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1); #[cfg(ossl111)] ctx.set_options(SslOptions::NO_TLSV1_3); setup_curves(&mut ctx)?; ctx.set_cipher_list( "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:\ ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:\ ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256", )?; Ok(SslAcceptorBuilder(ctx)) } /// Initiates a server-side TLS session on a stream. pub fn accept(&self, stream: S) -> Result, HandshakeError> where S: Read + Write, { let ssl = Ssl::new(&self.0)?; ssl.accept(stream) } } /// A builder for `SslAcceptor`s. pub struct SslAcceptorBuilder(SslContextBuilder); impl SslAcceptorBuilder { /// Consumes the builder, returning a `SslAcceptor`. pub fn build(self) -> SslAcceptor { SslAcceptor(self.0.build()) } } impl Deref for SslAcceptorBuilder { type Target = SslContextBuilder; fn deref(&self) -> &SslContextBuilder { &self.0 } } impl DerefMut for SslAcceptorBuilder { fn deref_mut(&mut self) -> &mut SslContextBuilder { &mut self.0 } } cfg_if! { if #[cfg(ossl110)] { fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { Ok(()) } } else if #[cfg(any(ossl102, libressl))] { fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { ctx.set_ecdh_auto(true) } } else { fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { use ec::EcKey; use nid::Nid; let curve = EcKey::from_curve_name(Nid::X9_62_PRIME256V1)?; ctx.set_tmp_ecdh(&curve) } } } cfg_if! { if #[cfg(any(ossl102, libressl261))] { fn setup_verify(ctx: &mut SslContextBuilder) { ctx.set_verify(SslVerifyMode::PEER); } fn setup_verify_hostname(ssl: &mut SslRef, domain: &str) -> Result<(), ErrorStack> { use x509::verify::X509CheckFlags; let param = ssl.param_mut(); param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); match domain.parse() { Ok(ip) => param.set_ip(ip), Err(_) => param.set_host(domain), } } } else { fn setup_verify(ctx: &mut SslContextBuilder) { ctx.set_verify_callback(SslVerifyMode::PEER, verify::verify_callback); } fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { let domain = domain.to_string(); ssl.set_ex_data(*verify::HOSTNAME_IDX, domain); Ok(()) } mod verify { use std::net::IpAddr; use std::str; use ex_data::Index; use nid::Nid; use ssl::Ssl; use stack::Stack; use x509::{ GeneralName, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, X509VerifyResult, }; lazy_static! { pub static ref HOSTNAME_IDX: Index = Ssl::new_ex_index().unwrap(); } pub fn verify_callback(preverify_ok: bool, x509_ctx: &mut X509StoreContextRef) -> bool { if !preverify_ok || x509_ctx.error_depth() != 0 { return preverify_ok; } let ok = match ( x509_ctx.current_cert(), X509StoreContext::ssl_idx() .ok() .and_then(|idx| x509_ctx.ex_data(idx)) .and_then(|ssl| ssl.ex_data(*HOSTNAME_IDX)), ) { (Some(x509), Some(domain)) => verify_hostname(domain, &x509), _ => true, }; if !ok { x509_ctx.set_error(X509VerifyResult::APPLICATION_VERIFICATION); } ok } fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { match cert.subject_alt_names() { Some(names) => verify_subject_alt_names(domain, names), None => verify_subject_name(domain, &cert.subject_name()), } } fn verify_subject_alt_names(domain: &str, names: Stack) -> bool { let ip = domain.parse(); for name in &names { match ip { Ok(ip) => { if let Some(actual) = name.ipaddress() { if matches_ip(&ip, actual) { return true; } } } Err(_) => { if let Some(pattern) = name.dnsname() { if matches_dns(pattern, domain) { return true; } } } } } false } fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { match subject_name.entries_by_nid(Nid::COMMONNAME).next() { Some(pattern) => { let pattern = match str::from_utf8(pattern.data().as_slice()) { Ok(pattern) => pattern, Err(_) => return false, }; // Unlike SANs, IP addresses in the subject name don't have a // different encoding. match domain.parse::() { Ok(ip) => pattern .parse::() .ok() .map_or(false, |pattern| pattern == ip), Err(_) => matches_dns(pattern, domain), } } None => false, } } fn matches_dns(mut pattern: &str, mut hostname: &str) -> bool { // first strip trailing . off of pattern and hostname to normalize if pattern.ends_with('.') { pattern = &pattern[..pattern.len() - 1]; } if hostname.ends_with('.') { hostname = &hostname[..hostname.len() - 1]; } matches_wildcard(pattern, hostname).unwrap_or_else(|| pattern == hostname) } fn matches_wildcard(pattern: &str, hostname: &str) -> Option { // internationalized domains can't involved in wildcards if pattern.starts_with("xn--") { return None; } let wildcard_location = match pattern.find('*') { Some(l) => l, None => return None, }; let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); let wildcard_end = match dot_idxs.next() { Some(l) => l, None => return None, }; // Never match wildcards if the pattern has less than 2 '.'s (no *.com) // // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. // Chrome has a black- and white-list for this, but Firefox (via NSS) does // the same thing we do here. // // The Public Suffix (https://www.publicsuffix.org/) list could // potentially be used here, but it's both huge and updated frequently // enough that management would be a PITA. if dot_idxs.next().is_none() { return None; } // Wildcards can only be in the first component if wildcard_location > wildcard_end { return None; } let hostname_label_end = match hostname.find('.') { Some(l) => l, None => return None, }; // check that the non-wildcard parts are identical if pattern[wildcard_end..] != hostname[hostname_label_end..] { return Some(false); } let wildcard_prefix = &pattern[..wildcard_location]; let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; let hostname_label = &hostname[..hostname_label_end]; // check the prefix of the first label if !hostname_label.starts_with(wildcard_prefix) { return Some(false); } // and the suffix if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { return Some(false); } Some(true) } fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { match *expected { IpAddr::V4(ref addr) => actual == addr.octets(), IpAddr::V6(ref addr) => actual == addr.octets(), } } } } } openssl-0.10.23/src/ssl/error.rs010064400017500001750000000131631346222217000146530ustar0000000000000000use ffi; use libc::c_int; use std::error; use std::error::Error as StdError; use std::fmt; use std::io; use error::ErrorStack; use ssl::MidHandshakeSslStream; use x509::X509VerifyResult; /// An error code returned from SSL functions. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct ErrorCode(c_int); impl ErrorCode { pub fn from_raw(raw: c_int) -> ErrorCode { ErrorCode(raw) } pub fn as_raw(&self) -> c_int { self.0 } /// The SSL session has been closed. pub const ZERO_RETURN: ErrorCode = ErrorCode(ffi::SSL_ERROR_ZERO_RETURN); /// An attempt to read data from the underlying socket returned `WouldBlock`. /// /// Wait for read readiness and retry the operation. pub const WANT_READ: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_READ); /// An attempt to write data to the underlying socket returned `WouldBlock`. /// /// Wait for write readiness and retry the operation. pub const WANT_WRITE: ErrorCode = ErrorCode(ffi::SSL_ERROR_WANT_WRITE); /// A non-recoverable IO error occurred. pub const SYSCALL: ErrorCode = ErrorCode(ffi::SSL_ERROR_SYSCALL); /// An error occurred in the SSL library. 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); } #[derive(Debug)] pub(crate) enum InnerError { Io(io::Error), Ssl(ErrorStack), } /// An SSL error. #[derive(Debug)] pub struct Error { pub(crate) code: ErrorCode, pub(crate) cause: Option, } impl Error { pub fn code(&self) -> ErrorCode { self.code } pub fn io_error(&self) -> Option<&io::Error> { match self.cause { Some(InnerError::Io(ref e)) => Some(e), _ => None, } } pub fn into_io_error(self) -> Result { match self.cause { Some(InnerError::Io(e)) => Ok(e), _ => Err(self), } } pub fn ssl_error(&self) -> Option<&ErrorStack> { match self.cause { Some(InnerError::Ssl(ref e)) => Some(e), _ => None, } } } impl From for Error { fn from(e: ErrorStack) -> Error { Error { code: ErrorCode::SSL, cause: Some(InnerError::Ssl(e)), } } } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self.code { ErrorCode::ZERO_RETURN => fmt.write_str("the SSL session has been shut down"), ErrorCode::WANT_READ => match self.io_error() { Some(_) => fmt.write_str("a nonblocking read call would have blocked"), None => fmt.write_str("the operation should be retried"), }, ErrorCode::WANT_WRITE => match self.io_error() { Some(_) => fmt.write_str("a nonblocking write call would have blocked"), None => fmt.write_str("the operation should be retried"), }, ErrorCode::SYSCALL => match self.io_error() { Some(err) => write!(fmt, "{}", err), None => fmt.write_str("unexpected EOF"), }, ErrorCode::SSL => match self.ssl_error() { Some(e) => write!(fmt, "{}", e), None => fmt.write_str("OpenSSL error"), }, ErrorCode(code) => write!(fmt, "unknown error code {}", code), } } } impl error::Error for Error { fn description(&self) -> &str { "an OpenSSL error" } fn cause(&self) -> Option<&error::Error> { match self.cause { Some(InnerError::Io(ref e)) => Some(e), Some(InnerError::Ssl(ref e)) => Some(e), None => None, } } } /// An error or intermediate state after a TLS handshake attempt. // FIXME overhaul #[derive(Debug)] pub enum HandshakeError { /// Setup failed. SetupFailure(ErrorStack), /// The handshake failed. Failure(MidHandshakeSslStream), /// The handshake encountered a `WouldBlock` error midway through. /// /// This error will never be returned for blocking streams. WouldBlock(MidHandshakeSslStream), } impl StdError for HandshakeError { fn description(&self) -> &str { match *self { HandshakeError::SetupFailure(_) => "stream setup failed", HandshakeError::Failure(_) => "the handshake failed", HandshakeError::WouldBlock(_) => "the handshake was interrupted", } } fn cause(&self) -> Option<&StdError> { match *self { HandshakeError::SetupFailure(ref e) => Some(e), HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => Some(s.error()), } } } impl fmt::Display for HandshakeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(StdError::description(self))?; match *self { HandshakeError::SetupFailure(ref e) => write!(f, ": {}", e)?, HandshakeError::Failure(ref s) | HandshakeError::WouldBlock(ref s) => { write!(f, ": {}", s.error())?; let verify = s.ssl().verify_result(); if verify != X509VerifyResult::OK { write!(f, ": {}", verify)?; } } } Ok(()) } } impl From for HandshakeError { fn from(e: ErrorStack) -> HandshakeError { HandshakeError::SetupFailure(e) } } openssl-0.10.23/src/ssl/mod.rs010064400017500001750000004250121347005411600143030ustar0000000000000000//! SSL/TLS support. //! //! `SslConnector` and `SslAcceptor` should be used in most cases - they handle //! configuration of the OpenSSL primitives for you. //! //! # Examples //! //! To connect as a client to a remote server: //! //! ```no_run //! use openssl::ssl::{SslMethod, SslConnector}; //! use std::io::{Read, Write}; //! use std::net::TcpStream; //! //! let connector = SslConnector::builder(SslMethod::tls()).unwrap().build(); //! //! let stream = TcpStream::connect("google.com:443").unwrap(); //! let mut stream = connector.connect("google.com", stream).unwrap(); //! //! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap(); //! let mut res = vec![]; //! stream.read_to_end(&mut res).unwrap(); //! println!("{}", String::from_utf8_lossy(&res)); //! ``` //! //! To accept connections as a server from remote clients: //! //! ```no_run //! use openssl::ssl::{SslMethod, SslAcceptor, SslStream, SslFiletype}; //! use std::net::{TcpListener, TcpStream}; //! use std::sync::Arc; //! use std::thread; //! //! //! let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); //! acceptor.set_private_key_file("key.pem", SslFiletype::PEM).unwrap(); //! acceptor.set_certificate_chain_file("certs.pem").unwrap(); //! acceptor.check_private_key().unwrap(); //! let acceptor = Arc::new(acceptor.build()); //! //! let listener = TcpListener::bind("0.0.0.0:8443").unwrap(); //! //! fn handle_client(stream: SslStream) { //! // ... //! } //! //! for stream in listener.incoming() { //! match stream { //! Ok(stream) => { //! let acceptor = acceptor.clone(); //! thread::spawn(move || { //! let stream = acceptor.accept(stream).unwrap(); //! handle_client(stream); //! }); //! } //! Err(e) => { /* connection failed */ } //! } //! } //! ``` use ffi; use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void}; use std::any::TypeId; use std::cmp; use std::collections::HashMap; use std::ffi::{CStr, CString}; use std::fmt; use std::io; use std::io::prelude::*; use std::marker::PhantomData; use std::mem::{self, ManuallyDrop}; use std::ops::{Deref, DerefMut}; use std::panic::resume_unwind; use std::path::Path; use std::ptr; use std::slice; use std::str; use std::sync::{Arc, Mutex}; use dh::{Dh, DhRef}; #[cfg(all(ossl101, not(ossl110)))] use ec::EcKey; use ec::EcKeyRef; use error::ErrorStack; use ex_data::Index; #[cfg(ossl111)] use hash::MessageDigest; #[cfg(ossl110)] use nid::Nid; use pkey::{HasPrivate, PKeyRef, Params, Private}; use srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use ssl::bio::BioMethod; use ssl::callbacks::*; use ssl::error::InnerError; use stack::{Stack, StackRef}; #[cfg(ossl102)] use x509::store::X509Store; use x509::store::{X509StoreBuilderRef, X509StoreRef}; #[cfg(any(ossl102, libressl261))] use x509::verify::X509VerifyParamRef; use x509::{X509Name, X509Ref, X509StoreContextRef, X509VerifyResult, X509}; use {cvt, cvt_n, cvt_p, init}; pub use ssl::connector::{ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, }; pub use ssl::error::{Error, ErrorCode, HandshakeError}; mod bio; mod callbacks; mod connector; mod error; #[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 { /// Disables a countermeasure against an SSLv3/TLSv1.0 vulnerability affecting CBC ciphers. const DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; /// A "reasonable default" set of options which enables compatibility flags. const ALL = ffi::SSL_OP_ALL; /// Do not query the MTU. /// /// Only affects DTLS connections. const NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU; /// Enables Cookie Exchange as described in [RFC 4347 Section 4.2.1]. /// /// Only affects DTLS connections. /// /// [RFC 4347 Section 4.2.1]: https://tools.ietf.org/html/rfc4347#section-4.2.1 const COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE; /// Disables the use of session tickets for session resumption. const NO_TICKET = ffi::SSL_OP_NO_TICKET; /// Always start a new session when performing a renegotiation on the server side. const NO_SESSION_RESUMPTION_ON_RENEGOTIATION = ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION; /// Disables the use of TLS compression. const NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION; /// Allow legacy insecure renegotiation with servers or clients that do not support secure /// renegotiation. const ALLOW_UNSAFE_LEGACY_RENEGOTIATION = ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION; /// Creates a new key for each session when using ECDHE. /// /// This is always enabled in OpenSSL 1.1.0. const SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE; /// Creates a new key for each session when using DHE. /// /// This is always enabled in OpenSSL 1.1.0. const SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE; /// Use the server's preferences rather than the client's when selecting a cipher. /// /// This has no effect on the client side. const CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE; /// Disables version rollback attach detection. const TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG; /// Disables the use of SSLv2. const NO_SSLV2 = ffi::SSL_OP_NO_SSLv2; /// Disables the use of SSLv3. const NO_SSLV3 = ffi::SSL_OP_NO_SSLv3; /// Disables the use of TLSv1.0. const NO_TLSV1 = ffi::SSL_OP_NO_TLSv1; /// Disables the use of TLSv1.1. const NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1; /// Disables the use of TLSv1.2. const NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2; /// Disables the use of TLSv1.3. /// /// Requires OpenSSL 1.1.1 or newer. #[cfg(ossl111)] const NO_TLSV1_3 = ffi::SSL_OP_NO_TLSv1_3; /// Disables the use of DTLSv1.0 /// /// Requires OpenSSL 1.0.2 or newer. #[cfg(any(ossl102, ossl110))] const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1; /// Disables the use of DTLSv1.2. /// /// Requires OpenSSL 1.0.2, or newer. #[cfg(any(ossl102, ossl110))] const NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2; /// Disables the use of all (D)TLS protocol versions. /// /// This can be used as a mask when whitelisting protocol versions. /// /// Requires OpenSSL 1.0.2 or newer. /// /// # Examples /// /// Only support TLSv1.2: /// /// ```rust /// use openssl::ssl::SslOptions; /// /// let options = SslOptions::NO_SSL_MASK & !SslOptions::NO_TLSV1_2; /// ``` #[cfg(any(ossl102, ossl110))] const NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK; /// Enable TLSv1.3 Compatibility mode. /// /// Requires OpenSSL 1.1.1 or newer. This is on by default in 1.1.1, but a future version /// may have this disabled by default. #[cfg(ossl111)] const ENABLE_MIDDLEBOX_COMPAT = ffi::SSL_OP_ENABLE_MIDDLEBOX_COMPAT; } } bitflags! { /// Options controlling the behavior of an `SslContext`. pub struct SslMode: c_long { /// Enables "short writes". /// /// Normally, a write in OpenSSL will always write out all of the requested data, even if it /// requires more than one TLS record or write to the underlying stream. This option will /// cause a write to return after writing a single TLS record instead. const ENABLE_PARTIAL_WRITE = ffi::SSL_MODE_ENABLE_PARTIAL_WRITE; /// Disables a check that the data buffer has not moved between calls when operating in a /// nonblocking context. const ACCEPT_MOVING_WRITE_BUFFER = ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; /// Enables automatic retries after TLS session events such as renegotiations or heartbeats. /// /// By default, OpenSSL will return a `WantRead` error after a renegotiation or heartbeat. /// This option will cause OpenSSL to automatically continue processing the requested /// operation instead. /// /// Note that `SslStream::read` and `SslStream::write` will automatically retry regardless /// of the state of this option. It only affects `SslStream::ssl_read` and /// `SslStream::ssl_write`. const AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY; /// Disables automatic chain building when verifying a peer's certificate. /// /// TLS peers are responsible for sending the entire certificate chain from the leaf to a /// trusted root, but some will incorrectly not do so. OpenSSL will try to build the chain /// out of certificates it knows of, and this option will disable that behavior. const NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN; /// Release memory buffers when the session does not need them. /// /// This saves ~34 KiB of memory for idle streams. const RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS; /// Sends the fake `TLS_FALLBACK_SCSV` cipher suite in the ClientHello message of a /// handshake. /// /// This should only be enabled if a client has failed to connect to a server which /// attempted to downgrade the protocol version of the session. /// /// Do not use this unless you know what you're doing! #[cfg(not(libressl))] const SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV; } } /// A type specifying the kind of protocol an `SslContext` will speak. #[derive(Copy, Clone)] pub struct SslMethod(*const ffi::SSL_METHOD); impl SslMethod { /// Support all versions of the TLS protocol. /// /// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method` /// on OpenSSL 1.0.x. pub fn tls() -> SslMethod { unsafe { SslMethod(TLS_method()) } } /// Support all versions of the DTLS protocol. /// /// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method` /// on OpenSSL 1.0.x. pub fn dtls() -> SslMethod { unsafe { SslMethod(DTLS_method()) } } /// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value. pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod { SslMethod(ptr) } /// Returns a pointer to the underlying OpenSSL value. pub fn as_ptr(&self) -> *const ffi::SSL_METHOD { self.0 } } unsafe impl Sync for SslMethod {} unsafe impl Send for SslMethod {} bitflags! { /// Options controling the behavior of certificate verification. pub struct SslVerifyMode: i32 { /// Verifies that the peer's certificate is trusted. /// /// On the server side, this will cause OpenSSL to request a certificate from the client. const PEER = ffi::SSL_VERIFY_PEER; /// Disables verification of the peer's certificate. /// /// On the server side, this will cause OpenSSL to not request a certificate from the /// client. On the client side, the certificate will be checked for validity, but the /// negotiation will continue regardless of the result of that check. const NONE = ffi::SSL_VERIFY_NONE; /// On the server side, abort the handshake if the client did not send a certificate. /// /// This should be paired with `SSL_VERIFY_PEER`. It has no effect on the client side. const FAIL_IF_NO_PEER_CERT = ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT; } } bitflags! { /// Options controlling the behavior of session caching. pub struct SslSessionCacheMode: c_long { /// No session caching for the client or server takes place. const OFF = ffi::SSL_SESS_CACHE_OFF; /// Enable session caching on the client side. /// /// OpenSSL has no way of identifying the proper session to reuse automatically, so the /// application is responsible for setting it explicitly via [`SslRef::set_session`]. /// /// [`SslRef::set_session`]: struct.SslRef.html#method.set_session const CLIENT = ffi::SSL_SESS_CACHE_CLIENT; /// Enable session caching on the server side. /// /// This is the default mode. const SERVER = ffi::SSL_SESS_CACHE_SERVER; /// Enable session caching on both the client and server side. const BOTH = ffi::SSL_SESS_CACHE_BOTH; /// Disable automatic removal of expired sessions from the session cache. const NO_AUTO_CLEAR = ffi::SSL_SESS_CACHE_NO_AUTO_CLEAR; /// Disable use of the internal session cache for session lookups. const NO_INTERNAL_LOOKUP = ffi::SSL_SESS_CACHE_NO_INTERNAL_LOOKUP; /// Disable use of the internal session cache for session storage. const NO_INTERNAL_STORE = ffi::SSL_SESS_CACHE_NO_INTERNAL_STORE; /// Disable use of the internal session cache for storage and lookup. const NO_INTERNAL = ffi::SSL_SESS_CACHE_NO_INTERNAL; } } #[cfg(ossl111)] bitflags! { /// Which messages and under which conditions an extension should be added or expected. pub struct ExtensionContext: c_uint { /// This extension is only allowed in TLS const TLS_ONLY = ffi::SSL_EXT_TLS_ONLY; /// This extension is only allowed in DTLS const DTLS_ONLY = ffi::SSL_EXT_DTLS_ONLY; /// Some extensions may be allowed in DTLS but we don't implement them for it const TLS_IMPLEMENTATION_ONLY = ffi::SSL_EXT_TLS_IMPLEMENTATION_ONLY; /// Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is const SSL3_ALLOWED = ffi::SSL_EXT_SSL3_ALLOWED; /// Extension is only defined for TLS1.2 and below const TLS1_2_AND_BELOW_ONLY = ffi::SSL_EXT_TLS1_2_AND_BELOW_ONLY; /// Extension is only defined for TLS1.3 and above const TLS1_3_ONLY = ffi::SSL_EXT_TLS1_3_ONLY; /// Ignore this extension during parsing if we are resuming const IGNORE_ON_RESUMPTION = ffi::SSL_EXT_IGNORE_ON_RESUMPTION; const CLIENT_HELLO = ffi::SSL_EXT_CLIENT_HELLO; /// Really means TLS1.2 or below const TLS1_2_SERVER_HELLO = ffi::SSL_EXT_TLS1_2_SERVER_HELLO; const TLS1_3_SERVER_HELLO = ffi::SSL_EXT_TLS1_3_SERVER_HELLO; const TLS1_3_ENCRYPTED_EXTENSIONS = ffi::SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS; const TLS1_3_HELLO_RETRY_REQUEST = ffi::SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST; const TLS1_3_CERTIFICATE = ffi::SSL_EXT_TLS1_3_CERTIFICATE; const TLS1_3_NEW_SESSION_TICKET = ffi::SSL_EXT_TLS1_3_NEW_SESSION_TICKET; const TLS1_3_CERTIFICATE_REQUEST = ffi::SSL_EXT_TLS1_3_CERTIFICATE_REQUEST; } } /// An identifier of the format of a certificate or key file. #[derive(Copy, Clone)] pub struct SslFiletype(c_int); impl SslFiletype { /// Constructs an `SslFiletype` from a raw OpenSSL value. pub fn from_raw(raw: c_int) -> SslFiletype { SslFiletype(raw) } /// Returns the raw OpenSSL value represented by this type. pub fn as_raw(&self) -> c_int { self.0 } /// The PEM format. /// /// This corresponds to `SSL_FILETYPE_PEM`. pub const PEM: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_PEM); /// The ASN1 format. /// /// This corresponds to `SSL_FILETYPE_ASN1`. pub const ASN1: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_ASN1); } /// An identifier of a certificate status type. #[derive(Copy, Clone)] pub struct StatusType(c_int); impl StatusType { /// Constructs a `StatusType` from a raw OpenSSL value. pub fn from_raw(raw: c_int) -> StatusType { StatusType(raw) } /// Returns the raw OpenSSL value represented by this type. pub fn as_raw(&self) -> c_int { self.0 } /// An OSCP status. pub const OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp); } /// An identifier of a session name type. #[derive(Copy, Clone)] pub struct NameType(c_int); impl NameType { /// Constructs a `StatusType` from a raw OpenSSL value. pub fn from_raw(raw: c_int) -> StatusType { StatusType(raw) } /// Returns the raw OpenSSL value represented by this type. pub fn as_raw(&self) -> c_int { self.0 } /// A host name. pub const HOST_NAME: NameType = NameType(ffi::TLSEXT_NAMETYPE_host_name); } 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( _parent: *mut c_void, ptr: *mut c_void, _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int, _argl: c_long, _argp: *mut c_void, ) { if !ptr.is_null() { Box::::from_raw(ptr as *mut T); } } /// An error returned from the SNI callback. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct SniError(c_int); impl SniError { /// Abort the handshake with a fatal alert. pub const ALERT_FATAL: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL); /// Send a warning alert to the client and continue the handshake. pub const ALERT_WARNING: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_WARNING); pub const NOACK: SniError = SniError(ffi::SSL_TLSEXT_ERR_NOACK); } /// An SSL/TLS alert. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct SslAlert(c_int); impl SslAlert { /// Alert 112 - `unrecognized_name`. pub const UNRECOGNIZED_NAME: SslAlert = SslAlert(ffi::SSL_AD_UNRECOGNIZED_NAME); pub const ILLEGAL_PARAMETER: SslAlert = SslAlert(ffi::SSL_AD_ILLEGAL_PARAMETER); pub const DECODE_ERROR: SslAlert = SslAlert(ffi::SSL_AD_DECODE_ERROR); } /// An error returned from an ALPN selection callback. /// /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. #[cfg(any(ossl102, libressl261))] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct AlpnError(c_int); #[cfg(any(ossl102, libressl261))] impl AlpnError { /// Terminate the handshake with a fatal alert. /// /// Requires OpenSSL 1.1.0 or newer. #[cfg(any(ossl110))] pub const ALERT_FATAL: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL); /// Do not select a protocol, but continue the handshake. pub const NOACK: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_NOACK); } /// The result of a client hello callback. /// /// Requires OpenSSL 1.1.1 or newer. #[cfg(ossl111)] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct ClientHelloResponse(c_int); #[cfg(ossl111)] impl ClientHelloResponse { /// Continue the handshake. pub const SUCCESS: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_SUCCESS); /// Return from the handshake with an `ErrorCode::WANT_CLIENT_HELLO_CB` error. pub const RETRY: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_RETRY); } /// An SSL/TLS protocol version. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct SslVersion(c_int); impl SslVersion { /// SSLv3 pub const SSL3: SslVersion = SslVersion(ffi::SSL3_VERSION); /// TLSv1.0 pub const TLS1: SslVersion = SslVersion(ffi::TLS1_VERSION); /// TLSv1.1 pub const TLS1_1: SslVersion = SslVersion(ffi::TLS1_1_VERSION); /// TLSv1.2 pub const TLS1_2: SslVersion = SslVersion(ffi::TLS1_2_VERSION); /// TLSv1.3 /// /// Requires OpenSSL 1.1.1 or newer. #[cfg(ossl111)] pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION); } /// A standard implementation of protocol selection for Application Layer Protocol Negotiation /// (ALPN). /// /// `server` should contain the server's list of supported protocols and `client` the client's. They /// must both be in the ALPN wire format. See the documentation for /// [`SslContextBuilder::set_alpn_protos`] for details. /// /// It will select the first protocol supported by the server which is also supported by the client. /// /// This corresponds to [`SSL_select_next_proto`]. /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos /// [`SSL_select_next_proto`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8]> { unsafe { let mut out = ptr::null_mut(); let mut outlen = 0; let r = ffi::SSL_select_next_proto( &mut out, &mut outlen, server.as_ptr(), server.len() as c_uint, client.as_ptr(), client.len() as c_uint, ); if r == ffi::OPENSSL_NPN_NEGOTIATED { Some(slice::from_raw_parts(out as *const u8, outlen as usize)) } else { None } } } /// A builder for `SslContext`s. pub struct SslContextBuilder(SslContext); impl SslContextBuilder { /// Creates a new `SslContextBuilder`. /// /// This corresponds to [`SSL_CTX_new`]. /// /// [`SSL_CTX_new`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_new.html pub fn new(method: SslMethod) -> Result { unsafe { init(); let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?; Ok(SslContextBuilder::from_ptr(ctx)) } } /// Creates an `SslContextBuilder` from a pointer to a raw OpenSSL value. pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder { SslContextBuilder(SslContext::from_ptr(ctx)) } /// Returns a pointer to the raw OpenSSL value. pub fn as_ptr(&self) -> *mut ffi::SSL_CTX { self.0.as_ptr() } /// Configures the certificate verification method for new connections. /// /// This corresponds to [`SSL_CTX_set_verify`]. /// /// [`SSL_CTX_set_verify`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html pub fn set_verify(&mut self, mode: SslVerifyMode) { unsafe { ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, None); } } /// Configures the certificate verification method for new connections and /// registers a verification callback. /// /// The callback is passed a boolean indicating if OpenSSL's internal verification succeeded as /// well as a reference to the `X509StoreContext` which can be used to examine the certificate /// chain. It should return a boolean indicating if verification succeeded. /// /// This corresponds to [`SSL_CTX_set_verify`]. /// /// [`SSL_CTX_set_verify`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify.html pub fn set_verify_callback(&mut self, mode: SslVerifyMode, verify: F) where F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), verify); ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::)); } } /// Configures the server name indication (SNI) callback for new connections. /// /// SNI is used to allow a single server to handle requests for multiple domains, each of which /// has its own certificate chain and configuration. /// /// Obtain the server name with the `servername` method and then set the corresponding context /// with `set_ssl_context` /// /// This corresponds to [`SSL_CTX_set_tlsext_servername_callback`]. /// /// [`SSL_CTX_set_tlsext_servername_callback`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_tlsext_servername_callback.html // FIXME tlsext prefix? pub fn set_servername_callback(&mut self, callback: F) where F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send, { unsafe { // The SNI callback is somewhat unique in that the callback associated with the original // context associated with an SSL can be used even if the SSL's context has been swapped // out. When that happens, we wouldn't be able to look up the callback's state in the // context's ex data. Instead, pass the pointer directly as the servername arg. It's // still stored in ex data to manage the lifetime. let arg = self.set_ex_data_inner(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_tlsext_servername_arg(self.as_ptr(), arg); let f: extern "C" fn(_, _, _) -> _ = raw_sni::; let f: extern "C" fn() = mem::transmute(f); ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(f)); } } /// Sets the certificate verification depth. /// /// If the peer's certificate chain is longer than this value, verification will fail. /// /// This corresponds to [`SSL_CTX_set_verify_depth`]. /// /// [`SSL_CTX_set_verify_depth`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_verify_depth.html pub fn set_verify_depth(&mut self, depth: u32) { unsafe { ffi::SSL_CTX_set_verify_depth(self.as_ptr(), depth as c_int); } } /// Sets a custom certificate store for verifying peer certificates. /// /// Requires OpenSSL 1.0.2 or newer. /// /// This corresponds to [`SSL_CTX_set0_verify_cert_store`]. /// /// [`SSL_CTX_set0_verify_cert_store`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set0_verify_cert_store.html #[cfg(any(ossl102, ossl110))] pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { unsafe { let ptr = cert_store.as_ptr(); cvt(ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), ptr) as c_int)?; mem::forget(cert_store); Ok(()) } } /// Controls read ahead behavior. /// /// If enabled, OpenSSL will read as much data as is available from the underlying stream, /// instead of a single record at a time. /// /// It has no effect when used with DTLS. /// /// This corresponds to [`SSL_CTX_set_read_ahead`]. /// /// [`SSL_CTX_set_read_ahead`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_read_ahead.html pub fn set_read_ahead(&mut self, read_ahead: bool) { unsafe { ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as c_long); } } /// Sets the mode used by the context, returning the previous mode. /// /// This corresponds to [`SSL_CTX_set_mode`]. /// /// [`SSL_CTX_set_mode`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_mode.html pub fn set_mode(&mut self, mode: SslMode) -> SslMode { unsafe { let bits = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits()); SslMode { bits } } } /// Sets the parameters to be used during ephemeral Diffie-Hellman key exchange. /// /// This corresponds to [`SSL_CTX_set_tmp_dh`]. /// /// [`SSL_CTX_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tmp_dh.html pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } } /// Sets the callback which will generate parameters to be used during ephemeral Diffie-Hellman /// key exchange. /// /// The callback is provided with a reference to the `Ssl` for the session, as well as a boolean /// indicating if the selected cipher is export-grade, and the key length. The export and key /// length options are archaic and should be ignored in almost all cases. /// /// This corresponds to [`SSL_CTX_set_tmp_dh_callback`]. /// /// [`SSL_CTX_set_tmp_dh_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tmp_dh.html pub fn set_tmp_dh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), raw_tmp_dh::); } } /// Sets the parameters to be used during ephemeral elliptic curve Diffie-Hellman key exchange. /// /// This corresponds to `SSL_CTX_set_tmp_ecdh`. pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } } /// Sets the callback which will generate parameters to be used during ephemeral elliptic curve /// Diffie-Hellman key exchange. /// /// The callback is provided with a reference to the `Ssl` for the session, as well as a boolean /// indicating if the selected cipher is export-grade, and the key length. The export and key /// length options are archaic and should be ignored in almost all cases. /// /// Requires OpenSSL 1.0.1 or 1.0.2. /// /// This corresponds to `SSL_CTX_set_tmp_ecdh_callback`. #[cfg(all(ossl101, not(ossl110)))] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), raw_tmp_ecdh::); } } /// Use the default locations of trusted certificates for verification. /// /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables /// if present, or defaults specified at OpenSSL build time otherwise. /// /// This corresponds to [`SSL_CTX_set_default_verify_paths`]. /// /// [`SSL_CTX_set_default_verify_paths`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_default_verify_paths.html pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_default_verify_paths(self.as_ptr())).map(|_| ()) } } /// Loads trusted root certificates from a file. /// /// The file should contain a sequence of PEM-formatted CA certificates. /// /// This corresponds to [`SSL_CTX_load_verify_locations`]. /// /// [`SSL_CTX_load_verify_locations`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_load_verify_locations.html pub fn set_ca_file>(&mut self, file: P) -> Result<(), ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { cvt(ffi::SSL_CTX_load_verify_locations( self.as_ptr(), file.as_ptr() as *const _, ptr::null(), )) .map(|_| ()) } } /// Sets the list of CA names sent to the client. /// /// The CA certificates must still be added to the trust root - they are not automatically set /// as trusted by this method. /// /// This corresponds to [`SSL_CTX_set_client_CA_list`]. /// /// [`SSL_CTX_set_client_CA_list`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_client_CA_list.html pub fn set_client_ca_list(&mut self, list: Stack) { unsafe { ffi::SSL_CTX_set_client_CA_list(self.as_ptr(), list.as_ptr()); mem::forget(list); } } /// 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 /// able to reuse sessions. It should be be set to a unique value per server, unless multiple /// servers share a session cache. /// /// This value should be set when using client certificates, or each request will fail its /// handshake and need to be restarted. /// /// This corresponds to [`SSL_CTX_set_session_id_context`]. /// /// [`SSL_CTX_set_session_id_context`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_session_id_context.html pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(sid_ctx.len() <= c_uint::max_value() as usize); cvt(ffi::SSL_CTX_set_session_id_context( self.as_ptr(), sid_ctx.as_ptr(), sid_ctx.len() as c_uint, )) .map(|_| ()) } } /// Loads a leaf certificate from a file. /// /// Only a single certificate will be loaded - use `add_extra_chain_cert` to add the remainder /// of the certificate chain, or `set_certificate_chain_file` to load the entire chain from a /// single file. /// /// This corresponds to [`SSL_CTX_use_certificate_file`]. /// /// [`SSL_CTX_use_certificate_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html pub fn set_certificate_file>( &mut self, file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { cvt(ffi::SSL_CTX_use_certificate_file( self.as_ptr(), file.as_ptr() as *const _, file_type.as_raw(), )) .map(|_| ()) } } /// Loads a certificate chain from a file. /// /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf /// certificate, and the remainder forming the chain of certificates up to and including the /// trusted root certificate. /// /// This corresponds to [`SSL_CTX_use_certificate_chain_file`]. /// /// [`SSL_CTX_use_certificate_chain_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html pub fn set_certificate_chain_file>( &mut self, file: P, ) -> Result<(), ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { cvt(ffi::SSL_CTX_use_certificate_chain_file( self.as_ptr(), file.as_ptr() as *const _, )) .map(|_| ()) } } /// Sets the leaf certificate. /// /// Use `add_extra_chain_cert` to add the remainder of the certificate chain. /// /// This corresponds to [`SSL_CTX_use_certificate`]. /// /// [`SSL_CTX_use_certificate`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_certificate_file.html pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } /// Appends a certificate to the certificate chain. /// /// This chain should contain all certificates necessary to go from the certificate specified by /// `set_certificate` to a trusted root. /// /// This corresponds to [`SSL_CTX_add_extra_chain_cert`]. /// /// [`SSL_CTX_add_extra_chain_cert`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_extra_chain_cert.html pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)?; mem::forget(cert); Ok(()) } } /// Loads the private key from a file. /// /// This corresponds to [`SSL_CTX_use_PrivateKey_file`]. /// /// [`SSL_CTX_use_PrivateKey_file`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_PrivateKey_file.html pub fn set_private_key_file>( &mut self, file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { cvt(ffi::SSL_CTX_use_PrivateKey_file( self.as_ptr(), file.as_ptr() as *const _, file_type.as_raw(), )) .map(|_| ()) } } /// Sets the private key. /// /// This corresponds to [`SSL_CTX_use_PrivateKey`]. /// /// [`SSL_CTX_use_PrivateKey`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_use_PrivateKey_file.html pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where T: HasPrivate, { unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } } /// Sets the list of supported ciphers for protocols before TLSv1.3. /// /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3. /// /// See [`ciphers`] for details on the format. /// /// This corresponds to [`SSL_CTX_set_cipher_list`]. /// /// [`ciphers`]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html /// [`SSL_CTX_set_cipher_list`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_ciphers.html pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); unsafe { cvt(ffi::SSL_CTX_set_cipher_list( self.as_ptr(), cipher_list.as_ptr() as *const _, )) .map(|_| ()) } } /// Sets the list of supported ciphers for the TLSv1.3 protocol. /// /// The `set_cipher_list` method controls lthe cipher suites for protocols before TLSv1.3. /// /// The format consists of TLSv1.3 ciphersuite names separated by `:` characters in order of /// preference. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_CTX_set_ciphersuites`]. /// /// [`SSL_CTX_set_ciphersuites`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_ciphersuites.html #[cfg(ossl111)] pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); unsafe { cvt(ffi::SSL_CTX_set_ciphersuites( self.as_ptr(), cipher_list.as_ptr() as *const _, )) .map(|_| ()) } } /// Enables ECDHE key exchange with an automatically chosen curve list. /// /// Requires OpenSSL 1.0.2. /// /// This corresponds to [`SSL_CTX_set_ecdh_auto`]. /// /// [`SSL_CTX_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ecdh_auto.html #[cfg(any(libressl, all(ossl102, not(ossl110))))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } } /// Sets the options used by the context, returning the old set. /// /// This corresponds to [`SSL_CTX_set_options`]. /// /// # Note /// /// This *enables* the specified options, but does not disable unspecified options. Use /// `clear_options` for that. /// /// [`SSL_CTX_set_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn set_options(&mut self, option: SslOptions) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; SslOptions { bits } } /// Returns the options used by the context. /// /// This corresponds to [`SSL_CTX_get_options`]. /// /// [`SSL_CTX_get_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn options(&self) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) }; SslOptions { bits } } /// Clears the options used by the context, returning the old set. /// /// This corresponds to [`SSL_CTX_clear_options`]. /// /// [`SSL_CTX_clear_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn clear_options(&mut self, option: SslOptions) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; SslOptions { bits } } /// Sets the minimum supported protocol version. /// /// A value of `None` will enable protocol versions down the the lowest version supported by /// OpenSSL. /// /// This corresponds to [`SSL_CTX_set_min_proto_version`]. /// /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html #[cfg(any(ossl110, libressl261))] pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_min_proto_version( self.as_ptr(), version.map_or(0, |v| v.0 as _), )) .map(|_| ()) } } /// Sets the maximum supported protocol version. /// /// A value of `None` will enable protocol versions down the the highest version supported by /// OpenSSL. /// /// This corresponds to [`SSL_CTX_set_max_proto_version`]. /// /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html #[cfg(any(ossl110, libressl261))] pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_max_proto_version( self.as_ptr(), version.map_or(0, |v| v.0 as _), )) .map(|_| ()) } } /// Gets the minimum supported protocol version. /// /// A value of `None` indicates that all versions down the the lowest version supported by /// OpenSSL are enabled. /// /// This corresponds to [`SSL_CTX_get_min_proto_version`]. /// /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. /// /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html #[cfg(any(ossl110g, libressl270))] pub fn min_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); if r == 0 { None } else { Some(SslVersion(r)) } } } /// Gets the maximum supported protocol version. /// /// A value of `None` indicates that all versions down the the highest version supported by /// OpenSSL are enabled. /// /// This corresponds to [`SSL_CTX_get_max_proto_version`]. /// /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. /// /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html #[cfg(any(ossl110g, libressl270))] pub fn max_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); if r == 0 { None } else { Some(SslVersion(r)) } } } /// Sets the protocols to sent to the server for Application Layer Protocol Negotiation (ALPN). /// /// The input must be in ALPN "wire format". It consists of a sequence of supported protocol /// names prefixed by their byte length. For example, the protocol list consisting of `spdy/1` /// and `http/1.1` is encoded as `b"\x06spdy/1\x08http/1.1"`. The protocols are ordered by /// preference. /// /// This corresponds to [`SSL_CTX_set_alpn_protos`]. /// /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html #[cfg(any(ossl102, libressl261))] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(protocols.len() <= c_uint::max_value() as usize); let r = ffi::SSL_CTX_set_alpn_protos( self.as_ptr(), protocols.as_ptr(), protocols.len() as c_uint, ); // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D: if r == 0 { Ok(()) } else { Err(ErrorStack::get()) } } } /// Enables the DTLS extension "use_srtp" as defined in RFC5764. /// /// This corresponds to [`SSL_CTX_set_tlsext_use_srtp`]. /// /// [`SSL_CTX_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> { unsafe { let cstr = CString::new(protocols).unwrap(); let r = ffi::SSL_CTX_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr()); // fun fact, set_tlsext_use_srtp has a reversed return code D: if r == 0 { Ok(()) } else { Err(ErrorStack::get()) } } } /// Sets the callback used by a server to select a protocol for Application Layer Protocol /// Negotiation (ALPN). /// /// The callback is provided with the client's protocol list in ALPN wire format. See the /// documentation for [`SslContextBuilder::set_alpn_protos`] for details. It should return one /// of those protocols on success. The [`select_next_proto`] function implements the standard /// protocol selection algorithm. /// /// This corresponds to [`SSL_CTX_set_alpn_select_cb`]. /// /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos /// [`select_next_proto`]: fn.select_next_proto.html /// [`SSL_CTX_set_alpn_select_cb`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html #[cfg(any(ossl102, libressl261))] pub fn set_alpn_select_callback(&mut self, callback: F) where F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_alpn_select_cb( self.as_ptr(), callbacks::raw_alpn_select::, ptr::null_mut(), ); } } /// Checks for consistency between the private key and certificate. /// /// This corresponds to [`SSL_CTX_check_private_key`]. /// /// [`SSL_CTX_check_private_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_check_private_key.html pub fn check_private_key(&self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) } } /// Returns a shared reference to the context's certificate store. /// /// This corresponds to [`SSL_CTX_get_cert_store`]. /// /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html pub fn cert_store(&self) -> &X509StoreBuilderRef { unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } } /// Returns a mutable reference to the context's certificate store. /// /// This corresponds to [`SSL_CTX_get_cert_store`]. /// /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef { unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } } /// Sets the callback dealing with OCSP stapling. /// /// On the client side, this callback is responsible for validating the OCSP status response /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method. /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be /// terminated. /// /// On the server side, this callback is resopnsible for setting the OCSP status response to be /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and /// `Ok(false)` indicates that the status should not be returned to the client. /// /// This corresponds to [`SSL_CTX_set_tlsext_status_cb`]. /// /// [`SSL_CTX_set_tlsext_status_cb`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_tlsext_status_cb.html pub fn set_status_callback(&mut self, callback: F) -> Result<(), ErrorStack> where F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); cvt( ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(raw_tlsext_status::)) as c_int, ) .map(|_| ()) } } /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK client. /// /// The callback will be called with the SSL context, an identity hint if one was provided /// by the server, a mutable slice for each of the identity and pre-shared key bytes. The /// identity must be written as a null-terminated C string. /// /// This corresponds to [`SSL_CTX_set_psk_client_callback`]. /// /// [`SSL_CTX_set_psk_client_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_psk_client_callback.html #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub fn set_psk_client_callback(&mut self, callback: F) where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_client_psk::)); } } #[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 F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + 'static + Sync + Send, { self.set_psk_client_callback(callback) } /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK server. /// /// The callback will be called with the SSL context, an identity provided by the client, /// and, a mutable slice for the pre-shared key bytes. The callback returns the number of /// bytes in the pre-shared key. /// /// This corresponds to [`SSL_CTX_set_psk_server_callback`]. /// /// [`SSL_CTX_set_psk_server_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_psk_server_callback.html #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub fn set_psk_server_callback(&mut self, callback: F) where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_psk_server_callback(self.as_ptr(), Some(raw_server_psk::)); } } /// Sets the callback which is called when new sessions are negotiated. /// /// This can be used by clients to implement session caching. While in TLSv1.2 the session is /// available to access via [`SslRef::session`] immediately after the handshake completes, this /// is not the case for TLSv1.3. There, a session is not generally available immediately, and /// the server may provide multiple session tokens to the client over a single session. The new /// session callback is a portable way to deal with both cases. /// /// Note that session caching must be enabled for the callback to be invoked, and it defaults /// off for clients. [`set_session_cache_mode`] controls that behavior. /// /// This corresponds to [`SSL_CTX_sess_set_new_cb`]. /// /// [`SslRef::session`]: struct.SslRef.html#method.session /// [`set_session_cache_mode`]: #method.set_session_cache_mode /// [`SSL_CTX_sess_set_new_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html pub fn set_new_session_callback(&mut self, callback: F) where F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), Some(callbacks::raw_new_session::)); } } /// Sets the callback which is called when sessions are removed from the context. /// /// Sessions can be removed because they have timed out or because they are considered faulty. /// /// This corresponds to [`SSL_CTX_sess_set_remove_cb`]. /// /// [`SSL_CTX_sess_set_remove_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html pub fn set_remove_session_callback(&mut self, callback: F) where F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_sess_set_remove_cb( self.as_ptr(), Some(callbacks::raw_remove_session::), ); } } /// Sets the callback which is called when a client proposed to resume a session but it was not /// found in the internal cache. /// /// The callback is passed a reference to the session ID provided by the client. It should /// return the session corresponding to that ID if available. This is only used for servers, not /// clients. /// /// This corresponds to [`SSL_CTX_sess_set_get_cb`]. /// /// # Safety /// /// The returned `SslSession` must not be associated with a different `SslContext`. /// /// [`SSL_CTX_sess_set_get_cb`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_sess_set_new_cb.html pub unsafe fn set_get_session_callback(&mut self, callback: F) where F: Fn(&mut SslRef, &[u8]) -> Option + 'static + Sync + Send, { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_sess_set_get_cb(self.as_ptr(), Some(callbacks::raw_get_session::)); } /// Sets the TLS key logging callback. /// /// The callback is invoked whenever TLS key material is generated, and is passed a line of NSS /// SSLKEYLOGFILE-formatted text. This can be used by tools like Wireshark to decrypt message /// traffic. The line does not contain a trailing newline. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_CTX_set_keylog_callback`]. /// /// [`SSL_CTX_set_keylog_callback`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_keylog_callback.html #[cfg(ossl111)] pub fn set_keylog_callback(&mut self, callback: F) where F: Fn(&SslRef, &str) + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_keylog_callback(self.as_ptr(), Some(callbacks::raw_keylog::)); } } /// Sets the session caching mode use for connections made with the context. /// /// Returns the previous session caching mode. /// /// This corresponds to [`SSL_CTX_set_session_cache_mode`]. /// /// [`SSL_CTX_set_session_cache_mode`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_session_cache_mode.html pub fn set_session_cache_mode(&mut self, mode: SslSessionCacheMode) -> SslSessionCacheMode { unsafe { let bits = ffi::SSL_CTX_set_session_cache_mode(self.as_ptr(), mode.bits()); SslSessionCacheMode { bits } } } /// Sets the callback for generating an application cookie for TLS1.3 /// stateless handshakes. /// /// The callback will be called with the SSL context and a slice into which the cookie /// should be written. The callback should return the number of bytes written. /// /// This corresponds to `SSL_CTX_set_stateless_cookie_generate_cb`. #[cfg(ossl111)] pub fn set_stateless_cookie_generate_cb(&mut self, callback: F) where F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_stateless_cookie_generate_cb( self.as_ptr(), Some(raw_stateless_cookie_generate::), ); } } /// Sets the callback for verifying an application cookie for TLS1.3 /// stateless handshakes. /// /// The callback will be called with the SSL context and the cookie supplied by the /// client. It should return true if and only if the cookie is valid. /// /// Note that the OpenSSL implementation independently verifies the integrity of /// application cookies using an HMAC before invoking the supplied callback. /// /// This corresponds to `SSL_CTX_set_stateless_cookie_verify_cb`. #[cfg(ossl111)] pub fn set_stateless_cookie_verify_cb(&mut self, callback: F) where F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_stateless_cookie_verify_cb( self.as_ptr(), Some(raw_stateless_cookie_verify::), ) } } /// Sets the callback for generating a DTLSv1 cookie /// /// The callback will be called with the SSL context and a slice into which the cookie /// should be written. The callback should return the number of bytes written. /// /// This corresponds to `SSL_CTX_set_cookie_generate_cb`. pub fn set_cookie_generate_cb(&mut self, callback: F) where F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_cookie_generate_cb(self.as_ptr(), Some(raw_cookie_generate::)); } } /// Sets the callback for verifying a DTLSv1 cookie /// /// The callback will be called with the SSL context and the cookie supplied by the /// client. It should return true if and only if the cookie is valid. /// /// This corresponds to `SSL_CTX_set_cookie_verify_cb`. pub fn set_cookie_verify_cb(&mut self, callback: F) where F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, { unsafe { self.set_ex_data(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_cookie_verify_cb(self.as_ptr(), Some(raw_cookie_verify::)); } } /// Sets the extra data at the specified index. /// /// This can be used to provide data to callbacks registered with the context. Use the /// `SslContext::new_ex_index` method to create an `Index`. /// /// This corresponds to [`SSL_CTX_set_ex_data`]. /// /// [`SSL_CTX_set_ex_data`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ex_data.html pub fn set_ex_data(&mut self, index: Index, data: T) { self.set_ex_data_inner(index, data); } fn set_ex_data_inner(&mut self, index: Index, data: T) -> *mut c_void { unsafe { let data = Box::into_raw(Box::new(data)) as *mut c_void; ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data); data } } /// Adds a custom extension for a TLS/DTLS client or server for all supported protocol versions. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_CTX_add_custom_ext`]. /// /// [`SSL_CTX_add_custom_ext`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_add_custom_ext.html #[cfg(ossl111)] pub fn add_custom_ext( &mut self, ext_type: u16, context: ExtensionContext, add_cb: AddFn, parse_cb: ParseFn, ) -> Result<(), ErrorStack> where 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> + 'static + Sync + Send, { let ret = unsafe { self.set_ex_data(SslContext::cached_ex_index::(), add_cb); self.set_ex_data(SslContext::cached_ex_index::(), parse_cb); ffi::SSL_CTX_add_custom_ext( self.as_ptr(), ext_type as c_uint, context.bits(), Some(raw_custom_ext_add::), Some(raw_custom_ext_free::), ptr::null_mut(), Some(raw_custom_ext_parse::), ptr::null_mut(), ) }; if ret == 1 { Ok(()) } else { Err(ErrorStack::get()) } } /// Sets the maximum amount of early data that will be accepted on incoming connections. /// /// Defaults to 0. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_CTX_set_max_early_data`]. /// /// [`SSL_CTX_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_max_early_data.html #[cfg(ossl111)] pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> { if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 { Ok(()) } else { Err(ErrorStack::get()) } } /// 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 #[cfg(ossl111)] pub fn set_client_hello_callback(&mut self, callback: F) where F: Fn(&mut SslRef, &mut SslAlert) -> Result + 'static + Sync + Send, { unsafe { let ptr = self.set_ex_data_inner(SslContext::cached_ex_index::(), callback); ffi::SSL_CTX_set_client_hello_cb( self.as_ptr(), Some(callbacks::raw_client_hello::), ptr, ); } } /// 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 } } foreign_type_and_impl_send_sync! { type CType = ffi::SSL_CTX; fn drop = ffi::SSL_CTX_free; /// A context object for TLS streams. /// /// Applications commonly configure a single `SslContext` that is shared by all of its /// `SslStreams`. pub struct SslContext; /// Reference to [`SslContext`] /// /// [`SslContext`]: struct.SslContext.html pub struct SslContextRef; } impl Clone for SslContext { fn clone(&self) -> Self { unsafe { SSL_CTX_up_ref(self.as_ptr()); SslContext::from_ptr(self.as_ptr()) } } } // TODO: add useful info here impl fmt::Debug for SslContext { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "SslContext") } } impl SslContext { /// Creates a new builder object for an `SslContext`. pub fn builder(method: SslMethod) -> Result { SslContextBuilder::new(method) } /// Returns a new extra data index. /// /// Each invocation of this function is guaranteed to return a distinct index. These can be used /// to store data in the context that can be retrieved later by callbacks, for example. /// /// This corresponds to [`SSL_CTX_get_ex_new_index`]. /// /// [`SSL_CTX_get_ex_new_index`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_get_ex_new_index.html pub fn new_ex_index() -> Result, ErrorStack> where T: 'static + Sync + Send, { unsafe { ffi::init(); let idx = cvt_n(get_new_idx(free_data_box::))?; Ok(Index::from_raw(idx)) } } // FIXME should return a result? fn cached_ex_index() -> Index where T: 'static + Sync + Send, { unsafe { let idx = *INDEXES .lock() .unwrap_or_else(|e| e.into_inner()) .entry(TypeId::of::()) .or_insert_with(|| SslContext::new_ex_index::().unwrap().as_raw()); Index::from_raw(idx) } } } impl SslContextRef { /// Returns the certificate associated with this `SslContext`, if present. /// /// Requires OpenSSL 1.0.2 or newer. /// /// This corresponds to [`SSL_CTX_get0_certificate`]. /// /// [`SSL_CTX_get0_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html #[cfg(any(ossl102, ossl110))] pub fn certificate(&self) -> Option<&X509Ref> { unsafe { let ptr = ffi::SSL_CTX_get0_certificate(self.as_ptr()); if ptr.is_null() { None } else { Some(X509Ref::from_ptr(ptr)) } } } /// Returns the private key associated with this `SslContext`, if present. /// /// Requires OpenSSL 1.0.2 or newer. /// /// This corresponds to [`SSL_CTX_get0_privatekey`]. /// /// [`SSL_CTX_get0_privatekey`]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html #[cfg(any(ossl102, ossl110))] pub fn private_key(&self) -> Option<&PKeyRef> { unsafe { let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr()); if ptr.is_null() { None } else { Some(PKeyRef::from_ptr(ptr)) } } } /// Returns a shared reference to the certificate store used for verification. /// /// This corresponds to [`SSL_CTX_get_cert_store`]. /// /// [`SSL_CTX_get_cert_store`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_get_cert_store.html pub fn cert_store(&self) -> &X509StoreRef { unsafe { X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } } /// Returns a shared reference to the stack of certificates making up the chain from the leaf. /// /// This corresponds to `SSL_CTX_get_extra_chain_certs`. pub fn extra_chain_certs(&self) -> &StackRef { unsafe { let mut chain = ptr::null_mut(); ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain); assert!(!chain.is_null()); StackRef::from_ptr(chain) } } /// Returns a reference to the extra data at the specified index. /// /// This corresponds to [`SSL_CTX_get_ex_data`]. /// /// [`SSL_CTX_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_get_ex_data.html pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw()); if data.is_null() { None } else { Some(&*(data as *const T)) } } } /// Gets the maximum amount of early data that will be accepted on incoming connections. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_CTX_get_max_early_data`]. /// /// [`SSL_CTX_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_get_max_early_data.html #[cfg(ossl111)] 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. pub struct CipherBits { /// The number of secret bits used for the cipher. pub secret: i32, /// The number of bits processed by the chosen algorithm. pub algorithm: i32, } /// Information about a cipher. pub struct SslCipher(*mut ffi::SSL_CIPHER); impl ForeignType for SslCipher { type CType = ffi::SSL_CIPHER; type Ref = SslCipherRef; #[inline] unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher { SslCipher(ptr) } #[inline] fn as_ptr(&self) -> *mut ffi::SSL_CIPHER { self.0 } } impl Deref for SslCipher { type Target = SslCipherRef; fn deref(&self) -> &SslCipherRef { unsafe { SslCipherRef::from_ptr(self.0) } } } impl DerefMut for SslCipher { fn deref_mut(&mut self) -> &mut SslCipherRef { unsafe { SslCipherRef::from_ptr_mut(self.0) } } } /// Reference to an [`SslCipher`]. /// /// [`SslCipher`]: struct.SslCipher.html pub struct SslCipherRef(Opaque); impl ForeignTypeRef for SslCipherRef { type CType = ffi::SSL_CIPHER; } impl SslCipherRef { /// Returns the name of the cipher. /// /// This corresponds to [`SSL_CIPHER_get_name`]. /// /// [`SSL_CIPHER_get_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html pub fn name(&self) -> &'static str { unsafe { let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr()); CStr::from_ptr(ptr).to_str().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. /// /// This corresponds to [`SSL_CIPHER_get_version`]. /// /// [`SSL_CIPHER_get_version`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html pub fn version(&self) -> &'static str { let version = unsafe { let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr()); CStr::from_ptr(ptr as *const _) }; str::from_utf8(version.to_bytes()).unwrap() } /// Returns the number of bits used for the cipher. /// /// This corresponds to [`SSL_CIPHER_get_bits`]. /// /// [`SSL_CIPHER_get_bits`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html pub fn bits(&self) -> CipherBits { unsafe { let mut algo_bits = 0; let secret_bits = ffi::SSL_CIPHER_get_bits(self.as_ptr(), &mut algo_bits); CipherBits { secret: secret_bits.into(), algorithm: algo_bits.into(), } } } /// Returns a textual description of the cipher. /// /// This corresponds to [`SSL_CIPHER_description`]. /// /// [`SSL_CIPHER_description`]: https://www.openssl.org/docs/manmaster/man3/SSL_CIPHER_get_name.html pub fn description(&self) -> String { unsafe { // SSL_CIPHER_description requires a buffer of at least 128 bytes. let mut buf = [0; 128]; let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128); String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap() } } /// Returns the handshake digest of the cipher. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_CIPHER_get_handshake_digest`]. /// /// [`SSL_CIPHER_get_handshake_digest`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CIPHER_get_handshake_digest.html #[cfg(ossl111)] pub fn handshake_digest(&self) -> Option { unsafe { let ptr = ffi::SSL_CIPHER_get_handshake_digest(self.as_ptr()); if ptr.is_null() { None } else { Some(MessageDigest::from_ptr(ptr)) } } } /// Returns the NID corresponding to the cipher. /// /// Requires OpenSSL 1.1.0 or newer. /// /// This corresponds to [`SSL_CIPHER_get_cipher_nid`]. /// /// [`SSL_CIPHER_get_cipher_nid`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CIPHER_get_cipher_nid.html #[cfg(any(ossl110))] pub fn cipher_nid(&self) -> Option { let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) }; if n == 0 { None } else { Some(Nid::from_raw(n)) } } } foreign_type_and_impl_send_sync! { type CType = ffi::SSL_SESSION; fn drop = ffi::SSL_SESSION_free; /// An encoded SSL session. /// /// These can be cached to share sessions across connections. pub struct SslSession; /// Reference to [`SslSession`]. /// /// [`SslSession`]: struct.SslSession.html pub struct SslSessionRef; } impl Clone for SslSession { fn clone(&self) -> SslSession { SslSessionRef::to_owned(self) } } impl SslSession { from_der! { /// Deserializes a DER-encoded session structure. /// /// This corresponds to [`d2i_SSL_SESSION`]. /// /// [`d2i_SSL_SESSION`]: https://www.openssl.org/docs/man1.0.2/ssl/d2i_SSL_SESSION.html from_der, SslSession, ffi::d2i_SSL_SESSION } } impl ToOwned for SslSessionRef { type Owned = SslSession; fn to_owned(&self) -> SslSession { unsafe { SSL_SESSION_up_ref(self.as_ptr()); SslSession(self.as_ptr()) } } } impl SslSessionRef { /// Returns the SSL session ID. /// /// This corresponds to [`SSL_SESSION_get_id`]. /// /// [`SSL_SESSION_get_id`]: https://www.openssl.org/docs/manmaster/man3/SSL_SESSION_get_id.html pub fn id(&self) -> &[u8] { unsafe { let mut len = 0; let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len); slice::from_raw_parts(p as *const u8, len as usize) } } /// Returns the length of the master key. /// /// This corresponds to [`SSL_SESSION_get_master_key`]. /// /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html pub fn master_key_len(&self) -> usize { unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } } /// Copies the master key into the provided buffer. /// /// Returns the number of bytes written, or the size of the master key if the buffer is empty. /// /// This corresponds to [`SSL_SESSION_get_master_key`]. /// /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html pub fn master_key(&self, buf: &mut [u8]) -> usize { unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } } /// Gets the maximum amount of early data that can be sent on this session. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_SESSION_get_max_early_data`]. /// /// [`SSL_SESSION_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_max_early_data.html #[cfg(ossl111)] pub fn max_early_data(&self) -> u32 { 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. /// /// This corresponds to [`i2d_SSL_SESSION`]. /// /// [`i2d_SSL_SESSION`]: https://www.openssl.org/docs/man1.0.2/ssl/i2d_SSL_SESSION.html to_der, ffi::i2d_SSL_SESSION } } foreign_type_and_impl_send_sync! { type CType = ffi::SSL; fn drop = ffi::SSL_free; /// The state of an SSL/TLS session. /// /// `Ssl` objects are created from an [`SslContext`], which provides configuration defaults. /// These defaults can be overridden on a per-`Ssl` basis, however. /// /// [`SslContext`]: struct.SslContext.html pub struct Ssl; /// Reference to an [`Ssl`]. /// /// [`Ssl`]: struct.Ssl.html pub struct SslRef; } impl fmt::Debug for Ssl { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, fmt) } } impl Ssl { /// Returns a new extra data index. /// /// Each invocation of this function is guaranteed to return a distinct index. These can be used /// to store data in the context that can be retrieved later by callbacks, for example. /// /// This corresponds to [`SSL_get_ex_new_index`]. /// /// [`SSL_get_ex_new_index`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_ex_new_index.html pub fn new_ex_index() -> Result, ErrorStack> where T: 'static + Sync + Send, { unsafe { ffi::init(); let idx = cvt_n(get_new_ssl_idx(free_data_box::))?; Ok(Index::from_raw(idx)) } } // FIXME should return a result? fn cached_ex_index() -> Index where T: 'static + Sync + Send, { unsafe { let idx = *SSL_INDEXES .lock() .unwrap_or_else(|e| e.into_inner()) .entry(TypeId::of::()) .or_insert_with(|| Ssl::new_ex_index::().unwrap().as_raw()); Index::from_raw(idx) } } /// Creates a new `Ssl`. /// /// 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 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) } } /// Initiates a client-side TLS handshake. /// /// This corresponds to [`SSL_connect`]. /// /// # Warning /// /// OpenSSL's default configuration is insecure. It is highly recommended to use /// `SslConnector` rather than `Ssl` directly, as it manages that configuration. /// /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html pub fn connect(self, stream: S) -> Result, HandshakeError> where S: Read + Write, { SslStreamBuilder::new(self, stream).connect() } /// Initiates a server-side TLS handshake. /// /// This corresponds to [`SSL_accept`]. /// /// # Warning /// /// OpenSSL's default configuration is insecure. It is highly recommended to use /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration. /// /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html pub fn accept(self, stream: S) -> Result, HandshakeError> where S: Read + Write, { SslStreamBuilder::new(self, stream).accept() } } impl fmt::Debug for SslRef { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("Ssl") .field("state", &self.state_string_long()) .field("verify_result", &self.verify_result()) .finish() } } impl SslRef { fn get_raw_rbio(&self) -> *mut ffi::BIO { unsafe { ffi::SSL_get_rbio(self.as_ptr()) } } fn read(&mut self, buf: &mut [u8]) -> c_int { let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int; unsafe { ffi::SSL_read(self.as_ptr(), buf.as_ptr() as *mut c_void, len) } } fn write(&mut self, buf: &[u8]) -> c_int { let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int; unsafe { ffi::SSL_write(self.as_ptr(), buf.as_ptr() as *const c_void, len) } } fn get_error(&self, ret: c_int) -> ErrorCode { unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) } } /// Like [`SslContextBuilder::set_verify`]. /// /// This corresponds to [`SSL_set_verify`]. /// /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html pub fn set_verify(&mut self, mode: SslVerifyMode) { unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, None) } } /// Like [`SslContextBuilder::set_verify_callback`]. /// /// This corresponds to [`SSL_set_verify`]. /// /// [`SslContextBuilder::set_verify_callback`]: struct.SslContextBuilder.html#method.set_verify_callback /// [`SSL_set_verify`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html pub fn set_verify_callback(&mut self, mode: SslVerifyMode, verify: F) where F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send, { unsafe { // this needs to be in an Arc since the callback can register a new callback! self.set_ex_data(Ssl::cached_ex_index(), Arc::new(verify)); ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::)); } } /// Like [`SslContextBuilder::set_tmp_dh`]. /// /// This corresponds to [`SSL_set_tmp_dh`]. /// /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh /// [`SSL_set_tmp_dh`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } } /// Like [`SslContextBuilder::set_tmp_dh_callback`]. /// /// This corresponds to [`SSL_set_tmp_dh_callback`]. /// /// [`SslContextBuilder::set_tmp_dh_callback`]: struct.SslContextBuilder.html#method.set_tmp_dh_callback /// [`SSL_set_tmp_dh_callback`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tmp_dh.html pub fn set_tmp_dh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { unsafe { // this needs to be in an Arc since the callback can register a new callback! self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback)); ffi::SSL_set_tmp_dh_callback(self.as_ptr(), raw_tmp_dh_ssl::); } } /// Like [`SslContextBuilder::set_tmp_ecdh`]. /// /// This corresponds to `SSL_set_tmp_ecdh`. /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } } /// Like [`SslContextBuilder::set_tmp_ecdh_callback`]. /// /// Requires OpenSSL 1.0.1 or 1.0.2. /// /// This corresponds to `SSL_set_tmp_ecdh_callback`. /// /// [`SslContextBuilder::set_tmp_ecdh_callback`]: struct.SslContextBuilder.html#method.set_tmp_ecdh_callback #[cfg(any(all(ossl101, not(ossl110))))] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { unsafe { // this needs to be in an Arc since the callback can register a new callback! self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback)); ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), raw_tmp_ecdh_ssl::); } } /// Like [`SslContextBuilder::set_ecdh_auto`]. /// /// Requires OpenSSL 1.0.2. /// /// This corresponds to [`SSL_set_ecdh_auto`]. /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh /// [`SSL_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_ecdh_auto.html #[cfg(all(ossl102, not(ossl110)))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } } /// Like [`SslContextBuilder::set_alpn_protos`]. /// /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// This corresponds to [`SSL_set_alpn_protos`]. /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos /// [`SSL_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_alpn_protos.html #[cfg(any(ossl102, libressl261))] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(protocols.len() <= c_uint::max_value() as usize); let r = ffi::SSL_set_alpn_protos( self.as_ptr(), protocols.as_ptr(), protocols.len() as c_uint, ); // fun fact, SSL_set_alpn_protos has a reversed return code D: if r == 0 { Ok(()) } else { Err(ErrorStack::get()) } } } /// Returns the current cipher if the session is active. /// /// This corresponds to [`SSL_get_current_cipher`]. /// /// [`SSL_get_current_cipher`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_current_cipher.html pub fn current_cipher(&self) -> Option<&SslCipherRef> { unsafe { let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); if ptr.is_null() { None } else { Some(SslCipherRef::from_ptr(ptr as *mut _)) } } } /// Returns a short string describing the state of the session. /// /// This corresponds to [`SSL_state_string`]. /// /// [`SSL_state_string`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_state_string.html pub fn state_string(&self) -> &'static str { let state = unsafe { let ptr = ffi::SSL_state_string(self.as_ptr()); CStr::from_ptr(ptr as *const _) }; str::from_utf8(state.to_bytes()).unwrap() } /// Returns a longer string describing the state of the session. /// /// This corresponds to [`SSL_state_string_long`]. /// /// [`SSL_state_string_long`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_state_string_long.html pub fn state_string_long(&self) -> &'static str { let state = unsafe { let ptr = ffi::SSL_state_string_long(self.as_ptr()); CStr::from_ptr(ptr as *const _) }; str::from_utf8(state.to_bytes()).unwrap() } /// Sets the host name to be sent to the server for Server Name Indication (SNI). /// /// It has no effect for a server-side connection. /// /// This corresponds to [`SSL_set_tlsext_host_name`]. /// /// [`SSL_set_tlsext_host_name`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername_type.html pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> { let cstr = CString::new(hostname).unwrap(); unsafe { cvt(ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr() as *mut _) as c_int) .map(|_| ()) } } /// Returns the peer's certificate, if present. /// /// This corresponds to [`SSL_get_peer_certificate`]. /// /// [`SSL_get_peer_certificate`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_certificate.html pub fn peer_certificate(&self) -> Option { unsafe { let ptr = ffi::SSL_get_peer_certificate(self.as_ptr()); if ptr.is_null() { None } else { Some(X509::from_ptr(ptr)) } } } /// Returns the certificate chain of the peer, if present. /// /// On the client side, the chain includes the leaf certificate, but on the server side it does /// not. Fun! /// /// This corresponds to [`SSL_get_peer_cert_chain`]. /// /// [`SSL_get_peer_cert_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_peer_cert_chain.html pub fn peer_cert_chain(&self) -> Option<&StackRef> { unsafe { let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr()); if ptr.is_null() { None } else { Some(StackRef::from_ptr(ptr)) } } } /// Returns the verified certificate chani of the peer, including the leaf certificate. /// /// If verification was not successful (i.e. [`verify_result`] does not return /// [`X509VerifyResult::OK`]), this chain may be incomplete or invalid. /// /// Requires OpenSSL 1.1.0 or newer. /// /// This corresponds to [`SSL_get0_verified_chain`]. /// /// [`verify_result`]: #method.verify_result /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK /// [`SSL_get0_verified_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get0_verified_chain.html #[cfg(ossl110)] pub fn verified_chain(&self) -> Option<&StackRef> { unsafe { let ptr = ffi::SSL_get0_verified_chain(self.as_ptr()); if ptr.is_null() { None } else { Some(StackRef::from_ptr(ptr)) } } } /// Like [`SslContext::certificate`]. /// /// This corresponds to `SSL_get_certificate`. /// /// [`SslContext::certificate`]: struct.SslContext.html#method.certificate pub fn certificate(&self) -> Option<&X509Ref> { unsafe { let ptr = ffi::SSL_get_certificate(self.as_ptr()); if ptr.is_null() { None } else { Some(X509Ref::from_ptr(ptr)) } } } /// Like [`SslContext::private_key`]. /// /// This corresponds to `SSL_get_privatekey`. /// /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key pub fn private_key(&self) -> Option<&PKeyRef> { unsafe { let ptr = ffi::SSL_get_privatekey(self.as_ptr()); if ptr.is_null() { None } else { Some(PKeyRef::from_ptr(ptr)) } } } #[deprecated(since = "0.10.5", note = "renamed to `version_str`")] pub fn version(&self) -> &str { self.version_str() } /// Returns the protocol version of the session. /// /// This corresponds to [`SSL_version`]. /// /// [`SSL_version`]: https://www.openssl.org/docs/manmaster/man3/SSL_version.html pub fn version2(&self) -> Option { unsafe { let r = ffi::SSL_version(self.as_ptr()); if r == 0 { None } else { Some(SslVersion(r)) } } } /// Returns a string describing the protocol version of the session. /// /// This corresponds to [`SSL_get_version`]. /// /// [`SSL_get_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_version.html pub fn version_str(&self) -> &'static str { let version = unsafe { let ptr = ffi::SSL_get_version(self.as_ptr()); CStr::from_ptr(ptr as *const _) }; str::from_utf8(version.to_bytes()).unwrap() } /// Returns the protocol selected via Application Layer Protocol Negotiation (ALPN). /// /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client /// to interpret it. /// /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// This corresponds to [`SSL_get0_alpn_selected`]. /// /// [`SSL_get0_alpn_selected`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html #[cfg(any(ossl102, libressl261))] pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { unsafe { let mut data: *const c_uchar = ptr::null(); let mut len: c_uint = 0; // Get the negotiated protocol from the SSL instance. // `data` will point at a `c_uchar` array; `len` will contain the length of this array. ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len); if data.is_null() { None } else { Some(slice::from_raw_parts(data, len as usize)) } } } /// Enables the DTLS extension "use_srtp" as defined in RFC5764. /// /// This corresponds to [`SSL_set_tlsext_use_srtp`]. /// /// [`SSL_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> { unsafe { let cstr = CString::new(protocols).unwrap(); let r = ffi::SSL_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr()); // fun fact, set_tlsext_use_srtp has a reversed return code D: if r == 0 { Ok(()) } else { Err(ErrorStack::get()) } } } /// Gets all SRTP profiles that are enabled for handshake via set_tlsext_use_srtp /// /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled. /// /// This corresponds to [`SSL_get_srtp_profiles`]. /// /// [`SSL_get_srtp_profiles`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html pub fn srtp_profiles(&self) -> Option<&StackRef> { unsafe { let chain = ffi::SSL_get_srtp_profiles(self.as_ptr()); if chain.is_null() { None } else { Some(StackRef::from_ptr(chain)) } } } /// Gets the SRTP profile selected by handshake. /// /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled. /// /// This corresponds to [`SSL_get_selected_srtp_profile`]. /// /// [`SSL_get_selected_srtp_profile`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html pub fn selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef> { unsafe { let profile = ffi::SSL_get_selected_srtp_profile(self.as_ptr()); if profile.is_null() { None } else { Some(SrtpProtectionProfileRef::from_ptr(profile as *mut _)) } } } /// Returns the number of bytes remaining in the currently processed TLS record. /// /// If this is greater than 0, the next call to `read` will not call down to the underlying /// stream. /// /// This corresponds to [`SSL_pending`]. /// /// [`SSL_pending`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_pending.html pub fn pending(&self) -> usize { unsafe { ffi::SSL_pending(self.as_ptr()) as usize } } /// Returns the servername sent by the client via Server Name Indication (SNI). /// /// It is only useful on the server side. /// /// This corresponds to [`SSL_get_servername`]. /// /// # Note /// /// While the SNI specification requires that servernames be valid domain names (and therefore /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns /// the raw bytes and does not have this restriction. /// /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html // FIXME maybe rethink in 0.11? pub fn servername(&self, type_: NameType) -> Option<&str> { self.servername_raw(type_) .and_then(|b| str::from_utf8(b).ok()) } /// Returns the servername sent by the client via Server Name Indication (SNI). /// /// It is only useful on the server side. /// /// This corresponds to [`SSL_get_servername`]. /// /// # Note /// /// Unlike `servername`, this method does not require the name be valid UTF-8. /// /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> { unsafe { let name = ffi::SSL_get_servername(self.as_ptr(), type_.0); if name == ptr::null() { None } else { Some(CStr::from_ptr(name as *const _).to_bytes()) } } } /// Changes the context corresponding to the current connection. /// /// It is most commonly used in the Server Name Indication (SNI) callback. /// /// This corresponds to `SSL_set_SSL_CTX`. pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> { unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) } } /// Returns the context corresponding to the current connection. /// /// This corresponds to [`SSL_get_SSL_CTX`]. /// /// [`SSL_get_SSL_CTX`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_SSL_CTX.html pub fn ssl_context(&self) -> &SslContextRef { unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr()); SslContextRef::from_ptr(ssl_ctx) } } /// Returns a mutable reference to the X509 verification configuration. /// /// Requires OpenSSL 1.0.2 or newer. /// /// This corresponds to [`SSL_get0_param`]. /// /// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html #[cfg(any(ossl102, libressl261))] pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } } /// Returns the certificate verification result. /// /// This corresponds to [`SSL_get_verify_result`]. /// /// [`SSL_get_verify_result`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get_verify_result.html pub fn verify_result(&self) -> X509VerifyResult { unsafe { X509VerifyResult::from_raw(ffi::SSL_get_verify_result(self.as_ptr()) as c_int) } } /// Returns a shared reference to the SSL session. /// /// This corresponds to [`SSL_get_session`]. /// /// [`SSL_get_session`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_session.html pub fn session(&self) -> Option<&SslSessionRef> { unsafe { let p = ffi::SSL_get_session(self.as_ptr()); if p.is_null() { None } else { Some(SslSessionRef::from_ptr(p)) } } } /// Copies the client_random value sent by the client in the TLS handshake into a buffer. /// /// Returns the number of bytes copied, or if the buffer is empty, the size of the client_random /// value. /// /// Requires OpenSSL 1.1.0 or newer. /// /// This corresponds to [`SSL_get_client_random`]. /// /// [`SSL_get_client_random`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_random.html #[cfg(any(ossl110))] pub fn client_random(&self, buf: &mut [u8]) -> usize { unsafe { ffi::SSL_get_client_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len()) } } /// Copies the server_random value sent by the server in the TLS handshake into a buffer. /// /// Returns the number of bytes copied, or if the buffer is empty, the size of the server_random /// value. /// /// Requires OpenSSL 1.1.0 or newer. /// /// This corresponds to [`SSL_get_server_random`]. /// /// [`SSL_get_server_random`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get_client_random.html #[cfg(any(ossl110))] pub fn server_random(&self, buf: &mut [u8]) -> usize { unsafe { ffi::SSL_get_server_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len()) } } /// Derives keying material for application use in accordance to RFC 5705. /// /// This corresponds to [`SSL_export_keying_material`]. /// /// [`SSL_export_keying_material`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material.html pub fn export_keying_material( &self, out: &mut [u8], label: &str, context: Option<&[u8]>, ) -> Result<(), ErrorStack> { unsafe { let (context, contextlen, use_context) = match context { Some(context) => (context.as_ptr() as *const c_uchar, context.len(), 1), None => (ptr::null(), 0, 0), }; cvt(ffi::SSL_export_keying_material( self.as_ptr(), out.as_mut_ptr() as *mut c_uchar, out.len(), label.as_ptr() as *const c_char, label.len(), context, contextlen, use_context, )) .map(|_| ()) } } /// Derives keying material for application use in accordance to RFC 5705. /// /// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no /// context. Therefore, unlike `export_keying_material`, `context` must always be supplied. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_export_keying_material_early`]. /// /// [`SSL_export_keying_material_early`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material_early.html #[cfg(ossl111)] pub fn export_keying_material_early( &self, out: &mut [u8], label: &str, context: &[u8], ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_export_keying_material_early( self.as_ptr(), out.as_mut_ptr() as *mut c_uchar, out.len(), label.as_ptr() as *const c_char, label.len(), context.as_ptr() as *const c_uchar, context.len(), )) .map(|_| ()) } } /// Sets the session to be used. /// /// This should be called before the handshake to attempt to reuse a previously established /// session. If the server is not willing to reuse the session, a new one will be transparently /// negotiated. /// /// This corresponds to [`SSL_set_session`]. /// /// # Safety /// /// The caller of this method is responsible for ensuring that the session is associated /// with the same `SslContext` as this `Ssl`. /// /// [`SSL_set_session`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_session.html pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> { cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ()) } /// Determines if the session provided to `set_session` was successfully reused. /// /// This corresponds to [`SSL_session_reused`]. /// /// [`SSL_session_reused`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_session_reused.html pub fn session_reused(&self) -> bool { unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 } } /// Sets the status response a client wishes the server to reply with. /// /// This corresponds to [`SSL_set_tlsext_status_type`]. /// /// [`SSL_set_tlsext_status_type`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ()) } } /// Returns the server's OCSP response, if present. /// /// This corresponds to [`SSL_get_tlsext_status_ocsp_resp`]. /// /// [`SSL_get_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html pub fn ocsp_status(&self) -> Option<&[u8]> { unsafe { let mut p = ptr::null_mut(); let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p); if len < 0 { None } else { Some(slice::from_raw_parts(p as *const u8, len as usize)) } } } /// Sets the OCSP response to be returned to the client. /// /// This corresponds to [`SSL_set_tlsext_status_ocsp_resp`]. /// /// [`SSL_set_tlsext_status_ocsp_resp`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_tlsext_status_type.html pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(response.len() <= c_int::max_value() as usize); let p = cvt_p(ffi::CRYPTO_malloc( response.len() as _, concat!(file!(), "\0").as_ptr() as *const _, line!() as c_int, ))?; ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len()); cvt(ffi::SSL_set_tlsext_status_ocsp_resp( self.as_ptr(), p as *mut c_uchar, response.len() as c_long, ) as c_int) .map(|_| ()) } } /// Determines if this `Ssl` is configured for server-side or client-side use. /// /// This corresponds to [`SSL_is_server`]. /// /// [`SSL_is_server`]: https://www.openssl.org/docs/manmaster/man3/SSL_is_server.html pub fn is_server(&self) -> bool { unsafe { SSL_is_server(self.as_ptr()) != 0 } } /// Sets the extra data at the specified index. /// /// This can be used to provide data to callbacks registered with the context. Use the /// `Ssl::new_ex_index` method to create an `Index`. /// /// This corresponds to [`SSL_set_ex_data`]. /// /// [`SSL_set_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html pub fn set_ex_data(&mut self, index: Index, data: T) { unsafe { let data = Box::new(data); ffi::SSL_set_ex_data( self.as_ptr(), index.as_raw(), Box::into_raw(data) as *mut c_void, ); } } /// Returns a reference to the extra data at the specified index. /// /// This corresponds to [`SSL_get_ex_data`]. /// /// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); if data.is_null() { None } else { Some(&*(data as *const T)) } } } /// Returns a mutable reference to the extra data at the specified index. /// /// This corresponds to [`SSL_get_ex_data`]. /// /// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html pub fn ex_data_mut(&mut self, index: Index) -> Option<&mut T> { unsafe { let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw()); if data.is_null() { None } else { Some(&mut *(data as *mut T)) } } } /// Sets the maximum amount of early data that will be accepted on this connection. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_set_max_early_data`]. /// /// [`SSL_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_max_early_data.html #[cfg(ossl111)] pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> { if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 { Ok(()) } else { Err(ErrorStack::get()) } } /// Gets the maximum amount of early data that can be sent on this connection. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_get_max_early_data`]. /// /// [`SSL_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_max_early_data.html #[cfg(ossl111)] pub fn max_early_data(&self) -> u32 { unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) } } /// Copies the contents of the last Finished message sent to the peer into the provided buffer. /// /// The total size of the message is returned, so this can be used to determine the size of the /// buffer required. /// /// This corresponds to `SSL_get_finished`. pub fn finished(&self, buf: &mut [u8]) -> usize { unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } } /// Copies the contents of the last Finished message received from the peer into the provided /// buffer. /// /// The total size of the message is returned, so this can be used to determine the size of the /// buffer required. /// /// This corresponds to `SSL_get_finished`. pub fn peer_finished(&self, buf: &mut [u8]) -> usize { unsafe { ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } } /// 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 } } /// 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 { unsafe { let version = ffi::SSL_client_hello_get0_legacy_version(self.as_ptr()); if version == 0 { None } else { Some(SslVersion(version as c_int)) } } } /// 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]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_random(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// 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]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_session_id(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// 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]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_ciphers(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } /// 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]> { unsafe { let mut ptr = ptr::null(); let len = ffi::SSL_client_hello_get0_compression_methods(self.as_ptr(), &mut ptr); if len == 0 { None } else { Some(slice::from_raw_parts(ptr, len)) } } } } /// An SSL stream midway through the handshake process. #[derive(Debug)] pub struct MidHandshakeSslStream { stream: SslStream, error: Error, } impl MidHandshakeSslStream { /// Returns a shared reference to the inner stream. pub fn get_ref(&self) -> &S { self.stream.get_ref() } /// Returns a mutable reference to the inner stream. pub fn get_mut(&mut self) -> &mut S { self.stream.get_mut() } /// Returns a shared reference to the `Ssl` of the stream. pub fn ssl(&self) -> &SslRef { self.stream.ssl() } /// Returns the underlying error which interrupted this handshake. pub fn error(&self) -> &Error { &self.error } /// Consumes `self`, returning its error. pub fn into_error(self) -> Error { self.error } /// Restarts the handshake process. /// /// This corresponds to [`SSL_do_handshake`]. /// /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html pub fn handshake(mut self) -> Result, HandshakeError> { let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) }; if ret > 0 { Ok(self.stream) } else { self.error = self.stream.make_error(ret); match self.error.code() { ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { Err(HandshakeError::WouldBlock(self)) } _ => Err(HandshakeError::Failure(self)), } } } } /// A TLS session over a stream. pub struct SslStream { ssl: ManuallyDrop, method: ManuallyDrop, _p: PhantomData, } impl Drop for SslStream { fn drop(&mut self) { // ssl holds a reference to method internally so it has to drop first unsafe { ManuallyDrop::drop(&mut self.ssl); ManuallyDrop::drop(&mut self.method); } } } impl fmt::Debug for SslStream where S: fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("SslStream") .field("stream", &self.get_ref()) .field("ssl", &self.ssl()) .finish() } } impl SslStream { fn new_base(ssl: Ssl, stream: S) -> Self { unsafe { let (bio, method) = bio::new(stream).unwrap(); ffi::SSL_set_bio(ssl.as_ptr(), bio, bio); SslStream { ssl: ManuallyDrop::new(ssl), method: ManuallyDrop::new(method), _p: PhantomData, } } } /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`. /// /// It is particularly useful with a nonblocking socket, where the error value will identify if /// OpenSSL is waiting on read or write readiness. /// /// This corresponds to [`SSL_read`]. /// /// [`SSL_read`]: https://www.openssl.org/docs/manmaster/man3/SSL_read.html pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { // The intepretation of the return code here is a little odd with a // zero-length write. OpenSSL will likely correctly report back to us // that it read zero bytes, but zero is also the sentinel for "error". // To avoid that confusion short-circuit that logic and return quickly // if `buf` has a length of zero. if buf.len() == 0 { return Ok(0); } let ret = self.ssl.read(buf); if ret > 0 { Ok(ret as usize) } else { Err(self.make_error(ret)) } } /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`. /// /// It is particularly useful with a nonblocking socket, where the error value will identify if /// OpenSSL is waiting on read or write readiness. /// /// This corresponds to [`SSL_write`]. /// /// [`SSL_write`]: https://www.openssl.org/docs/manmaster/man3/SSL_write.html pub fn ssl_write(&mut self, buf: &[u8]) -> Result { // See above for why we short-circuit on zero-length buffers if buf.len() == 0 { return Ok(0); } let ret = self.ssl.write(buf); if ret > 0 { Ok(ret as usize) } else { Err(self.make_error(ret)) } } /// Shuts down the session. /// /// The shutdown process consists of two steps. The first step sends a close notify message to /// the peer, after which `ShutdownResult::Sent` is returned. The second step awaits the receipt /// of a close notify message from the peer, after which `ShutdownResult::Received` is returned. /// /// While the connection may be closed after the first step, it is recommended to fully shut the /// session down. In particular, it must be fully shut down if the connection is to be used for /// further communication in the future. /// /// This corresponds to [`SSL_shutdown`]. /// /// [`SSL_shutdown`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_shutdown.html pub fn shutdown(&mut self) -> Result { match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } { 0 => Ok(ShutdownResult::Sent), 1 => Ok(ShutdownResult::Received), n => Err(self.make_error(n)), } } /// Returns the session's shutdown state. /// /// This corresponds to [`SSL_get_shutdown`]. /// /// [`SSL_get_shutdown`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_shutdown.html pub fn get_shutdown(&mut self) -> ShutdownState { unsafe { let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr()); ShutdownState { bits } } } /// Sets the session's shutdown state. /// /// This can be used to tell OpenSSL that the session should be cached even if a full two-way /// shutdown was not completed. /// /// This corresponds to [`SSL_set_shutdown`]. /// /// [`SSL_set_shutdown`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_shutdown.html pub fn set_shutdown(&mut self, state: ShutdownState) { unsafe { ffi::SSL_set_shutdown(self.ssl.as_ptr(), state.bits()) } } } impl SslStream { fn make_error(&mut self, ret: c_int) -> Error { self.check_panic(); let code = self.ssl.get_error(ret); let cause = match code { ErrorCode::SSL => Some(InnerError::Ssl(ErrorStack::get())), ErrorCode::SYSCALL => { let errs = ErrorStack::get(); if errs.errors().is_empty() { self.get_bio_error().map(InnerError::Io) } else { Some(InnerError::Ssl(errs)) } } ErrorCode::ZERO_RETURN => None, ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { self.get_bio_error().map(InnerError::Io) } _ => None, }; Error { code, cause } } fn check_panic(&mut self) { if let Some(err) = unsafe { bio::take_panic::(self.ssl.get_raw_rbio()) } { resume_unwind(err) } } fn get_bio_error(&mut self) -> Option { unsafe { bio::take_error::(self.ssl.get_raw_rbio()) } } /// Returns a shared reference to the underlying stream. pub fn get_ref(&self) -> &S { unsafe { let bio = self.ssl.get_raw_rbio(); bio::get_ref(bio) } } /// Returns a mutable reference to the underlying stream. /// /// # Warning /// /// It is inadvisable to read from or write to the underlying stream as it /// will most likely corrupt the SSL session. pub fn get_mut(&mut self) -> &mut S { unsafe { let bio = self.ssl.get_raw_rbio(); bio::get_mut(bio) } } /// Returns a shared reference to the `Ssl` object associated with this stream. pub fn ssl(&self) -> &SslRef { &self.ssl } } impl Read for SslStream { fn read(&mut self, buf: &mut [u8]) -> io::Result { loop { match self.ssl_read(buf) { 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); } 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))); } } } } } impl Write for SslStream { fn write(&mut self, buf: &[u8]) -> io::Result { loop { match self.ssl_write(buf) { Ok(n) => return Ok(n), 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))); } } } } fn flush(&mut self) -> io::Result<()> { self.get_mut().flush() } } /// A partially constructed `SslStream`, useful for unusual handshakes. pub struct SslStreamBuilder { inner: SslStream, } impl SslStreamBuilder where S: Read + Write, { /// Begin creating an `SslStream` atop `stream` pub fn new(ssl: Ssl, stream: S) -> Self { Self { inner: SslStream::new_base(ssl, stream), } } /// Perform a stateless server-side handshake /// /// Requires that cookie generation and verification callbacks were /// set on the SSL context. /// /// Returns `Ok(true)` if a complete ClientHello containing a valid cookie /// was read, in which case the handshake should be continued via /// `accept`. If a HelloRetryRequest containing a fresh cookie was /// transmitted, `Ok(false)` is returned instead. If the handshake cannot /// proceed at all, `Err` is returned. /// /// This corresponds to [`SSL_stateless`] /// /// [`SSL_stateless`]: https://www.openssl.org/docs/manmaster/man3/SSL_stateless.html #[cfg(ossl111)] pub fn stateless(&mut self) -> Result { match unsafe { ffi::SSL_stateless(self.inner.ssl.as_ptr()) } { 1 => Ok(true), 0 => Ok(false), -1 => Err(ErrorStack::get()), _ => unreachable!(), } } /// Configure as an outgoing stream from a client. /// /// This corresponds to [`SSL_set_connect_state`]. /// /// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html pub fn set_connect_state(&mut self) { unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) } } /// Configure as an incoming stream to a server. /// /// This corresponds to [`SSL_set_accept_state`]. /// /// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html pub fn set_accept_state(&mut self) { unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) } } /// See `Ssl::connect` pub fn connect(self) -> Result, HandshakeError> { let mut stream = self.inner; let ret = unsafe { ffi::SSL_connect(stream.ssl.as_ptr()) }; if ret > 0 { Ok(stream) } else { let error = stream.make_error(ret); match error.code() { ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error, })) } _ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream, error, })), } } } /// See `Ssl::accept` pub fn accept(self) -> Result, HandshakeError> { let mut stream = self.inner; let ret = unsafe { ffi::SSL_accept(stream.ssl.as_ptr()) }; if ret > 0 { Ok(stream) } else { let error = stream.make_error(ret); match error.code() { ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error, })) } _ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream, error, })), } } } /// Initiates the handshake. /// /// This will fail if `set_accept_state` or `set_connect_state` was not called first. /// /// This corresponds to [`SSL_do_handshake`]. /// /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html pub fn handshake(self) -> Result, HandshakeError> { let mut stream = self.inner; let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) }; if ret > 0 { Ok(stream) } else { let error = stream.make_error(ret); match error.code() { ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error, })) } _ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream, error, })), } } } /// Read application data transmitted by a client before handshake /// completion. /// /// Useful for reducing latency, but vulnerable to replay attacks. Call /// `set_accept_state` first. /// /// Returns `Ok(0)` if all early data has been read. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_read_early_data`]. /// /// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html #[cfg(ossl111)] pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result { let mut read = 0; let ret = unsafe { ffi::SSL_read_early_data( self.inner.ssl.as_ptr(), buf.as_ptr() as *mut c_void, buf.len(), &mut read, ) }; match ret { ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.inner.make_error(ret)), ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read), ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0), _ => unreachable!(), } } /// Send data to the server without blocking on handshake completion. /// /// Useful for reducing latency, but vulnerable to replay attacks. Call /// `set_connect_state` first. /// /// Requires OpenSSL 1.1.1 or newer. /// /// This corresponds to [`SSL_write_early_data`]. /// /// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html #[cfg(ossl111)] pub fn write_early_data(&mut self, buf: &[u8]) -> Result { let mut written = 0; let ret = unsafe { ffi::SSL_write_early_data( self.inner.ssl.as_ptr(), buf.as_ptr() as *const c_void, buf.len(), &mut written, ) }; if ret > 0 { Ok(written as usize) } else { Err(self.inner.make_error(ret)) } } } impl SslStreamBuilder { /// Returns a shared reference to the underlying stream. pub fn get_ref(&self) -> &S { unsafe { let bio = self.inner.ssl.get_raw_rbio(); bio::get_ref(bio) } } /// Returns a mutable reference to the underlying stream. /// /// # Warning /// /// It is inadvisable to read from or write to the underlying stream as it /// will most likely corrupt the SSL session. pub fn get_mut(&mut self) -> &mut S { unsafe { let bio = self.inner.ssl.get_raw_rbio(); bio::get_mut(bio) } } /// Returns a shared reference to the `Ssl` object associated with this builder. pub fn ssl(&self) -> &SslRef { &self.inner.ssl } } /// The result of a shutdown request. #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ShutdownResult { /// A close notify message has been sent to the peer. Sent, /// A close notify response message has been received from the peer. Received, } bitflags! { /// The shutdown state of a session. pub struct ShutdownState: c_int { /// A close notify message has been sent to the peer. const SENT = ffi::SSL_SENT_SHUTDOWN; /// A close notify message has been received from the peer. const RECEIVED = ffi::SSL_RECEIVED_SHUTDOWN; } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{SSL_CTX_up_ref, SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server}; } else { #[allow(bad_style)] pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> c_int { ffi::CRYPTO_add_lock( &mut (*ssl).references, 1, ffi::CRYPTO_LOCK_SSL_CTX, "mod.rs\0".as_ptr() as *const _, line!() as c_int, ); 0 } #[allow(bad_style)] pub unsafe fn SSL_SESSION_get_master_key( session: *const ffi::SSL_SESSION, out: *mut c_uchar, mut outlen: usize, ) -> usize { if outlen == 0 { return (*session).master_key_length as usize; } if outlen > (*session).master_key_length as usize { outlen = (*session).master_key_length as usize; } ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); outlen } #[allow(bad_style)] pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { (*s).server } #[allow(bad_style)] pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int { ffi::CRYPTO_add_lock( &mut (*ses).references, 1, ffi::CRYPTO_LOCK_SSL_CTX, "mod.rs\0".as_ptr() as *const _, line!() as c_int, ); 0 } } } cfg_if! { 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, 0, ptr::null_mut(), None, None, Some(f), ) } unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { ffi::CRYPTO_get_ex_new_index( ffi::CRYPTO_EX_INDEX_SSL, 0, ptr::null_mut(), None, None, Some(f), ) } } else { 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)) } unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) } } } openssl-0.10.23/src/ssl/test/mod.rs010064400017500001750000001174301347005411600152640ustar0000000000000000#![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); } openssl-0.10.23/src/ssl/test/server.rs010064400017500001750000000075521346222217000160140ustar0000000000000000use 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(); } } openssl-0.10.23/src/stack.rs010064400017500001750000000221321346222217000140220ustar0000000000000000use ffi; use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::c_int; use std::borrow::Borrow; use std::convert::AsRef; use std::iter; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut, Index, IndexMut, Range}; use error::ErrorStack; use {cvt, cvt_p}; cfg_if! { if #[cfg(ossl110)] { use ffi::{ OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK, OPENSSL_sk_new_null, OPENSSL_sk_push, }; } else { use ffi::{ sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK, sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push, }; } } /// Trait implemented by types which can be placed in a stack. /// /// It should not be implemented for any type outside of this crate. pub trait Stackable: ForeignType { /// The C stack type for this element. /// /// Generally called `stack_st_{ELEMENT_TYPE}`, normally hidden by the /// `STACK_OF(ELEMENT_TYPE)` macro in the OpenSSL API. type StackType; } /// An owned stack of `T`. pub struct Stack(*mut T::StackType); unsafe impl Send for Stack {} unsafe impl Sync for Stack {} impl Drop for Stack { fn drop(&mut self) { unsafe { while let Some(_) = self.pop() {} OPENSSL_sk_free(self.0 as *mut _); } } } impl Stack { pub fn new() -> Result, ErrorStack> { unsafe { ffi::init(); let ptr = cvt_p(OPENSSL_sk_new_null())?; Ok(Stack(ptr as *mut _)) } } } impl iter::IntoIterator for Stack { type IntoIter = IntoIter; type Item = T; fn into_iter(self) -> IntoIter { let it = IntoIter { stack: self.0, idxs: 0..self.len() as c_int, }; mem::forget(self); it } } impl AsRef> for Stack { fn as_ref(&self) -> &StackRef { &*self } } impl Borrow> for Stack { fn borrow(&self) -> &StackRef { &*self } } impl ForeignType for Stack { type CType = T::StackType; type Ref = StackRef; #[inline] unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack { assert!( !ptr.is_null(), "Must not instantiate a Stack from a null-ptr - use Stack::new() in \ that case" ); Stack(ptr) } #[inline] fn as_ptr(&self) -> *mut T::StackType { self.0 } } impl Deref for Stack { type Target = StackRef; fn deref(&self) -> &StackRef { unsafe { StackRef::from_ptr(self.0) } } } impl DerefMut for Stack { fn deref_mut(&mut self) -> &mut StackRef { unsafe { StackRef::from_ptr_mut(self.0) } } } pub struct IntoIter { stack: *mut T::StackType, idxs: Range, } impl Drop for IntoIter { fn drop(&mut self) { unsafe { while let Some(_) = self.next() {} OPENSSL_sk_free(self.stack as *mut _); } } } impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { unsafe { self.idxs .next() .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _)) } } fn size_hint(&self) -> (usize, Option) { self.idxs.size_hint() } } impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { unsafe { self.idxs .next_back() .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _)) } } } impl ExactSizeIterator for IntoIter {} pub struct StackRef(Opaque, PhantomData); unsafe impl Send for StackRef {} unsafe impl Sync for StackRef {} impl ForeignTypeRef for StackRef { type CType = T::StackType; } impl StackRef { fn as_stack(&self) -> *mut OPENSSL_STACK { self.as_ptr() as *mut _ } /// Returns the number of items in the stack pub fn len(&self) -> usize { unsafe { OPENSSL_sk_num(self.as_stack()) as usize } } pub fn iter(&self) -> Iter { Iter { stack: self, idxs: 0..self.len() as c_int, } } pub fn iter_mut(&mut self) -> IterMut { IterMut { idxs: 0..self.len() as c_int, stack: self, } } /// Returns a reference to the element at the given index in the /// stack or `None` if the index is out of bounds pub fn get(&self, idx: usize) -> Option<&T::Ref> { unsafe { if idx >= self.len() { return None; } Some(T::Ref::from_ptr(self._get(idx))) } } /// Returns a mutable reference to the element at the given index in the /// stack or `None` if the index is out of bounds pub fn get_mut(&mut self, idx: usize) -> Option<&mut T::Ref> { unsafe { if idx >= self.len() { return None; } Some(T::Ref::from_ptr_mut(self._get(idx))) } } /// Pushes a value onto the top of the stack. pub fn push(&mut self, data: T) -> Result<(), ErrorStack> { unsafe { cvt(OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _))?; mem::forget(data); Ok(()) } } /// Removes the last element from the stack and returns it. pub fn pop(&mut self) -> Option { unsafe { let ptr = OPENSSL_sk_pop(self.as_stack()); if ptr.is_null() { None } else { Some(T::from_ptr(ptr as *mut _)) } } } unsafe fn _get(&self, idx: usize) -> *mut T::CType { OPENSSL_sk_value(self.as_stack(), idx as c_int) as *mut _ } } impl Index for StackRef { type Output = T::Ref; fn index(&self, index: usize) -> &T::Ref { self.get(index).unwrap() } } impl IndexMut for StackRef { fn index_mut(&mut self, index: usize) -> &mut T::Ref { self.get_mut(index).unwrap() } } impl<'a, T: Stackable> iter::IntoIterator for &'a StackRef { type Item = &'a T::Ref; type IntoIter = Iter<'a, T>; fn into_iter(self) -> Iter<'a, T> { self.iter() } } impl<'a, T: Stackable> iter::IntoIterator for &'a mut StackRef { type Item = &'a mut T::Ref; type IntoIter = IterMut<'a, T>; fn into_iter(self) -> IterMut<'a, T> { self.iter_mut() } } impl<'a, T: Stackable> iter::IntoIterator for &'a Stack { type Item = &'a T::Ref; type IntoIter = Iter<'a, T>; fn into_iter(self) -> Iter<'a, T> { self.iter() } } impl<'a, T: Stackable> iter::IntoIterator for &'a mut Stack { type Item = &'a mut T::Ref; type IntoIter = IterMut<'a, T>; fn into_iter(self) -> IterMut<'a, T> { self.iter_mut() } } /// An iterator over the stack's contents. pub struct Iter<'a, T: Stackable> where T: 'a, { stack: &'a StackRef, idxs: Range, } impl<'a, T: Stackable> Iterator for Iter<'a, T> { type Item = &'a T::Ref; fn next(&mut self) -> Option<&'a T::Ref> { unsafe { self.idxs .next() .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) } } fn size_hint(&self) -> (usize, Option) { self.idxs.size_hint() } } impl<'a, T: Stackable> DoubleEndedIterator for Iter<'a, T> { fn next_back(&mut self) -> Option<&'a T::Ref> { unsafe { self.idxs .next_back() .map(|i| T::Ref::from_ptr(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) } } } impl<'a, T: Stackable> ExactSizeIterator for Iter<'a, T> {} /// A mutable iterator over the stack's contents. pub struct IterMut<'a, T: Stackable + 'a> { stack: &'a mut StackRef, idxs: Range, } impl<'a, T: Stackable> Iterator for IterMut<'a, T> { type Item = &'a mut T::Ref; fn next(&mut self) -> Option<&'a mut T::Ref> { unsafe { self.idxs .next() .map(|i| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) } } fn size_hint(&self) -> (usize, Option) { self.idxs.size_hint() } } impl<'a, T: Stackable> DoubleEndedIterator for IterMut<'a, T> { fn next_back(&mut self) -> Option<&'a mut T::Ref> { unsafe { self.idxs .next_back() .map(|i| T::Ref::from_ptr_mut(OPENSSL_sk_value(self.stack.as_stack(), i) as *mut _)) } } } impl<'a, T: Stackable> ExactSizeIterator for IterMut<'a, T> {} openssl-0.10.23/src/string.rs010064400017500001750000000036161346222217000142310ustar0000000000000000use ffi; use foreign_types::ForeignTypeRef; use libc::{c_char, c_void}; use std::convert::AsRef; use std::ffi::CStr; use std::fmt; use std::ops::Deref; use std::str; use stack::Stackable; foreign_type_and_impl_send_sync! { type CType = c_char; fn drop = free; pub struct OpensslString; pub struct OpensslStringRef; } impl fmt::Display for OpensslString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } impl fmt::Debug for OpensslString { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } impl Stackable for OpensslString { 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; fn deref(&self) -> &str { unsafe { let slice = CStr::from_ptr(self.as_ptr()).to_bytes(); str::from_utf8_unchecked(slice) } } } 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) } } impl fmt::Debug for OpensslStringRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[cfg(not(ossl110))] unsafe fn free(buf: *mut c_char) { ::ffi::CRYPTO_free(buf as *mut c_void); } #[cfg(ossl110)] unsafe fn free(buf: *mut c_char) { ::ffi::CRYPTO_free( buf as *mut c_void, concat!(file!(), "\0").as_ptr() as *const c_char, line!() as ::libc::c_int, ); } openssl-0.10.23/src/symm.rs010064400017500001750000001252461346470244000137210ustar0000000000000000//! High level interface to certain symmetric ciphers. //! //! # Examples //! //! Encrypt data in AES128 CBC mode //! //! ``` //! use openssl::symm::{encrypt, Cipher}; //! //! let cipher = Cipher::aes_128_cbc(); //! let data = b"Some Crypto Text"; //! let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; //! let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; //! let ciphertext = encrypt( //! cipher, //! key, //! Some(iv), //! data).unwrap(); //! //! assert_eq!( //! b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\ //! \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1", //! &ciphertext[..]); //! ``` //! //! Encrypting an asymmetric key with a symmetric cipher //! //! ``` //! use openssl::rsa::{Padding, Rsa}; //! use openssl::symm::Cipher; //! //! // Generate keypair and encrypt private key: //! let keypair = Rsa::generate(2048).unwrap(); //! let cipher = Cipher::aes_256_cbc(); //! let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap(); //! let privkey_pem = keypair.private_key_to_pem_passphrase(cipher, b"Rust").unwrap(); //! // pubkey_pem and privkey_pem could be written to file here. //! //! // Load private and public key from string: //! let pubkey = Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap(); //! let privkey = Rsa::private_key_from_pem_passphrase(&privkey_pem, b"Rust").unwrap(); //! //! // Use the asymmetric keys to encrypt and decrypt a short message: //! let msg = b"Foo bar"; //! let mut encrypted = vec![0; pubkey.size() as usize]; //! let mut decrypted = vec![0; privkey.size() as usize]; //! let len = pubkey.public_encrypt(msg, &mut encrypted, Padding::PKCS1).unwrap(); //! assert!(len > msg.len()); //! let len = privkey.private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1).unwrap(); //! let output_string = String::from_utf8(decrypted[..len].to_vec()).unwrap(); //! assert_eq!("Foo bar", output_string); //! println!("Decrypted: '{}'", output_string); //! ``` use ffi; use libc::c_int; use std::cmp; use std::ptr; use error::ErrorStack; use nid::Nid; use {cvt, cvt_p}; #[derive(Copy, Clone)] pub enum Mode { Encrypt, Decrypt, } /// Represents a particular cipher algorithm. /// /// See OpenSSL doc at [`EVP_EncryptInit`] for more information on each algorithms. /// /// [`EVP_EncryptInit`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_EncryptInit.html #[derive(Copy, Clone, PartialEq, Eq)] pub struct Cipher(*const ffi::EVP_CIPHER); impl Cipher { /// Looks up the cipher for a certain nid. /// /// This corresponds to [`EVP_get_cipherbynid`] /// /// [`EVP_get_cipherbynid`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_get_cipherbyname.html pub fn from_nid(nid: Nid) -> Option { let ptr = unsafe { ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())) }; if ptr.is_null() { None } else { Some(Cipher(ptr)) } } pub fn aes_128_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_ecb()) } } pub fn aes_128_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_cbc()) } } pub fn aes_128_xts() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_xts()) } } pub fn aes_128_ctr() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_ctr()) } } pub fn aes_128_cfb1() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_cfb1()) } } pub fn aes_128_cfb128() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_cfb128()) } } pub fn aes_128_cfb8() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_cfb8()) } } pub fn aes_128_gcm() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_gcm()) } } pub fn aes_128_ccm() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_ccm()) } } pub fn aes_256_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_ecb()) } } pub fn aes_256_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_cbc()) } } pub fn aes_256_xts() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_xts()) } } pub fn aes_256_ctr() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_ctr()) } } pub fn aes_256_cfb1() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_cfb1()) } } pub fn aes_256_cfb128() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_cfb128()) } } pub fn aes_256_cfb8() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_cfb8()) } } pub fn aes_256_gcm() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_gcm()) } } pub fn aes_256_ccm() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_ccm()) } } pub fn bf_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_bf_cbc()) } } pub fn bf_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_bf_ecb()) } } pub fn bf_cfb64() -> Cipher { unsafe { Cipher(ffi::EVP_bf_cfb64()) } } pub fn bf_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_bf_ofb()) } } pub fn des_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_des_cbc()) } } pub fn des_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_des_ecb()) } } pub fn des_ede3() -> Cipher { unsafe { Cipher(ffi::EVP_des_ede3()) } } pub fn des_ede3_cbc() -> Cipher { 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()) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(any(ossl110))] pub fn chacha20() -> Cipher { unsafe { Cipher(ffi::EVP_chacha20()) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(any(ossl110))] pub fn chacha20_poly1305() -> Cipher { unsafe { Cipher(ffi::EVP_chacha20_poly1305()) } } pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher { Cipher(ptr) } pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER { self.0 } /// Returns the length of keys used with this cipher. pub fn key_len(&self) -> usize { unsafe { EVP_CIPHER_key_length(self.0) as usize } } /// Returns the length of the IV used with this cipher, or `None` if the /// cipher does not use an IV. pub fn iv_len(&self) -> Option { unsafe { let len = EVP_CIPHER_iv_length(self.0) as usize; if len == 0 { None } else { Some(len) } } } /// Returns the block size of the cipher. /// /// # Note /// /// Stream ciphers such as RC4 have a block size of 1. pub fn block_size(&self) -> usize { unsafe { EVP_CIPHER_block_size(self.0) as usize } } /// Determines whether the cipher is using CCM mode fn is_ccm(&self) -> bool { // NOTE: OpenSSL returns pointers to static structs, which makes this work as expected *self == Cipher::aes_128_ccm() || *self == Cipher::aes_256_ccm() } } unsafe impl Sync for Cipher {} unsafe impl Send for Cipher {} /// Represents a symmetric cipher context. /// /// Padding is enabled by default. /// /// # Examples /// /// Encrypt some plaintext in chunks, then decrypt the ciphertext back into plaintext, in AES 128 /// CBC mode. /// /// ``` /// use openssl::symm::{Cipher, Mode, Crypter}; /// /// let plaintexts: [&[u8]; 2] = [b"Some Stream of", b" Crypto Text"]; /// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; /// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; /// let data_len = plaintexts.iter().fold(0, |sum, x| sum + x.len()); /// /// // Create a cipher context for encryption. /// let mut encrypter = Crypter::new( /// Cipher::aes_128_cbc(), /// Mode::Encrypt, /// key, /// Some(iv)).unwrap(); /// /// let block_size = Cipher::aes_128_cbc().block_size(); /// let mut ciphertext = vec![0; data_len + block_size]; /// /// // Encrypt 2 chunks of plaintexts successively. /// let mut count = encrypter.update(plaintexts[0], &mut ciphertext).unwrap(); /// count += encrypter.update(plaintexts[1], &mut ciphertext[count..]).unwrap(); /// count += encrypter.finalize(&mut ciphertext[count..]).unwrap(); /// ciphertext.truncate(count); /// /// assert_eq!( /// b"\x0F\x21\x83\x7E\xB2\x88\x04\xAF\xD9\xCC\xE2\x03\x49\xB4\x88\xF6\xC4\x61\x0E\x32\x1C\xF9\ /// \x0D\x66\xB1\xE6\x2C\x77\x76\x18\x8D\x99", /// &ciphertext[..] /// ); /// /// /// // Let's pretend we don't know the plaintext, and now decrypt the ciphertext. /// let data_len = ciphertext.len(); /// let ciphertexts = [&ciphertext[..9], &ciphertext[9..]]; /// /// // Create a cipher context for decryption. /// let mut decrypter = Crypter::new( /// Cipher::aes_128_cbc(), /// Mode::Decrypt, /// key, /// Some(iv)).unwrap(); /// let mut plaintext = vec![0; data_len + block_size]; /// /// // Decrypt 2 chunks of ciphertexts successively. /// let mut count = decrypter.update(ciphertexts[0], &mut plaintext).unwrap(); /// count += decrypter.update(ciphertexts[1], &mut plaintext[count..]).unwrap(); /// count += decrypter.finalize(&mut plaintext[count..]).unwrap(); /// plaintext.truncate(count); /// /// assert_eq!(b"Some Stream of Crypto Text", &plaintext[..]); /// ``` pub struct Crypter { ctx: *mut ffi::EVP_CIPHER_CTX, block_size: usize, } unsafe impl Sync for Crypter {} unsafe impl Send for Crypter {} impl Crypter { /// Creates a new `Crypter`. The initialisation vector, `iv`, is not necesarry for certain /// types of `Cipher`. /// /// # Panics /// /// Panics if an IV is required by the cipher but not provided. Also make sure that the key /// and IV size are appropriate for your cipher. pub fn new( t: Cipher, mode: Mode, key: &[u8], iv: Option<&[u8]>, ) -> Result { ffi::init(); unsafe { let ctx = cvt_p(ffi::EVP_CIPHER_CTX_new())?; let crypter = Crypter { ctx: ctx, block_size: t.block_size(), }; let mode = match mode { Mode::Encrypt => 1, Mode::Decrypt => 0, }; cvt(ffi::EVP_CipherInit_ex( crypter.ctx, t.as_ptr(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), mode, ))?; assert!(key.len() <= c_int::max_value() as usize); cvt(ffi::EVP_CIPHER_CTX_set_key_length( crypter.ctx, key.len() as c_int, ))?; let key = key.as_ptr() as *mut _; let iv = match (iv, t.iv_len()) { (Some(iv), Some(len)) => { if iv.len() != len { assert!(iv.len() <= c_int::max_value() as usize); cvt(ffi::EVP_CIPHER_CTX_ctrl( crypter.ctx, ffi::EVP_CTRL_GCM_SET_IVLEN, iv.len() as c_int, ptr::null_mut(), ))?; } iv.as_ptr() as *mut _ } (Some(_), None) | (None, None) => ptr::null_mut(), (None, Some(_)) => panic!("an IV is required for this cipher"), }; cvt(ffi::EVP_CipherInit_ex( crypter.ctx, ptr::null(), ptr::null_mut(), key, iv, mode, ))?; Ok(crypter) } } /// Enables or disables padding. /// /// If padding is disabled, total amount of data encrypted/decrypted must /// be a multiple of the cipher's block size. pub fn pad(&mut self, padding: bool) { unsafe { ffi::EVP_CIPHER_CTX_set_padding(self.ctx, padding as c_int); } } /// Sets the tag used to authenticate ciphertext in AEAD ciphers such as AES GCM. /// /// When decrypting cipher text using an AEAD cipher, this must be called before `finalize`. pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(tag.len() <= c_int::max_value() as usize); // NB: this constant is actually more general than just GCM. cvt(ffi::EVP_CIPHER_CTX_ctrl( self.ctx, ffi::EVP_CTRL_GCM_SET_TAG, tag.len() as c_int, tag.as_ptr() as *mut _, )) .map(|_| ()) } } /// Sets the length of the authentication tag to generate in AES CCM. /// /// When encrypting with AES CCM, the tag length needs to be explicitly set in order /// to use a value different than the default 12 bytes. pub fn set_tag_len(&mut self, tag_len: usize) -> Result<(), ErrorStack> { unsafe { assert!(tag_len <= c_int::max_value() as usize); // NB: this constant is actually more general than just GCM. cvt(ffi::EVP_CIPHER_CTX_ctrl( self.ctx, ffi::EVP_CTRL_GCM_SET_TAG, tag_len as c_int, ptr::null_mut(), )) .map(|_| ()) } } /// Feeds total plaintext length to the cipher. /// /// The total plaintext or ciphertext length MUST be passed to the cipher when it operates in /// CCM mode. pub fn set_data_len(&mut self, data_len: usize) -> Result<(), ErrorStack> { unsafe { assert!(data_len <= c_int::max_value() as usize); let mut len = 0; cvt(ffi::EVP_CipherUpdate( self.ctx, ptr::null_mut(), &mut len, ptr::null_mut(), data_len as c_int, )) .map(|_| ()) } } /// Feeds Additional Authenticated Data (AAD) through the cipher. /// /// This can only be used with AEAD ciphers such as AES GCM. Data fed in is not encrypted, but /// is factored into the authentication tag. It must be called before the first call to /// `update`. pub fn aad_update(&mut self, input: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(input.len() <= c_int::max_value() as usize); let mut len = 0; cvt(ffi::EVP_CipherUpdate( self.ctx, ptr::null_mut(), &mut len, input.as_ptr(), input.len() as c_int, )) .map(|_| ()) } } /// Feeds data from `input` through the cipher, writing encrypted/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 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 { 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; cvt(ffi::EVP_CipherUpdate( self.ctx, output.as_mut_ptr(), &mut outl, input.as_ptr(), inl, ))?; Ok(outl as usize) } } /// Finishes the encryption/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 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 { 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( self.ctx, output.as_mut_ptr(), &mut outl, ))?; Ok(outl as usize) } } /// Retrieves the authentication tag used to authenticate ciphertext in AEAD ciphers such /// as AES GCM. /// /// When encrypting data with an AEAD cipher, this must be called after `finalize`. /// /// The size of the buffer indicates the required size of the tag. While some ciphers support a /// range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 /// bytes, for example. pub fn get_tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> { unsafe { assert!(tag.len() <= c_int::max_value() as usize); cvt(ffi::EVP_CIPHER_CTX_ctrl( self.ctx, ffi::EVP_CTRL_GCM_GET_TAG, tag.len() as c_int, tag.as_mut_ptr() as *mut _, )) .map(|_| ()) } } } impl Drop for Crypter { fn drop(&mut self) { unsafe { ffi::EVP_CIPHER_CTX_free(self.ctx); } } } /// Encrypts data in one go, and returns the encrypted data. /// /// Data is encrypted using the specified cipher type `t` in encrypt mode with the specified `key` /// and initailization vector `iv`. Padding is enabled. /// /// This is a convenient interface to `Crypter` to encrypt all data in one go. To encrypt a stream /// of data increamentally , use `Crypter` instead. /// /// # Examples /// /// Encrypt data in AES128 CBC mode /// /// ``` /// use openssl::symm::{encrypt, Cipher}; /// /// let cipher = Cipher::aes_128_cbc(); /// let data = b"Some Crypto Text"; /// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; /// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; /// let ciphertext = encrypt( /// cipher, /// key, /// Some(iv), /// data).unwrap(); /// /// assert_eq!( /// b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\x87\x4D\ /// \xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1", /// &ciphertext[..]); /// ``` pub fn encrypt( t: Cipher, key: &[u8], iv: Option<&[u8]>, data: &[u8], ) -> Result, ErrorStack> { cipher(t, Mode::Encrypt, key, iv, data) } /// Decrypts data in one go, and returns the decrypted data. /// /// Data is decrypted using the specified cipher type `t` in decrypt mode with the specified `key` /// and initailization vector `iv`. Padding is enabled. /// /// This is a convenient interface to `Crypter` to decrypt all data in one go. To decrypt a stream /// of data increamentally , use `Crypter` instead. /// /// # Examples /// /// Decrypt data in AES128 CBC mode /// /// ``` /// use openssl::symm::{decrypt, Cipher}; /// /// let cipher = Cipher::aes_128_cbc(); /// let data = b"\xB4\xB9\xE7\x30\xD6\xD6\xF7\xDE\x77\x3F\x1C\xFF\xB3\x3E\x44\x5A\x91\xD7\x27\x62\ /// \x87\x4D\xFB\x3C\x5E\xC4\x59\x72\x4A\xF4\x7C\xA1"; /// let key = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; /// let iv = b"\x00\x01\x02\x03\x04\x05\x06\x07\x00\x01\x02\x03\x04\x05\x06\x07"; /// let ciphertext = decrypt( /// cipher, /// key, /// Some(iv), /// data).unwrap(); /// /// assert_eq!( /// b"Some Crypto Text", /// &ciphertext[..]); /// ``` pub fn decrypt( t: Cipher, key: &[u8], iv: Option<&[u8]>, data: &[u8], ) -> Result, ErrorStack> { cipher(t, Mode::Decrypt, key, iv, data) } fn cipher( t: Cipher, mode: Mode, key: &[u8], iv: Option<&[u8]>, data: &[u8], ) -> Result, ErrorStack> { let mut c = Crypter::new(t, mode, key, iv)?; let mut out = vec![0; data.len() + t.block_size()]; let count = c.update(data, &mut out)?; let rest = c.finalize(&mut out[count..])?; out.truncate(count + rest); Ok(out) } /// Like `encrypt`, but for AEAD ciphers such as AES GCM. /// /// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag /// will be copied into the `tag` field. /// /// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support /// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes, /// for example. pub fn encrypt_aead( t: Cipher, key: &[u8], iv: Option<&[u8]>, aad: &[u8], data: &[u8], tag: &mut [u8], ) -> Result, ErrorStack> { let mut c = Crypter::new(t, Mode::Encrypt, key, iv)?; let mut out = vec![0; data.len() + t.block_size()]; if t.is_ccm() { c.set_tag_len(tag.len())?; c.set_data_len(data.len())?; } c.aad_update(aad)?; let count = c.update(data, &mut out)?; let rest = c.finalize(&mut out[count..])?; c.get_tag(tag)?; out.truncate(count + rest); Ok(out) } /// Like `decrypt`, but for AEAD ciphers such as AES GCM. /// /// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag /// should be provided in the `tag` field. pub fn decrypt_aead( t: Cipher, key: &[u8], iv: Option<&[u8]>, aad: &[u8], data: &[u8], tag: &[u8], ) -> Result, ErrorStack> { let mut c = Crypter::new(t, Mode::Decrypt, key, iv)?; let mut out = vec![0; data.len() + t.block_size()]; if t.is_ccm() { c.set_tag(tag)?; c.set_data_len(data.len())?; } c.aad_update(aad)?; let count = c.update(data, &mut out)?; let mut rest = 0; if !t.is_ccm() { c.set_tag(tag)?; rest = c.finalize(&mut out[count..])?; } out.truncate(count + rest); Ok(out) } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; } else { #[allow(bad_style)] pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> c_int { (*ptr).iv_len } #[allow(bad_style)] pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> c_int { (*ptr).block_size } #[allow(bad_style)] pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> c_int { (*ptr).key_len } } } #[cfg(test)] mod tests { 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] fn test_aes_256_ecb() { let k0 = [ 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0x07u8, 0x08u8, 0x09u8, 0x0au8, 0x0bu8, 0x0cu8, 0x0du8, 0x0eu8, 0x0fu8, 0x10u8, 0x11u8, 0x12u8, 0x13u8, 0x14u8, 0x15u8, 0x16u8, 0x17u8, 0x18u8, 0x19u8, 0x1au8, 0x1bu8, 0x1cu8, 0x1du8, 0x1eu8, 0x1fu8, ]; let p0 = [ 0x00u8, 0x11u8, 0x22u8, 0x33u8, 0x44u8, 0x55u8, 0x66u8, 0x77u8, 0x88u8, 0x99u8, 0xaau8, 0xbbu8, 0xccu8, 0xddu8, 0xeeu8, 0xffu8, ]; let c0 = [ 0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8, 0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8, ]; let mut c = super::Crypter::new( super::Cipher::aes_256_ecb(), super::Mode::Encrypt, &k0, None, ) .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(); let rest = c.finalize(&mut r0[count..]).unwrap(); r0.truncate(count + rest); assert_eq!(hex::encode(&r0), hex::encode(c0)); let mut c = super::Crypter::new( super::Cipher::aes_256_ecb(), super::Mode::Decrypt, &k0, None, ) .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(); let rest = c.finalize(&mut p1[count..]).unwrap(); p1.truncate(count + rest); assert_eq!(hex::encode(p1), hex::encode(p0)); } #[test] fn test_aes_256_cbc_decrypt() { let iv = [ 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, ]; let data = [ 143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, 233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8, ]; let ciphered_data = [ 0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, 0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0x65_u8, 0x6f_u8, ]; let mut cr = super::Crypter::new( super::Cipher::aes_256_cbc(), super::Mode::Decrypt, &data, Some(&iv), ) .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(); let rest = cr.finalize(&mut unciphered_data[count..]).unwrap(); unciphered_data.truncate(count + rest); let expected_unciphered_data = b"I love turtles.\x01"; assert_eq!(&unciphered_data, expected_unciphered_data); } fn cipher_test(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) { let pt = Vec::from_hex(pt).unwrap(); let ct = Vec::from_hex(ct).unwrap(); let key = Vec::from_hex(key).unwrap(); let iv = Vec::from_hex(iv).unwrap(); let computed = super::decrypt(ciphertype, &key, Some(&iv), &ct).unwrap(); let expected = pt; if computed != expected { println!("Computed: {}", hex::encode(&computed)); println!("Expected: {}", hex::encode(&expected)); if computed.len() != expected.len() { println!( "Lengths differ: {} in computed vs {} expected", computed.len(), expected.len() ); } panic!("test failure"); } } fn cipher_test_nopad(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) { let pt = Vec::from_hex(pt).unwrap(); let ct = Vec::from_hex(ct).unwrap(); let key = Vec::from_hex(key).unwrap(); let iv = Vec::from_hex(iv).unwrap(); let computed = { let mut c = Crypter::new(ciphertype, Mode::Decrypt, &key, Some(&iv)).unwrap(); c.pad(false); let mut out = vec![0; ct.len() + ciphertype.block_size()]; let count = c.update(&ct, &mut out).unwrap(); let rest = c.finalize(&mut out[count..]).unwrap(); out.truncate(count + rest); out }; let expected = pt; if computed != expected { println!("Computed: {}", hex::encode(&computed)); println!("Expected: {}", hex::encode(&expected)); if computed.len() != expected.len() { println!( "Lengths differ: {} in computed vs {} expected", computed.len(), expected.len() ); } panic!("test failure"); } } #[test] fn test_rc4() { let pt = "0000000000000000000000000000000000000000000000000000000000000000000000000000"; let ct = "A68686B04D686AA107BD8D4CAB191A3EEC0A6294BC78B60F65C25CB47BD7BB3A48EFC4D26BE4"; let key = "97CD440324DA5FD1F7955C1C13B6B466"; let iv = ""; cipher_test(super::Cipher::rc4(), pt, ct, key, iv); } #[test] fn test_aes256_xts() { // Test case 174 from // http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip let pt = "77f4ef63d734ebd028508da66c22cdebdd52ecd6ee2ab0a50bc8ad0cfd692ca5fcd4e6dedc45df7f\ 6503f462611dc542"; let ct = "ce7d905a7776ac72f240d22aafed5e4eb7566cdc7211220e970da634ce015f131a5ecb8d400bc9e8\ 4f0b81d8725dbbc7"; let key = "b6bfef891f83b5ff073f2231267be51eb084b791fa19a154399c0684c8b2dfcb37de77d28bbda3b\ 4180026ad640b74243b3133e7b9fae629403f6733423dae28"; let iv = "db200efb7eaaa737dbdf40babb68953f"; cipher_test(super::Cipher::aes_256_xts(), pt, ct, key, iv); } #[test] fn test_aes128_ctr() { let pt = "6BC1BEE22E409F96E93D7E117393172AAE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411\ E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710"; let ct = "874D6191B620E3261BEF6864990DB6CE9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E\ 5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE"; let key = "2B7E151628AED2A6ABF7158809CF4F3C"; let iv = "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"; cipher_test(super::Cipher::aes_128_ctr(), pt, ct, key, iv); } #[test] fn test_aes128_cfb1() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf let pt = "6bc1"; let ct = "68b3"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_128_cfb1(), pt, ct, key, iv); } #[test] fn test_aes128_cfb128() { let pt = "6bc1bee22e409f96e93d7e117393172a"; let ct = "3b3fd92eb72dad20333449f8e83cfb4a"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_128_cfb128(), pt, ct, key, iv); } #[test] fn test_aes128_cfb8() { let pt = "6bc1bee22e409f96e93d7e117393172aae2d"; let ct = "3b79424c9c0dd436bace9e0ed4586a4f32b9"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_128_cfb8(), pt, ct, key, iv); } #[test] fn test_aes256_cfb1() { let pt = "6bc1"; let ct = "9029"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_256_cfb1(), pt, ct, key, iv); } #[test] fn test_aes256_cfb128() { let pt = "6bc1bee22e409f96e93d7e117393172a"; let ct = "dc7e84bfda79164b7ecd8486985d3860"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_256_cfb128(), pt, ct, key, iv); } #[test] fn test_aes256_cfb8() { let pt = "6bc1bee22e409f96e93d7e117393172aae2d"; let ct = "dc1f1a8520a64db55fcc8ac554844e889700"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_256_cfb8(), pt, ct, key, iv); } #[test] fn test_bf_cbc() { // https://www.schneier.com/code/vectors.txt let pt = "37363534333231204E6F77206973207468652074696D6520666F722000000000"; let ct = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"; let key = "0123456789ABCDEFF0E1D2C3B4A59687"; let iv = "FEDCBA9876543210"; cipher_test_nopad(super::Cipher::bf_cbc(), pt, ct, key, iv); } #[test] fn test_bf_ecb() { let pt = "5CD54CA83DEF57DA"; let ct = "B1B8CC0B250F09A0"; let key = "0131D9619DC1376E"; let iv = "0000000000000000"; cipher_test_nopad(super::Cipher::bf_ecb(), pt, ct, key, iv); } #[test] fn test_bf_cfb64() { let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; let ct = "E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3"; let key = "0123456789ABCDEFF0E1D2C3B4A59687"; let iv = "FEDCBA9876543210"; cipher_test_nopad(super::Cipher::bf_cfb64(), pt, ct, key, iv); } #[test] fn test_bf_ofb() { let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; let ct = "E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"; let key = "0123456789ABCDEFF0E1D2C3B4A59687"; let iv = "FEDCBA9876543210"; cipher_test_nopad(super::Cipher::bf_ofb(), pt, ct, key, iv); } #[test] fn test_des_cbc() { let pt = "54686973206973206120746573742e"; let ct = "6f2867cfefda048a4046ef7e556c7132"; let key = "7cb66337f3d3c0fe"; let iv = "0001020304050607"; cipher_test(super::Cipher::des_cbc(), pt, ct, key, iv); } #[test] fn test_des_ecb() { let pt = "54686973206973206120746573742e"; let ct = "0050ab8aecec758843fe157b4dde938c"; let key = "7cb66337f3d3c0fe"; let iv = "0001020304050607"; cipher_test(super::Cipher::des_ecb(), pt, ct, key, iv); } #[test] fn test_des_ede3() { let pt = "9994f4c69d40ae4f34ff403b5cf39d4c8207ea5d3e19a5fd"; let ct = "9e5c4297d60582f81071ac8ab7d0698d4c79de8b94c519858207ea5d3e19a5fd"; let key = "010203040506070801020304050607080102030405060708"; let iv = "5cc118306dc702e4"; cipher_test(super::Cipher::des_ede3(), pt, ct, key, iv); } #[test] fn test_des_ede3_cbc() { let pt = "54686973206973206120746573742e"; let ct = "6f2867cfefda048a4046ef7e556c7132"; let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe"; let iv = "0001020304050607"; cipher_test(super::Cipher::des_ede3_cbc(), pt, ct, key, iv); } #[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\ 4cbb921d8326631631fc6a5d304f39166daf7ea15fa1977f101819adb510b50fe9932e12c5a85aa3fd1e73\ d8d760af218be829903a77c63359d75edd91b4f6ed5465a72662f5055999e059e7654a8edc921aa0d496"; let pt = "fef03c2d7fb15bf0d2df18007d99f967c878ad59359034f7bb2c19af120685d78e32f6b8b83b032019956c\ a9c0195721476b85"; let aad = "d8f1163d8c840292a2b2dacf4ac7c36aff8733f18fabb4fa5594544125e03d1e6e5d6d0fd61656c8d8f327\ c92839ae5539bb469c9257f109ebff85aad7bd220fdaa95c022dbd0c7bb2d878ad504122c943045d3c5eba\ 8f1f56c0"; let ct = "4f6cf471be7cbd2575cd5a1747aea8fe9dea83e51936beac3e68f66206922060c697ffa7af80ad6bb68f2c\ f4fc97416ee52abe"; let tag = "e20b6655"; // this tag is smaller than you'd normally want, but I pulled this test from the part of // the NIST test vectors that cover 4 byte tags. let mut actual_tag = [0; 4]; let out = encrypt_aead( Cipher::aes_128_gcm(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(iv).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, ) .unwrap(); assert_eq!(ct, hex::encode(out)); assert_eq!(tag, hex::encode(actual_tag)); let out = decrypt_aead( Cipher::aes_128_gcm(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(iv).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), ) .unwrap(); assert_eq!(pt, hex::encode(out)); } #[test] fn test_aes128_ccm() { let key = "3ee186594f110fb788a8bf8aa8be5d4a"; let nonce = "44f705d52acf27b7f17196aa9b"; let aad = "2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57"; let pt = "d71864877f2578db092daba2d6a1f9f4698a9c356c7830a1"; let ct = "b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0"; let tag = "d6965f5aa6e31302a9cc2b36"; let mut actual_tag = [0; 12]; let out = encrypt_aead( Cipher::aes_128_ccm(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(nonce).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, ) .unwrap(); assert_eq!(ct, hex::encode(out)); assert_eq!(tag, hex::encode(actual_tag)); let out = decrypt_aead( Cipher::aes_128_ccm(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(nonce).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), ) .unwrap(); assert_eq!(pt, hex::encode(out)); } #[test] fn test_aes128_ccm_verify_fail() { let key = "3ee186594f110fb788a8bf8aa8be5d4a"; let nonce = "44f705d52acf27b7f17196aa9b"; let aad = "2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57"; let ct = "b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0"; let tag = "00005f5aa6e31302a9cc2b36"; let out = decrypt_aead( Cipher::aes_128_ccm(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(nonce).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), ); assert!(out.is_err()); } #[test] fn test_aes256_ccm() { let key = "7f4af6765cad1d511db07e33aaafd57646ec279db629048aa6770af24849aa0d"; let nonce = "dde2a362ce81b2b6913abc3095"; let aad = "404f5df97ece7431987bc098cce994fc3c063b519ffa47b0365226a0015ef695"; let pt = "7ebef26bf4ecf6f0ebb2eb860edbf900f27b75b4a6340fdb"; let ct = "353022db9c568bd7183a13c40b1ba30fcc768c54264aa2cd"; let tag = "2927a053c9244d3217a7ad05"; let mut actual_tag = [0; 12]; let out = encrypt_aead( Cipher::aes_256_ccm(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(nonce).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, ) .unwrap(); assert_eq!(ct, hex::encode(out)); assert_eq!(tag, hex::encode(actual_tag)); let out = decrypt_aead( Cipher::aes_256_ccm(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(nonce).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), ) .unwrap(); assert_eq!(pt, hex::encode(out)); } #[test] fn test_aes256_ccm_verify_fail() { let key = "7f4af6765cad1d511db07e33aaafd57646ec279db629048aa6770af24849aa0d"; let nonce = "dde2a362ce81b2b6913abc3095"; let aad = "404f5df97ece7431987bc098cce994fc3c063b519ffa47b0365226a0015ef695"; let ct = "353022db9c568bd7183a13c40b1ba30fcc768c54264aa2cd"; let tag = "0000a053c9244d3217a7ad05"; let out = decrypt_aead( Cipher::aes_256_ccm(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(nonce).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), ); assert!(out.is_err()); } #[test] #[cfg(any(ossl110))] fn test_chacha20() { let key = "0000000000000000000000000000000000000000000000000000000000000000"; let iv = "00000000000000000000000000000000"; let pt = "000000000000000000000000000000000000000000000000000000000000000000000000000000000\ 00000000000000000000000000000000000000000000000"; let ct = "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7\ 724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586"; cipher_test(Cipher::chacha20(), pt, ct, key, iv); } #[test] #[cfg(any(ossl110))] fn test_chacha20_poly1305() { let key = "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"; let iv = "070000004041424344454647"; let aad = "50515253c0c1c2c3c4c5c6c7"; let pt = "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393\ a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f722074\ 6865206675747572652c2073756e73637265656e20776f756c642062652069742e"; let ct = "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca967128\ 2fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fa\ b324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116"; let tag = "1ae10b594f09e26a7e902ecbd0600691"; let mut actual_tag = [0; 16]; let out = encrypt_aead( Cipher::chacha20_poly1305(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(iv).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(pt).unwrap(), &mut actual_tag, ) .unwrap(); assert_eq!(ct, hex::encode(out)); assert_eq!(tag, hex::encode(actual_tag)); let out = decrypt_aead( Cipher::chacha20_poly1305(), &Vec::from_hex(key).unwrap(), Some(&Vec::from_hex(iv).unwrap()), &Vec::from_hex(aad).unwrap(), &Vec::from_hex(ct).unwrap(), &Vec::from_hex(tag).unwrap(), ) .unwrap(); assert_eq!(pt, hex::encode(out)); } } openssl-0.10.23/src/util.rs010064400017500001750000000034211346222217000136720ustar0000000000000000use libc::{c_char, c_int, c_void}; use std::any::Any; use std::panic::{self, AssertUnwindSafe}; use std::slice; use error::ErrorStack; /// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI /// frames are on the stack). /// /// When dropped, checks if the callback has panicked, and resumes unwinding if so. pub struct CallbackState { /// The user callback. Taken out of the `Option` when called. cb: Option, /// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL /// returns. panic: Option>, } impl CallbackState { pub fn new(callback: F) -> Self { CallbackState { cb: Some(callback), panic: None, } } } impl Drop for CallbackState { fn drop(&mut self) { if let Some(panic) = self.panic.take() { panic::resume_unwind(panic); } } } /// Password callback function, passed to private key loading functions. /// /// `cb_state` is expected to be a pointer to a `CallbackState`. pub unsafe extern "C" fn invoke_passwd_cb( buf: *mut c_char, size: c_int, _rwflag: c_int, cb_state: *mut c_void, ) -> c_int where F: FnOnce(&mut [u8]) -> Result, { let callback = &mut *(cb_state as *mut CallbackState); let result = panic::catch_unwind(AssertUnwindSafe(|| { let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize); callback.cb.take().unwrap()(pass_slice) })); match result { Ok(Ok(len)) => len as c_int, Ok(Err(_)) => { // FIXME restore error stack 0 } Err(err) => { callback.panic = Some(err); 0 } } } openssl-0.10.23/src/version.rs010064400017500001750000000106071346470247500144230ustar0000000000000000// Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // use std::ffi::CStr; cfg_if! { if #[cfg(any(ossl110, libressl271))] { use ffi::{ OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, OpenSSL_version_num, OpenSSL_version, }; } else { use ffi::{ SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM, SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num, SSLeay_version as OpenSSL_version, }; } } /// OPENSSL_VERSION_NUMBER is a numeric release version identifier: /// /// `MNNFFPPS: major minor fix patch status` /// /// The status nibble has one of the values 0 for development, 1 to e for betas 1 to 14, and f for release. /// /// for example /// /// `0x000906000 == 0.9.6 dev` /// `0x000906023 == 0.9.6b beta 3` /// `0x00090605f == 0.9.6e release` /// /// Versions prior to 0.9.3 have identifiers < 0x0930. Versions between 0.9.3 and 0.9.5 had a version identifier with this interpretation: /// /// `MMNNFFRBB major minor fix final beta/patch` /// /// for example /// /// `0x000904100 == 0.9.4 release` /// `0x000905000 == 0.9.5 dev` /// /// Version 0.9.5a had an interim interpretation that is like the current one, except the patch level got the highest bit set, to keep continuity. The number was therefore 0x0090581f /// /// The return value of this function can be compared to the macro to make sure that the correct version of the library has been loaded, especially when using DLLs on Windows systems. pub fn number() -> i64 { unsafe { OpenSSL_version_num() as i64 } } /// The text variant of the version number and the release date. For example, "OpenSSL 0.9.5a 1 Apr 2000". pub fn version() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_VERSION)) .to_str() .unwrap() } } /// The compiler flags set for the compilation process in the form "compiler: ..." if available or /// "compiler: information not available" otherwise. pub fn c_flags() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_CFLAGS)) .to_str() .unwrap() } } /// The date of the build process in the form "built on: ..." if available or "built on: date not available" otherwise. pub fn built_on() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_BUILT_ON)) .to_str() .unwrap() } } /// The "Configure" target of the library build in the form "platform: ..." if available or "platform: information not available" otherwise. pub fn platform() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_PLATFORM)) .to_str() .unwrap() } } /// The "OPENSSLDIR" setting of the library build in the form "OPENSSLDIR: "..."" if available or "OPENSSLDIR: N/A" otherwise. pub fn dir() -> &'static str { unsafe { CStr::from_ptr(OpenSSL_version(OPENSSL_DIR)) .to_str() .unwrap() } } /// This test ensures that we do not segfault when calling the functions of this module /// and that the strings respect a reasonable format. #[test] fn test_versions() { println!("Number: '{}'", number()); println!("Version: '{}'", version()); println!("C flags: '{}'", c_flags()); println!("Built on: '{}'", built_on()); println!("Platform: '{}'", platform()); println!("Dir: '{}'", dir()); #[cfg(not(libressl))] fn expected_name() -> &'static str { "OpenSSL" } #[cfg(libressl)] fn expected_name() -> &'static str { "LibreSSL" } assert!(number() > 0); assert!(version().starts_with(expected_name())); assert!(c_flags().starts_with("compiler:")); assert!(built_on().starts_with("built on:")); assert!(dir().starts_with("OPENSSLDIR:")); } openssl-0.10.23/src/x509/extension.rs010064400017500001750000000365351346222217000154520ustar0000000000000000//! 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 //! managing relationships between CAs. The extensions created using this //! module can be used with `X509v3Context` objects. //! //! # Example //! //! ```rust //! extern crate openssl; //! //! use openssl::x509::extension::BasicConstraints; //! use openssl::x509::X509Extension; //! //! fn main() { //! let mut bc = BasicConstraints::new(); //! let bc = bc.critical().ca().pathlen(1); //! //! let extension: X509Extension = bc.build().unwrap(); //! } //! ``` use std::fmt::Write; use error::ErrorStack; use nid::Nid; use x509::{X509Extension, X509v3Context}; /// An extension which indicates whether a certificate is a CA certificate. pub struct BasicConstraints { critical: bool, ca: bool, pathlen: Option, } impl BasicConstraints { /// Construct a new `BasicConstraints` extension. pub fn new() -> BasicConstraints { BasicConstraints { critical: false, ca: false, pathlen: None, } } /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut BasicConstraints { self.critical = true; self } /// Sets the `ca` flag to `true`. pub fn ca(&mut self) -> &mut BasicConstraints { self.ca = true; self } /// Sets the pathlen to an optional non-negative value. The pathlen is the /// maximum number of CAs that can appear below this one in a chain. pub fn pathlen(&mut self, pathlen: u32) -> &mut BasicConstraints { self.pathlen = Some(pathlen); self } /// Return the `BasicConstraints` extension as an `X509Extension`. pub fn build(&self) -> Result { let mut value = String::new(); if self.critical { value.push_str("critical,"); } value.push_str("CA:"); if self.ca { value.push_str("TRUE"); } else { value.push_str("FALSE"); } if let Some(pathlen) = self.pathlen { write!(value, ",pathlen:{}", pathlen).unwrap(); } X509Extension::new_nid(None, None, Nid::BASIC_CONSTRAINTS, &value) } } /// An extension consisting of a list of names of the permitted key usages. pub struct KeyUsage { critical: bool, digital_signature: bool, non_repudiation: bool, key_encipherment: bool, data_encipherment: bool, key_agreement: bool, key_cert_sign: bool, crl_sign: bool, encipher_only: bool, decipher_only: bool, } impl KeyUsage { /// Construct a new `KeyUsage` extension. pub fn new() -> KeyUsage { KeyUsage { critical: false, digital_signature: false, non_repudiation: false, key_encipherment: false, data_encipherment: false, key_agreement: false, key_cert_sign: false, crl_sign: false, encipher_only: false, decipher_only: false, } } /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut KeyUsage { self.critical = true; self } /// Sets the `digitalSignature` flag to `true`. pub fn digital_signature(&mut self) -> &mut KeyUsage { self.digital_signature = true; self } /// Sets the `nonRepudiation` flag to `true`. pub fn non_repudiation(&mut self) -> &mut KeyUsage { self.non_repudiation = true; self } /// Sets the `keyEncipherment` flag to `true`. pub fn key_encipherment(&mut self) -> &mut KeyUsage { self.key_encipherment = true; self } /// Sets the `dataEncipherment` flag to `true`. pub fn data_encipherment(&mut self) -> &mut KeyUsage { self.data_encipherment = true; self } /// Sets the `keyAgreement` flag to `true`. pub fn key_agreement(&mut self) -> &mut KeyUsage { self.key_agreement = true; self } /// Sets the `keyCertSign` flag to `true`. pub fn key_cert_sign(&mut self) -> &mut KeyUsage { self.key_cert_sign = true; self } /// Sets the `cRLSign` flag to `true`. pub fn crl_sign(&mut self) -> &mut KeyUsage { self.crl_sign = true; self } /// Sets the `encipherOnly` flag to `true`. pub fn encipher_only(&mut self) -> &mut KeyUsage { self.encipher_only = true; self } /// Sets the `decipherOnly` flag to `true`. pub fn decipher_only(&mut self) -> &mut KeyUsage { self.decipher_only = true; self } /// Return the `KeyUsage` extension as an `X509Extension`. pub fn build(&self) -> Result { let mut value = String::new(); let mut first = true; append(&mut value, &mut first, self.critical, "critical"); append( &mut value, &mut first, self.digital_signature, "digitalSignature", ); append( &mut value, &mut first, self.non_repudiation, "nonRepudiation", ); append( &mut value, &mut first, self.key_encipherment, "keyEncipherment", ); append( &mut value, &mut first, self.data_encipherment, "dataEncipherment", ); append(&mut value, &mut first, self.key_agreement, "keyAgreement"); append(&mut value, &mut first, self.key_cert_sign, "keyCertSign"); append(&mut value, &mut first, self.crl_sign, "cRLSign"); append(&mut value, &mut first, self.encipher_only, "encipherOnly"); append(&mut value, &mut first, self.decipher_only, "decipherOnly"); X509Extension::new_nid(None, None, Nid::KEY_USAGE, &value) } } /// An extension consisting of a list of usages indicating purposes /// for which the certificate public key can be used for. pub struct ExtendedKeyUsage { critical: bool, server_auth: bool, client_auth: bool, code_signing: bool, email_protection: bool, time_stamping: bool, ms_code_ind: bool, ms_code_com: bool, ms_ctl_sign: bool, ms_sgc: bool, ms_efs: bool, ns_sgc: bool, other: Vec, } impl ExtendedKeyUsage { /// Construct a new `ExtendedKeyUsage` extension. pub fn new() -> ExtendedKeyUsage { ExtendedKeyUsage { critical: false, server_auth: false, client_auth: false, code_signing: false, email_protection: false, time_stamping: false, ms_code_ind: false, ms_code_com: false, ms_ctl_sign: false, ms_sgc: false, ms_efs: false, ns_sgc: false, other: vec![], } } /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut ExtendedKeyUsage { self.critical = true; self } /// Sets the `serverAuth` flag to `true`. pub fn server_auth(&mut self) -> &mut ExtendedKeyUsage { self.server_auth = true; self } /// Sets the `clientAuth` flag to `true`. pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage { self.client_auth = true; self } /// Sets the `codeSigning` flag to `true`. pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage { self.code_signing = true; self } /// Sets the `timeStamping` flag to `true`. pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage { self.time_stamping = true; self } /// Sets the `msCodeInd` flag to `true`. pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage { self.ms_code_ind = true; self } /// Sets the `msCodeCom` flag to `true`. pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage { self.ms_code_com = true; self } /// Sets the `msCTLSign` flag to `true`. pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage { self.ms_ctl_sign = true; self } /// Sets the `msSGC` flag to `true`. pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage { self.ms_sgc = true; self } /// Sets the `msEFS` flag to `true`. pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage { self.ms_efs = true; self } /// Sets the `nsSGC` flag to `true`. pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage { self.ns_sgc = true; self } /// Sets a flag not already defined. pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage { self.other.push(other.to_owned()); self } /// Return the `ExtendedKeyUsage` extension as an `X509Extension`. pub fn build(&self) -> Result { let mut value = String::new(); let mut first = true; append(&mut value, &mut first, self.critical, "critical"); append(&mut value, &mut first, self.server_auth, "serverAuth"); append(&mut value, &mut first, self.client_auth, "clientAuth"); append(&mut value, &mut first, self.code_signing, "codeSigning"); append( &mut value, &mut first, self.email_protection, "emailProtection", ); append(&mut value, &mut first, self.time_stamping, "timeStamping"); append(&mut value, &mut first, self.ms_code_ind, "msCodeInd"); append(&mut value, &mut first, self.ms_code_com, "msCodeCom"); append(&mut value, &mut first, self.ms_ctl_sign, "msCTLSign"); append(&mut value, &mut first, self.ms_sgc, "msSGC"); append(&mut value, &mut first, self.ms_efs, "msEFS"); append(&mut value, &mut first, self.ns_sgc, "nsSGC"); for other in &self.other { append(&mut value, &mut first, true, other); } X509Extension::new_nid(None, None, Nid::EXT_KEY_USAGE, &value) } } /// An extension that provides a means of identifying certificates that contain a /// particular public key. pub struct SubjectKeyIdentifier { critical: bool, } impl SubjectKeyIdentifier { /// Construct a new `SubjectKeyIdentifier` extension. pub fn new() -> SubjectKeyIdentifier { SubjectKeyIdentifier { critical: false } } /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut SubjectKeyIdentifier { self.critical = true; self } /// Return a `SubjectKeyIdentifier` extension as an `X509Extension`. pub fn build(&self, ctx: &X509v3Context) -> Result { let mut value = String::new(); let mut first = true; append(&mut value, &mut first, self.critical, "critical"); append(&mut value, &mut first, true, "hash"); X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_KEY_IDENTIFIER, &value) } } /// An extension that provides a means of identifying the public key corresponding /// to the private key used to sign a CRL. pub struct AuthorityKeyIdentifier { critical: bool, keyid: Option, issuer: Option, } impl AuthorityKeyIdentifier { /// Construct a new `AuthorityKeyIdentifier` extension. pub fn new() -> AuthorityKeyIdentifier { AuthorityKeyIdentifier { critical: false, keyid: None, issuer: None, } } /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut AuthorityKeyIdentifier { self.critical = true; self } /// Sets the `keyid` flag. pub fn keyid(&mut self, always: bool) -> &mut AuthorityKeyIdentifier { self.keyid = Some(always); self } /// Sets the `issuer` flag. pub fn issuer(&mut self, always: bool) -> &mut AuthorityKeyIdentifier { self.issuer = Some(always); self } /// Return a `AuthorityKeyIdentifier` extension as an `X509Extension`. pub fn build(&self, ctx: &X509v3Context) -> Result { let mut value = String::new(); let mut first = true; append(&mut value, &mut first, self.critical, "critical"); match self.keyid { Some(true) => append(&mut value, &mut first, true, "keyid:always"), Some(false) => append(&mut value, &mut first, true, "keyid"), None => {} } match self.issuer { Some(true) => append(&mut value, &mut first, true, "issuer:always"), Some(false) => append(&mut value, &mut first, true, "issuer"), None => {} } X509Extension::new_nid(None, Some(ctx), Nid::AUTHORITY_KEY_IDENTIFIER, &value) } } /// An extension that allows additional identities to be bound to the subject /// of the certificate. pub struct SubjectAlternativeName { critical: bool, names: Vec, } impl SubjectAlternativeName { /// Construct a new `SubjectAlternativeName` extension. pub fn new() -> SubjectAlternativeName { SubjectAlternativeName { critical: false, names: vec![], } } /// Sets the `critical` flag to `true`. The extension will be critical. pub fn critical(&mut self) -> &mut SubjectAlternativeName { self.critical = true; self } /// Sets the `email` flag. pub fn email(&mut self, email: &str) -> &mut SubjectAlternativeName { self.names.push(format!("email:{}", email)); self } /// Sets the `uri` flag. pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName { self.names.push(format!("URI:{}", uri)); self } /// Sets the `dns` flag. pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName { self.names.push(format!("DNS:{}", dns)); self } /// Sets the `rid` flag. pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName { self.names.push(format!("RID:{}", rid)); self } /// Sets the `ip` flag. pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName { self.names.push(format!("IP:{}", ip)); self } /// Sets the `dirName` flag. pub fn dir_name(&mut self, dir_name: &str) -> &mut SubjectAlternativeName { self.names.push(format!("dirName:{}", dir_name)); self } /// Sets the `otherName` flag. pub fn other_name(&mut self, other_name: &str) -> &mut SubjectAlternativeName { self.names.push(format!("otherName:{}", other_name)); self } /// Return a `SubjectAlternativeName` extension as an `X509Extension`. pub fn build(&self, ctx: &X509v3Context) -> Result { let mut value = String::new(); let mut first = true; append(&mut value, &mut first, self.critical, "critical"); for name in &self.names { append(&mut value, &mut first, true, name); } X509Extension::new_nid(None, Some(ctx), Nid::SUBJECT_ALT_NAME, &value) } } fn append(value: &mut String, first: &mut bool, should: bool, element: &str) { if !should { return; } if !*first { value.push(','); } *first = false; value.push_str(element); } openssl-0.10.23/src/x509/mod.rs010064400017500001750000001316021346222217000142040ustar0000000000000000//! The standard defining the format of public key certificates. //! //! An `X509` certificate binds an identity to a public key, and is either //! signed by a certificate authority (CA) or self-signed. An entity that gets //! a hold of a certificate can both verify your identity (via a CA) and encrypt //! data with the included public key. `X509` certificates are used in many //! Internet protocols, including SSL/TLS, which is the basis for HTTPS, //! the secure protocol for browsing the web. use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long}; use std::error::Error; use std::ffi::{CStr, CString}; use std::fmt; use std::marker::PhantomData; use std::mem; use std::path::Path; use std::ptr; use std::slice; use std::str; use asn1::{Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef}; use bio::MemBioSlice; use conf::ConfRef; use error::ErrorStack; use ex_data::Index; use hash::{DigestBytes, MessageDigest}; use nid::Nid; use pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; use ssl::SslRef; use stack::{Stack, StackRef, Stackable}; use string::OpensslString; use {cvt, cvt_n, cvt_p}; #[cfg(any(ossl102, libressl261))] pub mod verify; pub mod extension; pub mod store; #[cfg(test)] mod tests; foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE_CTX; fn drop = ffi::X509_STORE_CTX_free; /// An `X509` certificate store context. pub struct X509StoreContext; /// Reference to `X509StoreContext`. pub struct X509StoreContextRef; } impl X509StoreContext { /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a /// context. pub fn ssl_idx() -> Result, ErrorStack> { unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) } } /// Creates a new `X509StoreContext` instance. /// /// This corresponds to [`X509_STORE_CTX_new`]. /// /// [`X509_STORE_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_new.html pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext(p)) } } } impl X509StoreContextRef { /// Returns application data pertaining to an `X509` store context. /// /// This corresponds to [`X509_STORE_CTX_get_ex_data`]. /// /// [`X509_STORE_CTX_get_ex_data`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_get_ex_data.html pub fn ex_data(&self, index: Index) -> Option<&T> { unsafe { let data = ffi::X509_STORE_CTX_get_ex_data(self.as_ptr(), index.as_raw()); if data.is_null() { None } else { Some(&*(data as *const T)) } } } /// Returns the error code of the context. /// /// This corresponds to [`X509_STORE_CTX_get_error`]. /// /// [`X509_STORE_CTX_get_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error.html pub fn error(&self) -> X509VerifyResult { unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) } } /// Initializes this context with the given certificate, certificates chain and certificate /// store. After initializing the context, the `with_context` closure is called with the prepared /// context. As long as the closure is running, the context stays initialized and can be used /// to e.g. verify a certificate. The context will be cleaned up, after the closure finished. /// /// * `trust` - The certificate store with the trusted certificates. /// * `cert` - The certificate that should be verified. /// * `cert_chain` - The certificates chain. /// * `with_context` - The closure that is called with the initialized context. /// /// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to /// [`X509_STORE_CTX_cleanup`] after calling `with_context`. /// /// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html pub fn init( &mut self, trust: &store::X509StoreRef, cert: &X509Ref, cert_chain: &StackRef, with_context: F, ) -> Result where F: FnOnce(&mut X509StoreContextRef) -> Result, { struct Cleanup<'a>(&'a mut X509StoreContextRef); impl<'a> Drop for Cleanup<'a> { fn drop(&mut self) { unsafe { ffi::X509_STORE_CTX_cleanup(self.0.as_ptr()); } } } unsafe { cvt(ffi::X509_STORE_CTX_init( self.as_ptr(), trust.as_ptr(), cert.as_ptr(), cert_chain.as_ptr(), ))?; let cleanup = Cleanup(self); with_context(cleanup.0) } } /// Verifies the stored certificate. /// /// Returns `true` if verification succeeds. The `error` method will return the specific /// validation error if the certificate was not valid. /// /// This will only work inside of a call to `init`. /// /// This corresponds to [`X509_verify_cert`]. /// /// [`X509_verify_cert`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_verify_cert.html pub fn verify_cert(&mut self) -> Result { unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) } } /// Set the error code of the context. /// /// This corresponds to [`X509_STORE_CTX_set_error`]. /// /// [`X509_STORE_CTX_set_error`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_set_error.html pub fn set_error(&mut self, result: X509VerifyResult) { unsafe { ffi::X509_STORE_CTX_set_error(self.as_ptr(), result.as_raw()); } } /// Returns a reference to the certificate which caused the error or None if /// no certificate is relevant to the error. /// /// This corresponds to [`X509_STORE_CTX_get_current_cert`]. /// /// [`X509_STORE_CTX_get_current_cert`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_current_cert.html pub fn current_cert(&self) -> Option<&X509Ref> { unsafe { let ptr = ffi::X509_STORE_CTX_get_current_cert(self.as_ptr()); if ptr.is_null() { None } else { Some(X509Ref::from_ptr(ptr)) } } } /// Returns a non-negative integer representing the depth in the certificate /// chain where the error occurred. If it is zero it occurred in the end /// entity certificate, one if it is the certificate which signed the end /// entity certificate and so on. /// /// This corresponds to [`X509_STORE_CTX_get_error_depth`]. /// /// [`X509_STORE_CTX_get_error_depth`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get_error_depth.html pub fn error_depth(&self) -> u32 { unsafe { ffi::X509_STORE_CTX_get_error_depth(self.as_ptr()) as u32 } } /// Returns a reference to a complete valid `X509` certificate chain. /// /// This corresponds to [`X509_STORE_CTX_get0_chain`]. /// /// [`X509_STORE_CTX_get0_chain`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get0_chain.html pub fn chain(&self) -> Option<&StackRef> { unsafe { let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); if chain.is_null() { None } else { Some(StackRef::from_ptr(chain)) } } } } /// A builder used to construct an `X509`. pub struct X509Builder(X509); impl X509Builder { /// Creates a new builder. pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p))) } } /// Sets the notAfter constraint on the certificate. pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } } /// Sets the notBefore constraint on the certificate. pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } } /// Sets the version of the certificate. /// /// Note that the version is zero-indexed; that is, a certificate corresponding to version 3 of /// the X.509 standard should pass `2` to this method. pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } } /// Sets the serial number of the certificate. pub fn set_serial_number(&mut self, serial_number: &Asn1IntegerRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_serialNumber( self.0.as_ptr(), serial_number.as_ptr(), )) .map(|_| ()) } } /// Sets the issuer name of the certificate. pub fn set_issuer_name(&mut self, issuer_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_issuer_name( self.0.as_ptr(), issuer_name.as_ptr(), )) .map(|_| ()) } } /// Sets the subject name of the certificate. /// /// When building certificates, the `C`, `ST`, and `O` options are common when using the openssl command line tools. /// The `CN` field is used for the common name, such as a DNS name. /// /// ``` /// use openssl::x509::{X509, X509NameBuilder}; /// /// let mut x509_name = openssl::x509::X509NameBuilder::new().unwrap(); /// x509_name.append_entry_by_text("C", "US").unwrap(); /// x509_name.append_entry_by_text("ST", "CA").unwrap(); /// x509_name.append_entry_by_text("O", "Some organization").unwrap(); /// x509_name.append_entry_by_text("CN", "www.example.com").unwrap(); /// let x509_name = x509_name.build(); /// /// let mut x509 = openssl::x509::X509::builder().unwrap(); /// x509.set_subject_name(&x509_name).unwrap(); /// ``` pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_subject_name( self.0.as_ptr(), subject_name.as_ptr(), )) .map(|_| ()) } } /// Sets the public key associated with the certificate. pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, { unsafe { cvt(ffi::X509_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } } /// Returns a context object which is needed to create certain X509 extension values. /// /// Set `issuer` to `None` if the certificate will be self-signed. pub fn x509v3_context<'a>( &'a self, issuer: Option<&'a X509Ref>, conf: Option<&'a ConfRef>, ) -> X509v3Context<'a> { unsafe { let mut ctx = mem::zeroed(); let issuer = match issuer { Some(issuer) => issuer.as_ptr(), None => self.0.as_ptr(), }; let subject = self.0.as_ptr(); ffi::X509V3_set_ctx( &mut ctx, issuer, subject, ptr::null_mut(), ptr::null_mut(), 0, ); // nodb case taken care of since we zeroed ctx above if let Some(conf) = conf { ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); } X509v3Context(ctx, PhantomData) } } /// Adds an X509 extension value to the certificate. pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; mem::forget(extension); Ok(()) } } /// Signs the certificate with a private key. pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate, { unsafe { cvt(ffi::X509_sign(self.0.as_ptr(), key.as_ptr(), hash.as_ptr())).map(|_| ()) } } /// Consumes the builder, returning the certificate. pub fn build(self) -> X509 { self.0 } } foreign_type_and_impl_send_sync! { type CType = ffi::X509; fn drop = ffi::X509_free; /// An `X509` public key certificate. pub struct X509; /// Reference to `X509`. pub struct X509Ref; } impl X509Ref { /// Returns this certificate's subject name. /// /// This corresponds to [`X509_get_subject_name`]. /// /// [`X509_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = ffi::X509_get_subject_name(self.as_ptr()); assert!(!name.is_null()); X509NameRef::from_ptr(name) } } /// Returns this certificate's issuer name. /// /// This corresponds to [`X509_get_issuer_name`]. /// /// [`X509_get_issuer_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_subject_name.html pub fn issuer_name(&self) -> &X509NameRef { unsafe { let name = ffi::X509_get_issuer_name(self.as_ptr()); assert!(!name.is_null()); X509NameRef::from_ptr(name) } } /// Returns this certificate's subject alternative name entries, if they exist. /// /// This corresponds to [`X509_get_ext_d2i`] called with `NID_subject_alt_name`. /// /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html pub fn subject_alt_names(&self) -> Option> { unsafe { let stack = ffi::X509_get_ext_d2i( self.as_ptr(), ffi::NID_subject_alt_name, ptr::null_mut(), ptr::null_mut(), ); if stack.is_null() { None } else { Some(Stack::from_ptr(stack as *mut _)) } } } /// Returns this certificate's issuer alternative name entries, if they exist. /// /// This corresponds to [`X509_get_ext_d2i`] called with `NID_issuer_alt_name`. /// /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html pub fn issuer_alt_names(&self) -> Option> { unsafe { let stack = ffi::X509_get_ext_d2i( self.as_ptr(), ffi::NID_issuer_alt_name, ptr::null_mut(), ptr::null_mut(), ); if stack.is_null() { None } else { Some(Stack::from_ptr(stack as *mut _)) } } } pub fn public_key(&self) -> Result, ErrorStack> { unsafe { let pkey = cvt_p(ffi::X509_get_pubkey(self.as_ptr()))?; Ok(PKey::from_ptr(pkey)) } } /// Returns a digest of the DER representation of the certificate. /// /// This corresponds to [`X509_digest`]. /// /// [`X509_digest`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_digest.html pub fn digest(&self, hash_type: MessageDigest) -> Result { unsafe { let mut digest = DigestBytes { buf: [0; ffi::EVP_MAX_MD_SIZE as usize], len: ffi::EVP_MAX_MD_SIZE as usize, }; let mut len = ffi::EVP_MAX_MD_SIZE; cvt(ffi::X509_digest( self.as_ptr(), hash_type.as_ptr(), digest.buf.as_mut_ptr() as *mut _, &mut len, ))?; digest.len = len as usize; Ok(digest) } } #[deprecated(since = "0.10.9", note = "renamed to digest")] pub fn fingerprint(&self, hash_type: MessageDigest) -> Result, ErrorStack> { self.digest(hash_type).map(|b| b.to_vec()) } /// Returns the certificate's Not After validity period. pub fn not_after(&self) -> &Asn1TimeRef { unsafe { let date = X509_getm_notAfter(self.as_ptr()); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date) } } /// Returns the certificate's Not Before validity period. pub fn not_before(&self) -> &Asn1TimeRef { unsafe { let date = X509_getm_notBefore(self.as_ptr()); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date) } } /// Returns the certificate's signature pub fn signature(&self) -> &Asn1BitStringRef { unsafe { let mut signature = ptr::null(); X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); assert!(!signature.is_null()); Asn1BitStringRef::from_ptr(signature as *mut _) } } /// Returns the certificate's signature algorithm. pub fn signature_algorithm(&self) -> &X509AlgorithmRef { unsafe { let mut algor = ptr::null(); X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); assert!(!algor.is_null()); X509AlgorithmRef::from_ptr(algor as *mut _) } } /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information /// Access field. pub fn ocsp_responders(&self) -> Result, ErrorStack> { unsafe { cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) } } /// Checks that this certificate issued `subject`. pub fn issued(&self, subject: &X509Ref) -> X509VerifyResult { unsafe { let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr()); X509VerifyResult::from_raw(r) } } /// 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`]. /// /// [`X509_get_serialNumber`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_serialNumber.html pub fn serial_number(&self) -> &Asn1IntegerRef { unsafe { let r = ffi::X509_get_serialNumber(self.as_ptr()); assert!(!r.is_null()); Asn1IntegerRef::from_ptr(r) } } to_pem! { /// Serializes the certificate into a PEM-encoded X509 structure. /// /// The output will have a header of `-----BEGIN CERTIFICATE-----`. /// /// This corresponds to [`PEM_write_bio_X509`]. /// /// [`PEM_write_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509.html to_pem, ffi::PEM_write_bio_X509 } to_der! { /// Serializes the certificate into a DER-encoded X509 structure. /// /// This corresponds to [`i2d_X509`]. /// /// [`i2d_X509`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_X509.html to_der, ffi::i2d_X509 } } impl ToOwned for X509Ref { type Owned = X509; fn to_owned(&self) -> X509 { unsafe { X509_up_ref(self.as_ptr()); X509::from_ptr(self.as_ptr()) } } } impl X509 { /// Returns a new builder. pub fn builder() -> Result { X509Builder::new() } from_pem! { /// Deserializes a PEM-encoded X509 structure. /// /// The input should have a header of `-----BEGIN CERTIFICATE-----`. /// /// This corresponds to [`PEM_read_bio_X509`]. /// /// [`PEM_read_bio_X509`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509.html from_pem, X509, ffi::PEM_read_bio_X509 } from_der! { /// Deserializes a DER-encoded X509 structure. /// /// This corresponds to [`d2i_X509`]. /// /// [`d2i_X509`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509.html from_der, X509, ffi::d2i_X509 } /// Deserializes a list of PEM-formatted certificates. pub fn stack_from_pem(pem: &[u8]) -> Result, ErrorStack> { unsafe { ffi::init(); let bio = MemBioSlice::new(pem)?; let mut certs = vec![]; loop { let r = ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut()); if r.is_null() { let err = ffi::ERR_peek_last_error(); if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE { ffi::ERR_clear_error(); break; } return Err(ErrorStack::get()); } else { certs.push(X509(r)); } } Ok(certs) } } } impl Clone for X509 { fn clone(&self) -> X509 { X509Ref::to_owned(self) } } impl AsRef for X509Ref { fn as_ref(&self) -> &X509Ref { self } } impl Stackable for X509 { type StackType = ffi::stack_st_X509; } /// A context object required to construct certain `X509` extension values. pub struct X509v3Context<'a>(ffi::X509V3_CTX, PhantomData<(&'a X509Ref, &'a ConfRef)>); impl<'a> X509v3Context<'a> { pub fn as_ptr(&self) -> *mut ffi::X509V3_CTX { &self.0 as *const _ as *mut _ } } foreign_type_and_impl_send_sync! { type CType = ffi::X509_EXTENSION; fn drop = ffi::X509_EXTENSION_free; /// Permit additional fields to be added to an `X509` v3 certificate. pub struct X509Extension; /// Reference to `X509Extension`. pub struct X509ExtensionRef; } impl Stackable for X509Extension { type StackType = ffi::stack_st_X509_EXTENSION; } impl X509Extension { /// Constructs an X509 extension value. See `man x509v3_config` for information on supported /// names and their value formats. /// /// Some extension types, such as `subjectAlternativeName`, require an `X509v3Context` to be /// provided. /// /// See the extension module for builder types which will construct certain common extensions. pub fn new( conf: Option<&ConfRef>, context: Option<&X509v3Context>, name: &str, value: &str, ) -> Result { let name = CString::new(name).unwrap(); let value = CString::new(value).unwrap(); unsafe { ffi::init(); let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); let name = name.as_ptr() as *mut _; let value = value.as_ptr() as *mut _; cvt_p(ffi::X509V3_EXT_nconf(conf, context, name, value)).map(X509Extension) } } /// Constructs an X509 extension value. See `man x509v3_config` for information on supported /// extensions and their value formats. /// /// Some extension types, such as `nid::SUBJECT_ALTERNATIVE_NAME`, require an `X509v3Context` to /// be provided. /// /// See the extension module for builder types which will construct certain common extensions. pub fn new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context>, name: Nid, value: &str, ) -> Result { let value = CString::new(value).unwrap(); unsafe { ffi::init(); let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); let context = context.map_or(ptr::null_mut(), X509v3Context::as_ptr); let name = name.as_raw(); let value = value.as_ptr() as *mut _; cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context, name, value)).map(X509Extension) } } } /// A builder used to construct an `X509Name`. pub struct X509NameBuilder(X509Name); impl X509NameBuilder { /// Creates a new builder. pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::X509_NAME_new()).map(|p| X509NameBuilder(X509Name(p))) } } /// Add a field entry by str. /// /// This corresponds to [`X509_NAME_add_entry_by_txt`]. /// /// [`X509_NAME_add_entry_by_txt`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_txt.html pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { unsafe { let field = CString::new(field).unwrap(); assert!(value.len() <= c_int::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_txt( self.0.as_ptr(), field.as_ptr() as *mut _, ffi::MBSTRING_UTF8, value.as_ptr(), value.len() as c_int, -1, 0, )) .map(|_| ()) } } /// Add a field entry by NID. /// /// This corresponds to [`X509_NAME_add_entry_by_NID`]. /// /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_add_entry_by_NID.html pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { unsafe { assert!(value.len() <= c_int::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_NID( self.0.as_ptr(), field.as_raw(), ffi::MBSTRING_UTF8, value.as_ptr() as *mut _, value.len() as c_int, -1, 0, )) .map(|_| ()) } } /// Return an `X509Name`. pub fn build(self) -> X509Name { self.0 } } foreign_type_and_impl_send_sync! { type CType = ffi::X509_NAME; fn drop = ffi::X509_NAME_free; /// The names of an `X509` certificate. pub struct X509Name; /// Reference to `X509Name`. pub struct X509NameRef; } impl X509Name { /// Returns a new builder. pub fn builder() -> Result { X509NameBuilder::new() } /// Loads subject names from a file containing PEM-formatted certificates. /// /// This is commonly used in conjunction with `SslContextBuilder::set_client_ca_list`. pub fn load_client_ca_file>(file: P) -> Result, ErrorStack> { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { cvt_p(ffi::SSL_load_client_CA_file(file.as_ptr())).map(|p| Stack::from_ptr(p)) } } } impl Stackable for X509Name { type StackType = ffi::stack_st_X509_NAME; } impl X509NameRef { /// Returns the name entries by the nid. pub fn entries_by_nid<'a>(&'a self, nid: Nid) -> X509NameEntries<'a> { X509NameEntries { name: self, nid: Some(nid), loc: -1, } } /// Returns an iterator over all `X509NameEntry` values pub fn entries<'a>(&'a self) -> X509NameEntries<'a> { X509NameEntries { name: self, nid: None, loc: -1, } } } /// A type to destructure and examine an `X509Name`. pub struct X509NameEntries<'a> { name: &'a X509NameRef, nid: Option, loc: c_int, } impl<'a> Iterator for X509NameEntries<'a> { type Item = &'a X509NameEntryRef; fn next(&mut self) -> Option<&'a X509NameEntryRef> { unsafe { match self.nid { Some(nid) => { // There is a `Nid` specified to search for self.loc = ffi::X509_NAME_get_index_by_NID(self.name.as_ptr(), nid.as_raw(), self.loc); if self.loc == -1 { return None; } } None => { // Iterate over all `Nid`s self.loc += 1; if self.loc >= ffi::X509_NAME_entry_count(self.name.as_ptr()) { return None; } } } let entry = ffi::X509_NAME_get_entry(self.name.as_ptr(), self.loc); assert!(!entry.is_null()); Some(X509NameEntryRef::from_ptr(entry)) } } } foreign_type_and_impl_send_sync! { type CType = ffi::X509_NAME_ENTRY; fn drop = ffi::X509_NAME_ENTRY_free; /// A name entry associated with a `X509Name`. pub struct X509NameEntry; /// Reference to `X509NameEntry`. pub struct X509NameEntryRef; } impl X509NameEntryRef { /// Returns the field value of an `X509NameEntry`. /// /// This corresponds to [`X509_NAME_ENTRY_get_data`]. /// /// [`X509_NAME_ENTRY_get_data`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_data.html pub fn data(&self) -> &Asn1StringRef { unsafe { let data = ffi::X509_NAME_ENTRY_get_data(self.as_ptr()); Asn1StringRef::from_ptr(data) } } /// Returns the `Asn1Object` value of an `X509NameEntry`. /// This is useful for finding out about the actual `Nid` when iterating over all `X509NameEntries`. /// /// This corresponds to [`X509_NAME_ENTRY_get_object`]. /// /// [`X509_NAME_ENTRY_get_object`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_NAME_ENTRY_get_object.html pub fn object(&self) -> &Asn1ObjectRef { unsafe { let object = ffi::X509_NAME_ENTRY_get_object(self.as_ptr()); Asn1ObjectRef::from_ptr(object) } } } /// A builder used to construct an `X509Req`. pub struct X509ReqBuilder(X509Req); impl X509ReqBuilder { /// Returns a builder for a certificate request. /// /// This corresponds to [`X509_REQ_new`]. /// ///[`X509_REQ_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_new.html pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::X509_REQ_new()).map(|p| X509ReqBuilder(X509Req(p))) } } /// Set the numerical value of the version field. /// /// This corresponds to [`X509_REQ_set_version`]. /// ///[`X509_REQ_set_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_version.html pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_version(self.0.as_ptr(), version.into())).map(|_| ()) } } /// Set the issuer name. /// /// This corresponds to [`X509_REQ_set_subject_name`]. /// /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_subject_name.html pub fn set_subject_name(&mut self, subject_name: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_subject_name( self.0.as_ptr(), subject_name.as_ptr(), )) .map(|_| ()) } } /// Set the public key. /// /// This corresponds to [`X509_REQ_set_pubkey`]. /// /// [`X509_REQ_set_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_set_pubkey.html pub fn set_pubkey(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, { unsafe { cvt(ffi::X509_REQ_set_pubkey(self.0.as_ptr(), key.as_ptr())).map(|_| ()) } } /// Return an `X509v3Context`. This context object can be used to construct /// certain `X509` extensions. pub fn x509v3_context<'a>(&'a self, conf: Option<&'a ConfRef>) -> X509v3Context<'a> { unsafe { let mut ctx = mem::zeroed(); ffi::X509V3_set_ctx( &mut ctx, ptr::null_mut(), ptr::null_mut(), self.0.as_ptr(), ptr::null_mut(), 0, ); // nodb case taken care of since we zeroed ctx above if let Some(conf) = conf { ffi::X509V3_set_nconf(&mut ctx, conf.as_ptr()); } X509v3Context(ctx, PhantomData) } } /// Permits any number of extension fields to be added to the certificate. pub fn add_extensions( &mut self, extensions: &StackRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_add_extensions( self.0.as_ptr(), extensions.as_ptr(), )) .map(|_| ()) } } /// Sign the request using a private key. /// /// This corresponds to [`X509_REQ_sign`]. /// /// [`X509_REQ_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_sign.html pub fn sign(&mut self, key: &PKeyRef, hash: MessageDigest) -> Result<(), ErrorStack> where T: HasPrivate, { unsafe { cvt(ffi::X509_REQ_sign( self.0.as_ptr(), key.as_ptr(), hash.as_ptr(), )) .map(|_| ()) } } /// Returns the `X509Req`. pub fn build(self) -> X509Req { self.0 } } foreign_type_and_impl_send_sync! { type CType = ffi::X509_REQ; fn drop = ffi::X509_REQ_free; /// An `X509` certificate request. pub struct X509Req; /// Reference to `X509Req`. pub struct X509ReqRef; } impl X509Req { /// A builder for `X509Req`. pub fn builder() -> Result { X509ReqBuilder::new() } from_pem! { /// Deserializes a PEM-encoded PKCS#10 certificate request structure. /// /// The input should have a header of `-----BEGIN CERTIFICATE REQUEST-----`. /// /// This corresponds to [`PEM_read_bio_X509_REQ`]. /// /// [`PEM_read_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_read_bio_X509_REQ.html from_pem, X509Req, ffi::PEM_read_bio_X509_REQ } from_der! { /// Deserializes a DER-encoded PKCS#10 certificate request structure. /// /// This corresponds to [`d2i_X509_REQ`]. /// /// [`d2i_X509_REQ`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_X509_REQ.html from_der, X509Req, ffi::d2i_X509_REQ } } impl X509ReqRef { to_pem! { /// Serializes the certificate request to a PEM-encoded PKCS#10 structure. /// /// The output will have a header of `-----BEGIN CERTIFICATE REQUEST-----`. /// /// This corresponds to [`PEM_write_bio_X509_REQ`]. /// /// [`PEM_write_bio_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/PEM_write_bio_X509_REQ.html to_pem, ffi::PEM_write_bio_X509_REQ } to_der! { /// Serializes the certificate request to a DER-encoded PKCS#10 structure. /// /// This corresponds to [`i2d_X509_REQ`]. /// /// [`i2d_X509_REQ`]: https://www.openssl.org/docs/man1.0.2/crypto/i2d_X509_REQ.html to_der, ffi::i2d_X509_REQ } /// Returns the numerical value of the version field of the certificate request. /// /// This corresponds to [`X509_REQ_get_version`] /// /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html pub fn version(&self) -> i32 { unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } } /// Returns the subject name of the certificate request. /// /// This corresponds to [`X509_REQ_get_subject_name`] /// /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = X509_REQ_get_subject_name(self.as_ptr()); assert!(!name.is_null()); X509NameRef::from_ptr(name) } } /// Returns the public key of the certificate request. /// /// This corresponds to [`X509_REQ_get_pubkey"] /// /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html pub fn public_key(&self) -> Result, ErrorStack> { unsafe { let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?; Ok(PKey::from_ptr(key)) } } /// 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"] pub fn extensions(&self) -> Result, ErrorStack> { unsafe { let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?; Ok(Stack::from_ptr(extensions)) } } } /// The result of peer certificate verification. #[derive(Copy, Clone, PartialEq, Eq)] pub struct X509VerifyResult(c_int); impl fmt::Debug for X509VerifyResult { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("X509VerifyResult") .field("code", &self.0) .field("error", &self.error_string()) .finish() } } impl fmt::Display for X509VerifyResult { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.write_str(self.error_string()) } } impl Error for X509VerifyResult { fn description(&self) -> &str { "an X509 validation error" } } impl X509VerifyResult { /// Creates an `X509VerifyResult` from a raw error number. /// /// # Safety /// /// Some methods on `X509VerifyResult` are not thread safe if the error /// number is invalid. pub unsafe fn from_raw(err: c_int) -> X509VerifyResult { X509VerifyResult(err) } /// Return the integer representation of an `X509VerifyResult`. pub fn as_raw(&self) -> c_int { self.0 } /// Return a human readable error string from the verification error. /// /// This corresponds to [`X509_verify_cert_error_string`]. /// /// [`X509_verify_cert_error_string`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_verify_cert_error_string.html pub fn error_string(&self) -> &'static str { ffi::init(); unsafe { let s = ffi::X509_verify_cert_error_string(self.0 as c_long); str::from_utf8(CStr::from_ptr(s).to_bytes()).unwrap() } } /// Successful peer certifiate verification. pub const OK: X509VerifyResult = X509VerifyResult(ffi::X509_V_OK); /// Application verification failure. pub const APPLICATION_VERIFICATION: X509VerifyResult = X509VerifyResult(ffi::X509_V_ERR_APPLICATION_VERIFICATION); } foreign_type_and_impl_send_sync! { type CType = ffi::GENERAL_NAME; fn drop = ffi::GENERAL_NAME_free; /// An `X509` certificate alternative names. pub struct GeneralName; /// Reference to `GeneralName`. pub struct GeneralNameRef; } impl GeneralNameRef { fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { unsafe { if (*self.as_ptr()).type_ != ffi_type { return None; } let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); // IA5Strings are stated to be ASCII (specifically IA5). Hopefully // OpenSSL checks that when loading a certificate but if not we'll // use this instead of from_utf8_unchecked just in case. str::from_utf8(slice).ok() } } /// Returns the contents of this `GeneralName` if it is an `rfc822Name`. pub fn email(&self) -> Option<&str> { self.ia5_string(ffi::GEN_EMAIL) } /// Returns the contents of this `GeneralName` if it is a `dNSName`. pub fn dnsname(&self) -> Option<&str> { self.ia5_string(ffi::GEN_DNS) } /// Returns the contents of this `GeneralName` if it is an `uniformResourceIdentifier`. pub fn uri(&self) -> Option<&str> { self.ia5_string(ffi::GEN_URI) } /// Returns the contents of this `GeneralName` if it is an `iPAddress`. pub fn ipaddress(&self) -> Option<&[u8]> { unsafe { if (*self.as_ptr()).type_ != ffi::GEN_IPADD { return None; } let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) } } } impl Stackable for GeneralName { type StackType = ffi::stack_st_GENERAL_NAME; } foreign_type_and_impl_send_sync! { type CType = ffi::X509_ALGOR; fn drop = ffi::X509_ALGOR_free; /// An `X509` certificate signature algorithm. pub struct X509Algorithm; /// Reference to `X509Algorithm`. pub struct X509AlgorithmRef; } impl X509AlgorithmRef { /// Returns the ASN.1 OID of this algorithm. pub fn object(&self) -> &Asn1ObjectRef { unsafe { let mut oid = ptr::null(); X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); assert!(!oid.is_null()); Asn1ObjectRef::from_ptr(oid as *mut _) } } } cfg_if! { if #[cfg(any(ossl110, libressl273))] { use ffi::{X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, X509_get0_signature}; } else { #[allow(bad_style)] unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { (*(*(*x).cert_info).validity).notAfter } #[allow(bad_style)] unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { (*(*(*x).cert_info).validity).notBefore } #[allow(bad_style)] unsafe fn X509_up_ref(x: *mut ffi::X509) { ffi::CRYPTO_add_lock( &mut (*x).references, 1, ffi::CRYPTO_LOCK_X509, "mod.rs\0".as_ptr() as *const _, line!() as c_int, ); } #[allow(bad_style)] unsafe fn X509_get0_signature( psig: *mut *const ffi::ASN1_BIT_STRING, palg: *mut *const ffi::X509_ALGOR, x: *const ffi::X509, ) { if !psig.is_null() { *psig = (*x).signature; } if !palg.is_null() { *palg = (*x).sig_alg; } } } } cfg_if! { if #[cfg(ossl110)] { use ffi::{ X509_ALGOR_get0, ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter, X509_set1_notBefore, X509_REQ_get_version, X509_REQ_get_subject_name, }; } else { use ffi::{ ASN1_STRING_data as ASN1_STRING_get0_data, X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, X509_set_notAfter as X509_set1_notAfter, X509_set_notBefore as X509_set1_notBefore, }; #[allow(bad_style)] unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { ffi::ASN1_INTEGER_get((*(*x).req_info).version) } #[allow(bad_style)] unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { (*(*x).req_info).subject } #[allow(bad_style)] unsafe fn X509_ALGOR_get0( paobj: *mut *const ffi::ASN1_OBJECT, pptype: *mut c_int, pval: *mut *mut ::libc::c_void, alg: *const ffi::X509_ALGOR, ) { if !paobj.is_null() { *paobj = (*alg).algorithm; } assert!(pptype.is_null()); assert!(pval.is_null()); } } } openssl-0.10.23/src/x509/store.rs010064400017500001750000000060311346222217000145560ustar0000000000000000//! Describe a context in which to verify an `X509` certificate. //! //! The `X509` certificate store holds trusted CA certificates used to verify //! peer certificates. //! //! # Example //! //! ```rust //! //! extern crate openssl; //! //! use openssl::x509::store::{X509StoreBuilder, X509Store}; //! use openssl::x509::{X509, X509Name}; //! use openssl::pkey::PKey; //! use openssl::hash::MessageDigest; //! use openssl::rsa::Rsa; //! use openssl::nid::Nid; //! //! fn main() { //! let rsa = Rsa::generate(2048).unwrap(); //! let pkey = PKey::from_rsa(rsa).unwrap(); //! //! let mut name = X509Name::builder().unwrap(); //! name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap(); //! let name = name.build(); //! //! let mut builder = X509::builder().unwrap(); //! builder.set_version(2).unwrap(); //! builder.set_subject_name(&name).unwrap(); //! builder.set_issuer_name(&name).unwrap(); //! builder.set_pubkey(&pkey).unwrap(); //! builder.sign(&pkey, MessageDigest::sha256()).unwrap(); //! //! let certificate: X509 = builder.build(); //! //! let mut builder = X509StoreBuilder::new().unwrap(); //! let _ = builder.add_cert(certificate); //! //! let store: X509Store = builder.build(); //! } //! ``` use ffi; use foreign_types::ForeignTypeRef; use std::mem; use error::ErrorStack; use x509::X509; use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; fn drop = ffi::X509_STORE_free; /// A builder type used to construct an `X509Store`. pub struct X509StoreBuilder; /// Reference to an `X509StoreBuilder`. pub struct X509StoreBuilderRef; } impl X509StoreBuilder { /// Returns a builder for a certificate store. /// /// The store is initially empty. pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::X509_STORE_new()).map(X509StoreBuilder) } } /// Constructs the `X509Store`. pub fn build(self) -> X509Store { let store = X509Store(self.0); mem::forget(self); store } } impl X509StoreBuilderRef { /// Adds a certificate to the certificate store. // FIXME should take an &X509Ref pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } /// Load certificates from their default locations. /// /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` /// environment variables if present, or defaults specified at OpenSSL /// build time otherwise. pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) } } } foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; fn drop = ffi::X509_STORE_free; /// A certificate store to hold trusted `X509` certificates. pub struct X509Store; /// Reference to an `X509Store`. pub struct X509StoreRef; } openssl-0.10.23/src/x509/tests.rs010064400017500001750000000274201346222217000145710ustar0000000000000000use hex::{self, FromHex}; use asn1::Asn1Time; use bn::{BigNum, MsbOption}; use hash::MessageDigest; use nid::Nid; use pkey::{PKey, Private}; use rsa::Rsa; use stack::Stack; use x509::extension::{ AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier, }; use x509::store::X509StoreBuilder; use x509::{X509Name, X509Req, X509StoreContext, X509VerifyResult, X509}; fn pkey() -> PKey { let rsa = Rsa::generate(2048).unwrap(); PKey::from_rsa(rsa).unwrap() } #[test] fn test_cert_loading() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; let hash_vec = Vec::from_hex(hash_str).unwrap(); assert_eq!(hash_vec, &*fingerprint); } #[test] fn test_cert_issue_validity() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let not_before = cert.not_before().to_string(); let not_after = cert.not_after().to_string(); assert_eq!(not_before, "Aug 14 17:00:03 2016 GMT"); assert_eq!(not_after, "Aug 12 17:00:03 2026 GMT"); } #[test] fn test_save_der() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let der = cert.to_der().unwrap(); assert!(!der.is_empty()); } #[test] fn test_subject_read_cn() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap(); assert_eq!(cn.data().as_slice(), b"foobar.com") } #[test] fn test_nid_values() { let cert = include_bytes!("../../test/nid_test_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = subject.entries_by_nid(Nid::COMMONNAME).next().unwrap(); assert_eq!(cn.data().as_slice(), b"example.com"); let email = subject .entries_by_nid(Nid::PKCS9_EMAILADDRESS) .next() .unwrap(); assert_eq!(email.data().as_slice(), b"test@example.com"); let friendly = subject.entries_by_nid(Nid::FRIENDLYNAME).next().unwrap(); assert_eq!(&**friendly.data().as_utf8().unwrap(), "Example"); } #[test] fn test_nameref_iterator() { let cert = include_bytes!("../../test/nid_test_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); 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.data().as_slice(), b"test@example.com"); let cn = all_entries.next().unwrap(); assert_eq!(cn.object().nid().as_raw(), Nid::COMMONNAME.as_raw()); assert_eq!(cn.data().as_slice(), b"example.com"); let friendly = all_entries.next().unwrap(); assert_eq!(friendly.object().nid().as_raw(), Nid::FRIENDLYNAME.as_raw()); assert_eq!(&**friendly.data().as_utf8().unwrap(), "Example"); if let Some(_) = all_entries.next() { assert!(false); } } #[test] fn test_nid_uid_value() { let cert = include_bytes!("../../test/nid_uid_test_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let cn = subject.entries_by_nid(Nid::USERID).next().unwrap(); assert_eq!(cn.data().as_slice(), b"this is the userId"); } #[test] fn test_subject_alt_name() { let cert = include_bytes!("../../test/alt_name_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject_alt_names = cert.subject_alt_names().unwrap(); assert_eq!(5, subject_alt_names.len()); assert_eq!(Some("example.com"), subject_alt_names[0].dnsname()); assert_eq!(subject_alt_names[1].ipaddress(), Some(&[127, 0, 0, 1][..])); assert_eq!( subject_alt_names[2].ipaddress(), Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]) ); assert_eq!(Some("test@example.com"), subject_alt_names[3].email()); assert_eq!(Some("http://www.example.com"), subject_alt_names[4].uri()); } #[test] fn test_subject_alt_name_iter() { let cert = include_bytes!("../../test/alt_name_cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); let subject_alt_names = cert.subject_alt_names().unwrap(); let mut subject_alt_names_iter = subject_alt_names.iter(); assert_eq!( subject_alt_names_iter.next().unwrap().dnsname(), Some("example.com") ); assert_eq!( subject_alt_names_iter.next().unwrap().ipaddress(), Some(&[127, 0, 0, 1][..]) ); assert_eq!( subject_alt_names_iter.next().unwrap().ipaddress(), Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..]) ); assert_eq!( subject_alt_names_iter.next().unwrap().email(), Some("test@example.com") ); assert_eq!( subject_alt_names_iter.next().unwrap().uri(), Some("http://www.example.com") ); assert!(subject_alt_names_iter.next().is_none()); } #[test] fn x509_builder() { let pkey = pkey(); let mut name = X509Name::builder().unwrap(); name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com") .unwrap(); let name = name.build(); let mut builder = X509::builder().unwrap(); builder.set_version(2).unwrap(); builder.set_subject_name(&name).unwrap(); builder.set_issuer_name(&name).unwrap(); builder .set_not_before(&Asn1Time::days_from_now(0).unwrap()) .unwrap(); builder .set_not_after(&Asn1Time::days_from_now(365).unwrap()) .unwrap(); builder.set_pubkey(&pkey).unwrap(); let mut serial = BigNum::new().unwrap(); serial.rand(128, MsbOption::MAYBE_ZERO, false).unwrap(); builder .set_serial_number(&serial.to_asn1_integer().unwrap()) .unwrap(); let basic_constraints = BasicConstraints::new().critical().ca().build().unwrap(); builder.append_extension(basic_constraints).unwrap(); let key_usage = KeyUsage::new() .digital_signature() .key_encipherment() .build() .unwrap(); builder.append_extension(key_usage).unwrap(); let ext_key_usage = ExtendedKeyUsage::new() .client_auth() .server_auth() .other("2.999.1") .build() .unwrap(); builder.append_extension(ext_key_usage).unwrap(); let subject_key_identifier = SubjectKeyIdentifier::new() .build(&builder.x509v3_context(None, None)) .unwrap(); builder.append_extension(subject_key_identifier).unwrap(); let authority_key_identifier = AuthorityKeyIdentifier::new() .keyid(true) .build(&builder.x509v3_context(None, None)) .unwrap(); builder.append_extension(authority_key_identifier).unwrap(); let subject_alternative_name = SubjectAlternativeName::new() .dns("example.com") .build(&builder.x509v3_context(None, None)) .unwrap(); builder.append_extension(subject_alternative_name).unwrap(); builder.sign(&pkey, MessageDigest::sha256()).unwrap(); let x509 = builder.build(); assert!(pkey.public_eq(&x509.public_key().unwrap())); assert!(x509.verify(&pkey).unwrap()); let cn = x509 .subject_name() .entries_by_nid(Nid::COMMONNAME) .next() .unwrap(); assert_eq!("foobar.com".as_bytes(), cn.data().as_slice()); assert_eq!(serial, x509.serial_number().to_bn().unwrap()); } #[test] fn x509_req_builder() { let pkey = pkey(); let mut name = X509Name::builder().unwrap(); name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com") .unwrap(); let name = name.build(); let mut builder = X509Req::builder().unwrap(); builder.set_version(2).unwrap(); builder.set_subject_name(&name).unwrap(); builder.set_pubkey(&pkey).unwrap(); let mut extensions = Stack::new().unwrap(); let key_usage = KeyUsage::new() .digital_signature() .key_encipherment() .build() .unwrap(); extensions.push(key_usage).unwrap(); let subject_alternative_name = SubjectAlternativeName::new() .dns("example.com") .build(&builder.x509v3_context(None)) .unwrap(); extensions.push(subject_alternative_name).unwrap(); builder.add_extensions(&extensions).unwrap(); builder.sign(&pkey, MessageDigest::sha256()).unwrap(); 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] fn test_stack_from_pem() { let certs = include_bytes!("../../test/certs.pem"); let certs = X509::stack_from_pem(certs).unwrap(); assert_eq!(certs.len(), 2); assert_eq!( hex::encode(certs[0].digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); assert_eq!( hex::encode(certs[1].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } #[test] fn issued() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let ca = include_bytes!("../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); assert_eq!(ca.issued(&cert), X509VerifyResult::OK); assert_ne!(cert.issued(&cert), X509VerifyResult::OK); } #[test] fn signature() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let signature = cert.signature(); assert_eq!( hex::encode(signature.as_slice()), "4af607b889790b43470442cfa551cdb8b6d0b0340d2958f76b9e3ef6ad4992230cead6842587f0ecad5\ 78e6e11a221521e940187e3d6652de14e84e82f6671f097cc47932e022add3c0cb54a26bf27fa84c107\ 4971caa6bee2e42d34a5b066c427f2d452038082b8073993399548088429de034fdd589dcfb0dd33be7\ ebdfdf698a28d628a89568881d658151276bde333600969502c4e62e1d3470a683364dfb241f78d310a\ 89c119297df093eb36b7fd7540224f488806780305d1e79ffc938fe2275441726522ab36d88348e6c51\ f13dcc46b5e1cdac23c974fd5ef86aa41e91c9311655090a52333bc79687c748d833595d4c5f987508f\ e121997410d37c" ); let algorithm = cert.signature_algorithm(); assert_eq!(algorithm.object().nid(), Nid::SHA256WITHRSAENCRYPTION); assert_eq!(algorithm.object().to_string(), "sha256WithRSAEncryption"); } #[test] fn clone_x509() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); drop(cert.clone()); } #[test] fn test_verify_cert() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let ca = include_bytes!("../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); let chain = Stack::new().unwrap(); let mut store_bldr = X509StoreBuilder::new().unwrap(); store_bldr.add_cert(ca).unwrap(); 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()); } #[test] fn test_verify_fails() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let ca = include_bytes!("../../test/alt_name_cert.pem"); let ca = X509::from_pem(ca).unwrap(); let chain = Stack::new().unwrap(); let mut store_bldr = X509StoreBuilder::new().unwrap(); store_bldr.add_cert(ca).unwrap(); let store = store_bldr.build(); let mut context = X509StoreContext::new().unwrap(); assert!(!context .init(&store, &cert, &chain, |c| c.verify_cert()) .unwrap()); } openssl-0.10.23/src/x509/verify.rs010064400017500001750000000060001346222217000147220ustar0000000000000000use ffi; use foreign_types::ForeignTypeRef; use libc::c_uint; use std::net::IpAddr; use cvt; use error::ErrorStack; bitflags! { /// Flags used to check an `X509` certificate. pub struct X509CheckFlags: c_uint { const ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT; const NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS; const NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; const MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS; const SINGLE_LABEL_SUBDOMAINS = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS; /// Requires OpenSSL 1.1.0 or newer. #[cfg(any(ossl110))] const NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT; #[deprecated(since = "0.10.6", note = "renamed to NO_WILDCARDS")] const FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS; } } foreign_type_and_impl_send_sync! { type CType = ffi::X509_VERIFY_PARAM; fn drop = ffi::X509_VERIFY_PARAM_free; /// Adjust parameters associated with certificate verification. pub struct X509VerifyParam; /// Reference to `X509VerifyParam`. pub struct X509VerifyParamRef; } impl X509VerifyParamRef { /// Set the host flags. /// /// This corresponds to [`X509_VERIFY_PARAM_set_hostflags`]. /// /// [`X509_VERIFY_PARAM_set_hostflags`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_VERIFY_PARAM_set_hostflags.html pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) { unsafe { ffi::X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags.bits); } } /// Set the expected DNS hostname. /// /// This corresponds to [`X509_VERIFY_PARAM_set1_host`]. /// /// [`X509_VERIFY_PARAM_set1_host`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_VERIFY_PARAM_set1_host.html pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_VERIFY_PARAM_set1_host( self.as_ptr(), host.as_ptr() as *const _, host.len(), )) .map(|_| ()) } } /// Set the expected IPv4 or IPv6 address. /// /// This corresponds to [`X509_VERIFY_PARAM_set1_ip`]. /// /// [`X509_VERIFY_PARAM_set1_ip`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_VERIFY_PARAM_set1_ip.html pub fn set_ip(&mut self, ip: IpAddr) -> Result<(), ErrorStack> { unsafe { let mut buf = [0; 16]; let len = match ip { IpAddr::V4(addr) => { buf[..4].copy_from_slice(&addr.octets()); 4 } IpAddr::V6(addr) => { buf.copy_from_slice(&addr.octets()); 16 } }; cvt(ffi::X509_VERIFY_PARAM_set1_ip( self.as_ptr(), buf.as_ptr() as *const _, len, )) .map(|_| ()) } } } openssl-0.10.23/test/alt_name_cert.pem010064400017500001750000000024721346222217000160440ustar0000000000000000-----BEGIN CERTIFICATE----- MIIDsDCCApigAwIBAgIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJBVTET MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ dHkgTHRkMB4XDTE4MDExNTExMDcwM1oXDTI4MDExMzExMDcwM1owfDELMAkGA1UE BhMCVVMxCzAJBgNVBAgMAk5ZMREwDwYDVQQHDAhOZXcgWW9yazEVMBMGA1UECgwM RXhhbXBsZSwgTExDMTYwNAYDVQQDDC1FeGFtcGxlIENvbXBhbnkvZW1haWxBZGRy ZXNzPXRlc3RAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK AoIBAQCo9CWMRLMXo1CF/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErpl xfLkt0pJqcoiZG8g9NU0kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10 uSDk6V9aJSX1vKwONVNSwiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1V fOugka7UktYnk9mrBbAMjmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1G bN4AtDuhs252eqE9E4iTHk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U 3KTfhO/mTlAUWVyg9tCtOzboKgs1AgMBAAGjdDByMAkGA1UdEwQCMAAwCwYDVR0P BAQDAgWgMFgGA1UdEQRRME+CC2V4YW1wbGUuY29thwR/AAABhxAAAAAAAAAAAAAA AAAAAAABgRB0ZXN0QGV4YW1wbGUuY29thhZodHRwOi8vd3d3LmV4YW1wbGUuY29t MA0GCSqGSIb3DQEBCwUAA4IBAQAx14G99z/MnSbs8h5jSos+dgLvhc2IQB/3CChE hPyELc7iyw1iteRs7bS1m2NZx6gv6TZ6VydDrK1dnWSatQ7sskXTO+zfC6qjMwXl IV+u7T8EREwciniIA82d8GWs60BGyBL3zp2iUOr5ULG4+c/S6OLdlyJv+fDKv+Xo fKv1UGDi5rcvUBikeNkpEPTN9UsE9/A8XJfDyq+4RKuDW19EtzOOeVx4xpHOMnAy VVAQVMKJzhoXtLF4k2j409na+f6FIcZSBet+plmzfB+WZNIgUUi/7MQIXOFQRkj4 zH3SnsPm/IYpJzlH2vHhlqIBdaSoTWpGVWPq7D+H8OS3mmXF -----END CERTIFICATE----- openssl-0.10.23/test/cert.pem010064400017500001750000000021631346222217000142010ustar0000000000000000-----BEGIN CERTIFICATE----- MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub 3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM 6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== -----END CERTIFICATE----- openssl-0.10.23/test/certs.pem010064400017500001750000000045001346222217000143610ustar0000000000000000-----BEGIN CERTIFICATE----- MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub 3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM 6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr 7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92 aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3 AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3 mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9 GA== -----END CERTIFICATE----- openssl-0.10.23/test/cms.p12010064400017500001750000000032551346222217000136520ustar000000000000000000o *H `\0X0W *H H0D0= *H 0 *H  0:-`"0ux YP N,7~[,Dm#VhQ3\DEχ=!*Z UQƳM(ZoUIJKc/uC?`^z0Y?[I bleW'i6ON:k1>db6,j5qS Zx=4Ml+lդߡh9oQ3&5 wIH8HKN~˘Ƞ^Es=D')a#4A~]R&fIߝ %**#td#󄝪"W.d`nnSy]N{GaеkW6ar=~q)vznOfaaf3ԕdכCsp=a-b_IWoW EE_Z2g _ HɸBgeݼǒ%;D T+/S쎑Tu!?}^4<VԊIі6m1 ~Ǚ1N)_03Z 5ٽlЍgl**Qeبj.Ei5 0w'a"VmteQ``0n&}S'lDeUpLwkLV}_^hS".H[Qfi-I/T(0 *H 00 *H  00 *H  0q6C>+9SgJ}0Up- TI7ٟ{ln ua`VPy[J:(Lsqv*/ ds%v9h9*hjıiPJ7Xlɂj*" DlfȲd$ m<5"tN@+ԋ?IͳU@*=I@yjK7qɔT Qy^Zi ᚖIK^ Ôzl'Djߍ'Wh y.G%QX\5Wx ǩWyI 3:BU Q2Gx9T~a j)I,uK"_NA=!B~ %/>2llCnivya0.COFn'Ub n/sȗWE&qwX<=Xqy"c.Hfۏ^i,:k4}\OeԛX';yT(DDuk]T6n^nD'Yj(;$v"|-~7N!o]F J~:PG!xRގ/Byb@=O7{Oф'{]#2,:E1%0# *H  15VR)a`pҏ010!0 +TѰCJ,QOXe̡Jopenssl-0.10.23/test/cms_pubkey.der010064400017500001750000000012601346222217000153730ustar000000000000000000rV!_ /ǴNB0  *H  0g1 0 UUS10U Some-State10U openssl-rust10U openssl-rust10U openssl-rust0  190123211015Z22921106211015Z0g1 0 UUS10U Some-State10U openssl-rust10U openssl-rust10U openssl-rust00  *H 0SJyf1})O`NaѬײځZ.fj=X'i(WzE[YUqLOO٦JQX JAzk}"yS0Q0U=m?Զ?Ic!0U#0=m?Զ?Ic!0U00  *H  Mvʇ^{=iN~~.Sjr&$lT,% oXힶ"H$C:M.M;I[MRH̦a"te&E:e29QAU@LTPkopenssl-0.10.23/test/dhparams.pem010064400017500001750000000006501346222217000150420ustar0000000000000000-----BEGIN DH PARAMETERS----- MIIBCAKCAQEAh3Betv+hf5jNsOmGXU8oxuABD2B8r0yU8FVgjnCZBSVo61qJ0A2d J6r8rYKbjtolnrZN/V4IPSzYvxurHbu8nbiFVyhOySPchI2Fu+YT/HsSe/0MH9bW gJTNzmutWoy9VxtWLCmXnOSZHep3MZ1ZNimno6Kh2qQ7VJr0+KF8GbxUKOPv4SqK NBwouIQXFc0pE9kGhcGKbr7TnHhyJFCRLNP1OVDQZbcoKjk1Vh+5sy7vM2VUTQmM yOToT2LEZVAUJXNumcYMki9MIwfYCwYZbNt0ZEolyHzUEesuyHfU1eJd6+sKEjUz 5GteQIR7AehxZIS+cytu7BXO7B0owLJ2awIBAg== -----END DH PARAMETERS----- openssl-0.10.23/test/dsa.pem010064400017500001750000000012341346222217000140110ustar0000000000000000-----BEGIN DSA PRIVATE KEY----- MIIBuwIBAAKBgQCkKe/jtYKJNQafaE7kg2aaJOEPUV0Doi451jkXHp5UfLh6+t42 eabSGkE9WBAlILgaB8yHckLe9+zozN39+SUDp94kb2r38/8w/9Ffhbsep9uiyOj2 ZRQur6SkpKQDKcnAd6IMZXZcvdSgPC90A6qraYUZKq7Csjn63gbC+IvXHwIVAIgS PE43lXD8/rGYxos4cxCgGGAxAoGASMV56WhLvVQtWMVI36WSIxbZnC2EsnNIKeVW yXnP/OmPJ2mdezG7i1alcwsO2TnSLbvjvGPlyzIqZzHvWC8EmDqsfbU+n8we/Eal sm5nloC8m9ECWpbTzbNdvrAAj9UPVWjcDwg7grAGGysh6lGbBv5P+4zL/niq1UiE LnKcifgCgYEAo6mAasO0+MVcu8shxxUXXNeTLsZ8NB/BIx9EZ/dzE23ivNW8dq1A eecAAYhssI2m/CspQvyKw+seCvg4FccxJgB3+mGOe+blFHwO3eAwoyRn/t3DZDHh FjxKKRsQdy4BkZv+vhTyIYYCw0iPZ5Wfln+pyGGTveIDED1MPG+J6c8CFCJAUlEl 4nHvbC15xLXXpd46zycY -----END DSA PRIVATE KEY----- openssl-0.10.23/test/dsa.pem.pub010064400017500001750000000012161346222217000145760ustar0000000000000000-----BEGIN PUBLIC KEY----- MIIBtzCCASsGByqGSM44BAEwggEeAoGBAKQp7+O1gok1Bp9oTuSDZpok4Q9RXQOi LjnWORcenlR8uHr63jZ5ptIaQT1YECUguBoHzIdyQt737OjM3f35JQOn3iRvavfz /zD/0V+Fux6n26LI6PZlFC6vpKSkpAMpycB3ogxldly91KA8L3QDqqtphRkqrsKy OfreBsL4i9cfAhUAiBI8TjeVcPz+sZjGizhzEKAYYDECgYBIxXnpaEu9VC1YxUjf pZIjFtmcLYSyc0gp5VbJec/86Y8naZ17MbuLVqVzCw7ZOdItu+O8Y+XLMipnMe9Y LwSYOqx9tT6fzB78RqWybmeWgLyb0QJaltPNs12+sACP1Q9VaNwPCDuCsAYbKyHq UZsG/k/7jMv+eKrVSIQucpyJ+AOBhQACgYEAo6mAasO0+MVcu8shxxUXXNeTLsZ8 NB/BIx9EZ/dzE23ivNW8dq1AeecAAYhssI2m/CspQvyKw+seCvg4FccxJgB3+mGO e+blFHwO3eAwoyRn/t3DZDHhFjxKKRsQdy4BkZv+vhTyIYYCw0iPZ5Wfln+pyGGT veIDED1MPG+J6c8= -----END PUBLIC KEY----- openssl-0.10.23/test/dsaparam.pem010064400017500001750000000007071346222217000150360ustar0000000000000000-----BEGIN DSA PARAMETERS----- MIIBHgKBgQCkKe/jtYKJNQafaE7kg2aaJOEPUV0Doi451jkXHp5UfLh6+t42eabS GkE9WBAlILgaB8yHckLe9+zozN39+SUDp94kb2r38/8w/9Ffhbsep9uiyOj2ZRQu r6SkpKQDKcnAd6IMZXZcvdSgPC90A6qraYUZKq7Csjn63gbC+IvXHwIVAIgSPE43 lXD8/rGYxos4cxCgGGAxAoGASMV56WhLvVQtWMVI36WSIxbZnC2EsnNIKeVWyXnP /OmPJ2mdezG7i1alcwsO2TnSLbvjvGPlyzIqZzHvWC8EmDqsfbU+n8we/Ealsm5n loC8m9ECWpbTzbNdvrAAj9UPVWjcDwg7grAGGysh6lGbBv5P+4zL/niq1UiELnKc ifg= -----END DSA PARAMETERS----- openssl-0.10.23/test/identity.p12010064400017500001750000000064721346222217000147250ustar00000000000000000 60  *H   0 0w *H h0d0] *H 0 *H  0u W70l<6- I\?ӳ]:Wh aXI3."!Dc3,[LөB':SlZuS؁! $9Bb&AHUFCew!=@2 x񘛬G"2G`DRx矱Ra}Pz6Ԥ)}`Y'BЂ)-kH̞6.K7.h͞kg9|PctGؙNchk ]ӢɛĮT:9\ =0RT{O0'23.R ' { JOVDc5V-3E _i^O* )'[䓬=d$ %vhYy<4Q\1S(|Ad)59iʅZ|ORvNyOK' HA#B$ٻ8NJB _F} T/f%.L~Z/ǹ_ ס]ǰbf@Z f4TrB!æU콆B/I$79Idz .Q^$@L*fYlx.OI;ꔛ%Raڐ㜥\Zcyx|K|>"\ձW2g_?*0SQQl F/sng^$3Ĭh'0p|.22*c K~"bgY*Tn̤zzR9r(7m૘zm Wн3-P}HԊ@_z4Di۩rpg$T#E$L =/M4 q`ИRΏ&7k'*~ݏgzcؚq@Ά)UrnXΧW,.M=9sIOXO #I͊ ȸҝ\:2S1؏_j:Purd+8p=,2ZdSMKPf|#.+";נ"$K_\>%]o LBG 5Ut!uoPfd6 ZIZeXfO^K'hpIY= 0U-uh1Gx|C["y6]C\ Nֺ OV:6bGUʶ+=,.{*2Н$6AXKS2>9RLw6Ӆn~x7*-btJ֛-rwn n u13+$)u7 XD/gZ(DY: I[N'h㾯38H |v0e4 ͍@)MZw oy=Oru7=E5_BσRYP {h%s.oY4gaɠXs)[>UdѰ 1C6qJ׽nEʹ0kVEG>,QXA*ZF4GXduȞvu[Jdʘb"MHufQPXf=7h3tᆳHr&2)TTt"^=@ӕ(G/;z-%3Xbijk&nRP 8σzHX4GC؁ʥMshՉR/uȮ ]d( N U|5u[?DSbǤVE 9G4g0f *H WS0O0K *H  00 *H  0iK[Kq=7_޼5Ue eTJc,v@D$COHpȮxM?͒i@ g*V@6>p5e OHݢfOg<`Q =S;]ZhPO@=:lpYĥe mE4oeD cMz環= 쩉q膔D"%aZG7kqv|sc"mwOŀ%ʱw3Vģ?.Z[dk;g2M5O6rdYNc;.59:7_IHR Ui9"־I+{azw}Ed||yԨZ4#.l$2l;D=;JH#Ǻ1>Z }y:֔ ;2Q Bi|KVA SCZ ^1s^Zk# ަ+>/^w;,]=^if ,Xǜ@gkWt!qЎiu4bYW&Y"Cb ;\RV) KkCp@QQ苇Zˡٿ:4z[< %}v6=O6 saBvȄ9[КQ~ (V-qϒ:Gnнҡ"M5!/Za` =&}S|m B`-H6~=$$!k[&pQxShtn+hW:f3>s26aK3}OV"poYus!㿬a5 sI;&^ݭ"g2@<]~ 9,fy!#PQ#ޛugsOe`#Cc=>ڈ1J0# *H  1foobar.com0# *H  1Y-DY'gn010!0 +d)II Z)Z#Fճ"oopenssl-0.10.23/test/key.der010064400017500001750000000022511346222217000140230ustar00000000000000000%DP#x6I-Gl6?7޿3eJI"do 4N?rPК6bOBt _Z%%5SR!W.xN:HexYT`^U|렑Ԓ'٫ fgړ  UሹIleFl;nvz=N׌KRV^zd3Qݔܤ߄NPY\Э;6* 5胉Ϳ #AzK\t'= cv\M)mxPcfn+c2nPI^nNԪcv MܕŹ$&W_X#j=U)~?; d89+ X358a͏WM_Yƃ_lcJ`,9&Q+W= ,46`>(dD-[W>j5aEX#!m/papQ aa%4ҫo,WE\L31y>ne?|/f;o_'kjT}Y^Dvv#+,q.v N2C*f}&GmѮ ;fi;+F2m4)ȁye>KPCB: TK v>jShPE26W.>@.Z뉬dcC)vopenssl-0.10.23/test/key.pem010064400017500001750000000032541346222217000140360ustar0000000000000000-----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCo9CWMRLMXo1CF /iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt OzboKgs1AgMBAAECggEBAKLj6IOJBKXolczpzb8UkyAjAkGBektcseV07gelJ/fk 3z0LuWPv5p12E/HlXB24vU2x/ikUbbP3eMsawRzDEahQqmNmPEkYAYUAy/Qpi9GN DYvn3LqDec4jVgeQKS+p9H2DzUpTogp8zR2//yzbuWBg2+F//xh7vU0S0RQCziPM x7RSBgbhxSfChfEJbS2sDnzfh0jRQmoY95iFv7puet1FJtzdZ4fgCd1RqmC2lFM5 H0eZtN/Cz19lieVs0b996DErdEBqClVZO00eYbRozCDaBzRU3ybB/dMrGJxhkkXm wb3kWMtziH9qOYsostuHIFu8eKFLloKxFnq2R4DGxOECgYEA2KUIZISOeGJSBcLJ JAUK2gvgXPNo4HHWIwOA9xeN3ZJlsnPlffXQNnm6t1st1V2gfMm9I2n0m/F0y2B/ n/XGSa8bghfPA9l0c2h58lkL3JQJR/paa8ycTz+YZPrznEyN7Qa0RrJXUvZv9lQL Hc3+FHcSHgMqDV2f2bHAEu9YGi0CgYEAx6VEIPNvrHFgjo/jk1RTuk+m0xEWQsZL Cs+izQMr2TaeJn8LG+93AvFuYn0J0nT3WuStLPrUg8i4IhSS6lf1tId5ivIZPm4r YwMyblBJXhnHbk7Uqodjfw/3s6V2HAu++B7hTdyVr9DFuST9uv4m8bkPV8rfX1jE I2rAPVWvgikCgYB+wNAQP547wQrMZBLbCDg5KwmyWJfb+b6X7czexOEz6humNTjo YZHYzY/5B1fhpk3ntQD8X1nGg5caBvOk21+QbOtjShrM3cXMYCw5JvBRtitX+Zo9 yBEMLOE0877ki8XeEDYZxu5gk98d+D4oygUGZEQtWxyXhVepPt5qNa8OYQKBgQDH RVgZI6KFlqzv3wMh3PutbS9wYQ+9GrtwUQuIYe/0YSW9+vSVr5E0qNKrD28sV39F hBauXLady0yvB6YUrjMbPFW+sCMuQzyfGWPO4+g3OrfqjFiM1ZIkE0YEU9Tt7XNx qTDtTI1D7bhNMnTnniI1B6ge0und+3XafAThs5L48QKBgQCTTpfqMt8kU3tcI9sf 0MK03y7kA76d5uw0pZbWFy7KI4qnzWutCzb+FMPWWsoFtLJLPZy//u/ZCUVFVa4d 0Y/ASNQIESVPXFLAltlLo4MSmsg1vCBsbviEEaPeEjvMrgki93pYtd/aOSgkYC1T mEq154s5rmqh+h+XRIf7Au0SLw== -----END PRIVATE KEY----- openssl-0.10.23/test/key.pem.pub010064400017500001750000000007031346222217000146170ustar0000000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr1bXMptaIgOL9PVL8a7W KG/C8+IbxP018eMBQZT0SnPQmXp0Q8Aai/F+AEDE7b5sO5U7WdxU4GRYw0wqkQNF si78KNfoj2ZMlx6NRfl4UKuzrpGTPgQxuKDYedngPpWcbmW4P3zEL2Y7b18n9NJr atRUzH1Zh/ReRO525Xadu58aviPw1Mzgse7cKyzb03Gll9noLnYNIIpO8jL+QyrD 8qNmfacmR20U0a6XDTtmsmk7AitGETICbTT0KRf+oAP0yIHoonllPpNLUEPZQjrp ClS/S/wKdj7gaq9TaMbHULhFMjbCV8cuPu//rUAuWp3riaznZGOVQyn3Dp2CB3ad yQIDAQAB -----END PUBLIC KEY----- openssl-0.10.23/test/keystore-empty-chain.p12010064400017500001750000000047221346222217000171510ustar00000000000000000 0  *H  y u0 q0n *H _[0W0S *H  00( *H  0VB,$ `{L:%\DڋMRɗ2 1$sUo&-*;ťd#gJL0xh ě T$e7mbyȶ.S=gTt>Ղ0'~>.n( Sd Ɯ4U|`Jb]׫ C 5~j4yz&{).צmQeuΈ ЄznYkI0 cf>eTOU<Zټ $KQYHEj% $+ @7b W{ MJc&$ITd K$v'NO8 _(oTy0r?6vg=:[^WyPTh~!Tz>G"u7jWW`KW gzX7bȣ/TV ö;^4yfND@y|^lL]̕7ւkdr iv[x}V. #e.WsWuWMlt 1gR)K@M՘'q5&"שWw36ӭ<l1bq]C(3[+R:EyA \ Ԓ@ #LjΡem^tTPjEe+y?\ۆh2$K1k娝`@?{?ؕ QaC(^`10:23F|B8 Jf0rah41:@=$n˚7"z%TkIG-dtGqV*H&yW0.3@. Y#Yxq-&тv!rȊ6ZGVqIGSh_CeM9tbyc|ڴQc ܸw[̈fzUPH$vԭ+:-XTK AiU,&lgP P=oU~~FA;oSMJLFU$:-Pq5:rYnA @P.ap5xq΋dG0F~*K,:gWx2v>dϣO&W~@꽌* |SyS:&}]R `)N0$3%&HX})d=4?ac0]'NK Hiw5j=q@EѲ[S121F0! *H  1docker-db0! *H  1Time 14878352479100 *H 00 *H 0( *H  0._C+Cf'Sz0=-w1R$? XO{4eI8; %#Bz05;$~o 6 G͡{.F'6|ZU ]`!* D`$_S̅-tj˱TRA]@DWNrS+5^Lj i)̐]1OM%&EZn0^x7[jWZÞDH6)lj/! bZ\tL0q՘^Kv߭#G6 5UZ *SU58YHf&B]<~åøBM.afgFȪ:_S8֡DڼH.jAx83`B/>Y *I4!= [LnXsah{f6t';WXNkZKY0AW^V| :V1ގƔ96TNQ.o4n7skEue_Z+nA?fOEo屃nJIۈGld{"70=0!0 +)҂q{<{$.m\RFLopenssl-0.10.23/test/nid_test_cert.pem010064400017500001750000000012701346222217000160700ustar0000000000000000-----BEGIN CERTIFICATE----- MIIB1DCCAX6gAwIBAgIJAMzXWZGWHleWMA0GCSqGSIb3DQEBCwUAMFYxHzAdBgkq hkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20xFDASBgNVBAMMC2V4YW1wbGUuY29t MR0wGwYJKoZIhvcNAQkUHg4ARQB4AGEAbQBwAGwAZTAeFw0xNTA3MDEwNjQ3NDRa Fw0xNTA3MzEwNjQ3NDRaMFYxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhhbXBsZS5j b20xFDASBgNVBAMMC2V4YW1wbGUuY29tMR0wGwYJKoZIhvcNAQkUHg4ARQB4AGEA bQBwAGwAZTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCmejzp4+o35FD0hAnx2trL 08h07X5jZca9DgZH35hWXPh7fMucLt/IPXIRnz2zKEa/Mo6D2V/fx03Mqo0epid7 AgMBAAGjLzAtMB0GA1UdDgQWBBRQa57tXz3rZNRz+fTbo3w3jQJMBTAMBgNVHRME BTADAQH/MA0GCSqGSIb3DQEBCwUAA0EAm0iY9cr+gvC+vcQIebdofpQ4GcDW8U6W Bxs8ZXinLl69P0jYLum3+XITNFRiyQqcivaxdxthxDNOX7P+aKwkJA== -----END CERTIFICATE----- openssl-0.10.23/test/nid_uid_test_cert.pem010064400017500001750000000027101346222217000167310ustar0000000000000000-----BEGIN CERTIFICATE----- MIIEGTCCAwGgAwIBAgIJAItKTzcGfL1lMA0GCSqGSIb3DQEBCwUAMIGiMSIwIAYK CZImiZPyLGQBAQwSdGhpcyBpcyB0aGUgdXNlcklkMQswCQYDVQQGEwJVUzETMBEG A1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxlMRUwEwYDVQQKDAxS dXN0IE9wZW5TU0wxDDAKBgNVBAsMA09TUzEhMB8GA1UEAwwYcnVzdC1vcGVuc3Ns LmV4YW1wbGUuY29tMB4XDTE2MDIwMjE3MjIwMVoXDTE2MDMwMzE3MjIwMVowgaIx IjAgBgoJkiaJk/IsZAEBDBJ0aGlzIGlzIHRoZSB1c2VySWQxCzAJBgNVBAYTAlVT MRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlTdW5ueXZhbGUxFTATBgNV BAoMDFJ1c3QgT3BlblNTTDEMMAoGA1UECwwDT1NTMSEwHwYDVQQDDBhydXN0LW9w ZW5zc2wuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB AQDa3Gc+IE5DOhTv1m5DZW8qKiyNLd7v4DaAYLXSsDuLs+9wJ+Bs+wlBfrg+PT0t EJlPaLL9IfD5eR3WpFu62TUexYhnJh+3vhCGsFHOXcTjtM+wy/dzZtOVh2wTzvqE /FHBGw1eG3Ww+RkSFbwYmtm8JhIN8ffYxGn2O0yQpxypf5hNPYrC81zX+52X2w1h jDYLpYt55w+e6q+iRRFk0tKiWHEqqh/r6UQQRpj2EeS+xTloZlO6h0nl2NPkVF3r CXBoT8Ittxr7sqcYqf8TAA0I4qZRYXKYehFmv/VkSt85CcURJ/zXeoJ1TpxSvQie 2R9cRDkYROrIOAFbB/0mmHLBAgMBAAGjUDBOMB0GA1UdDgQWBBRKfPqtgrbdbTmH XR6RC/p8t/65GjAfBgNVHSMEGDAWgBRKfPqtgrbdbTmHXR6RC/p8t/65GjAMBgNV HRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCKfeGRduGsIwKNiGcDUNkNrc7Z f8SWAmb/R6xiDfgjbhrtfBDowIZ5natEkTgf6kQPMJKyjg2NEM2uJWBc55rLOHIv es1wQOlYjfEUmFD3lTIt2TM/IUgXn2j+zV1CRkJthQLVFChXsidd0Bqq2fBjd3ad Yjzrxf3uOTBAs27koh2INNHfcUZCRsx8hP739zz2kw/r5NB/9iyENEyJKQvxo0jb oN0JK2joGZrWetDukQrqf032TsdkboW5JresYybbAD3326Ljp+hlT/3WINc+3nZJ Dn+pPMdpuZ5BUZ+u+XyNEPum3k3P3K19AF+zWYGooX0J1cmuCBrrqce20Lwy -----END CERTIFICATE----- openssl-0.10.23/test/pkcs1.pem.pub010064400017500001750000000006521346222217000150530ustar0000000000000000-----BEGIN RSA PUBLIC KEY----- MIIBCgKCAQEAyrcf7lv42BCoiDd3LYmF8eaGO4rhmGzGgi+NSZowkEuLhibHGQle FkZC7h1VKsxKFgy7Fx+GYHkv9OLm9H5fdp3HhYlo19bZVGvSJ66OJe/Bc4S02bBb Y8vwpc/N5O77m5J/nHLuL7XJtpfSKkX+3NPiX1X2L99iipt7F0a7hNws3G3Lxg6t P3Yc55TPjXzXvDIgjt/fag6iF8L/bR3augJJdDhLzNucR8A5HcvPtIVo51R631Zq MCh+dZvgz9zGCXwsvSky/iOJTHN3wnpsWuCAzS1iJMfjR783Tfv6sWFs19FH7pHP xBA3b2enPM9KBzINGOly0eM4h0fh+VBltQIDAQAB -----END RSA PUBLIC KEY----- openssl-0.10.23/test/pkcs8.der010064400017500001750000000024221346222217000142630ustar000000000000000000@ *H  030 *H  0us’%0*H 1yͭygymH$F}{o1ҝ#V7L;27:c$_5"znZvho˜'ĉrD{ )D; xOAw?1i"Yd ʼnUd :< ^!L\gƢ\RЄ݅z}Ċ[})uOm,S!|ni0] 71XSj˚4ɨ^<4T]!Q8*:n ^p}?v0huqMTx(_0@Eu~#Z,2%L5@*ᴬy.]o֍sN { v̳Ku"o\ٔ9-:S>K '9lyǾ)% J@|.>9E gDGɂjhAo`4ČG _ul){Tgh]Hȓ8v]V 8G8#JVķALV)8|,/π_Z[CcIxʀ Դδ\8j{?V`R#Y]_Jɥ)-EEޕ>0h+P?]Tʻ' OZF\|q˷/fU- E=q 2HB1D 4N `]Oa=fg]-%iLΏu:֏S*OU #5:HkHLp\RxkOF&]5}99{iVXbbZ>SC5Zhq5 9d:*XGgYA -ͺjiˉljH76߳G0r#] Rou$UH(-;9G$6X.n ta `~sկQ,{Aguopenssl-0.10.23/test/root-ca.key010064400017500001750000000032171346222217000146200ustar0000000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/ 1Kzox+2GZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd 7SBXieIVeIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQ r4XsZuQr7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdW pGTNVZ92aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrk gRob6eBcklDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABAoIBAGZrnd/dC2kp11uq Sg8SHk3GMdPPjTf/lq51sVJAU4fdV2Eso0XCiCzdKDcqR6F+jiu8jHp4YO0riW8N b1pkjohGjyOaddIaaVsZ80/OkgDz20Ird9XQ7uoEODvopA12+755BDH5PDwqHVeM nKfPiwAK6Jz6CxGO9bq9ZNoBiSyO1uofaB4Cpp8t74XVeAuPiI/Bb6WJ8TW5K5dt x0Jihdo46QgZR+z4PnyWIoACkhSoQmtTb9NUrpKceBcxdCrZ/kEmYpnPq/PuSw6g 6HthjYP/H9Xulz69UR5Ez6z+1pU1rKFmQ46qK7X3zVHg233MlGekMzxdmShEjzCP BMGYpQECgYEA5tqTZsUJwx3HDhkaZ/XOtaQqwOnZm9wPwTjGbV1t4+NUJzsl5gjP ho+I8ZSGZ6MnNSh+ClpYhUHYBq0rTuAAYL2arcMOuOs1GrMmiZJbXm8zq8M7gYr5 V99H/7akSx66WV/agPkLIvh/BWxlWgQcoVAIzZibbLUxr7Ye50pCLfECgYEAwDLn mFz0mFMvGtaSp8RnTDTFCz9czCeDt0GujCxG1epdvtuxlg/S1QH+mGzA/AHkiu7z uzCwGKWozNTdRkqVwYoJTB+AYHseSkuGP+a1zr39w+xBW/vESb2oP95GIwprXcG2 b/qdeQVzuLQhYoqWI2u8CBwlHFfpQO4Bp2ea+ocCgYEAurIgLSfCqlpFpiAlG9hN 8NYwgU1d4E+LKj+JMd8yRO+PGh8amjub4X3pST5NqDjpN3Nk42iHWFWUqGmZsbM0 ewg7tLUgDeqiStKBoxaK8AdMqWc9k5lZ53e6mZISsnHKUQdVBaLjH8gJqdAs8yyK HudEB0mYwMSUxz6pJXIHrXECgYEAhJkaCpXm8chB8UQj/baUhZDKeI4IWZjRWHbq Ey7g1+hPMMOk6yCTlf1ARqyRH8u2ftuIL5bRhs+Te21IE5yVYOb4rxn0mZuXNC6S ujdTKwUMtESkeu9hZnaAQz/4J2ii1hY05WCDj+DhC4bKmY9/MYS8PuQb/kfwVqld Xr8tvrUCgYEAmslHocXBUFXyRDkEOx/aKo+t9fPBr95PBZzFUt9ejrTP4PXsLa46 3/PNOCGdrQxh5qHHcvLwR4bPL++Dj+qMUTJXANrArKPDpE2WqH6pqWIC6yaZvzUk 17QbpXR6bHcdJV045pWpw40UCStTocVynY1lBfOw8VqxBIBlpVBBzew= -----END RSA PRIVATE KEY----- openssl-0.10.23/test/root-ca.pem010064400017500001750000000023151346222217000146070ustar0000000000000000-----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr 7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92 aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3 AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3 mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9 GA== -----END CERTIFICATE----- openssl-0.10.23/test/rsa-encrypted.pem010064400017500001750000000033461346222217000160300ustar0000000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,E2F16153E2BA3D617285A68C896BA6AF vO9SnhtGjGe8pG1pN//vsONnvJr+DjU+lFCiSqGMPT7tezDnbehLfS+9kus2HV7r HmI14JvVG9O7NpF7zMyBRlHYdWcCCWED9Yar0NsWN9419e5pMe/bqIXAzAiJbtT4 OB9U5XF3m+349zjN1dVXPPLGRmMC1pcHAlofeb5nIUFTvUi5xcsbe1itGjgkkvHb Bt8NioHTBun8kKrlsFQOuB55ylBU/eWG8DQBtvFOmQ7iWp0RnGQfh8k5e5rcZNpQ fD9ygc7UVISl0xTrIG4IH15g34H+nrBauKtIPOpNPuXQPOMHCZv3XH8wnhrWHHwT ZFnQBdXbSpQtMsRh0phG2G+VIlyCgSn4+CxjCJ+TgFtsoK/tU0unmRYc59QnTxxb qkHYsPs3E0NApQAgH1ENEGl1M+FGLYQH7gftjc3ophBTeRA17sRmD7Y4QBInggsq Gv6tImPVBdekAjz/Ls/EyMwjAvvrL5eAokqrIsAarGo+zmbJKHzknw2KUz2En0+k YYaxB4oy9u7bzuQlvio6xYHJEb4K197bby4Dldmqv7YCCJBJwhOBAInMD687viKv vcUwL8YuS6cW5E8MbvEENlY4+lvKKj3M8Bnyb79cYIPQe92EuCwXU9DZXPRMLwwM oFEJpF5E/PmNJzu+B52ahHtDrh83WSx71fWqjdTqwkPZhAYo3ztsfFkb/UqUcq8u rBSebeUjZh0XZ9B04eshZQ5vJUcXGtYIe/77beV3Pv89/fw+zTZjpiP9Q3sZALzf Qt0YGp0/6qBuqR1tcqdu65AS2hun7yFw7uRavqYKvww4axRiz2do+xWmZFuoCAwD EWktaUujltpvAc1lo7lg4C6nByefJB9Xqk22N/vpqOsWr1NbAntT42Qj/HF9BVWR osvN3yMnKYWYe6oSTVnNBDM5obWAIHd3I9gcxTOTb1KsEwt2RrDs5EpB5ptS3Fjo JfBRhNZQ3cXttrIIhsHgDn9BDNg865/xpIgktKj0gEd60Abx0PqkAIm6IZTh4Efg 7uZwfzxB+saOcddbrW2gNdzVZMC0s2Ye3sqHhtLbAJ3BlXYTxE4CAvTg54Ny+5hF IjvjlOKgXceSG1cSfk21/wyp9RY3Ft0AEYvvp0kZScWZaoA2aSFDUrchXVhgrEbn lJ7UptjefwRFIreAlwbKSbIDDNWnyzvIWyHfQ2aYqgnb7W7XqNPSgH9cALCfzirI dlRHjha0bMUtrjPCC/YfMXzJBVniy0gG6Pd5uC7vz/Awn6/6HRQVNaTQASphPBQ7 bJuz+JTfzI9OUVCMRMdnb6b35U4P9tibFmnPvzTIPe+3WUmf8aRsLS3NN3G1Webd PMYVZpMycPaAI0Ht87axhsOzlxCWHYWjdHa+WoNNc1J90TxLCmAHquh5BDaWvjMK 0DySftJZjV7Tf1p2KosmU83LRl39B5NHMbZb1xOEZl9IWwhT/PVKTVZ25xdxWLfb hF4l8rfvKehIp5r4t8zW1bvI2Hl6vrUvmcUVWt3BfKjxlgwRVD0vvwonMt1INesF 204vUBeXbDsUUicLwOyUgaFvJ3XU3dOyvL9MhOgM5OgoFRRhG+4AS8a5JCD8iLtq -----END RSA PRIVATE KEY----- openssl-0.10.23/test/rsa.pem010064400017500001750000000032131346222217000140260ustar0000000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAofgWCuLjybRlzo0tZWJjNiuSfb4p4fAkd/wWJcyQoTbji9k0 l8W26mPddxHmfHQp+Vaw+4qPCJrcS2mJPMEzP1Pt0Bm4d4QlL+yRT+SFd2lZS+pC gNMsD1W/YpRPEwOWvG6b32690r2jZ47soMZo9wGzjb/7OMg0LOL+bSf63kpaSHSX ndS5z5rexMdbBYUsLA9e+KXBdQOS+UTo7WTBEMa2R2CapHg665xsmtdVMTBQY4uD Zlxvb3qCo5ZwKh9kG4LT6/I5IhlJH7aGhyxXFvUK+DWNmoudF8NAco9/h9iaGNj8 q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXpoQIDAQABAoIBABKucaRpzQorw35S bEUAVx8dYXUdZOlJcHtiWQ+dC6V8ljxAHj/PLyzTveyI5QO/xkObCyjIL303l2cf UhPu2MFaJdjVzqACXuOrLot/eSFvxjvqVidTtAZExqFRJ9mylUVAoLvhowVWmC1O n95fZCXxTUtxNEG1Xcc7m0rtzJKs45J+N/V9DP1edYH6USyPSWGp6wuA+KgHRnKK Vf9GRx80JQY7nVNkL17eHoTWEwga+lwi0FEoW9Y7lDtWXYmKBWhUE+U8PGxlJf8f 40493HDw1WRQ/aSLoS4QTp3rn7gYgeHEvfJdkkf0UMhlknlo53M09EFPdadQ4TlU bjqKc50CgYEA4BzEEOtIpmVdVEZNCqS7baC4crd0pqnRH/5IB3jw3bcxGn6QLvnE tfdUdiYrqBdss1l58BQ3KhooKeQTa9AB0Hw/Py5PJdTJNPY8cQn7ouZ2KKDcmnPG BY5t7yLc1QlQ5xHdwW1VhvKn+nXqhJTBgIPgtldC+KDV5z+y2XDwGUcCgYEAuQPE fgmVtjL0Uyyx88GZFF1fOunH3+7cepKmtH4pxhtCoHqpWmT8YAmZxaewHgHAjLYs p1ZSe7zFYHj7C6ul7TjeLQeZD/YwD66t62wDmpe/HlB+TnBA+njbglfIsRLtXlnD zQkv5dTltRJ11BKBBypeeF6689rjcJIDEz9RWdcCgYAHAp9XcCSrn8wVkMVkKdb7 DOX4IKjzdahm+ctDAJN4O/y7OW5FKebvUjdAIt2GuoTZ71iTG+7F0F+lP88jtjP4 U4qe7VHoewl4MKOfXZKTe+YCS1XbNvfgwJ3Ltyl1OH9hWvu2yza7q+d5PCsDzqtm 27kxuvULVeya+TEdAB1ijQKBgQCH/3r6YrVH/uCWGy6bzV1nGNOdjKc9tmkfOJmN 54dxdixdpozCQ6U4OxZrsj3FcOhHBsqAHvX2uuYjagqvo3cOj1TRqNocX40omfCC Mx3bD1yPPf/6TI2XECva/ggqEY2mYzmIiA5LVVmc5nrybr+lssFKneeyxN2Wq93S 0iJMdQKBgCGHewxzoa1r8ZMD0LETNrToK423K377UCYqXfg5XMclbrjPbEC3YI1Z NqMtuhdBJqUnBi6tjKMF+34Xf0CUN8ncuXGO2CAYvO8PdyCixHX52ybaDjy1FtCE 6yUXjoKNXKvUm7MWGsAYH6f4IegOetN5NvmUMFStCSkh7ixZLkN1 -----END RSA PRIVATE KEY----- openssl-0.10.23/test/rsa.pem.pub010064400017500001750000000007031346222217000146140ustar0000000000000000-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAofgWCuLjybRlzo0tZWJj NiuSfb4p4fAkd/wWJcyQoTbji9k0l8W26mPddxHmfHQp+Vaw+4qPCJrcS2mJPMEz P1Pt0Bm4d4QlL+yRT+SFd2lZS+pCgNMsD1W/YpRPEwOWvG6b32690r2jZ47soMZo 9wGzjb/7OMg0LOL+bSf63kpaSHSXndS5z5rexMdbBYUsLA9e+KXBdQOS+UTo7WTB EMa2R2CapHg665xsmtdVMTBQY4uDZlxvb3qCo5ZwKh9kG4LT6/I5IhlJH7aGhyxX FvUK+DWNmoudF8NAco9/h9iaGNj8q2ethFkMLs91kzk2PAcDTW9gb54h4FRWyuXp oQIDAQAB -----END PUBLIC KEY----- openssl-0.10.23/.cargo_vcs_info.json0000644000000001120000000000000127130ustar00{ "git": { "sha1": "3b064fdb022912bbb98f5b8d9d111aeb6fec8f79" } }