openssl-0.10.36/.cargo_vcs_info.json0000644000000001120000000000100126600ustar { "git": { "sha1": "d95befdd7e90c363dc88ef3bf25cadb417335f4c" } } openssl-0.10.36/CHANGELOG.md000064400000000000000000000540750072674642500133320ustar 00000000000000# Change Log ## [Unreleased] ## [v0.10.36] - 2021-08-17 ### Added * Added `Asn1Object::as_slice`. * Added `PKeyRef::{raw_public_key, raw_private_key, private_key_to_pkcs8_passphrase}` and `PKey::{private_key_from_raw_bytes, public_key_from_raw_bytes}`. * Added `Cipher::{seed_cbc, seed_cfb128, seed_ecb, seed_ofb}`. ## [v0.10.35] - 2021-06-18 ### Fixed * Fixed a memory leak in `Deriver`. ### Added * Added support for OpenSSL 3.x.x. * Added `SslStream::peek`. ## [v0.10.34] - 2021-04-28 ### Added * Added `Dh::set_private_key` and `DhRef::private_key`. * Added `EcPointRef::affine_coordinates`. * Added `TryFrom` implementations to convert between `PKey` and specific key types. * Added `X509StoreBuilderRef::set_flags`. ## [v0.10.33] - 2021-03-13 ### Fixed * `Dh::generate_params` now uses `DH_generate_params_ex` rather than the deprecated `DH_generated_params` function. ### Added * Added `Asn1Type`. * Added `CmsContentInfoRef::decrypt_without_cert_check`. * Added `EcPointRef::{is_infinity, is_on_curve}`. * Added `Encrypter::set_rsa_oaep_label`. * Added `MessageDigest::sm3`. * Added `Pkcs7Ref::signers`. * Added `Cipher::nid`. * Added `X509Ref::authority_info` and `AccessDescription::{method, location}`. * Added `X509NameBuilder::{append_entry_by_text_with_type, append_entry_by_nid_with_type}`. ## [v0.10.32] - 2020-12-24 ### Fixed * Fixed `Ssl::new` to take a `&SslContextRef` rather than `&SslContext`. ### Added * Added the `encrypt` module to support asymmetric encryption and decryption with `PKey`s. * Added `MessageDigest::from_name`. * Added `ConnectConfiguration::into_ssl`. * Added the ability to create unconnected `SslStream`s directly from an `Ssl` and transport stream without performing any part of the handshake with `SslStream::new`. * Added `SslStream::{read_early_data, write_early_data, connect, accept, do_handshake, stateless}`. * Implemented `ToOwned` for `SslContextRef`. * Added `SslRef::{set_connect_state, set_accept_state}`. ### Deprecated * Deprecated `SslStream::from_raw_parts` in favor of `Ssl::from_ptr` and `SslStream::new`. * Deprecated `SslStreamBuilder` in favor of methods on `Ssl` and `SslStream`. ## [v0.10.31] - 2020-12-09 ### Added * Added `Asn1Object::from_str`. * Added `Dh::from_pgq`, `DhRef::prime_p`, `DhRef::prime_q`, `DhRef::generator`, `DhRef::generate_params`, `DhRef::generate_key`, `DhRef::public_key`, and `DhRef::compute_key`. * Added `Pkcs7::from_der` and `Pkcs7Ref::to_der`. * Added `Id::X25519`, `Id::X448`, `PKey::generate_x25519`, and `PKey::generate_x448`. * Added `SrtpProfileId::SRTP_AEAD_AES_128_GCM` and `SrtpProfileId::SRTP_AEAD_AES_256_GCM`. * Added `SslContextBuilder::verify_param` and `SslContextBuilder::verify_param_mut`. * Added `X509Ref::subject_name_hash` and `X509Ref::version`. * Added `X509StoreBuilderRef::add_lookup`, and the `X509Lookup` type. * Added `X509VerifyFlags`, `X509VerifyParamRef::set_flags`, `X509VerifyParamRef::clear_flags` `X509VerifyParamRef::get_flags`. ## [v0.10.30] - 2020-06-25 ### Fixed * `DsaRef::private_key_to_pem` can no longer be called without a private key. ### Changed * Improved the `Debug` implementations of many types. ### Added * Added `is_empty` implementations for `Asn1StringRef` and `Asn1BitStringRef`. * Added `EcPointRef::{to_pem, to_dir}` and `EcKeyRef::{public_key_from_pem, public_key_from_der}`. * Added `Default` implementations for many types. * Added `Debug` implementations for many types. * Added `SslStream::from_raw_parts`. * Added `SslRef::set_mtu`. * Added `Cipher::{aes_128_ocb, aes_192_ocb, aes_256_ocb}`. ### Deprecated * Deprecated `SslStreamBuilder::set_dtls_mtu_size` in favor of `SslRef::set_mtu`. ## [v0.10.29] - 2020-04-07 ### Fixed * Fixed a memory leak in `X509Builder::append_extension`. ### Added * Added `SslConnector::into_context` and `SslConnector::context`. * Added `SslAcceptor::into_context` and `SslAcceptor::context`. * Added `SslMethod::tls_client` and `SslMethod::tls_server`. * Added `SslContextBuilder::set_cert_store`. * Added `SslContextRef::verify_mode` and `SslRef::verify_mode`. * Added `SslRef::is_init_finished`. * Added `X509Object`. * Added `X509StoreRef::objects`. ## [v0.10.28] - 2020-02-04 ### Fixed * Fixed the mutability of `Signer::sign_oneshot` and `Verifier::verify_oneshot`. This is unfortunately a breaking change, but a necessary soundness fix. ## [v0.10.27] - 2020-01-29 ### Added * Added `MessageDigest::null`. * Added `PKey::private_key_from_pkcs8`. * Added `SslOptions::NO_RENEGOTIATION`. * Added `SslStreamBuilder::set_dtls_mtu_size`. ## [v0.10.26] - 2019-11-22 ### Fixed * Fixed improper handling of the IV buffer in `envelope::{Seal, Unseal}`. ### Added * Added `Asn1TimeRef::{diff, compare}`. * Added `Asn1Time::from_unix`. * Added `PartialEq` and `PartialOrd` implementations for `Asn1Time` and `Asn1TimeRef`. * Added `base64::{encode_block, decode_block}`. * Added `EcGroupRef::order_bits`. * Added `Clone` implementations for `Sha1`, `Sha224`, `Sha256`, `Sha384`, and `Sha512`. * Added `SslContextBuilder::{set_sigalgs_list, set_groups_list}`. ## [v0.10.25] - 2019-10-02 ### Fixed * Fixed a memory leak in `EcdsaSig::from_private_components` when using OpenSSL 1.0.x. ### Added * Added support for Ed25519 and Ed448 keys. * Implemented `ToOwned` for `PKeyRef` and `Clone` for `PKey`. ## [v0.10.24] - 2019-07-19 ### Fixed * Worked around an OpenSSL 1.0.x bug triggered by code calling `SSL_set_app_data`. ### Added * Added `aes::{wrap_key, unwrap_key}`. * Added `CmsContentInfoRef::to_pem` and `CmsContentInfo::from_pem`. * Added `DsaRef::private_key_to_pem`. * Added `EcGroupRef::{cofactor, generator}`. * Added `EcPointRef::to_owned`. * Added a `Debug` implementation for `EcKey`. * Added `SslAcceptor::{mozilla_intermediate_v5, mozilla_modern_v5}`. * Added `Cipher::{aes_128_ofb, aes_192_ecb, aes_192_cbc, aes_192_ctr, aes_192_cfb1, aes_192_cfb128, aes_192_cfb8, aes_192_gcm, aes_192_ccm, aes_192_ofb, aes_256_ofb}`. ## [v0.10.23] - 2019-05-18 ### Fixed * Fixed session callbacks when an `Ssl`'s context is replaced. ### Added * Added `SslContextBuilder::add_client_ca`. ## [v0.10.22] - 2019-05-08 ### 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.36...master [v0.10.36]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.35...openssl-v0.10.36 [v0.10.35]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.34...openssl-v0.10.35 [v0.10.34]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.33...openssl-v0.10.34 [v0.10.33]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.32...openssl-v0.10.33 [v0.10.32]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.31...openssl-v0.10.32 [v0.10.31]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.30...openssl-v0.10.31 [v0.10.30]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.29...openssl-v0.10.30 [v0.10.29]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.28...openssl-v0.10.29 [v0.10.28]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.27...openssl-v0.10.28 [v0.10.27]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.26...openssl-v0.10.27 [v0.10.26]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.25...openssl-v0.10.26 [v0.10.25]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.24...openssl-v0.10.25 [v0.10.24]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.23...openssl-v0.10.24 [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.36/Cargo.lock0000644000000121630000000000100106440ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cc" version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" [[package]] name = "libc" version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765" [[package]] name = "once_cell" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" [[package]] name = "openssl" version = "0.10.36" dependencies = [ "bitflags", "cfg-if", "foreign-types", "hex", "libc", "once_cell", "openssl-sys", "tempdir", ] [[package]] name = "openssl-src" version = "111.15.0+1.1.1k" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a5f6ae2ac04393b217ea9f700cd04fa9bf3d93fae2872069f3d15d908af70a" dependencies = [ "cc", ] [[package]] name = "openssl-sys" version = "0.9.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1996d2d305e561b70d1ee0c53f1542833f4e1ac6ce9a6708b6ff2738ca67dc82" dependencies = [ "autocfg", "cc", "libc", "openssl-src", "pkg-config", "vcpkg", ] [[package]] name = "pkg-config" version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" [[package]] name = "rand" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" dependencies = [ "fuchsia-cprng", "libc", "rand_core 0.3.1", "rdrand", "winapi", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ "rand_core 0.3.1", ] [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[package]] name = "tempdir" version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" dependencies = [ "rand", "remove_dir_all", ] [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" openssl-0.10.36/Cargo.toml0000644000000024200000000000100106620ustar # 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] edition = "2018" name = "openssl" version = "0.10.36" 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 = "1.0" [dependencies.ffi] version = "0.9.66" package = "openssl-sys" [dependencies.foreign-types] version = "0.3.1" [dependencies.libc] version = "0.2" [dependencies.once_cell] version = "1.5.2" [dev-dependencies.hex] version = "0.3" [dev-dependencies.tempdir] version = "0.3" [features] v101 = [] v102 = [] v110 = [] v111 = [] vendored = ["ffi/vendored"] openssl-0.10.36/Cargo.toml.orig000064400000000000000000000013000072674642500143670ustar 00000000000000[package] name = "openssl" version = "0.10.36" 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"] edition = "2018" # these are deprecated and don't do anything anymore [features] v101 = [] v102 = [] v110 = [] v111 = [] vendored = ['ffi/vendored'] [dependencies] bitflags = "1.0" cfg-if = "1.0" foreign-types = "0.3.1" libc = "0.2" once_cell = "1.5.2" ffi = { package = "openssl-sys", version = "0.9.66", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" hex = "0.3" openssl-0.10.36/LICENSE000064400000000000000000000011520072674642500125120ustar 00000000000000Copyright 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.36/README.md000064400000000000000000000014760072674642500127750ustar 00000000000000# rust-openssl [![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 of `openssl` is 0.10 and `openssl-sys` is 0.9. 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.36/build.rs000064400000000000000000000042310072674642500131530ustar 00000000000000#![allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)] use std::env; fn main() { if env::var("DEP_OPENSSL_LIBRESSL").is_ok() { 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 version >= 0x3_00_00_00_0 { println!("cargo:rustc-cfg=ossl300"); } } 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"); } if version >= 0x3_02_01_00_0 { println!("cargo:rustc-cfg=libressl321"); } if version >= 0x3_03_02_00_0 { println!("cargo:rustc-cfg=libressl332"); } } } openssl-0.10.36/examples/mk_certs.rs000064400000000000000000000125470072674642500155120ustar 00000000000000//! A program that generates ca certs, certs verified by the ca, and public //! and private keys. 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 key_pair = 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(&key_pair)?; 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(&key_pair, MessageDigest::sha256())?; let cert = cert_builder.build(); Ok((cert, key_pair)) } /// Make a X509 request with the given private key fn mk_request(key_pair: &PKey) -> Result { let mut req_builder = X509ReqBuilder::new()?; req_builder.set_pubkey(key_pair)?; 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(key_pair, 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_key_pair: &PKeyRef, ) -> Result<(X509, PKey), ErrorStack> { let rsa = Rsa::generate(2048)?; let key_pair = PKey::from_rsa(rsa)?; let req = mk_request(&key_pair)?; 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(&key_pair)?; 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_key_pair, MessageDigest::sha256())?; let cert = cert_builder.build(); Ok((cert, key_pair)) } fn real_main() -> Result<(), ErrorStack> { let (ca_cert, ca_key_pair) = mk_ca_cert()?; let (cert, _key_pair) = mk_ca_signed_cert(&ca_cert, &ca_key_pair)?; // 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.36/src/aes.rs000064400000000000000000000240130072674642500134130ustar 00000000000000//! Low level AES IGE and key wrapping 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 and key wrapping //! //! 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 //! //! ## AES IGE //! ```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"); //! ``` //! //! ## Key wrapping //! ```rust //! use openssl::aes::{AesKey, unwrap_key, wrap_key}; //! //! let kek = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F"; //! let key_to_wrap = b"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"; //! //! let enc_key = AesKey::new_encrypt(kek).unwrap(); //! let mut ciphertext = [0u8; 24]; //! wrap_key(&enc_key, None, &mut ciphertext, &key_to_wrap[..]).unwrap(); //! let dec_key = AesKey::new_decrypt(kek).unwrap(); //! let mut orig_key = [0u8; 16]; //! unwrap_key(&dec_key, None, &mut orig_key, &ciphertext[..]).unwrap(); //! //! assert_eq!(&orig_key[..], &key_to_wrap[..]); //! ``` //! use libc::{c_int, c_uint}; use std::mem::MaybeUninit; use std::ptr; use crate::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 = MaybeUninit::uninit(); let r = ffi::AES_set_encrypt_key( key.as_ptr() as *const _, key.len() as c_int * 8, aes_key.as_mut_ptr(), ); if r == 0 { Ok(AesKey(aes_key.assume_init())) } 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 = MaybeUninit::uninit(); let r = ffi::AES_set_decrypt_key( key.as_ptr() as *const _, key.len() as c_int * 8, aes_key.as_mut_ptr(), ); if r == 0 { Ok(AesKey(aes_key.assume_init())) } 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 refers to propagating forward errors. IGE, like other /// block ciphers implemented for AES requires an initialization 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 implementation will panic /// if the input or output does not meet this 16-byte boundary. Attention must /// be made in this low level implementation to pad the value to the 128-bit boundary. /// /// [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, ); } } /// Wrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394) /// /// * `key`: The key-encrypting-key to use. Must be a encrypting key /// * `iv`: The IV to use. You must use the same IV for both wrapping and unwrapping /// * `out`: The output buffer to store the ciphertext /// * `in_`: The input buffer, storing the key to be wrapped /// /// Returns the number of bytes written into `out` /// /// # Panics /// /// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or if /// `out` is not 8 bytes longer than `in_` pub fn wrap_key( key: &AesKey, iv: Option<[u8; 8]>, out: &mut [u8], in_: &[u8], ) -> Result { unsafe { assert!(out.len() >= in_.len() + 8); // Ciphertext is 64 bits longer (see 2.2.1) let written = ffi::AES_wrap_key( &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. iv.as_ref() .map_or(ptr::null(), |iv| iv.as_ptr() as *const _), out.as_ptr() as *mut _, in_.as_ptr() as *const _, in_.len() as c_uint, ); if written <= 0 { Err(KeyError(())) } else { Ok(written as usize) } } } /// Unwrap a key, according to [RFC 3394](https://tools.ietf.org/html/rfc3394) /// /// * `key`: The key-encrypting-key to decrypt the wrapped key. Must be a decrypting key /// * `iv`: The same IV used for wrapping the key /// * `out`: The buffer to write the unwrapped key to /// * `in_`: The input ciphertext /// /// Returns the number of bytes written into `out` /// /// # Panics /// /// Panics if either `out` or `in_` do not have sizes that are a multiple of 8, or /// if `in_` is not 8 bytes longer than `out` pub fn unwrap_key( key: &AesKey, iv: Option<[u8; 8]>, out: &mut [u8], in_: &[u8], ) -> Result { unsafe { assert!(out.len() + 8 <= in_.len()); let written = ffi::AES_unwrap_key( &key.0 as *const _ as *mut _, // this is safe, the implementation only uses the key as a const pointer. iv.as_ref() .map_or(ptr::null(), |iv| iv.as_ptr() as *const _), out.as_ptr() as *mut _, in_.as_ptr() as *const _, in_.len() as c_uint, ); if written <= 0 { Err(KeyError(())) } else { Ok(written as usize) } } } #[cfg(test)] mod test { use hex::FromHex; use super::*; use crate::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); } // from the RFC https://tools.ietf.org/html/rfc3394#section-2.2.3 #[test] fn test_wrap_unwrap() { let raw_key = Vec::from_hex("000102030405060708090A0B0C0D0E0F").unwrap(); let key_data = Vec::from_hex("00112233445566778899AABBCCDDEEFF").unwrap(); let expected_ciphertext = Vec::from_hex("1FA68B0A8112B447AEF34BD8FB5A7B829D3E862371D2CFE5").unwrap(); let enc_key = AesKey::new_encrypt(&raw_key).unwrap(); let mut wrapped = [0; 24]; assert_eq!( wrap_key(&enc_key, None, &mut wrapped, &key_data).unwrap(), 24 ); assert_eq!(&wrapped[..], &expected_ciphertext[..]); let dec_key = AesKey::new_decrypt(&raw_key).unwrap(); let mut unwrapped = [0; 16]; assert_eq!( unwrap_key(&dec_key, None, &mut unwrapped, &wrapped).unwrap(), 16 ); assert_eq!(&unwrapped[..], &key_data[..]); } } openssl-0.10.36/src/asn1.rs000064400000000000000000000602600072674642500135110ustar 00000000000000#![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 cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_long, time_t}; #[cfg(ossl102)] use std::cmp::Ordering; use std::ffi::CString; use std::fmt; use std::ptr; use std::slice; use std::str; use crate::bio::MemBio; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; use crate::nid::Nid; use crate::string::OpensslString; use crate::{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 implementation. 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 = match MemBio::new() { Err(_) => return f.write_str("error"), Ok(m) => m, }; let print_result = cvt(ffi::ASN1_GENERALIZEDTIME_print( mem_bio.as_ptr(), self.as_ptr(), )); match print_result { Err(_) => f.write_str("error"), Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())), } } } } /// The type of an ASN.1 value. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Asn1Type(c_int); #[allow(missing_docs)] // no need to document the constants impl Asn1Type { pub const EOC: Asn1Type = Asn1Type(ffi::V_ASN1_EOC); pub const BOOLEAN: Asn1Type = Asn1Type(ffi::V_ASN1_BOOLEAN); pub const INTEGER: Asn1Type = Asn1Type(ffi::V_ASN1_INTEGER); pub const BIT_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_BIT_STRING); pub const OCTET_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_OCTET_STRING); pub const NULL: Asn1Type = Asn1Type(ffi::V_ASN1_NULL); pub const OBJECT: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT); pub const OBJECT_DESCRIPTOR: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT_DESCRIPTOR); pub const EXTERNAL: Asn1Type = Asn1Type(ffi::V_ASN1_EXTERNAL); pub const REAL: Asn1Type = Asn1Type(ffi::V_ASN1_REAL); pub const ENUMERATED: Asn1Type = Asn1Type(ffi::V_ASN1_ENUMERATED); pub const UTF8STRING: Asn1Type = Asn1Type(ffi::V_ASN1_UTF8STRING); pub const SEQUENCE: Asn1Type = Asn1Type(ffi::V_ASN1_SEQUENCE); pub const SET: Asn1Type = Asn1Type(ffi::V_ASN1_SET); pub const NUMERICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_NUMERICSTRING); pub const PRINTABLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_PRINTABLESTRING); pub const T61STRING: Asn1Type = Asn1Type(ffi::V_ASN1_T61STRING); pub const TELETEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_TELETEXSTRING); pub const VIDEOTEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VIDEOTEXSTRING); pub const IA5STRING: Asn1Type = Asn1Type(ffi::V_ASN1_IA5STRING); pub const UTCTIME: Asn1Type = Asn1Type(ffi::V_ASN1_UTCTIME); pub const GENERALIZEDTIME: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALIZEDTIME); pub const GRAPHICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GRAPHICSTRING); pub const ISO64STRING: Asn1Type = Asn1Type(ffi::V_ASN1_ISO64STRING); pub const VISIBLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VISIBLESTRING); pub const GENERALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALSTRING); pub const UNIVERSALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_UNIVERSALSTRING); pub const BMPSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_BMPSTRING); /// Constructs an `Asn1Type` from a raw OpenSSL value. pub fn from_raw(value: c_int) -> Self { Asn1Type(value) } /// Returns the raw OpenSSL value represented by this type. pub fn as_raw(&self) -> c_int { self.0 } } /// Difference between two ASN1 times. /// /// This `struct` is created by the [`diff`] method on [`Asn1TimeRef`]. See its /// documentation for more. /// /// [`diff`]: struct.Asn1TimeRef.html#method.diff /// [`Asn1TimeRef`]: struct.Asn1TimeRef.html #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[cfg(ossl102)] pub struct TimeDiff { /// Difference in days pub days: c_int, /// Difference in seconds. /// /// This is always less than the number of seconds in a day. pub secs: c_int, } 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 implementation /// 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 Asn1TimeRef { /// Find difference between two times /// /// This corresponds to [`ASN1_TIME_diff`]. /// /// [`ASN1_TIME_diff`]: https://www.openssl.org/docs/man1.1.0/crypto/ASN1_TIME_diff.html #[cfg(ossl102)] pub fn diff(&self, compare: &Self) -> Result { let mut days = 0; let mut secs = 0; let other = compare.as_ptr(); let err = unsafe { ffi::ASN1_TIME_diff(&mut days, &mut secs, self.as_ptr(), other) }; match err { 0 => Err(ErrorStack::get()), _ => Ok(TimeDiff { days, secs }), } } /// Compare two times /// /// This corresponds to [`ASN1_TIME_compare`] but is implemented using [`diff`] so that it is /// also supported on older versions of OpenSSL. /// /// [`ASN1_TIME_compare`]: https://www.openssl.org/docs/man1.1.1/man3/ASN1_TIME_compare.html /// [`diff`]: struct.Asn1TimeRef.html#method.diff #[cfg(ossl102)] pub fn compare(&self, other: &Self) -> Result { let d = self.diff(other)?; if d.days > 0 || d.secs > 0 { return Ok(Ordering::Less); } if d.days < 0 || d.secs < 0 { return Ok(Ordering::Greater); } Ok(Ordering::Equal) } } #[cfg(ossl102)] impl PartialEq for Asn1TimeRef { fn eq(&self, other: &Asn1TimeRef) -> bool { self.diff(other) .map(|t| t.days == 0 && t.secs == 0) .unwrap_or(false) } } #[cfg(ossl102)] impl PartialEq for Asn1TimeRef { fn eq(&self, other: &Asn1Time) -> bool { self.diff(other) .map(|t| t.days == 0 && t.secs == 0) .unwrap_or(false) } } #[cfg(ossl102)] impl<'a> PartialEq for &'a Asn1TimeRef { fn eq(&self, other: &Asn1Time) -> bool { self.diff(other) .map(|t| t.days == 0 && t.secs == 0) .unwrap_or(false) } } #[cfg(ossl102)] impl PartialOrd for Asn1TimeRef { fn partial_cmp(&self, other: &Asn1TimeRef) -> Option { self.compare(other).ok() } } #[cfg(ossl102)] impl PartialOrd for Asn1TimeRef { fn partial_cmp(&self, other: &Asn1Time) -> Option { self.compare(other).ok() } } #[cfg(ossl102)] impl<'a> PartialOrd for &'a Asn1TimeRef { fn partial_cmp(&self, other: &Asn1Time) -> Option { self.compare(other).ok() } } impl fmt::Display for Asn1TimeRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { unsafe { let mem_bio = match MemBio::new() { Err(_) => return f.write_str("error"), Ok(m) => m, }; let print_result = cvt(ffi::ASN1_TIME_print(mem_bio.as_ptr(), self.as_ptr())); match print_result { Err(_) => f.write_str("error"), Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())), } } } } impl fmt::Debug for Asn1TimeRef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(&self.to_string()) } } 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 from the specified `time_t` value pub fn from_unix(time: time_t) -> Result { ffi::init(); unsafe { let handle = cvt_p(ffi::ASN1_TIME_set(ptr::null_mut(), time))?; Ok(Asn1Time::from_ptr(handle)) } } /// 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 #[allow(clippy::should_implement_trait)] 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) } } } #[cfg(ossl102)] impl PartialEq for Asn1Time { fn eq(&self, other: &Asn1Time) -> bool { self.diff(other) .map(|t| t.days == 0 && t.secs == 0) .unwrap_or(false) } } #[cfg(ossl102)] impl PartialEq for Asn1Time { fn eq(&self, other: &Asn1TimeRef) -> bool { self.diff(other) .map(|t| t.days == 0 && t.secs == 0) .unwrap_or(false) } } #[cfg(ossl102)] impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time { fn eq(&self, other: &&'a Asn1TimeRef) -> bool { self.diff(other) .map(|t| t.days == 0 && t.secs == 0) .unwrap_or(false) } } #[cfg(ossl102)] impl PartialOrd for Asn1Time { fn partial_cmp(&self, other: &Asn1Time) -> Option { self.compare(other).ok() } } #[cfg(ossl102)] impl PartialOrd for Asn1Time { fn partial_cmp(&self, other: &Asn1TimeRef) -> Option { self.compare(other).ok() } } #[cfg(ossl102)] impl<'a> PartialOrd<&'a Asn1TimeRef> for Asn1Time { fn partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option { self.compare(other).ok() } } 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 correspond 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()) } } /// Returns the number of bytes in the string. pub fn len(&self) -> usize { unsafe { ffi::ASN1_STRING_length(self.as_ptr()) as usize } } /// Determines if the string is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } } impl fmt::Debug for Asn1StringRef { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match self.as_utf8() { Ok(openssl_string) => openssl_string.fmt(fmt), Err(_) => fmt.write_str("error"), } } } 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()) } } /// Returns the number of bytes in the string. pub fn len(&self) -> usize { unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize } } /// Determines if the string is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } } 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 Asn1Object { /// Constructs an ASN.1 Object Identifier from a string representation of /// the OID. /// /// This corresponds to [`OBJ_txt2obj`]. /// /// [`OBJ_txt2obj`]: https://www.openssl.org/docs/man1.1.0/man3/OBJ_txt2obj.html #[allow(clippy::should_implement_trait)] pub fn from_str(txt: &str) -> Result { unsafe { ffi::init(); let txt = CString::new(txt).unwrap(); let obj: *mut ffi::ASN1_OBJECT = cvt_p(ffi::OBJ_txt2obj(txt.as_ptr() as *const _, 0))?; Ok(Asn1Object::from_ptr(obj)) } } /// Return the OID as an DER encoded array of bytes. This is the ASN.1 /// value, not including tag or length. /// /// This corresponds to [`OBJ_get0_data`]. /// /// Requires OpenSSL 1.1.1 or newer. /// /// [`OBJ_get0_data`]: https://www.openssl.org/docs/man1.1.0/man3/OBJ_get0_data.html #[cfg(ossl111)] pub fn as_slice(&self) -> &[u8] { unsafe { let len = ffi::OBJ_length(self.as_ptr()); slice::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len) } } } 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, ); match str::from_utf8(&buf[..len as usize]) { Err(_) => fmt.write_str("error"), Ok(s) => fmt.write_str(s), } } } } impl fmt::Debug for Asn1ObjectRef { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.write_str(self.to_string().as_str()) } } 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 crate::bn::BigNum; use crate::nid::Nid; /// 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(); } #[test] fn time_from_unix() { let t = Asn1Time::from_unix(0).unwrap(); assert_eq!("Jan 1 00:00:00 1970 GMT", t.to_string()); } #[test] #[cfg(ossl102)] fn time_eq() { let a = Asn1Time::from_str("99991231235959Z").unwrap(); let b = Asn1Time::from_str("99991231235959Z").unwrap(); let c = Asn1Time::from_str("99991231235958Z").unwrap(); let a_ref = a.as_ref(); let b_ref = b.as_ref(); let c_ref = c.as_ref(); assert!(a == b); assert!(a != c); assert!(a == b_ref); assert!(a != c_ref); assert!(b_ref == a); assert!(c_ref != a); assert!(a_ref == b_ref); assert!(a_ref != c_ref); } #[test] #[cfg(ossl102)] fn time_ord() { let a = Asn1Time::from_str("99991231235959Z").unwrap(); let b = Asn1Time::from_str("99991231235959Z").unwrap(); let c = Asn1Time::from_str("99991231235958Z").unwrap(); let a_ref = a.as_ref(); let b_ref = b.as_ref(); let c_ref = c.as_ref(); assert!(a >= b); assert!(a > c); assert!(b <= a); assert!(c < a); assert!(a_ref >= b); assert!(a_ref > c); assert!(b_ref <= a); assert!(c_ref < a); assert!(a >= b_ref); assert!(a > c_ref); assert!(b <= a_ref); assert!(c < a_ref); assert!(a_ref >= b_ref); assert!(a_ref > c_ref); assert!(b_ref <= a_ref); assert!(c_ref < a_ref); } #[test] fn object_from_str() { let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap(); assert_eq!(object.nid(), Nid::SHA256); } #[test] fn object_from_str_with_invalid_input() { Asn1Object::from_str("NOT AN OID") .map(|object| object.to_string()) .expect_err("parsing invalid OID should fail"); } #[test] #[cfg(ossl111)] fn object_to_slice() { let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap(); assert_eq!( object.as_slice(), &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01], ); } } openssl-0.10.36/src/base64.rs000064400000000000000000000077710072674642500137430ustar 00000000000000//! Base64 encoding support. use crate::cvt_n; use crate::error::ErrorStack; use libc::c_int; /// Encodes a slice of bytes to a base64 string. /// /// This corresponds to [`EVP_EncodeBlock`]. /// /// # Panics /// /// Panics if the input length or computed output length overflow a signed C integer. /// /// [`EVP_EncodeBlock`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DecodeBlock.html pub fn encode_block(src: &[u8]) -> String { assert!(src.len() <= c_int::max_value() as usize); let src_len = src.len() as c_int; let len = encoded_len(src_len).unwrap(); let mut out = Vec::with_capacity(len as usize); // SAFETY: `encoded_len` ensures space for 4 output characters // for every 3 input bytes including padding and nul terminator. // `EVP_EncodeBlock` will write only single byte ASCII characters. // `EVP_EncodeBlock` will only write to not read from `out`. unsafe { let out_len = ffi::EVP_EncodeBlock(out.as_mut_ptr(), src.as_ptr(), src_len); out.set_len(out_len as usize); String::from_utf8_unchecked(out) } } /// Decodes a base64-encoded string to bytes. /// /// This corresponds to [`EVP_DecodeBlock`]. /// /// # Panics /// /// Panics if the input length or computed output length overflow a signed C integer. /// /// [`EVP_DecodeBlock`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DecodeBlock.html pub fn decode_block(src: &str) -> Result, ErrorStack> { let src = src.trim(); // https://github.com/openssl/openssl/issues/12143 if src.is_empty() { return Ok(vec![]); } assert!(src.len() <= c_int::max_value() as usize); let src_len = src.len() as c_int; let len = decoded_len(src_len).unwrap(); let mut out = Vec::with_capacity(len as usize); // SAFETY: `decoded_len` ensures space for 3 output bytes // for every 4 input characters including padding. // `EVP_DecodeBlock` can write fewer bytes after stripping // leading and trailing whitespace, but never more. // `EVP_DecodeBlock` will only write to not read from `out`. unsafe { let out_len = cvt_n(ffi::EVP_DecodeBlock( out.as_mut_ptr(), src.as_ptr(), src_len, ))?; out.set_len(out_len as usize); } if src.ends_with('=') { out.pop(); if src.ends_with("==") { out.pop(); } } Ok(out) } fn encoded_len(src_len: c_int) -> Option { let mut len = (src_len / 3).checked_mul(4)?; if src_len % 3 != 0 { len = len.checked_add(4)?; } len = len.checked_add(1)?; Some(len) } fn decoded_len(src_len: c_int) -> Option { let mut len = (src_len / 4).checked_mul(3)?; if src_len % 4 != 0 { len = len.checked_add(3)?; } Some(len) } #[cfg(test)] mod tests { use super::*; #[test] fn test_encode_block() { assert_eq!("".to_string(), encode_block(b"")); assert_eq!("Zg==".to_string(), encode_block(b"f")); assert_eq!("Zm8=".to_string(), encode_block(b"fo")); assert_eq!("Zm9v".to_string(), encode_block(b"foo")); assert_eq!("Zm9vYg==".to_string(), encode_block(b"foob")); assert_eq!("Zm9vYmE=".to_string(), encode_block(b"fooba")); assert_eq!("Zm9vYmFy".to_string(), encode_block(b"foobar")); } #[test] fn test_decode_block() { assert_eq!(b"".to_vec(), decode_block("").unwrap()); assert_eq!(b"f".to_vec(), decode_block("Zg==").unwrap()); assert_eq!(b"fo".to_vec(), decode_block("Zm8=").unwrap()); assert_eq!(b"foo".to_vec(), decode_block("Zm9v").unwrap()); assert_eq!(b"foob".to_vec(), decode_block("Zm9vYg==").unwrap()); assert_eq!(b"fooba".to_vec(), decode_block("Zm9vYmE=").unwrap()); assert_eq!(b"foobar".to_vec(), decode_block("Zm9vYmFy").unwrap()); } #[test] fn test_strip_whitespace() { assert_eq!(b"foobar".to_vec(), decode_block(" Zm9vYmFy\n").unwrap()); assert_eq!(b"foob".to_vec(), decode_block(" Zm9vYg==\n").unwrap()); } } openssl-0.10.36/src/bio.rs000064400000000000000000000034670072674642500134260ustar 00000000000000use cfg_if::cfg_if; use libc::c_int; use std::marker::PhantomData; use std::ptr; use std::slice; use crate::cvt_p; use crate::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.36/src/bn.rs000064400000000000000000001310000072674642500132350ustar 00000000000000//! 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 main() -> Result<(), ErrorStack> { //! let a = BigNum::new()?; // a = 0 //! let b = BigNum::from_dec_str("1234567890123456789012345")?; //! let c = &a * &b; //! assert_eq!(a, c); //! Ok(()) //! } //! ``` //! //! [`BIGNUM`]: https://wiki.openssl.org/index.php/Manual:Bn_internal(3) use cfg_if::cfg_if; 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 crate::asn1::Asn1Integer; use crate::error::ErrorStack; use crate::string::OpensslString; use crate::{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 implementation /// /// Perform large number mathematics. Create a new BigNum /// with [`new`]. Perform standard mathematics on large numbers using /// methods from [`Dref`] /// /// OpenSSL documentation 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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`. #[allow(clippy::useless_conversion)] 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`. #[allow(clippy::useless_conversion)] 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 crate::bn::{BigNum, BigNumContext}; #[test] fn test_to_from_slice() { let v0 = BigNum::from_u32(10_203_004).unwrap(); let vec = v0.to_vec(); let v1 = BigNum::from_slice(&vec).unwrap(); assert_eq!(v0, v1); } #[test] fn test_negation() { let a = BigNum::from_u32(909_829_283).unwrap(); assert!(!a.is_negative()); assert!((-a).is_negative()); } #[test] fn test_shift() { let a = BigNum::from_u32(909_829_283).unwrap(); assert_eq!(a, &(&a << 1) >> 1); } #[test] fn test_rand_range() { let range = BigNum::from_u32(909_829_283).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(909_829_283).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(19_029_017).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.36/src/cms.rs000064400000000000000000000267470072674642500134450ustar 00000000000000//! SMIME implementation using CMS //! //! CMS (PKCS#7) is an encryption standard. It allows signing and encrypting 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 bitflags::bitflags; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_uint; use std::ptr; use crate::bio::{MemBio, MemBioSlice}; use crate::error::ErrorStack; use crate::pkey::{HasPrivate, PKeyRef}; use crate::stack::StackRef; use crate::symm::Cipher; use crate::x509::{X509Ref, X509}; use crate::{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 implementation. /// /// [`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()?; cvt(ffi::CMS_decrypt( self.as_ptr(), pkey, cert, ptr::null_mut(), out.as_ptr(), 0, ))?; Ok(out.get_buf().to_owned()) } } /// Given the sender's private key, `pkey`, /// decrypt the data in `self` without validating the recipient certificate. /// /// *Warning*: Not checking the recipient certificate may leave you vulnerable to Bleichenbacher's attack on PKCS#1 v1.5 RSA padding. /// See [`CMS_decrypt`] for more information. /// /// [`CMS_decrypt`]: https://www.openssl.org/docs/man1.1.0/crypto/CMS_decrypt.html // FIXME merge into decrypt pub fn decrypt_without_cert_check(&self, pkey: &PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { unsafe { let pkey = pkey.as_ptr(); let out = MemBio::new()?; cvt(ffi::CMS_decrypt( self.as_ptr(), pkey, ptr::null_mut(), ptr::null_mut(), out.as_ptr(), 0, ))?; 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 } to_pem! { /// Serializes this CmsContentInfo using DER. /// /// OpenSSL documentation at [`PEM_write_bio_CMS`] /// /// [`PEM_write_bio_CMS`]: https://www.openssl.org/docs/man1.1.0/man3/PEM_write_bio_CMS.html to_pem, ffi::PEM_write_bio_CMS } } 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 } from_pem! { /// Deserializes a PEM-encoded ContentInfo structure. /// /// This corresponds to [`PEM_read_bio_CMS`]. /// /// [`PEM_read_bio_CMS`]: https://www.openssl.org/docs/man1.1.0/man3/PEM_read_bio_CMS.html from_pem, CmsContentInfo, ffi::PEM_read_bio_CMS } /// 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 crate::pkcs12::Pkcs12; use crate::stack::Stack; use crate::x509::X509; #[test] #[cfg_attr(ossl300, ignore)] // 3.0.0 can't load RC2-40-CBC 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"); // decrypt cms message using private key cert (DER) { let encrypted_der = encrypt.to_der().expect("failed to create der from cms"); let decrypt = CmsContentInfo::from_der(&encrypted_der).expect("failed read cms from der"); let decrypt_with_cert_check = decrypt .decrypt(&priv_cert.pkey, &priv_cert.cert) .expect("failed to decrypt cms"); let decrypt_with_cert_check = String::from_utf8(decrypt_with_cert_check) .expect("failed to create string from cms content"); let decrypt_without_cert_check = decrypt .decrypt_without_cert_check(&priv_cert.pkey) .expect("failed to decrypt cms"); let decrypt_without_cert_check = String::from_utf8(decrypt_without_cert_check) .expect("failed to create string from cms content"); assert_eq!(input, decrypt_with_cert_check); assert_eq!(input, decrypt_without_cert_check); } // decrypt cms message using private key cert (PEM) { let encrypted_pem = encrypt.to_pem().expect("failed to create pem from cms"); let decrypt = CmsContentInfo::from_pem(&encrypted_pem).expect("failed read cms from pem"); let decrypt_with_cert_check = decrypt .decrypt(&priv_cert.pkey, &priv_cert.cert) .expect("failed to decrypt cms"); let decrypt_with_cert_check = String::from_utf8(decrypt_with_cert_check) .expect("failed to create string from cms content"); let decrypt_without_cert_check = decrypt .decrypt_without_cert_check(&priv_cert.pkey) .expect("failed to decrypt cms"); let decrypt_without_cert_check = String::from_utf8(decrypt_without_cert_check) .expect("failed to create string from cms content"); assert_eq!(input, decrypt_with_cert_check); assert_eq!(input, decrypt_without_cert_check); } } } openssl-0.10.36/src/conf.rs000064400000000000000000000025640072674642500135770ustar 00000000000000//! Interface for processing OpenSSL configuration files. use crate::cvt_p; use crate::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. /// /// # Safety /// /// The caller must ensure that the pointer is valid. 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.36/src/derive.rs000064400000000000000000000103550072674642500141250ustar 00000000000000//! Shared secret derivation. use foreign_types::ForeignTypeRef; use std::marker::PhantomData; use std::ptr; use crate::error::ErrorStack; use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; use crate::{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> {} #[allow(clippy::len_without_is_empty)] 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) } } impl<'a> Drop for Deriver<'a> { fn drop(&mut self) { unsafe { ffi::EVP_PKEY_CTX_free(self.0); } } } #[cfg(test)] mod test { use super::*; use crate::ec::{EcGroup, EcKey}; use crate::nid::Nid; use crate::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.36/src/dh.rs000064400000000000000000000342700072674642500132440ustar 00000000000000use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use std::mem; use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private}; use crate::{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> { Self::from_pqg(p, Some(q), g) } /// Creates a DH instance based upon the given primes and generator params. /// /// This corresponds to [`DH_new`] and [`DH_set0_pqg`]. /// /// [`DH_new`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_new.html /// [`DH_set0_pqg`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_set0_pqg.html pub fn from_pqg( prime_p: BigNum, prime_q: Option, generator: BigNum, ) -> Result, ErrorStack> { unsafe { let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); cvt(DH_set0_pqg( dh.0, prime_p.as_ptr(), prime_q.as_ref().map_or(ptr::null_mut(), |q| q.as_ptr()), generator.as_ptr(), ))?; mem::forget((prime_p, prime_q, generator)); Ok(dh) } } /// Sets the private key on the DH object and recomputes the public key. pub fn set_private_key(self, priv_key: BigNum) -> Result, ErrorStack> { unsafe { let dh_ptr = self.0; cvt(DH_set0_key(dh_ptr, ptr::null_mut(), priv_key.as_ptr()))?; mem::forget(priv_key); cvt(ffi::DH_generate_key(dh_ptr))?; mem::forget(self); Ok(Dh::from_ptr(dh_ptr)) } } /// Generates DH params based on the given `prime_len` and a fixed `generator` value. /// /// This corresponds to [`DH_generate_parameters_ex`]. /// /// [`DH_generate_parameters_ex`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_generate_parameters.html pub fn generate_params(prime_len: u32, generator: u32) -> Result, ErrorStack> { unsafe { let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); cvt(ffi::DH_generate_parameters_ex( dh.0, prime_len as i32, generator as i32, ptr::null_mut(), ))?; Ok(dh) } } /// Generates a public and a private key based on the DH params. /// /// This corresponds to [`DH_generate_key`]. /// /// [`DH_generate_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_generate_key.html pub fn generate_key(self) -> Result, ErrorStack> { unsafe { let dh_ptr = self.0; cvt(ffi::DH_generate_key(dh_ptr))?; mem::forget(self); Ok(Dh::from_ptr(dh_ptr)) } } 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)) } } } impl Dh where T: HasParams, { /// Returns the prime `p` from the DH instance. /// /// This corresponds to [`DH_get0_pqg`]. /// /// [`DH_get0_pqg`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html pub fn prime_p(&self) -> &BigNumRef { let mut p = ptr::null(); unsafe { DH_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); BigNumRef::from_ptr(p as *mut _) } } /// Returns the prime `q` from the DH instance. /// /// This corresponds to [`DH_get0_pqg`]. /// /// [`DH_get0_pqg`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html pub fn prime_q(&self) -> Option<&BigNumRef> { let mut q = ptr::null(); unsafe { DH_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); if q.is_null() { None } else { Some(BigNumRef::from_ptr(q as *mut _)) } } } /// Returns the generator from the DH instance. /// /// This corresponds to [`DH_get0_pqg`]. /// /// [`DH_get0_pqg`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_pqg.html pub fn generator(&self) -> &BigNumRef { let mut g = ptr::null(); unsafe { DH_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); BigNumRef::from_ptr(g as *mut _) } } } impl DhRef where T: HasPublic, { /// Returns the public key from the DH instance. /// /// This corresponds to [`DH_get0_key`]. /// /// [`DH_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_key.html pub fn public_key(&self) -> &BigNumRef { let mut pub_key = ptr::null(); unsafe { DH_get0_key(self.as_ptr(), &mut pub_key, ptr::null_mut()); BigNumRef::from_ptr(pub_key as *mut _) } } } impl DhRef where T: HasPrivate, { /// Computes a shared secret from the own private key and the given `public_key`. /// /// This corresponds to [`DH_compute_key`]. /// /// [`DH_compute_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_compute_key.html pub fn compute_key(&self, public_key: &BigNumRef) -> Result, ErrorStack> { unsafe { let key_len = ffi::DH_size(self.as_ptr()); let mut key = vec![0u8; key_len as usize]; cvt(ffi::DH_compute_key( key.as_mut_ptr(), public_key.as_ptr(), self.as_ptr(), ))?; Ok(key) } } /// Returns the private key from the DH instance. /// /// This corresponds to [`DH_get0_key`]. /// /// [`DH_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/DH_get0_key.html pub fn private_key(&self) -> &BigNumRef { let mut priv_key = ptr::null(); unsafe { DH_get0_key(self.as_ptr(), ptr::null_mut(), &mut priv_key); BigNumRef::from_ptr(priv_key as *mut _) } } } cfg_if! { if #[cfg(any(ossl110, libressl270))] { use ffi::{DH_set0_pqg, DH_get0_pqg, DH_get0_key, DH_set0_key}; } 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 } #[allow(bad_style)] unsafe fn DH_get0_pqg( dh: *mut ffi::DH, p: *mut *const ffi::BIGNUM, q: *mut *const ffi::BIGNUM, g: *mut *const ffi::BIGNUM, ) { if !p.is_null() { *p = (*dh).p; } if !q.is_null() { *q = (*dh).q; } if !g.is_null() { *g = (*dh).g; } } #[allow(bad_style)] unsafe fn DH_set0_key( dh: *mut ffi::DH, pub_key: *mut ffi::BIGNUM, priv_key: *mut ffi::BIGNUM, ) -> ::libc::c_int { (*dh).pub_key = pub_key; (*dh).priv_key = priv_key; 1 } #[allow(bad_style)] unsafe fn DH_get0_key( dh: *mut ffi::DH, pub_key: *mut *const ffi::BIGNUM, priv_key: *mut *const ffi::BIGNUM, ) { if !pub_key.is_null() { *pub_key = (*dh).pub_key; } if !priv_key.is_null() { *priv_key = (*dh).priv_key; } } } } #[cfg(test)] mod tests { use crate::bn::BigNum; use crate::dh::Dh; use crate::ssl::{SslContext, SslMethod}; #[test] #[cfg(ossl102)] fn test_dh_rfc5114() { let mut ctx = SslContext::builder(SslMethod::tls()).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_params() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); let prime_p = BigNum::from_hex_str( "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF\ 4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B47\ 58C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B6\ 3ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5\ 140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710\ C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597", ).unwrap(); let prime_q = BigNum::from_hex_str( "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED\ 4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A\ 57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5\ 045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E\ 052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67E\ B6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659", ).unwrap(); let generator = BigNum::from_hex_str( "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3", ) .unwrap(); let dh = Dh::from_params( prime_p.to_owned().unwrap(), generator.to_owned().unwrap(), prime_q.to_owned().unwrap(), ) .unwrap(); ctx.set_tmp_dh(&dh).unwrap(); assert_eq!(dh.prime_p(), &prime_p); assert_eq!(dh.prime_q().unwrap(), &prime_q); assert_eq!(dh.generator(), &generator); } #[test] #[cfg(ossl102)] fn test_dh_stored_restored() { let dh1 = Dh::get_2048_256().unwrap(); let key1 = dh1.generate_key().unwrap(); let dh2 = Dh::get_2048_256().unwrap(); let key2 = dh2 .set_private_key(key1.private_key().to_owned().unwrap()) .unwrap(); assert_eq!(key1.public_key(), key2.public_key()); assert_eq!(key1.private_key(), key2.private_key()); } #[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(); } #[test] #[cfg(ossl102)] fn test_dh_generate_key_compute_key() { let dh1 = Dh::get_2048_224().unwrap().generate_key().unwrap(); let dh2 = Dh::get_2048_224().unwrap().generate_key().unwrap(); let shared_a = dh1.compute_key(dh2.public_key()).unwrap(); let shared_b = dh2.compute_key(dh1.public_key()).unwrap(); assert_eq!(shared_a, shared_b); } #[test] fn test_dh_generate_params_generate_key_compute_key() { let dh_params1 = Dh::generate_params(512, 2).unwrap(); let dh_params2 = Dh::from_pqg( dh_params1.prime_p().to_owned().unwrap(), None, dh_params1.generator().to_owned().unwrap(), ) .unwrap(); let dh1 = dh_params1.generate_key().unwrap(); let dh2 = dh_params2.generate_key().unwrap(); let shared_a = dh1.compute_key(dh2.public_key()).unwrap(); let shared_b = dh2.compute_key(dh1.public_key()).unwrap(); assert_eq!(shared_a, shared_b); } } openssl-0.10.36/src/dsa.rs000064400000000000000000000341050072674642500134150ustar 00000000000000//! Digital Signatures //! //! DSA ensures a message originated from a known sender, and was not modified. //! DSA uses asymmetrical 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 cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; use std::mem; use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; use crate::pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; use crate::util::ForeignTypeRefExt; use crate::{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 asymmetrical 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_const_ptr(pub_key) } } } impl DsaRef where T: HasPrivate, { private_key_to_pem! { /// Serializes the private key to a PEM-encoded DSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. /// /// This corresponds to [`PEM_write_bio_DSAPrivateKey`]. /// /// [`PEM_write_bio_DSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_DSAPrivateKey.html private_key_to_pem, /// Serializes the private key to a PEM-encoded encrypted DSAPrivateKey structure. /// /// The output will have a header of `-----BEGIN DSA PRIVATE KEY-----`. /// /// This corresponds to [`PEM_write_bio_DSAPrivateKey`]. /// /// [`PEM_write_bio_DSAPrivateKey`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_DSAPrivateKey.html private_key_to_pem_passphrase, ffi::PEM_write_bio_DSAPrivateKey } /// 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_const_ptr(priv_key) } } } 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_const_ptr(p) } } /// 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_const_ptr(q) } } /// 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_const_ptr(g) } } } 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 crate::bn::BigNumContext; use crate::hash::MessageDigest; use crate::pkey::PKey; use crate::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] #[allow(clippy::redundant_clone)] fn clone() { let key = Dsa::generate(2048).unwrap(); drop(key.clone()); } } openssl-0.10.36/src/ec.rs000064400000000000000000001155260072674642500132440ustar 00000000000000//! 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 use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; use std::ptr; use crate::bn::{BigNumContextRef, BigNumRef}; use crate::error::ErrorStack; use crate::nid::Nid; use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; use crate::util::ForeignTypeRefExt; use crate::{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 preferred. /// /// [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(|_| ()) } } /// Places the cofactor of the group in the provided `BigNum`. /// /// OpenSSL documentation at [`EC_GROUP_get_cofactor`] /// /// [`EC_GROUP_get_cofactor`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_get_cofactor.html pub fn cofactor( &self, cofactor: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_GROUP_get_cofactor( self.as_ptr(), cofactor.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 } } /// Returns the number of bits in the group order. /// /// OpenSSL documentation at [`EC_GROUP_order_bits`] /// /// [`EC_GROUP_order_bits`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_GROUP_order_bits.html #[cfg(ossl110)] pub fn order_bits(&self) -> u32 { unsafe { ffi::EC_GROUP_order_bits(self.as_ptr()) as u32 } } /// Returns the generator for the given curve as a [`EcPoint`]. /// /// OpenSSL documentation at [`EC_GROUP_get0_generator`] /// /// [`EC_GROUP_get0_generator`]: https://www.openssl.org/docs/man1.1.0/man3/EC_GROUP_get0_generator.html pub fn generator(&self) -> &EcPointRef { unsafe { let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr()); EcPointRef::from_const_ptr(ptr) } } /// 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, // FIXME should be &mut 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 in `self`. pub fn mul_generator( &mut self, group: &EcGroupRef, n: &BigNumRef, // FIXME should be &mut 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) } } } /// Creates a new point on the specified curve with the same value. /// /// OpenSSL documentation at [`EC_POINT_dup`] /// /// [`EC_POINT_dup`]: https://www.openssl.org/docs/man1.1.0/crypto/EC_POINT_dup.html pub fn to_owned(&self, group: &EcGroupRef) -> Result { unsafe { cvt_p(ffi::EC_POINT_dup(self.as_ptr(), group.as_ptr())).map(EcPoint) } } /// 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`] /// /// [`EC_POINT_get_affine_coordinates`]: https://www.openssl.org/docs/man1.1.1/man3/EC_POINT_get_affine_coordinates.html #[cfg(ossl111)] pub fn affine_coordinates( &self, group: &EcGroupRef, x: &mut BigNumRef, y: &mut BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_get_affine_coordinates( group.as_ptr(), self.as_ptr(), x.as_ptr(), y.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// 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(|_| ()) } } /// Checks if point is infinity /// /// OpenSSL documentation at [`EC_POINT_is_at_infinity`] /// /// [`EC_POINT_is_at_infinity`]: https://www.openssl.org/docs/man1.1.0/man3/EC_POINT_is_at_infinity.html pub fn is_infinity(&self, group: &EcGroupRef) -> bool { unsafe { let res = ffi::EC_POINT_is_at_infinity(group.as_ptr(), self.as_ptr()); res == 1 } } /// Checks if point is on a given curve /// /// OpenSSL documentation at [`EC_POINT_is_on_curve`] /// /// [`EC_POINT_is_on_curve`]: https://www.openssl.org/docs/man1.1.0/man3/EC_POINT_is_on_curve.html pub fn is_on_curve( &self, group: &EcGroupRef, ctx: &mut BigNumContextRef, ) -> Result { unsafe { let res = cvt_n(ffi::EC_POINT_is_on_curve( group.as_ptr(), self.as_ptr(), ctx.as_ptr(), ))?; Ok(res == 1) } } } 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_const_ptr(ptr) } } } impl EcKeyRef where T: HasPublic, { /// Returns the public key. /// /// OpenSSL documentation at [`EC_KEY_get0_public_key`] /// /// [`EC_KEY_get0_public_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_const_ptr(ptr) } } 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_EC_PUBKEY`]. /// /// [`PEM_write_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_write_bio_EC_PUBKEY.html public_key_to_pem, ffi::PEM_write_bio_EC_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. /// /// This corresponds to [`i2d_EC_PUBKEY`]. /// /// [`i2d_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/i2d_EC_PUBKEY.html public_key_to_der, ffi::i2d_EC_PUBKEY } } 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_const_ptr(ptr) } } /// Checks the key for validity. /// /// OpenSSL documentation 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 documentation 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) }) } } from_pem! { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure containing a EC key. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. /// /// This corresponds to [`PEM_read_bio_EC_PUBKEY`]. /// /// [`PEM_read_bio_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/PEM_read_bio_EC_PUBKEY.html public_key_from_pem, EcKey, ffi::PEM_read_bio_EC_PUBKEY } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key. /// /// This corresponds to [`d2i_EC_PUBKEY`]. /// /// [`d2i_EC_PUBKEY`]: https://www.openssl.org/docs/man1.1.0/crypto/d2i_EC_PUBKEY.html public_key_from_der, EcKey, ffi::d2i_EC_PUBKEY } } 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() } } impl fmt::Debug for EcKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "EcKey") } } #[cfg(test)] mod test { use hex::FromHex; use super::*; use crate::bn::{BigNum, BigNumContext}; use crate::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 cofactor() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let mut cofactor = BigNum::new().unwrap(); group.cofactor(&mut cofactor, &mut ctx).unwrap(); let one = BigNum::from_u32(1).unwrap(); assert_eq!(cofactor, one); } #[test] #[allow(clippy::redundant_clone)] 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 point_owned() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let point = key.public_key(); let owned = point.to_owned(&group).unwrap(); let mut ctx = BigNumContext::new().unwrap(); assert!(owned.eq(&group, point, &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(), &ctx) .unwrap(); assert!(public_key.eq(&group, key.public_key(), &mut ctx).unwrap()); } #[test] fn generator() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let gen = group.generator(); let one = BigNum::from_u32(1).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let mut ecp = EcPoint::new(&group).unwrap(); ecp.mul_generator(&group, &one, &ctx).unwrap(); assert!(ecp.eq(&group, gen, &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(); dup_key.check_key().unwrap(); 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()); } #[cfg(ossl111)] #[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(&group, &mut xbn2, &mut ybn2, &mut ctx) .unwrap(); assert_eq!(xbn2, xbn); assert_eq!(ybn2, ybn); } #[test] fn get_affine_coordinates_gfp() { 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); } #[test] fn is_infinity() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let g = group.generator(); assert!(!g.is_infinity(&group)); let mut order = BigNum::new().unwrap(); group.order(&mut order, &mut ctx).unwrap(); let mut inf = EcPoint::new(&group).unwrap(); inf.mul_generator(&group, &order, &ctx).unwrap(); assert!(inf.is_infinity(&group)); } #[test] #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] fn is_on_curve() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let g = group.generator(); assert!(g.is_on_curve(&group, &mut ctx).unwrap()); let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap(); assert!(!g.is_on_curve(&group2, &mut ctx).unwrap()); } } openssl-0.10.36/src/ecdsa.rs000064400000000000000000000201150072674642500137210ustar 00000000000000//! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions. use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::mem; use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::ec::EcKeyRef; use crate::error::ErrorStack; use crate::pkey::{HasPrivate, HasPublic}; use crate::util::ForeignTypeRefExt; use crate::{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 where T: HasPrivate, { 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)) } } /// 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)) } } 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 } /// 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 where T: HasPublic, { 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 an `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_const_ptr(r) } } /// Returns internal components: `s` of an `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_const_ptr(s) } } } 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 { if r.is_null() || s.is_null() { return 0; } ffi::BN_clear_free((*sig).r); ffi::BN_clear_free((*sig).s); (*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 crate::ec::EcGroup; use crate::ec::EcKey; use crate::nid::Nid; use crate::pkey::{Private, Public}; fn get_public_key(group: &EcGroup, x: &EcKey) -> Result, ErrorStack> { EcKey::from_public_key(group, x.public_key()) } #[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); // 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); } #[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.36/src/encrypt.rs000064400000000000000000000441000072674642500143260ustar 00000000000000//! Message encryption. //! //! The [`Encrypter`] allows for encryption of data given a public key. The [`Decrypter`] can be //! used with the corresponding private key to decrypt the data. //! //! # Examples //! //! Encrypt and decrypt data given an RSA keypair: //! //! ```rust //! use openssl::encrypt::{Encrypter, Decrypter}; //! use openssl::rsa::{Rsa, Padding}; //! use openssl::pkey::PKey; //! //! // Generate a keypair //! let keypair = Rsa::generate(2048).unwrap(); //! let keypair = PKey::from_rsa(keypair).unwrap(); //! //! let data = b"hello, world!"; //! //! // Encrypt the data with RSA PKCS1 //! let mut encrypter = Encrypter::new(&keypair).unwrap(); //! encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); //! // Create an output buffer //! let buffer_len = encrypter.encrypt_len(data).unwrap(); //! let mut encrypted = vec![0; buffer_len]; //! // Encrypt and truncate the buffer //! let encrypted_len = encrypter.encrypt(data, &mut encrypted).unwrap(); //! encrypted.truncate(encrypted_len); //! //! // Decrypt the data //! let mut decrypter = Decrypter::new(&keypair).unwrap(); //! decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); //! // Create an output buffer //! let buffer_len = decrypter.decrypt_len(&encrypted).unwrap(); //! let mut decrypted = vec![0; buffer_len]; //! // Encrypt and truncate the buffer //! let decrypted_len = decrypter.decrypt(&encrypted, &mut decrypted).unwrap(); //! decrypted.truncate(decrypted_len); //! assert_eq!(&*decrypted, data); //! ``` #[cfg(any(ossl102, libressl310))] use libc::{c_int, c_void}; use std::{marker::PhantomData, ptr}; use crate::error::ErrorStack; use crate::hash::MessageDigest; use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; use crate::rsa::Padding; use crate::{cvt, cvt_p}; use foreign_types::ForeignTypeRef; /// A type which encrypts data. pub struct Encrypter<'a> { pctx: *mut ffi::EVP_PKEY_CTX, _p: PhantomData<&'a ()>, } unsafe impl<'a> Sync for Encrypter<'a> {} unsafe impl<'a> Send for Encrypter<'a> {} impl<'a> Drop for Encrypter<'a> { fn drop(&mut self) { unsafe { ffi::EVP_PKEY_CTX_free(self.pctx); } } } impl<'a> Encrypter<'a> { /// Creates a new `Encrypter`. /// /// OpenSSL documentation at [`EVP_PKEY_encrypt_init`]. /// /// [`EVP_PKEY_encrypt_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt_init.html pub fn new(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPublic, { unsafe { ffi::init(); let pctx = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; let r = ffi::EVP_PKEY_encrypt_init(pctx); if r != 1 { ffi::EVP_PKEY_CTX_free(pctx); return Err(ErrorStack::get()); } Ok(Encrypter { 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 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(|_| ()) } } /// Sets the RSA OAEP algorithm. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`]. /// /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html #[cfg(any(ossl102, libressl310))] pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( self.pctx, md.as_ptr() as *mut _, )) .map(|_| ()) } } /// Sets the RSA OAEP label. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set0_rsa_oaep_label`]. /// /// [`EVP_PKEY_CTX_set0_rsa_oaep_label`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set0_rsa_oaep_label.html #[cfg(any(ossl102, libressl310))] pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { unsafe { let p = cvt_p(ffi::CRYPTO_malloc( label.len() as _, concat!(file!(), "\0").as_ptr() as *const _, line!() as c_int, ))?; ptr::copy_nonoverlapping(label.as_ptr(), p as *mut u8, label.len()); cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( self.pctx, p as *mut c_void, label.len() as c_int, )) .map(|_| ()) .map_err(|e| { #[cfg(not(ossl110))] ::ffi::CRYPTO_free(p as *mut c_void); #[cfg(ossl110)] ::ffi::CRYPTO_free( p as *mut c_void, concat!(file!(), "\0").as_ptr() as *const _, line!() as c_int, ); e }) } } /// Performs public key encryption. /// /// In order to know the size needed for the output buffer, use [`encrypt_len`](Encrypter::encrypt_len). /// Note that the length of the output buffer can be greater of the length of the encoded data. /// ``` /// # use openssl::{ /// # encrypt::Encrypter, /// # pkey::PKey, /// # rsa::{Rsa, Padding}, /// # }; /// # /// # 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 input = b"hello world".to_vec(); /// # /// let mut encrypter = Encrypter::new(&pkey).unwrap(); /// encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); /// /// // Get the length of the output buffer /// let buffer_len = encrypter.encrypt_len(&input).unwrap(); /// let mut encoded = vec![0u8; buffer_len]; /// /// // Encode the data and get its length /// let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); /// /// // Use only the part of the buffer with the encoded data /// let encoded = &encoded[..encoded_len]; /// ``` /// /// This corresponds to [`EVP_PKEY_encrypt`]. /// /// [`EVP_PKEY_encrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html pub fn encrypt(&self, from: &[u8], to: &mut [u8]) -> Result { let mut written = to.len(); unsafe { cvt(ffi::EVP_PKEY_encrypt( self.pctx, to.as_mut_ptr(), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } /// Gets the size of the buffer needed to encrypt the input data. /// /// This corresponds to [`EVP_PKEY_encrypt`] called with a null pointer as output argument. /// /// [`EVP_PKEY_encrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_encrypt.html pub fn encrypt_len(&self, from: &[u8]) -> Result { let mut written = 0; unsafe { cvt(ffi::EVP_PKEY_encrypt( self.pctx, ptr::null_mut(), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } } /// A type which decrypts data. pub struct Decrypter<'a> { pctx: *mut ffi::EVP_PKEY_CTX, _p: PhantomData<&'a ()>, } unsafe impl<'a> Sync for Decrypter<'a> {} unsafe impl<'a> Send for Decrypter<'a> {} impl<'a> Drop for Decrypter<'a> { fn drop(&mut self) { unsafe { ffi::EVP_PKEY_CTX_free(self.pctx); } } } impl<'a> Decrypter<'a> { /// Creates a new `Decrypter`. /// /// OpenSSL documentation at [`EVP_PKEY_decrypt_init`]. /// /// [`EVP_PKEY_decrypt_init`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt_init.html pub fn new(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { unsafe { ffi::init(); let pctx = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; let r = ffi::EVP_PKEY_decrypt_init(pctx); if r != 1 { ffi::EVP_PKEY_CTX_free(pctx); return Err(ErrorStack::get()); } Ok(Decrypter { 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 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(|_| ()) } } /// Sets the RSA OAEP algorithm. /// /// This is only useful for RSA keys. /// /// This corresponds to [`EVP_PKEY_CTX_set_rsa_oaep_md`]. /// /// [`EVP_PKEY_CTX_set_rsa_oaep_md`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_CTX_set_rsa_oaep_md.html #[cfg(any(ossl102, libressl310))] pub fn set_rsa_oaep_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( self.pctx, md.as_ptr() as *mut _, )) .map(|_| ()) } } /// Performs public key decryption. /// /// In order to know the size needed for the output buffer, use [`decrypt_len`](Decrypter::decrypt_len). /// Note that the length of the output buffer can be greater of the length of the decoded data. /// ``` /// # use openssl::{ /// # encrypt::Decrypter, /// # pkey::PKey, /// # rsa::{Rsa, Padding}, /// # }; /// # /// # const INPUT: &[u8] = b"\ /// # \x26\xa1\xc1\x13\xc5\x7f\xb4\x9f\xa0\xb4\xde\x61\x5e\x2e\xc6\xfb\x76\x5c\xd1\x2b\x5f\ /// # \x1d\x36\x60\xfa\xf8\xe8\xb3\x21\xf4\x9c\x70\xbc\x03\xea\xea\xac\xce\x4b\xb3\xf6\x45\ /// # \xcc\xb3\x80\x9e\xa8\xf7\xc3\x5d\x06\x12\x7a\xa3\x0c\x30\x67\xf1\xe7\x94\x6c\xf6\x26\ /// # \xac\x28\x17\x59\x69\xe1\xdc\xed\x7e\xc0\xe9\x62\x57\x49\xce\xdd\x13\x07\xde\x18\x03\ /// # \x0f\x9d\x61\x65\xb9\x23\x8c\x78\x4b\xad\x23\x49\x75\x47\x64\xa0\xa0\xa2\x90\xc1\x49\ /// # \x1b\x05\x24\xc2\xe9\x2c\x0d\x49\x78\x72\x61\x72\xed\x8b\x6f\x8a\xe8\xca\x05\x5c\x58\ /// # \xd6\x95\xd6\x7b\xe3\x2d\x0d\xaa\x3e\x6d\x3c\x9a\x1c\x1d\xb4\x6c\x42\x9d\x9a\x82\x55\ /// # \xd9\xde\xc8\x08\x7b\x17\xac\xd7\xaf\x86\x7b\x69\x9e\x3c\xf4\x5e\x1c\x39\x52\x6d\x62\ /// # \x50\x51\xbd\xa6\xc8\x4e\xe9\x34\xf0\x37\x0d\xa9\xa9\x77\xe6\xf5\xc2\x47\x2d\xa8\xee\ /// # \x3f\x69\x78\xff\xa9\xdc\x70\x22\x20\x9a\x5c\x9b\x70\x15\x90\xd3\xb4\x0e\x54\x9e\x48\ /// # \xed\xb6\x2c\x88\xfc\xb4\xa9\x37\x10\xfa\x71\xb2\xec\x75\xe7\xe7\x0e\xf4\x60\x2c\x7b\ /// # \x58\xaf\xa0\x53\xbd\x24\xf1\x12\xe3\x2e\x99\x25\x0a\x54\x54\x9d\xa1\xdb\xca\x41\x85\ /// # \xf4\x62\x78\x64"; /// # /// # 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 input = INPUT.to_vec(); /// # /// let mut decrypter = Decrypter::new(&pkey).unwrap(); /// decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); /// /// // Get the length of the output buffer /// let buffer_len = decrypter.decrypt_len(&input).unwrap(); /// let mut decoded = vec![0u8; buffer_len]; /// /// // Decrypt the data and get its length /// let decoded_len = decrypter.decrypt(&input, &mut decoded).unwrap(); /// /// // Use only the part of the buffer with the decrypted data /// let decoded = &decoded[..decoded_len]; /// ``` /// /// This corresponds to [`EVP_PKEY_decrypt`]. /// /// [`EVP_PKEY_decrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt.html pub fn decrypt(&self, from: &[u8], to: &mut [u8]) -> Result { let mut written = to.len(); unsafe { cvt(ffi::EVP_PKEY_decrypt( self.pctx, to.as_mut_ptr(), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } /// Gets the size of the buffer needed to decrypt the input data. /// /// This corresponds to [`EVP_PKEY_decrypt`] called with a null pointer as output argument. /// /// [`EVP_PKEY_decrypt`]: https://www.openssl.org/docs/manmaster/man3/EVP_PKEY_decrypt.html pub fn decrypt_len(&self, from: &[u8]) -> Result { let mut written = 0; unsafe { cvt(ffi::EVP_PKEY_decrypt( self.pctx, ptr::null_mut(), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } } #[cfg(test)] mod test { use hex::FromHex; use crate::encrypt::{Decrypter, Encrypter}; #[cfg(any(ossl102, libressl310))] use crate::hash::MessageDigest; use crate::pkey::PKey; use crate::rsa::{Padding, Rsa}; const INPUT: &str = "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ 654841694f6a457a4d4441344d546b7a4f44417344516f67496d6830644841364c79396c654746746347786c4c\ 6d4e76625339706331397962323930496a7030636e566c6651"; #[test] fn rsa_encrypt_decrypt() { 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 encrypter = Encrypter::new(&pkey).unwrap(); encrypter.set_rsa_padding(Padding::PKCS1).unwrap(); let input = Vec::from_hex(INPUT).unwrap(); let buffer_len = encrypter.encrypt_len(&input).unwrap(); let mut encoded = vec![0u8; buffer_len]; let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); let encoded = &encoded[..encoded_len]; let mut decrypter = Decrypter::new(&pkey).unwrap(); decrypter.set_rsa_padding(Padding::PKCS1).unwrap(); let buffer_len = decrypter.decrypt_len(encoded).unwrap(); let mut decoded = vec![0u8; buffer_len]; let decoded_len = decrypter.decrypt(encoded, &mut decoded).unwrap(); let decoded = &decoded[..decoded_len]; assert_eq!(decoded, &*input); } #[test] #[cfg(any(ossl102, libressl310))] fn rsa_encrypt_decrypt_with_sha256() { 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 md = MessageDigest::sha256(); let mut encrypter = Encrypter::new(&pkey).unwrap(); encrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); encrypter.set_rsa_oaep_md(md).unwrap(); encrypter.set_rsa_mgf1_md(md).unwrap(); let input = Vec::from_hex(INPUT).unwrap(); let buffer_len = encrypter.encrypt_len(&input).unwrap(); let mut encoded = vec![0u8; buffer_len]; let encoded_len = encrypter.encrypt(&input, &mut encoded).unwrap(); let encoded = &encoded[..encoded_len]; let mut decrypter = Decrypter::new(&pkey).unwrap(); decrypter.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); decrypter.set_rsa_oaep_md(md).unwrap(); decrypter.set_rsa_mgf1_md(md).unwrap(); let buffer_len = decrypter.decrypt_len(encoded).unwrap(); let mut decoded = vec![0u8; buffer_len]; let decoded_len = decrypter.decrypt(encoded, &mut decoded).unwrap(); let decoded = &decoded[..decoded_len]; assert_eq!(decoded, &*input); } } openssl-0.10.36/src/envelope.rs000064400000000000000000000216700072674642500144660ustar 00000000000000//! Envelope encryption. //! //! # Example //! //! ```rust //! use openssl::rsa::Rsa; //! use openssl::envelope::Seal; //! use openssl::pkey::PKey; //! use openssl::symm::Cipher; //! //! 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 crate::error::ErrorStack; use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef}; use crate::symm::Cipher; use crate::{cvt, cvt_p}; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::cmp; use std::ptr; /// 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![0; 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. #[allow(clippy::option_as_ref_deref)] 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); match (cipher.iv_len(), iv) { (Some(len), Some(iv)) => assert_eq!(len, iv.len(), "IV length mismatch"), (None, None) => {} (Some(_), None) => panic!("an IV was required but not provided"), (None, Some(_)) => panic!("an IV was provided but not required"), } 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 crate::pkey::PKey; use crate::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.36/src/error.rs000064400000000000000000000224150072674642500140000ustar 00000000000000//! 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 cfg_if::cfg_if; 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; /// 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 {} 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, func: *const c_char, 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 func = ptr::null(); let mut data = ptr::null(); let mut flags = 0; match ERR_get_error_all(&mut file, &mut line, &mut func, &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, func, data, }) } } } } /// Pushes the error back onto the OpenSSL error stack. pub fn put(&self) { self.put_error(); unsafe { 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.add(data.len()) = 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); } } } #[cfg(ossl300)] fn put_error(&self) { unsafe { ffi::ERR_new(); ffi::ERR_set_debug(self.file, self.line, self.func); ffi::ERR_set_error( ffi::ERR_GET_LIB(self.code), ffi::ERR_GET_REASON(self.code), ptr::null(), ); } } #[cfg(not(ossl300))] fn put_error(&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, ); } } /// 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 { if self.func.is_null() { return None; } let bytes = CStr::from_ptr(self.func).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. #[allow(clippy::option_as_ref_deref)] 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_REASON(self.code()))?, } write!( fmt, ":{}:{}:{}", self.file(), self.line(), self.data().unwrap_or("") ) } } impl error::Error for Error {} cfg_if! { if #[cfg(ossl300)] { use ffi::ERR_get_error_all; } else { #[allow(bad_style)] unsafe extern "C" fn ERR_get_error_all( file: *mut *const c_char, line: *mut c_int, func: *mut *const c_char, data: *mut *const c_char, flags: *mut c_int, ) -> c_ulong { let code = ffi::ERR_get_error_line_data(file, line, data, flags); *func = ffi::ERR_func_error_string(code); code } } } openssl-0.10.36/src/ex_data.rs000064400000000000000000000014430072674642500142520ustar 00000000000000use 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 { /// Creates an `Index` from a raw integer index. /// /// # Safety /// /// The caller must ensure that the index correctly maps to a `U` value stored in a `T`. pub unsafe fn from_raw(idx: c_int) -> Index { Index(idx, PhantomData) } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } openssl-0.10.36/src/fips.rs000064400000000000000000000012140072674642500136020ustar 00000000000000//! FIPS 140-2 support. //! //! See [OpenSSL's documentation] for details. //! //! [OpenSSL's documentation]: https://www.openssl.org/docs/fips/UserGuide-2.0.pdf use crate::cvt; use crate::error::ErrorStack; /// 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> { ffi::init(); 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.36/src/hash.rs000064400000000000000000000433070072674642500135750ustar 00000000000000use cfg_if::cfg_if; use std::ffi::CString; use std::fmt; use std::io; use std::io::prelude::*; use std::ops::{Deref, DerefMut}; use std::ptr; use crate::error::ErrorStack; use crate::nid::Nid; use crate::{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 { /// Creates a `MessageDigest` from a raw OpenSSL pointer. /// /// # Safety /// /// The caller must ensure the pointer is valid. 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)) } } } /// Returns the `MessageDigest` corresponding to an algorithm name. /// /// This corresponds to [`EVP_get_digestbyname`]. /// /// [`EVP_get_digestbyname`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html pub fn from_name(name: &str) -> Option { ffi::init(); let name = CString::new(name).ok()?; unsafe { let ptr = ffi::EVP_get_digestbyname(name.as_ptr()); if ptr.is_null() { None } else { Some(MessageDigest(ptr)) } } } pub fn null() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_md_null()) } } 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()) } } #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))] pub fn ripemd160() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_ripemd160()) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))] pub fn sm3() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sm3()) } } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_ptr(&self) -> *const ffi::EVP_MD { self.0 } /// The size of the digest in bytes. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn size(&self) -> usize { unsafe { ffi::EVP_MD_size(self.0) as usize } } /// The name of the digest. #[allow(clippy::trivially_copy_pass_by_ref)] 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, 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, ptr::null_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, 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, 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)) { 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/ const MD5_TESTS: [(&str, &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] #[allow(clippy::redundant_clone)] 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] #[cfg_attr(ossl300, ignore)] fn test_ripemd160() { let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")]; for test in tests.iter() { hash_test(MessageDigest::ripemd160(), test); } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))] #[test] fn test_sm3() { let tests = [( "616263", "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", )]; for test in tests.iter() { hash_test(MessageDigest::sm3(), test); } } #[test] fn from_nid() { assert_eq!( MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(), MessageDigest::sha256().as_ptr() ); } #[test] fn from_name() { assert_eq!( MessageDigest::from_name("SHA256").unwrap().as_ptr(), MessageDigest::sha256().as_ptr() ) } } openssl-0.10.36/src/lib.rs000064400000000000000000000135600072674642500134160ustar 00000000000000//! 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 3.3.x 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 (Homebrew) //! $ brew install openssl@1.1 //! //! # macOS (MacPorts) //! $ sudo port install openssl //! //! # macOS (pkgsrc) //! $ sudo pkgin install openssl //! //! # 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. //! * `OPENSSL_NO_VENDOR` - If set, always find OpenSSL in the system, even if the `vendored` feature is enabled. //! //! 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")] #![warn(rust_2018_idioms)] #[doc(inline)] pub use ffi::init; use libc::c_int; use crate::error::ErrorStack; #[macro_use] mod macros; mod bio; #[macro_use] mod util; pub mod aes; pub mod asn1; pub mod base64; pub mod bn; #[cfg(all(not(libressl), not(osslconf = "OPENSSL_NO_CMS")))] pub mod cms; pub mod conf; pub mod derive; pub mod dh; pub mod dsa; pub mod ec; pub mod ecdsa; pub mod encrypt; pub mod envelope; pub mod error; pub mod ex_data; #[cfg(not(any(libressl, ossl300)))] pub mod fips; pub mod hash; pub mod memcmp; pub mod nid; #[cfg(not(osslconf = "OPENSSL_NO_OCSP"))] 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.36/src/macros.rs000064400000000000000000000210660072674642500141340ustar 00000000000000macro_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, crate::error::ErrorStack> { unsafe { ffi::init(); let bio = crate::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, crate::error::ErrorStack> where F: FnOnce(&mut [u8]) -> Result { unsafe { ffi::init(); let mut cb = crate::util::CallbackState::new(callback); let bio = crate::bio::MemBioSlice::new(pem)?; cvt_p($f(bio.as_ptr(), ptr::null_mut(), Some(crate::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, crate::error::ErrorStack> { unsafe { let bio = crate::bio::MemBio::new()?; 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: crate::symm::Cipher, passphrase: &[u8] ) -> Result, crate::error::ErrorStack> { unsafe { let bio = crate::bio::MemBio::new()?; assert!(passphrase.len() <= ::libc::c_int::max_value() as usize); 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, crate::error::ErrorStack> { unsafe { let bio = crate::bio::MemBio::new()?; 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, crate::error::ErrorStack> { unsafe { let len = crate::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), ptr::null_mut()))?; let mut buf = vec![0; len as usize]; crate::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, crate::error::ErrorStack> { unsafe { ffi::init(); let len = ::std::cmp::min(der.len(), ::libc::c_long::max_value() as usize) as ::libc::c_long; crate::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, crate::error::ErrorStack> { unsafe { crate::init(); let bio = crate::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_types::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.36/src/memcmp.rs000064400000000000000000000045220072674642500141240ustar 00000000000000//! 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 comparison 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 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 comparison 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.36/src/nid.rs000064400000000000000000002102160072674642500134170ustar 00000000000000//! A collection of numerical identifiers for OpenSSL objects. use libc::{c_char, c_int}; use std::ffi::CStr; use std::str; use crate::cvt_p; use crate::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`. #[allow(clippy::trivially_copy_pass_by_ref)] 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`. #[allow(clippy::trivially_copy_pass_by_ref)] 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 #[allow(clippy::trivially_copy_pass_by_ref)] 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 #[allow(clippy::trivially_copy_pass_by_ref)] 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.36/src/ocsp.rs000064400000000000000000000263000072674642500136100ustar 00000000000000use bitflags::bitflags; use foreign_types::ForeignTypeRef; use libc::{c_int, c_long, c_ulong}; use std::mem; use std::ptr; use crate::asn1::Asn1GeneralizedTimeRef; use crate::error::ErrorStack; use crate::hash::MessageDigest; use crate::stack::StackRef; use crate::util::ForeignTypeRefExt; use crate::x509::store::X509StoreRef; use crate::x509::{X509Ref, X509}; use crate::{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 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); pub fn from_raw(raw: c_int) -> OcspResponseStatus { OcspResponseStatus(raw) } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct OcspCertStatus(c_int); impl OcspCertStatus { 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); pub fn from_raw(raw: c_int) -> OcspCertStatus { OcspCertStatus(raw) } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct OcspRevokedStatus(c_int); impl OcspRevokedStatus { 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 fn from_raw(raw: c_int) -> OcspRevokedStatus { OcspRevokedStatus(raw) } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } 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 = Asn1GeneralizedTimeRef::from_const_ptr_opt(revocation_time); Some(OcspStatus { status: OcspCertStatus(status), reason: OcspRevokedStatus(status), 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.36/src/pkcs12.rs000064400000000000000000000205360072674642500137540ustar 00000000000000//! PKCS #12 archives. use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::ffi::CString; use std::ptr; use crate::error::ErrorStack; use crate::nid::Nid; use crate::pkey::{HasPrivate, PKey, PKeyRef, Private}; use crate::stack::Stack; use crate::util::ForeignTypeExt; use crate::x509::{X509Ref, X509}; use crate::{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 = Stack::from_ptr_opt(chain); Ok(ParsedPkcs12 { pkey, cert, 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 crate::asn1::Asn1Time; use crate::hash::MessageDigest; use crate::nid::Nid; use crate::pkey::PKey; use crate::rsa::Rsa; use crate::x509::extension::KeyUsage; use crate::x509::{X509Name, X509}; use super::*; #[test] #[cfg_attr(ossl300, ignore)] // https://github.com/openssl/openssl/issues/11672 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] #[cfg_attr(ossl300, ignore)] // https://github.com/openssl/openssl/issues/11672 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] #[cfg_attr(ossl300, ignore)] // https://github.com/openssl/openssl/issues/11672 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.36/src/pkcs5.rs000064400000000000000000000225540072674642500137000ustar 00000000000000use libc::c_int; use std::ptr; use crate::cvt; use crate::error::ErrorStack; use crate::hash::MessageDigest; use crate::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. #[allow(clippy::useless_conversion)] 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, 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 crate::hash::MessageDigest; use crate::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() { 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.36/src/pkcs7.rs000064400000000000000000000363240072674642500137020ustar 00000000000000use bitflags::bitflags; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::mem; use std::ptr; use crate::bio::{MemBio, MemBioSlice}; use crate::error::ErrorStack; use crate::pkey::{HasPrivate, PKeyRef}; use crate::stack::{Stack, StackRef}; use crate::symm::Cipher; use crate::x509::store::X509StoreRef; use crate::x509::{X509Ref, X509}; use crate::{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 } from_der! { /// Deserializes a DER-encoded PKCS#7 signature /// /// This corresponds to [`d2i_PKCS7`]. /// /// [`d2i_PKCS7`]: https://www.openssl.org/docs/man1.1.0/man3/d2i_PKCS7.html from_der, Pkcs7, ffi::d2i_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 } to_der! { /// Serializes the data into a DER-encoded PKCS#7 structure. /// /// This corresponds to [`i2d_PKCS7`]. /// /// [`i2d_PKCS7`]: https://www.openssl.org/docs/man1.1.0/man3/i2d_PKCS7.html to_der, ffi::i2d_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(()) } /// Retrieve the signer's certificates from the PKCS#7 structure without verifying them. /// /// This corresponds to [`PKCS7_get0_signers`]. /// /// [`PKCS7_get0_signers`]: https://www.openssl.org/docs/man1.0.2/crypto/PKCS7_verify.html pub fn signers( &self, certs: &StackRef, flags: Pkcs7Flags, ) -> Result, ErrorStack> { unsafe { let ptr = cvt_p(ffi::PKCS7_get0_signers( self.as_ptr(), certs.as_ptr(), flags.bits, ))?; // The returned stack is owned by the caller, but the certs inside are not! Our stack interface can't deal // with that, so instead we just manually bump the refcount of the certs so that the whole stack is properly // owned. let stack = Stack::::from_ptr(ptr); for cert in &stack { mem::forget(cert.to_owned()); } Ok(stack) } } } #[cfg(test)] mod tests { use crate::hash::MessageDigest; use crate::pkcs7::{Pkcs7, Pkcs7Flags}; use crate::pkey::PKey; use crate::stack::Stack; use crate::symm::Cipher; use crate::x509::store::X509StoreBuilder; use crate::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 = "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!(output, message.as_bytes()); assert_eq!(content.expect("should be non-empty"), message.as_bytes()); } #[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 = "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!(output, message.as_bytes()); assert!(content.is_none()); } #[test] fn signers() { let cert = include_bytes!("../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let cert_digest = cert.digest(MessageDigest::sha256()).unwrap(); let certs = Stack::new().unwrap(); let message = "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 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, _) = Pkcs7::from_smime(signed.as_slice()).expect("should succeed"); let empty_certs = Stack::new().unwrap(); let signer_certs = pkcs7_decoded .signers(&empty_certs, flags) .expect("should succeed"); assert_eq!(empty_certs.len(), 0); assert_eq!(signer_certs.len(), 1); let signer_digest = signer_certs[0].digest(MessageDigest::sha256()).unwrap(); assert_eq!(*cert_digest, *signer_digest); } #[test] fn invalid_from_smime() { let input = String::from("Invalid SMIME Message"); let result = Pkcs7::from_smime(input.as_bytes()); assert!(result.is_err()); } } openssl-0.10.36/src/pkey.rs000064400000000000000000001054730072674642500136250ustar 00000000000000//! 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 //! use openssl::rsa::Rsa; //! use openssl::pkey::PKey; //! use std::str; //! //! 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 cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long}; use std::convert::TryFrom; use std::ffi::CString; use std::fmt; use std::mem; use std::ptr; use crate::bio::{MemBio, MemBioSlice}; use crate::dh::Dh; use crate::dsa::Dsa; use crate::ec::EcKey; use crate::error::ErrorStack; use crate::rsa::Rsa; use crate::symm::Cipher; use crate::util::{invoke_passwd_cb, CallbackState}; use crate::{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 { 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); #[cfg(ossl111)] pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519); #[cfg(ossl111)] pub const ED448: Id = Id(ffi::EVP_PKEY_ED448); #[cfg(ossl111)] pub const X25519: Id = Id(ffi::EVP_PKEY_X25519); #[cfg(ossl111)] pub const X448: Id = Id(ffi::EVP_PKEY_X448); /// Creates a `Id` from an integer representation. pub fn from_raw(value: c_int) -> Id { Id(value) } /// Returns the integer representation of the `Id`. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } /// 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 ToOwned for PKeyRef { type Owned = PKey; fn to_owned(&self) -> PKey { unsafe { EVP_PKEY_up_ref(self.as_ptr()); PKey::from_ptr(self.as_ptr()) } } } 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 } } /// Raw byte representation of a public key /// /// This function only works for algorithms that support raw public keys. /// Currently this is: X25519, ED25519, X448 or ED448 /// /// This corresponds to [`EVP_PKEY_get_raw_public_key`]. /// /// [`EVP_PKEY_get_raw_public_key`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_get_raw_public_key.html #[cfg(ossl111)] pub fn raw_public_key(&self) -> Result, ErrorStack> { unsafe { let mut len = 0; cvt(ffi::EVP_PKEY_get_raw_public_key( self.as_ptr(), ptr::null_mut(), &mut len, ))?; let mut buf = vec![0u8; len]; cvt(ffi::EVP_PKEY_get_raw_public_key( self.as_ptr(), buf.as_mut_ptr(), &mut len, ))?; buf.truncate(len); Ok(buf) } } } 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 } /// Raw byte representation of a private key /// /// This function only works for algorithms that support raw private keys. /// Currently this is: HMAC, X25519, ED25519, X448 or ED448 /// /// This corresponds to [`EVP_PKEY_get_raw_private_key`]. /// /// [`EVP_PKEY_get_raw_private_key`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_get_raw_private_key.html #[cfg(ossl111)] pub fn raw_private_key(&self) -> Result, ErrorStack> { unsafe { let mut len = 0; cvt(ffi::EVP_PKEY_get_raw_private_key( self.as_ptr(), ptr::null_mut(), &mut len, ))?; let mut buf = vec![0u8; len]; cvt(ffi::EVP_PKEY_get_raw_private_key( self.as_ptr(), buf.as_mut_ptr(), &mut len, ))?; buf.truncate(len); Ok(buf) } } /// Serializes a private key into a DER-formatted PKCS#8, using the supplied password to /// encrypt the key. /// /// # Panics /// /// Panics if `passphrase` contains an embedded null. pub fn private_key_to_pkcs8_passphrase( &self, cipher: Cipher, passphrase: &[u8], ) -> Result, ErrorStack> { unsafe { let bio = MemBio::new()?; let len = passphrase.len(); let passphrase = CString::new(passphrase).unwrap(); cvt(ffi::i2d_PKCS8PrivateKey_bio( bio.as_ptr(), self.as_ptr(), cipher.as_ptr(), passphrase.as_ptr() as *const _ as *mut _, len as ::libc::c_int, None, ptr::null_mut(), ))?; Ok(bio.get_buf().to_owned()) } } } impl fmt::Debug for PKey { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let alg = match self.id() { Id::RSA => "RSA", Id::HMAC => "HMAC", Id::DSA => "DSA", Id::DH => "DH", Id::EC => "EC", #[cfg(ossl111)] Id::ED25519 => "Ed25519", #[cfg(ossl111)] Id::ED448 => "Ed448", _ => "unknown", }; fmt.debug_struct("PKey").field("algorithm", &alg).finish() // TODO: Print details for each specific type of key } } impl Clone for PKey { fn clone(&self) -> PKey { PKeyRef::to_owned(self) } } 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)] #[allow(clippy::trivially_copy_pass_by_ref)] pub fn cmac(cipher: &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)) } } #[cfg(ossl111)] fn generate_eddsa(nid: c_int) -> Result, ErrorStack> { unsafe { let kctx = cvt_p(ffi::EVP_PKEY_CTX_new_id(nid, ptr::null_mut()))?; let ret = cvt(ffi::EVP_PKEY_keygen_init(kctx)); if let Err(e) = ret { ffi::EVP_PKEY_CTX_free(kctx); return Err(e); } let mut key = ptr::null_mut(); let ret = cvt(ffi::EVP_PKEY_keygen(kctx, &mut key)); ffi::EVP_PKEY_CTX_free(kctx); if let Err(e) = ret { return Err(e); } Ok(PKey::from_ptr(key)) } } /// Generates a new private Ed25519 key #[cfg(ossl111)] pub fn generate_x25519() -> Result, ErrorStack> { PKey::generate_eddsa(ffi::EVP_PKEY_X25519) } /// Generates a new private Ed448 key #[cfg(ossl111)] pub fn generate_x448() -> Result, ErrorStack> { PKey::generate_eddsa(ffi::EVP_PKEY_X448) } /// Generates a new private Ed25519 key #[cfg(ossl111)] pub fn generate_ed25519() -> Result, ErrorStack> { PKey::generate_eddsa(ffi::EVP_PKEY_ED25519) } /// Generates a new private Ed448 key #[cfg(ossl111)] pub fn generate_ed448() -> Result, ErrorStack> { PKey::generate_eddsa(ffi::EVP_PKEY_ED448) } 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 unencrypted private key. /// /// This method is mainly for interoperability reasons. Encrypted keyfiles should be preferred. pub fn private_key_from_pkcs8(der: &[u8]) -> Result, ErrorStack> { unsafe { ffi::init(); let len = der.len().min(c_long::max_value() as usize) as c_long; let p8inf = cvt_p(ffi::d2i_PKCS8_PRIV_KEY_INFO( ptr::null_mut(), &mut der.as_ptr(), len, ))?; let res = cvt_p(ffi::EVP_PKCS82PKEY(p8inf)).map(|p| PKey::from_ptr(p)); ffi::PKCS8_PRIV_KEY_INFO_free(p8inf); res } } /// 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)) } } /// Creates a private key from its raw byte representation /// /// Algorithm types that support raw private keys are HMAC, X25519, ED25519, X448 or ED448 /// /// This corresponds to [`EVP_PKEY_new_raw_private_key`]. /// /// [`EVP_PKEY_new_raw_private_key`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_private_key.html #[cfg(ossl111)] pub fn private_key_from_raw_bytes( bytes: &[u8], key_type: Id, ) -> Result, ErrorStack> { unsafe { ffi::init(); cvt_p(ffi::EVP_PKEY_new_raw_private_key( key_type.as_raw(), ptr::null_mut(), bytes.as_ptr(), bytes.len(), )) .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 } /// Creates a public key from its raw byte representation /// /// Algorithm types that support raw public keys are X25519, ED25519, X448 or ED448 /// /// This corresponds to [`EVP_PKEY_new_raw_public_key`]. /// /// [`EVP_PKEY_new_raw_public_key`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_PKEY_new_raw_public_key.html #[cfg(ossl111)] pub fn public_key_from_raw_bytes( bytes: &[u8], key_type: Id, ) -> Result, ErrorStack> { unsafe { ffi::init(); cvt_p(ffi::EVP_PKEY_new_raw_public_key( key_type.as_raw(), ptr::null_mut(), bytes.as_ptr(), bytes.len(), )) .map(|p| PKey::from_ptr(p)) } } } cfg_if! { if #[cfg(any(ossl110, libressl270))] { use ffi::EVP_PKEY_up_ref; } else { #[allow(bad_style)] unsafe extern "C" fn EVP_PKEY_up_ref(pkey: *mut ffi::EVP_PKEY) { ffi::CRYPTO_add_lock( &mut (*pkey).references, 1, ffi::CRYPTO_LOCK_EVP_PKEY, "pkey.rs\0".as_ptr() as *const _, line!() as c_int, ); } } } impl TryFrom> for PKey { type Error = ErrorStack; fn try_from(ec_key: EcKey) -> Result, ErrorStack> { PKey::from_ec_key(ec_key) } } impl TryFrom> for EcKey { type Error = ErrorStack; fn try_from(pkey: PKey) -> Result, ErrorStack> { pkey.ec_key() } } impl TryFrom> for PKey { type Error = ErrorStack; fn try_from(rsa: Rsa) -> Result, ErrorStack> { PKey::from_rsa(rsa) } } impl TryFrom> for Rsa { type Error = ErrorStack; fn try_from(pkey: PKey) -> Result, ErrorStack> { pkey.rsa() } } impl TryFrom> for PKey { type Error = ErrorStack; fn try_from(dsa: Dsa) -> Result, ErrorStack> { PKey::from_dsa(dsa) } } impl TryFrom> for Dsa { type Error = ErrorStack; fn try_from(pkey: PKey) -> Result, ErrorStack> { pkey.dsa() } } impl TryFrom> for PKey { type Error = ErrorStack; fn try_from(dh: Dh) -> Result, ErrorStack> { PKey::from_dh(dh) } } impl TryFrom> for Dh { type Error = ErrorStack; fn try_from(pkey: PKey) -> Result, ErrorStack> { pkey.dh() } } #[cfg(test)] mod tests { use std::convert::TryInto; use crate::dh::Dh; use crate::dsa::Dsa; use crate::ec::EcKey; use crate::nid::Nid; use crate::rsa::Rsa; use crate::symm::Cipher; use super::*; #[cfg(ossl111)] use crate::rand::rand_bytes; #[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_unencrypted_pkcs8() { let key = include_bytes!("../test/pkcs8-nocrypt.der"); PKey::private_key_from_pkcs8(key).unwrap(); } #[test] fn test_encrypted_pkcs8_passphrase() { let key = include_bytes!("../test/pkcs8.der"); PKey::private_key_from_pkcs8_passphrase(key, b"mypass").unwrap(); let rsa = Rsa::generate(2048).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); let der = pkey .private_key_to_pkcs8_passphrase(Cipher::aes_128_cbc(), b"mypass") .unwrap(); let pkey2 = PKey::private_key_from_pkcs8_passphrase(&der, b"mypass").unwrap(); assert_eq!( pkey.private_key_to_der().unwrap(), pkey2.private_key_to_der().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()); } #[test] fn test_rsa_conversion() { let rsa = Rsa::generate(2048).unwrap(); let pkey: PKey = rsa.clone().try_into().unwrap(); let rsa_: Rsa = pkey.try_into().unwrap(); // Eq is missing assert_eq!(rsa.p(), rsa_.p()); assert_eq!(rsa.q(), rsa_.q()); } #[test] fn test_dsa_conversion() { let dsa = Dsa::generate(2048).unwrap(); let pkey: PKey = dsa.clone().try_into().unwrap(); let dsa_: Dsa = pkey.try_into().unwrap(); // Eq is missing assert_eq!(dsa.priv_key(), dsa_.priv_key()); } #[test] fn test_ec_key_conversion() { let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::X9_62_PRIME256V1).unwrap(); let ec_key = EcKey::generate(&group).unwrap(); let pkey: PKey = ec_key.clone().try_into().unwrap(); let ec_key_: EcKey = pkey.try_into().unwrap(); // Eq is missing assert_eq!(ec_key.private_key(), ec_key_.private_key()); } #[test] fn test_dh_conversion() { let dh_params = include_bytes!("../test/dhparams.pem"); let dh_params = Dh::params_from_pem(dh_params).unwrap(); let dh = dh_params.generate_key().unwrap(); // Clone is missing for Dh, save the parameters let p = dh.prime_p().to_owned().unwrap(); let q = dh.prime_q().map(|q| q.to_owned().unwrap()); let g = dh.generator().to_owned().unwrap(); let pkey: PKey = dh.try_into().unwrap(); let dh_: Dh = pkey.try_into().unwrap(); // Eq is missing assert_eq!(&p, dh_.prime_p()); assert_eq!(q, dh_.prime_q().map(|q| q.to_owned().unwrap())); assert_eq!(&g, dh_.generator()); } #[cfg(ossl111)] fn test_raw_public_key(gen: fn() -> Result, ErrorStack>, key_type: Id) { // Generate a new key let key = gen().unwrap(); // Get the raw bytes, and create a new key from the raw bytes let raw = key.raw_public_key().unwrap(); let from_raw = PKey::public_key_from_raw_bytes(&raw, key_type).unwrap(); // Compare the der encoding of the original and raw / restored public key assert_eq!( key.public_key_to_der().unwrap(), from_raw.public_key_to_der().unwrap() ); } #[cfg(ossl111)] fn test_raw_private_key(gen: fn() -> Result, ErrorStack>, key_type: Id) { // Generate a new key let key = gen().unwrap(); // Get the raw bytes, and create a new key from the raw bytes let raw = key.raw_private_key().unwrap(); let from_raw = PKey::private_key_from_raw_bytes(&raw, key_type).unwrap(); // Compare the der encoding of the original and raw / restored public key assert_eq!( key.private_key_to_der().unwrap(), from_raw.private_key_to_der().unwrap() ); } #[cfg(ossl111)] #[test] fn test_raw_public_key_bytes() { test_raw_public_key(PKey::generate_x25519, Id::X25519); test_raw_public_key(PKey::generate_ed25519, Id::ED25519); test_raw_public_key(PKey::generate_x448, Id::X448); test_raw_public_key(PKey::generate_ed448, Id::ED448); } #[cfg(ossl111)] #[test] fn test_raw_private_key_bytes() { test_raw_private_key(PKey::generate_x25519, Id::X25519); test_raw_private_key(PKey::generate_ed25519, Id::ED25519); test_raw_private_key(PKey::generate_x448, Id::X448); test_raw_private_key(PKey::generate_ed448, Id::ED448); } #[cfg(ossl111)] #[test] fn test_raw_hmac() { let mut test_bytes = vec![0u8; 32]; rand_bytes(&mut test_bytes).unwrap(); let hmac_key = PKey::hmac(&test_bytes).unwrap(); assert!(hmac_key.raw_public_key().is_err()); let key_bytes = hmac_key.raw_private_key().unwrap(); assert_eq!(key_bytes, test_bytes); } #[cfg(ossl111)] #[test] fn test_raw_key_fail() { // Getting a raw byte representation will not work with Nist curves let group = crate::ec::EcGroup::from_curve_name(Nid::SECP256K1).unwrap(); let ec_key = EcKey::generate(&group).unwrap(); let pkey = PKey::from_ec_key(ec_key).unwrap(); assert!(pkey.raw_private_key().is_err()); assert!(pkey.raw_public_key().is_err()); } } openssl-0.10.36/src/rand.rs000064400000000000000000000030310072674642500135640ustar 00000000000000//! 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 libc::c_int; use crate::cvt; use crate::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.36/src/rsa.rs000064400000000000000000000725510072674642500134420ustar 00000000000000//! 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 //! use openssl::rsa::{Rsa, Padding}; //! //! 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 cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; use std::mem; use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; use crate::pkey::{HasPrivate, HasPublic, Private, Public}; use crate::util::ForeignTypeRefExt; use crate::{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 { 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); /// Creates a `Padding` from an integer representation. pub fn from_raw(value: c_int) -> Padding { Padding(value) } /// Returns the integer representation of `Padding`. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } 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_const_ptr(d) } } /// 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()); BigNumRef::from_const_ptr_opt(p) } } /// 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); BigNumRef::from_const_ptr_opt(q) } } /// 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()); BigNumRef::from_const_ptr_opt(dp) } } /// 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()); BigNumRef::from_const_ptr_opt(dq) } } /// 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); BigNumRef::from_const_ptr_opt(qi) } } /// 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_const_ptr(n) } } /// 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_const_ptr(e) } } } 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()` #[allow(clippy::too_many_arguments, clippy::many_single_char_names)] 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 crate::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 = b"Hello, world!"; 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!(&decrypted[..len], msg); } #[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 = b"foo"; 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] #[allow(clippy::redundant_clone)] 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.36/src/sha.rs000064400000000000000000000324600072674642500134230ustar 00000000000000//! 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 irreversible. //! 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 //! use openssl::sha; //! //! 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 would 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 //! use openssl::sha::sha256; //! //! let hash = sha256(b"your data or message"); //! println!("Hash = {}", hex::encode(hash)); //! ``` use cfg_if::cfg_if; use libc::c_void; use std::mem::MaybeUninit; /// 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 = MaybeUninit::<[u8; 20]>::uninit(); ffi::SHA1(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); hash.assume_init() } } /// Computes the SHA224 hash of some data. #[inline] pub fn sha224(data: &[u8]) -> [u8; 28] { unsafe { let mut hash = MaybeUninit::<[u8; 28]>::uninit(); ffi::SHA224(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); hash.assume_init() } } /// Computes the SHA256 hash of some data. #[inline] pub fn sha256(data: &[u8]) -> [u8; 32] { unsafe { let mut hash = MaybeUninit::<[u8; 32]>::uninit(); ffi::SHA256(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); hash.assume_init() } } /// Computes the SHA384 hash of some data. #[inline] pub fn sha384(data: &[u8]) -> [u8; 48] { unsafe { let mut hash = MaybeUninit::<[u8; 48]>::uninit(); ffi::SHA384(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); hash.assume_init() } } /// Computes the SHA512 hash of some data. #[inline] pub fn sha512(data: &[u8]) -> [u8; 64] { unsafe { let mut hash = MaybeUninit::<[u8; 64]>::uninit(); ffi::SHA512(data.as_ptr(), data.len(), hash.as_mut_ptr() as *mut _); hash.assume_init() } } cfg_if! { if #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] { /// 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. #[derive(Clone)] pub struct Sha1(ffi::SHA_CTX); impl Default for Sha1 { #[inline] fn default() -> Sha1 { Sha1::new() } } impl Sha1 { /// Creates a new hasher. #[inline] pub fn new() -> Sha1 { unsafe { let mut ctx = MaybeUninit::uninit(); ffi::SHA1_Init( ctx.as_mut_ptr()); Sha1(ctx.assume_init()) } } /// 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 = MaybeUninit::<[u8; 20]>::uninit(); ffi::SHA1_Final(hash.as_mut_ptr() as *mut _, &mut self.0); hash.assume_init() } } } /// An object which calculates a SHA224 hash of some data. #[derive(Clone)] pub struct Sha224(ffi::SHA256_CTX); impl Default for Sha224 { #[inline] fn default() -> Sha224 { Sha224::new() } } impl Sha224 { /// Creates a new hasher. #[inline] pub fn new() -> Sha224 { unsafe { let mut ctx = MaybeUninit::uninit(); ffi::SHA224_Init(ctx.as_mut_ptr()); Sha224(ctx.assume_init()) } } /// 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 = MaybeUninit::<[u8; 28]>::uninit(); ffi::SHA224_Final(hash.as_mut_ptr() as *mut _, &mut self.0); hash.assume_init() } } } /// An object which calculates a SHA256 hash of some data. #[derive(Clone)] pub struct Sha256(ffi::SHA256_CTX); impl Default for Sha256 { #[inline] fn default() -> Sha256 { Sha256::new() } } impl Sha256 { /// Creates a new hasher. #[inline] pub fn new() -> Sha256 { unsafe { let mut ctx = MaybeUninit::uninit(); ffi::SHA256_Init(ctx.as_mut_ptr()); Sha256(ctx.assume_init()) } } /// 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 = MaybeUninit::<[u8; 32]>::uninit(); ffi::SHA256_Final(hash.as_mut_ptr() as *mut _, &mut self.0); hash.assume_init() } } } /// An object which calculates a SHA384 hash of some data. #[derive(Clone)] pub struct Sha384(ffi::SHA512_CTX); impl Default for Sha384 { #[inline] fn default() -> Sha384 { Sha384::new() } } impl Sha384 { /// Creates a new hasher. #[inline] pub fn new() -> Sha384 { unsafe { let mut ctx = MaybeUninit::uninit(); ffi::SHA384_Init(ctx.as_mut_ptr()); Sha384(ctx.assume_init()) } } /// 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 = MaybeUninit::<[u8; 48]>::uninit(); ffi::SHA384_Final(hash.as_mut_ptr() as *mut _, &mut self.0); hash.assume_init() } } } /// An object which calculates a SHA512 hash of some data. #[derive(Clone)] pub struct Sha512(ffi::SHA512_CTX); impl Default for Sha512 { #[inline] fn default() -> Sha512 { Sha512::new() } } impl Sha512 { /// Creates a new hasher. #[inline] pub fn new() -> Sha512 { unsafe { let mut ctx = MaybeUninit::uninit(); ffi::SHA512_Init(ctx.as_mut_ptr()); Sha512(ctx.assume_init()) } } /// 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= MaybeUninit::<[u8; 64]>::uninit(); ffi::SHA512_Final(hash.as_mut_ptr() as *mut _, &mut self.0); hash.assume_init() } } } } } #[cfg(test)] mod test { use super::*; #[test] fn standalone_1() { let data = b"abc"; let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; assert_eq!(hex::encode(sha1(data)), expected); } #[test] #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] 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] #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] fn cloning_allows_incremental_hashing() { let expected = "a9993e364706816aba3e25717850c26c9cd0d89d"; let mut hasher = Sha1::new(); hasher.update(b"a"); let mut incr_hasher = hasher.clone(); incr_hasher.update(b"bc"); assert_eq!(hex::encode(incr_hasher.finish()), expected); assert_ne!(hex::encode(hasher.finish()), expected); } #[test] fn standalone_224() { let data = b"abc"; let expected = "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"; assert_eq!(hex::encode(sha224(data)), expected); } #[test] #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] 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] #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] 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] #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] 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] #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] 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.36/src/sign.rs000064400000000000000000000711350072674642500136120ustar 00000000000000//! 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 cfg_if::cfg_if; use foreign_types::ForeignTypeRef; use libc::c_int; use std::io::{self, Write}; use std::marker::PhantomData; use std::ptr; use crate::error::ErrorStack; use crate::hash::MessageDigest; use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; use crate::rsa::Padding; use crate::{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); } } } #[allow(clippy::len_without_is_empty)] impl<'a> Signer<'a> { /// Creates a new `Signer`. /// /// This cannot be used with Ed25519 or Ed448 keys. Please refer to /// `new_without_digest`. /// /// 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 is the only way to create a `Verifier` for Ed25519 or Ed448 keys. /// It can also 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) } 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`. /// /// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming. /// Use `sign_oneshot` instead. /// /// 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 { self.len_intern() } #[cfg(not(ossl111))] fn len_intern(&self) -> Result { unsafe { let mut len = 0; cvt(ffi::EVP_DigestSignFinal( self.md_ctx, ptr::null_mut(), &mut len, ))?; Ok(len) } } #[cfg(ossl111)] fn len_intern(&self) -> Result { unsafe { let mut len = 0; cvt(ffi::EVP_DigestSign( self.md_ctx, ptr::null_mut(), &mut len, ptr::null(), 0, ))?; 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) } /// Signs the data in data_buf and writes the signature into the buffer sig_buf, returning the /// number of bytes written. /// /// For PureEdDSA (Ed25519 and Ed448 keys) this is the only way to sign data. /// /// 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_DigestSign`]. /// /// [`EVP_DigestSign`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestSign.html #[cfg(ossl111)] pub fn sign_oneshot( &mut self, sig_buf: &mut [u8], data_buf: &[u8], ) -> Result { unsafe { let mut sig_len = sig_buf.len(); cvt(ffi::EVP_DigestSign( self.md_ctx, sig_buf.as_mut_ptr() as *mut _, &mut sig_len, data_buf.as_ptr() as *const _, data_buf.len(), ))?; Ok(sig_len) } } /// Returns the signature. /// /// This is a simple convenience wrapper over `len` and `sign_oneshot`. #[cfg(ossl111)] pub fn sign_oneshot_to_vec(&mut self, data_buf: &[u8]) -> Result, ErrorStack> { let mut sig_buf = vec![0; self.len()?]; let len = self.sign_oneshot(&mut sig_buf, data_buf)?; // The advertised length is not always equal to the real length for things like DSA sig_buf.truncate(len); Ok(sig_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`. /// /// This cannot be used with Ed25519 or Ed448 keys. Please refer to /// `new_without_digest`. /// /// 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, { Verifier::new_intern(Some(type_), pkey) } /// Creates a new `Verifier` without a digest. /// /// This is the only way to create a `Verifier` for Ed25519 or Ed448 keys. /// /// OpenSSL documentation at [`EVP_DigestVerifyInit`]. /// /// [`EVP_DigestVerifyInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestVerifyInit.html pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> where T: HasPublic, { Verifier::new_intern(None, pkey) } fn new_intern( type_: Option, 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_.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(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`. /// /// Please note that PureEdDSA (Ed25519 and Ed448 keys) do not support streaming. /// Use `verify_oneshot` instead. /// /// 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()), } } } /// Determines if the data given in buf matches the provided signature. /// /// OpenSSL documentation at [`EVP_DigestVerify`]. /// /// [`EVP_DigestVerify`]: https://www.openssl.org/docs/man1.1.1/man3/EVP_DigestVerify.html #[cfg(ossl111)] pub fn verify_oneshot(&mut self, signature: &[u8], buf: &[u8]) -> Result { unsafe { let r = ffi::EVP_DigestVerify( self.md_ctx, signature.as_ptr() as *const _, signature.len(), buf.as_ptr() as *const _, buf.len(), ); match r { 1 => Ok(true), 0 => { ErrorStack::get(); 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 crate::ec::{EcGroup, EcKey}; use crate::hash::MessageDigest; use crate::nid::Nid; use crate::pkey::PKey; use crate::rsa::{Padding, Rsa}; #[cfg(ossl111)] use crate::sign::RsaPssSaltlen; use crate::sign::{Signer, Verifier}; const INPUT: &str = "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ 654841694f6a457a4d4441344d546b7a4f44417344516f67496d6830644841364c79396c654746746347786c4c\ 6d4e76625339706331397962323930496a7030636e566c6651"; const SIGNATURE: &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)] #[cfg_attr(ossl300, ignore)] // https://github.com/openssl/openssl/issues/11671 fn test_cmac() { let cipher = crate::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] #[cfg(ossl111)] fn eddsa() { let key = PKey::generate_ed25519().unwrap(); let mut signer = Signer::new_without_digest(&key).unwrap(); let signature = signer.sign_oneshot_to_vec(b"hello world").unwrap(); let mut verifier = Verifier::new_without_digest(&key).unwrap(); assert!(verifier.verify_oneshot(&signature, b"hello world").unwrap()); } #[test] #[cfg(ossl111)] 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.36/src/srtp.rs000064400000000000000000000042410072674642500136340ustar 00000000000000use crate::stack::Stackable; use foreign_types::ForeignTypeRef; use libc::c_ulong; 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 { 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); #[cfg(ossl110)] pub const SRTP_AEAD_AES_128_GCM: SrtpProfileId = SrtpProfileId(ffi::SRTP_AEAD_AES_128_GCM); #[cfg(ossl110)] pub const SRTP_AEAD_AES_256_GCM: SrtpProfileId = SrtpProfileId(ffi::SRTP_AEAD_AES_256_GCM); /// Creates a `SrtpProfileId` from an integer representation. pub fn from_raw(value: c_ulong) -> SrtpProfileId { SrtpProfileId(value) } /// Returns the integer representation of `SrtpProfileId`. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_ulong { self.0 } } openssl-0.10.36/src/ssl/bio.rs000064400000000000000000000177070072674642500142310ustar 00000000000000use cfg_if::cfg_if; use ffi::{ self, BIO_clear_retry_flags, BIO_new, BIO_set_retry_read, BIO_set_retry_write, BIO, BIO_CTRL_DGRAM_QUERY_MTU, 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::panic::{catch_unwind, AssertUnwindSafe}; use std::ptr; use std::slice; use crate::cvt_p; use crate::error::ErrorStack; pub struct StreamState { pub stream: S, pub error: Option, pub panic: Option>, pub dtls_mtu_size: c_long, } /// Safe wrapper for BIO_METHOD pub struct BioMethod(BIO_METHOD); impl BioMethod { fn new() -> Result { BIO_METHOD::new::().map(BioMethod) } } 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, error: None, panic: None, dtls_mtu_size: 0, }); 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); 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 = &*(BIO_get_data(bio) as *const StreamState); &state.stream } pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { &mut state(bio).stream } pub unsafe fn set_dtls_mtu_size(bio: *mut BIO, mtu_size: usize) { if mtu_size as u64 > c_long::max_value() as u64 { panic!( "Given MTU size {} can't be represented in a positive `c_long` range", mtu_size ) } state::(bio).dtls_mtu_size = mtu_size as c_long; } 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 } } } #[allow(clippy::match_like_matches_macro)] // matches macro requires rust 1.42.0 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 { let state = state::(bio); if cmd == BIO_CTRL_FLUSH { 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 if cmd == BIO_CTRL_DGRAM_QUERY_MTU { state.dtls_mtu_size } 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}; use crate::cvt; #[allow(bad_style)] unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} #[allow(bad_style, clippy::upper_case_acronyms)] struct BIO_METHOD(*mut ffi::BIO_METHOD); impl BIO_METHOD { fn new() -> Result { unsafe { let ptr = cvt_p(ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _))?; let method = BIO_METHOD(ptr); cvt(ffi::BIO_meth_set_write(method.0, bwrite::))?; cvt(ffi::BIO_meth_set_read(method.0, bread::))?; cvt(ffi::BIO_meth_set_puts(method.0, bputs::))?; cvt(ffi::BIO_meth_set_ctrl(method.0, ctrl::))?; cvt(ffi::BIO_meth_set_create(method.0, create))?; cvt(ffi::BIO_meth_set_destroy(method.0, destroy::))?; Ok(method) } } 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, clippy::upper_case_acronyms)] struct BIO_METHOD(*mut ffi::BIO_METHOD); impl BIO_METHOD { fn new() -> Result { 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, }); Ok(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.36/src/ssl/callbacks.rs000064400000000000000000000467160072674642500154010ustar 00000000000000use cfg_if::cfg_if; 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 crate::dh::Dh; #[cfg(all(ossl101, not(ossl110)))] use crate::ec::EcKey; use crate::error::ErrorStack; use crate::pkey::Params; #[cfg(any(ossl102, libressl261))] use crate::ssl::AlpnError; use crate::ssl::{ try_get_session_ctx_index, SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, SslSessionRef, }; #[cfg(ossl111)] use crate::ssl::{ClientHelloResponse, ExtensionContext}; #[cfg(ossl111)] use crate::util::ForeignTypeRefExt; #[cfg(ossl111)] use crate::x509::X509Ref; use crate::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.is_null() { None } else { Some(CStr::from_ptr(identity).to_bytes()) }; // 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 session_ctx_index = try_get_session_ctx_index().expect("BUG: session context index initialization failed"); 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 session_ctx_index = try_get_session_ctx_index().expect("BUG: session context index initialization failed"); 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_const_ptr(ssl); 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.36/src/ssl/connector.rs000064400000000000000000000556700072674642500154530ustar 00000000000000use cfg_if::cfg_if; use std::io::{Read, Write}; use std::ops::{Deref, DerefMut}; use crate::dh::Dh; use crate::error::ErrorStack; use crate::ssl::{ HandshakeError, Ssl, SslContext, SslContextBuilder, SslContextRef, SslMethod, SslMode, SslOptions, SslRef, SslStream, SslVerifyMode, }; use crate::version; const FFDHE_2048: &str = " -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a 87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS----- "; #[allow(clippy::inconsistent_digit_grouping, clippy::unusual_byte_groupings)] 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; 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, Debug)] 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, }) } /// Consumes the `SslConnector`, returning the inner raw `SslContext`. pub fn into_context(self) -> SslContext { self.0 } /// Returns a shared reference to the inner raw `SslContext`. pub fn context(&self) -> &SslContextRef { &*self.0 } } /// 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; } /// Returns an `Ssl` configured to connect to the provided domain. /// /// The domain is used for SNI and hostname verification if enabled. pub fn into_ssl(mut self, domain: &str) -> Result { if self.sni { self.ssl.set_hostname(domain)?; } if self.verify_hostname { setup_verify_hostname(&mut self.ssl, domain)?; } Ok(self.ssl) } /// Initiates a client-side TLS session on a stream. /// /// The domain is used for SNI and hostname verification if enabled. pub fn connect(self, domain: &str, stream: S) -> Result, HandshakeError> where S: Read + Write, { self.into_ssl(domain)?.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 version 5 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_v5(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_options(SslOptions::NO_TLSV1 | SslOptions::NO_TLSV1_1); let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?; ctx.set_tmp_dh(&dh)?; setup_curves(&mut ctx)?; ctx.set_cipher_list( "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:\ ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" )?; #[cfg(ossl111)] ctx.set_ciphersuites( "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256", )?; Ok(SslAcceptorBuilder(ctx)) } /// Creates a new builder configured to connect to modern clients. /// /// This corresponds to the modern configuration of version 5 of Mozilla's server side TLS recommendations. /// See its [documentation][docs] for more details on specifics. /// /// Requires OpenSSL 1.1.1 or newer. /// /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS #[cfg(ossl111)] pub fn mozilla_modern_v5(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_options(SslOptions::NO_SSL_MASK & !SslOptions::NO_TLSV1_3); ctx.set_ciphersuites( "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256", )?; Ok(SslAcceptorBuilder(ctx)) } /// 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 version 4 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 // FIXME remove in next major version pub fn mozilla_intermediate(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_options(SslOptions::CIPHER_SERVER_PREFERENCE); #[cfg(ossl111)] ctx.set_options(SslOptions::NO_TLSV1_3); let dh = Dh::params_from_pem(FFDHE_2048.as_bytes())?; 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 version 4 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 // FIXME remove in next major version pub fn mozilla_modern(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_options( SslOptions::CIPHER_SERVER_PREFERENCE | 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) } /// Consumes the `SslAcceptor`, returning the inner raw `SslContext`. pub fn into_context(self) -> SslContext { self.0 } /// Returns a shared reference to the inner raw `SslContext`. pub fn context(&self) -> &SslContextRef { &*self.0 } } /// 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)] { #[allow(clippy::unnecessary_wraps)] 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 crate::ec::EcKey; use crate::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 crate::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(); let hostname_idx = verify::try_get_hostname_idx()?; ssl.set_ex_data(*hostname_idx, domain); Ok(()) } mod verify { use std::net::IpAddr; use std::str; use once_cell::sync::OnceCell; use crate::error::ErrorStack; use crate::ex_data::Index; use crate::nid::Nid; use crate::ssl::Ssl; use crate::stack::Stack; use crate::x509::{ GeneralName, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, X509VerifyResult, }; static HOSTNAME_IDX: OnceCell> = OnceCell::new(); pub fn try_get_hostname_idx() -> Result<&'static Index, ErrorStack> { HOSTNAME_IDX.get_or_try_init(Ssl::new_ex_index) } pub fn verify_callback(preverify_ok: bool, x509_ctx: &mut X509StoreContextRef) -> bool { if !preverify_ok || x509_ctx.error_depth() != 0 { return preverify_ok; } let hostname_idx = try_get_hostname_idx().expect("failed to initialize hostname index"); 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.eq_ignore_ascii_case(hostname)) } fn matches_wildcard(pattern: &str, hostname: &str) -> Option { 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, and must be the entire first label if wildcard_location != 0 || wildcard_end != wildcard_location + 1 { return None; } let hostname_label_end = match hostname.find('.') { Some(l) => l, None => return None, }; let pattern_after_wildcard = &pattern[wildcard_end..]; let hostname_after_wildcard = &hostname[hostname_label_end..]; Some(pattern_after_wildcard.eq_ignore_ascii_case(hostname_after_wildcard)) } fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { match *expected { IpAddr::V4(ref addr) => actual == addr.octets(), IpAddr::V6(ref addr) => actual == addr.octets(), } } #[test] fn test_dns_match() { use crate::ssl::connector::verify::matches_dns; assert!(matches_dns("website.tld", "website.tld")); // A name should match itself. assert!(matches_dns("website.tld", "wEbSiTe.tLd")); // DNS name matching ignores case of hostname. assert!(matches_dns("wEbSiTe.TlD", "website.tld")); // DNS name matching ignores case of subject. assert!(matches_dns("xn--bcher-kva.tld", "xn--bcher-kva.tld")); // Likewise, nothing special to punycode names. assert!(matches_dns("xn--bcher-kva.tld", "xn--BcHer-Kva.tLd")); // And punycode must be compared similarly case-insensitively. assert!(matches_dns("*.example.com", "subdomain.example.com")); // Wildcard matching works. assert!(matches_dns("*.eXaMpLe.cOm", "subdomain.example.com")); // Wildcard matching ignores case of subject. assert!(matches_dns("*.example.com", "sUbDoMaIn.eXaMpLe.cOm")); // Wildcard matching ignores case of hostname. assert!(!matches_dns("prefix*.example.com", "p.example.com")); // Prefix longer than the label works and does not match. assert!(!matches_dns("*suffix.example.com", "s.example.com")); // Suffix longer than the label works and does not match. assert!(!matches_dns("prefix*.example.com", "prefix.example.com")); // Partial wildcards do not work. assert!(!matches_dns("*suffix.example.com", "suffix.example.com")); // Partial wildcards do not work. assert!(!matches_dns("prefix*.example.com", "prefixdomain.example.com")); // Partial wildcards do not work. assert!(!matches_dns("*suffix.example.com", "domainsuffix.example.com")); // Partial wildcards do not work. assert!(!matches_dns("xn--*.example.com", "subdomain.example.com")); // Punycode domains with wildcard parts do not match. assert!(!matches_dns("xN--*.example.com", "subdomain.example.com")); // And we can't bypass a punycode test with weird casing. assert!(!matches_dns("Xn--*.example.com", "subdomain.example.com")); // And we can't bypass a punycode test with weird casing. assert!(!matches_dns("XN--*.example.com", "subdomain.example.com")); // And we can't bypass a punycode test with weird casing. } } } } openssl-0.10.36/src/ssl/error.rs000064400000000000000000000131740072674642500146030ustar 00000000000000use libc::c_int; use std::error; use std::error::Error as StdError; use std::fmt; use std::io; use crate::error::ErrorStack; use crate::ssl::MidHandshakeSslStream; use crate::x509::X509VerifyResult; /// An error code returned from SSL functions. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct ErrorCode(c_int); impl ErrorCode { /// 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); pub fn from_raw(raw: c_int) -> ErrorCode { ErrorCode(raw) } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } #[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 source(&self) -> Option<&(dyn error::Error + 'static)> { 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 source(&self) -> Option<&(dyn StdError + 'static)> { 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 { match *self { HandshakeError::SetupFailure(ref e) => write!(f, "stream setup failed: {}", e)?, HandshakeError::Failure(ref s) => { write!(f, "the handshake failed: {}", s.error())?; let verify = s.ssl().verify_result(); if verify != X509VerifyResult::OK { write!(f, ": {}", verify)?; } } HandshakeError::WouldBlock(ref s) => { write!(f, "the handshake was interrupted: {}", 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.36/src/ssl/mod.rs000064400000000000000000004571710072674642500142420ustar 00000000000000//! 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 bitflags::bitflags; use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_void}; use once_cell::sync::{Lazy, OnceCell}; 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 crate::dh::{Dh, DhRef}; #[cfg(all(ossl101, not(ossl110)))] use crate::ec::EcKey; use crate::ec::EcKeyRef; use crate::error::ErrorStack; use crate::ex_data::Index; #[cfg(ossl111)] use crate::hash::MessageDigest; #[cfg(ossl110)] use crate::nid::Nid; use crate::pkey::{HasPrivate, PKeyRef, Params, Private}; use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; use crate::ssl::error::InnerError; use crate::stack::{Stack, StackRef}; use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; #[cfg(any(ossl102, libressl261))] use crate::x509::verify::X509VerifyParamRef; use crate::x509::{X509Name, X509Ref, X509StoreContextRef, X509VerifyResult, X509}; use crate::{cvt, cvt_n, cvt_p, init}; pub use crate::ssl::connector::{ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder, }; pub use crate::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() } } cfg_if! { if #[cfg(ossl300)] { type SslOptionsRepr = u64; } else { type SslOptionsRepr = libc::c_ulong; } } bitflags! { /// Options controlling the behavior of an `SslContext`. pub struct SslOptions: SslOptionsRepr { /// 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 LibreSSL 3.3.2 or newer. #[cfg(any(ossl102, ossl110, libressl332))] const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1; /// Disables the use of DTLSv1.2. /// /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer. #[cfg(any(ossl102, ossl110, libressl332))] 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; /// Disallow all renegotiation in TLSv1.2 and earlier. /// /// Requires OpenSSL 1.1.0h or newer. #[cfg(ossl110h)] const NO_RENEGOTIATION = ffi::SSL_OP_NO_RENEGOTIATION; /// 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()) } } /// Support all versions of the TLS protocol, explicitly as a client. /// /// This corresponds to `TLS_client_method` on OpenSSL 1.1.0 and /// `SSLv23_client_method` on OpenSSL 1.0.x. pub fn tls_client() -> SslMethod { unsafe { SslMethod(TLS_client_method()) } } /// Support all versions of the TLS protocol, explicitly as a server. /// /// This corresponds to `TLS_server_method` on OpenSSL 1.1.0 and /// `SSLv23_server_method` on OpenSSL 1.0.x. pub fn tls_server() -> SslMethod { unsafe { SslMethod(TLS_server_method()) } } /// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value. /// /// # Safety /// /// The caller must ensure the pointer is valid. pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod { SslMethod(ptr) } /// Returns a pointer to the underlying OpenSSL value. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_ptr(&self) -> *const ffi::SSL_METHOD { self.0 } } unsafe impl Sync for SslMethod {} unsafe impl Send for SslMethod {} bitflags! { /// Options controlling 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 { /// 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); /// 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. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } /// An identifier of a certificate status type. #[derive(Copy, Clone)] pub struct StatusType(c_int); impl StatusType { /// An OSCP status. pub const OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp); /// 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. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } /// An identifier of a session name type. #[derive(Copy, Clone)] pub struct NameType(c_int); impl NameType { /// A host name. pub const HOST_NAME: NameType = NameType(ffi::TLSEXT_NAMETYPE_host_name); /// 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. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_raw(&self) -> c_int { self.0 } } static INDEXES: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); static SSL_INDEXES: Lazy>> = Lazy::new(|| Mutex::new(HashMap::new())); static SESSION_CTX_INDEX: OnceCell> = OnceCell::new(); fn try_get_session_ctx_index() -> Result<&'static Index, ErrorStack> { SESSION_CTX_INDEX.get_or_try_init(Ssl::new_ex_index) } 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. /// /// # Safety /// /// The caller must ensure that the pointer is valid and uniquely owned by the builder. 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(()) } } /// Replaces the context's certificate store. /// /// This corresponds to [`SSL_CTX_set_cert_store`]. /// /// [`SSL_CTX_set_cert_store`]: https://www.openssl.org/docs/man1.0.2/man3/SSL_CTX_set_cert_store.html pub fn set_cert_store(&mut self, cert_store: X509Store) { unsafe { ffi::SSL_CTX_set_cert_store(self.as_ptr(), cert_store.as_ptr()); mem::forget(cert_store); } } /// 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 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/manmaster/man3/SSL_CTX_set_cipher_list.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 the 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())) } } /// Returns a reference to the X509 verification configuration. /// /// Requires OpenSSL 1.0.2 or newer. /// /// This corresponds to [`SSL_CTX_get0_param`]. /// /// [`SSL_CTX_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_get0_param.html #[cfg(any(ossl102, libressl261))] pub fn verify_param(&self) -> &X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr(ffi::SSL_CTX_get0_param(self.as_ptr())) } } /// Returns a mutable reference to the X509 verification configuration. /// /// Requires OpenSSL 1.0.2 or newer. /// /// This corresponds to [`SSL_CTX_get0_param`]. /// /// [`SSL_CTX_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_get0_param.html #[cfg(any(ossl102, libressl261))] pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_CTX_get0_param(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 #[allow(clippy::useless_conversion)] 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() } } /// Sets the context's supported signature algorithms. /// /// This corresponds to [`SSL_CTX_set1_sigalgs_list`]. /// /// Requires OpenSSL 1.0.2 or newer. /// /// [`SSL_CTX_set1_sigalgs_list`]: https://www.openssl.org/docs/man1.1.0/man3/SSL_CTX_set1_sigalgs_list.html #[cfg(ossl102)] pub fn set_sigalgs_list(&mut self, sigalgs: &str) -> Result<(), ErrorStack> { let sigalgs = CString::new(sigalgs).unwrap(); unsafe { cvt(ffi::SSL_CTX_set1_sigalgs_list(self.as_ptr(), sigalgs.as_ptr()) as c_int) .map(|_| ()) } } /// Sets the context's supported elliptic curve groups. /// /// This corresponds to [`SSL_CTX_set1_groups_list`]. /// /// Requires OpenSSL 1.1.1 or newer. /// /// [`SSL_CTX_set1_groups_list`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set1_groups_list.html #[cfg(ossl111)] pub fn set_groups_list(&mut self, groups: &str) -> Result<(), ErrorStack> { let groups = CString::new(groups).unwrap(); unsafe { cvt(ffi::SSL_CTX_set1_groups_list(self.as_ptr(), groups.as_ptr()) as c_int).map(|_| ()) } } /// 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 { (**self).to_owned() } } impl ToOwned for SslContextRef { type Owned = SslContext; fn to_owned(&self) -> Self::Owned { 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()); X509Ref::from_const_ptr_opt(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()); PKeyRef::from_const_ptr_opt(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); StackRef::from_const_ptr_opt(chain).expect("extra chain certs must not be null") } } /// 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 #[allow(clippy::useless_conversion)] pub fn session_cache_size(&self) -> i64 { unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()).into() } } /// Returns the verify mode that was set on this context from [`SslContextBuilder::set_verify`]. /// /// This corresponds to [`SSL_CTX_get_verify_mode`]. /// /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify /// [`SSL_CTX_get_verify_mode`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_get_verify_mode.html pub fn verify_mode(&self) -> SslVerifyMode { let mode = unsafe { ffi::SSL_CTX_get_verify_mode(self.as_ptr()) }; SslVerifyMode::from_bits(mode).expect("SSL_CTX_get_verify_mode returned invalid mode") } } /// 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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 #[allow(clippy::useless_conversion)] 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_protocol_version.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: &SslContextRef) -> Result { let session_ctx_index = try_get_session_ctx_index()?; 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.to_owned()); 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 #[allow(deprecated)] 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 #[allow(deprecated)] 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 peek(&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_peek(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)) } } /// 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.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.as_ptr()) } } /// 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) } } /// Returns the verify mode that was set using `set_verify`. /// /// This corresponds to [`SSL_get_verify_mode`]. /// /// [`SSL_get_verify_mode`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_verify_mode.html pub fn verify_mode(&self) -> SslVerifyMode { let mode = unsafe { ffi::SSL_get_verify_mode(self.as_ptr()) }; SslVerifyMode::from_bits(mode).expect("SSL_get_verify_mode returned invalid mode") } /// 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()); SslCipherRef::from_const_ptr_opt(ptr) } } /// 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 = SSL_get1_peer_certificate(self.as_ptr()); X509::from_ptr_opt(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()); StackRef::from_const_ptr_opt(ptr) } } /// Returns the verified certificate chain 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()); StackRef::from_const_ptr_opt(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()); X509Ref::from_const_ptr_opt(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()); PKeyRef::from_const_ptr_opt(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()); StackRef::from_const_ptr_opt(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()); SrtpProtectionProfileRef::from_const_ptr_opt(profile) } } /// 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.is_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()); SslSessionRef::from_const_ptr_opt(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_peer_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 initial handshake has been completed. /// /// This corresponds to [`SSL_is_init_finished`]. /// /// [`SSL_is_init_finished`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_is_init_finished.html #[cfg(ossl110)] pub fn is_init_finished(&self) -> bool { unsafe { ffi::SSL_is_init_finished(self.as_ptr()) != 0 } } /// 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 returned. /// /// 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 returned. /// /// 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 returned. /// /// 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 returned. /// /// 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)) } } } /// Sets the MTU used for DTLS connections. /// /// This corresponds to `SSL_set_mtu`. pub fn set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_mtu(self.as_ptr(), mtu as c_long) as c_int).map(|_| ()) } } } /// 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 } } impl MidHandshakeSslStream where S: Read + Write, { /// 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> { match self.stream.do_handshake() { Ok(()) => Ok(self.stream), Err(error) => { self.error = error; 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 { /// Creates a new `SslStream`. /// /// This function performs no IO; the stream will not have performed any part of the handshake /// with the peer. If the `Ssl` was configured with [`SslRef::set_connect_state`] or /// [`SslRef::set_accept_state`], the handshake can be performed automatically during the first /// call to read or write. Otherwise the `connect` and `accept` methods can be used to /// explicitly perform the handshake. /// /// This corresponds to [`SSL_set_bio`]. /// /// [`SSL_set_bio`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_bio.html pub fn new(ssl: Ssl, stream: S) -> Result { let (bio, method) = bio::new(stream)?; unsafe { ffi::SSL_set_bio(ssl.as_ptr(), bio, bio); } Ok(SslStream { ssl: ManuallyDrop::new(ssl), method: ManuallyDrop::new(method), _p: PhantomData, }) } /// Constructs an `SslStream` from a pointer to the underlying OpenSSL `SSL` struct. /// /// This is useful if the handshake has already been completed elsewhere. /// /// # Safety /// /// The caller must ensure the pointer is valid. #[deprecated( since = "0.10.32", note = "use Ssl::from_ptr and SslStream::new instead" )] pub unsafe fn from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self { let ssl = Ssl::from_ptr(ssl); Self::new(ssl, stream).unwrap() } /// Read application data transmitted by a client before handshake completion. /// /// Useful for reducing latency, but vulnerable to replay attacks. Call /// [`SslRef::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.ssl.as_ptr(), buf.as_ptr() as *mut c_void, buf.len(), &mut read, ) }; match ret { ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.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 /// [`SslRef::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.ssl.as_ptr(), buf.as_ptr() as *const c_void, buf.len(), &mut written, ) }; if ret > 0 { Ok(written as usize) } else { Err(self.make_error(ret)) } } /// 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(&mut self) -> Result<(), Error> { let ret = unsafe { ffi::SSL_connect(self.ssl.as_ptr()) }; if ret > 0 { Ok(()) } else { Err(self.make_error(ret)) } } /// 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(&mut self) -> Result<(), Error> { let ret = unsafe { ffi::SSL_accept(self.ssl.as_ptr()) }; if ret > 0 { Ok(()) } else { Err(self.make_error(ret)) } } /// 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 do_handshake(&mut self) -> Result<(), Error> { let ret = unsafe { ffi::SSL_do_handshake(self.ssl.as_ptr()) }; if ret > 0 { Ok(()) } else { Err(self.make_error(ret)) } } /// 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.ssl.as_ptr()) } { 1 => Ok(true), 0 => Ok(false), -1 => Err(ErrorStack::get()), _ => unreachable!(), } } /// 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 interpretation 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.is_empty() { 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.is_empty() { return Ok(0); } let ret = self.ssl.write(buf); if ret > 0 { Ok(ret as usize) } else { Err(self.make_error(ret)) } } /// Reads data from the stream, without removing it from the queue. /// /// This corresponds to [`SSL_peek`]. /// /// [`SSL_peek`]: https://www.openssl.org/docs/manmaster/man3/SSL_peek.html pub fn ssl_peek(&mut self, buf: &mut [u8]) -> Result { // See above for why we short-circuit on zero-length buffers if buf.is_empty() { return Ok(0); } let ret = self.ssl.peek(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. #[deprecated( since = "0.10.32", note = "use the methods directly on Ssl/SslStream instead" )] pub struct SslStreamBuilder { inner: SslStream, } #[allow(deprecated)] impl SslStreamBuilder where S: Read + Write, { /// Begin creating an `SslStream` atop `stream` pub fn new(ssl: Ssl, stream: S) -> Self { Self { inner: SslStream::new(ssl, stream).unwrap(), } } /// 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(mut self) -> Result, HandshakeError> { match self.inner.connect() { Ok(()) => Ok(self.inner), Err(error) => match error.code() { ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream: self.inner, error, })) } _ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream: self.inner, error, })), }, } } /// See `Ssl::accept` pub fn accept(mut self) -> Result, HandshakeError> { match self.inner.accept() { Ok(()) => Ok(self.inner), Err(error) => match error.code() { ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream: self.inner, error, })) } _ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream: self.inner, 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(mut self) -> Result, HandshakeError> { match self.inner.do_handshake() { Ok(()) => Ok(self.inner), Err(error) => match error.code() { ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => { Err(HandshakeError::WouldBlock(MidHandshakeSslStream { stream: self.inner, error, })) } _ => Err(HandshakeError::Failure(MidHandshakeSslStream { stream: self.inner, 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 { self.inner.read_early_data(buf) } /// 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 { self.inner.write_early_data(buf) } } #[allow(deprecated)] 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 } /// Set the DTLS MTU size. /// /// It will be ignored if the value is smaller than the minimum packet size /// the DTLS protocol requires. /// /// # Panics /// This function panics if the given mtu size can't be represented in a positive `c_long` range #[deprecated(note = "Use SslRef::set_mtu instead", since = "0.10.30")] pub fn set_dtls_mtu_size(&mut self, mtu_size: usize) { unsafe { let bio = self.inner.ssl.get_raw_rbio(); bio::set_dtls_mtu_size::(bio, mtu_size); } } } /// 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(ossl300)] { use ffi::SSL_get1_peer_certificate; } else { use ffi::SSL_get_peer_certificate as SSL_get1_peer_certificate; } } cfg_if! { if #[cfg(any(ossl110, libressl291))] { use ffi::{TLS_method, DTLS_method, TLS_client_method, TLS_server_method}; } else { use ffi::{ SSLv23_method as TLS_method, DTLSv1_method as DTLS_method, SSLv23_client_method as TLS_client_method, SSLv23_server_method as TLS_server_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 { use std::sync::Once; unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest static ONCE: Once = Once::new(); ONCE.call_once(|| { ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, None); }); 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 { // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest static ONCE: Once = Once::new(); ONCE.call_once(|| { ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, None); }); ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) } } } openssl-0.10.36/src/ssl/test/mod.rs000064400000000000000000001163210072674642500152060ustar 00000000000000#![allow(unused_imports)] use std::env; use std::fs::File; use std::io::prelude::*; use std::io::{self, BufReader}; use std::iter; use std::mem; use std::net::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 crate::dh::Dh; use crate::error::ErrorStack; use crate::hash::MessageDigest; use crate::ocsp::{OcspResponse, OcspResponseStatus}; use crate::pkey::PKey; use crate::srtp::SrtpProfileId; use crate::ssl; use crate::ssl::test::server::Server; #[cfg(any(ossl110, ossl111, libressl261))] use crate::ssl::SslVersion; #[cfg(ossl111)] use crate::ssl::{ClientHelloResponse, ExtensionContext}; use crate::ssl::{ Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, ShutdownState, Ssl, SslAcceptor, SslAcceptorBuilder, SslConnector, SslContext, SslContextBuilder, SslFiletype, SslMethod, SslOptions, SslSessionCacheMode, SslStream, SslVerifyMode, StatusType, }; #[cfg(ossl102)] use crate::x509::store::X509StoreBuilder; #[cfg(ossl102)] use crate::x509::verify::X509CheckFlags; use crate::x509::{X509Name, X509StoreContext, X509VerifyResult, X509}; mod server; static ROOT_CERT: &[u8] = include_bytes!("../../../test/root-ca.pem"); static CERT: &[u8] = include_bytes!("../../../test/cert.pem"); static KEY: &[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] 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 mut ssl = Ssl::new(&ctx.build()).unwrap(); ssl.set_mtu(1500).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 mut ssl = Ssl::new(&ctx.build()).unwrap(); ssl.set_mtu(1500).unwrap(); let mut stream = ssl.connect(stream).unwrap(); let mut buf = [1; 60]; { let srtp_profile = stream.ssl().selected_srtp_profile().unwrap(); assert_eq!("SRTP_AES128_CM_SHA1_80", srtp_profile.name()); assert_eq!(SrtpProfileId::SRTP_AES128_CM_SHA1_80, srtp_profile.id()); } stream .ssl() .export_keying_material(&mut buf, "EXTRACTOR-dtls_srtp", None) .expect("extract"); stream.read_exact(&mut [0]).unwrap(); let buf2 = guard.join().unwrap(); assert_eq!(buf[..], buf2[..]); } /// Tests that when both the client as well as the server use SRTP and their /// lists of supported protocols have an overlap -- with only ONE protocol /// being valid for both. #[test] fn test_connect_with_srtp_ssl() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); let guard = thread::spawn(move || { let stream = listener.accept().unwrap().0; let mut ctx = SslContext::builder(SslMethod::dtls()).unwrap(); ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM) .unwrap(); ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM) .unwrap(); let mut ssl = Ssl::new(&ctx.build()).unwrap(); ssl.set_tlsext_use_srtp("SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32") .unwrap(); let mut profilenames = String::new(); for profile in ssl.srtp_profiles().unwrap() { if !profilenames.is_empty() { profilenames.push(':'); } profilenames += profile.name(); } assert_eq!( "SRTP_AES128_CM_SHA1_80:SRTP_AES128_CM_SHA1_32", profilenames ); ssl.set_mtu(1500).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 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(); ssl.set_mtu(1500).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] #[cfg_attr(libressl321, ignore)] #[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(target_os = "windows", 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 = match TcpStream::connect("google.com:443") { Ok(s) => s, Err(_) => return, }; 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(); } fn test_mozilla_server(new: fn(SslMethod) -> Result) { 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 = new(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_intermediate() { test_mozilla_server(SslAcceptor::mozilla_intermediate); } #[test] fn connector_client_server_mozilla_modern() { test_mozilla_server(SslAcceptor::mozilla_modern); } #[test] fn connector_client_server_mozilla_intermediate_v5() { test_mozilla_server(SslAcceptor::mozilla_intermediate_v5); } #[test] #[cfg(ossl111)] fn connector_client_server_mozilla_modern_v5() { test_mozilla_server(SslAcceptor::mozilla_modern_v5); } #[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] #[cfg_attr(libressl321, ignore)] 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 crate::ec::EcKey; use crate::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] #[cfg_attr(libressl321, ignore)] 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 crate::ec::EcKey; use crate::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] #[cfg_attr(libressl321, ignore)] 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] #[cfg_attr(libressl321, ignore)] 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] #[cfg_attr(libressl321, ignore)] 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()); } // // Setup // let mut client_ctx = SslContext::builder(SslMethod::tls()).unwrap(); client_ctx.clear_options(SslOptions::ENABLE_MIDDLEBOX_COMPAT); let mut client_stream = SslStream::new(Ssl::new(&client_ctx.build()).unwrap(), MemoryStream::new()).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 = SslStream::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new()).unwrap(); // // Handshake // // Initial ClientHello client_stream.connect().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 client_stream.do_handshake().unwrap_err(); send(client_stream.get_mut(), server_stream.get_mut()); // OldServerHello assert!(server_stream.stateless().unwrap()); server_stream.accept().unwrap_err(); send(server_stream.get_mut(), client_stream.get_mut()); // Finished client_stream.do_handshake().unwrap(); send(client_stream.get_mut(), server_stream.get_mut()); server_stream.do_handshake().unwrap(); } #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] #[test] fn psk_ciphers() { const CIPHER: &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.36/src/ssl/test/server.rs000064400000000000000000000075710072674642500157430ustar 00000000000000use std::io::{Read, Write}; use std::net::{SocketAddr, TcpListener, TcpStream}; use std::thread::{self, JoinHandle}; use crate::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.36/src/stack.rs000064400000000000000000000227450072674642500137620ustar 00000000000000use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::c_int; use std::borrow::Borrow; use std::convert::AsRef; use std::fmt; use std::iter; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut, Index, IndexMut, Range}; use crate::error::ErrorStack; use crate::util::ForeignTypeExt; use crate::{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 fmt::Debug for Stack where T: Stackable, T::Ref: fmt::Debug, { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { fmt.debug_list().entries(self).finish() } } impl Drop for Stack { fn drop(&mut self) { unsafe { while self.pop().is_some() {} 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 { // https://github.com/rust-lang/rust-clippy/issues/7510 #[allow(clippy::while_let_on_iterator)] 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 } } /// Determines if the stack is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn iter(&self) -> Iter<'_, T> { Iter { stack: self, idxs: 0..self.len() as c_int, } } pub fn iter_mut(&mut self) -> IterMut<'_, T> { 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()); T::from_ptr_opt(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> { 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> { 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.36/src/string.rs000064400000000000000000000036320072674642500141550ustar 00000000000000use 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 crate::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.36/src/symm.rs000064400000000000000000001521040072674642500136330ustar 00000000000000//! 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 cfg_if::cfg_if; use libc::c_int; use std::cmp; use std::ptr; use crate::error::ErrorStack; use crate::nid::Nid; use crate::{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)) } } /// Returns the cipher's Nid. /// /// This corresponds to [`EVP_CIPHER_nid`] /// /// [`EVP_CIPHER_nid`]: https://www.openssl.org/docs/man1.0.2/crypto/EVP_CIPHER_nid.html pub fn nid(&self) -> Nid { let nid = unsafe { ffi::EVP_CIPHER_nid(self.0) }; Nid::from_raw(nid) } 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_128_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_ofb()) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(ossl110)] pub fn aes_128_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_ocb()) } } pub fn aes_192_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_ecb()) } } pub fn aes_192_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_cbc()) } } pub fn aes_192_ctr() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_ctr()) } } pub fn aes_192_cfb1() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_cfb1()) } } pub fn aes_192_cfb128() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_cfb128()) } } pub fn aes_192_cfb8() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_cfb8()) } } pub fn aes_192_gcm() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_gcm()) } } pub fn aes_192_ccm() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_ccm()) } } pub fn aes_192_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_ofb()) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(ossl110)] pub fn aes_192_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_ocb()) } } 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 aes_256_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_ofb()) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(ossl110)] pub fn aes_256_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_ocb()) } } #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_bf_cbc()) } } #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_bf_ecb()) } } #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_cfb64() -> Cipher { unsafe { Cipher(ffi::EVP_bf_cfb64()) } } #[cfg(not(osslconf = "OPENSSL_NO_BF"))] 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()) } } #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_seed_cbc()) } } #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_cfb128() -> Cipher { unsafe { Cipher(ffi::EVP_seed_cfb128()) } } #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_seed_ecb()) } } #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_seed_ofb()) } } /// Creates a `Cipher` from a raw pointer to its OpenSSL type. /// /// # Safety /// /// The caller must ensure the pointer is valid for the `'static` lifetime. pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher { Cipher(ptr) } #[allow(clippy::trivially_copy_pass_by_ref)] pub fn as_ptr(&self) -> *const ffi::EVP_CIPHER { self.0 } /// Returns the length of keys used with this cipher. #[allow(clippy::trivially_copy_pass_by_ref)] 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. #[allow(clippy::trivially_copy_pass_by_ref)] 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. #[allow(clippy::trivially_copy_pass_by_ref)] 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() } /// Determines whether the cipher is using OCB mode #[cfg(ossl110)] fn is_ocb(self) -> bool { self == Cipher::aes_128_ocb() || self == Cipher::aes_192_ocb() || self == Cipher::aes_256_ocb() } #[cfg(not(ossl110))] const fn is_ocb(self) -> bool { false } } 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 necessary 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, 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 initialization 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 initialization 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()]; let is_ccm = t.is_ccm(); if is_ccm || t.is_ocb() { c.set_tag_len(tag.len())?; if is_ccm { 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()]; let is_ccm = t.is_ccm(); if is_ccm || t.is_ocb() { c.set_tag(tag)?; if is_ccm { c.set_data_len(data.len())?; } } c.aad_update(aad)?; let count = c.update(data, &mut out)?; let rest = if t.is_ccm() { 0 } else { c.set_tag(tag)?; 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] #[cfg_attr(ossl300, ignore)] 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_aes128_ofb() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; let ct = "3b3fd92eb72dad20333449f8e83cfb4a7789508d16918f03f53c52dac54ed8259740051e9c5fecf64344f7a82260edcc304c6528f659c77866a510d9c1d6ae5e"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_128_ofb(), pt, ct, key, iv); } #[test] fn test_aes192_ctr() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; let ct = "1abc932417521ca24f2b0459fe7e6e0b090339ec0aa6faefd5ccc2c6f4ce8e941e36b26bd1ebc670d1bd1d665620abf74f78a7f6d29809585a97daec58c6b050"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; let iv = "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"; cipher_test(super::Cipher::aes_192_ctr(), pt, ct, key, iv); } #[test] fn test_aes192_cfb1() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf let pt = "6bc1"; let ct = "9359"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_192_cfb1(), pt, ct, key, iv); } #[test] fn test_aes192_cfb128() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; let ct = "cdc80d6fddf18cab34c25909c99a417467ce7f7f81173621961a2b70171d3d7a2e1e8a1dd59b88b1c8e60fed1efac4c9c05f9f9ca9834fa042ae8fba584b09ff"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_192_cfb128(), pt, ct, key, iv); } #[test] fn test_aes192_cfb8() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf let pt = "6bc1bee22e409f96e93d7e117393172aae2d"; let ct = "cda2521ef0a905ca44cd057cbf0d47a0678a"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_192_cfb8(), pt, ct, key, iv); } #[test] fn test_aes192_ofb() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; let ct = "cdc80d6fddf18cab34c25909c99a4174fcc28b8d4c63837c09e81700c11004018d9a9aeac0f6596f559c6d4daf59a5f26d9f200857ca6c3e9cac524bd9acc92a"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_192_ofb(), 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_aes256_ofb() { // Lifted from http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"; let ct = "dc7e84bfda79164b7ecd8486985d38604febdc6740d20b3ac88f6ad82a4fb08d71ab47a086e86eedf39d1c5bba97c4080126141d67f37be8538f5a8be740e484"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; let iv = "000102030405060708090a0b0c0d0e0f"; cipher_test(super::Cipher::aes_256_ofb(), pt, ct, key, iv); } #[test] #[cfg_attr(ossl300, ignore)] 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] #[cfg_attr(ossl300, ignore)] 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] #[cfg_attr(ossl300, ignore)] 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] #[cfg_attr(ossl300, ignore)] 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] #[cfg_attr(ossl300, ignore)] 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] #[cfg_attr(ossl300, ignore)] 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 = "23dc8d23d95b6fd1251741a64f7d4f41"; let iv = "f416f48ad44d9efa1179e167"; let pt = "6cb9b71dd0ccd42cdf87e8e396fc581fd8e0d700e360f590593b748e105390de"; let aad = "45074844c97d515c65bbe37c210a5a4b08c21c588efe5c5f73c4d9c17d34dacddc0bb6a8a53f7bf477b9780c1c2a928660df87016b2873fe876b2b887fb5886bfd63216b7eaecc046372a82c047eb043f0b063226ee52a12c69b"; let ct = "8ad20486778e87387efb3f2574e509951c0626816722018129e578b2787969d3"; let tag = "91e1bc09"; // 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(ossl110)] fn test_aes_128_ocb() { let key = "000102030405060708090a0b0c0d0e0f"; let aad = "0001020304050607"; let tag = "16dc76a46d47e1ead537209e8a96d14e"; let iv = "000102030405060708090a0b"; let pt = "0001020304050607"; let ct = "92b657130a74b85a"; let mut actual_tag = [0; 16]; let out = encrypt_aead( Cipher::aes_128_ocb(), &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_ocb(), &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] #[cfg(ossl110)] fn test_aes_128_ocb_fail() { let key = "000102030405060708090a0b0c0d0e0f"; let aad = "0001020304050607"; let tag = "16dc76a46d47e1ead537209e8a96d14e"; let iv = "000000000405060708090a0b"; let ct = "92b657130a74b85a"; let out = decrypt_aead( Cipher::aes_128_ocb(), &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(), ); 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)); } #[test] #[cfg(not(any(osslconf = "OPENSSL_NO_SEED", ossl300)))] fn test_seed_cbc() { let pt = "5363686f6b6f6c6164656e6b756368656e0a"; let ct = "c2edf0fb2eb11bf7b2f39417a8528896d34b24b6fd79e5923b116dfcd2aba5a4"; let key = "41414141414141414141414141414141"; let iv = "41414141414141414141414141414141"; cipher_test(super::Cipher::seed_cbc(), pt, ct, key, iv); } #[test] #[cfg(not(any(osslconf = "OPENSSL_NO_SEED", ossl300)))] fn test_seed_cfb128() { let pt = "5363686f6b6f6c6164656e6b756368656e0a"; let ct = "71d4d25fc1750cb7789259e7f34061939a41"; let key = "41414141414141414141414141414141"; let iv = "41414141414141414141414141414141"; cipher_test(super::Cipher::seed_cfb128(), pt, ct, key, iv); } #[test] #[cfg(not(any(osslconf = "OPENSSL_NO_SEED", ossl300)))] fn test_seed_ecb() { let pt = "5363686f6b6f6c6164656e6b756368656e0a"; let ct = "0263a9cd498cf0edb0ef72a3231761d00ce601f7d08ad19ad74f0815f2c77f7e"; let key = "41414141414141414141414141414141"; let iv = "41414141414141414141414141414141"; cipher_test(super::Cipher::seed_ecb(), pt, ct, key, iv); } #[test] #[cfg(not(any(osslconf = "OPENSSL_NO_SEED", ossl300)))] fn test_seed_ofb() { let pt = "5363686f6b6f6c6164656e6b756368656e0a"; let ct = "71d4d25fc1750cb7789259e7f34061930afd"; let key = "41414141414141414141414141414141"; let iv = "41414141414141414141414141414141"; cipher_test(super::Cipher::seed_ofb(), pt, ct, key, iv); } } openssl-0.10.36/src/util.rs000064400000000000000000000050450072674642500136240ustar 00000000000000use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_void}; use std::any::Any; use std::panic::{self, AssertUnwindSafe}; use std::slice; use crate::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 } } } pub trait ForeignTypeExt: ForeignType { unsafe fn from_ptr_opt(ptr: *mut Self::CType) -> Option { if ptr.is_null() { None } else { Some(Self::from_ptr(ptr)) } } } impl ForeignTypeExt for FT {} pub trait ForeignTypeRefExt: ForeignTypeRef { unsafe fn from_const_ptr<'a>(ptr: *const Self::CType) -> &'a Self { Self::from_ptr(ptr as *mut Self::CType) } unsafe fn from_const_ptr_opt<'a>(ptr: *const Self::CType) -> Option<&'a Self> { if ptr.is_null() { None } else { Some(Self::from_const_ptr(ptr as *mut Self::CType)) } } } impl ForeignTypeRefExt for FT {} openssl-0.10.36/src/version.rs000064400000000000000000000106330072674642500143330ustar 00000000000000// 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 cfg_if::cfg_if; 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.36/src/x509/extension.rs000064400000000000000000000402750072674642500153740ustar 00000000000000//! 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 //! use openssl::x509::extension::BasicConstraints; //! use openssl::x509::X509Extension; //! //! let mut bc = BasicConstraints::new(); //! let bc = bc.critical().ca().pathlen(1); //! //! let extension: X509Extension = bc.build().unwrap(); //! ``` use std::fmt::Write; use crate::error::ErrorStack; use crate::nid::Nid; use crate::x509::{X509Extension, X509v3Context}; /// An extension which indicates whether a certificate is a CA certificate. pub struct BasicConstraints { critical: bool, ca: bool, pathlen: Option, } impl Default for BasicConstraints { fn default() -> BasicConstraints { BasicConstraints::new() } } 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 Default for KeyUsage { fn default() -> KeyUsage { KeyUsage::new() } } 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 Default for ExtendedKeyUsage { fn default() -> ExtendedKeyUsage { ExtendedKeyUsage::new() } } 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 `emailProtection` flag to `true`. pub fn email_protection(&mut self) -> &mut ExtendedKeyUsage { self.email_protection = 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 Default for SubjectKeyIdentifier { fn default() -> SubjectKeyIdentifier { SubjectKeyIdentifier::new() } } 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 Default for AuthorityKeyIdentifier { fn default() -> AuthorityKeyIdentifier { AuthorityKeyIdentifier::new() } } 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 Default for SubjectAlternativeName { fn default() -> SubjectAlternativeName { SubjectAlternativeName::new() } } 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.36/src/x509/mod.rs000064400000000000000000001510040072674642500141300ustar 00000000000000//! 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 cfg_if::cfg_if; 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 crate::asn1::{ Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef, Asn1Type, }; use crate::bio::MemBioSlice; use crate::conf::ConfRef; use crate::error::ErrorStack; use crate::ex_data::Index; use crate::hash::{DigestBytes, MessageDigest}; use crate::nid::Nid; use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; use crate::ssl::SslRef; use crate::stack::{Stack, StackRef, Stackable}; use crate::string::OpensslString; use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; use crate::{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(X509StoreContext) } } } 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()); X509Ref::from_const_ptr_opt(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. /// /// This works just as `append_extension` except it takes ownership of the `X509Extension`. pub fn append_extension(&mut self, extension: X509Extension) -> Result<(), ErrorStack> { self.append_extension2(&extension) } /// Adds an X509 extension value to the certificate. /// /// This corresponds to [`X509_add_ext`]. /// /// [`X509_add_ext`]: https://www.openssl.org/docs/man1.1.0/man3/X509_get_ext.html pub fn append_extension2(&mut self, extension: &X509ExtensionRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_add_ext(self.0.as_ptr(), extension.as_ptr(), -1))?; 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()); X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") } } /// Returns the hash of the certificates subject /// /// This corresponds to `X509_subject_name_hash`. pub fn subject_name_hash(&self) -> u32 { unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } } /// 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()); X509NameRef::from_const_ptr_opt(name).expect("issuer name must not be null") } } /// 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(), ); Stack::from_ptr_opt(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(), ); Stack::from_ptr_opt(stack as *mut _) } } /// Returns this certificate's [`authority information access`] entries, if they exist. /// /// This corresponds to [`X509_get_ext_d2i`] called with `NID_info_access`. /// /// [`X509_get_ext_d2i`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_get_ext_d2i.html /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1 pub fn authority_info(&self) -> Option> { unsafe { let stack = ffi::X509_get_ext_d2i( self.as_ptr(), ffi::NID_info_access, ptr::null_mut(), ptr::null_mut(), ); Stack::from_ptr_opt(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()); Asn1TimeRef::from_const_ptr_opt(date).expect("not_after must not be null") } } /// Returns the certificate's Not Before validity period. pub fn not_before(&self) -> &Asn1TimeRef { unsafe { let date = X509_getm_notBefore(self.as_ptr()); Asn1TimeRef::from_const_ptr_opt(date).expect("not_before must not be null") } } /// 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()); Asn1BitStringRef::from_const_ptr_opt(signature).expect("signature must not be null") } } /// 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()); X509AlgorithmRef::from_const_ptr_opt(algor) .expect("signature algorithm must not be null") } } /// 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) } } /// Returns certificate version. If this certificate has no explicit version set, it defaults to /// version 1. /// /// Note that `0` return value stands for version 1, `1` for version 2 and so on. /// /// This corresponds to [`X509_get_version`]. /// /// [`X509_get_version`]: https://www.openssl.org/docs/man1.1.1/man3/X509_get_version.html #[cfg(ossl110)] pub fn version(&self) -> i32 { // Covered with `x509_ref_version()`, `x509_ref_version_no_version_set()` tests unsafe { ffi::X509_get_version(self.as_ptr()) as i32 } } /// 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()); Asn1IntegerRef::from_const_ptr_opt(r).expect("serial number must not be null") } } 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 fmt::Debug for X509 { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { let serial = match &self.serial_number().to_bn() { Ok(bn) => match bn.to_hex_str() { Ok(hex) => hex.to_string(), Err(_) => "".to_string(), }, Err(_) => "".to_string(), }; let mut debug_struct = formatter.debug_struct("X509"); debug_struct.field("serial_number", &serial); debug_struct.field("signature_algorithm", &self.signature_algorithm().object()); debug_struct.field("issuer", &self.issuer_name()); debug_struct.field("subject", &self.subject_name()); if let Some(subject_alt_names) = &self.subject_alt_names() { debug_struct.field("subject_alt_names", subject_alt_names); } debug_struct.field("not_before", &self.not_before()); debug_struct.field("not_after", &self.not_after()); if let Ok(public_key) = &self.public_key() { debug_struct.field("public_key", public_key); }; // TODO: Print extensions once they are supported on the X509 struct. debug_struct.finish() } } 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 str with a specific type. /// /// 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_with_type( &mut self, field: &str, value: &str, ty: Asn1Type, ) -> 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 _, ty.as_raw(), 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(|_| ()) } } /// Add a field entry by NID with a specific type. /// /// 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_with_type( &mut self, field: Nid, value: &str, ty: Asn1Type, ) -> 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(), ty.as_raw(), 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(&self, nid: Nid) -> X509NameEntries<'_> { X509NameEntries { name: self, nid: Some(nid), loc: -1, } } /// Returns an iterator over all `X509NameEntry` values pub fn entries(&self) -> X509NameEntries<'_> { X509NameEntries { name: self, nid: None, loc: -1, } } } impl fmt::Debug for X509NameRef { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.debug_list().entries(self.entries()).finish() } } /// 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); Some(X509NameEntryRef::from_const_ptr_opt(entry).expect("entry must not be null")) } } } 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) } } } impl fmt::Debug for X509NameEntryRef { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_fmt(format_args!("{:?} = {:?}", self.object(), self.data())) } } /// 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()); X509NameRef::from_const_ptr_opt(name).expect("subject name must not be null") } } /// 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 {} 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`. #[allow(clippy::trivially_copy_pass_by_ref)] 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 #[allow(clippy::trivially_copy_pass_by_ref)] 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 fmt::Debug for GeneralNameRef { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { if let Some(email) = self.email() { formatter.write_str(email) } else if let Some(dnsname) = self.dnsname() { formatter.write_str(dnsname) } else if let Some(uri) = self.uri() { formatter.write_str(uri) } else if let Some(ipaddress) = self.ipaddress() { let result = String::from_utf8_lossy(ipaddress); formatter.write_str(&result) } else { formatter.write_str("(empty)") } } } impl Stackable for GeneralName { type StackType = ffi::stack_st_GENERAL_NAME; } foreign_type_and_impl_send_sync! { type CType = ffi::ACCESS_DESCRIPTION; fn drop = ffi::ACCESS_DESCRIPTION_free; /// `AccessDescription` of certificate authority information. pub struct AccessDescription; /// Reference to `AccessDescription`. pub struct AccessDescriptionRef; } impl AccessDescriptionRef { /// Returns the access method OID. pub fn method(&self) -> &Asn1ObjectRef { unsafe { Asn1ObjectRef::from_ptr((*self.as_ptr()).method) } } // Returns the access location. pub fn location(&self) -> &GeneralNameRef { unsafe { GeneralNameRef::from_ptr((*self.as_ptr()).location) } } } impl Stackable for AccessDescription { type StackType = ffi::stack_st_ACCESS_DESCRIPTION; } 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()); Asn1ObjectRef::from_const_ptr_opt(oid).expect("algorithm oid must not be null") } } } foreign_type_and_impl_send_sync! { type CType = ffi::X509_OBJECT; fn drop = X509_OBJECT_free; /// An `X509` or an X509 certificate revocation list. pub struct X509Object; /// Reference to `X509Object` pub struct X509ObjectRef; } impl X509ObjectRef { pub fn x509(&self) -> Option<&X509Ref> { unsafe { let ptr = X509_OBJECT_get0_X509(self.as_ptr()); X509Ref::from_const_ptr_opt(ptr) } } } impl Stackable for X509Object { type StackType = ffi::stack_st_X509_OBJECT; } 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()); } } } cfg_if! { if #[cfg(any(ossl110, libressl270))] { use ffi::X509_OBJECT_get0_X509; } else { #[allow(bad_style)] unsafe fn X509_OBJECT_get0_X509(x: *mut ffi::X509_OBJECT) -> *mut ffi::X509 { if (*x).type_ == ffi::X509_LU_X509 { (*x).data.x509 } else { ptr::null_mut() } } } } cfg_if! { if #[cfg(ossl110)] { use ffi::X509_OBJECT_free; } else { #[allow(bad_style)] unsafe fn X509_OBJECT_free(x: *mut ffi::X509_OBJECT) { ffi::X509_OBJECT_free_contents(x); ffi::CRYPTO_free(x as *mut libc::c_void); } } } openssl-0.10.36/src/x509/store.rs000064400000000000000000000155160072674642500145140ustar 00000000000000//! 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 //! 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; //! //! 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 cfg_if::cfg_if; use foreign_types::ForeignTypeRef; use std::mem; use crate::error::ErrorStack; use crate::stack::StackRef; #[cfg(any(ossl102, libressl261))] use crate::x509::verify::X509VerifyFlags; use crate::x509::{X509Object, X509}; use crate::{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(|_| ()) } } /// Adds a lookup method to the store. /// /// This corresponds to [`X509_STORE_add_lookup`]. /// /// [`X509_STORE_add_lookup`]: https://www.openssl.org/docs/man1.1.1/man3/X509_STORE_add_lookup.html pub fn add_lookup( &mut self, method: &'static X509LookupMethodRef, ) -> Result<&mut X509LookupRef, ErrorStack> { let lookup = unsafe { ffi::X509_STORE_add_lookup(self.as_ptr(), method.as_ptr()) }; cvt_p(lookup).map(|ptr| unsafe { X509LookupRef::from_ptr_mut(ptr) }) } /// Sets certificate chain validation related flags. /// /// This corresponds to [`X509_STORE_set_flags`]. /// /// [`X509_STORE_set_flags`]: https://www.openssl.org/docs/man1.1.1/man3/X509_STORE_set_flags.html #[cfg(any(ossl102, libressl261))] pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) } } } generic_foreign_type_and_impl_send_sync! { type CType = ffi::X509_LOOKUP; fn drop = ffi::X509_LOOKUP_free; /// Information used by an `X509Store` to look up certificates and CRLs. pub struct X509Lookup; /// Reference to an `X509Lookup`. pub struct X509LookupRef; } /// Marker type corresponding to the [`X509_LOOKUP_hash_dir`] lookup method. /// /// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_LOOKUP_hash_dir.html pub struct HashDir; impl X509Lookup { /// Lookup method that loads certificates and CRLs on demand and caches /// them in memory once they are loaded. It also checks for newer CRLs upon /// each lookup, so that newer CRLs are used as soon as they appear in the /// directory. /// /// This corresponds to [`X509_LOOKUP_hash_dir`]. /// /// [`X509_LOOKUP_hash_dir`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_LOOKUP_hash_dir.html pub fn hash_dir() -> &'static X509LookupMethodRef { unsafe { X509LookupMethodRef::from_ptr(ffi::X509_LOOKUP_hash_dir()) } } } impl X509LookupRef { /// Specifies a directory from which certificates and CRLs will be loaded /// on-demand. Must be used with `X509Lookup::hash_dir`. /// /// This corresponds to [`X509_LOOKUP_add_dir`]. /// /// [`X509_LOOKUP_add_dir`]: https://www.openssl.org/docs/man1.1.1/man3/X509_LOOKUP_add_dir.html pub fn add_dir( &mut self, name: &str, file_type: crate::ssl::SslFiletype, ) -> Result<(), ErrorStack> { let name = std::ffi::CString::new(name).unwrap(); unsafe { cvt(ffi::X509_LOOKUP_add_dir( self.as_ptr(), name.as_ptr(), file_type.as_raw(), )) .map(|_| ()) } } } generic_foreign_type_and_impl_send_sync! { type CType = ffi::X509_LOOKUP_METHOD; fn drop = X509_LOOKUP_meth_free; /// Method used to look up certificates and CRLs. pub struct X509LookupMethod; /// Reference to an `X509LookupMethod`. pub struct X509LookupMethodRef; } 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; } impl X509StoreRef { /// Get a reference to the cache of certificates in this store. pub fn objects(&self) -> &StackRef { unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) } } } cfg_if! { if #[cfg(any(ossl110, libressl270))] { use ffi::X509_STORE_get0_objects; } else { #[allow(bad_style)] unsafe fn X509_STORE_get0_objects(x: *mut ffi::X509_STORE) -> *mut ffi::stack_st_X509_OBJECT { (*x).objs } } } cfg_if! { if #[cfg(ossl110)] { use ffi::X509_LOOKUP_meth_free; } else { #[allow(bad_style)] unsafe fn X509_LOOKUP_meth_free(_x: *mut ffi::X509_LOOKUP_METHOD) {} } } openssl-0.10.36/src/x509/tests.rs000064400000000000000000000350660072674642500145240ustar 00000000000000use crate::asn1::Asn1Time; use crate::bn::{BigNum, MsbOption}; use crate::hash::MessageDigest; use crate::nid::Nid; use crate::pkey::{PKey, Private}; use crate::rsa::Rsa; use crate::stack::Stack; use crate::x509::extension::{ AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier, }; use crate::x509::store::X509StoreBuilder; #[cfg(any(ossl102, libressl261))] use crate::x509::verify::X509VerifyFlags; #[cfg(ossl110)] use crate::x509::X509Builder; use crate::x509::{X509Name, X509Req, X509StoreContext, X509VerifyResult, X509}; use hex::{self, FromHex}; 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).unwrap(); 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_debug() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let debugged = format!("{:#?}", cert); assert!(debugged.contains(r#"serial_number: "8771F7BDEE982FA5""#)); assert!(debugged.contains(r#"signature_algorithm: sha256WithRSAEncryption"#)); assert!(debugged.contains(r#"countryName = "AU""#)); assert!(debugged.contains(r#"stateOrProvinceName = "Some-State""#)); assert!(debugged.contains(r#"not_before: Aug 14 17:00:03 2016 GMT"#)); assert!(debugged.contains(r#"not_after: Aug 12 17:00:03 2026 GMT"#)); } #[test] fn test_cert_issue_validity() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); 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).unwrap(); 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 all_entries.next().is_some() { panic!(); } } #[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).unwrap(); 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 test_aia_ca_issuer() { // With AIA let cert = include_bytes!("../../test/aia_test_cert.pem"); let cert = X509::from_pem(cert).unwrap(); let authority_info = cert.authority_info().unwrap(); assert_eq!(authority_info.len(), 1); assert_eq!(authority_info[0].method().to_string(), "CA Issuers"); assert_eq!( authority_info[0].location().uri(), Some("http://www.example.com/cert.pem") ); // Without AIA let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); assert!(cert.authority_info().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!(cn.data().as_slice(), b"foobar.com"); 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] #[allow(clippy::redundant_clone)] 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()); } #[test] #[cfg(any(ossl102, libressl261))] fn test_verify_fails_with_crl_flag_set_and_no_crl() { 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(); store_bldr.set_flags(X509VerifyFlags::CRL_CHECK).unwrap(); let store = store_bldr.build(); let mut context = X509StoreContext::new().unwrap(); assert_eq!( context .init(&store, &cert, &chain, |c| { c.verify_cert()?; Ok(c.error()) }) .unwrap() .error_string(), "unable to get certificate CRL" ) } #[cfg(ossl110)] #[test] fn x509_ref_version() { let mut builder = X509Builder::new().unwrap(); let expected_version = 2; builder .set_version(expected_version) .expect("Failed to set certificate version"); let cert = builder.build(); let actual_version = cert.version(); assert_eq!( expected_version, actual_version, "Obtained certificate version is incorrect", ); } #[cfg(ossl110)] #[test] fn x509_ref_version_no_version_set() { let cert = X509Builder::new().unwrap().build(); let actual_version = cert.version(); assert_eq!( 0, actual_version, "Default certificate version is incorrect", ); } openssl-0.10.36/src/x509/verify.rs000064400000000000000000000137460072674642500146670ustar 00000000000000use bitflags::bitflags; use foreign_types::ForeignTypeRef; use libc::{c_uint, c_ulong}; use std::net::IpAddr; use crate::cvt; use crate::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; } } bitflags! { /// Flags used to verify an `X509` certificate chain. pub struct X509VerifyFlags: c_ulong { const CB_ISSUER_CHECK = ffi::X509_V_FLAG_CB_ISSUER_CHECK; const USE_CHECK_TIME = ffi::X509_V_FLAG_USE_CHECK_TIME; const CRL_CHECK = ffi::X509_V_FLAG_CRL_CHECK; const CRL_CHECK_ALL = ffi::X509_V_FLAG_CRL_CHECK_ALL; const IGNORE_CRITICAL = ffi::X509_V_FLAG_IGNORE_CRITICAL; const X509_STRICT = ffi::X509_V_FLAG_X509_STRICT; const ALLOW_PROXY_CERTS = ffi::X509_V_FLAG_ALLOW_PROXY_CERTS; const POLICY_CHECK = ffi::X509_V_FLAG_POLICY_CHECK; const EXPLICIT_POLICY = ffi::X509_V_FLAG_EXPLICIT_POLICY; const INHIBIT_ANY = ffi::X509_V_FLAG_INHIBIT_ANY; const INHIBIT_MAP = ffi::X509_V_FLAG_INHIBIT_MAP; const NOTIFY_POLICY = ffi::X509_V_FLAG_NOTIFY_POLICY; const EXTENDED_CRL_SUPPORT = ffi::X509_V_FLAG_EXTENDED_CRL_SUPPORT; const USE_DELTAS = ffi::X509_V_FLAG_USE_DELTAS; const CHECK_SS_SIGNATURE = ffi::X509_V_FLAG_CHECK_SS_SIGNATURE; #[cfg(ossl102)] const TRUSTED_FIRST = ffi::X509_V_FLAG_TRUSTED_FIRST; #[cfg(ossl102)] const SUITEB_128_LOS_ONLY = ffi::X509_V_FLAG_SUITEB_128_LOS_ONLY; #[cfg(ossl102)] const SUITEB_192_LOS = ffi::X509_V_FLAG_SUITEB_128_LOS; #[cfg(ossl102)] const SUITEB_128_LOS = ffi::X509_V_FLAG_SUITEB_192_LOS; #[cfg(ossl102)] const PARTIAL_CHAIN = ffi::X509_V_FLAG_PARTIAL_CHAIN; #[cfg(ossl110)] const NO_ALT_CHAINS = ffi::X509_V_FLAG_NO_ALT_CHAINS; #[cfg(ossl110)] const NO_CHECK_TIME = ffi::X509_V_FLAG_NO_CHECK_TIME; } } 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 verification flags. /// /// This corresponds to [`X509_VERIFY_PARAM_set_flags`]. /// /// [`X509_VERIFY_PARAM_set_flags`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_VERIFY_PARAM_set_flags.html pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_VERIFY_PARAM_set_flags(self.as_ptr(), flags.bits)).map(|_| ()) } } /// Clear verification flags. /// /// This corresponds to [`X509_VERIFY_PARAM_clear_flags`]. /// /// [`X509_VERIFY_PARAM_clear_flags`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_VERIFY_PARAM_clear_flags.html pub fn clear_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_VERIFY_PARAM_clear_flags( self.as_ptr(), flags.bits, )) .map(|_| ()) } } /// Gets verification flags. /// /// This corresponds to [`X509_VERIFY_PARAM_get_flags`]. /// /// [`X509_VERIFY_PARAM_get_flags`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_VERIFY_PARAM_get_flags.html pub fn flags(&mut self) -> X509VerifyFlags { let bits = unsafe { ffi::X509_VERIFY_PARAM_get_flags(self.as_ptr()) }; X509VerifyFlags { 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.36/test/aia_test_cert.pem000064400000000000000000000024520072674642500160010ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDozCCAougAwIBAgIJAJayG40CARAjMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV BAMMBHRlc3QwHhcNMjEwMzAyMDA1NzQ3WhcNNDgwNzE4MDA1NzQ3WjBzMQswCQYD VQQGEwJYWDELMAkGA1UECAwCWFgxEDAOBgNVBAcMB25vd2hlcmUxEDAOBgNVBAoM B3Rlc3RvcmcxEjAQBgNVBAsMCXRlc3Rncm91cDEfMB0GA1UEAwwWbWFjaGluZS0w Lm15aG9zdC5teW5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANKA 3zhwC70hbxFVdC0dYk9BHaNntZ4LPUVwFSG2HBn34oO8zCp4wkH+VIi9vOhWiySK Gs3gW4qpjMbF82Gqc3dG2KfqUrOtWY+u54zAzqpgiJf08wmREHPoZmjqfCfgM3FO VMEA8g1BQxXEd+y7UEDoXhPIoeFnqzMu9sg4npnL9U5BLaQJiWnXHClnBrvAAKXW E8KDNmcavtFvo2xQVC09C6dJG5CrigWcZe4CaUl44rHiPaQd+jOp0HAccl/XLA0/ QyHvW6ksjco/mb7ia1U9ohaC/3NHmzUA1S3kdq/qgnkPsjmy5v8k5vizowNc5rFO XsV86BIv44rh1Jut52ECAwEAAaOBnTCBmjAMBgNVHRMEBTADAQH/MAsGA1UdDwQE AwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIQYDVR0RBBowGIIW bWFjaGluZS0wLm15aG9zdC5teW5ldDA7BggrBgEFBQcBAQQvMC0wKwYIKwYBBQUH MAKGH2h0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2VydC5wZW0wDQYJKoZIhvcNAQEL BQADggEBAH+ayx8qGvxzrG57jgXJudq+z783O6E2xGBJn1cT9Jhrg1VnlU+tHcNd fFcsp0gdQZCmm3pu3E0m/FsgTpfHUgdCOmZQp45QrxCz2oRdWQM71SSA/x1VfQ9w 670iZOEY15/ss2nRl0woaYO7tBVadpZfymW5+OhsTKn5gL0pVmW3RciHuAmbIvQO bouUwzuZIJMfca7T1MqZYdrKoJrOBj0LaPTutjfQB7O/02vUCPjTTIH20aqsMe5K KXCrjiZO2jkxQ49Hz5uwfPx12dSVHNLpsnfOAH+MUToeW+SPx2OPvl/uAHcph2lj MLA6Wi64rSUxzkcFLFsGpKcK6QKcHUw= -----END CERTIFICATE----- openssl-0.10.36/test/alt_name_cert.pem000064400000000000000000000024720072674642500157720ustar 00000000000000-----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.36/test/cert.pem000064400000000000000000000021630072674642500141270ustar 00000000000000-----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.36/test/certs.pem000064400000000000000000000045000072674642500143070ustar 00000000000000-----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.36/test/cms.p12000064400000000000000000000032550072674642500136000ustar 0000000000000000o *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.36/test/cms_pubkey.der000064400000000000000000000012600072674642500153210ustar 0000000000000000rV!_ /Ǵ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.36/test/dhparams.pem000064400000000000000000000006500072674642500147700ustar 00000000000000-----BEGIN DH PARAMETERS----- MIIBCAKCAQEAh3Betv+hf5jNsOmGXU8oxuABD2B8r0yU8FVgjnCZBSVo61qJ0A2d J6r8rYKbjtolnrZN/V4IPSzYvxurHbu8nbiFVyhOySPchI2Fu+YT/HsSe/0MH9bW gJTNzmutWoy9VxtWLCmXnOSZHep3MZ1ZNimno6Kh2qQ7VJr0+KF8GbxUKOPv4SqK NBwouIQXFc0pE9kGhcGKbr7TnHhyJFCRLNP1OVDQZbcoKjk1Vh+5sy7vM2VUTQmM yOToT2LEZVAUJXNumcYMki9MIwfYCwYZbNt0ZEolyHzUEesuyHfU1eJd6+sKEjUz 5GteQIR7AehxZIS+cytu7BXO7B0owLJ2awIBAg== -----END DH PARAMETERS----- openssl-0.10.36/test/dsa.pem000064400000000000000000000012340072674642500137370ustar 00000000000000-----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.36/test/dsa.pem.pub000064400000000000000000000012160072674642500145240ustar 00000000000000-----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.36/test/dsaparam.pem000064400000000000000000000007070072674642500147640ustar 00000000000000-----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.36/test/identity.p12000064400000000000000000000064720072674642500146530ustar 000000000000000 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.36/test/key.der000064400000000000000000000022510072674642500137510ustar 000000000000000%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.36/test/key.pem000064400000000000000000000032540072674642500137640ustar 00000000000000-----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.36/test/key.pem.pub000064400000000000000000000007030072674642500145450ustar 00000000000000-----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.36/test/keystore-empty-chain.p12000064400000000000000000000047220072674642500170770ustar 000000000000000 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.36/test/nid_test_cert.pem000064400000000000000000000012700072674642500160160ustar 00000000000000-----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.36/test/nid_uid_test_cert.pem000064400000000000000000000027100072674642500166570ustar 00000000000000-----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.36/test/pkcs1.pem.pub000064400000000000000000000006520072674642500150010ustar 00000000000000-----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.36/test/pkcs8-nocrypt.der000064400000000000000000000023000072674642500157000ustar 0000000000000000  *H 0)9{ߢ3nfEO;]R# RͳV\aJ^GRYoGF2Z /銑 N.W]`K(>lmENdzQfLI,~*c?dnr h4Z6We\vV0P(҃ 8Z/Ck#/]K[89*aU?D ִHMl&]Vs]6XL8^elNy~V/"8u~IfQNr@=~lzs;0RWe1h[!{1"N]5$#F\/(qm8lpU2b?e.JGx 9rNB}u2 %vЪ^.iư?wR)' rͮm' gGYMʡZT:UpE"j%{ Gd`-< S{Ɔ 2֖i;_dPenE%ғ;@bΕn{T}ؙ*m BVѪJ3lNDԱy+ù*af!]IAИ R˙d1Y ޢWo+%nM |VC^?gO"ܯfL A￞C]-gl=c)i!NoT|H΅#{%x;^]8X?[jJdX|nv{(jbMƋJ &9%$?$! m֥uuzRK ,)2p)?|T 95k`RSӎɄVʫt͠I@R"t"QbqRO!nIyF;~,.AՓ9)/5&׎cih~g7 yz+\2j:hwun6@XOr|gؘ;N#Zvl$ v*iNɵ!ΒNȸZERL-P%ζQۛWk~5'\L2n[n \fdWfi9!݋VM openssl-0.10.36/test/pkcs8.der000064400000000000000000000024220072674642500142110ustar 0000000000000000@ *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.36/test/root-ca.key000064400000000000000000000032170072674642500145460ustar 00000000000000-----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.36/test/root-ca.pem000064400000000000000000000023150072674642500145350ustar 00000000000000-----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.36/test/rsa-encrypted.pem000064400000000000000000000033460072674642500157560ustar 00000000000000-----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.36/test/rsa.pem000064400000000000000000000032130072674642500137540ustar 00000000000000-----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.36/test/rsa.pem.pub000064400000000000000000000007030072674642500145420ustar 00000000000000-----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-----