openssl-0.10.64/.cargo_vcs_info.json0000644000000001450000000000100126670ustar { "git": { "sha1": "4a19cd48259e0755d9a9067f4c1a51ee63844c66" }, "path_in_vcs": "openssl" }openssl-0.10.64/CHANGELOG.md000064400000000000000000001062061046102023000132750ustar 00000000000000# Change Log ## [Unreleased] ## [v0.10.64] - 2024-02-19 ### Added * Added `PkeyCtxRef::{nonce_type, set_nonce_type}`. * Added `X509Ref::alias`. ## [v0.10.63] - 2024-01-19 ### Added * Added `Pkcs7Ref::{type_,signed}`. * Added `Pkcs7SignedRef::certificates`. * Added `Cipher::{aes_256_xts,des_ede3_ecb,des_ede3_cfb8,des_ede3_ofb,camellia128_ofb,camellia192_ofb,camellia256_ofb,cast5_ofb,idea_ofb}` * Added `PKey::from_dhx` * Added `PKey::{public_key_from_pem_passphrase,public_key_from_pem_callback}`. ### Changed * `Cipher::aes_128_ofb` is now available on BoringSSL * `Nid::{BRAINPOOL_P256R1,BRAINPOOL_P320R1,BRAINPOOL_P384R1,BRAINPOOL_P512R1}` are now available on LibreSSL. ## [v0.10.62] - 2023-12-22 ### Added * Added `Nid::BRAINPOOL_P320R1` * Added `rand_priv_bytes` ### Fixed * Fixed building on the latest version of BoringSSL ## [v0.10.61] - 2023-12-04 ### Changed * `SslStream` now uses `SSL_read_ex`, `SSL_write_ex`, and `SSL_peek_ex` when available ### Added * Added `SslStream::{read_uninit, ssl_read_uninit}`. ## [v0.10.60] - 2023-11-22 ### Deprecated * Deprecated `X509StoreRef::objects`. It is unsound. All callers should migrate to using `X509StoreRef::all_certificates` instead. ### Fixed * Fixed a memory leak when calling `SslContextBuilder::set_ex_data` and `SslRef::set_ex_data` multiple times with the same index. ### Added * Added `X509StoreRef::all_certificates` * Added `cipher::Cipher::{camellia128_cbc,camellia192_cbc,camellia256_cbc,cast5_cbc,idea_cbc}` * Added `symm::Cipher::{des_ede3_ecb,des_ede3_cfb8,des_ede3_ofb,camellia_128_ecb,camellia_128_ofb,camellia_128_cfb128,camellia_192_ecb,camellia_192_ofb,camellia_192_cfb128,camellia_256_ecb,camellia_256_ofb,camellia_256_cfb128,cast5_ecb,cast5_ofb,cast5_cfb64,idea_ecb,idea_ofb,idea_cfb64}` * Added `Crypter::update_unchecked` * Added `SslRef::{peer_tmp_key,tmp_key}` ### Changed * `cipher::Cipher::chacha20` is now available on LibreSSL * `symm::Cipher::chacha20` is now available on LibreSSL ## [v0.10.59] - 2023-11-03 ### Added * Added `Nid::CHACHA20_POLY1305` ### Changed * Fixed the availability of `Id::RSA_PSS` on OpenSSL ## [v0.10.58] - 2023-11-01 ### Added * Added `Id::{RSA_PSS,DHX}` constants * Added `SslContextBuilder::set_security_level` * Added `SslContextRef::security_level` * Added `SslRef::set_security_level`, `SslRef::security_level` * Added `Cipher::{camellia_128_cbc, camellia_192_cbc, camellia_256_cbc, cast5_cbc, idea_cbc}` * Added `X509CrlRef::extension` * Added `X509PurposeId::CODE_SIGN` ### Changed * `Pkey` HKDF functionality now works on LibreSSL * `BigNum::mod_sqrt` is now available on all OpenSSLs * `MessageDigest::sha3*` are now available on LibreSSL ## [v0.10.57] - 2023-08-27 ### Added * Added `X509VerifyParam::set_email` * `Cipher::chacha20_poly1305` is now available on LibreSSL * Added `CipherCtx::copy` ### Changed * Updated `bitflags` dependecy to the 2.x series ## [v0.10.56] - 2023-08-06 ## Added * Added `BigNumRef::mod_sqrt`. * Added `PkeyCtxRef::set_signature_md` and `PkeyCtxRef::set_rsa_pss_saltlen`. * Added `PkeyCtxRef::verify_recover_init` and `PkeyCtxRef::verify_recover`. * Added `BigNumRef::is_even` and `BigNumRef::is_odd`. * Added `EcPointRef::to_hex_str` and `EcPoint::from_hex_str`. * Added support for AES key wrap and wrap pad. ## [v0.10.55] - 2023-06-20 ### Fixed * Fixed compilation with the latest version of BoringSSL. * Fixed compilation when OpenSSL is compiled with `OPENSSL_NO_OCB`. * Fixed a segfault in `X509VerifyParamRef::set_host` when called with an empty string. ### Added * Added `Deriver::set_peer_ex`. * Added `EcGroupRef::asn1_flag`. * Exposed `EcPointRef::affine_coordinates` on BoringSSL and LibreSSL. * Added `Nid::SM2` and `Id::SM2` ## [v0.10.54] - 2023-05-31 ### Fixed * `PKey::private_key_to_pkcs8_passphrase` no longer panics if a `passphrase` contains a NUL byte. ## [v0.10.53] - 2023-05-30 ### Added * Added `Dsa::from_pqg`, `Dsa::generate_key`, and `Dsa::generate_params`. * Added `SslRef::bytes_to_cipher_list`. * Added `SubjectAlternativeName::other_name2` ## [v0.10.52] - 2023-04-24 ### Added * Added `DhRef::check_key`. * Added `Id::POLY1305`. * Added `X509Ref::subject_key_id`, `X509Ref::authority_key_id`, `X509Ref::authority_issuer`, and `X509Ref::authority_serial`. ## [v0.10.51] - 2023-04-20 ### Added * Added `X509RevokedRef::issuer_name` and `X509RevokedRef::reason_code`. * Added `Dh::set_key` and `Dh::set_public_key` * Added `Asn1OctetString` and `Asn1OctetStringRef1` * Added `X509Extension::new_from_der` ### Deprecated * Deprecated `X509Extension::new` and `X509Extension::new_nid` in favor of `X509Extension::new_from_der` and the `extensions` module. * Deprecated `X509Extension::add_alias`, it is not required with `new_from_der` or the `extensions` module. ## [v0.10.50] - 2023-04-09 ### Added * Added `CipherCtxRef::cipher_update_inplace`. ## [v0.10.49] - 2023-04-01 ### Fixed * `SslConnector` no longer sets the SNI extension when connecting to an IP address. ### Added * Implemented `Ord`, `PartialOrd`, `Eq`, and `PartialEq` for `Asn1Integer` and `Asn1IntegerRef`. * Added `X509Ref::crl_distribution_points`, and `DistPoint`. ## [v0.10.48] - 2023-03-23 ### Fixed * Fixed injection vulnerabilities where OpenSSL's configuration mini-language could be used via `x509::extension::SubjectAlternativeName` and `x509::extension::ExtendedKeyUsage`. The mini-language can read arbitrary files amongst other things. * As part of fixing this `SubjectAlternativeName::dir_name` and `SubjectAlternativeName::other_name` are deprecated and their implementations always `panic!`. If you have a use case for these, please file an issue. * Fixed several NULL pointer dereferences in OpenSSL that could be triggered via `x509::X509Extension::new` and `x509::X509Extension::new_nid`. Note that these methods still accept OpenSSL's configuration mini-language, and therefore should not be used with untrusted data. * Fixed a data-race with `x509::X509Name` that are created with `x509::X509NameBuilder` and then used concurrently. * Fixed LibreSSL version checking. More functions should now be correctly available on LibreSSL. ## [v0.10.47] - 2023-03-19 ### Added * Added support for X25519 and Ed25519 on LibreSSL and BoringSSL. * Added `Error::library_code` and `Error::reason_code`. ## [v0.10.46] - 2023-03-14 ### Fixed * Fixed a potential null-pointer deref when parsing a PKCS#12 archive with no identity. * Fixed builds against OpenSSL built with `no-cast`. * Fixed debug formatting of `GeneralName`. ### Deprecated * Deprecated `PKcs12Ref::parse` in favor of `Pkcs12Ref::parse2`. * Deprecated `ParsedPkcs12` in favor of `ParsedPkcs12_2`. * Deprecated `Pkcs12Builder::build` in favor of `Pkcs12Builder::build2`. ### Added * Added `X509VerifyParamRef::set_auth_level`, `X509VerifyParamRef::auth_level`, and `X509VerifyParamRef::set_purpose`. * Added `X509PurposeId` and `X509Purpose`. * Added `X509NameBuilder::append_entry`. * Added `PKeyRef::private_key_to_pkcs8`. * Added `X509LookupRef::load_crl_file`. * Added `Pkcs12Builder::name`, `Pkcs12Builder::pkey`, and `Pkcs12Builder::cert`. * Added `SslRef::set_method`, `SslRef::set_private_key_file`, `SslRef::set_private_key`, `SslRef::set_certificate`, `SslRef::set_certificate_chain_file`, `SslRef::add_client_ca`, `SslRef::set_client_ca_list`, `SslRef::set_min_proto_version`, `SslREf::set_max_proto_version`, `SslRef::set_ciphersuites`, `SslRef::set_cipher_list`, `SslRef::set_verify_cert_store`. * Added `X509NameRef::to_owned`. * Added `SslContextBuilder::set_num_tickets`, `SslContextRef::num_tickets`, `SslRef::set_num_tickets`, and `SslRef::num_tickets`. * Added `CmsContentInfo::verify`. ## [v0.10.45] - 2022-12-20 ### Fixed * Removed the newly added `CipherCtxRef::minimal_output_size` method, which did not work properly. * Added `NO_DEPRECATED_3_0` cfg checks for more APIs. ### Added * Added `SslRef::add_chain_cert`. * Added `PKeyRef::security_bits`. * Added `Provider::set_default_search_path`. * Added `CipherCtxRef::cipher_final_unchecked`. ## [v0.10.44] - 2022-12-06 ### Added * Added `CipherCtxRef::num`, `CipherCtxRef::minimal_output_size`, and `CipherCtxRef::cipher_update_unchecked`. * Improved output buffer size checks in `CipherCtxRef::cipher_update`. * Added `X509Lookup::file` and `X509LookupRef::load_cert_file`. ## [v0.10.43] - 2022-11-23 ### Added * Added `Nid::BRAINPOOL_P256R1`, `Nid::BRAINPOOL_P384R1`, `Nid::BRAINPOOL_P512R1`. * Added `BigNumRef::copy_from_slice`. * Added `Cipher` constructors for Camellia, CAST5, and IDEA ciphers. * Added `DsaSig`. * Added `X509StoreBuilderRef::set_param`. * Added `X509VerifyParam::new`, `X509VerifyParamRef::set_time`, and `X509VerifyParamRef::set_depth`. ## [v0.10.42] - 2022-09-26 ### Added * Added `SslRef::psk_identity_hint` and `SslRef::psk_identity`. * Added SHA-3 constants to `Nid`. * Added `SslOptions::PRIORITIZE_CHACHA`. * Added `X509ReqRef::to_text`. * Added `MdCtxRef::size`. * Added `X509NameRef::try_cmp`. * Added `MdCtxRef::reset`. * Added experimental, unstable support for BoringSSL. ### Fixed * Fixed `MdCtxRef::digest_verify_init` to support `PKey`s with only public components. ## [v0.10.41] - 2022-06-09 ### Fixed * Fixed a use-after-free in `Error::function` and `Error::file` with OpenSSL 3.x. ### Added * Added `MessageDigest::block_size` and `MdRef::block_size`. * Implemented `Ord` and `Eq` for `X509` and `X509Ref`. * Added `X509Extension::add_alias`. * Added SM4 support. * Added `EcGroup::from_components` `EcGropuRef::set_generator`, and `EcPointRef::set_affine_coordinates_gfp`. ## [v0.10.40] - 2022-05-04 ### Fixed * Fixed the openssl-sys dependency version. ## [v0.10.39] - 2022-05-02 ### Deprecated * Deprecated `SslContextBuilder::set_tmp_ecdh_callback` and `SslRef::set_tmp_ecdh_callback`. ### Added * Added `SslRef::extms_support`. * Added `Nid::create`. * Added `CipherCtx`, which exposes a more direct interface to `EVP_CIPHER_CTX`. * Added `PkeyCtx`, which exposes a more direct interface to `EVP_PKEY_CTX`. * Added `MdCtx`, which exposes a more direct interface to `EVP_MD_CTX`. * Added `Pkcs12Builder::mac_md`. * Added `Provider`. * Added `X509Ref::issuer_name_hash`. * Added `Decrypter::set_rsa_oaep_label`. * Added `X509Ref::to_text`. ## [v0.10.38] - 2021-10-31 ### Added * Added `Pkey::ec_gen`. ## [v0.10.37] - 2021-10-27 ### Fixed * Fixed linkage against OpenSSL distributions built with `no-chacha`. ### Added * Added `BigNumRef::to_vec_padded`. * Added `X509Name::from_der` and `X509NameRef::to_der`. * Added `BigNum::new_secure`, `BigNumReef::set_const_time`, `BigNumref::is_const_time`, and `BigNumRef::is_secure`. ## [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.64...master [v0.10.64]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.63...openssl-v0.10.64 [v0.10.63]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.62...openssl-v0.10.63 [v0.10.62]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.61...openssl-v0.10.62 [v0.10.61]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.60...openssl-v0.10.61 [v0.10.60]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.59...openssl-v0.10.60 [v0.10.59]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.58...openssl-v0.10.59 [v0.10.58]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.57...openssl-v0.10.58 [v0.10.57]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.56...openssl-v0.10.57 [v0.10.56]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.55...openssl-v0.10.56 [v0.10.55]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.54...openssl-v0.10.55 [v0.10.54]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.53...openssl-v0.10.54 [v0.10.53]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.52...openssl-v0.10.53 [v0.10.52]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.51...openssl-v0.10.52 [v0.10.51]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.50...openssl-v0.10.51 [v0.10.50]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.49...openssl-v0.10.50 [v0.10.49]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...openssl-v0.10.49 [v0.10.48]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.47...openssl-v0.10.48 [v0.10.47]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.46...openssl-v0.10.47 [v0.10.46]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.45...openssl-v0.10.46 [v0.10.45]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.44...openssl-v0.10.45 [v0.10.44]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.43...openssl-v0.10.44 [v0.10.43]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.42...openssl-v0.10.43 [v0.10.42]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.41...openssl-v0.10.42 [v0.10.41]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.40...openssl-v0.10.41 [v0.10.40]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.39...openssl-v0.10.40 [v0.10.39]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.38...openssl-v0.10.39 [v0.10.38]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.37...openssl-v0.10.38 [v0.10.37]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.36...openssl-v0.10.37 [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.64/Cargo.lock0000644000000232760000000000100106540ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "annotate-snippets" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e" dependencies = [ "unicode-width", "yansi-term", ] [[package]] name = "bindgen" version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ "annotate-snippets", "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", "lazycell", "log", "peeking_take_while", "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn", "which", ] [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bssl-sys" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "312d12393c060384f2e6ed14c7b4be37b3dd90249857485613c1a91b9a1abb5c" [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clang-sys" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[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 = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" [[package]] name = "libloading" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ "cfg-if", "winapi", ] [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "once_cell" version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "openssl" version = "0.10.64" dependencies = [ "bitflags 2.4.1", "cfg-if", "foreign-types", "hex", "libc", "once_cell", "openssl-macros", "openssl-sys", ] [[package]] name = "openssl-macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "openssl-src" version = "300.1.6+3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085" dependencies = [ "cc", ] [[package]] name = "openssl-sys" version = "0.9.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae94056a791d0e1217d18b6cbdccb02c61e3054fc69893607f4067e3bb0b1fd1" dependencies = [ "bindgen", "bssl-sys", "cc", "libc", "openssl-src", "pkg-config", "vcpkg", ] [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "prettyplease" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", "syn", ] [[package]] name = "proc-macro2" version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39278fbbf5fb4f646ce651690877f89d1c5811a3d4acb27700c1cb3cdb78fd3b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "regex" version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "shlex" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" [[package]] name = "syn" version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-width" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "which" version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2441c784c52b289a054b7201fc93253e288f094e2f4be9058343127c4226a269" dependencies = [ "either", "libc", "once_cell", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "yansi-term" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1" dependencies = [ "winapi", ] openssl-0.10.64/Cargo.toml0000644000000025250000000000100106710ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "openssl" version = "0.10.64" 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 = "2.2.1" [dependencies.cfg-if] version = "1.0" [dependencies.ffi] version = "0.9.100" package = "openssl-sys" [dependencies.foreign-types] version = "0.3.1" [dependencies.libc] version = "0.2" [dependencies.once_cell] version = "1.5.2" [dependencies.openssl-macros] version = "0.1.0" [dev-dependencies.hex] version = "0.3" [features] bindgen = ["ffi/bindgen"] default = [] unstable_boringssl = ["ffi/unstable_boringssl"] v101 = [] v102 = [] v110 = [] v111 = [] vendored = ["ffi/vendored"] openssl-0.10.64/Cargo.toml.orig000064400000000000000000000015151046102023000143500ustar 00000000000000[package] name = "openssl" version = "0.10.64" 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'] bindgen = ['ffi/bindgen'] unstable_boringssl = ["ffi/unstable_boringssl"] default = [] [dependencies] bitflags = "2.2.1" cfg-if = "1.0" foreign-types = "0.3.1" libc = "0.2" once_cell = "1.5.2" openssl-macros = { version = "0.1.0", path = "../openssl-macros" } ffi = { package = "openssl-sys", version = "0.9.100", path = "../openssl-sys" } [dev-dependencies] hex = "0.3" openssl-0.10.64/LICENSE000064400000000000000000000011521046102023000124630ustar 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.64/README.md000064400000000000000000000014761046102023000127460ustar 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.64/build.rs000064400000000000000000000070551046102023000131330ustar 00000000000000#![allow( clippy::inconsistent_digit_grouping, clippy::uninlined_format_args, clippy::unusual_byte_groupings )] use std::env; fn main() { if env::var("DEP_OPENSSL_LIBRESSL").is_ok() { println!("cargo:rustc-cfg=libressl"); } if env::var("DEP_OPENSSL_BORINGSSL").is_ok() { println!("cargo:rustc-cfg=boringssl"); } if let Ok(v) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { let version = u64::from_str_radix(&v, 16).unwrap(); if version >= 0x2_05_00_00_0 { println!("cargo:rustc-cfg=libressl250"); } if version >= 0x2_05_01_00_0 { println!("cargo:rustc-cfg=libressl251"); } 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_01_00_00_0 { println!("cargo:rustc-cfg=libressl310"); } if version >= 0x3_02_01_00_0 { println!("cargo:rustc-cfg=libressl321"); } if version >= 0x3_03_02_00_0 { println!("cargo:rustc-cfg=libressl332"); } if version >= 0x3_04_00_00_0 { println!("cargo:rustc-cfg=libressl340"); } if version >= 0x3_05_00_00_0 { println!("cargo:rustc-cfg=libressl350"); } if version >= 0x3_06_00_00_0 { println!("cargo:rustc-cfg=libressl360"); } if version >= 0x3_06_01_00_0 { println!("cargo:rustc-cfg=libressl361"); } if version >= 0x3_07_00_00_0 { println!("cargo:rustc-cfg=libressl370"); } if version >= 0x3_08_00_00_0 { println!("cargo:rustc-cfg=libressl380"); } if version >= 0x3_08_02_00_0 { println!("cargo:rustc-cfg=libressl382"); } if version >= 0x3_09_00_00_0 { println!("cargo:rustc-cfg=libressl390"); } } 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_00_08_0 { println!("cargo:rustc-cfg=ossl110h"); } 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 version >= 0x3_01_00_00_0 { println!("cargo:rustc-cfg=ossl310"); } if version >= 0x3_02_00_00_0 { println!("cargo:rustc-cfg=ossl320"); } } } openssl-0.10.64/examples/mk_certs.rs000064400000000000000000000126211046102023000154540ustar 00000000000000#![allow(clippy::uninlined_format_args)] //! 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.64/src/aes.rs000064400000000000000000000252761046102023000134000ustar 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 cipher 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 #![cfg_attr( all(not(boringssl), not(osslconf = "OPENSSL_NO_DEPRECATED_3_0")), doc = r#"\ ## 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 cfg_if::cfg_if; use libc::{c_int, c_uint}; use std::mem::MaybeUninit; use std::ptr; #[cfg(not(boringssl))] use crate::symm::Mode; use openssl_macros::corresponds; /// 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); cfg_if! { if #[cfg(boringssl)] { type AesBitType = c_uint; type AesSizeType = usize; } else { type AesBitType = c_int; type AesSizeType = c_uint; } } impl AesKey { /// Prepares a key for encryption. /// /// # Failure /// /// Returns an error if the key is not 128, 192, or 256 bits. #[corresponds(AES_set_encrypt_key)] 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 AesBitType * 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. #[corresponds(AES_set_decrypt_key)] 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 AesBitType * 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. #[cfg(not(boringssl))] #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(AES_ige_encrypt)] 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_` #[corresponds(AES_wrap_key)] 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 AesSizeType, ); 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` #[corresponds(AES_unwrap_key)] 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 AesSizeType, ); if written <= 0 { Err(KeyError(())) } else { Ok(written as usize) } } } #[cfg(test)] mod test { use hex::FromHex; use super::*; #[cfg(not(boringssl))] use crate::symm::Mode; // From https://www.mgp25.com/AESIGE/ #[test] #[cfg(not(boringssl))] #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] 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.64/src/asn1.rs000064400000000000000000000672541046102023000134740ustar 00000000000000#![deny(missing_docs)] //! Defines the format of certificates //! //! 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}; use std::cmp::Ordering; use std::convert::TryInto; 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::stack::Stackable; use crate::string::OpensslString; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; 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(any(ossl102, boringssl))] 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/manmaster/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 #[corresponds(ASN1_TIME_diff)] #[cfg(any(ossl102, boringssl))] 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 #[corresponds(ASN1_TIME_compare)] #[cfg(any(ossl102, boringssl))] 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(any(ossl102, boringssl))] 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(any(ossl102, boringssl))] 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(any(ossl102, boringssl))] 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(any(ossl102, boringssl))] impl PartialOrd for Asn1TimeRef { fn partial_cmp(&self, other: &Asn1TimeRef) -> Option { self.compare(other).ok() } } #[cfg(any(ossl102, boringssl))] impl PartialOrd for Asn1TimeRef { fn partial_cmp(&self, other: &Asn1Time) -> Option { self.compare(other).ok() } } #[cfg(any(ossl102, boringssl))] 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 { #[corresponds(ASN1_TIME_new)] fn new() -> Result { ffi::init(); unsafe { let handle = cvt_p(ffi::ASN1_TIME_new())?; Ok(Asn1Time::from_ptr(handle)) } } #[corresponds(X509_gmtime_adj)] 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 #[corresponds(ASN1_TIME_set)] 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. #[corresponds(ASN1_TIME_set_string)] #[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. /// /// Requires BoringSSL or OpenSSL 1.1.1 or newer. #[corresponds(ASN1_TIME_set_string_X509)] #[cfg(any(ossl111, boringssl))] 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(any(ossl102, boringssl))] 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(any(ossl102, boringssl))] 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(any(ossl102, boringssl))] 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(any(ossl102, boringssl))] impl PartialOrd for Asn1Time { fn partial_cmp(&self, other: &Asn1Time) -> Option { self.compare(other).ok() } } #[cfg(any(ossl102, boringssl))] impl PartialOrd for Asn1Time { fn partial_cmp(&self, other: &Asn1TimeRef) -> Option { self.compare(other).ok() } } #[cfg(any(ossl102, boringssl))] 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/manmaster/crypto/ASN1_STRING_to_UTF8.html pub struct Asn1String; /// A reference to an [`Asn1String`]. 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. #[corresponds(ASN1_STRING_to_UTF8)] 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 #[corresponds(ASN1_STRING_get0_data)] 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. #[corresponds(ASN1_STRING_length)] 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/manmaster/crypto/ASN1_INTEGER_set.html pub struct Asn1Integer; /// A reference to an [`Asn1Integer`]. 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/manmaster/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 Ord for Asn1Integer { fn cmp(&self, other: &Self) -> Ordering { Asn1IntegerRef::cmp(self, other) } } impl PartialOrd for Asn1Integer { fn partial_cmp(&self, other: &Asn1Integer) -> Option { Some(self.cmp(other)) } } impl Eq for Asn1Integer {} impl PartialEq for Asn1Integer { fn eq(&self, other: &Asn1Integer) -> bool { Asn1IntegerRef::eq(self, other) } } impl Asn1IntegerRef { #[allow(missing_docs, clippy::unnecessary_cast)] #[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`. #[corresponds(ASN1_INTEGER_to_BN)] 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`]. /// /// [`bn`]: ../bn/struct.BigNumRef.html#method.to_asn1_integer #[corresponds(ASN1_INTEGER_set)] pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } } /// Creates a new Asn1Integer with the same value. #[corresponds(ASN1_INTEGER_dup)] pub fn to_owned(&self) -> Result { unsafe { cvt_p(ffi::ASN1_INTEGER_dup(self.as_ptr())).map(|p| Asn1Integer::from_ptr(p)) } } } impl Ord for Asn1IntegerRef { fn cmp(&self, other: &Self) -> Ordering { let res = unsafe { ffi::ASN1_INTEGER_cmp(self.as_ptr(), other.as_ptr()) }; res.cmp(&0) } } impl PartialOrd for Asn1IntegerRef { fn partial_cmp(&self, other: &Asn1IntegerRef) -> Option { Some(self.cmp(other)) } } impl Eq for Asn1IntegerRef {} impl PartialEq for Asn1IntegerRef { fn eq(&self, other: &Asn1IntegerRef) -> bool { self.cmp(other) == Ordering::Equal } } 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; /// A reference to an [`Asn1BitString`]. pub struct Asn1BitStringRef; } impl Asn1BitStringRef { /// Returns the Asn1BitString as a slice. #[corresponds(ASN1_STRING_get0_data)] 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. #[corresponds(ASN1_STRING_length)] 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_OCTET_STRING; fn drop = ffi::ASN1_OCTET_STRING_free; /// ASN.1 OCTET STRING type pub struct Asn1OctetString; /// A reference to an [`Asn1OctetString`]. pub struct Asn1OctetStringRef; } impl Asn1OctetString { /// Creates an Asn1OctetString from bytes pub fn new_from_bytes(value: &[u8]) -> Result { ffi::init(); unsafe { let s = cvt_p(ffi::ASN1_OCTET_STRING_new())?; ffi::ASN1_OCTET_STRING_set(s, value.as_ptr(), value.len().try_into().unwrap()); Ok(Self::from_ptr(s)) } } } impl Asn1OctetStringRef { /// Returns the octet string as an array of bytes. #[corresponds(ASN1_STRING_get0_data)] pub fn as_slice(&self) -> &[u8] { unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) } } /// Returns the number of bytes in the octet string. #[corresponds(ASN1_STRING_length)] pub fn len(&self) -> usize { unsafe { ffi::ASN1_STRING_length(self.as_ptr().cast()) 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; fn clone = ffi::OBJ_dup; /// 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/manmaster/crypto/OBJ_obj2nid.html pub struct Asn1Object; /// A reference to an [`Asn1Object`]. pub struct Asn1ObjectRef; } impl Stackable for Asn1Object { type StackType = ffi::stack_st_ASN1_OBJECT; } impl Asn1Object { /// Constructs an ASN.1 Object Identifier from a string representation of the OID. #[corresponds(OBJ_txt2obj)] #[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. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(OBJ_get0_data)] #[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, boringssl))] { 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) } } } foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_ENUMERATED; fn drop = ffi::ASN1_ENUMERATED_free; /// An ASN.1 enumerated. pub struct Asn1Enumerated; /// A reference to an [`Asn1Enumerated`]. pub struct Asn1EnumeratedRef; } impl Asn1EnumeratedRef { /// Get the value, if it fits in the required bounds. #[corresponds(ASN1_ENUMERATED_get_int64)] #[cfg(ossl110)] pub fn get_i64(&self) -> Result { let mut crl_reason = 0; unsafe { cvt(ffi::ASN1_ENUMERATED_get_int64( &mut crl_reason, self.as_ptr(), ))?; } Ok(crl_reason) } } #[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(any(ossl102, boringssl))] 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(any(ossl102, boringssl))] 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 integer_to_owned() { let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); let b = a.to_owned().unwrap(); assert_eq!( a.to_bn().unwrap().to_dec_str().unwrap().to_string(), b.to_bn().unwrap().to_dec_str().unwrap().to_string(), ); assert_ne!(a.as_ptr(), b.as_ptr()); } #[test] fn integer_cmp() { let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); let b = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); let c = Asn1Integer::from_bn(&BigNum::from_dec_str("43").unwrap()).unwrap(); assert!(a == b); assert!(a != c); assert!(a < c); assert!(c > b); } #[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], ); } #[test] fn asn1_octet_string() { let octet_string = Asn1OctetString::new_from_bytes(b"hello world").unwrap(); assert_eq!(octet_string.as_slice(), b"hello world"); assert_eq!(octet_string.len(), 11); } } openssl-0.10.64/src/base64.rs000064400000000000000000000075251046102023000137110ustar 00000000000000//! Base64 encoding support. use crate::error::ErrorStack; use crate::{cvt_n, LenType}; use libc::c_int; use openssl_macros::corresponds; /// Encodes a slice of bytes to a base64 string. /// /// # Panics /// /// Panics if the input length or computed output length overflow a signed C integer. #[corresponds(EVP_EncodeBlock)] pub fn encode_block(src: &[u8]) -> String { assert!(src.len() <= c_int::max_value() as usize); let src_len = src.len() as LenType; 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. /// /// # Panics /// /// Panics if the input length or computed output length overflow a signed C integer. #[corresponds(EVP_DecodeBlock)] 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 LenType; 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: LenType) -> 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: LenType) -> 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.64/src/bio.rs000064400000000000000000000035541046102023000133740ustar 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 crate::SLenType, ))? }; 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) } } #[cfg(not(boringssl))] pub unsafe fn from_ptr(bio: *mut ffi::BIO) -> MemBio { MemBio(bio) } } cfg_if! { if #[cfg(any(ossl102, boringssl))] { 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.64/src/bn.rs000064400000000000000000001327021046102023000132200ustar 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, LenType}; use openssl_macros::corresponds; cfg_if! { if #[cfg(any(ossl110, libressl350))] { 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 if #[cfg(boringssl)] { use ffi::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/manmaster/crypto/BN_CTX_new.html pub struct BigNumContext; /// Reference to [`BigNumContext`] /// /// [`BigNumContext`]: struct.BigNumContext.html pub struct BigNumContextRef; } impl BigNumContext { /// Returns a new `BigNumContext`. #[corresponds(BN_CTX_new)] pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::BN_CTX_new()).map(BigNumContext) } } /// Returns a new secure `BigNumContext`. #[corresponds(BN_CTX_secure_new)] #[cfg(ossl110)] pub fn new_secure() -> Result { unsafe { ffi::init(); cvt_p(ffi::BN_CTX_secure_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/manmaster/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. #[corresponds(BN_clear)] pub fn clear(&mut self) { unsafe { ffi::BN_clear(self.as_ptr()) } } /// Adds a `u32` to `self`. #[corresponds(BN_add_word)] 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`. #[corresponds(BN_sub_word)] 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`. #[corresponds(BN_mul_word)] 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. #[corresponds(BN_div_word)] #[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`. #[corresponds(BN_mod_word)] #[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`. #[corresponds(BN_rand_range)] 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`. #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(BN_pseudo_rand_range)] 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. #[corresponds(BN_set_bit)] #[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. #[corresponds(BN_clear_bit)] #[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. #[corresponds(BN_is_bit_set)] #[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. #[corresponds(BN_mask_bits)] #[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`. #[corresponds(BN_lshift1)] 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`. #[corresponds(BN_rshift1)] 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`. /// /// [`core::ops::Add`]: struct.BigNumRef.html#method.add #[corresponds(BN_add)] 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`. /// /// [`core::ops::Sub`]: struct.BigNumRef.html#method.sub #[corresponds(BN_sub)] 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`. #[corresponds(BN_lshift)] #[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`. #[corresponds(BN_rshift)] #[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. #[corresponds(BN_dup)] 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. #[corresponds(BN_set_negative)] 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`. /// /// # 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); /// ``` #[corresponds(BN_ucmp)] 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. #[corresponds(BN_is_negative)] pub fn is_negative(&self) -> bool { unsafe { BN_is_negative(self.as_ptr()) == 1 } } /// Returns `true` is `self` is even. #[corresponds(BN_is_even)] #[cfg(any(ossl110, boringssl, libressl350))] pub fn is_even(&self) -> bool { !self.is_odd() } /// Returns `true` is `self` is odd. #[corresponds(BN_is_odd)] #[cfg(any(ossl110, boringssl, libressl350))] pub fn is_odd(&self) -> bool { unsafe { ffi::BN_is_odd(self.as_ptr()) == 1 } } /// Returns the number of significant bits in `self`. #[corresponds(BN_num_bits)] #[allow(clippy::unnecessary_cast)] 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)) /// } /// ``` /// /// [`constants`]: index.html#constants #[corresponds(BN_rand)] #[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. #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(BN_pseudo_rand)] #[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)) /// } /// ``` #[corresponds(BN_generate_prime_ex)] 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`. /// /// [`core::ops::Mul`]: struct.BigNumRef.html#method.mul #[corresponds(BN_mul)] 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`. /// /// [`core::ops::Div`]: struct.BigNumRef.html#method.div #[corresponds(BN_div)] 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`. #[corresponds(BN_div)] 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`. #[corresponds(BN_div)] 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`. #[corresponds(BN_sqr)] 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. #[corresponds(BN_nnmod)] 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`. #[corresponds(BN_mod_add)] 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`. #[corresponds(BN_mod_sub)] 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`. #[corresponds(BN_mod_mul)] 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`. #[corresponds(BN_mod_sqr)] 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 into `self` the modular square root of `a` such that `self^2 = a (mod p)` #[corresponds(BN_mod_sqrt)] pub fn mod_sqrt( &mut self, a: &BigNumRef, p: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt_p(ffi::BN_mod_sqrt( self.as_ptr(), a.as_ptr(), p.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places the result of `a^p` in `self`. #[corresponds(BN_exp)] 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`. #[corresponds(BN_mod_exp)] 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`. #[corresponds(BN_mod_inverse)] 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`. #[corresponds(BN_gcd)] 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. /// /// # Return Value /// /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(BN_is_prime_ex)] #[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. /// /// # Return Value /// /// Returns `true` if `self` is prime with an error probability of less than `0.25 ^ checks`. #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[corresponds(BN_is_prime_fasttest_ex)] #[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); /// ``` #[corresponds(BN_bn2bin)] 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 big-endian byte vector representation of the absolute value of `self` padded /// to `pad_to` bytes. /// /// If `pad_to` is less than `self.num_bytes()` then an error is returned. /// /// `self` can be recreated by using `from_slice`. /// /// ``` /// # use openssl::bn::BigNum; /// let bn = BigNum::from_u32(0x4543).unwrap(); /// /// let bn_vec = bn.to_vec_padded(4).unwrap(); /// assert_eq!(&bn_vec, &[0, 0, 0x45, 0x43]); /// /// let r = bn.to_vec_padded(1); /// assert!(r.is_err()); /// /// let bn = -BigNum::from_u32(0x4543).unwrap(); /// let bn_vec = bn.to_vec_padded(4).unwrap(); /// assert_eq!(&bn_vec, &[0, 0, 0x45, 0x43]); /// ``` #[corresponds(BN_bn2binpad)] #[cfg(any(ossl110, libressl340, boringssl))] pub fn to_vec_padded(&self, pad_to: i32) -> Result, ErrorStack> { let mut v = Vec::with_capacity(pad_to as usize); unsafe { cvt(ffi::BN_bn2binpad(self.as_ptr(), v.as_mut_ptr(), pad_to))?; v.set_len(pad_to as usize); } Ok(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"); /// ``` #[corresponds(BN_bn2dec)] 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().to_uppercase(), "-99FF"); /// ``` #[corresponds(BN_bn2hex)] 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`. #[corresponds(BN_to_ASN1_INTEGER)] 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)) } } /// Force constant time computation on this value. #[corresponds(BN_set_flags)] #[cfg(ossl110)] pub fn set_const_time(&mut self) { unsafe { ffi::BN_set_flags(self.as_ptr(), ffi::BN_FLG_CONSTTIME) } } /// Returns true if `self` is in const time mode. #[corresponds(BN_get_flags)] #[cfg(ossl110)] pub fn is_const_time(&self) -> bool { unsafe { let ret = ffi::BN_get_flags(self.as_ptr(), ffi::BN_FLG_CONSTTIME); ret == ffi::BN_FLG_CONSTTIME } } /// Returns true if `self` was created with [`BigNum::new_secure`]. #[corresponds(BN_get_flags)] #[cfg(ossl110)] pub fn is_secure(&self) -> bool { unsafe { let ret = ffi::BN_get_flags(self.as_ptr(), ffi::BN_FLG_SECURE); ret == ffi::BN_FLG_SECURE } } } impl BigNum { /// Creates a new `BigNum` with the value 0. #[corresponds(BN_new)] pub fn new() -> Result { unsafe { ffi::init(); let v = cvt_p(ffi::BN_new())?; Ok(BigNum::from_ptr(v)) } } /// Returns a new secure `BigNum`. #[corresponds(BN_secure_new)] #[cfg(ossl110)] pub fn new_secure() -> Result { unsafe { ffi::init(); let v = cvt_p(ffi::BN_secure_new())?; Ok(BigNum::from_ptr(v)) } } /// Creates a new `BigNum` with the given value. #[corresponds(BN_set_word)] 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. #[corresponds(BN_dec2bn)] 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. #[corresponds(BN_hex2bn)] 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. /// /// [`RFC 2409`]: https://tools.ietf.org/html/rfc2409#page-21 #[corresponds(BN_get_rfc2409_prime_768)] #[cfg(not(boringssl))] 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. /// /// [`RFC 2409`]: https://tools.ietf.org/html/rfc2409#page-21 #[corresponds(BN_get_rfc2409_prime_1024)] #[cfg(not(boringssl))] 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. /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-3 #[corresponds(BN_get_rfc3526_prime_1536)] #[cfg(not(boringssl))] 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. /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-3 #[corresponds(BN_get_rfc3526_prime_2048)] #[cfg(not(boringssl))] 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. /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-4 #[corresponds(BN_get_rfc3526_prime_3072)] #[cfg(not(boringssl))] 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. /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-4 #[corresponds(BN_get_rfc3526_prime_4096)] #[cfg(not(boringssl))] 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. /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-6 #[corresponds(BN_get_rfc3526_prime_6114)] #[cfg(not(boringssl))] 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. /// /// [`RFC 3526`]: https://tools.ietf.org/html/rfc3526#page-6 #[corresponds(BN_get_rfc3526_prime_8192)] #[cfg(not(boringssl))] 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/manmaster/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()); /// ``` #[corresponds(BN_bin2bn)] pub fn from_slice(n: &[u8]) -> Result { unsafe { ffi::init(); assert!(n.len() <= LenType::max_value() as usize); cvt_p(ffi::BN_bin2bn( n.as_ptr(), n.len() as LenType, ptr::null_mut(), )) .map(|p| BigNum::from_ptr(p)) } } /// Copies data from a slice overwriting what was in the BigNum. /// /// This function can be used to copy data from a slice to a /// [secure BigNum][`BigNum::new_secure`]. /// /// # Examples /// /// ``` /// # use openssl::bn::BigNum; /// let mut bignum = BigNum::new().unwrap(); /// bignum.copy_from_slice(&[0x12, 0x00, 0x34]).unwrap(); /// /// assert_eq!(bignum, BigNum::from_u32(0x120034).unwrap()); /// ``` #[corresponds(BN_bin2bn)] pub fn copy_from_slice(&mut self, n: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(n.len() <= LenType::max_value() as usize); cvt_p(ffi::BN_bin2bn(n.as_ptr(), n.len() as LenType, self.0))?; Ok(()) } } } 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 { Some(self.cmp(oth)) } } 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); } #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[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); } #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[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); } #[cfg(not(osslconf = "OPENSSL_NO_DEPRECATED_3_0"))] #[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()); } #[cfg(ossl110)] #[test] fn test_secure_bn_ctx() { let mut cxt = BigNumContext::new_secure().unwrap(); let a = BigNum::from_u32(8).unwrap(); let b = BigNum::from_u32(3).unwrap(); let mut remainder = BigNum::new().unwrap(); remainder.nnmod(&a, &b, &mut cxt).unwrap(); assert!(remainder.eq(&BigNum::from_u32(2).unwrap())); } #[cfg(ossl110)] #[test] fn test_secure_bn() { let a = BigNum::new().unwrap(); assert!(!a.is_secure()); let b = BigNum::new_secure().unwrap(); assert!(b.is_secure()) } #[cfg(ossl110)] #[test] fn test_const_time_bn() { let a = BigNum::new().unwrap(); assert!(!a.is_const_time()); let mut b = BigNum::new().unwrap(); b.set_const_time(); assert!(b.is_const_time()) } #[test] fn test_mod_sqrt() { let mut ctx = BigNumContext::new().unwrap(); let s = BigNum::from_hex_str("2").unwrap(); let p = BigNum::from_hex_str("7DEB1").unwrap(); let mut sqrt = BigNum::new().unwrap(); let mut out = BigNum::new().unwrap(); // Square the root because OpenSSL randomly returns one of 2E42C or 4FA85 sqrt.mod_sqrt(&s, &p, &mut ctx).unwrap(); out.mod_sqr(&sqrt, &p, &mut ctx).unwrap(); assert!(out == s); let s = BigNum::from_hex_str("3").unwrap(); let p = BigNum::from_hex_str("5").unwrap(); assert!(out.mod_sqrt(&s, &p, &mut ctx).is_err()); } #[test] #[cfg(any(ossl110, boringssl, libressl350))] fn test_odd_even() { let a = BigNum::from_u32(17).unwrap(); let b = BigNum::from_u32(18).unwrap(); assert!(a.is_odd()); assert!(!b.is_odd()); assert!(!a.is_even()); assert!(b.is_even()); } } openssl-0.10.64/src/cipher.rs000064400000000000000000000445621046102023000141010ustar 00000000000000//! Symmetric ciphers. #[cfg(ossl300)] use crate::cvt_p; #[cfg(ossl300)] use crate::error::ErrorStack; #[cfg(ossl300)] use crate::lib_ctx::LibCtxRef; use crate::nid::Nid; use cfg_if::cfg_if; use foreign_types::{ForeignTypeRef, Opaque}; use openssl_macros::corresponds; #[cfg(ossl300)] use std::ffi::CString; use std::ops::{Deref, DerefMut}; #[cfg(ossl300)] use std::ptr; cfg_if! { if #[cfg(any(boringssl, ossl110, libressl273))] { use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; } else { use libc::c_int; #[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_if! { if #[cfg(ossl300)] { use foreign_types::ForeignType; type Inner = *mut ffi::EVP_CIPHER; impl Drop for Cipher { #[inline] fn drop(&mut self) { unsafe { ffi::EVP_CIPHER_free(self.as_ptr()); } } } impl ForeignType for Cipher { type CType = ffi::EVP_CIPHER; type Ref = CipherRef; #[inline] unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { Cipher(ptr) } #[inline] fn as_ptr(&self) -> *mut Self::CType { self.0 } } impl Deref for Cipher { type Target = CipherRef; #[inline] fn deref(&self) -> &Self::Target { unsafe { CipherRef::from_ptr(self.as_ptr()) } } } impl DerefMut for Cipher { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { CipherRef::from_ptr_mut(self.as_ptr()) } } } } else { enum Inner {} impl Deref for Cipher { type Target = CipherRef; #[inline] fn deref(&self) -> &Self::Target { match self.0 {} } } impl DerefMut for Cipher { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { match self.0 {} } } } } /// A symmetric cipher. pub struct Cipher(Inner); unsafe impl Sync for Cipher {} unsafe impl Send for Cipher {} impl Cipher { /// Looks up the cipher for a certain nid. #[corresponds(EVP_get_cipherbynid)] pub fn from_nid(nid: Nid) -> Option<&'static CipherRef> { unsafe { let ptr = ffi::EVP_get_cipherbyname(ffi::OBJ_nid2sn(nid.as_raw())); if ptr.is_null() { None } else { Some(CipherRef::from_ptr(ptr as *mut _)) } } } /// Fetches a cipher object corresponding to the specified algorithm name and properties. /// /// Requires OpenSSL 3.0.0 or newer. #[corresponds(EVP_CIPHER_fetch)] #[cfg(ossl300)] pub fn fetch( ctx: Option<&LibCtxRef>, algorithm: &str, properties: Option<&str>, ) -> Result { let algorithm = CString::new(algorithm).unwrap(); let properties = properties.map(|s| CString::new(s).unwrap()); unsafe { let ptr = cvt_p(ffi::EVP_CIPHER_fetch( ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), algorithm.as_ptr(), properties.map_or(ptr::null_mut(), |s| s.as_ptr()), ))?; Ok(Cipher::from_ptr(ptr)) } } pub fn aes_128_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ecb() as *mut _) } } pub fn aes_128_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cbc() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_128_xts() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_xts() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_256_xts() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_xts() as *mut _) } } pub fn aes_128_ctr() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ctr() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_128_cfb1() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb1() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_128_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb128() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_128_cfb8() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb8() as *mut _) } } pub fn aes_128_gcm() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_gcm() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_128_ccm() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ccm() as *mut _) } } pub fn aes_128_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ofb() as *mut _) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_128_ocb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ocb() as *mut _) } } /// Requires OpenSSL 1.0.2 or newer. #[cfg(ossl102)] pub fn aes_128_wrap() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_wrap() as *mut _) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(ossl110)] pub fn aes_128_wrap_pad() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_wrap_pad() as *mut _) } } pub fn aes_192_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ecb() as *mut _) } } pub fn aes_192_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cbc() as *mut _) } } pub fn aes_192_ctr() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ctr() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_192_cfb1() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb1() as *mut _) } } pub fn aes_192_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb128() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_192_cfb8() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb8() as *mut _) } } pub fn aes_192_gcm() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_gcm() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_192_ccm() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ccm() as *mut _) } } pub fn aes_192_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ofb() as *mut _) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_192_ocb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ocb() as *mut _) } } /// Requires OpenSSL 1.0.2 or newer. #[cfg(ossl102)] pub fn aes_192_wrap() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_wrap() as *mut _) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(ossl110)] pub fn aes_192_wrap_pad() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_wrap_pad() as *mut _) } } pub fn aes_256_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ecb() as *mut _) } } pub fn aes_256_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cbc() as *mut _) } } pub fn aes_256_ctr() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ctr() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_256_cfb1() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb1() as *mut _) } } pub fn aes_256_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb128() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_256_cfb8() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb8() as *mut _) } } pub fn aes_256_gcm() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_gcm() as *mut _) } } #[cfg(not(boringssl))] pub fn aes_256_ccm() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ccm() as *mut _) } } pub fn aes_256_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ofb() as *mut _) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_256_ocb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ocb() as *mut _) } } /// Requires OpenSSL 1.0.2 or newer. #[cfg(ossl102)] pub fn aes_256_wrap() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_wrap() as *mut _) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(ossl110)] pub fn aes_256_wrap_pad() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_wrap_pad() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_bf_cbc() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_bf_ecb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_cfb64() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_bf_cfb64() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_bf_ofb() as *mut _) } } pub fn des_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_des_cbc() as *mut _) } } pub fn des_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_des_ecb() as *mut _) } } pub fn des_ede3() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3() as *mut _) } } pub fn des_ede3_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_ecb() as *mut _) } } pub fn des_ede3_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cbc() as *mut _) } } #[cfg(not(boringssl))] pub fn des_ede3_cfb8() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cfb8() as *mut _) } } #[cfg(not(boringssl))] pub fn des_ede3_cfb64() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cfb64() as *mut _) } } #[cfg(not(boringssl))] pub fn des_ede3_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_ofb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn rc4() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_rc4() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia128_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_cfb128() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia128_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_ecb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia128_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_cbc() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia128_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_ofb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia192_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_cfb128() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia192_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_ecb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia192_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_cbc() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia192_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_ofb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia256_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_cfb128() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia256_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_ecb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia256_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_cbc() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia256_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_ofb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_cfb64() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cfb64() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_cast5_ecb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cbc() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_cast5_ofb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_cfb64() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_idea_cfb64() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_idea_ecb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_idea_cbc() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_idea_ofb() as *mut _) } } #[cfg(all(any(ossl110, libressl310), not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn chacha20() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_chacha20() as *mut _) } } #[cfg(all(any(ossl110, libressl360), not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn chacha20_poly1305() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_chacha20_poly1305() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_seed_cbc() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_seed_cfb128() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_seed_ecb() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_SEED"))] pub fn seed_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_seed_ofb() as *mut _) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ecb() as *mut _) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_sm4_cbc() as *mut _) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_ctr() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ctr() as *mut _) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_cfb128() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_sm4_cfb128() as *mut _) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_ofb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ofb() as *mut _) } } } /// A reference to a [`Cipher`]. pub struct CipherRef(Opaque); impl ForeignTypeRef for CipherRef { type CType = ffi::EVP_CIPHER; } unsafe impl Sync for CipherRef {} unsafe impl Send for CipherRef {} impl CipherRef { /// Returns the cipher's Nid. #[corresponds(EVP_CIPHER_nid)] pub fn nid(&self) -> Nid { let nid = unsafe { ffi::EVP_CIPHER_nid(self.as_ptr()) }; Nid::from_raw(nid) } /// Returns the length of keys used with this cipher. #[corresponds(EVP_CIPHER_key_length)] pub fn key_length(&self) -> usize { unsafe { EVP_CIPHER_key_length(self.as_ptr()) as usize } } /// Returns the length of the IV used with this cipher. /// /// # Note /// /// Ciphers that do not use an IV have an IV length of 0. #[corresponds(EVP_CIPHER_iv_length)] pub fn iv_length(&self) -> usize { unsafe { EVP_CIPHER_iv_length(self.as_ptr()) as usize } } /// Returns the block size of the cipher. /// /// # Note /// /// Stream ciphers have a block size of 1. #[corresponds(EVP_CIPHER_block_size)] pub fn block_size(&self) -> usize { unsafe { EVP_CIPHER_block_size(self.as_ptr()) as usize } } } openssl-0.10.64/src/cipher_ctx.rs000064400000000000000000001074001046102023000147460ustar 00000000000000//! The symmetric encryption context. //! //! # Examples //! //! Encrypt data with AES128 CBC //! //! ``` //! use openssl::cipher::Cipher; //! use openssl::cipher_ctx::CipherCtx; //! //! 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 mut ctx = CipherCtx::new().unwrap(); //! ctx.encrypt_init(Some(cipher), Some(key), Some(iv)).unwrap(); //! //! let mut ciphertext = vec![]; //! ctx.cipher_update_vec(data, &mut ciphertext).unwrap(); //! ctx.cipher_final_vec(&mut ciphertext).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[..], //! ); //! ``` //! //! Decrypt data with AES128 CBC //! //! ``` //! use openssl::cipher::Cipher; //! use openssl::cipher_ctx::CipherCtx; //! //! 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 mut ctx = CipherCtx::new().unwrap(); //! ctx.decrypt_init(Some(cipher), Some(key), Some(iv)).unwrap(); //! //! let mut plaintext = vec![]; //! ctx.cipher_update_vec(data, &mut plaintext).unwrap(); //! ctx.cipher_final_vec(&mut plaintext).unwrap(); //! //! assert_eq!(b"Some Crypto Text", &plaintext[..]); //! ``` #![warn(missing_docs)] use crate::cipher::CipherRef; use crate::error::ErrorStack; #[cfg(not(boringssl))] use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef}; use crate::{cvt, cvt_p}; #[cfg(ossl102)] use bitflags::bitflags; use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_uchar}; use openssl_macros::corresponds; use std::convert::{TryFrom, TryInto}; use std::ptr; cfg_if! { if #[cfg(ossl300)] { use ffi::EVP_CIPHER_CTX_get0_cipher; } else { use ffi::EVP_CIPHER_CTX_cipher as EVP_CIPHER_CTX_get0_cipher; } } foreign_type_and_impl_send_sync! { type CType = ffi::EVP_CIPHER_CTX; fn drop = ffi::EVP_CIPHER_CTX_free; /// A context object used to perform symmetric encryption operations. pub struct CipherCtx; /// A reference to a [`CipherCtx`]. pub struct CipherCtxRef; } #[cfg(ossl102)] bitflags! { /// Flags for `EVP_CIPHER_CTX`. pub struct CipherCtxFlags : c_int { /// The flag used to opt into AES key wrap ciphers. const FLAG_WRAP_ALLOW = ffi::EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; } } impl CipherCtx { /// Creates a new context. #[corresponds(EVP_CIPHER_CTX_new)] pub fn new() -> Result { ffi::init(); unsafe { let ptr = cvt_p(ffi::EVP_CIPHER_CTX_new())?; Ok(CipherCtx::from_ptr(ptr)) } } } impl CipherCtxRef { #[corresponds(EVP_CIPHER_CTX_copy)] pub fn copy(&mut self, src: &CipherCtxRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_CIPHER_CTX_copy(self.as_ptr(), src.as_ptr()))?; Ok(()) } } /// Initializes the context for encryption. /// /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used /// to, for example, use a nonstandard IV size. /// /// # Panics /// /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size /// of the cipher, or if a key or IV is provided before a cipher. #[corresponds(EVP_EncryptInit_ex)] pub fn encrypt_init( &mut self, type_: Option<&CipherRef>, key: Option<&[u8]>, iv: Option<&[u8]>, ) -> Result<(), ErrorStack> { self.cipher_init(type_, key, iv, ffi::EVP_EncryptInit_ex) } /// Initializes the context for decryption. /// /// Normally this is called once to set all of the cipher, key, and IV. However, this process can be split up /// by first setting the cipher with no key or IV and then setting the key and IV with no cipher. This can be used /// to, for example, use a nonstandard IV size. /// /// # Panics /// /// Panics if the key buffer is smaller than the key size of the cipher, the IV buffer is smaller than the IV size /// of the cipher, or if a key or IV is provided before a cipher. #[corresponds(EVP_DecryptInit_ex)] pub fn decrypt_init( &mut self, type_: Option<&CipherRef>, key: Option<&[u8]>, iv: Option<&[u8]>, ) -> Result<(), ErrorStack> { self.cipher_init(type_, key, iv, ffi::EVP_DecryptInit_ex) } fn cipher_init( &mut self, type_: Option<&CipherRef>, key: Option<&[u8]>, iv: Option<&[u8]>, f: unsafe extern "C" fn( *mut ffi::EVP_CIPHER_CTX, *const ffi::EVP_CIPHER, *mut ffi::ENGINE, *const c_uchar, *const c_uchar, ) -> c_int, ) -> Result<(), ErrorStack> { if let Some(key) = key { let key_len = type_.map_or_else(|| self.key_length(), |c| c.key_length()); assert!(key_len <= key.len()); } if let Some(iv) = iv { let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); assert!(iv_len <= iv.len()); } unsafe { cvt(f( self.as_ptr(), type_.map_or(ptr::null(), |p| p.as_ptr()), ptr::null_mut(), key.map_or(ptr::null(), |k| k.as_ptr()), iv.map_or(ptr::null(), |iv| iv.as_ptr()), ))?; } Ok(()) } /// Initializes the context to perform envelope encryption. /// /// Normally this is called once to set both the cipher and public keys. However, this process may be split up by /// first providing the cipher with no public keys and then setting the public keys with no cipher. /// /// `encrypted_keys` will contain the generated symmetric key encrypted with each corresponding asymmetric private /// key. The generated IV will be written to `iv`. /// /// # Panics /// /// Panics if `pub_keys` is not the same size as `encrypted_keys`, the IV buffer is smaller than the cipher's IV /// size, or if an IV is provided before the cipher. #[corresponds(EVP_SealInit)] #[cfg(not(boringssl))] pub fn seal_init( &mut self, type_: Option<&CipherRef>, pub_keys: &[PKey], encrypted_keys: &mut [Vec], iv: Option<&mut [u8]>, ) -> Result<(), ErrorStack> where T: HasPublic, { assert_eq!(pub_keys.len(), encrypted_keys.len()); if !pub_keys.is_empty() { let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); assert!(iv.as_ref().map_or(0, |b| b.len()) >= iv_len); } for (pub_key, buf) in pub_keys.iter().zip(&mut *encrypted_keys) { buf.resize(pub_key.size(), 0); } let mut keys = encrypted_keys .iter_mut() .map(|b| b.as_mut_ptr()) .collect::>(); let mut key_lengths = vec![0; pub_keys.len()]; let pub_keys_len = i32::try_from(pub_keys.len()).unwrap(); unsafe { cvt(ffi::EVP_SealInit( self.as_ptr(), type_.map_or(ptr::null(), |p| p.as_ptr()), keys.as_mut_ptr(), key_lengths.as_mut_ptr(), iv.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), pub_keys.as_ptr() as *mut _, pub_keys_len, ))?; } for (buf, len) in encrypted_keys.iter_mut().zip(key_lengths) { buf.truncate(len as usize); } Ok(()) } /// Initializes the context to perform envelope decryption. /// /// Normally this is called once with all of the arguments present. However, this process may be split up by first /// providing the cipher alone and then after providing the rest of the arguments in a second call. /// /// # Panics /// /// Panics if the IV buffer is smaller than the cipher's required IV size or if the IV is provided before the /// cipher. #[corresponds(EVP_OpenInit)] #[cfg(not(boringssl))] pub fn open_init( &mut self, type_: Option<&CipherRef>, encrypted_key: &[u8], iv: Option<&[u8]>, priv_key: Option<&PKeyRef>, ) -> Result<(), ErrorStack> where T: HasPrivate, { if priv_key.is_some() { let iv_len = type_.map_or_else(|| self.iv_length(), |c| c.iv_length()); assert!(iv.map_or(0, |b| b.len()) >= iv_len); } let len = c_int::try_from(encrypted_key.len()).unwrap(); unsafe { cvt(ffi::EVP_OpenInit( self.as_ptr(), type_.map_or(ptr::null(), |p| p.as_ptr()), encrypted_key.as_ptr(), len, iv.map_or(ptr::null(), |b| b.as_ptr()), priv_key.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), ))?; } Ok(()) } fn assert_cipher(&self) { unsafe { assert!(!EVP_CIPHER_CTX_get0_cipher(self.as_ptr()).is_null()); } } /// Returns the block size of the context's cipher. /// /// Stream ciphers will report a block size of 1. /// /// # Panics /// /// Panics if the context has not been initialized with a cipher. #[corresponds(EVP_CIPHER_CTX_block_size)] pub fn block_size(&self) -> usize { self.assert_cipher(); unsafe { ffi::EVP_CIPHER_CTX_block_size(self.as_ptr()) as usize } } /// Returns the key length of the context's cipher. /// /// # Panics /// /// Panics if the context has not been initialized with a cipher. #[corresponds(EVP_CIPHER_CTX_key_length)] pub fn key_length(&self) -> usize { self.assert_cipher(); unsafe { ffi::EVP_CIPHER_CTX_key_length(self.as_ptr()) as usize } } /// Generates a random key based on the configured cipher. /// /// # Panics /// /// Panics if the context has not been initialized with a cipher or if the buffer is smaller than the cipher's key /// length. /// /// This corresponds to [`EVP_CIPHER_CTX_rand_key`]. /// /// [`EVP_CIPHER_CTX_rand_key`]: https://www.openssl.org/docs/manmaster/man3/EVP_CIPHER_CTX_rand_key.html #[corresponds(EVP_CIPHER_CTX_rand_key)] #[cfg(not(boringssl))] pub fn rand_key(&self, buf: &mut [u8]) -> Result<(), ErrorStack> { assert!(buf.len() >= self.key_length()); unsafe { cvt(ffi::EVP_CIPHER_CTX_rand_key( self.as_ptr(), buf.as_mut_ptr(), ))?; } Ok(()) } /// Sets the length of the key expected by the context. /// /// Only some ciphers support configurable key lengths. /// /// # Panics /// /// Panics if the context has not been initialized with a cipher. #[corresponds(EVP_CIPHER_CTX_set_key_length)] pub fn set_key_length(&mut self, len: usize) -> Result<(), ErrorStack> { self.assert_cipher(); unsafe { cvt(ffi::EVP_CIPHER_CTX_set_key_length( self.as_ptr(), len.try_into().unwrap(), ))?; } Ok(()) } /// Returns the length of the IV expected by this context. /// /// Returns 0 if the cipher does not use an IV. /// /// # Panics /// /// Panics if the context has not been initialized with a cipher. #[corresponds(EVP_CIPHER_CTX_iv_length)] pub fn iv_length(&self) -> usize { self.assert_cipher(); unsafe { ffi::EVP_CIPHER_CTX_iv_length(self.as_ptr()) as usize } } /// Returns the `num` parameter of the cipher. /// /// Built-in ciphers typically use this to track how much of the /// current underlying block has been "used" already. /// /// # Panics /// /// Panics if the context has not been initialized with a cipher. #[corresponds(EVP_CIPHER_CTX_num)] #[cfg(ossl110)] pub fn num(&self) -> usize { self.assert_cipher(); unsafe { ffi::EVP_CIPHER_CTX_num(self.as_ptr()) as usize } } /// Sets the length of the IV expected by this context. /// /// Only some ciphers support configurable IV lengths. /// /// # Panics /// /// Panics if the context has not been initialized with a cipher. #[corresponds(EVP_CIPHER_CTX_ctrl)] pub fn set_iv_length(&mut self, len: usize) -> Result<(), ErrorStack> { self.assert_cipher(); let len = c_int::try_from(len).unwrap(); unsafe { cvt(ffi::EVP_CIPHER_CTX_ctrl( self.as_ptr(), ffi::EVP_CTRL_GCM_SET_IVLEN, len, ptr::null_mut(), ))?; } Ok(()) } /// Returns the length of the authentication tag expected by this context. /// /// Returns 0 if the cipher is not authenticated. /// /// # Panics /// /// Panics if the context has not been initialized with a cipher. /// /// Requires OpenSSL 3.0.0 or newer. #[corresponds(EVP_CIPHER_CTX_get_tag_length)] #[cfg(ossl300)] pub fn tag_length(&self) -> usize { self.assert_cipher(); unsafe { ffi::EVP_CIPHER_CTX_get_tag_length(self.as_ptr()) as usize } } /// Retrieves the calculated authentication tag from the context. /// /// This should be called after [`Self::cipher_final`], and is only supported by authenticated ciphers. /// /// The size of the buffer indicates the size of the tag. While some ciphers support a range of tag sizes, it is /// recommended to pick the maximum size. #[corresponds(EVP_CIPHER_CTX_ctrl)] pub fn tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> { let len = c_int::try_from(tag.len()).unwrap(); unsafe { cvt(ffi::EVP_CIPHER_CTX_ctrl( self.as_ptr(), ffi::EVP_CTRL_GCM_GET_TAG, len, tag.as_mut_ptr() as *mut _, ))?; } Ok(()) } /// Sets the length of the generated authentication tag. /// /// This must be called when encrypting with a cipher in CCM mode to use a tag size other than the default. #[corresponds(EVP_CIPHER_CTX_ctrl)] pub fn set_tag_length(&mut self, len: usize) -> Result<(), ErrorStack> { let len = c_int::try_from(len).unwrap(); unsafe { cvt(ffi::EVP_CIPHER_CTX_ctrl( self.as_ptr(), ffi::EVP_CTRL_GCM_SET_TAG, len, ptr::null_mut(), ))?; } Ok(()) } /// Sets the authentication tag for verification during decryption. #[corresponds(EVP_CIPHER_CTX_ctrl)] pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> { let len = c_int::try_from(tag.len()).unwrap(); unsafe { cvt(ffi::EVP_CIPHER_CTX_ctrl( self.as_ptr(), ffi::EVP_CTRL_GCM_SET_TAG, len, tag.as_ptr() as *mut _, ))?; } Ok(()) } /// Enables or disables padding. /// /// If padding is disabled, the plaintext must be an exact multiple of the cipher's block size. #[corresponds(EVP_CIPHER_CTX_set_padding)] pub fn set_padding(&mut self, padding: bool) { unsafe { ffi::EVP_CIPHER_CTX_set_padding(self.as_ptr(), padding as c_int); } } /// Sets the total length of plaintext data. /// /// This is required for ciphers operating in CCM mode. #[corresponds(EVP_CipherUpdate)] pub fn set_data_len(&mut self, len: usize) -> Result<(), ErrorStack> { let len = c_int::try_from(len).unwrap(); unsafe { cvt(ffi::EVP_CipherUpdate( self.as_ptr(), ptr::null_mut(), &mut 0, ptr::null(), len, ))?; } Ok(()) } /// Set ctx flags. /// /// This function is currently used to enable AES key wrap feature supported by OpenSSL 1.0.2 or newer. #[corresponds(EVP_CIPHER_CTX_set_flags)] #[cfg(ossl102)] pub fn set_flags(&mut self, flags: CipherCtxFlags) { unsafe { ffi::EVP_CIPHER_CTX_set_flags(self.as_ptr(), flags.bits()); } } /// Writes data into the context. /// /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD). /// /// Returns the number of bytes written to `output`. /// /// # Panics /// /// Panics if `output` doesn't contain enough space for data to be /// written. #[corresponds(EVP_CipherUpdate)] pub fn cipher_update( &mut self, input: &[u8], output: Option<&mut [u8]>, ) -> Result { if let Some(output) = &output { let mut block_size = self.block_size(); if block_size == 1 { block_size = 0; } let min_output_size = input.len() + block_size; assert!( output.len() >= min_output_size, "Output buffer size should be at least {} bytes.", min_output_size ); } unsafe { self.cipher_update_unchecked(input, output) } } /// Writes data into the context. /// /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD). /// /// Returns the number of bytes written to `output`. /// /// This function is the same as [`Self::cipher_update`] but with the /// output size check removed. It can be used when the exact /// buffer size control is maintained by the caller. /// /// # Safety /// /// The caller is expected to provide `output` buffer /// large enough to contain correct number of bytes. For streaming /// ciphers the output buffer size should be at least as big as /// the input buffer. For block ciphers the size of the output /// buffer depends on the state of partially updated blocks. #[corresponds(EVP_CipherUpdate)] pub unsafe fn cipher_update_unchecked( &mut self, input: &[u8], output: Option<&mut [u8]>, ) -> Result { let inlen = c_int::try_from(input.len()).unwrap(); let mut outlen = 0; cvt(ffi::EVP_CipherUpdate( self.as_ptr(), output.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), &mut outlen, input.as_ptr(), inlen, ))?; Ok(outlen as usize) } /// Like [`Self::cipher_update`] except that it appends output to a [`Vec`]. pub fn cipher_update_vec( &mut self, input: &[u8], output: &mut Vec, ) -> Result { let base = output.len(); output.resize(base + input.len() + self.block_size(), 0); let len = self.cipher_update(input, Some(&mut output[base..]))?; output.truncate(base + len); Ok(len) } /// Like [`Self::cipher_update`] except that it writes output into the /// `data` buffer. The `inlen` parameter specifies the number of bytes in /// `data` that are considered the input. For streaming ciphers, the size of /// `data` must be at least the input size. Otherwise, it must be at least /// an additional block size larger. /// /// Note: Use [`Self::cipher_update`] with no output argument to write AAD. /// /// # Panics /// /// This function panics if the input size cannot be represented as `int` or /// exceeds the buffer size, or if the output buffer does not contain enough /// additional space. #[corresponds(EVP_CipherUpdate)] pub fn cipher_update_inplace( &mut self, data: &mut [u8], inlen: usize, ) -> Result { assert!(inlen <= data.len(), "Input size may not exceed buffer size"); let block_size = self.block_size(); if block_size != 1 { assert!( data.len() >= inlen + block_size, "Output buffer size must be at least {} bytes.", inlen + block_size ); } let inlen = c_int::try_from(inlen).unwrap(); let mut outlen = 0; unsafe { cvt(ffi::EVP_CipherUpdate( self.as_ptr(), data.as_mut_ptr(), &mut outlen, data.as_ptr(), inlen, )) }?; Ok(outlen as usize) } /// Finalizes the encryption or decryption process. /// /// Any remaining data will be written to the output buffer. /// /// Returns the number of bytes written to `output`. /// /// # Panics /// /// Panics if `output` is smaller than the cipher's block size. #[corresponds(EVP_CipherFinal)] pub fn cipher_final(&mut self, output: &mut [u8]) -> Result { let block_size = self.block_size(); if block_size > 1 { assert!(output.len() >= block_size); } unsafe { self.cipher_final_unchecked(output) } } /// Finalizes the encryption or decryption process. /// /// Any remaining data will be written to the output buffer. /// /// Returns the number of bytes written to `output`. /// /// This function is the same as [`Self::cipher_final`] but with /// the output buffer size check removed. /// /// # Safety /// /// The caller is expected to provide `output` buffer /// large enough to contain correct number of bytes. For streaming /// ciphers the output buffer can be empty, for block ciphers the /// output buffer should be at least as big as the block. #[corresponds(EVP_CipherFinal)] pub unsafe fn cipher_final_unchecked( &mut self, output: &mut [u8], ) -> Result { let mut outl = 0; cvt(ffi::EVP_CipherFinal( self.as_ptr(), output.as_mut_ptr(), &mut outl, ))?; Ok(outl as usize) } /// Like [`Self::cipher_final`] except that it appends output to a [`Vec`]. pub fn cipher_final_vec(&mut self, output: &mut Vec) -> Result { let base = output.len(); output.resize(base + self.block_size(), 0); let len = self.cipher_final(&mut output[base..])?; output.truncate(base + len); Ok(len) } } #[cfg(test)] mod test { use super::*; use crate::{cipher::Cipher, rand::rand_bytes}; #[cfg(not(boringssl))] use std::slice; #[test] #[cfg(not(boringssl))] fn seal_open() { 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 ctx = CipherCtx::new().unwrap(); let mut encrypted_key = vec![]; let mut iv = vec![0; cipher.iv_length()]; let mut encrypted = vec![]; ctx.seal_init( Some(cipher), &[public_key], slice::from_mut(&mut encrypted_key), Some(&mut iv), ) .unwrap(); ctx.cipher_update_vec(secret, &mut encrypted).unwrap(); ctx.cipher_final_vec(&mut encrypted).unwrap(); let mut decrypted = vec![]; ctx.open_init(Some(cipher), &encrypted_key, Some(&iv), Some(&private_key)) .unwrap(); ctx.cipher_update_vec(&encrypted, &mut decrypted).unwrap(); ctx.cipher_final_vec(&mut decrypted).unwrap(); assert_eq!(secret, &decrypted[..]); } fn aes_128_cbc(cipher: &CipherRef) { // from https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf let key = hex::decode("2b7e151628aed2a6abf7158809cf4f3c").unwrap(); let iv = hex::decode("000102030405060708090a0b0c0d0e0f").unwrap(); let pt = hex::decode("6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51") .unwrap(); let ct = hex::decode("7649abac8119b246cee98e9b12e9197d5086cb9b507219ee95db113a917678b2") .unwrap(); let mut ctx = CipherCtx::new().unwrap(); ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) .unwrap(); ctx.set_padding(false); let mut buf = vec![]; ctx.cipher_update_vec(&pt, &mut buf).unwrap(); ctx.cipher_final_vec(&mut buf).unwrap(); assert_eq!(buf, ct); ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) .unwrap(); ctx.set_padding(false); let mut buf = vec![]; ctx.cipher_update_vec(&ct, &mut buf).unwrap(); ctx.cipher_final_vec(&mut buf).unwrap(); assert_eq!(buf, pt); } #[test] #[cfg(ossl300)] fn fetched_aes_128_cbc() { let cipher = Cipher::fetch(None, "AES-128-CBC", None).unwrap(); aes_128_cbc(&cipher); } #[test] fn default_aes_128_cbc() { let cipher = Cipher::aes_128_cbc(); aes_128_cbc(cipher); } #[test] fn test_stream_ciphers() { test_stream_cipher(Cipher::aes_192_ctr()); test_stream_cipher(Cipher::aes_256_ctr()); } fn test_stream_cipher(cipher: &'static CipherRef) { let mut key = vec![0; cipher.key_length()]; rand_bytes(&mut key).unwrap(); let mut iv = vec![0; cipher.iv_length()]; rand_bytes(&mut iv).unwrap(); let mut ctx = CipherCtx::new().unwrap(); ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) .unwrap(); ctx.set_padding(false); assert_eq!( 1, cipher.block_size(), "Need a stream cipher, not a block cipher" ); // update cipher with non-full block // this is a streaming cipher so the number of output bytes // will be the same as the number of input bytes let mut output = vec![0; 32]; let outlen = ctx .cipher_update(&[1; 15], Some(&mut output[0..15])) .unwrap(); assert_eq!(15, outlen); // update cipher with missing bytes from the previous block // as previously it will output the same number of bytes as // the input let outlen = ctx .cipher_update(&[1; 17], Some(&mut output[15..])) .unwrap(); assert_eq!(17, outlen); ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); // encrypt again, but use in-place encryption this time // First reset the IV ctx.encrypt_init(None, None, Some(&iv)).unwrap(); ctx.set_padding(false); let mut data_inplace: [u8; 32] = [1; 32]; let outlen = ctx .cipher_update_inplace(&mut data_inplace[0..15], 15) .unwrap(); assert_eq!(15, outlen); let outlen = ctx .cipher_update_inplace(&mut data_inplace[15..32], 17) .unwrap(); assert_eq!(17, outlen); ctx.cipher_final(&mut [0u8; 0]).unwrap(); // Check that the resulting data is encrypted in the same manner assert_eq!(data_inplace.as_slice(), output.as_slice()); // try to decrypt ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) .unwrap(); ctx.set_padding(false); // update cipher with non-full block // expect that the output for stream cipher will contain // the same number of bytes as the input let mut output_decrypted = vec![0; 32]; let outlen = ctx .cipher_update(&output[0..15], Some(&mut output_decrypted[0..15])) .unwrap(); assert_eq!(15, outlen); let outlen = ctx .cipher_update(&output[15..], Some(&mut output_decrypted[15..])) .unwrap(); assert_eq!(17, outlen); ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); // check if the decrypted blocks are the same as input (all ones) assert_eq!(output_decrypted, vec![1; 32]); // decrypt again, but now the output in-place ctx.decrypt_init(None, None, Some(&iv)).unwrap(); ctx.set_padding(false); let outlen = ctx.cipher_update_inplace(&mut output[0..15], 15).unwrap(); assert_eq!(15, outlen); let outlen = ctx.cipher_update_inplace(&mut output[15..], 17).unwrap(); assert_eq!(17, outlen); ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); assert_eq!(output_decrypted, output); } #[test] #[should_panic(expected = "Output buffer size should be at least 33 bytes.")] fn full_block_updates_aes_128() { output_buffer_too_small(Cipher::aes_128_cbc()); } #[test] #[should_panic(expected = "Output buffer size should be at least 33 bytes.")] fn full_block_updates_aes_256() { output_buffer_too_small(Cipher::aes_256_cbc()); } #[test] #[should_panic(expected = "Output buffer size should be at least 17 bytes.")] fn full_block_updates_3des() { output_buffer_too_small(Cipher::des_ede3_cbc()); } fn output_buffer_too_small(cipher: &'static CipherRef) { let mut key = vec![0; cipher.key_length()]; rand_bytes(&mut key).unwrap(); let mut iv = vec![0; cipher.iv_length()]; rand_bytes(&mut iv).unwrap(); let mut ctx = CipherCtx::new().unwrap(); ctx.encrypt_init(Some(cipher), Some(&key), Some(&iv)) .unwrap(); ctx.set_padding(false); let block_size = cipher.block_size(); assert!(block_size > 1, "Need a block cipher, not a stream cipher"); ctx.cipher_update(&vec![0; block_size + 1], Some(&mut vec![0; block_size - 1])) .unwrap(); } #[cfg(ossl102)] fn cipher_wrap_test(cipher: &CipherRef, pt: &str, ct: &str, key: &str, iv: Option<&str>) { let pt = hex::decode(pt).unwrap(); let key = hex::decode(key).unwrap(); let expected = hex::decode(ct).unwrap(); let iv = iv.map(|v| hex::decode(v).unwrap()); let padding = 8 - pt.len() % 8; let mut computed = vec![0; pt.len() + padding + cipher.block_size() * 2]; let mut ctx = CipherCtx::new().unwrap(); ctx.set_flags(CipherCtxFlags::FLAG_WRAP_ALLOW); ctx.encrypt_init(Some(cipher), Some(&key), iv.as_deref()) .unwrap(); let count = ctx.cipher_update(&pt, Some(&mut computed)).unwrap(); let rest = ctx.cipher_final(&mut computed[count..]).unwrap(); computed.truncate(count + rest); 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(ossl102)] fn test_aes128_wrap() { let pt = "00112233445566778899aabbccddeeff"; let ct = "7940ff694448b5bb5139c959a4896832e55d69aa04daa27e"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; let iv = "0001020304050607"; cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, Some(iv)); } #[test] #[cfg(ossl102)] fn test_aes128_wrap_default_iv() { let pt = "00112233445566778899aabbccddeeff"; let ct = "38f1215f0212526f8a70b51955b9fbdc9fe3041d9832306e"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, None); } #[test] #[cfg(ossl110)] fn test_aes128_wrap_pad() { let pt = "00112233445566778899aabbccddee"; let ct = "f13998f5ab32ef82a1bdbcbe585e1d837385b529572a1e1b"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; let iv = "00010203"; cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, Some(iv)); } #[test] #[cfg(ossl110)] fn test_aes128_wrap_pad_default_iv() { let pt = "00112233445566778899aabbccddee"; let ct = "3a501085fb8cf66f4186b7df851914d471ed823411598add"; let key = "2b7e151628aed2a6abf7158809cf4f3c"; cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, None); } #[test] #[cfg(ossl102)] fn test_aes192_wrap() { let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b"; let ct = "83b89142dfeeb4871e078bfb81134d33e23fedc19b03a1cf689973d3831b6813"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; let iv = "0001020304050607"; cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, Some(iv)); } #[test] #[cfg(ossl102)] fn test_aes192_wrap_default_iv() { let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b"; let ct = "c02c2cf11505d3e4851030d5534cbf5a1d7eca7ba8839adbf239756daf1b43e6"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, None); } #[test] #[cfg(ossl110)] fn test_aes192_wrap_pad() { let pt = "00112233445566778899aabbccddee"; let ct = "b4f6bb167ef7caf061a74da82b36ad038ca057ab51e98d3a"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; let iv = "00010203"; cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, Some(iv)); } #[test] #[cfg(ossl110)] fn test_aes192_wrap_pad_default_iv() { let pt = "00112233445566778899aabbccddee"; let ct = "b2c37a28cc602753a7c944a4c2555a2df9c98b2eded5312e"; let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, None); } #[test] #[cfg(ossl102)] fn test_aes256_wrap() { let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"; let ct = "cc05da2a7f56f7dd0c144231f90bce58648fa20a8278f5a6b7d13bba6aa57a33229d4333866b7fd6"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; let iv = "0001020304050607"; cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, Some(iv)); } #[test] #[cfg(ossl102)] fn test_aes256_wrap_default_iv() { let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"; let ct = "0b24f068b50e52bc6987868411c36e1b03900866ed12af81eb87cef70a8d1911731c1d7abf789d88"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, None); } #[test] #[cfg(ossl110)] fn test_aes256_wrap_pad() { let pt = "00112233445566778899aabbccddee"; let ct = "91594e044ccc06130d60e6c84a996aa4f96a9faff8c5f6e7"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; let iv = "00010203"; cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, Some(iv)); } #[test] #[cfg(ossl110)] fn test_aes256_wrap_pad_default_iv() { let pt = "00112233445566778899aabbccddee"; let ct = "dc3c166a854afd68aea624a4272693554bf2e4fcbae602cd"; let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, None); } } openssl-0.10.64/src/cms.rs000064400000000000000000000404541046102023000134050ustar 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::{store::X509StoreRef, X509Ref, X509}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; bitflags! { #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] 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 certificate, `cert`, /// decrypt the data in `self`. #[corresponds(CMS_decrypt)] 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. #[corresponds(CMS_decrypt)] // 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. #[corresponds(i2d_CMS_ContentInfo)] to_der, ffi::i2d_CMS_ContentInfo } to_pem! { /// Serializes this CmsContentInfo using DER. #[corresponds(PEM_write_bio_CMS)] to_pem, ffi::PEM_write_bio_CMS } } impl CmsContentInfo { /// Parses a smime formatted `vec` of bytes into a `CmsContentInfo`. #[corresponds(SMIME_read_CMS)] 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. #[corresponds(d2i_CMS_ContentInfo)] from_der, CmsContentInfo, ffi::d2i_CMS_ContentInfo } from_pem! { /// Deserializes a PEM-encoded ContentInfo structure. #[corresponds(PEM_read_bio_CMS)] 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. #[corresponds(CMS_sign)] 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 #[corresponds(CMS_encrypt)] 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)) } } /// Verify this CmsContentInfo's signature, /// This will search the 'certs' list for the signing certificate. /// Additional certificates, needed for building the certificate chain, may be /// given in 'store' as well as additional CRLs. /// A detached signature may be passed in `detached_data`. The signed content /// without signature, will be copied into output_data if it is present. /// #[corresponds(CMS_verify)] pub fn verify( &mut self, certs: Option<&StackRef>, store: Option<&X509StoreRef>, detached_data: Option<&[u8]>, output_data: Option<&mut Vec>, flags: CMSOptions, ) -> Result<(), ErrorStack> { unsafe { let certs_ptr = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); let store_ptr = store.map_or(ptr::null_mut(), |p| p.as_ptr()); let detached_data_bio = match detached_data { Some(data) => Some(MemBioSlice::new(data)?), None => None, }; let detached_data_bio_ptr = detached_data_bio .as_ref() .map_or(ptr::null_mut(), |p| p.as_ptr()); let out_bio = MemBio::new()?; cvt(ffi::CMS_verify( self.as_ptr(), certs_ptr, store_ptr, detached_data_bio_ptr, out_bio.as_ptr(), flags.bits(), ))?; if let Some(data) = output_data { data.clear(); data.extend_from_slice(out_bio.get_buf()); }; Ok(()) } } } #[cfg(test)] mod test { use super::*; use crate::pkcs12::Pkcs12; use crate::pkey::PKey; use crate::stack::Stack; use crate::x509::{ store::{X509Store, X509StoreBuilder}, X509, }; #[test] fn cms_encrypt_decrypt() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); // 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 .parse2("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.as_ref().unwrap(), priv_cert.cert.as_ref().unwrap(), ) .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.as_ref().unwrap()) .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.as_ref().unwrap(), priv_cert.cert.as_ref().unwrap(), ) .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.as_ref().unwrap()) .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); } } fn cms_sign_verify_generic_helper(is_detached: bool) { // load cert with private key let cert_bytes = include_bytes!("../test/cert.pem"); let cert = X509::from_pem(cert_bytes).expect("failed to load cert.pem"); let key_bytes = include_bytes!("../test/key.pem"); let key = PKey::private_key_from_pem(key_bytes).expect("failed to load key.pem"); let root_bytes = include_bytes!("../test/root-ca.pem"); let root = X509::from_pem(root_bytes).expect("failed to load root-ca.pem"); // sign cms message using public key cert let data = b"Hello world!"; let (opt, ext_data): (CMSOptions, Option<&[u8]>) = if is_detached { (CMSOptions::DETACHED | CMSOptions::BINARY, Some(data)) } else { (CMSOptions::empty(), None) }; let mut cms = CmsContentInfo::sign(Some(&cert), Some(&key), None, Some(data), opt) .expect("failed to CMS sign a message"); // check CMS signature length let pem_cms = cms .to_pem() .expect("failed to pack CmsContentInfo into PEM"); assert!(!pem_cms.is_empty()); // verify CMS signature let mut builder = X509StoreBuilder::new().expect("failed to create X509StoreBuilder"); builder .add_cert(root) .expect("failed to add root-ca into X509StoreBuilder"); let store: X509Store = builder.build(); let mut out_data: Vec = Vec::new(); let res = cms.verify( None, Some(&store), ext_data, Some(&mut out_data), CMSOptions::empty(), ); // check verification result - valid signature res.unwrap(); assert_eq!(data.to_vec(), out_data); } #[test] fn cms_sign_verify_ok() { cms_sign_verify_generic_helper(false); } #[test] fn cms_sign_verify_detached_ok() { cms_sign_verify_generic_helper(true); } #[test] fn cms_sign_verify_error() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); // 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 .parse2("mypass") .expect("failed to parse priv cert"); // sign cms message using public key cert let data = b"Hello world!"; let mut cms = CmsContentInfo::sign( Some(&priv_cert.cert.unwrap()), Some(&priv_cert.pkey.unwrap()), None, Some(data), CMSOptions::empty(), ) .expect("failed to CMS sign a message"); // check CMS signature length let pem_cms = cms .to_pem() .expect("failed to pack CmsContentInfo into PEM"); assert!(!pem_cms.is_empty()); let empty_store = X509StoreBuilder::new() .expect("failed to create X509StoreBuilder") .build(); // verify CMS signature let res = cms.verify( None, Some(&empty_store), Some(data), None, CMSOptions::empty(), ); // check verification result - this is an invalid signature // defined in openssl crypto/cms/cms.h const CMS_R_CERTIFICATE_VERIFY_ERROR: i32 = 100; let es = res.unwrap_err(); let error_array = es.errors(); assert_eq!(1, error_array.len()); let code = error_array[0].reason_code(); assert_eq!(code, CMS_R_CERTIFICATE_VERIFY_ERROR); } } openssl-0.10.64/src/conf.rs000064400000000000000000000034311046102023000135420ustar 00000000000000//! Interface for processing OpenSSL configuration files. foreign_type_and_impl_send_sync! { type CType = ffi::CONF; fn drop = ffi::NCONF_free; pub struct Conf; pub struct ConfRef; } #[cfg(not(boringssl))] mod methods { use super::Conf; use crate::cvt_p; use crate::error::ErrorStack; use openssl_macros::corresponds; pub struct ConfMethod(*mut ffi::CONF_METHOD); impl ConfMethod { /// Retrieve handle to the default OpenSSL configuration file processing function. #[corresponds(NCONF_default)] #[allow(clippy::should_implement_trait)] 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 } } impl Conf { /// Create a configuration parser. /// /// # Examples /// /// ``` /// use openssl::conf::{Conf, ConfMethod}; /// /// let conf = Conf::new(ConfMethod::default()); /// ``` #[corresponds(NCONF_new)] pub fn new(method: ConfMethod) -> Result { unsafe { cvt_p(ffi::NCONF_new(method.as_ptr())).map(Conf) } } } } #[cfg(not(boringssl))] pub use methods::*; openssl-0.10.64/src/derive.rs000064400000000000000000000157241046102023000141030ustar 00000000000000//! Shared secret derivation. //! //! # Example //! //! The following example implements [ECDH] using `NIST P-384` keys: //! //! ``` //! # fn main() -> Result<(), Box> { //! # use std::convert::TryInto; //! use openssl::bn::BigNumContext; //! use openssl::pkey::PKey; //! use openssl::derive::Deriver; //! use openssl::ec::{EcGroup, EcKey, EcPoint, PointConversionForm}; //! use openssl::nid::Nid; //! //! let group = EcGroup::from_curve_name(Nid::SECP384R1)?; //! //! let first: PKey<_> = EcKey::generate(&group)?.try_into()?; //! //! // second party generates an ephemeral key and derives //! // a shared secret using first party's public key //! let shared_key = EcKey::generate(&group)?; //! // shared_public is sent to first party //! let mut ctx = BigNumContext::new()?; //! let shared_public = shared_key.public_key().to_bytes( //! &group, //! PointConversionForm::COMPRESSED, //! &mut ctx, //! )?; //! //! let shared_key: PKey<_> = shared_key.try_into()?; //! let mut deriver = Deriver::new(&shared_key)?; //! deriver.set_peer(&first)?; //! // secret can be used e.g. as a symmetric encryption key //! let secret = deriver.derive_to_vec()?; //! # drop(deriver); //! //! // first party derives the same shared secret using //! // shared_public //! let point = EcPoint::from_bytes(&group, &shared_public, &mut ctx)?; //! let recipient_key: PKey<_> = EcKey::from_public_key(&group, &point)?.try_into()?; //! let mut deriver = Deriver::new(&first)?; //! deriver.set_peer(&recipient_key)?; //! let first_secret = deriver.derive_to_vec()?; //! //! assert_eq!(secret, first_secret); //! # Ok(()) } //! ``` //! //! [ECDH]: https://wiki.openssl.org/index.php/Elliptic_Curve_Diffie_Hellman 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}; use openssl_macros::corresponds; /// 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/manmaster/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. #[corresponds(EVP_PKEY_derive_set_peer)] 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(|_| ()) } } /// Sets the peer key used for secret derivation along with optionally validating the peer public key. /// /// Requires OpenSSL 3.0.0 or newer. #[corresponds(EVP_PKEY_derive_set_peer_ex)] #[cfg(ossl300)] pub fn set_peer_ex( &mut self, key: &'a PKeyRef, validate_peer: bool, ) -> Result<(), ErrorStack> where T: HasPublic, { unsafe { cvt(ffi::EVP_PKEY_derive_set_peer_ex( self.0, key.as_ptr(), validate_peer as i32, )) .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/manmaster/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/manmaster/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()); } #[test] #[cfg(ossl300)] fn test_ec_key_derive_ex() { 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_ex(&pkey2, true).unwrap(); let shared = deriver.derive_to_vec().unwrap(); assert!(!shared.is_empty()); } } openssl-0.10.64/src/dh.rs000064400000000000000000000503761046102023000132220ustar 00000000000000//! Diffie-Hellman key agreement. use 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, Public}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; 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-----`. #[corresponds(PEM_write_bio_DHparams)] params_to_pem, ffi::PEM_write_bio_DHparams } to_der! { /// Serializes the parameters into a DER-encoded PKCS#3 DHparameter structure. #[corresponds(i2d_DHparams)] params_to_der, ffi::i2d_DHparams } /// Validates DH parameters for correctness #[corresponds(DH_check_key)] pub fn check_key(&self) -> Result { unsafe { let mut codes = 0; cvt(ffi::DH_check(self.as_ptr(), &mut codes))?; Ok(codes == 0) } } } 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. #[corresponds(DH_set0_pqg)] 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 public key on the DH object. pub fn set_public_key(self, pub_key: BigNum) -> Result, ErrorStack> { unsafe { let dh_ptr = self.0; cvt(DH_set0_key(dh_ptr, pub_key.as_ptr(), ptr::null_mut()))?; mem::forget((self, pub_key)); Ok(Dh::from_ptr(dh_ptr)) } } /// 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)) } } /// Sets the public and private keys on the DH object. pub fn set_key(self, pub_key: BigNum, priv_key: BigNum) -> Result, ErrorStack> { unsafe { let dh_ptr = self.0; cvt(DH_set0_key(dh_ptr, pub_key.as_ptr(), priv_key.as_ptr()))?; mem::forget((self, pub_key, priv_key)); Ok(Dh::from_ptr(dh_ptr)) } } /// Generates DH params based on the given `prime_len` and a fixed `generator` value. #[corresponds(DH_generate_parameters_ex)] 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. #[corresponds(DH_generate_key)] 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-----`. #[corresponds(PEM_read_bio_DHparams)] params_from_pem, Dh, ffi::PEM_read_bio_DHparams } from_der! { /// Deserializes a DER-encoded PKCS#3 DHparameters structure. #[corresponds(d2i_DHparams)] params_from_der, Dh, ffi::d2i_DHparams } /// Requires OpenSSL 1.0.2 or newer. #[corresponds(DH_get_1024_160)] #[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. #[corresponds(DH_get_2048_224)] #[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. #[corresponds(DH_get_2048_256)] #[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. #[corresponds(DH_get0_pqg)] 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. #[corresponds(DH_get0_pqg)] 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. #[corresponds(DH_get0_pqg)] 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. #[corresponds(DH_get0_key)] 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`. #[corresponds(DH_compute_key)] 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. #[corresponds(DH_get0_key)] 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, boringssl))] { 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; #[cfg(all(not(boringssl), ossl110))] use crate::pkey::PKey; 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(all(not(boringssl), ossl110))] fn test_from_dhx_serializes_q() { let p = BigNum::from_hex_str("00ad107e1e9123a9d0d660faa79559c51fa20d64e5683b9fd1b54b1597b61d0a75e6fa141df95a56dbaf9a3c407ba1df15eb3d688a309c180e1de6b85a1274a0a66d3f8152ad6ac2129037c9edefda4df8d91e8fef55b7394b7ad5b7d0b6c12207c9f98d11ed34dbf6c6ba0b2c8bbc27be6a00e0a0b9c49708b3bf8a317091883681286130bc8985db1602e714415d9330278273c7de31efdc7310f7121fd5a07415987d9adc0a486dcdf93acc44328387315d75e198c641a480cd86a1b9e587e8be60e69cc928b2b9c52172e413042e9b23f10b0e16e79763c9b53dcf4ba80a29e3fb73c16b8e75b97ef363e2ffa31f71cf9de5384e71b81c0ac4dffe0c10e64f").unwrap(); let g = BigNum::from_hex_str("00ac4032ef4f2d9ae39df30b5c8ffdac506cdebe7b89998caf74866a08cfe4ffe3a6824a4e10b9a6f0dd921f01a70c4afaab739d7700c29f52c57db17c620a8652be5e9001a8d66ad7c17669101999024af4d027275ac1348bb8a762d0521bc98ae247150422ea1ed409939d54da7460cdb5f6c6b250717cbef180eb34118e98d119529a45d6f834566e3025e316a330efbb77a86f0c1ab15b051ae3d428c8f8acb70a8137150b8eeb10e183edd19963ddd9e263e4770589ef6aa21e7f5f2ff381b539cce3409d13cd566afbb48d6c019181e1bcfe94b30269edfe72fe9b6aa4bd7b5a0f1c71cfff4c19c418e1f6ec017981bc087f2a7065b384b890d3191f2bfa").unwrap(); let q = BigNum::from_hex_str("00801c0d34c58d93fe997177101f80535a4738cebcbf389a99b36371eb") .unwrap(); let y = BigNum::from_hex_str("0082c165bb576243ecf46d58c3d1501616955fca0320fa95ea11d2e6c1b9cf217676720dc1c08c85bf20c4d232b60a29a1e51c7b773bc645014587c525c86151b30d75486ec7b6c98efb5f74955b83116d01d0af1232af89213c2de574369d701aba9357300b920d3d8b98252d46c46952c16a5f33554b38317809c7b9add4701f5c158c1b7035e9fe39366ececb90d2896b78c523c4a577287ef5ba7a2663ed58aa20b5ec66e30f316610dfaa38583e495ab6af771c284387e660edbef4edb872e2e80e1d244ee95622e76d028e61c1e887c2aa792717362139f4dd26eafd49b2366eeb2350b01fe1b56022a2809e379559c37b375ba01c4eaacc14fd1b247837").unwrap(); let dh = Dh::from_params(p, g, q).unwrap(); let dh = dh.set_public_key(y).unwrap(); // Verify that 'q' is serialized in the public key. let pkey = PKey::from_dhx(dh).unwrap(); assert_eq!(pkey.public_key_to_der().unwrap(), b"\x30\x82\x03\x44\x30\x82\x02\x36\x06\x07\x2a\x86\x48\xce\x3e\x02\x01\x30\x82\x02\x29\x02\x82\x01\x01\x00\xad\x10\x7e\x1e\x91\x23\xa9\xd0\xd6\x60\xfa\xa7\x95\x59\xc5\x1f\xa2\x0d\x64\xe5\x68\x3b\x9f\xd1\xb5\x4b\x15\x97\xb6\x1d\x0a\x75\xe6\xfa\x14\x1d\xf9\x5a\x56\xdb\xaf\x9a\x3c\x40\x7b\xa1\xdf\x15\xeb\x3d\x68\x8a\x30\x9c\x18\x0e\x1d\xe6\xb8\x5a\x12\x74\xa0\xa6\x6d\x3f\x81\x52\xad\x6a\xc2\x12\x90\x37\xc9\xed\xef\xda\x4d\xf8\xd9\x1e\x8f\xef\x55\xb7\x39\x4b\x7a\xd5\xb7\xd0\xb6\xc1\x22\x07\xc9\xf9\x8d\x11\xed\x34\xdb\xf6\xc6\xba\x0b\x2c\x8b\xbc\x27\xbe\x6a\x00\xe0\xa0\xb9\xc4\x97\x08\xb3\xbf\x8a\x31\x70\x91\x88\x36\x81\x28\x61\x30\xbc\x89\x85\xdb\x16\x02\xe7\x14\x41\x5d\x93\x30\x27\x82\x73\xc7\xde\x31\xef\xdc\x73\x10\xf7\x12\x1f\xd5\xa0\x74\x15\x98\x7d\x9a\xdc\x0a\x48\x6d\xcd\xf9\x3a\xcc\x44\x32\x83\x87\x31\x5d\x75\xe1\x98\xc6\x41\xa4\x80\xcd\x86\xa1\xb9\xe5\x87\xe8\xbe\x60\xe6\x9c\xc9\x28\xb2\xb9\xc5\x21\x72\xe4\x13\x04\x2e\x9b\x23\xf1\x0b\x0e\x16\xe7\x97\x63\xc9\xb5\x3d\xcf\x4b\xa8\x0a\x29\xe3\xfb\x73\xc1\x6b\x8e\x75\xb9\x7e\xf3\x63\xe2\xff\xa3\x1f\x71\xcf\x9d\xe5\x38\x4e\x71\xb8\x1c\x0a\xc4\xdf\xfe\x0c\x10\xe6\x4f\x02\x82\x01\x01\x00\xac\x40\x32\xef\x4f\x2d\x9a\xe3\x9d\xf3\x0b\x5c\x8f\xfd\xac\x50\x6c\xde\xbe\x7b\x89\x99\x8c\xaf\x74\x86\x6a\x08\xcf\xe4\xff\xe3\xa6\x82\x4a\x4e\x10\xb9\xa6\xf0\xdd\x92\x1f\x01\xa7\x0c\x4a\xfa\xab\x73\x9d\x77\x00\xc2\x9f\x52\xc5\x7d\xb1\x7c\x62\x0a\x86\x52\xbe\x5e\x90\x01\xa8\xd6\x6a\xd7\xc1\x76\x69\x10\x19\x99\x02\x4a\xf4\xd0\x27\x27\x5a\xc1\x34\x8b\xb8\xa7\x62\xd0\x52\x1b\xc9\x8a\xe2\x47\x15\x04\x22\xea\x1e\xd4\x09\x93\x9d\x54\xda\x74\x60\xcd\xb5\xf6\xc6\xb2\x50\x71\x7c\xbe\xf1\x80\xeb\x34\x11\x8e\x98\xd1\x19\x52\x9a\x45\xd6\xf8\x34\x56\x6e\x30\x25\xe3\x16\xa3\x30\xef\xbb\x77\xa8\x6f\x0c\x1a\xb1\x5b\x05\x1a\xe3\xd4\x28\xc8\xf8\xac\xb7\x0a\x81\x37\x15\x0b\x8e\xeb\x10\xe1\x83\xed\xd1\x99\x63\xdd\xd9\xe2\x63\xe4\x77\x05\x89\xef\x6a\xa2\x1e\x7f\x5f\x2f\xf3\x81\xb5\x39\xcc\xe3\x40\x9d\x13\xcd\x56\x6a\xfb\xb4\x8d\x6c\x01\x91\x81\xe1\xbc\xfe\x94\xb3\x02\x69\xed\xfe\x72\xfe\x9b\x6a\xa4\xbd\x7b\x5a\x0f\x1c\x71\xcf\xff\x4c\x19\xc4\x18\xe1\xf6\xec\x01\x79\x81\xbc\x08\x7f\x2a\x70\x65\xb3\x84\xb8\x90\xd3\x19\x1f\x2b\xfa\x02\x1d\x00\x80\x1c\x0d\x34\xc5\x8d\x93\xfe\x99\x71\x77\x10\x1f\x80\x53\x5a\x47\x38\xce\xbc\xbf\x38\x9a\x99\xb3\x63\x71\xeb\x03\x82\x01\x06\x00\x02\x82\x01\x01\x00\x82\xc1\x65\xbb\x57\x62\x43\xec\xf4\x6d\x58\xc3\xd1\x50\x16\x16\x95\x5f\xca\x03\x20\xfa\x95\xea\x11\xd2\xe6\xc1\xb9\xcf\x21\x76\x76\x72\x0d\xc1\xc0\x8c\x85\xbf\x20\xc4\xd2\x32\xb6\x0a\x29\xa1\xe5\x1c\x7b\x77\x3b\xc6\x45\x01\x45\x87\xc5\x25\xc8\x61\x51\xb3\x0d\x75\x48\x6e\xc7\xb6\xc9\x8e\xfb\x5f\x74\x95\x5b\x83\x11\x6d\x01\xd0\xaf\x12\x32\xaf\x89\x21\x3c\x2d\xe5\x74\x36\x9d\x70\x1a\xba\x93\x57\x30\x0b\x92\x0d\x3d\x8b\x98\x25\x2d\x46\xc4\x69\x52\xc1\x6a\x5f\x33\x55\x4b\x38\x31\x78\x09\xc7\xb9\xad\xd4\x70\x1f\x5c\x15\x8c\x1b\x70\x35\xe9\xfe\x39\x36\x6e\xce\xcb\x90\xd2\x89\x6b\x78\xc5\x23\xc4\xa5\x77\x28\x7e\xf5\xba\x7a\x26\x63\xed\x58\xaa\x20\xb5\xec\x66\xe3\x0f\x31\x66\x10\xdf\xaa\x38\x58\x3e\x49\x5a\xb6\xaf\x77\x1c\x28\x43\x87\xe6\x60\xed\xbe\xf4\xed\xb8\x72\xe2\xe8\x0e\x1d\x24\x4e\xe9\x56\x22\xe7\x6d\x02\x8e\x61\xc1\xe8\x87\xc2\xaa\x79\x27\x17\x36\x21\x39\xf4\xdd\x26\xea\xfd\x49\xb2\x36\x6e\xeb\x23\x50\xb0\x1f\xe1\xb5\x60\x22\xa2\x80\x9e\x37\x95\x59\xc3\x7b\x37\x5b\xa0\x1c\x4e\xaa\xcc\x14\xfd\x1b\x24\x78\x37"); } #[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] #[cfg(ossl102)] fn test_set_keys() { let dh1 = Dh::get_2048_256().unwrap(); let key1 = dh1.generate_key().unwrap(); let dh2 = Dh::get_2048_256().unwrap(); let key2 = dh2 .set_public_key(key1.public_key().to_owned().unwrap()) .unwrap(); assert_eq!(key1.public_key(), key2.public_key()); let dh3 = Dh::get_2048_256().unwrap(); let key3 = dh3 .set_key( key1.public_key().to_owned().unwrap(), key1.private_key().to_owned().unwrap(), ) .unwrap(); assert_eq!(key1.public_key(), key3.public_key()); assert_eq!(key1.private_key(), key3.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); } #[test] fn test_dh_check_key() { let dh1 = Dh::generate_params(512, 2).unwrap(); let p = BigNum::from_hex_str("04").unwrap(); let g = BigNum::from_hex_str("02").unwrap(); let dh2 = Dh::from_pqg(p, None, g).unwrap(); assert!(dh1.check_key().unwrap()); assert!(matches!(dh2.check_key(), Ok(false) | Err(_))); } } openssl-0.10.64/src/dsa.rs000064400000000000000000000516241046102023000133730ustar 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}; #[cfg(not(boringssl))] 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, Params, Private, Public}; use crate::util::ForeignTypeRefExt; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; 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/manmaster/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! { /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. #[corresponds(PEM_write_bio_DSA_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_DSA_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. #[corresponds(i2d_DSA_PUBKEY)] public_key_to_der, ffi::i2d_DSA_PUBKEY } /// Returns a reference to the public key component of `self`. #[corresponds(DSA_get0_key)] 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-----`. #[corresponds(PEM_write_bio_DSAPrivateKey)] 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-----`. #[corresponds(PEM_write_bio_DSAPrivateKey)] private_key_to_pem_passphrase, ffi::PEM_write_bio_DSAPrivateKey } to_der! { /// Serializes the private_key to a DER-encoded `DSAPrivateKey` structure. #[corresponds(i2d_DSAPrivateKey)] private_key_to_der, ffi::i2d_DSAPrivateKey } /// Returns a reference to the private key component of `self`. #[corresponds(DSA_get0_key)] 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. #[corresponds(DSA_size)] pub fn size(&self) -> u32 { unsafe { ffi::DSA_size(self.as_ptr()) as u32 } } /// Returns the DSA prime parameter of `self`. #[corresponds(DSA_get0_pqg)] 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`. #[corresponds(DSA_get0_pqg)] 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`. #[corresponds(DSA_get0_pqg)] 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) } } } #[cfg(boringssl)] type BitType = libc::c_uint; #[cfg(not(boringssl))] type BitType = c_int; impl Dsa { /// Creates a DSA params based upon the given parameters. #[corresponds(DSA_set0_pqg)] pub fn from_pqg(p: BigNum, q: BigNum, g: BigNum) -> Result, ErrorStack> { 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)); Ok(dsa) } } /// Generates DSA params based on the given number of bits. #[corresponds(DSA_generate_parameters_ex)] pub fn generate_params(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 BitType, ptr::null(), 0, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ))?; Ok(dsa) } } /// Generates a private key based on the DSA params. #[corresponds(DSA_generate_key)] pub fn generate_key(self) -> Result, ErrorStack> { unsafe { let dsa_ptr = self.0; cvt(ffi::DSA_generate_key(dsa_ptr))?; mem::forget(self); Ok(Dsa::from_ptr(dsa_ptr)) } } } impl Dsa { /// Generate a DSA key pair. /// /// The `bits` parameter corresponds to the length of the prime `p`. pub fn generate(bits: u32) -> Result, ErrorStack> { let params = Dsa::generate_params(bits)?; params.generate_key() } /// 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-----`. #[corresponds(PEM_read_bio_DSA_PUBKEY)] public_key_from_pem, Dsa, ffi::PEM_read_bio_DSA_PUBKEY } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a DSA key. #[corresponds(d2i_DSA_PUBKEY)] 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, boringssl))] { 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 } } } foreign_type_and_impl_send_sync! { type CType = ffi::DSA_SIG; fn drop = ffi::DSA_SIG_free; /// Object representing DSA signature. /// /// DSA signatures consist of two components: `r` and `s`. /// /// # Examples /// /// ``` /// use std::convert::TryInto; /// /// use openssl::bn::BigNum; /// use openssl::dsa::{Dsa, DsaSig}; /// use openssl::hash::MessageDigest; /// use openssl::pkey::PKey; /// use openssl::sign::{Signer, Verifier}; /// /// const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; /// let dsa_ref = Dsa::generate(1024).unwrap(); /// /// let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap(); /// let priv_key: PKey<_> = dsa_ref.try_into().unwrap(); /// /// let mut signer = if let Ok(signer) = Signer::new(MessageDigest::sha256(), &priv_key) { /// signer /// } else { /// // DSA signing is not supported (eg. BoringSSL) /// return; /// }; /// /// signer.update(TEST_DATA).unwrap(); /// /// let signature = signer.sign_to_vec().unwrap(); /// // Parse DER-encoded DSA signature /// let signature = DsaSig::from_der(&signature).unwrap(); /// /// // Extract components `r` and `s` /// let r = BigNum::from_slice(&signature.r().to_vec()).unwrap(); /// let s = BigNum::from_slice(&signature.s().to_vec()).unwrap(); /// /// // Construct new DSA signature from components /// let signature = DsaSig::from_private_components(r, s).unwrap(); /// /// // Serialize DSA signature to DER /// let signature = signature.to_der().unwrap(); /// /// let mut verifier = Verifier::new(MessageDigest::sha256(), &pub_key).unwrap(); /// verifier.update(TEST_DATA).unwrap(); /// assert!(verifier.verify(&signature[..]).unwrap()); /// ``` pub struct DsaSig; /// Reference to a [`DsaSig`]. pub struct DsaSigRef; } impl DsaSig { /// Returns a new `DsaSig` by setting the `r` and `s` values associated with an DSA signature. #[corresponds(DSA_SIG_set0)] pub fn from_private_components(r: BigNum, s: BigNum) -> Result { unsafe { let sig = cvt_p(ffi::DSA_SIG_new())?; DSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); mem::forget((r, s)); Ok(DsaSig::from_ptr(sig)) } } from_der! { /// Decodes a DER-encoded DSA signature. #[corresponds(d2i_DSA_SIG)] from_der, DsaSig, ffi::d2i_DSA_SIG } } impl fmt::Debug for DsaSig { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("DsaSig") .field("r", self.r()) .field("s", self.s()) .finish() } } impl DsaSigRef { to_der! { /// Serializes the DSA signature into a DER-encoded `DSASignature` structure. #[corresponds(i2d_DSA_SIG)] to_der, ffi::i2d_DSA_SIG } /// Returns internal component `r` of an `DsaSig`. #[corresponds(DSA_SIG_get0)] pub fn r(&self) -> &BigNumRef { unsafe { let mut r = ptr::null(); DSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); BigNumRef::from_const_ptr(r) } } /// Returns internal component `s` of an `DsaSig`. #[corresponds(DSA_SIG_get0)] pub fn s(&self) -> &BigNumRef { unsafe { let mut s = ptr::null(); DSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); BigNumRef::from_const_ptr(s) } } } cfg_if! { if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{DSA_SIG_set0, DSA_SIG_get0}; } else { #[allow(bad_style)] unsafe fn DSA_SIG_set0( sig: *mut ffi::DSA_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 DSA_SIG_get0( sig: *const ffi::DSA_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::bn::BigNumContext; #[cfg(not(boringssl))] use crate::hash::MessageDigest; #[cfg(not(boringssl))] use crate::pkey::PKey; #[cfg(not(boringssl))] 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_params() { let params = Dsa::generate_params(1024).unwrap(); let p = params.p().to_owned().unwrap(); let q = params.q().to_owned().unwrap(); let g = params.g().to_owned().unwrap(); let key = params.generate_key().unwrap(); let params2 = Dsa::from_pqg( key.p().to_owned().unwrap(), key.q().to_owned().unwrap(), key.g().to_owned().unwrap(), ) .unwrap(); assert_eq!(p, *params2.p()); assert_eq!(q, *params2.q()); assert_eq!(g, *params2.g()); } #[test] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] fn test_signature_der() { use std::convert::TryInto; const TEST_DATA: &[u8] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let dsa_ref = Dsa::generate(1024).unwrap(); let pub_key: PKey<_> = dsa_ref.clone().try_into().unwrap(); let priv_key: PKey<_> = dsa_ref.try_into().unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &priv_key).unwrap(); signer.update(TEST_DATA).unwrap(); let signature = signer.sign_to_vec().unwrap(); eprintln!("{:?}", signature); let signature = DsaSig::from_der(&signature).unwrap(); let r = BigNum::from_slice(&signature.r().to_vec()).unwrap(); let s = BigNum::from_slice(&signature.s().to_vec()).unwrap(); let signature = DsaSig::from_private_components(r, s).unwrap(); let signature = signature.to_der().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()); } #[test] fn dsa_sig_debug() { let sig = DsaSig::from_der(&[ 48, 46, 2, 21, 0, 135, 169, 24, 58, 153, 37, 175, 248, 200, 45, 251, 112, 238, 238, 89, 172, 177, 182, 166, 237, 2, 21, 0, 159, 146, 151, 237, 187, 8, 82, 115, 14, 183, 103, 12, 203, 46, 161, 208, 251, 167, 123, 131, ]) .unwrap(); let s = format!("{:?}", sig); assert_eq!(s, "DsaSig { r: 774484690634577222213819810519929266740561094381, s: 910998676210681457251421818099943952372231273347 }"); } } openssl-0.10.64/src/ec.rs000064400000000000000000001247311046102023000132130ustar 00000000000000//! Elliptic Curve //! //! Cryptography 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 elliptic 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 curves are generally referenced by [`EcGroup`]. There are many built-in groups //! found in [`Nid`]. //! //! OpenSSL Wiki explains the fields and curves in detail at [Elliptic Curve Cryptography]. //! //! [`EcGroup`]: struct.EcGroup.html //! [`Nid`]: ../nid/struct.Nid.html //! [Elliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; use std::ptr; use crate::bn::{BigNum, 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}; use openssl_macros::corresponds; cfg_if! { if #[cfg(not(boringssl))] { use std::ffi::CString; use crate::string::OpensslString; } } /// 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, Debug, PartialEq)] 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/manmaster/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. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box> { /// use openssl::nid::Nid; /// use openssl::ec::{EcGroup, EcKey}; /// /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve /// let group = EcGroup::from_curve_name(nid)?; /// let key = EcKey::generate(&group)?; /// # Ok(()) } /// ``` #[corresponds(EC_GROUP_new_by_curve_name)] pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) } } /// Returns the group for given parameters #[corresponds(EC_GROUP_new_curve_GFp)] pub fn from_components( p: BigNum, a: BigNum, b: BigNum, ctx: &mut BigNumContextRef, ) -> Result { unsafe { cvt_p(ffi::EC_GROUP_new_curve_GFp( p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr(), )) .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`. #[corresponds(EC_GROUP_get_curve_GFp)] 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. #[corresponds(EC_GROUP_get_curve_GF2m)] #[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`. #[corresponds(EC_GROUP_get_cofactor)] 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. #[corresponds(EC_GROUP_get_degree)] 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. #[corresponds(EC_GROUP_order_bits)] #[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 an [`EcPoint`]. #[corresponds(EC_GROUP_get0_generator)] pub fn generator(&self) -> &EcPointRef { unsafe { let ptr = ffi::EC_GROUP_get0_generator(self.as_ptr()); EcPointRef::from_const_ptr(ptr) } } /// Sets the generator point for the given curve #[corresponds(EC_GROUP_set_generator)] pub fn set_generator( &mut self, generator: EcPoint, order: BigNum, cofactor: BigNum, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_GROUP_set_generator( self.as_ptr(), generator.as_ptr(), order.as_ptr(), cofactor.as_ptr(), )) .map(|_| ()) } } /// Places the order of the curve in the provided `BigNum`. #[corresponds(EC_GROUP_get_order)] 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. #[corresponds(EC_GROUP_set_asn1_flag)] pub fn set_asn1_flag(&mut self, flag: Asn1Flag) { unsafe { ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0); } } /// Gets the flag determining if the group corresponds to a named curve. #[corresponds(EC_GROUP_get_asn1_flag)] pub fn asn1_flag(&self) -> Asn1Flag { unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) } } /// Returns the name of the curve, if a name is associated. #[corresponds(EC_GROUP_get_curve_name)] 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 pub struct EcPoint; /// A reference a borrowed [`EcPoint`]. pub struct EcPointRef; } impl EcPointRef { /// Computes `a + b`, storing the result in `self`. #[corresponds(EC_POINT_add)] 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`. #[corresponds(EC_POINT_mul)] 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`. #[corresponds(EC_POINT_mul)] 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`. #[corresponds(EC_POINT_mul)] 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`. #[corresponds(EC_POINT_invert)] // FIXME should be mutable 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. #[corresponds(EC_POINT_point2oct)] 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) } } } /// Serializes the point to a hexadecimal string representation. #[corresponds(EC_POINT_point2hex)] #[cfg(not(boringssl))] pub fn to_hex_str( &self, group: &EcGroupRef, form: PointConversionForm, ctx: &mut BigNumContextRef, ) -> Result { unsafe { let buf = cvt_p(ffi::EC_POINT_point2hex( group.as_ptr(), self.as_ptr(), form.0, ctx.as_ptr(), ))?; Ok(OpensslString::from_ptr(buf)) } } /// Creates a new point on the specified curve with the same value. #[corresponds(EC_POINT_dup)] 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. #[corresponds(EC_POINT_cmp)] 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) } } /// Places affine coordinates of a curve over a prime field in the provided /// `x` and `y` `BigNum`s. #[corresponds(EC_POINT_get_affine_coordinates)] #[cfg(any(ossl111, boringssl, libressl350))] 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(|_| ()) } } /// Places affine coordinates of a curve over a prime field in the provided /// `x` and `y` `BigNum`s #[corresponds(EC_POINT_get_affine_coordinates_GFp)] 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(|_| ()) } } /// Sets affine coordinates of a curve over a prime field using the provided /// `x` and `y` `BigNum`s #[corresponds(EC_POINT_set_affine_coordinates_GFp)] pub fn set_affine_coordinates_gfp( &mut self, group: &EcGroupRef, x: &BigNumRef, y: &BigNumRef, ctx: &mut BigNumContextRef, ) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_set_affine_coordinates_GFp( group.as_ptr(), self.as_ptr(), x.as_ptr(), y.as_ptr(), ctx.as_ptr(), )) .map(|_| ()) } } /// Places affine coordinates of a curve over a binary field in the provided /// `x` and `y` `BigNum`s #[corresponds(EC_POINT_get_affine_coordinates_GF2m)] #[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 #[corresponds(EC_POINT_is_at_infinity)] 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 #[corresponds(EC_POINT_is_on_curve)] 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. #[corresponds(EC_POINT_new)] pub fn new(group: &EcGroupRef) -> Result { unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } } /// Creates point from a binary representation #[corresponds(EC_POINT_oct2point)] 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) } /// Creates point from a hexadecimal string representation #[corresponds(EC_POINT_hex2point)] #[cfg(not(boringssl))] pub fn from_hex_str( group: &EcGroupRef, s: &str, ctx: &mut BigNumContextRef, ) -> Result { let point = EcPoint::new(group)?; unsafe { let c_str = CString::new(s.as_bytes()).unwrap(); cvt_p(ffi::EC_POINT_hex2point( group.as_ptr(), c_str.as_ptr() as *const _, point.as_ptr(), 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. pub struct EcKey; /// A reference to an [`EcKey`]. 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-----`. #[corresponds(PEM_write_bio_ECPrivateKey)] 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-----`. #[corresponds(PEM_write_bio_ECPrivateKey)] private_key_to_pem_passphrase, ffi::PEM_write_bio_ECPrivateKey } to_der! { /// Serializes the private key into a DER-encoded ECPrivateKey structure. #[corresponds(i2d_ECPrivateKey)] private_key_to_der, ffi::i2d_ECPrivateKey } /// Returns the private key value. #[corresponds(EC_KEY_get0_private_key)] 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. #[corresponds(EC_KEY_get0_public_key)] 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! { /// Serializes the public key into a PEM-encoded SubjectPublicKeyInfo structure. /// /// The output will have a header of `-----BEGIN PUBLIC KEY-----`. #[corresponds(PEM_write_bio_EC_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_EC_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. #[corresponds(i2d_EC_PUBKEY)] public_key_to_der, ffi::i2d_EC_PUBKEY } } impl EcKeyRef where T: HasParams, { /// Returns the key's group. #[corresponds(EC_KEY_get0_group)] 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. #[corresponds(EC_KEY_check_key)] 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`. #[corresponds(EC_KEY_new_by_curve_name)] 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. #[corresponds(EC_KEY_set_group)] 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 /// /// ``` /// # fn main() -> Result<(), Box> { /// use openssl::bn::BigNumContext; /// use openssl::ec::*; /// use openssl::nid::Nid; /// use openssl::pkey::PKey; /// /// let group = EcGroup::from_curve_name(Nid::SECP384R1)?; /// let mut ctx = BigNumContext::new()?; /// /// // get bytes from somewhere /// let public_key = // ... /// # EcKey::generate(&group)?.public_key().to_bytes(&group, /// # PointConversionForm::COMPRESSED, &mut ctx)?; /// /// // create an EcKey from the binary form of a EcPoint /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx)?; /// let key = EcKey::from_public_key(&group, &point)?; /// key.check_key()?; /// # Ok(()) } /// ``` #[corresponds(EC_KEY_set_public_key)] 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. #[corresponds(EC_KEY_set_public_key_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-----`. #[corresponds(PEM_read_bio_EC_PUBKEY)] public_key_from_pem, EcKey, ffi::PEM_read_bio_EC_PUBKEY } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing a EC key. #[corresponds(d2i_EC_PUBKEY)] public_key_from_der, EcKey, ffi::d2i_EC_PUBKEY } } impl EcKey { /// Generates a new public/private key pair on the specified curve. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box> { /// use openssl::bn::BigNumContext; /// use openssl::nid::Nid; /// use openssl::ec::{EcGroup, EcKey, PointConversionForm}; /// /// let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve /// let group = EcGroup::from_curve_name(nid)?; /// let key = EcKey::generate(&group)?; /// /// let mut ctx = BigNumContext::new()?; /// /// let public_key = &key.public_key().to_bytes( /// &group, /// PointConversionForm::COMPRESSED, /// &mut ctx, /// )?; /// assert_eq!(public_key.len(), 33); /// assert_ne!(public_key[0], 0x04); /// /// let private_key = key.private_key().to_vec(); /// assert!(private_key.len() >= 31); /// # Ok(()) } /// ``` #[corresponds(EC_KEY_generate_key)] 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. #[corresponds(EC_KEY_set_private_key)] 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-----`. #[corresponds(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-----`. #[corresponds(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-----`. #[corresponds(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. #[corresponds(d2i_ECPrivateKey)] 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 ec_group_from_components() { // parameters are from secp256r1 let p = BigNum::from_hex_str( "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", ) .unwrap(); let a = BigNum::from_hex_str( "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", ) .unwrap(); let b = BigNum::from_hex_str( "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", ) .unwrap(); let mut ctx = BigNumContext::new().unwrap(); let _curve = EcGroup::from_components(p, a, b, &mut ctx).unwrap(); } #[test] fn ec_point_set_affine() { // parameters are from secp256r1 let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let mut ctx = BigNumContext::new().unwrap(); let mut gen_point = EcPoint::new(&group).unwrap(); let gen_x = BigNum::from_hex_str( "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", ) .unwrap(); let gen_y = BigNum::from_hex_str( "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", ) .unwrap(); gen_point .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx) .unwrap(); assert!(gen_point.is_on_curve(&group, &mut ctx).unwrap()); } #[test] fn ec_group_set_generator() { // parameters are from secp256r1 let mut ctx = BigNumContext::new().unwrap(); let p = BigNum::from_hex_str( "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", ) .unwrap(); let a = BigNum::from_hex_str( "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC", ) .unwrap(); let b = BigNum::from_hex_str( "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B", ) .unwrap(); let mut group = EcGroup::from_components(p, a, b, &mut ctx).unwrap(); let mut gen_point = EcPoint::new(&group).unwrap(); let gen_x = BigNum::from_hex_str( "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296", ) .unwrap(); let gen_y = BigNum::from_hex_str( "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", ) .unwrap(); gen_point .set_affine_coordinates_gfp(&group, &gen_x, &gen_y, &mut ctx) .unwrap(); let order = BigNum::from_hex_str( "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", ) .unwrap(); let cofactor = BigNum::from_hex_str("01").unwrap(); group.set_generator(gen_point, order, cofactor).unwrap(); let mut constructed_order = BigNum::new().unwrap(); group.order(&mut constructed_order, &mut ctx).unwrap(); let named_group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let mut named_order = BigNum::new().unwrap(); named_group.order(&mut named_order, &mut ctx).unwrap(); assert_eq!( constructed_order.ucmp(&named_order), std::cmp::Ordering::Equal ); } #[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] #[cfg(not(boringssl))] fn point_hex_str() { 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 hex = point .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx) .unwrap(); let point2 = EcPoint::from_hex_str(&group, &hex, &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(any(ossl111, boringssl, libressl350))] #[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()); } #[test] #[cfg(any(boringssl, ossl111, libressl350))] fn asn1_flag() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let flag = group.asn1_flag(); assert_eq!(flag, Asn1Flag::NAMED_CURVE); } } openssl-0.10.64/src/ecdsa.rs000064400000000000000000000161011046102023000136720ustar 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, LenType}; use openssl_macros::corresponds; foreign_type_and_impl_send_sync! { type CType = ffi::ECDSA_SIG; fn drop = ffi::ECDSA_SIG_free; /// A low level interface to ECDSA. pub struct EcdsaSig; /// A reference to an [`EcdsaSig`]. pub struct EcdsaSigRef; } impl EcdsaSig { /// Computes a digital signature of the hash value `data` using the private EC key eckey. #[corresponds(ECDSA_do_sign)] 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 LenType, eckey.as_ptr(), ))?; Ok(EcdsaSig::from_ptr(sig)) } } /// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with an ECDSA signature. #[corresponds(ECDSA_SIG_set0)] 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. #[corresponds(d2i_ECDSA_SIG)] from_der, EcdsaSig, ffi::d2i_ECDSA_SIG } } impl EcdsaSigRef { to_der! { /// Serializes the ECDSA signature into a DER-encoded ECDSASignature structure. #[corresponds(i2d_ECDSA_SIG)] to_der, ffi::i2d_ECDSA_SIG } /// Verifies if the signature is a valid ECDSA signature using the given public key. #[corresponds(ECDSA_do_verify)] 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 LenType, self.as_ptr(), eckey.as_ptr(), )) .map(|x| x == 1) } } /// Returns internal component: `r` of an `EcdsaSig`. (See X9.62 or FIPS 186-2) #[corresponds(ECDSA_SIG_get0)] 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) #[corresponds(ECDSA_SIG_get0)] 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, boringssl))] { 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_EC", ignore)] fn sign_and_verify() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).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_EC", ignore)] fn check_private_components() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).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_EC", ignore)] fn serialize_deserialize() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).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.64/src/encrypt.rs000064400000000000000000000477061046102023000143160ustar 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; 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/manmaster/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::OPENSSL_malloc(label.len() as _))?; ptr::copy_nonoverlapping(label.as_ptr(), p as *mut u8, label.len()); cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( self.pctx, p, label.len() as c_int, )) .map(|_| ()) .map_err(|e| { ffi::OPENSSL_free(p); 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/manmaster/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::OPENSSL_malloc(label.len() as _))?; ptr::copy_nonoverlapping(label.as_ptr(), p as *mut u8, label.len()); cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( self.pctx, p, label.len() as c_int, )) .map(|_| ()) .map_err(|e| { ffi::OPENSSL_free(p); e }) } } /// 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); } #[test] #[cfg(any(ossl102, libressl310))] fn rsa_encrypt_decrypt_oaep_label() { 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_OAEP).unwrap(); encrypter.set_rsa_oaep_label(b"test_oaep_label").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_label(b"test_oaep_label").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); decrypter.set_rsa_oaep_label(b"wrong_oaep_label").unwrap(); let buffer_len = decrypter.decrypt_len(encoded).unwrap(); let mut decoded = vec![0u8; buffer_len]; assert!(decrypter.decrypt(encoded, &mut decoded).is_err()); } } openssl-0.10.64/src/envelope.rs000064400000000000000000000132631046102023000144360ustar 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::cipher::CipherRef; use crate::cipher_ctx::CipherCtx; use crate::error::ErrorStack; use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef}; use crate::symm::Cipher; use foreign_types::ForeignTypeRef; /// Represents an EVP_Seal context. pub struct Seal { ctx: CipherCtx, iv: Option>, enc_keys: Vec>, } impl Seal { /// Creates a new `Seal`. pub fn new(cipher: Cipher, pub_keys: &[PKey]) -> Result where T: HasPublic, { let mut iv = cipher.iv_len().map(|len| vec![0; len]); let mut enc_keys = vec![vec![]; pub_keys.len()]; let mut ctx = CipherCtx::new()?; ctx.seal_init( Some(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) }), pub_keys, &mut enc_keys, iv.as_deref_mut(), )?; Ok(Seal { ctx, 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 { self.ctx.cipher_update(input, Some(output)) } /// 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 { self.ctx.cipher_final(output) } } /// Represents an EVP_Open context. pub struct Open { ctx: CipherCtx, } impl Open { /// Creates a new `Open`. pub fn new( cipher: Cipher, priv_key: &PKeyRef, iv: Option<&[u8]>, encrypted_key: &[u8], ) -> Result where T: HasPrivate, { let mut ctx = CipherCtx::new()?; ctx.open_init( Some(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) }), encrypted_key, iv, Some(priv_key), )?; Ok(Open { ctx }) } /// 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 { self.ctx.cipher_update(input, Some(output)) } /// 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 { self.ctx.cipher_final(output) } } #[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.64/src/error.rs000064400000000000000000000274771046102023000137660ustar 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}; use std::borrow::Cow; #[cfg(boringssl)] use std::convert::TryInto; use std::error; use std::ffi::CStr; use std::fmt; use std::io; use std::ptr; use std::str; #[cfg(not(boringssl))] type ErrType = libc::c_ulong; #[cfg(boringssl)] type ErrType = libc::c_uint; /// 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: ErrType, file: ShimStr, line: c_int, func: Option, 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(); #[cfg(not(boringssl))] let data = if flags & ffi::ERR_TXT_MALLOCED != 0 { Cow::Owned(data.to_string()) } else { Cow::Borrowed(data) }; #[cfg(boringssl)] let data = Cow::Borrowed(data); Some(data) } else { None }; let file = ShimStr::new(file); let func = if func.is_null() { None } else { Some(ShimStr::new(func)) }; 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.as_ptr(), self.line, self.func.as_ref().map_or(ptr::null(), |s| s.as_ptr()), ); ffi::ERR_set_error(self.library_code(), self.reason_code(), ptr::null()); } } #[cfg(not(ossl300))] fn put_error(&self) { #[cfg(not(boringssl))] let line = self.line; #[cfg(boringssl)] let line = self.line.try_into().unwrap(); unsafe { ffi::ERR_put_error( self.library_code(), ffi::ERR_GET_FUNC(self.code), self.reason_code(), self.file.as_ptr(), line, ); } } /// Returns the raw OpenSSL error code for this error. pub fn code(&self) -> ErrType { 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 raw OpenSSL error constant for the library reporting the /// error. // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on // OpenSSL/LibreSSL they're safe. #[allow(unused_unsafe)] pub fn library_code(&self) -> libc::c_int { unsafe { ffi::ERR_GET_LIB(self.code) } } /// Returns the name of the function reporting the error. pub fn function(&self) -> Option> { self.func.as_ref().map(|s| s.as_str()) } /// 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 raw OpenSSL error constant for the reason for the error. // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on // OpenSSL/LibreSSL they're safe. #[allow(unused_unsafe)] pub fn reason_code(&self) -> libc::c_int { unsafe { ffi::ERR_GET_REASON(self.code) } } /// Returns the name of the source file which encountered the error. pub fn file(&self) -> RetStr<'_> { self.file.as_str() } /// 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 { // On BoringSSL ERR_GET_{LIB,FUNC,REASON} are `unsafe`, but on // OpenSSL/LibreSSL they're safe. #[allow(unused_unsafe)] 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({})", self.library_code())?, } match self.function() { Some(f) => write!(fmt, ":{}", f)?, None => write!(fmt, ":func({})", unsafe { ffi::ERR_GET_FUNC(self.code()) })?, } match self.reason() { Some(r) => write!(fmt, ":{}", r)?, None => write!(fmt, ":reason({})", self.reason_code())?, } write!( fmt, ":{}:{}:{}", self.file(), self.line(), self.data().unwrap_or("") ) } } impl error::Error for Error {} cfg_if! { if #[cfg(ossl300)] { use std::ffi::{CString}; use ffi::ERR_get_error_all; type RetStr<'a> = &'a str; #[derive(Clone)] struct ShimStr(CString); impl ShimStr { unsafe fn new(s: *const c_char) -> Self { ShimStr(CStr::from_ptr(s).to_owned()) } fn as_ptr(&self) -> *const c_char { self.0.as_ptr() } fn as_str(&self) -> &str { self.0.to_str().unwrap() } } } 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, ) -> ErrType { let code = ffi::ERR_get_error_line_data(file, line, data, flags); *func = ffi::ERR_func_error_string(code); code } type RetStr<'a> = &'static str; #[derive(Clone)] struct ShimStr(*const c_char); impl ShimStr { unsafe fn new(s: *const c_char) -> Self { ShimStr(s) } fn as_ptr(&self) -> *const c_char { self.0 } fn as_str(&self) -> &'static str { unsafe { CStr::from_ptr(self.0).to_str().unwrap() } } } } } #[cfg(test)] mod tests { #[cfg(not(ossl310))] use crate::nid::Nid; #[test] // Due to a bug in OpenSSL 3.1.0, this test can hang there. Skip for now. #[cfg(not(ossl310))] fn test_error_library_code() { let stack = Nid::create("not-an-oid", "invalid", "invalid").unwrap_err(); let errors = stack.errors(); #[cfg(not(boringssl))] assert_eq!(errors[0].library_code(), ffi::ERR_LIB_ASN1); #[cfg(boringssl)] assert_eq!(errors[0].library_code(), ffi::ERR_LIB_OBJ as libc::c_int); } } openssl-0.10.64/src/ex_data.rs000064400000000000000000000014431046102023000142230ustar 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.64/src/fips.rs000064400000000000000000000012171046102023000135560ustar 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; use openssl_macros::corresponds; /// Moves the library into or out of the FIPS 140-2 mode of operation. #[corresponds(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. #[corresponds(FIPS_mode)] pub fn enabled() -> bool { unsafe { ffi::FIPS_mode() != 0 } } openssl-0.10.64/src/hash.rs000064400000000000000000000546551046102023000135560ustar 00000000000000//! Message digest (hash) computation support. //! //! # Examples //! //! Calculate a hash in one go: //! //! ``` //! # fn main() -> Result<(), Box> { //! 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)?; //! assert_eq!(&*res, spec); //! # Ok(()) } //! ``` //! //! Supply the input in chunks: //! //! ``` //! use openssl::hash::{Hasher, MessageDigest}; //! //! # fn main() -> Result<(), Box> { //! let mut hasher = Hasher::new(MessageDigest::sha256())?; //! hasher.update(b"test")?; //! hasher.update(b"this")?; //! let digest: &[u8] = &hasher.finish()?; //! //! let expected = hex::decode("9740e652ab5b4acd997a7cca13d6696702ccb2d441cca59fc6e285127f28cfe6")?; //! assert_eq!(digest, expected); //! # Ok(()) } //! ``` use 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(any(ossl110, boringssl, libressl382))] { 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}; } } /// A message digest algorithm. #[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/manmaster/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/manmaster/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)) } } } #[cfg(not(boringssl))] 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(any(ossl111, libressl380))] pub fn sha3_224() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha3_224()) } } #[cfg(any(ossl111, libressl380))] pub fn sha3_256() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha3_256()) } } #[cfg(any(ossl111, libressl380))] pub fn sha3_384() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_sha3_384()) } } #[cfg(any(ossl111, libressl380))] 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 block size of the digest in bytes. #[allow(clippy::trivially_copy_pass_by_ref)] pub fn block_size(&self) -> usize { unsafe { ffi::EVP_MD_block_size(self.0) as usize } } /// 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 /// /// ``` /// use openssl::hash::{Hasher, MessageDigest}; /// /// # fn main() -> Result<(), Box> { /// 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())?; /// h.update(data[0])?; /// h.update(data[1])?; /// let res = h.finish()?; /// assert_eq!(&*res, spec); /// # Ok(()) } /// ``` /// /// # 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 [`Hasher::finish_xof`] instead of [`Hasher::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 { #[cfg(not(boringssl))] let mut len = ffi::EVP_MAX_MD_SIZE; #[cfg(boringssl)] let mut len = ffi::EVP_MAX_MD_SIZE as u32; 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`. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box> { /// 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)?; /// assert_eq!(&*res, spec); /// # Ok(()) } /// ``` 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`. /// /// # Examples /// /// ``` /// 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); /// ``` /// #[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); } assert_eq!(MessageDigest::md5().block_size(), 64); assert_eq!(MessageDigest::md5().size(), 16); assert_eq!(MessageDigest::md5().type_().as_raw(), Nid::MD5.as_raw()); } #[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); } assert_eq!(MessageDigest::sha1().block_size(), 64); assert_eq!(MessageDigest::sha1().size(), 20); assert_eq!(MessageDigest::sha1().type_().as_raw(), Nid::SHA1.as_raw()); } #[test] fn test_sha256() { let tests = [( "616263", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", )]; for test in tests.iter() { hash_test(MessageDigest::sha256(), test); } assert_eq!(MessageDigest::sha256().block_size(), 64); assert_eq!(MessageDigest::sha256().size(), 32); assert_eq!( MessageDigest::sha256().type_().as_raw(), Nid::SHA256.as_raw() ); } #[test] fn test_sha512() { let tests = [( "737465766566696e647365766572797468696e67", "ba61d1f1af0f2dd80729f6cc900f19c0966bd38ba5c75e4471ef11b771dfe7551afab7fcbd300fdc4418f2\ b07a028fcd99e7b6446a566f2d9bcd7c604a1ea801", )]; for test in tests.iter() { hash_test(MessageDigest::sha512(), test); } assert_eq!(MessageDigest::sha512().block_size(), 128); assert_eq!(MessageDigest::sha512().size(), 64); assert_eq!( MessageDigest::sha512().type_().as_raw(), Nid::SHA512.as_raw() ); } #[cfg(any(ossl111, libressl380))] #[test] fn test_sha3_224() { let tests = [( "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913", )]; for test in tests.iter() { hash_test(MessageDigest::sha3_224(), test); } assert_eq!(MessageDigest::sha3_224().block_size(), 144); assert_eq!(MessageDigest::sha3_224().size(), 28); assert_eq!( MessageDigest::sha3_224().type_().as_raw(), Nid::SHA3_224.as_raw() ); } #[cfg(any(ossl111, libressl380))] #[test] fn test_sha3_256() { let tests = [( "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61", )]; for test in tests.iter() { hash_test(MessageDigest::sha3_256(), test); } assert_eq!(MessageDigest::sha3_256().block_size(), 136); assert_eq!(MessageDigest::sha3_256().size(), 32); assert_eq!( MessageDigest::sha3_256().type_().as_raw(), Nid::SHA3_256.as_raw() ); } #[cfg(any(ossl111, libressl380))] #[test] fn test_sha3_384() { let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\ ef2008ff16" )]; for test in tests.iter() { hash_test(MessageDigest::sha3_384(), test); } assert_eq!(MessageDigest::sha3_384().block_size(), 104); assert_eq!(MessageDigest::sha3_384().size(), 48); assert_eq!( MessageDigest::sha3_384().type_().as_raw(), Nid::SHA3_384.as_raw() ); } #[cfg(any(ossl111, libressl380))] #[test] fn test_sha3_512() { let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\ 807caee3a79f8eb02dcd61589fbbdf5f40c8787a72" )]; for test in tests.iter() { hash_test(MessageDigest::sha3_512(), test); } assert_eq!(MessageDigest::sha3_512().block_size(), 72); assert_eq!(MessageDigest::sha3_512().size(), 64); assert_eq!( MessageDigest::sha3_512().type_().as_raw(), Nid::SHA3_512.as_raw() ); } #[cfg(ossl111)] #[test] fn test_shake_128() { let tests = [( "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "49d0697ff508111d8b84f15e46daf135", )]; for test in tests.iter() { hash_xof_test(MessageDigest::shake_128(), test); } assert_eq!(MessageDigest::shake_128().block_size(), 168); assert_eq!(MessageDigest::shake_128().size(), 16); assert_eq!( MessageDigest::shake_128().type_().as_raw(), Nid::SHAKE128.as_raw() ); } #[cfg(ossl111)] #[test] fn test_shake_256() { let tests = [( "416c6c20796f75722062617365206172652062656c6f6e6720746f207573", "4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697", )]; for test in tests.iter() { hash_xof_test(MessageDigest::shake_256(), test); } assert_eq!(MessageDigest::shake_256().block_size(), 136); assert_eq!(MessageDigest::shake_256().size(), 32); assert_eq!( MessageDigest::shake_256().type_().as_raw(), Nid::SHAKE256.as_raw() ); } #[test] #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))] #[cfg_attr(ossl300, ignore)] fn test_ripemd160() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")]; for test in tests.iter() { hash_test(MessageDigest::ripemd160(), test); } assert_eq!(MessageDigest::ripemd160().block_size(), 64); assert_eq!(MessageDigest::ripemd160().size(), 20); assert_eq!( MessageDigest::ripemd160().type_().as_raw(), Nid::RIPEMD160.as_raw() ); } #[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); } assert_eq!(MessageDigest::sm3().block_size(), 64); assert_eq!(MessageDigest::sm3().size(), 32); assert_eq!(MessageDigest::sm3().type_().as_raw(), Nid::SM3.as_raw()); } #[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.64/src/lib.rs000064400000000000000000000160231046102023000133640ustar 00000000000000//! Bindings to OpenSSL //! //! This crate provides a safe interface to the popular OpenSSL cryptography library. OpenSSL versions 1.0.1 through //! 3.x.x and LibreSSL versions 2.5 through 3.7.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 perl-core), 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@3 //! //! # 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 perl-FindBin openssl-devel //! //! # Alpine Linux //! $ apk add pkgconfig openssl-dev //! //! # openSUSE //! $ sudo zypper in libopenssl-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)] #![allow(clippy::uninlined_format_args, clippy::needless_doctest_main)] #[doc(inline)] pub use ffi::init; use libc::c_int; #[cfg(ossl300)] use libc::c_long; 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; pub mod cipher; pub mod cipher_ctx; #[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; #[cfg(not(boringssl))] pub mod envelope; pub mod error; pub mod ex_data; #[cfg(not(any(libressl, ossl300)))] pub mod fips; pub mod hash; #[cfg(ossl300)] pub mod lib_ctx; pub mod md; pub mod md_ctx; pub mod memcmp; pub mod nid; #[cfg(not(osslconf = "OPENSSL_NO_OCSP"))] pub mod ocsp; pub mod pkcs12; pub mod pkcs5; #[cfg(not(boringssl))] pub mod pkcs7; pub mod pkey; pub mod pkey_ctx; #[cfg(ossl300)] pub mod provider; 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; #[cfg(boringssl)] type LenType = libc::size_t; #[cfg(not(boringssl))] type LenType = libc::c_int; #[cfg(boringssl)] type SLenType = libc::ssize_t; #[cfg(not(boringssl))] type SLenType = libc::c_int; #[inline] fn cvt_p(r: *mut T) -> Result<*mut T, ErrorStack> { if r.is_null() { Err(ErrorStack::get()) } else { Ok(r) } } #[inline] fn cvt_p_const(r: *const T) -> Result<*const T, ErrorStack> { if r.is_null() { Err(ErrorStack::get()) } else { Ok(r) } } #[inline] fn cvt(r: c_int) -> Result { if r <= 0 { Err(ErrorStack::get()) } else { Ok(r) } } // cvt_long is currently only used in functions that require openssl >= 3.0.0, // so this cfg statement is used to avoid "unused function" errors when // compiling with openssl < 3.0.0 #[inline] #[cfg(ossl300)] fn cvt_long(r: c_long) -> Result { if r <= 0 { Err(ErrorStack::get()) } else { Ok(r) } } #[inline] fn cvt_n(r: c_int) -> Result { if r < 0 { Err(ErrorStack::get()) } else { Ok(r) } } openssl-0.10.64/src/lib_ctx.rs000064400000000000000000000007661046102023000142510ustar 00000000000000use crate::cvt_p; use crate::error::ErrorStack; use foreign_types::ForeignType; use openssl_macros::corresponds; foreign_type_and_impl_send_sync! { type CType = ffi::OSSL_LIB_CTX; fn drop = ffi::OSSL_LIB_CTX_free; pub struct LibCtx; pub struct LibCtxRef; } impl LibCtx { #[corresponds(OSSL_LIB_CTX_new)] pub fn new() -> Result { unsafe { let ptr = cvt_p(ffi::OSSL_LIB_CTX_new())?; Ok(LibCtx::from_ptr(ptr)) } } } openssl-0.10.64/src/macros.rs000064400000000000000000000211611046102023000141010ustar 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> { use std::convert::TryInto; 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.try_into().unwrap())) .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.64/src/md.rs000064400000000000000000000134341046102023000132210ustar 00000000000000//! Message digest algorithms. #[cfg(ossl300)] use crate::cvt_p; #[cfg(ossl300)] use crate::error::ErrorStack; #[cfg(ossl300)] use crate::lib_ctx::LibCtxRef; use crate::nid::Nid; use cfg_if::cfg_if; use foreign_types::{ForeignTypeRef, Opaque}; use openssl_macros::corresponds; #[cfg(ossl300)] use std::ffi::CString; #[cfg(ossl300)] use std::ptr; cfg_if! { if #[cfg(ossl300)] { use foreign_types::ForeignType; use std::ops::{Deref, DerefMut}; type Inner = *mut ffi::EVP_MD; impl Drop for Md { #[inline] fn drop(&mut self) { unsafe { ffi::EVP_MD_free(self.as_ptr()); } } } impl ForeignType for Md { type CType = ffi::EVP_MD; type Ref = MdRef; #[inline] unsafe fn from_ptr(ptr: *mut Self::CType) -> Self { Md(ptr) } #[inline] fn as_ptr(&self) -> *mut Self::CType { self.0 } } impl Deref for Md { type Target = MdRef; #[inline] fn deref(&self) -> &Self::Target { unsafe { MdRef::from_ptr(self.as_ptr()) } } } impl DerefMut for Md { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { unsafe { MdRef::from_ptr_mut(self.as_ptr()) } } } } else { enum Inner {} } } /// A message digest algorithm. pub struct Md(Inner); unsafe impl Sync for Md {} unsafe impl Send for Md {} impl Md { /// Returns the `Md` corresponding to an [`Nid`]. #[corresponds(EVP_get_digestbynid)] pub fn from_nid(type_: Nid) -> Option<&'static MdRef> { unsafe { let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); if ptr.is_null() { None } else { Some(MdRef::from_ptr(ptr as *mut _)) } } } /// Fetches an `Md` object corresponding to the specified algorithm name and properties. /// /// Requires OpenSSL 3.0.0 or newer. #[corresponds(EVP_MD_fetch)] #[cfg(ossl300)] pub fn fetch( ctx: Option<&LibCtxRef>, algorithm: &str, properties: Option<&str>, ) -> Result { let algorithm = CString::new(algorithm).unwrap(); let properties = properties.map(|s| CString::new(s).unwrap()); unsafe { let ptr = cvt_p(ffi::EVP_MD_fetch( ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), algorithm.as_ptr(), properties.map_or(ptr::null_mut(), |s| s.as_ptr()), ))?; Ok(Md::from_ptr(ptr)) } } #[inline] #[cfg(not(boringssl))] pub fn null() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_md_null() as *mut _) } } #[inline] pub fn md5() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_md5() as *mut _) } } #[inline] pub fn sha1() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha1() as *mut _) } } #[inline] pub fn sha224() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha224() as *mut _) } } #[inline] pub fn sha256() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha256() as *mut _) } } #[inline] pub fn sha384() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha384() as *mut _) } } #[inline] pub fn sha512() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha512() as *mut _) } } #[cfg(any(ossl111, libressl380))] #[inline] pub fn sha3_224() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha3_224() as *mut _) } } #[cfg(any(ossl111, libressl380))] #[inline] pub fn sha3_256() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha3_256() as *mut _) } } #[cfg(any(ossl111, libressl380))] #[inline] pub fn sha3_384() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha3_384() as *mut _) } } #[cfg(any(ossl111, libressl380))] #[inline] pub fn sha3_512() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sha3_512() as *mut _) } } #[cfg(ossl111)] #[inline] pub fn shake128() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_shake128() as *mut _) } } #[cfg(ossl111)] #[inline] pub fn shake256() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_shake256() as *mut _) } } #[cfg(not(osslconf = "OPENSSL_NO_RMD160"))] #[inline] pub fn ripemd160() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_ripemd160() as *mut _) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))] #[inline] pub fn sm3() -> &'static MdRef { unsafe { MdRef::from_ptr(ffi::EVP_sm3() as *mut _) } } } /// A reference to an [`Md`]. pub struct MdRef(Opaque); impl ForeignTypeRef for MdRef { type CType = ffi::EVP_MD; } unsafe impl Sync for MdRef {} unsafe impl Send for MdRef {} impl MdRef { /// Returns the block size of the digest in bytes. #[corresponds(EVP_MD_block_size)] #[inline] pub fn block_size(&self) -> usize { unsafe { ffi::EVP_MD_block_size(self.as_ptr()) as usize } } /// Returns the size of the digest in bytes. #[corresponds(EVP_MD_size)] #[inline] pub fn size(&self) -> usize { unsafe { ffi::EVP_MD_size(self.as_ptr()) as usize } } /// Returns the [`Nid`] of the digest. #[corresponds(EVP_MD_type)] #[inline] pub fn type_(&self) -> Nid { unsafe { Nid::from_raw(ffi::EVP_MD_type(self.as_ptr())) } } } openssl-0.10.64/src/md_ctx.rs000064400000000000000000000375171046102023000141070ustar 00000000000000//! The message digest context. //! //! # Examples //! //! Compute the SHA256 checksum of data //! //! ``` //! use openssl::md::Md; //! use openssl::md_ctx::MdCtx; //! //! let mut ctx = MdCtx::new().unwrap(); //! ctx.digest_init(Md::sha256()).unwrap(); //! ctx.digest_update(b"Some Crypto Text").unwrap(); //! let mut digest = [0; 32]; //! ctx.digest_final(&mut digest).unwrap(); //! //! assert_eq!( //! digest, //! *b"\x60\x78\x56\x38\x8a\xca\x5c\x51\x83\xc4\xd1\x4d\xc8\xf9\xcc\xf2\ //! \xa5\x21\xb3\x10\x93\x72\xfa\xd6\x7c\x55\xf5\xc9\xe3\xd1\x83\x19", //! ); //! ``` //! //! Sign and verify data with RSA and SHA256 //! //! ``` //! use openssl::md::Md; //! use openssl::md_ctx::MdCtx; //! use openssl::pkey::PKey; //! use openssl::rsa::Rsa; //! //! // Generate a random RSA key. //! let key = Rsa::generate(4096).unwrap(); //! let key = PKey::from_rsa(key).unwrap(); //! //! let text = b"Some Crypto Text"; //! //! // Create the signature. //! let mut ctx = MdCtx::new().unwrap(); //! ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap(); //! ctx.digest_sign_update(text).unwrap(); //! let mut signature = vec![]; //! ctx.digest_sign_final_to_vec(&mut signature).unwrap(); //! //! // Verify the signature. //! let mut ctx = MdCtx::new().unwrap(); //! ctx.digest_verify_init(Some(Md::sha256()), &key).unwrap(); //! ctx.digest_verify_update(text).unwrap(); //! let valid = ctx.digest_verify_final(&signature).unwrap(); //! assert!(valid); //! ``` //! #![cfg_attr( not(boringssl), doc = r#"\ Compute and verify an HMAC-SHA256 ``` use openssl::md::Md; use openssl::md_ctx::MdCtx; use openssl::memcmp; use openssl::pkey::PKey; // Create a key with the HMAC secret. let key = PKey::hmac(b"my secret").unwrap(); let text = b"Some Crypto Text"; // Compute the HMAC. let mut ctx = MdCtx::new().unwrap(); ctx.digest_sign_init(Some(Md::sha256()), &key).unwrap(); ctx.digest_sign_update(text).unwrap(); let mut hmac = vec![]; ctx.digest_sign_final_to_vec(&mut hmac).unwrap(); // Verify the HMAC. You can't use MdCtx to do this; instead use a constant time equality check. # let target = hmac.clone(); let valid = memcmp::eq(&hmac, &target); assert!(valid); ```"# )] use crate::error::ErrorStack; use crate::md::MdRef; use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; use crate::pkey_ctx::PkeyCtxRef; use crate::{cvt, cvt_n, cvt_p}; use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use openssl_macros::corresponds; use std::convert::TryFrom; use std::ptr; cfg_if! { if #[cfg(any(ossl110, boringssl, libressl382))] { 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}; } } foreign_type_and_impl_send_sync! { type CType = ffi::EVP_MD_CTX; fn drop = EVP_MD_CTX_free; pub struct MdCtx; /// A reference to an [`MdCtx`]. pub struct MdCtxRef; } impl MdCtx { /// Creates a new context. #[corresponds(EVP_MD_CTX_new)] #[inline] pub fn new() -> Result { ffi::init(); unsafe { let ptr = cvt_p(EVP_MD_CTX_new())?; Ok(MdCtx::from_ptr(ptr)) } } } impl MdCtxRef { /// Initializes the context to compute the digest of data. #[corresponds(EVP_DigestInit_ex)] #[inline] pub fn digest_init(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestInit_ex( self.as_ptr(), digest.as_ptr(), ptr::null_mut(), ))?; } Ok(()) } /// Initializes the context to compute the signature of data. /// /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured. #[corresponds(EVP_DigestSignInit)] #[inline] pub fn digest_sign_init<'a, T>( &'a mut self, digest: Option<&MdRef>, pkey: &PKeyRef, ) -> Result<&'a mut PkeyCtxRef, ErrorStack> where T: HasPrivate, { unsafe { let mut p = ptr::null_mut(); cvt(ffi::EVP_DigestSignInit( self.as_ptr(), &mut p, digest.map_or(ptr::null(), |p| p.as_ptr()), ptr::null_mut(), pkey.as_ptr(), ))?; Ok(PkeyCtxRef::from_ptr_mut(p)) } } /// Initializes the context to verify the signature of data. /// /// A reference to the context's inner `PkeyCtx` is returned, allowing signature settings to be configured. #[corresponds(EVP_DigestVerifyInit)] #[inline] pub fn digest_verify_init<'a, T>( &'a mut self, digest: Option<&MdRef>, pkey: &PKeyRef, ) -> Result<&'a mut PkeyCtxRef, ErrorStack> where T: HasPublic, { unsafe { let mut p = ptr::null_mut(); cvt(ffi::EVP_DigestVerifyInit( self.as_ptr(), &mut p, digest.map_or(ptr::null(), |p| p.as_ptr()), ptr::null_mut(), pkey.as_ptr(), ))?; Ok(PkeyCtxRef::from_ptr_mut(p)) } } /// Updates the context with more data. #[corresponds(EVP_DigestUpdate)] #[inline] pub fn digest_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestUpdate( self.as_ptr(), data.as_ptr() as *const _, data.len(), ))?; } Ok(()) } /// Updates the context with more data. #[corresponds(EVP_DigestSignUpdate)] #[inline] pub fn digest_sign_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestSignUpdate( self.as_ptr(), data.as_ptr() as *const _, data.len(), ))?; } Ok(()) } /// Updates the context with more data. #[corresponds(EVP_DigestVerifyUpdate)] #[inline] pub fn digest_verify_update(&mut self, data: &[u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestVerifyUpdate( self.as_ptr(), data.as_ptr() as *const _, data.len(), ))?; } Ok(()) } /// Copies the computed digest into the buffer, returning the number of bytes written. #[corresponds(EVP_DigestFinal)] #[inline] pub fn digest_final(&mut self, out: &mut [u8]) -> Result { let mut len = u32::try_from(out.len()).unwrap_or(u32::MAX); unsafe { cvt(ffi::EVP_DigestFinal( self.as_ptr(), out.as_mut_ptr(), &mut len, ))?; } Ok(len as usize) } /// Copies the computed digest into the buffer. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(EVP_DigestFinalXOF)] #[inline] #[cfg(ossl111)] pub fn digest_final_xof(&mut self, out: &mut [u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestFinalXOF( self.as_ptr(), out.as_mut_ptr(), out.len(), ))?; } Ok(()) } /// Signs the computed digest. /// /// If `out` is set to `None`, an upper bound on the number of bytes required for the output buffer will be /// returned. #[corresponds(EVP_DigestSignFinal)] #[inline] pub fn digest_sign_final(&mut self, out: Option<&mut [u8]>) -> Result { let mut len = out.as_ref().map_or(0, |b| b.len()); unsafe { cvt(ffi::EVP_DigestSignFinal( self.as_ptr(), out.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), &mut len, ))?; } Ok(len) } /// Like [`Self::digest_sign_final`] but appends the signature to a [`Vec`]. pub fn digest_sign_final_to_vec(&mut self, out: &mut Vec) -> Result { let base = out.len(); let len = self.digest_sign_final(None)?; out.resize(base + len, 0); let len = self.digest_sign_final(Some(&mut out[base..]))?; out.truncate(base + len); Ok(len) } /// Verifies the provided signature. /// /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error /// occurred. #[corresponds(EVP_DigestVerifyFinal)] #[inline] pub fn digest_verify_final(&mut self, signature: &[u8]) -> Result { unsafe { let r = cvt_n(ffi::EVP_DigestVerifyFinal( self.as_ptr(), signature.as_ptr() as *mut _, signature.len(), ))?; Ok(r == 1) } } /// Computes the signature of the data in `from`. /// /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be /// returned. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(EVP_DigestSign)] #[cfg(ossl111)] #[inline] pub fn digest_sign(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result { let mut len = to.as_ref().map_or(0, |b| b.len()); unsafe { cvt(ffi::EVP_DigestSign( self.as_ptr(), to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), &mut len, from.as_ptr(), from.len(), ))?; } Ok(len) } /// Like [`Self::digest_sign`] but appends the signature to a [`Vec`]. #[cfg(ossl111)] pub fn digest_sign_to_vec( &mut self, from: &[u8], to: &mut Vec, ) -> Result { let base = to.len(); let len = self.digest_sign(from, None)?; to.resize(base + len, 0); let len = self.digest_sign(from, Some(&mut to[base..]))?; to.truncate(base + len); Ok(len) } /// Verifies the signature of the data in `data`. /// /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error /// occurred. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(EVP_DigestVerify)] #[cfg(ossl111)] #[inline] pub fn digest_verify(&mut self, data: &[u8], signature: &[u8]) -> Result { unsafe { let r = cvt(ffi::EVP_DigestVerify( self.as_ptr(), signature.as_ptr(), signature.len(), data.as_ptr(), data.len(), ))?; Ok(r == 1) } } /// Returns the size of the message digest, i.e. the size of the hash #[corresponds(EVP_MD_CTX_size)] #[inline] pub fn size(&self) -> usize { unsafe { ffi::EVP_MD_CTX_size(self.as_ptr()) as usize } } /// Resets the underlying EVP_MD_CTX instance #[corresponds(EVP_MD_CTX_reset)] #[cfg(ossl111)] #[inline] pub fn reset(&mut self) -> Result<(), ErrorStack> { unsafe { let _ = cvt(ffi::EVP_MD_CTX_reset(self.as_ptr()))?; Ok(()) } } } #[cfg(test)] mod test { use super::*; use crate::md::Md; use crate::pkey::PKey; use crate::rsa::Rsa; #[test] fn verify_fail() { let key1 = Rsa::generate(4096).unwrap(); let key1 = PKey::from_rsa(key1).unwrap(); let md = Md::sha256(); let data = b"Some Crypto Text"; let mut ctx = MdCtx::new().unwrap(); ctx.digest_sign_init(Some(md), &key1).unwrap(); ctx.digest_sign_update(data).unwrap(); let mut signature = vec![]; ctx.digest_sign_final_to_vec(&mut signature).unwrap(); let bad_data = b"Some Crypto text"; ctx.digest_verify_init(Some(md), &key1).unwrap(); ctx.digest_verify_update(bad_data).unwrap(); let valid = ctx.digest_verify_final(&signature).unwrap(); assert!(!valid); } #[test] fn verify_success() { let key1 = Rsa::generate(2048).unwrap(); let key1 = PKey::from_rsa(key1).unwrap(); let md = Md::sha256(); let data = b"Some Crypto Text"; let mut ctx = MdCtx::new().unwrap(); ctx.digest_sign_init(Some(md), &key1).unwrap(); ctx.digest_sign_update(data).unwrap(); let mut signature = vec![]; ctx.digest_sign_final_to_vec(&mut signature).unwrap(); let good_data = b"Some Crypto Text"; ctx.digest_verify_init(Some(md), &key1).unwrap(); ctx.digest_verify_update(good_data).unwrap(); let valid = ctx.digest_verify_final(&signature).unwrap(); assert!(valid); } #[test] fn verify_with_public_success() { let rsa = Rsa::generate(2048).unwrap(); let key1 = PKey::from_rsa(rsa.clone()).unwrap(); let md = Md::sha256(); let data = b"Some Crypto Text"; let mut ctx = MdCtx::new().unwrap(); ctx.digest_sign_init(Some(md), &key1).unwrap(); ctx.digest_sign_update(data).unwrap(); let mut signature = vec![]; ctx.digest_sign_final_to_vec(&mut signature).unwrap(); let good_data = b"Some Crypto Text"; // try to verify using only public components of the key let n = rsa.n().to_owned().unwrap(); let e = rsa.e().to_owned().unwrap(); let rsa = Rsa::from_public_components(n, e).unwrap(); let key1 = PKey::from_rsa(rsa).unwrap(); ctx.digest_verify_init(Some(md), &key1).unwrap(); ctx.digest_verify_update(good_data).unwrap(); let valid = ctx.digest_verify_final(&signature).unwrap(); assert!(valid); } #[test] fn verify_md_ctx_size() { let mut ctx = MdCtx::new().unwrap(); ctx.digest_init(Md::sha224()).unwrap(); assert_eq!(Md::sha224().size(), ctx.size()); assert_eq!(Md::sha224().size(), 28); let mut ctx = MdCtx::new().unwrap(); ctx.digest_init(Md::sha256()).unwrap(); assert_eq!(Md::sha256().size(), ctx.size()); assert_eq!(Md::sha256().size(), 32); let mut ctx = MdCtx::new().unwrap(); ctx.digest_init(Md::sha384()).unwrap(); assert_eq!(Md::sha384().size(), ctx.size()); assert_eq!(Md::sha384().size(), 48); let mut ctx = MdCtx::new().unwrap(); ctx.digest_init(Md::sha512()).unwrap(); assert_eq!(Md::sha512().size(), ctx.size()); assert_eq!(Md::sha512().size(), 64); } #[test] #[cfg(ossl111)] fn verify_md_ctx_reset() { let hello_expected = hex::decode("185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969") .unwrap(); let world_expected = hex::decode("78ae647dc5544d227130a0682a51e30bc7777fbb6d8a8f17007463a3ecd1d524") .unwrap(); // Calculate SHA-256 digest of "Hello" let mut ctx = MdCtx::new().unwrap(); ctx.digest_init(Md::sha256()).unwrap(); ctx.digest_update(b"Hello").unwrap(); let mut result = vec![0; 32]; let result_len = ctx.digest_final(result.as_mut_slice()).unwrap(); assert_eq!(result_len, result.len()); // Validate result of "Hello" assert_eq!(result, hello_expected); // Create new context let mut ctx = MdCtx::new().unwrap(); // Initialize and update to "Hello" ctx.digest_init(Md::sha256()).unwrap(); ctx.digest_update(b"Hello").unwrap(); // Now reset, init to SHA-256 and use "World" ctx.reset().unwrap(); ctx.digest_init(Md::sha256()).unwrap(); ctx.digest_update(b"World").unwrap(); let mut reset_result = vec![0; 32]; let result_len = ctx.digest_final(reset_result.as_mut_slice()).unwrap(); assert_eq!(result_len, reset_result.len()); // Validate result of digest of "World" assert_eq!(reset_result, world_expected); } } openssl-0.10.64/src/memcmp.rs000064400000000000000000000046211046102023000140750ustar 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; use openssl_macros::corresponds; /// 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)); /// ``` #[corresponds(CRYPTO_memcmp)] 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.64/src/nid.rs000064400000000000000000002146231046102023000133760ustar 00000000000000//! A collection of numerical identifiers for OpenSSL objects. use libc::{c_char, c_int}; use std::ffi::CStr; use std::ffi::CString; use std::str; use crate::cvt_p; use crate::error::ErrorStack; use openssl_macros::corresponds; /// 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/manmaster/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 const fn from_raw(raw: c_int) -> Nid { Nid(raw) } /// Return the integer representation of a `Nid`. #[allow(clippy::trivially_copy_pass_by_ref)] pub const fn as_raw(&self) -> c_int { self.0 } /// Creates a new `Nid` for the `oid` with short name `sn` and long name `ln`. #[corresponds(OBJ_create)] pub fn create(oid: &str, sn: &str, ln: &str) -> Result { unsafe { ffi::init(); let oid = CString::new(oid).unwrap(); let sn = CString::new(sn).unwrap(); let ln = CString::new(ln).unwrap(); let raw = ffi::OBJ_create(oid.as_ptr(), sn.as_ptr(), ln.as_ptr()); if raw == ffi::NID_undef { Err(ErrorStack::get()) } else { Ok(Nid(raw)) } } } /// Returns the `Nid`s of the digest and public key algorithms associated with a signature ID. /// /// This corresponds to `OBJ_find_sigid_algs`. #[corresponds(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 } } } /// Returns the string representation of a `Nid` (long). #[corresponds(OBJ_nid2ln)] #[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()) } } /// Returns the string representation of a `Nid` (short). #[corresponds(OBJ_nid2sn)] #[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); #[cfg(not(boringssl))] 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); #[cfg(not(boringssl))] 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); #[cfg(any(ossl110, libressl))] pub const BRAINPOOL_P256R1: Nid = Nid(ffi::NID_brainpoolP256r1); #[cfg(any(ossl110, libressl))] pub const BRAINPOOL_P320R1: Nid = Nid(ffi::NID_brainpoolP320r1); #[cfg(any(ossl110, libressl))] pub const BRAINPOOL_P384R1: Nid = Nid(ffi::NID_brainpoolP384r1); #[cfg(any(ossl110, libressl))] pub const BRAINPOOL_P512R1: Nid = Nid(ffi::NID_brainpoolP512r1); 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(ossl111)] pub const SM2: Nid = Nid(ffi::NID_sm2); #[cfg(any(ossl111, libressl291))] pub const SM3: Nid = Nid(ffi::NID_sm3); #[cfg(any(ossl111, libressl380))] pub const SHA3_224: Nid = Nid(ffi::NID_sha3_224); #[cfg(any(ossl111, libressl380))] pub const SHA3_256: Nid = Nid(ffi::NID_sha3_256); #[cfg(any(ossl111, libressl380))] pub const SHA3_384: Nid = Nid(ffi::NID_sha3_384); #[cfg(any(ossl111, libressl380))] pub const SHA3_512: Nid = Nid(ffi::NID_sha3_512); #[cfg(ossl111)] pub const SHAKE128: Nid = Nid(ffi::NID_shake128); #[cfg(ossl111)] pub const SHAKE256: Nid = Nid(ffi::NID_shake256); #[cfg(any(ossl110, libressl271))] pub const CHACHA20_POLY1305: Nid = Nid(ffi::NID_chacha20_poly1305); } #[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" ); } #[test] fn test_create() { let nid = Nid::create("1.2.3.4", "foo", "foobar").unwrap(); assert_eq!(nid.short_name().unwrap(), "foo"); assert_eq!(nid.long_name().unwrap(), "foobar"); // Due to a bug in OpenSSL 3.1.0, this test crashes on Windows if !cfg!(ossl310) { let invalid_oid = Nid::create("invalid_oid", "invalid", "invalid"); assert!( invalid_oid.is_err(), "invalid_oid should not return a valid value" ); } } } openssl-0.10.64/src/ocsp.rs000064400000000000000000000261771046102023000135750ustar 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}; use openssl_macros::corresponds; bitflags! { #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] 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. #[corresponds(OCSP_check_validity)] 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. #[corresponds(OCSP_basic_verify)] 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. #[corresponds(OCSP_resp_find_status)] 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`. #[corresponds(OCSP_cert_to_id)] 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`. #[corresponds(OCSP_response_create)] 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. #[corresponds(d2i_OCSP_RESPONSE)] from_der, OcspResponse, ffi::d2i_OCSP_RESPONSE } } impl OcspResponseRef { to_der! { /// Serializes the response to its standard DER encoding. #[corresponds(i2d_OCSP_RESPONSE)] to_der, ffi::i2d_OCSP_RESPONSE } /// Returns the status of the response. #[corresponds(OCSP_response_status)] 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`. #[corresponds(OCSP_response_get1_basic)] 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 { #[corresponds(OCSP_REQUEST_new)] pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::OCSP_REQUEST_new()).map(OcspRequest) } } from_der! { /// Deserializes a DER-encoded OCSP request. #[corresponds(d2i_OCSP_REQUEST)] from_der, OcspRequest, ffi::d2i_OCSP_REQUEST } } impl OcspRequestRef { to_der! { /// Serializes the request to its standard DER encoding. #[corresponds(i2d_OCSP_REQUEST)] to_der, ffi::i2d_OCSP_REQUEST } #[corresponds(OCSP_request_add0_id)] 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.64/src/pkcs12.rs000064400000000000000000000270631046102023000137270ustar 00000000000000//! PKCS #12 archives. use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::ffi::CString; use std::ptr; use crate::error::ErrorStack; #[cfg(not(boringssl))] use crate::hash::MessageDigest; 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}; use openssl_macros::corresponds; 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. #[corresponds(i2d_PKCS12)] to_der, ffi::i2d_PKCS12 } /// Deprecated. #[deprecated(note = "Use parse2 instead", since = "0.10.46")] #[allow(deprecated)] pub fn parse(&self, pass: &str) -> Result { let parsed = self.parse2(pass)?; Ok(ParsedPkcs12 { pkey: parsed.pkey.unwrap(), cert: parsed.cert.unwrap(), chain: parsed.ca, }) } /// Extracts the contents of the `Pkcs12`. #[corresponds(PKCS12_parse)] pub fn parse2(&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 ca = ptr::null_mut(); cvt(ffi::PKCS12_parse( self.as_ptr(), pass.as_ptr(), &mut pkey, &mut cert, &mut ca, ))?; let pkey = PKey::from_ptr_opt(pkey); let cert = X509::from_ptr_opt(cert); let ca = Stack::from_ptr_opt(ca); Ok(ParsedPkcs12_2 { pkey, cert, ca }) } } } impl Pkcs12 { from_der! { /// Deserializes a DER-encoded PKCS#12 archive. #[corresponds(d2i_PKCS12)] 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` - `AES_256_CBC` (3.0.0+) or `PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` /// * `nid_cert` - `AES_256_CBC` (3.0.0+) or `PBE_WITHSHA1AND40BITRC2_CBC` /// * `iter` - `2048` /// * `mac_iter` - `2048` /// * `mac_md` - `SHA-256` (3.0.0+) or `SHA-1` (`SHA-1` only for BoringSSL) pub fn builder() -> Pkcs12Builder { ffi::init(); Pkcs12Builder { name: None, pkey: None, cert: None, ca: None, nid_key: Nid::UNDEF, nid_cert: Nid::UNDEF, iter: ffi::PKCS12_DEFAULT_ITER, mac_iter: ffi::PKCS12_DEFAULT_ITER, #[cfg(not(boringssl))] mac_md: None, } } } #[deprecated(note = "Use ParsedPkcs12_2 instead", since = "0.10.46")] pub struct ParsedPkcs12 { pub pkey: PKey, pub cert: X509, pub chain: Option>, } pub struct ParsedPkcs12_2 { pub pkey: Option>, pub cert: Option, pub ca: Option>, } pub struct Pkcs12Builder { // FIXME borrow name: Option, pkey: Option>, cert: Option, ca: Option>, nid_key: Nid, nid_cert: Nid, iter: c_int, mac_iter: c_int, // FIXME remove #[cfg(not(boringssl))] mac_md: Option, } impl Pkcs12Builder { /// The `friendlyName` used for the certificate and private key. pub fn name(&mut self, name: &str) -> &mut Self { self.name = Some(CString::new(name).unwrap()); self } /// The private key. pub fn pkey(&mut self, pkey: &PKeyRef) -> &mut Self where T: HasPrivate, { let new_pkey = unsafe { PKeyRef::from_ptr(pkey.as_ptr()) }; self.pkey = Some(new_pkey.to_owned()); self } /// The certificate. pub fn cert(&mut self, cert: &X509Ref) -> &mut Self { self.cert = Some(cert.to_owned()); 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 } /// 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 } /// MAC message digest type #[cfg(not(boringssl))] pub fn mac_md(&mut self, md: MessageDigest) -> &mut Self { self.mac_md = Some(md); self } /// Deprecated. #[deprecated( note = "Use Self::{name, pkey, cert, build2} instead.", since = "0.10.46" )] pub fn build( mut self, password: &str, friendly_name: &str, pkey: &PKeyRef, cert: &X509Ref, ) -> Result where T: HasPrivate, { self.name(friendly_name) .pkey(pkey) .cert(cert) .build2(password) } /// Builds the PKCS#12 object. #[corresponds(PKCS12_create)] pub fn build2(&self, password: &str) -> Result { unsafe { let pass = CString::new(password).unwrap(); let pass = pass.as_ptr(); let friendly_name = self.name.as_ref().map_or(ptr::null(), |p| p.as_ptr()); let pkey = self.pkey.as_ref().map_or(ptr::null(), |p| p.as_ptr()); let cert = self.cert.as_ref().map_or(ptr::null(), |p| p.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/manmaster/crypto/PKCS12_create.html let keytype = 0; let pkcs12 = cvt_p(ffi::PKCS12_create( pass as *mut _, friendly_name as *mut _, pkey as *mut _, cert as *mut _, ca, nid_key, nid_cert, self.iter, self.mac_iter, keytype, )) .map(Pkcs12)?; #[cfg(not(boringssl))] // BoringSSL does not support overriding the MAC and will always // use SHA-1 { let md_type = self .mac_md .map(|md_type| md_type.as_ptr()) .unwrap_or(ptr::null()); cvt(ffi::PKCS12_set_mac( pkcs12.as_ptr(), pass, -1, ptr::null_mut(), 0, self.mac_iter, md_type, ))?; } Ok(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] fn parse() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let der = include_bytes!("../test/identity.p12"); let pkcs12 = Pkcs12::from_der(der).unwrap(); let parsed = pkcs12.parse2("mypass").unwrap(); assert_eq!( hex::encode( parsed .cert .as_ref() .unwrap() .digest(MessageDigest::sha1()) .unwrap() ), "59172d9313e84459bcff27f967e79e6e9217e584" ); assert_eq!( parsed.cert.as_ref().unwrap().alias(), Some(b"foobar.com" as &[u8]) ); let chain = parsed.ca.unwrap(); assert_eq!(chain.len(), 1); assert_eq!( hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } #[test] fn parse_empty_chain() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let der = include_bytes!("../test/keystore-empty-chain.p12"); let pkcs12 = Pkcs12::from_der(der).unwrap(); let parsed = pkcs12.parse2("cassandra").unwrap(); if let Some(stack) = parsed.ca { assert_eq!(stack.len(), 0); } } #[test] fn create() { let subject_name = "ns.example.com"; let rsa = Rsa::generate(2048).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); let mut name = X509Name::builder().unwrap(); name.append_entry_by_nid(Nid::COMMONNAME, subject_name) .unwrap(); let name = name.build(); let key_usage = KeyUsage::new().digital_signature().build().unwrap(); let mut builder = X509::builder().unwrap(); builder.set_version(2).unwrap(); builder .set_not_before(&Asn1Time::days_from_now(0).unwrap()) .unwrap(); builder .set_not_after(&Asn1Time::days_from_now(365).unwrap()) .unwrap(); builder.set_subject_name(&name).unwrap(); builder.set_issuer_name(&name).unwrap(); builder.append_extension(key_usage).unwrap(); builder.set_pubkey(&pkey).unwrap(); builder.sign(&pkey, MessageDigest::sha256()).unwrap(); let cert = builder.build(); let pkcs12 = Pkcs12::builder() .name(subject_name) .pkey(&pkey) .cert(&cert) .build2("mypass") .unwrap(); let der = pkcs12.to_der().unwrap(); let pkcs12 = Pkcs12::from_der(&der).unwrap(); let parsed = pkcs12.parse2("mypass").unwrap(); assert_eq!( &*parsed.cert.unwrap().digest(MessageDigest::sha1()).unwrap(), &*cert.digest(MessageDigest::sha1()).unwrap() ); assert!(parsed.pkey.unwrap().public_eq(&pkey)); } #[test] fn create_only_ca() { let ca = include_bytes!("../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); let mut chain = Stack::new().unwrap(); chain.push(ca).unwrap(); let pkcs12 = Pkcs12::builder().ca(chain).build2("hunter2").unwrap(); let parsed = pkcs12.parse2("hunter2").unwrap(); assert!(parsed.cert.is_none()); assert!(parsed.pkey.is_none()); assert_eq!(parsed.ca.unwrap().len(), 1); } } openssl-0.10.64/src/pkcs5.rs000064400000000000000000000232131046102023000136420ustar 00000000000000#[cfg(not(boringssl))] use libc::c_int; use std::convert::TryInto; #[cfg(not(boringssl))] use std::ptr; use crate::cvt; use crate::error::ErrorStack; use crate::hash::MessageDigest; #[cfg(not(boringssl))] use crate::symm::Cipher; use openssl_macros::corresponds; #[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. #[corresponds(EVP_BytesToKey)] #[allow(clippy::useless_conversion)] #[cfg(not(boringssl))] 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. #[corresponds(PKCS5_PBKDF2_HMAC)] pub fn pbkdf2_hmac( pass: &[u8], salt: &[u8], iter: usize, hash: MessageDigest, key: &mut [u8], ) -> Result<(), ErrorStack> { unsafe { ffi::init(); cvt(ffi::PKCS5_PBKDF2_HMAC( pass.as_ptr() as *const _, pass.len().try_into().unwrap(), salt.as_ptr(), salt.len().try_into().unwrap(), iter.try_into().unwrap(), hash.as_ptr(), key.len().try_into().unwrap(), key.as_mut_ptr(), )) .map(|_| ()) } } /// Derives a key from a password and salt using the scrypt algorithm. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PBE_scrypt)] #[cfg(all(any(ossl110, boringssl), not(osslconf = "OPENSSL_NO_SCRYPT")))] #[allow(clippy::useless_conversion)] 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.try_into().unwrap(), key.as_mut_ptr() as *mut _, key.len(), )) .map(|_| ()) } } #[cfg(test)] mod tests { use crate::hash::MessageDigest; #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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, boringssl))] 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.64/src/pkcs7.rs000064400000000000000000000443661046102023000136600ustar 00000000000000use bitflags::bitflags; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::mem; use std::ptr; use crate::asn1::Asn1ObjectRef; use crate::bio::{MemBio, MemBioSlice}; use crate::error::ErrorStack; use crate::nid::Nid; use crate::pkey::{HasPrivate, PKeyRef}; use crate::stack::{Stack, StackRef, Stackable}; use crate::symm::Cipher; use crate::util::ForeignTypeRefExt; use crate::x509::store::X509StoreRef; use crate::x509::{X509Ref, X509}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; foreign_type_and_impl_send_sync! { type CType = ffi::PKCS7_SIGNER_INFO; fn drop = ffi::PKCS7_SIGNER_INFO_free; pub struct Pkcs7SignerInfo; pub struct Pkcs7SignerInfoRef; } impl Stackable for Pkcs7SignerInfo { type StackType = ffi::stack_st_PKCS7_SIGNER_INFO; } 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; } foreign_type_and_impl_send_sync! { type CType = ffi::PKCS7_SIGNED; fn drop = ffi::PKCS7_SIGNED_free; /// A PKCS#7 signed data structure. /// /// Contains signed data. pub struct Pkcs7Signed; /// Reference to `Pkcs7Signed` pub struct Pkcs7SignedRef; } bitflags! { #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] 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-----`. #[corresponds(PEM_read_bio_PKCS7)] from_pem, Pkcs7, ffi::PEM_read_bio_PKCS7 } from_der! { /// Deserializes a DER-encoded PKCS#7 signature #[corresponds(d2i_PKCS7)] from_der, Pkcs7, ffi::d2i_PKCS7 } /// Parses a message in S/MIME format. /// /// Returns the loaded signature, along with the cleartext message (if /// available). #[corresponds(SMIME_read_PKCS7)] 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. #[corresponds(PKCS7_encrypt)] 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). #[corresponds(PKCS7_sign)] 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 #[corresponds(SMIME_write_PKCS7)] 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-----`. #[corresponds(PEM_write_bio_PKCS7)] to_pem, ffi::PEM_write_bio_PKCS7 } to_der! { /// Serializes the data into a DER-encoded PKCS#7 structure. #[corresponds(i2d_PKCS7)] 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. #[corresponds(PKCS7_decrypt)] 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`. #[corresponds(PKCS7_verify)] 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. #[corresponds(PKCS7_get0_signers)] 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) } } /// Return the type of a PKCS#7 structure as an Asn1Object pub fn type_(&self) -> Option<&Asn1ObjectRef> { unsafe { let ptr = (*self.as_ptr()).type_; Asn1ObjectRef::from_const_ptr_opt(ptr) } } /// Get the signed data of a PKCS#7 structure of type PKCS7_SIGNED pub fn signed(&self) -> Option<&Pkcs7SignedRef> { unsafe { if self.type_().map(|x| x.nid()) != Some(Nid::PKCS7_SIGNED) { return None; } let signed_data = (*self.as_ptr()).d.sign; Pkcs7SignedRef::from_const_ptr_opt(signed_data) } } } impl Pkcs7SignedRef { /// Get the stack of certificates from the PKCS7_SIGNED object pub fn certificates(&self) -> Option<&StackRef> { unsafe { self.as_ptr() .as_ref() .and_then(|x| x.cert.as_mut()) .and_then(|x| StackRef::::from_const_ptr_opt(x)) } } } #[cfg(test)] mod tests { use crate::hash::MessageDigest; use crate::nid::Nid; 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 cipher = 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(), cipher, flags).expect("should succeed"); assert_eq!( pkcs7.type_().expect("PKCS7 should have a type").nid(), Nid::PKCS7_ENVELOPED ); 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"); assert_eq!( pkcs7.type_().expect("PKCS7 should have a type").nid(), Nid::PKCS7_SIGNED ); 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()); } /// https://marc.info/?l=openbsd-cvs&m=166602943014106&w=2 #[test] #[cfg_attr(all(libressl360, not(libressl361)), ignore)] 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"); assert_eq!( pkcs7.type_().expect("PKCS7 should have a type").nid(), Nid::PKCS7_SIGNED ); 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()); } /// https://marc.info/?l=openbsd-cvs&m=166602943014106&w=2 #[test] #[cfg_attr(all(libressl360, not(libressl361)), ignore)] 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"); assert_eq!( pkcs7.type_().expect("PKCS7 should have a type").nid(), Nid::PKCS7_SIGNED ); 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()); } #[test] fn signed_data_certificates() { let cert = include_bytes!("../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let mut extra_certs = Stack::::new().unwrap(); for cert in X509::stack_from_pem(include_bytes!("../test/certs.pem")).expect("should succeed") { extra_certs.push(cert).expect("should succeed"); } let message = "foo"; let flags = Pkcs7Flags::STREAM; let pkey = include_bytes!("../test/key.pem"); let pkey = PKey::private_key_from_pem(pkey).unwrap(); let pkcs7 = Pkcs7::sign(&cert, &pkey, &extra_certs, message.as_bytes(), flags) .expect("should succeed"); assert_eq!( pkcs7.type_().expect("PKCS7 should have a type").nid(), Nid::PKCS7_SIGNED ); let signed_data_certs = pkcs7.signed().and_then(|x| x.certificates()); assert_eq!(signed_data_certs.expect("should succeed").len(), 3); } #[test] fn signed_data_certificates_no_signed_data() { let cert = include_bytes!("../test/certs.pem"); let cert = X509::from_pem(cert).unwrap(); let mut certs = Stack::new().unwrap(); certs.push(cert).unwrap(); let message: String = String::from("foo"); let cipher = Cipher::des_ede3_cbc(); let flags = Pkcs7Flags::STREAM; // Use `Pkcs7::encrypt` since it populates the PKCS7_ENVELOPE struct rather than // PKCS7_SIGNED let pkcs7 = Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed"); assert_eq!( pkcs7.type_().expect("PKCS7 should have a type").nid(), Nid::PKCS7_ENVELOPED ); let signed_data_certs = pkcs7.signed().and_then(|x| x.certificates()); assert!(signed_data_certs.is_none()) } } openssl-0.10.64/src/pkey.rs000064400000000000000000001123151046102023000135670ustar 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()); //! ``` #![allow(clippy::missing_safety_doc)] use crate::bio::{MemBio, MemBioSlice}; #[cfg(ossl110)] use crate::cipher::CipherRef; use crate::dh::Dh; use crate::dsa::Dsa; use crate::ec::EcKey; use crate::error::ErrorStack; #[cfg(any(ossl110, boringssl, libressl370))] use crate::pkey_ctx::PkeyCtx; use crate::rsa::Rsa; use crate::symm::Cipher; use crate::util::{invoke_passwd_cb, CallbackState}; use crate::{cvt, cvt_p}; use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long}; use openssl_macros::corresponds; use std::convert::{TryFrom, TryInto}; use std::ffi::CString; use std::fmt; use std::mem; use std::ptr; /// 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); #[cfg(any(ossl111, libressl310, boringssl))] pub const RSA_PSS: Id = Id(ffi::EVP_PKEY_RSA_PSS); #[cfg(not(boringssl))] pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC); #[cfg(not(boringssl))] pub const CMAC: Id = Id(ffi::EVP_PKEY_CMAC); pub const DSA: Id = Id(ffi::EVP_PKEY_DSA); pub const DH: Id = Id(ffi::EVP_PKEY_DH); #[cfg(ossl110)] pub const DHX: Id = Id(ffi::EVP_PKEY_DHX); pub const EC: Id = Id(ffi::EVP_PKEY_EC); #[cfg(ossl111)] pub const SM2: Id = Id(ffi::EVP_PKEY_SM2); #[cfg(any(ossl110, boringssl, libressl360))] pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF); #[cfg(any(ossl111, boringssl, libressl370))] pub const ED25519: Id = Id(ffi::EVP_PKEY_ED25519); #[cfg(ossl111)] pub const ED448: Id = Id(ffi::EVP_PKEY_ED448); #[cfg(any(ossl111, boringssl, libressl370))] pub const X25519: Id = Id(ffi::EVP_PKEY_X25519); #[cfg(ossl111)] pub const X448: Id = Id(ffi::EVP_PKEY_X448); #[cfg(ossl111)] pub const POLY1305: Id = Id(ffi::EVP_PKEY_POLY1305); /// 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. #[corresponds(EVP_PKEY_get1_RSA)] 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. #[corresponds(EVP_PKEY_get1_DSA)] 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. #[corresponds(EVP_PKEY_get1_DH)] 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. #[corresponds(EVP_PKEY_get1_EC_KEY)] 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. #[corresponds(EVP_PKEY_id)] 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. #[corresponds(EVP_PKEY_size)] 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-----`. #[corresponds(PEM_write_bio_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. #[corresponds(i2d_PUBKEY)] 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. #[corresponds(EVP_PKEY_bits)] pub fn bits(&self) -> u32 { unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 } } ///Returns the number of security bits. /// ///Bits of security is defined in NIST SP800-57. #[corresponds(EVP_PKEY_security_bits)] #[cfg(any(ossl110, libressl360))] pub fn security_bits(&self) -> u32 { unsafe { ffi::EVP_PKEY_security_bits(self.as_ptr()) as u32 } } /// Compares the public component of this key with another. #[corresponds(EVP_PKEY_cmp)] pub fn public_eq(&self, other: &PKeyRef) -> bool where U: HasPublic, { let res = unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }; // Clear the stack. OpenSSL will put an error on the stack when the // keys are different types in some situations. let _ = ErrorStack::get(); res } /// Raw byte representation of a public key. /// /// This function only works for algorithms that support raw public keys. /// Currently this is: [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`]. #[corresponds(EVP_PKEY_get_raw_public_key)] #[cfg(any(ossl111, boringssl, libressl370))] 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-----`. #[corresponds(PEM_write_bio_PKCS8PrivateKey)] 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-----`. #[corresponds(PEM_write_bio_PKCS8PrivateKey)] 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. #[corresponds(i2d_PrivateKey)] 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: [`Id::HMAC`], [`Id::X25519`], [`Id::ED25519`], [`Id::X448`] or [`Id::ED448`]. #[corresponds(EVP_PKEY_get_raw_private_key)] #[cfg(any(ossl111, boringssl, libressl370))] 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 an unencrypted DER-formatted PKCS#8 #[corresponds(i2d_PKCS8PrivateKey_bio)] pub fn private_key_to_pkcs8(&self) -> Result, ErrorStack> { unsafe { let bio = MemBio::new()?; cvt(ffi::i2d_PKCS8PrivateKey_bio( bio.as_ptr(), self.as_ptr(), ptr::null(), ptr::null_mut(), 0, None, ptr::null_mut(), ))?; Ok(bio.get_buf().to_owned()) } } /// Serializes a private key into a DER-formatted PKCS#8, using the supplied password to /// encrypt the key. #[corresponds(i2d_PKCS8PrivateKey_bio)] pub fn private_key_to_pkcs8_passphrase( &self, cipher: Cipher, passphrase: &[u8], ) -> Result, ErrorStack> { unsafe { let bio = MemBio::new()?; cvt(ffi::i2d_PKCS8PrivateKey_bio( bio.as_ptr(), self.as_ptr(), cipher.as_ptr(), passphrase.as_ptr() as *const _ as *mut _, passphrase.len().try_into().unwrap(), 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", #[cfg(not(boringssl))] 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. #[corresponds(EVP_PKEY_assign_RSA)] 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_RSA(pkey.0, rsa.as_ptr()))?; mem::forget(rsa); Ok(pkey) } } /// Creates a new `PKey` containing a DSA key. #[corresponds(EVP_PKEY_assign_DSA)] 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_DSA(pkey.0, dsa.as_ptr()))?; mem::forget(dsa); Ok(pkey) } } /// Creates a new `PKey` containing a Diffie-Hellman key. #[corresponds(EVP_PKEY_assign_DH)] #[cfg(not(boringssl))] 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_DH(pkey.0, dh.as_ptr()))?; mem::forget(dh); Ok(pkey) } } /// Creates a new `PKey` containing a Diffie-Hellman key with type DHX. #[cfg(all(not(boringssl), ossl110))] pub fn from_dhx(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_DHX, dh.as_ptr().cast(), ))?; mem::forget(dh); Ok(pkey) } } /// Creates a new `PKey` containing an elliptic curve key. #[corresponds(EVP_PKEY_assign_EC_KEY)] 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_EC_KEY(pkey.0, ec_key.as_ptr()))?; 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. #[corresponds(EVP_PKEY_new_mac_key)] #[cfg(not(boringssl))] 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(all(not(boringssl), ossl110))] #[allow(clippy::trivially_copy_pass_by_ref)] pub fn cmac(cipher: &Cipher, key: &[u8]) -> Result, ErrorStack> { let mut ctx = PkeyCtx::new_id(Id::CMAC)?; ctx.keygen_init()?; ctx.set_keygen_cipher(unsafe { CipherRef::from_ptr(cipher.as_ptr() as *mut _) })?; ctx.set_keygen_mac_key(key)?; ctx.keygen() } #[cfg(any(ossl111, boringssl, libressl370))] fn generate_eddsa(id: Id) -> Result, ErrorStack> { let mut ctx = PkeyCtx::new_id(id)?; ctx.keygen_init()?; ctx.keygen() } /// Generates a new private X25519 key. /// /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`]. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box> { /// use openssl::pkey::{PKey, Id}; /// use openssl::derive::Deriver; /// /// let public = // ... /// # &PKey::generate_x25519()?.raw_public_key()?; /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X25519)?; /// /// let key = PKey::generate_x25519()?; /// let mut deriver = Deriver::new(&key)?; /// deriver.set_peer(&public_key)?; /// /// let secret = deriver.derive_to_vec()?; /// assert_eq!(secret.len(), 32); /// # Ok(()) } /// ``` #[cfg(any(ossl111, boringssl, libressl370))] pub fn generate_x25519() -> Result, ErrorStack> { PKey::generate_eddsa(Id::X25519) } /// Generates a new private X448 key. /// /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`]. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box> { /// use openssl::pkey::{PKey, Id}; /// use openssl::derive::Deriver; /// /// let public = // ... /// # &PKey::generate_x448()?.raw_public_key()?; /// let public_key = PKey::public_key_from_raw_bytes(public, Id::X448)?; /// /// let key = PKey::generate_x448()?; /// let mut deriver = Deriver::new(&key)?; /// deriver.set_peer(&public_key)?; /// /// let secret = deriver.derive_to_vec()?; /// assert_eq!(secret.len(), 56); /// # Ok(()) } /// ``` #[cfg(ossl111)] pub fn generate_x448() -> Result, ErrorStack> { PKey::generate_eddsa(Id::X448) } /// Generates a new private Ed25519 key. /// /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`]. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box> { /// use openssl::pkey::{PKey, Id}; /// use openssl::sign::Signer; /// /// let key = PKey::generate_ed25519()?; /// let public_key = key.raw_public_key()?; /// /// let mut signer = Signer::new_without_digest(&key)?; /// let digest = // ... /// # &vec![0; 32]; /// let signature = signer.sign_oneshot_to_vec(digest)?; /// assert_eq!(signature.len(), 64); /// # Ok(()) } /// ``` #[cfg(any(ossl111, boringssl, libressl370))] pub fn generate_ed25519() -> Result, ErrorStack> { PKey::generate_eddsa(Id::ED25519) } /// Generates a new private Ed448 key. /// /// To import a private key from raw bytes see [`PKey::private_key_from_raw_bytes`]. /// /// # Examples /// /// ``` /// # fn main() -> Result<(), Box> { /// use openssl::pkey::{PKey, Id}; /// use openssl::sign::Signer; /// /// let key = PKey::generate_ed448()?; /// let public_key = key.raw_public_key()?; /// /// let mut signer = Signer::new_without_digest(&key)?; /// let digest = // ... /// # &vec![0; 32]; /// let signature = signer.sign_oneshot_to_vec(digest)?; /// assert_eq!(signature.len(), 114); /// # Ok(()) } /// ``` #[cfg(ossl111)] pub fn generate_ed448() -> Result, ErrorStack> { PKey::generate_eddsa(Id::ED448) } /// Generates a new EC key using the provided curve. /// /// Requires OpenSSL 3.0.0 or newer. #[corresponds(EVP_EC_gen)] #[cfg(ossl300)] pub fn ec_gen(curve: &str) -> Result, ErrorStack> { ffi::init(); let curve = CString::new(curve).unwrap(); unsafe { let ptr = cvt_p(ffi::EVP_EC_gen(curve.as_ptr()))?; Ok(PKey::from_ptr(ptr)) } } private_key_from_pem! { /// Deserializes a private key from a PEM-encoded key type specific format. #[corresponds(PEM_read_bio_PrivateKey)] private_key_from_pem, /// Deserializes a private key from a PEM-encoded encrypted key type specific format. #[corresponds(PEM_read_bio_PrivateKey)] 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. #[corresponds(PEM_read_bio_PrivateKey)] private_key_from_pem_callback, PKey, ffi::PEM_read_bio_PrivateKey } from_der! { /// Decodes a DER-encoded private key. /// /// This function will attempt to automatically detect the underlying key format, and /// supports the unencrypted PKCS#8 PrivateKeyInfo structures as well as key type specific /// formats. #[corresponds(d2i_AutoPrivateKey)] 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 encrypted. /// /// The callback should copy the password into the provided buffer and return the number of /// bytes written. #[corresponds(d2i_PKCS8PrivateKey_bio)] 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. #[corresponds(d2i_PKCS8PrivateKey_bio)] 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 #[corresponds(EVP_PKEY_new_raw_private_key)] #[cfg(any(ossl111, boringssl, libressl370))] 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 { private_key_from_pem! { /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. /// /// The input should have a header of `-----BEGIN PUBLIC KEY-----`. #[corresponds(PEM_read_bio_PUBKEY)] public_key_from_pem, /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. #[corresponds(PEM_read_bio_PUBKEY)] public_key_from_pem_passphrase, /// Decodes a PEM-encoded SubjectPublicKeyInfo structure. /// /// The callback should fill the password into the provided buffer and return its length. #[corresponds(PEM_read_bio_PrivateKey)] public_key_from_pem_callback, PKey, ffi::PEM_read_bio_PUBKEY } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure. #[corresponds(d2i_PUBKEY)] 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 #[corresponds(EVP_PKEY_new_raw_public_key)] #[cfg(any(ossl111, boringssl, libressl370))] 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(boringssl, 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() } } #[cfg(not(boringssl))] 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; #[cfg(not(boringssl))] use crate::dh::Dh; use crate::dsa::Dsa; use crate::ec::EcKey; use crate::error::Error; 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"); let pkey = PKey::private_key_from_pkcs8(key).unwrap(); let serialized = pkey.private_key_to_pkcs8().unwrap(); let pkey2 = PKey::private_key_from_pkcs8(&serialized).unwrap(); assert_eq!( pkey2.private_key_to_der().unwrap(), pkey.private_key_to_der().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] #[cfg(not(boringssl))] 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] #[cfg(any(ossl110, libressl360))] fn test_security_bits() { let group = crate::ec::EcGroup::from_curve_name(crate::nid::Nid::SECP521R1).unwrap(); let ec_key = EcKey::generate(&group).unwrap(); let pkey: PKey = ec_key.try_into().unwrap(); assert_eq!(pkey.security_bits(), 256); } #[test] #[cfg(not(boringssl))] 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(any(ossl111, boringssl, libressl370))] 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(any(ossl111, boringssl, libressl370))] 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_pkcs8().unwrap(), from_raw.private_key_to_pkcs8().unwrap() ); } #[cfg(any(ossl111, boringssl, libressl370))] #[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); #[cfg(all(not(boringssl), not(libressl370)))] test_raw_public_key(PKey::generate_x448, Id::X448); #[cfg(all(not(boringssl), not(libressl370)))] test_raw_public_key(PKey::generate_ed448, Id::ED448); } #[cfg(any(ossl111, boringssl, libressl370))] #[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); #[cfg(all(not(boringssl), not(libressl370)))] test_raw_private_key(PKey::generate_x448, Id::X448); #[cfg(all(not(boringssl), not(libressl370)))] 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()); } #[cfg(ossl300)] #[test] fn test_ec_gen() { let key = PKey::ec_gen("prime256v1").unwrap(); assert!(key.ec_key().is_ok()); } #[test] fn test_public_eq() { let rsa = Rsa::generate(2048).unwrap(); let pkey1 = PKey::from_rsa(rsa).unwrap(); let group = crate::ec::EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let ec_key = EcKey::generate(&group).unwrap(); let pkey2 = PKey::from_ec_key(ec_key).unwrap(); assert!(!pkey1.public_eq(&pkey2)); assert!(Error::get().is_none()); } } openssl-0.10.64/src/pkey_ctx.rs000064400000000000000000001067261046102023000144560ustar 00000000000000//! The asymmetric encryption context. //! //! # Examples //! //! Encrypt data with RSA //! //! ``` //! use openssl::rsa::Rsa; //! use openssl::pkey::PKey; //! use openssl::pkey_ctx::PkeyCtx; //! //! let key = Rsa::generate(4096).unwrap(); //! let key = PKey::from_rsa(key).unwrap(); //! //! let mut ctx = PkeyCtx::new(&key).unwrap(); //! ctx.encrypt_init().unwrap(); //! //! let data = b"Some Crypto Text"; //! let mut ciphertext = vec![]; //! ctx.encrypt_to_vec(data, &mut ciphertext).unwrap(); //! ``` #![cfg_attr( not(boringssl), doc = r#"\ Generate a CMAC key ``` use openssl::pkey_ctx::PkeyCtx; use openssl::pkey::Id; use openssl::cipher::Cipher; let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap(); ctx.keygen_init().unwrap(); ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap(); ctx.set_keygen_mac_key(b"0123456789abcdef").unwrap(); let cmac_key = ctx.keygen().unwrap(); ```"# )] //! //! Sign and verify data with RSA //! //! ``` //! use openssl::pkey_ctx::PkeyCtx; //! use openssl::pkey::PKey; //! use openssl::rsa::Rsa; //! //! // Generate a random RSA key. //! let key = Rsa::generate(4096).unwrap(); //! let key = PKey::from_rsa(key).unwrap(); //! //! let text = b"Some Crypto Text"; //! //! // Create the signature. //! let mut ctx = PkeyCtx::new(&key).unwrap(); //! ctx.sign_init().unwrap(); //! let mut signature = vec![]; //! ctx.sign_to_vec(text, &mut signature).unwrap(); //! //! // Verify the signature. //! let mut ctx = PkeyCtx::new(&key).unwrap(); //! ctx.verify_init().unwrap(); //! let valid = ctx.verify(text, &signature).unwrap(); //! assert!(valid); //! ``` #[cfg(not(boringssl))] use crate::cipher::CipherRef; use crate::error::ErrorStack; use crate::md::MdRef; use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private}; use crate::rsa::Padding; use crate::sign::RsaPssSaltlen; use crate::{cvt, cvt_p}; use foreign_types::{ForeignType, ForeignTypeRef}; #[cfg(not(boringssl))] use libc::c_int; #[cfg(ossl320)] use libc::c_uint; use openssl_macros::corresponds; use std::convert::TryFrom; #[cfg(ossl320)] use std::ffi::CStr; use std::ptr; /// HKDF modes of operation. #[cfg(any(ossl111, libressl360))] pub struct HkdfMode(c_int); #[cfg(any(ossl111, libressl360))] impl HkdfMode { /// This is the default mode. Calling [`derive`][PkeyCtxRef::derive] on a [`PkeyCtxRef`] set up /// for HKDF will perform an extract followed by an expand operation in one go. The derived key /// returned will be the result after the expand operation. The intermediate fixed-length /// pseudorandom key K is not returned. pub const EXTRACT_THEN_EXPAND: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND); /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the extract operation. /// The value returned will be the intermediate fixed-length pseudorandom key K. /// /// The digest, key and salt values must be set before a key is derived or an error occurs. pub const EXTRACT_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY); /// In this mode calling [`derive`][PkeyCtxRef::derive] will just perform the expand operation. /// The input key should be set to the intermediate fixed-length pseudorandom key K returned /// from a previous extract operation. /// /// The digest, key and info values must be set before a key is derived or an error occurs. pub const EXPAND_ONLY: Self = HkdfMode(ffi::EVP_PKEY_HKDEF_MODE_EXPAND_ONLY); } /// Nonce type for ECDSA and DSA. #[cfg(ossl320)] #[derive(Debug, PartialEq)] pub struct NonceType(c_uint); #[cfg(ossl320)] impl NonceType { /// This is the default mode. It uses a random value for the nonce k as defined in FIPS 186-4 Section 6.3 /// “Secret Number Generation”. pub const RANDOM_K: Self = NonceType(0); /// Uses a deterministic value for the nonce k as defined in RFC #6979 (See Section 3.2 “Generation of k”). pub const DETERMINISTIC_K: Self = NonceType(1); } generic_foreign_type_and_impl_send_sync! { type CType = ffi::EVP_PKEY_CTX; fn drop = ffi::EVP_PKEY_CTX_free; /// A context object which can perform asymmetric cryptography operations. pub struct PkeyCtx; /// A reference to a [`PkeyCtx`]. pub struct PkeyCtxRef; } impl PkeyCtx { /// Creates a new pkey context using the provided key. #[corresponds(EVP_PKEY_CTX_new)] #[inline] pub fn new(pkey: &PKeyRef) -> Result { unsafe { let ptr = cvt_p(ffi::EVP_PKEY_CTX_new(pkey.as_ptr(), ptr::null_mut()))?; Ok(PkeyCtx::from_ptr(ptr)) } } } impl PkeyCtx<()> { /// Creates a new pkey context for the specified algorithm ID. #[corresponds(EVP_PKEY_new_id)] #[inline] pub fn new_id(id: Id) -> Result { unsafe { let ptr = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), ptr::null_mut()))?; Ok(PkeyCtx::from_ptr(ptr)) } } } impl PkeyCtxRef where T: HasPublic, { /// Prepares the context for encryption using the public key. #[corresponds(EVP_PKEY_encrypt_init)] #[inline] pub fn encrypt_init(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_encrypt_init(self.as_ptr()))?; } Ok(()) } /// Prepares the context for signature verification using the public key. #[corresponds(EVP_PKEY_verify_init)] #[inline] pub fn verify_init(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_verify_init(self.as_ptr()))?; } Ok(()) } /// Prepares the context for signature recovery using the public key. #[corresponds(EVP_PKEY_verify_recover_init)] #[inline] pub fn verify_recover_init(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_verify_recover_init(self.as_ptr()))?; } Ok(()) } /// Encrypts data using the public key. /// /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be /// returned. #[corresponds(EVP_PKEY_encrypt)] #[inline] pub fn encrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result { let mut written = to.as_ref().map_or(0, |b| b.len()); unsafe { cvt(ffi::EVP_PKEY_encrypt( self.as_ptr(), to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } /// Like [`Self::encrypt`] but appends ciphertext to a [`Vec`]. pub fn encrypt_to_vec(&mut self, from: &[u8], out: &mut Vec) -> Result { let base = out.len(); let len = self.encrypt(from, None)?; out.resize(base + len, 0); let len = self.encrypt(from, Some(&mut out[base..]))?; out.truncate(base + len); Ok(len) } /// Verifies the signature of data using the public key. /// /// Returns `Ok(true)` if the signature is valid, `Ok(false)` if the signature is invalid, and `Err` if an error /// occurred. /// /// # Note /// /// This verifies the signature of the *raw* data. It is more common to compute and verify the signature of the /// cryptographic hash of an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do /// that. #[corresponds(EVP_PKEY_verify)] #[inline] pub fn verify(&mut self, data: &[u8], sig: &[u8]) -> Result { unsafe { let r = ffi::EVP_PKEY_verify( self.as_ptr(), sig.as_ptr(), sig.len(), data.as_ptr(), data.len(), ); // `EVP_PKEY_verify` is not terribly consistent about how it, // reports errors. It does not clearly distinguish between 0 and // -1, and may put errors on the stack in both cases. If there's // errors on the stack, we return `Err()`, else we return // `Ok(false)`. if r <= 0 { let errors = ErrorStack::get(); if !errors.errors().is_empty() { return Err(errors); } } Ok(r == 1) } } /// Recovers the original data signed by the private key. You almost /// always want `verify` instead. /// /// Returns the number of bytes written to `to`, or the number of bytes /// that would be written, if `to` is `None. #[corresponds(EVP_PKEY_verify_recover)] #[inline] pub fn verify_recover( &mut self, sig: &[u8], to: Option<&mut [u8]>, ) -> Result { let mut written = to.as_ref().map_or(0, |b| b.len()); unsafe { cvt(ffi::EVP_PKEY_verify_recover( self.as_ptr(), to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), &mut written, sig.as_ptr(), sig.len(), ))?; } Ok(written) } } impl PkeyCtxRef where T: HasPrivate, { /// Prepares the context for decryption using the private key. #[corresponds(EVP_PKEY_decrypt_init)] #[inline] pub fn decrypt_init(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_decrypt_init(self.as_ptr()))?; } Ok(()) } /// Prepares the context for signing using the private key. #[corresponds(EVP_PKEY_sign_init)] #[inline] pub fn sign_init(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_sign_init(self.as_ptr()))?; } Ok(()) } /// Sets the peer key used for secret derivation. #[corresponds(EVP_PKEY_derive_set_peer)] pub fn derive_set_peer(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> where U: HasPublic, { unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.as_ptr(), key.as_ptr()))?; } Ok(()) } /// Decrypts data using the private key. /// /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be /// returned. #[corresponds(EVP_PKEY_decrypt)] #[inline] pub fn decrypt(&mut self, from: &[u8], to: Option<&mut [u8]>) -> Result { let mut written = to.as_ref().map_or(0, |b| b.len()); unsafe { cvt(ffi::EVP_PKEY_decrypt( self.as_ptr(), to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), &mut written, from.as_ptr(), from.len(), ))?; } Ok(written) } /// Like [`Self::decrypt`] but appends plaintext to a [`Vec`]. pub fn decrypt_to_vec(&mut self, from: &[u8], out: &mut Vec) -> Result { let base = out.len(); let len = self.decrypt(from, None)?; out.resize(base + len, 0); let len = self.decrypt(from, Some(&mut out[base..]))?; out.truncate(base + len); Ok(len) } /// Signs the contents of `data`. /// /// If `sig` is set to `None`, an upper bound on the number of bytes required for the output buffer will be /// returned. /// /// # Note /// /// This computes the signature of the *raw* bytes of `data`. It is more common to sign the cryptographic hash of /// an arbitrary amount of data. The [`MdCtx`](crate::md_ctx::MdCtx) type can be used to do that. #[corresponds(EVP_PKEY_sign)] #[inline] pub fn sign(&mut self, data: &[u8], sig: Option<&mut [u8]>) -> Result { let mut written = sig.as_ref().map_or(0, |b| b.len()); unsafe { cvt(ffi::EVP_PKEY_sign( self.as_ptr(), sig.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), &mut written, data.as_ptr(), data.len(), ))?; } Ok(written) } /// Like [`Self::sign`] but appends the signature to a [`Vec`]. pub fn sign_to_vec(&mut self, data: &[u8], sig: &mut Vec) -> Result { let base = sig.len(); let len = self.sign(data, None)?; sig.resize(base + len, 0); let len = self.sign(data, Some(&mut sig[base..]))?; sig.truncate(base + len); Ok(len) } } impl PkeyCtxRef { /// Prepares the context for shared secret derivation. #[corresponds(EVP_PKEY_derive_init)] #[inline] pub fn derive_init(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_derive_init(self.as_ptr()))?; } Ok(()) } /// Prepares the context for key generation. #[corresponds(EVP_PKEY_keygen_init)] #[inline] pub fn keygen_init(&mut self) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_keygen_init(self.as_ptr()))?; } Ok(()) } /// Sets which algorithm was used to compute the digest used in a /// signature. With RSA signatures this causes the signature to be wrapped /// in a `DigestInfo` structure. This is almost always what you want with /// RSA signatures. #[corresponds(EVP_PKEY_CTX_set_signature_md)] #[inline] pub fn set_signature_md(&self, md: &MdRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_signature_md( self.as_ptr(), md.as_ptr(), ))?; } Ok(()) } /// Returns the RSA padding mode in use. /// /// This is only useful for RSA keys. #[corresponds(EVP_PKEY_CTX_get_rsa_padding)] #[inline] pub fn rsa_padding(&self) -> Result { let mut pad = 0; unsafe { cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))?; } Ok(Padding::from_raw(pad)) } /// Sets the RSA padding mode. /// /// This is only useful for RSA keys. #[corresponds(EVP_PKEY_CTX_set_rsa_padding)] #[inline] pub fn set_rsa_padding(&mut self, padding: Padding) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_padding( self.as_ptr(), padding.as_raw(), ))?; } Ok(()) } /// Sets the RSA PSS salt length. /// /// This is only useful for RSA keys. #[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)] #[inline] pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( self.as_ptr(), len.as_raw(), )) .map(|_| ()) } } /// Sets the RSA MGF1 algorithm. /// /// This is only useful for RSA keys. #[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)] #[inline] pub fn set_rsa_mgf1_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md( self.as_ptr(), md.as_ptr(), ))?; } Ok(()) } /// Sets the RSA OAEP algorithm. /// /// This is only useful for RSA keys. #[corresponds(EVP_PKEY_CTX_set_rsa_oaep_md)] #[cfg(any(ossl102, libressl310, boringssl))] #[inline] pub fn set_rsa_oaep_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_rsa_oaep_md( self.as_ptr(), md.as_ptr() as *mut _, ))?; } Ok(()) } /// Sets the RSA OAEP label. /// /// This is only useful for RSA keys. #[corresponds(EVP_PKEY_CTX_set0_rsa_oaep_label)] #[cfg(any(ossl102, libressl310, boringssl))] pub fn set_rsa_oaep_label(&mut self, label: &[u8]) -> Result<(), ErrorStack> { use crate::LenType; let len = LenType::try_from(label.len()).unwrap(); unsafe { let p = ffi::OPENSSL_malloc(label.len() as _); ptr::copy_nonoverlapping(label.as_ptr(), p as *mut _, label.len()); let r = cvt(ffi::EVP_PKEY_CTX_set0_rsa_oaep_label( self.as_ptr(), p as *mut _, len, )); if r.is_err() { ffi::OPENSSL_free(p); } r?; } Ok(()) } /// Sets the cipher used during key generation. #[cfg(not(boringssl))] #[corresponds(EVP_PKEY_CTX_ctrl)] #[inline] pub fn set_keygen_cipher(&mut self, cipher: &CipherRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_ctrl( self.as_ptr(), -1, ffi::EVP_PKEY_OP_KEYGEN, ffi::EVP_PKEY_CTRL_CIPHER, 0, cipher.as_ptr() as *mut _, ))?; } Ok(()) } /// Sets the key MAC key used during key generation. #[cfg(not(boringssl))] #[corresponds(EVP_PKEY_CTX_ctrl)] #[inline] pub fn set_keygen_mac_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { let len = c_int::try_from(key.len()).unwrap(); unsafe { cvt(ffi::EVP_PKEY_CTX_ctrl( self.as_ptr(), -1, ffi::EVP_PKEY_OP_KEYGEN, ffi::EVP_PKEY_CTRL_SET_MAC_KEY, len, key.as_ptr() as *mut _, ))?; } Ok(()) } /// Sets the digest used for HKDF derivation. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set_hkdf_md)] #[cfg(any(ossl110, boringssl, libressl360))] #[inline] pub fn set_hkdf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_hkdf_md( self.as_ptr(), digest.as_ptr(), ))?; } Ok(()) } /// Sets the HKDF mode of operation. /// /// Defaults to [`HkdfMode::EXTRACT_THEN_EXPAND`]. /// /// WARNING: Although this API calls it a "mode", HKDF-Extract and HKDF-Expand are distinct /// operations with distinct inputs and distinct kinds of keys. Callers should not pass input /// secrets for one operation into the other. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(EVP_PKEY_CTX_set_hkdf_mode)] #[cfg(any(ossl111, libressl360))] #[inline] pub fn set_hkdf_mode(&mut self, mode: HkdfMode) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_PKEY_CTX_set_hkdf_mode(self.as_ptr(), mode.0))?; } Ok(()) } /// Sets the input material for HKDF generation as the "key". /// /// Which input is the key depends on the "mode" (see [`set_hkdf_mode`][Self::set_hkdf_mode]). /// If [`HkdfMode::EXTRACT_THEN_EXPAND`] or [`HkdfMode::EXTRACT_ONLY`], this function specifies /// the input keying material (IKM) for HKDF-Extract. If [`HkdfMode::EXPAND_ONLY`], it instead /// specifies the pseudorandom key (PRK) for HKDF-Expand. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set1_hkdf_key)] #[cfg(any(ossl110, boringssl, libressl360))] #[inline] pub fn set_hkdf_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { #[cfg(not(boringssl))] let len = c_int::try_from(key.len()).unwrap(); #[cfg(boringssl)] let len = key.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_set1_hkdf_key( self.as_ptr(), key.as_ptr(), len, ))?; } Ok(()) } /// Sets the salt value for HKDF generation. /// /// If performing HKDF-Expand only, this parameter is ignored. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set1_hkdf_salt)] #[cfg(any(ossl110, boringssl, libressl360))] #[inline] pub fn set_hkdf_salt(&mut self, salt: &[u8]) -> Result<(), ErrorStack> { #[cfg(not(boringssl))] let len = c_int::try_from(salt.len()).unwrap(); #[cfg(boringssl)] let len = salt.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_set1_hkdf_salt( self.as_ptr(), salt.as_ptr(), len, ))?; } Ok(()) } /// Appends info bytes for HKDF generation. /// /// If performing HKDF-Extract only, this parameter is ignored. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_add1_hkdf_info)] #[cfg(any(ossl110, boringssl, libressl360))] #[inline] pub fn add_hkdf_info(&mut self, info: &[u8]) -> Result<(), ErrorStack> { #[cfg(not(boringssl))] let len = c_int::try_from(info.len()).unwrap(); #[cfg(boringssl)] let len = info.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_add1_hkdf_info( self.as_ptr(), info.as_ptr(), len, ))?; } Ok(()) } /// Derives a shared secret between two keys. /// /// If `buf` is set to `None`, an upper bound on the number of bytes required for the buffer will be returned. #[corresponds(EVP_PKEY_derive)] pub fn derive(&mut self, buf: Option<&mut [u8]>) -> Result { let mut len = buf.as_ref().map_or(0, |b| b.len()); unsafe { cvt(ffi::EVP_PKEY_derive( self.as_ptr(), buf.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), &mut len, ))?; } Ok(len) } /// Like [`Self::derive`] but appends the secret to a [`Vec`]. pub fn derive_to_vec(&mut self, buf: &mut Vec) -> Result { let base = buf.len(); let len = self.derive(None)?; buf.resize(base + len, 0); let len = self.derive(Some(&mut buf[base..]))?; buf.truncate(base + len); Ok(len) } /// Generates a new public/private keypair. #[corresponds(EVP_PKEY_keygen)] #[inline] pub fn keygen(&mut self) -> Result, ErrorStack> { unsafe { let mut key = ptr::null_mut(); cvt(ffi::EVP_PKEY_keygen(self.as_ptr(), &mut key))?; Ok(PKey::from_ptr(key)) } } /// Sets the nonce type for a private key context. /// /// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979). /// /// This is only useful for DSA and ECDSA. /// Requires OpenSSL 3.2.0 or newer. #[cfg(ossl320)] #[corresponds(EVP_PKEY_CTX_set_params)] pub fn set_nonce_type(&mut self, nonce_type: NonceType) -> Result<(), ErrorStack> { let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type\0").unwrap(); let mut nonce_type = nonce_type.0; unsafe { let param_nonce = ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type); let param_end = ffi::OSSL_PARAM_construct_end(); let params = [param_nonce, param_end]; cvt(ffi::EVP_PKEY_CTX_set_params(self.as_ptr(), params.as_ptr()))?; } Ok(()) } /// Gets the nonce type for a private key context. /// /// The nonce for DSA and ECDSA can be either random (the default) or deterministic (as defined by RFC 6979). /// /// This is only useful for DSA and ECDSA. /// Requires OpenSSL 3.2.0 or newer. #[cfg(ossl320)] #[corresponds(EVP_PKEY_CTX_get_params)] pub fn nonce_type(&mut self) -> Result { let nonce_field_name = CStr::from_bytes_with_nul(b"nonce-type\0").unwrap(); let mut nonce_type: c_uint = 0; unsafe { let param_nonce = ffi::OSSL_PARAM_construct_uint(nonce_field_name.as_ptr(), &mut nonce_type); let param_end = ffi::OSSL_PARAM_construct_end(); let mut params = [param_nonce, param_end]; cvt(ffi::EVP_PKEY_CTX_get_params( self.as_ptr(), params.as_mut_ptr(), ))?; } Ok(NonceType(nonce_type)) } } #[cfg(test)] mod test { use super::*; #[cfg(not(boringssl))] use crate::cipher::Cipher; use crate::ec::{EcGroup, EcKey}; use crate::hash::{hash, MessageDigest}; use crate::md::Md; use crate::nid::Nid; use crate::pkey::PKey; use crate::rsa::Rsa; use crate::sign::Verifier; #[test] fn rsa() { let key = include_bytes!("../test/rsa.pem"); let rsa = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); let mut ctx = PkeyCtx::new(&pkey).unwrap(); ctx.encrypt_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1).unwrap(); let pt = "hello world".as_bytes(); let mut ct = vec![]; ctx.encrypt_to_vec(pt, &mut ct).unwrap(); ctx.decrypt_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1).unwrap(); let mut out = vec![]; ctx.decrypt_to_vec(&ct, &mut out).unwrap(); assert_eq!(pt, out); } #[test] #[cfg(any(ossl102, libressl310, boringssl))] fn rsa_oaep() { let key = include_bytes!("../test/rsa.pem"); let rsa = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); let mut ctx = PkeyCtx::new(&pkey).unwrap(); ctx.encrypt_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); let pt = "hello world".as_bytes(); let mut ct = vec![]; ctx.encrypt_to_vec(pt, &mut ct).unwrap(); ctx.decrypt_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1_OAEP).unwrap(); ctx.set_rsa_oaep_md(Md::sha256()).unwrap(); ctx.set_rsa_mgf1_md(Md::sha256()).unwrap(); let mut out = vec![]; ctx.decrypt_to_vec(&ct, &mut out).unwrap(); assert_eq!(pt, out); } #[test] fn rsa_sign() { let key = include_bytes!("../test/rsa.pem"); let rsa = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); let mut ctx = PkeyCtx::new(&pkey).unwrap(); ctx.sign_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1).unwrap(); ctx.set_signature_md(Md::sha384()).unwrap(); let msg = b"hello world"; let digest = hash(MessageDigest::sha384(), msg).unwrap(); let mut signature = vec![]; ctx.sign_to_vec(&digest, &mut signature).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap(); verifier.update(msg).unwrap(); assert!(matches!(verifier.verify(&signature), Ok(true))); } #[test] fn rsa_sign_pss() { let key = include_bytes!("../test/rsa.pem"); let rsa = Rsa::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(rsa).unwrap(); let mut ctx = PkeyCtx::new(&pkey).unwrap(); ctx.sign_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); ctx.set_signature_md(Md::sha384()).unwrap(); ctx.set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)).unwrap(); let msg = b"hello world"; let digest = hash(MessageDigest::sha384(), msg).unwrap(); let mut signature = vec![]; ctx.sign_to_vec(&digest, &mut signature).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap(); verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); verifier .set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)) .unwrap(); verifier.update(msg).unwrap(); assert!(matches!(verifier.verify(&signature), Ok(true))); } #[test] fn derive() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key1 = EcKey::generate(&group).unwrap(); let key1 = PKey::from_ec_key(key1).unwrap(); let key2 = EcKey::generate(&group).unwrap(); let key2 = PKey::from_ec_key(key2).unwrap(); let mut ctx = PkeyCtx::new(&key1).unwrap(); ctx.derive_init().unwrap(); ctx.derive_set_peer(&key2).unwrap(); let mut buf = vec![]; ctx.derive_to_vec(&mut buf).unwrap(); } #[test] #[cfg(not(boringssl))] fn cmac_keygen() { let mut ctx = PkeyCtx::new_id(Id::CMAC).unwrap(); ctx.keygen_init().unwrap(); ctx.set_keygen_cipher(Cipher::aes_128_cbc()).unwrap(); ctx.set_keygen_mac_key(&hex::decode("9294727a3638bb1c13f48ef8158bfc9d").unwrap()) .unwrap(); ctx.keygen().unwrap(); } #[test] #[cfg(any(ossl110, boringssl, libressl360))] fn hkdf() { let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); ctx.derive_init().unwrap(); ctx.set_hkdf_md(Md::sha256()).unwrap(); ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap()) .unwrap(); ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap()) .unwrap(); ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap()) .unwrap(); let mut out = [0; 42]; ctx.derive(Some(&mut out)).unwrap(); assert_eq!( &out[..], hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865") .unwrap() ); } #[test] #[cfg(any(ossl111, libressl360))] fn hkdf_expand() { let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); ctx.derive_init().unwrap(); ctx.set_hkdf_mode(HkdfMode::EXPAND_ONLY).unwrap(); ctx.set_hkdf_md(Md::sha256()).unwrap(); ctx.set_hkdf_key( &hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5") .unwrap(), ) .unwrap(); ctx.add_hkdf_info(&hex::decode("f0f1f2f3f4f5f6f7f8f9").unwrap()) .unwrap(); let mut out = [0; 42]; ctx.derive(Some(&mut out)).unwrap(); assert_eq!( &out[..], hex::decode("3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865") .unwrap() ); } #[test] #[cfg(any(ossl111, libressl360))] fn hkdf_extract() { let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); ctx.derive_init().unwrap(); ctx.set_hkdf_mode(HkdfMode::EXTRACT_ONLY).unwrap(); ctx.set_hkdf_md(Md::sha256()).unwrap(); ctx.set_hkdf_key(&hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap()) .unwrap(); ctx.set_hkdf_salt(&hex::decode("000102030405060708090a0b0c").unwrap()) .unwrap(); let mut out = vec![]; ctx.derive_to_vec(&mut out).unwrap(); assert_eq!( &out[..], hex::decode("077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5") .unwrap() ); } #[test] fn verify_fail() { let key1 = Rsa::generate(4096).unwrap(); let key1 = PKey::from_rsa(key1).unwrap(); let data = b"Some Crypto Text"; let mut ctx = PkeyCtx::new(&key1).unwrap(); ctx.sign_init().unwrap(); let mut signature = vec![]; ctx.sign_to_vec(data, &mut signature).unwrap(); let bad_data = b"Some Crypto text"; ctx.verify_init().unwrap(); let valid = ctx.verify(bad_data, &signature); assert!(matches!(valid, Ok(false) | Err(_))); assert!(ErrorStack::get().errors().is_empty()); } #[test] fn verify_fail_ec() { let key1 = EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap(); let key1 = PKey::from_ec_key(key1).unwrap(); let data = b"Some Crypto Text"; let mut ctx = PkeyCtx::new(&key1).unwrap(); ctx.verify_init().unwrap(); assert!(matches!(ctx.verify(data, &[0; 64]), Ok(false) | Err(_))); assert!(ErrorStack::get().errors().is_empty()); } #[test] fn test_verify_recover() { let key = Rsa::generate(2048).unwrap(); let key = PKey::from_rsa(key).unwrap(); let digest = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, ]; let mut ctx = PkeyCtx::new(&key).unwrap(); ctx.sign_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1).unwrap(); ctx.set_signature_md(Md::sha256()).unwrap(); let mut signature = vec![]; ctx.sign_to_vec(&digest, &mut signature).unwrap(); // Attempt recovery of just the digest. let mut ctx = PkeyCtx::new(&key).unwrap(); ctx.verify_recover_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1).unwrap(); ctx.set_signature_md(Md::sha256()).unwrap(); let length = ctx.verify_recover(&signature, None).unwrap(); let mut result_buf = vec![0; length]; let length = ctx .verify_recover(&signature, Some(&mut result_buf)) .unwrap(); assert_eq!(length, digest.len()); // result_buf contains the digest assert_eq!(result_buf[..length], digest); // Attempt recovery of teh entire DigestInfo let mut ctx = PkeyCtx::new(&key).unwrap(); ctx.verify_recover_init().unwrap(); ctx.set_rsa_padding(Padding::PKCS1).unwrap(); let length = ctx.verify_recover(&signature, None).unwrap(); let mut result_buf = vec![0; length]; let length = ctx .verify_recover(&signature, Some(&mut result_buf)) .unwrap(); // 32-bytes of SHA256 digest + the ASN.1 DigestInfo structure == 51 bytes assert_eq!(length, 51); // The digest is the end of the DigestInfo structure. assert_eq!(result_buf[length - digest.len()..length], digest); } #[test] #[cfg(ossl320)] fn set_nonce_type() { let key1 = EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap(); let key1 = PKey::from_ec_key(key1).unwrap(); let mut ctx = PkeyCtx::new(&key1).unwrap(); ctx.sign_init().unwrap(); ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap(); let nonce_type = ctx.nonce_type().unwrap(); assert_eq!(nonce_type, NonceType::DETERMINISTIC_K); assert!(ErrorStack::get().errors().is_empty()); } // Test vector from // https://github.com/openssl/openssl/blob/openssl-3.2.0/test/recipes/30-test_evp_data/evppkey_ecdsa_rfc6979.txt #[test] #[cfg(ossl320)] fn ecdsa_deterministic_signature() { let private_key_pem = "-----BEGIN PRIVATE KEY----- MDkCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEHzAdAgEBBBhvqwNJNOTA/Jrmf1tWWanX0f79GH7g n9Q= -----END PRIVATE KEY-----"; let key1 = EcKey::private_key_from_pem(private_key_pem.as_bytes()).unwrap(); let key1 = PKey::from_ec_key(key1).unwrap(); let input = "sample"; let expected_output = hex::decode("303502190098C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF021857A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64").unwrap(); let hashed_input = hash(MessageDigest::sha1(), input.as_bytes()).unwrap(); let mut ctx = PkeyCtx::new(&key1).unwrap(); ctx.sign_init().unwrap(); ctx.set_signature_md(Md::sha1()).unwrap(); ctx.set_nonce_type(NonceType::DETERMINISTIC_K).unwrap(); let mut output = vec![]; ctx.sign_to_vec(&hashed_input, &mut output).unwrap(); assert_eq!(output, expected_output); assert!(ErrorStack::get().errors().is_empty()); } } openssl-0.10.64/src/provider.rs000064400000000000000000000054211046102023000144500ustar 00000000000000use crate::error::ErrorStack; use crate::lib_ctx::LibCtxRef; use crate::{cvt, cvt_p}; use foreign_types::{ForeignType, ForeignTypeRef}; use openssl_macros::corresponds; use std::ffi::CString; use std::ptr; foreign_type_and_impl_send_sync! { type CType = ffi::OSSL_PROVIDER; fn drop = ossl_provider_free; pub struct Provider; /// A reference to a [`Provider`]. pub struct ProviderRef; } #[inline] unsafe fn ossl_provider_free(p: *mut ffi::OSSL_PROVIDER) { ffi::OSSL_PROVIDER_unload(p); } impl Provider { /// Loads a new provider into the specified library context, disabling the fallback providers. /// /// If `ctx` is `None`, the provider will be loaded in to the default library context. #[corresponds(OSSL_provider_load)] pub fn load(ctx: Option<&LibCtxRef>, name: &str) -> Result { let name = CString::new(name).unwrap(); unsafe { let p = cvt_p(ffi::OSSL_PROVIDER_load( ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), name.as_ptr(), ))?; Ok(Provider::from_ptr(p)) } } /// Loads a new provider into the specified library context, disabling the fallback providers if `retain_fallbacks` /// is `false` and the load succeeds. /// /// If `ctx` is `None`, the provider will be loaded into the default library context. #[corresponds(OSSL_provider_try_load)] pub fn try_load( ctx: Option<&LibCtxRef>, name: &str, retain_fallbacks: bool, ) -> Result { let name = CString::new(name).unwrap(); unsafe { let p = cvt_p(ffi::OSSL_PROVIDER_try_load( ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), name.as_ptr(), retain_fallbacks as _, ))?; // OSSL_PROVIDER_try_load seems to leave errors on the stack, even // when it succeeds. let _ = ErrorStack::get(); Ok(Provider::from_ptr(p)) } } /// Specifies the default search path that is to be used for looking for providers in the specified library context. /// If left unspecified, an environment variable and a fall back default value will be used instead /// /// If `ctx` is `None`, the provider will be loaded into the default library context. #[corresponds(OSSL_PROVIDER_set_default_search_path)] pub fn set_default_search_path(ctx: Option<&LibCtxRef>, path: &str) -> Result<(), ErrorStack> { let path = CString::new(path).unwrap(); unsafe { cvt(ffi::OSSL_PROVIDER_set_default_search_path( ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr), path.as_ptr(), )) .map(|_| ()) } } } openssl-0.10.64/src/rand.rs000064400000000000000000000042561046102023000135470ustar 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::error::ErrorStack; use crate::{cvt, LenType}; use openssl_macros::corresponds; /// Fill buffer with cryptographically strong pseudo-random bytes. /// /// # Examples /// /// To generate a buffer with cryptographically strong random bytes: /// /// ``` /// use openssl::rand::rand_bytes; /// /// let mut buf = [0; 256]; /// rand_bytes(&mut buf).unwrap(); /// ``` #[corresponds(RAND_bytes)] 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 LenType)).map(|_| ()) } } /// Fill buffer with cryptographically strong pseudo-random bytes. It is /// intended to be used for generating values that should remain private. /// /// # Examples /// /// To generate a buffer with cryptographically strong random bytes: /// /// ``` /// use openssl::rand::rand_priv_bytes; /// /// let mut buf = [0; 256]; /// rand_priv_bytes(&mut buf).unwrap(); /// ``` /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(RAND_priv_bytes)] #[cfg(ossl111)] pub fn rand_priv_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> { unsafe { ffi::init(); assert!(buf.len() <= c_int::max_value() as usize); cvt(ffi::RAND_priv_bytes(buf.as_mut_ptr(), buf.len() as LenType)).map(|_| ()) } } /// Controls random device file descriptor behavior. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(RAND_keep_random_devices_open)] #[cfg(ossl111)] pub fn keep_random_devices_open(keep: bool) { unsafe { ffi::RAND_keep_random_devices_open(keep as LenType); } } #[cfg(test)] mod tests { #[test] fn test_rand_bytes() { let mut buf = [0; 32]; super::rand_bytes(&mut buf).unwrap(); } #[test] #[cfg(ossl111)] fn test_rand_priv_bytes() { let mut buf = [0; 32]; super::rand_priv_bytes(&mut buf).unwrap(); } } openssl-0.10.64/src/rsa.rs000064400000000000000000000642311046102023000134070ustar 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, LenType}; use openssl_macros::corresponds; /// 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-----`. #[corresponds(PEM_write_bio_RSAPrivateKey)] 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-----`. #[corresponds(PEM_write_bio_RSAPrivateKey)] private_key_to_pem_passphrase, ffi::PEM_write_bio_RSAPrivateKey } to_der! { /// Serializes the private key to a DER-encoded PKCS#1 RSAPrivateKey structure. #[corresponds(i2d_RSAPrivateKey)] 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()`. #[corresponds(RSA_private_decrypt)] 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 LenType, 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()`. #[corresponds(RSA_private_encrypt)] 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 LenType, 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. #[corresponds(RSA_get0_key)] 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. #[corresponds(RSA_get0_factors)] 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. #[corresponds(RSA_get0_factors)] 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. #[corresponds(RSA_get0_crt_params)] 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. #[corresponds(RSA_get0_crt_params)] 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. #[corresponds(RSA_get0_crt_params)] 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 #[corresponds(RSA_check_key)] #[allow(clippy::unnecessary_cast)] 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-----`. #[corresponds(PEM_write_bio_RSA_PUBKEY)] public_key_to_pem, ffi::PEM_write_bio_RSA_PUBKEY } to_der! { /// Serializes the public key into a DER-encoded SubjectPublicKeyInfo structure. #[corresponds(i2d_RSA_PUBKEY)] 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-----`. #[corresponds(PEM_write_bio_RSAPublicKey)] public_key_to_pem_pkcs1, ffi::PEM_write_bio_RSAPublicKey } to_der! { /// Serializes the public key into a DER-encoded PKCS#1 RSAPublicKey structure. #[corresponds(i2d_RSAPublicKey)] public_key_to_der_pkcs1, ffi::i2d_RSAPublicKey } /// Returns the size of the modulus in bytes. #[corresponds(RSA_size)] 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()`. #[corresponds(RSA_public_decrypt)] 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 LenType, 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()`. #[corresponds(RSA_public_encrypt)] 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 LenType, 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. #[corresponds(RSA_get0_key)] 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. #[corresponds(RSA_get0_key)] 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/manmaster/crypto/RSA_new.html /// [`RSA_set0_key`]: https://www.openssl.org/docs/manmaster/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-----`. #[corresponds(PEM_read_bio_RSA_PUBKEY)] 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-----`. #[corresponds(PEM_read_bio_RSAPublicKey)] public_key_from_pem_pkcs1, Rsa, ffi::PEM_read_bio_RSAPublicKey } from_der! { /// Decodes a DER-encoded SubjectPublicKeyInfo structure containing an RSA key. #[corresponds(d2i_RSA_PUBKEY)] public_key_from_der, Rsa, ffi::d2i_RSA_PUBKEY } from_der! { /// Decodes a DER-encoded PKCS#1 RSAPublicKey structure. #[corresponds(d2i_RSAPublicKey)] 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/manmaster/crypto/RSA_new.html /// [`RSA_set0_key`]: https://www.openssl.org/docs/manmaster/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`. #[corresponds(RSA_set0_factors)] // 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. #[corresponds(RSA_set0_crt_params)] // 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: /// ``` /// # use openssl::rsa::RsaPrivateKeyBuilder; /// # fn main() -> Result<(), Box> { /// # let bn = || openssl::bn::BigNum::new().unwrap(); /// # let (n, e, d, p, q, dmp1, dmq1, iqmp) = (bn(), bn(), bn(), bn(), bn(), bn(), bn(), bn()); /// RsaPrivateKeyBuilder::new(n, e, d)? /// .set_factors(p, q)? /// .set_crt_params(dmp1, dmq1, iqmp)? /// .build(); /// # Ok(()) } /// ``` #[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. #[corresponds(RSA_generate_key_ex)] 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. #[corresponds(RSA_generate_key_ex)] 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. #[corresponds(PEM_read_bio_RSAPrivateKey)] private_key_from_pem, /// Deserializes a private key from a PEM-encoded encrypted PKCS#1 RSAPrivateKey structure. #[corresponds(PEM_read_bio_RSAPrivateKey)] 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. #[corresponds(PEM_read_bio_RSAPrivateKey)] private_key_from_pem_callback, Rsa, ffi::PEM_read_bio_RSAPrivateKey } from_der! { /// Decodes a DER-encoded PKCS#1 RSAPrivateKey structure. #[corresponds(d2i_RSAPrivateKey)] 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, boringssl))] { 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.64/src/sha.rs000064400000000000000000000340431046102023000133730ustar 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 openssl_macros::corresponds; 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. #[corresponds(SHA1)] #[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. #[corresponds(SHA224)] #[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. #[corresponds(SHA256)] #[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. #[corresponds(SHA384)] #[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. #[corresponds(SHA512)] #[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. #[corresponds(SHA1_Init)] #[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. #[corresponds(SHA1_Update)] #[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. #[corresponds(SHA1_Final)] #[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. #[corresponds(SHA224_Init)] #[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. #[corresponds(SHA224_Update)] #[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. #[corresponds(SHA224_Final)] #[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. #[corresponds(SHA256_Init)] #[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. #[corresponds(SHA256_Update)] #[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. #[corresponds(SHA256_Final)] #[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. #[corresponds(SHA384_Init)] #[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. #[corresponds(SHA384_Update)] #[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. #[corresponds(SHA384_Final)] #[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. #[corresponds(SHA512_Init)] #[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. #[corresponds(SHA512_Update)] #[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. #[corresponds(SHA512_Final)] #[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.64/src/sign.rs000064400000000000000000000716151046102023000135660ustar 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()); //! ``` #![cfg_attr( not(boringssl), doc = r#"\ 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(any(ossl110, libressl382))] { 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`. pub(crate) 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 Sync for Signer<'_> {} unsafe impl Send for Signer<'_> {} impl Drop for Signer<'_> { 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 Signer<'_> { /// 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<'a, T>(type_: MessageDigest, pkey: &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<'a, T>(pkey: &PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { Self::new_intern(None, pkey) } fn new_intern<'a, T>( type_: Option, pkey: &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/manmaster/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/manmaster/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/manmaster/crypto/EVP_DigestSignFinal.html pub fn len(&self) -> Result { self.len_intern() } #[cfg(all(not(ossl111), not(boringssl), not(libressl370)))] 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(any(ossl111, boringssl, libressl370))] 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/manmaster/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(any(ossl111, boringssl, libressl370))] 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(any(ossl111, boringssl, libressl370))] 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(()) } } /// A type which can be used to verify the integrity and authenticity /// of data given the signature. 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 /// [`Verifier::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/manmaster/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/manmaster/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 [`Verifier::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(any(ossl111, boringssl, libressl370))] 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}; #[cfg(not(boringssl))] 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()); } #[cfg(not(boringssl))] fn test_hmac(ty: MessageDigest, tests: &[(Vec, Vec, Vec)]) { for (key, data, 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] fn hmac_sha1() { // test vectors from RFC 2202 let tests: [(Vec, Vec, Vec); 7] = [ ( iter::repeat(0x0b_u8).take(20).collect(), b"Hi There".to_vec(), Vec::from_hex("b617318655057264e28bc0b6fb378c8ef146be00").unwrap(), ), ( b"Jefe".to_vec(), b"what do ya want for nothing?".to_vec(), Vec::from_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79").unwrap(), ), ( iter::repeat(0xaa_u8).take(20).collect(), iter::repeat(0xdd_u8).take(50).collect(), Vec::from_hex("125d7342b9ac11cd91a39af48aa17b4f63f175d3").unwrap(), ), ( Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(), iter::repeat(0xcd_u8).take(50).collect(), Vec::from_hex("4c9007f4026250c6bc8414f9bf50c86c2d7235da").unwrap(), ), ( iter::repeat(0x0c_u8).take(20).collect(), b"Test With Truncation".to_vec(), Vec::from_hex("4c1a03424b55e07fe7f27be1d58bb9324a9a5a04").unwrap(), ), ( iter::repeat(0xaa_u8).take(80).collect(), b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(), Vec::from_hex("aa4ae5e15272d00e95705637ce8a3b55ed402112").unwrap(), ), ( iter::repeat(0xaa_u8).take(80).collect(), b"Test Using Larger Than Block-Size Key \ and Larger Than One Block-Size Data" .to_vec(), Vec::from_hex("e8e99d0f45237d786d6bbaa7965c7808bbff1a91").unwrap(), ), ]; test_hmac(MessageDigest::sha1(), &tests); } #[test] #[cfg(ossl110)] fn test_cmac() { let cipher = 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(any(ossl111, boringssl, libressl370))] 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.64/src/srtp.rs000064400000000000000000000044611046102023000136110ustar 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) {} 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 as c_ulong); pub const SRTP_AES128_CM_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_CM_SHA1_32 as c_ulong); pub const SRTP_AES128_F8_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_80 as c_ulong); pub const SRTP_AES128_F8_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_AES128_F8_SHA1_32 as c_ulong); pub const SRTP_NULL_SHA1_80: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_80 as c_ulong); pub const SRTP_NULL_SHA1_32: SrtpProfileId = SrtpProfileId(ffi::SRTP_NULL_SHA1_32 as c_ulong); #[cfg(any(boringssl, ossl110))] pub const SRTP_AEAD_AES_128_GCM: SrtpProfileId = SrtpProfileId(ffi::SRTP_AEAD_AES_128_GCM as c_ulong); #[cfg(any(boringssl, ossl110))] pub const SRTP_AEAD_AES_256_GCM: SrtpProfileId = SrtpProfileId(ffi::SRTP_AEAD_AES_256_GCM as c_ulong); /// 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.64/src/ssl/bio.rs000064400000000000000000000201051046102023000141640ustar 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()); let _ = 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__fixed_rust(method.0, Some(bwrite::)))?; cvt(ffi::BIO_meth_set_read__fixed_rust(method.0, Some(bread::)))?; cvt(ffi::BIO_meth_set_puts__fixed_rust(method.0, Some(bputs::)))?; cvt(ffi::BIO_meth_set_ctrl__fixed_rust(method.0, Some(ctrl::)))?; cvt(ffi::BIO_meth_set_create__fixed_rust(method.0, Some(create)))?; cvt(ffi::BIO_meth_set_destroy__fixed_rust(method.0, Some(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 { let _ = 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.64/src/ssl/callbacks.rs000064400000000000000000000475761046102023000153570ustar 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); #[allow(clippy::unnecessary_cast)] 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. #[allow(clippy::unnecessary_cast)] 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; #[allow(clippy::unnecessary_cast)] 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, boringssl))] { 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; #[allow(clippy::unnecessary_cast)] 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; #[allow(clippy::unnecessary_cast)] 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; #[allow(clippy::unnecessary_cast)] let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len); (*callback)(ssl, slice) as c_int } #[cfg(not(boringssl))] 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. #[allow(clippy::unnecessary_cast)] 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(not(boringssl))] cfg_if! { if #[cfg(any(ossl110, libressl280))] { type CookiePtr = *const c_uchar; } else { type CookiePtr = *mut c_uchar; } } #[cfg(not(boringssl))] 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; #[allow(clippy::unnecessary_cast)] 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, _: *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); #[allow(clippy::unnecessary_cast)] let slice = slice::from_raw_parts(input as *const u8, inlen); 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.64/src/ssl/connector.rs000064400000000000000000000564321046102023000154210ustar 00000000000000use cfg_if::cfg_if; use std::io::{Read, Write}; use std::ops::{Deref, DerefMut}; use crate::dh::Dh; use crate::error::ErrorStack; #[cfg(any(ossl111, libressl340))] use crate::ssl::SslVersion; use crate::ssl::{ HandshakeError, Ssl, SslContext, SslContextBuilder, SslContextRef, SslMethod, SslMode, SslOptions, SslRef, SslStream, SslVerifyMode, }; use crate::version; use std::net::IpAddr; 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)?; cfg_if! { if #[cfg(not(boringssl))] { 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 (if it is not an IP address) and hostname verification if enabled. pub fn into_ssl(mut self, domain: &str) -> Result { if self.sni && domain.parse::().is_err() { 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(any(ossl111, libressl340))] 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 LibreSSL 3.4.0 or newer. /// /// [docs]: https://wiki.mozilla.org/Security/Server_Side_TLS #[cfg(any(ossl111, libressl340))] pub fn mozilla_modern_v5(method: SslMethod) -> Result { let mut ctx = ctx(method)?; ctx.set_min_proto_version(Some(SslVersion::TLS1_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(any(ossl111, libressl340))] 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(any(ossl111, libressl340))] 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.64/src/ssl/error.rs000064400000000000000000000131741046102023000145540ustar 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.64/src/ssl/mod.rs000064400000000000000000004645311046102023000142110ustar 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 */ } //! } //! } //! ``` #[cfg(ossl300)] use crate::cvt_long; 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(any(ossl110, libressl270))] use crate::nid::Nid; use crate::pkey::{HasPrivate, PKeyRef, Params, Private}; #[cfg(ossl300)] use crate::pkey::{PKey, Public}; use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; use crate::ssl::error::InnerError; use crate::stack::{Stack, StackRef, Stackable}; use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; #[cfg(any(ossl102, boringssl, libressl261))] use crate::x509::verify::X509VerifyParamRef; use crate::x509::{X509Name, X509Ref, X509StoreContextRef, X509VerifyResult, X509}; use crate::{cvt, cvt_n, cvt_p, init}; 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 openssl_macros::corresponds; use std::any::TypeId; 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, MaybeUninit}; 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}; 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. #[corresponds(OPENSSL_cipher_name)] #[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 if #[cfg(boringssl)] { type SslOptionsRepr = u32; } else { type SslOptionsRepr = libc::c_ulong; } } bitflags! { /// Options controlling the behavior of an `SslContext`. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] 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 as SslOptionsRepr; /// A "reasonable default" set of options which enables compatibility flags. #[cfg(not(boringssl))] const ALL = ffi::SSL_OP_ALL as SslOptionsRepr; /// Do not query the MTU. /// /// Only affects DTLS connections. const NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU as SslOptionsRepr; /// 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 #[cfg(not(boringssl))] const COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE as SslOptionsRepr; /// Disables the use of session tickets for session resumption. const NO_TICKET = ffi::SSL_OP_NO_TICKET as SslOptionsRepr; /// Always start a new session when performing a renegotiation on the server side. #[cfg(not(boringssl))] const NO_SESSION_RESUMPTION_ON_RENEGOTIATION = ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION as SslOptionsRepr; /// Disables the use of TLS compression. #[cfg(not(boringssl))] const NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION as SslOptionsRepr; /// 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 as SslOptionsRepr; /// 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 as SslOptionsRepr; /// 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 as SslOptionsRepr; /// 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 as SslOptionsRepr; /// Disables version rollback attach detection. const TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG as SslOptionsRepr; /// Disables the use of SSLv2. const NO_SSLV2 = ffi::SSL_OP_NO_SSLv2 as SslOptionsRepr; /// Disables the use of SSLv3. const NO_SSLV3 = ffi::SSL_OP_NO_SSLv3 as SslOptionsRepr; /// Disables the use of TLSv1.0. const NO_TLSV1 = ffi::SSL_OP_NO_TLSv1 as SslOptionsRepr; /// Disables the use of TLSv1.1. const NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1 as SslOptionsRepr; /// Disables the use of TLSv1.2. const NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2 as SslOptionsRepr; /// Disables the use of TLSv1.3. /// /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. #[cfg(any(boringssl, ossl111, libressl340))] const NO_TLSV1_3 = ffi::SSL_OP_NO_TLSv1_3 as SslOptionsRepr; /// Disables the use of DTLSv1.0 /// /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer. #[cfg(any(boringssl, ossl102, ossl110, libressl332))] const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1 as SslOptionsRepr; /// Disables the use of DTLSv1.2. /// /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer. #[cfg(any(boringssl, ossl102, ossl110, libressl332))] const NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2 as SslOptionsRepr; /// 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 as SslOptionsRepr; /// Disallow all renegotiation in TLSv1.2 and earlier. /// /// Requires OpenSSL 1.1.0h or newer. #[cfg(any(boringssl, ossl110h))] const NO_RENEGOTIATION = ffi::SSL_OP_NO_RENEGOTIATION as SslOptionsRepr; /// 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 as SslOptionsRepr; /// Prioritize ChaCha ciphers when preferred by clients. /// /// Temporarily reprioritize ChaCha20-Poly1305 ciphers to the top of the server cipher list /// if a ChaCha20-Poly1305 cipher is at the top of the client cipher list. This helps those /// clients (e.g. mobile) use ChaCha20-Poly1305 if that cipher is anywhere in the server /// cipher list; but still allows other clients to use AES and other ciphers. /// /// Requires enable [`SslOptions::CIPHER_SERVER_PREFERENCE`]. /// Requires OpenSSL 1.1.1 or newer. /// /// [`SslOptions::CIPHER_SERVER_PREFERENCE`]: struct.SslOptions.html#associatedconstant.CIPHER_SERVER_PREFERENCE #[cfg(ossl111)] const PRIORITIZE_CHACHA = ffi::SSL_OP_PRIORITIZE_CHACHA as SslOptionsRepr; } } bitflags! { /// Options controlling the behavior of an `SslContext`. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pub struct SslMode: SslBitType { /// 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 /// non-blocking 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. #[corresponds(TLS_method)] pub fn tls() -> SslMethod { unsafe { SslMethod(TLS_method()) } } /// Support all versions of the DTLS protocol. #[corresponds(DTLS_method)] pub fn dtls() -> SslMethod { unsafe { SslMethod(DTLS_method()) } } /// Support all versions of the TLS protocol, explicitly as a client. #[corresponds(TLS_client_method)] pub fn tls_client() -> SslMethod { unsafe { SslMethod(TLS_client_method()) } } /// Support all versions of the TLS protocol, explicitly as a server. #[corresponds(TLS_server_method)] 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. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] 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; } } #[cfg(boringssl)] type SslBitType = c_int; #[cfg(not(boringssl))] type SslBitType = c_long; #[cfg(boringssl)] type SslTimeTy = u64; #[cfg(not(boringssl))] type SslTimeTy = c_long; bitflags! { /// Options controlling the behavior of session caching. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pub struct SslSessionCacheMode: SslBitType { /// 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. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] 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() { let _ = 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(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 BoringSSL or OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. #[cfg(any(ossl111, libressl340, boringssl))] pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION); /// DTLSv1.0 /// /// DTLS 1.0 corresponds to TLS 1.1. pub const DTLS1: SslVersion = SslVersion(ffi::DTLS1_VERSION); /// DTLSv1.2 /// /// DTLS 1.2 corresponds to TLS 1.2 to harmonize versions. There was never a DTLS 1.1. #[cfg(any(ossl102, libressl332, boringssl))] pub const DTLS1_2: SslVersion = SslVersion(ffi::DTLS1_2_VERSION); } cfg_if! { if #[cfg(boringssl)] { type SslCacheTy = i64; type SslCacheSize = libc::c_ulong; type MtuTy = u32; type SizeTy = usize; } else { type SslCacheTy = i64; type SslCacheSize = c_long; type MtuTy = c_long; type SizeTy = u32; } } /// 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. /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos #[corresponds(SSL_select_next_proto)] 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`. #[corresponds(SSL_CTX_new)] 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. #[corresponds(SSL_CTX_set_verify)] 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. #[corresponds(SSL_CTX_set_verify)] 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` #[corresponds(SSL_CTX_set_tlsext_servername_callback)] // 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); #[cfg(boringssl)] ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(raw_sni::)); #[cfg(not(boringssl))] ffi::SSL_CTX_set_tlsext_servername_callback__fixed_rust( self.as_ptr(), Some(raw_sni::), ); } } /// Sets the certificate verification depth. /// /// If the peer's certificate chain is longer than this value, verification will fail. #[corresponds(SSL_CTX_set_verify_depth)] 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. #[corresponds(SSL_CTX_set0_verify_cert_store)] #[cfg(ossl102)] 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. #[corresponds(SSL_CTX_set_cert_store)] 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. #[corresponds(SSL_CTX_set_read_ahead)] pub fn set_read_ahead(&mut self, read_ahead: bool) { unsafe { ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as SslBitType); } } /// Sets the mode used by the context, returning the previous mode. #[corresponds(SSL_CTX_set_mode)] pub fn set_mode(&mut self, mode: SslMode) -> SslMode { unsafe { let bits = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits() as MtuTy) as SslBitType; SslMode::from_bits_retain(bits) } } /// Sets the parameters to be used during ephemeral Diffie-Hellman key exchange. #[corresponds(SSL_CTX_set_tmp_dh)] 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. #[corresponds(SSL_CTX_set_tmp_dh_callback)] 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); #[cfg(not(boringssl))] ffi::SSL_CTX_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh::)); #[cfg(boringssl)] ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh::)); } } /// Sets the parameters to be used during ephemeral elliptic curve Diffie-Hellman key exchange. #[corresponds(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. #[corresponds(SSL_CTX_set_tmp_ecdh_callback)] #[cfg(all(ossl101, not(ossl110)))] #[deprecated(note = "this function leaks memory and does not exist on newer OpenSSL versions")] 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__fixed_rust(self.as_ptr(), Some(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. #[corresponds(SSL_CTX_set_default_verify_paths)] 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. #[corresponds(SSL_CTX_load_verify_locations)] 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. #[corresponds(SSL_CTX_set_client_CA_list)] 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. #[corresponds(SSL_CTX_add_client_CA)] 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. #[corresponds(SSL_CTX_set_session_id_context)] 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 SizeTy, )) .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. #[corresponds(SSL_CTX_use_certificate_file)] 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. #[corresponds(SSL_CTX_use_certificate_chain_file)] 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. #[corresponds(SSL_CTX_use_certificate)] 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. #[corresponds(SSL_CTX_add_extra_chain_cert)] 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. #[corresponds(SSL_CTX_use_PrivateKey_file)] 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. #[corresponds(SSL_CTX_use_PrivateKey)] 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. /// /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html #[corresponds(SSL_CTX_set_cipher_list)] 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 cipher suite names separated by `:` characters in order of /// preference. /// /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. #[corresponds(SSL_CTX_set_ciphersuites)] #[cfg(any(ossl111, libressl340))] 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. #[corresponds(SSL_CTX_set_ecdh_auto)] #[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. /// /// # Note /// /// This *enables* the specified options, but does not disable unspecified options. Use /// `clear_options` for that. #[corresponds(SSL_CTX_set_options)] pub fn set_options(&mut self, option: SslOptions) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) } as SslOptionsRepr; SslOptions::from_bits_retain(bits) } /// Returns the options used by the context. #[corresponds(SSL_CTX_get_options)] pub fn options(&self) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) } as SslOptionsRepr; SslOptions::from_bits_retain(bits) } /// Clears the options used by the context, returning the old set. #[corresponds(SSL_CTX_clear_options)] pub fn clear_options(&mut self, option: SslOptions) -> SslOptions { let bits = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) } as SslOptionsRepr; SslOptions::from_bits_retain(bits) } /// Sets the minimum supported protocol version. /// /// A value of `None` will enable protocol versions down to the lowest version supported by /// OpenSSL. /// /// Requires BoringSSL or OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. #[corresponds(SSL_CTX_set_min_proto_version)] #[cfg(any(ossl110, libressl261, boringssl))] 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 up to the highest version supported by /// OpenSSL. /// /// Requires BoringSSL or OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. #[corresponds(SSL_CTX_set_max_proto_version)] #[cfg(any(ossl110, libressl261, boringssl))] 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 to the lowest version supported by /// OpenSSL are enabled. /// /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. #[corresponds(SSL_CTX_get_min_proto_version)] #[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 up to the highest version supported by /// OpenSSL are enabled. /// /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. #[corresponds(SSL_CTX_get_max_proto_version)] #[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. /// /// Requires BoringSSL or OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. #[corresponds(SSL_CTX_set_alpn_protos)] #[cfg(any(ossl102, libressl261, boringssl))] 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 _, ); // 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. #[corresponds(SSL_CTX_set_tlsext_use_srtp)] 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. /// /// 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 #[corresponds(SSL_CTX_set_alpn_select_cb)] #[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__fixed_rust( self.as_ptr(), Some(callbacks::raw_alpn_select::), ptr::null_mut(), ); } } /// Checks for consistency between the private key and certificate. #[corresponds(SSL_CTX_check_private_key)] 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. #[corresponds(SSL_CTX_get_cert_store)] 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. #[corresponds(SSL_CTX_get_cert_store)] 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 BoringSSL or OpenSSL 1.0.2 or newer. #[corresponds(SSL_CTX_get0_param)] #[cfg(any(ossl102, boringssl, 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 BoringSSL or OpenSSL 1.0.2 or newer. #[corresponds(SSL_CTX_get0_param)] #[cfg(any(ossl102, boringssl, 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 responsible 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. #[corresponds(SSL_CTX_set_tlsext_status_cb)] 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. #[corresponds(SSL_CTX_set_psk_client_callback)] #[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. #[corresponds(SSL_CTX_set_psk_server_callback)] #[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. /// /// [`SslRef::session`]: struct.SslRef.html#method.session /// [`set_session_cache_mode`]: #method.set_session_cache_mode #[corresponds(SSL_CTX_sess_set_new_cb)] 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. #[corresponds(SSL_CTX_sess_set_remove_cb)] 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. /// /// # Safety /// /// The returned `SslSession` must not be associated with a different `SslContext`. #[corresponds(SSL_CTX_sess_set_get_cb)] 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. #[corresponds(SSL_CTX_set_keylog_callback)] #[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. #[corresponds(SSL_CTX_set_session_cache_mode)] 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::from_bits_retain(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. #[corresponds(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. #[corresponds(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. #[corresponds(SSL_CTX_set_cookie_generate_cb)] #[cfg(not(boringssl))] 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. #[corresponds(SSL_CTX_set_cookie_verify_cb)] #[cfg(not(boringssl))] 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`. // FIXME should return a result #[corresponds(SSL_CTX_set_ex_data)] 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 { match self.ex_data_mut(index) { Some(v) => { *v = data; (v as *mut T).cast() } _ => 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 }, } } fn ex_data_mut(&mut self, index: Index) -> Option<&mut T> { unsafe { let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw()); if data.is_null() { None } else { Some(&mut *data.cast()) } } } /// Adds a custom extension for a TLS/DTLS client or server for all supported protocol versions. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(SSL_CTX_add_custom_ext)] #[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 LibreSSL 3.4.0 or newer. #[corresponds(SSL_CTX_set_max_early_data)] #[cfg(any(ossl111, libressl340))] 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. #[corresponds(SSL_CTX_set_client_hello_cb)] #[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. #[corresponds(SSL_CTX_sess_set_cache_size)] #[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 as SslCacheSize) as SslCacheTy } } /// Sets the context's supported signature algorithms. /// /// Requires OpenSSL 1.0.2 or newer. #[corresponds(SSL_CTX_set1_sigalgs_list)] #[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. /// /// Requires BoringSSL or OpenSSL 1.1.1 or LibreSSL 2.5.1 or newer. #[corresponds(SSL_CTX_set1_groups_list)] #[cfg(any(ossl111, boringssl, libressl251))] 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(|_| ()) } } /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full /// handshake. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(SSL_CTX_set_num_tickets)] #[cfg(ossl111)] pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) } } /// Set the context's security level to a value between 0 and 5, inclusive. /// A security value of 0 allows allows all parameters and algorithms. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(SSL_CTX_set_security_level)] #[cfg(any(ossl110, libressl360))] pub fn set_security_level(&mut self, level: u32) { unsafe { ffi::SSL_CTX_set_security_level(self.as_ptr(), level as c_int) } } /// 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. #[corresponds(SSL_CTX_get_ex_new_index)] pub fn new_ex_index() -> Result, ErrorStack> where T: 'static + Sync + Send, { unsafe { ffi::init(); #[cfg(boringssl)] let idx = cvt_n(get_new_idx(Some(free_data_box::)))?; #[cfg(not(boringssl))] 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 LibreSSL 2.7.0 or newer. #[corresponds(SSL_CTX_get0_certificate)] #[cfg(any(ossl102, libressl270))] 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 LibreSSL 3.4.0 or newer. #[corresponds(SSL_CTX_get0_privatekey)] #[cfg(any(ossl102, libressl340))] 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. #[corresponds(SSL_CTX_get_cert_store)] 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. #[corresponds(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. #[corresponds(SSL_CTX_get_ex_data)] 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 LibreSSL 3.4.0 or newer. #[corresponds(SSL_CTX_get_max_early_data)] #[cfg(any(ossl111, libressl340))] 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. /// /// # Safety /// /// The caller of this method is responsible for ensuring that the session has never been used with another /// `SslContext` than this one. #[corresponds(SSL_CTX_add_session)] 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. /// /// # Safety /// /// The caller of this method is responsible for ensuring that the session has never been used with another /// `SslContext` than this one. #[corresponds(SSL_CTX_remove_session)] 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. #[corresponds(SSL_CTX_sess_get_cache_size)] #[allow(clippy::unnecessary_cast)] pub fn session_cache_size(&self) -> i64 { unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()) as i64 } } /// Returns the verify mode that was set on this context from [`SslContextBuilder::set_verify`]. /// /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify #[corresponds(SSL_CTX_get_verify_mode)] 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") } /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full /// handshake. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(SSL_CTX_get_num_tickets)] #[cfg(ossl111)] pub fn num_tickets(&self) -> usize { unsafe { ffi::SSL_CTX_get_num_tickets(self.as_ptr()) } } /// Get the context's security level, which controls the allowed parameters /// and algorithms. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(SSL_CTX_get_security_level)] #[cfg(any(ossl110, libressl360))] pub fn security_level(&self) -> u32 { unsafe { ffi::SSL_CTX_get_security_level(self.as_ptr()) as u32 } } } /// 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 Stackable for SslCipher { type StackType = ffi::stack_st_SSL_CIPHER; } 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. #[corresponds(SSL_CIPHER_get_name)] 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. #[corresponds(SSL_CIPHER_standard_name)] #[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. #[corresponds(SSL_CIPHER_get_version)] 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. #[corresponds(SSL_CIPHER_get_bits)] #[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. #[corresponds(SSL_CIPHER_description)] 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. #[corresponds(SSL_CIPHER_get_handshake_digest)] #[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 LibreSSL 2.7.0 or newer. #[corresponds(SSL_CIPHER_get_cipher_nid)] #[cfg(any(ossl110, libressl270))] 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)) } } } impl fmt::Debug for SslCipherRef { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { write!(fmt, "{}", self.name()) } } /// A stack of selected ciphers, and a stack of selected signalling cipher suites #[derive(Debug)] pub struct CipherLists { pub suites: Stack, pub signalling_suites: Stack, } 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. #[corresponds(d2i_SSL_SESSION)] 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. #[corresponds(SSL_SESSION_get_id)] pub fn id(&self) -> &[u8] { unsafe { let mut len = 0; let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len); #[allow(clippy::unnecessary_cast)] slice::from_raw_parts(p as *const u8, len as usize) } } /// Returns the length of the master key. #[corresponds(SSL_SESSION_get_master_key)] 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. #[corresponds(SSL_SESSION_get_master_key)] 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 LibreSSL 3.4.0 or newer. #[corresponds(SSL_SESSION_get_max_early_data)] #[cfg(any(ossl111, libressl340))] 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. #[corresponds(SSL_SESSION_get_time)] #[allow(clippy::useless_conversion)] pub fn time(&self) -> SslTimeTy { unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()) } } /// Returns the sessions timeout, in seconds. /// /// A session older than this time should not be used for session resumption. #[corresponds(SSL_SESSION_get_timeout)] #[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 LibreSSL 2.7.0 or newer. #[corresponds(SSL_SESSION_get_protocol_version)] #[cfg(any(ossl110, libressl270))] 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. #[corresponds(i2d_SSL_SESSION)] 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. #[corresponds(SSL_get_ex_new_index)] pub fn new_ex_index() -> Result, ErrorStack> where T: 'static + Sync + Send, { unsafe { ffi::init(); #[cfg(boringssl)] let idx = cvt_n(get_new_ssl_idx(Some(free_data_box::)))?; #[cfg(not(boringssl))] 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/manmaster/ssl/SSL_new.html #[corresponds(SSL_new)] 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 #[corresponds(SSL_connect)] #[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 #[corresponds(SSL_accept)] #[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 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. #[corresponds(SSL_set_connect_state)] pub fn set_connect_state(&mut self) { unsafe { ffi::SSL_set_connect_state(self.as_ptr()) } } /// Configure as an incoming stream to a server. #[corresponds(SSL_set_accept_state)] pub fn set_accept_state(&mut self) { unsafe { ffi::SSL_set_accept_state(self.as_ptr()) } } /// Like [`SslContextBuilder::set_verify`]. /// /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify #[corresponds(SSL_set_verify)] 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`. #[corresponds(SSL_set_verify_mode)] 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`]. /// /// [`SslContextBuilder::set_verify_callback`]: struct.SslContextBuilder.html#method.set_verify_callback #[corresponds(SSL_set_verify)] 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`]. /// /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh #[corresponds(SSL_set_tmp_dh)] 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`]. /// /// [`SslContextBuilder::set_tmp_dh_callback`]: struct.SslContextBuilder.html#method.set_tmp_dh_callback #[corresponds(SSL_set_tmp_dh_callback)] 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)); #[cfg(boringssl)] ffi::SSL_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh_ssl::)); #[cfg(not(boringssl))] ffi::SSL_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh_ssl::)); } } /// Like [`SslContextBuilder::set_tmp_ecdh`]. /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh #[corresponds(SSL_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. #[corresponds(SSL_set_tmp_ecdh_callback)] #[cfg(all(ossl101, not(ossl110)))] #[deprecated(note = "this function leaks memory and does not exist on newer OpenSSL versions")] 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__fixed_rust(self.as_ptr(), Some(raw_tmp_ecdh_ssl::)); } } /// Like [`SslContextBuilder::set_ecdh_auto`]. /// /// Requires OpenSSL 1.0.2 or LibreSSL. /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh #[corresponds(SSL_set_ecdh_auto)] #[cfg(any(all(ossl102, not(ossl110)), libressl))] 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 BoringSSL or OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos #[corresponds(SSL_set_alpn_protos)] #[cfg(any(ossl102, libressl261, boringssl))] 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 _); // 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. #[corresponds(SSL_get_current_cipher)] 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. #[corresponds(SSL_state_string)] 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. #[corresponds(SSL_state_string_long)] 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. #[corresponds(SSL_set_tlsext_host_name)] 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. #[corresponds(SSL_get_peer_certificate)] 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! #[corresponds(SSL_get_peer_cert_chain)] 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. /// /// [`verify_result`]: #method.verify_result /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK #[corresponds(SSL_get0_verified_chain)] #[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`]. #[corresponds(SSL_get_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`]. /// /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key #[corresponds(SSL_get_privatekey)] 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. #[corresponds(SSL_version)] 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. #[corresponds(SSL_get_version)] 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 BoringSSL or OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. #[corresponds(SSL_get0_alpn_selected)] #[cfg(any(ossl102, libressl261, boringssl))] 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 #[corresponds(SSL_set_tlsext_use_srtp)] 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 #[corresponds(SSL_get_srtp_profiles)] 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. #[corresponds(SSL_get_selected_srtp_profile)] 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. #[corresponds(SSL_pending)] 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. /// /// # 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 #[corresponds(SSL_get_servername)] // 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. /// /// # Note /// /// Unlike `servername`, this method does not require the name be valid UTF-8. #[corresponds(SSL_get_servername)] 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. #[corresponds(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. #[corresponds(SSL_get_SSL_CTX)] 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 BoringSSL or OpenSSL 1.0.2 or newer. #[corresponds(SSL_get0_param)] #[cfg(any(ossl102, boringssl, 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. #[corresponds(SSL_get_verify_result)] 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. #[corresponds(SSL_get_session)] 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 LibreSSL 2.7.0 or newer. #[corresponds(SSL_get_client_random)] #[cfg(any(ossl110, libressl270))] 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 LibreSSL 2.7.0 or newer. #[corresponds(SSL_get_server_random)] #[cfg(any(ossl110, libressl270))] 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. #[corresponds(SSL_export_keying_material)] 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. #[corresponds(SSL_export_keying_material_early)] #[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. /// /// # Safety /// /// The caller of this method is responsible for ensuring that the session is associated /// with the same `SslContext` as this `Ssl`. #[corresponds(SSL_set_session)] 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. #[corresponds(SSL_session_reused)] 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. #[corresponds(SSL_set_tlsext_status_type)] 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(|_| ()) } } /// Determines if current session used Extended Master Secret /// /// Returns `None` if the handshake is still in-progress. #[corresponds(SSL_get_extms_support)] #[cfg(ossl110)] pub fn extms_support(&self) -> Option { unsafe { match ffi::SSL_get_extms_support(self.as_ptr()) { -1 => None, ret => Some(ret != 0), } } } /// Returns the server's OCSP response, if present. #[corresponds(SSL_get_tlsext_status_ocsp_resp)] #[cfg(not(boringssl))] 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. #[corresponds(SSL_set_tlsext_status_oscp_resp)] #[cfg(not(boringssl))] 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::OPENSSL_malloc(response.len() as _))?; 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(|_| ()) .map_err(|e| { ffi::OPENSSL_free(p); e }) } } /// Determines if this `Ssl` is configured for server-side or client-side use. #[corresponds(SSL_is_server)] 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`. // FIXME should return a result #[corresponds(SSL_set_ex_data)] pub fn set_ex_data(&mut self, index: Index, data: T) { match self.ex_data_mut(index) { Some(v) => *v = data, None => 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. #[corresponds(SSL_get_ex_data)] 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. #[corresponds(SSL_get_ex_data)] 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 LibreSSL 3.4.0 or newer. #[corresponds(SSL_set_max_early_data)] #[cfg(any(ossl111, libressl340))] 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 LibreSSL 3.4.0 or newer. #[corresponds(SSL_get_max_early_data)] #[cfg(any(ossl111, libressl340))] 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. #[corresponds(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. #[corresponds(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. #[corresponds(SSL_is_init_finished)] #[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. #[corresponds(SSL_client_hello_isv2)] #[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. #[corresponds(SSL_client_hello_get0_legacy_version)] #[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. #[corresponds(SSL_client_hello_get0_random)] #[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. #[corresponds(SSL_client_hello_get0_session_id)] #[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. #[corresponds(SSL_client_hello_get0_ciphers)] #[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)) } } } /// Decodes a slice of wire-format cipher suite specification bytes. Unsupported cipher suites /// are ignored. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(SSL_bytes_to_cipher_list)] #[cfg(ossl111)] pub fn bytes_to_cipher_list( &self, bytes: &[u8], isv2format: bool, ) -> Result { unsafe { let ptr = bytes.as_ptr(); let len = bytes.len(); let mut sk = ptr::null_mut(); let mut scsvs = ptr::null_mut(); let res = ffi::SSL_bytes_to_cipher_list( self.as_ptr(), ptr, len, isv2format as c_int, &mut sk, &mut scsvs, ); if res == 1 { Ok(CipherLists { suites: Stack::from_ptr(sk), signalling_suites: Stack::from_ptr(scsvs), }) } else { Err(ErrorStack::get()) } } } /// 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. #[corresponds(SSL_client_hello_get0_compression_methods)] #[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. #[corresponds(SSL_set_mtu)] pub fn set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_mtu(self.as_ptr(), mtu as MtuTy) as c_int).map(|_| ()) } } /// Returns the PSK identity hint used during connection setup. /// /// May return `None` if no PSK identity hint was used during the connection setup. #[corresponds(SSL_get_psk_identity_hint)] #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub fn psk_identity_hint(&self) -> Option<&[u8]> { unsafe { let ptr = ffi::SSL_get_psk_identity_hint(self.as_ptr()); if ptr.is_null() { None } else { Some(CStr::from_ptr(ptr).to_bytes()) } } } /// Returns the PSK identity used during connection setup. #[corresponds(SSL_get_psk_identity)] #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub fn psk_identity(&self) -> Option<&[u8]> { unsafe { let ptr = ffi::SSL_get_psk_identity(self.as_ptr()); if ptr.is_null() { None } else { Some(CStr::from_ptr(ptr).to_bytes()) } } } #[corresponds(SSL_add0_chain_cert)] #[cfg(ossl102)] pub fn add_chain_cert(&mut self, chain: X509) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_add0_chain_cert(self.as_ptr(), chain.as_ptr()) as c_int).map(|_| ())?; mem::forget(chain); } Ok(()) } /// Sets a new default TLS/SSL method for SSL objects #[cfg(not(boringssl))] pub fn set_method(&mut self, method: SslMethod) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_ssl_method(self.as_ptr(), method.as_ptr()))?; }; Ok(()) } /// Loads the private key from a file. #[corresponds(SSL_use_Private_Key_file)] pub fn set_private_key_file>( &mut self, path: P, ssl_file_type: SslFiletype, ) -> Result<(), ErrorStack> { let p = path.as_ref().as_os_str().to_str().unwrap(); let key_file = CString::new(p).unwrap(); unsafe { cvt(ffi::SSL_use_PrivateKey_file( self.as_ptr(), key_file.as_ptr(), ssl_file_type.as_raw(), ))?; }; Ok(()) } /// Sets the private key. #[corresponds(SSL_use_PrivateKey)] pub fn set_private_key(&mut self, pkey: &PKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_use_PrivateKey(self.as_ptr(), pkey.as_ptr()))?; }; Ok(()) } /// Sets the certificate #[corresponds(SSL_use_certificate)] pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?; }; Ok(()) } /// 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. #[corresponds(SSL_use_certificate_chain_file)] #[cfg(any(ossl110, libressl332))] pub fn set_certificate_chain_file>( &mut self, path: P, ) -> Result<(), ErrorStack> { let p = path.as_ref().as_os_str().to_str().unwrap(); let cert_file = CString::new(p).unwrap(); unsafe { cvt(ffi::SSL_use_certificate_chain_file( self.as_ptr(), cert_file.as_ptr(), ))?; }; Ok(()) } /// Sets ca certificate that client trusted #[corresponds(SSL_add_client_CA)] pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_add_client_CA(self.as_ptr(), cacert.as_ptr()))?; }; Ok(()) } // Sets the list of CAs sent to the client when requesting a client certificate for the chosen ssl #[corresponds(SSL_set_client_CA_list)] pub fn set_client_ca_list(&mut self, list: Stack) { unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) } mem::forget(list); } /// Sets the minimum supported protocol version. /// /// A value of `None` will enable protocol versions down to the lowest version supported by /// OpenSSL. /// /// Requires BoringSSL or OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. #[corresponds(SSL_set_min_proto_version)] #[cfg(any(ossl110, libressl261, boringssl))] pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_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 up to the highest version supported by /// OpenSSL. /// /// Requires BoringSSL or OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. #[corresponds(SSL_set_max_proto_version)] #[cfg(any(ossl110, libressl261, boringssl))] pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_max_proto_version( self.as_ptr(), version.map_or(0, |v| v.0 as _), )) .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 cipher suite names separated by `:` characters in order of /// preference. /// /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. #[corresponds(SSL_set_ciphersuites)] #[cfg(any(ossl111, libressl340))] pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); unsafe { cvt(ffi::SSL_set_ciphersuites( self.as_ptr(), cipher_list.as_ptr() as *const _, )) .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. /// /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html #[corresponds(SSL_set_cipher_list)] pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); unsafe { cvt(ffi::SSL_set_cipher_list( self.as_ptr(), cipher_list.as_ptr() as *const _, )) .map(|_| ()) } } /// Set the certificate store used for certificate verification #[corresponds(SSL_set_cert_store)] #[cfg(ossl102)] pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.as_ptr()) as c_int)?; mem::forget(cert_store); Ok(()) } } /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full /// handshake. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(SSL_set_num_tickets)] #[cfg(ossl111)] pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) } } /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full /// handshake. /// /// Requires OpenSSL 1.1.1 or newer. #[corresponds(SSL_get_num_tickets)] #[cfg(ossl111)] pub fn num_tickets(&self) -> usize { unsafe { ffi::SSL_get_num_tickets(self.as_ptr()) } } /// Set the context's security level to a value between 0 and 5, inclusive. /// A security value of 0 allows allows all parameters and algorithms. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(SSL_set_security_level)] #[cfg(any(ossl110, libressl360))] pub fn set_security_level(&mut self, level: u32) { unsafe { ffi::SSL_set_security_level(self.as_ptr(), level as c_int) } } /// Get the connection's security level, which controls the allowed parameters /// and algorithms. /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(SSL_get_security_level)] #[cfg(any(ossl110, libressl360))] pub fn security_level(&self) -> u32 { unsafe { ffi::SSL_get_security_level(self.as_ptr()) as u32 } } /// Get the temporary key provided by the peer that is used during key /// exchange. // We use an owned value because EVP_KEY free need to be called when it is // dropped #[corresponds(SSL_get_peer_tmp_key)] #[cfg(ossl300)] pub fn peer_tmp_key(&self) -> Result, ErrorStack> { unsafe { let mut key = ptr::null_mut(); match cvt_long(ffi::SSL_get_peer_tmp_key(self.as_ptr(), &mut key)) { Ok(_) => Ok(PKey::::from_ptr(key)), Err(e) => Err(e), } } } /// Returns the temporary key from the local end of the connection that is /// used during key exchange. // We use an owned value because EVP_KEY free need to be called when it is // dropped #[corresponds(SSL_get_tmp_key)] #[cfg(ossl300)] pub fn tmp_key(&self) -> Result, ErrorStack> { unsafe { let mut key = ptr::null_mut(); match cvt_long(ffi::SSL_get_tmp_key(self.as_ptr(), &mut key)) { Ok(_) => Ok(PKey::::from_ptr(key)), Err(e) => Err(e), } } } } /// 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. #[corresponds(SSL_set_bio)] 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 LibreSSL 3.4.0 or newer. #[corresponds(SSL_read_early_data)] #[cfg(any(ossl111, libressl340))] 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 LibreSSL 3.4.0 or newer. #[corresponds(SSL_write_early_data)] #[cfg(any(ossl111, libressl340))] 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) } else { Err(self.make_error(ret)) } } /// Initiates a client-side TLS handshake. /// /// # Warning /// /// OpenSSL's default configuration is insecure. It is highly recommended to use /// `SslConnector` rather than `Ssl` directly, as it manages that configuration. #[corresponds(SSL_connect)] 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. /// /// # Warning /// /// OpenSSL's default configuration is insecure. It is highly recommended to use /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration. #[corresponds(SSL_accept)] 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. #[corresponds(SSL_do_handshake)] 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. #[corresponds(SSL_stateless)] #[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 takes a possibly-uninitialized slice. /// /// # Safety /// /// No portion of `buf` will be de-initialized by this method. If the method returns `Ok(n)`, /// then the first `n` bytes of `buf` are guaranteed to be initialized. #[corresponds(SSL_read_ex)] pub fn read_uninit(&mut self, buf: &mut [MaybeUninit]) -> io::Result { loop { match self.ssl_read_uninit(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))); } } } } /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`. /// /// It is particularly useful with a non-blocking socket, where the error value will identify if /// OpenSSL is waiting on read or write readiness. #[corresponds(SSL_read_ex)] pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { // SAFETY: `ssl_read_uninit` does not de-initialize the buffer. unsafe { self.ssl_read_uninit(slice::from_raw_parts_mut( buf.as_mut_ptr().cast::>(), buf.len(), )) } } /// Like `read_ssl`, but takes a possibly-uninitialized slice. /// /// # Safety /// /// No portion of `buf` will be de-initialized by this method. If the method returns `Ok(n)`, /// then the first `n` bytes of `buf` are guaranteed to be initialized. #[corresponds(SSL_read_ex)] pub fn ssl_read_uninit(&mut self, buf: &mut [MaybeUninit]) -> Result { cfg_if! { if #[cfg(any(ossl111, libressl350))] { let mut readbytes = 0; let ret = unsafe { ffi::SSL_read_ex( self.ssl().as_ptr(), buf.as_mut_ptr().cast(), buf.len(), &mut readbytes, ) }; if ret > 0 { Ok(readbytes) } else { Err(self.make_error(ret)) } } else { if buf.is_empty() { return Ok(0); } let len = usize::min(c_int::max_value() as usize, buf.len()) as c_int; let ret = unsafe { ffi::SSL_read(self.ssl().as_ptr(), buf.as_mut_ptr().cast(), len) }; 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 non-blocking socket, where the error value will identify if /// OpenSSL is waiting on read or write readiness. #[corresponds(SSL_write_ex)] pub fn ssl_write(&mut self, buf: &[u8]) -> Result { cfg_if! { if #[cfg(any(ossl111, libressl350))] { let mut written = 0; let ret = unsafe { ffi::SSL_write_ex( self.ssl().as_ptr(), buf.as_ptr().cast(), buf.len(), &mut written, ) }; if ret > 0 { Ok(written) } else { Err(self.make_error(ret)) } } else { if buf.is_empty() { return Ok(0); } let len = usize::min(c_int::max_value() as usize, buf.len()) as c_int; let ret = unsafe { ffi::SSL_write(self.ssl().as_ptr(), buf.as_ptr().cast(), len) }; if ret > 0 { Ok(ret as usize) } else { Err(self.make_error(ret)) } } } } /// Reads data from the stream, without removing it from the queue. #[corresponds(SSL_peek_ex)] pub fn ssl_peek(&mut self, buf: &mut [u8]) -> Result { cfg_if! { if #[cfg(any(ossl111, libressl350))] { let mut readbytes = 0; let ret = unsafe { ffi::SSL_peek_ex( self.ssl().as_ptr(), buf.as_mut_ptr().cast(), buf.len(), &mut readbytes, ) }; if ret > 0 { Ok(readbytes) } else { Err(self.make_error(ret)) } } else { if buf.is_empty() { return Ok(0); } let len = usize::min(c_int::max_value() as usize, buf.len()) as c_int; let ret = unsafe { ffi::SSL_peek(self.ssl().as_ptr(), buf.as_mut_ptr().cast(), len) }; 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. #[corresponds(SSL_shutdown)] 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. #[corresponds(SSL_get_shutdown)] pub fn get_shutdown(&mut self) -> ShutdownState { unsafe { let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr()); ShutdownState::from_bits_retain(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. #[corresponds(SSL_set_shutdown)] 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 { // SAFETY: `read_uninit` does not de-initialize the buffer unsafe { self.read_uninit(slice::from_raw_parts_mut( buf.as_mut_ptr().cast::>(), buf.len(), )) } } } 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 LibreSSL 3.4.0 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(any(ossl111, libressl340))] 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 LibreSSL 3.4.0 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(any(ossl111, libressl340))] 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. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] 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(boringssl, 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(boringssl, 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(|| { cfg_if! { if #[cfg(not(boringssl))] { ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, None); } else { ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None); } } }); cfg_if! { if #[cfg(not(boringssl))] { ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) } else { ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, 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(|| { #[cfg(not(boringssl))] ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, None); #[cfg(boringssl)] ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None); }); #[cfg(not(boringssl))] return ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)); #[cfg(boringssl)] return ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f); } } } openssl-0.10.64/src/ssl/test/mod.rs000064400000000000000000001410431046102023000151560ustar 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, AtomicUsize, Ordering}; use std::thread; use std::time::Duration; use crate::dh::Dh; use crate::error::ErrorStack; use crate::hash::MessageDigest; #[cfg(not(boringssl))] use crate::ocsp::{OcspResponse, OcspResponseStatus}; use crate::pkey::{Id, PKey}; use crate::srtp::SrtpProfileId; use crate::ssl::test::server::Server; #[cfg(any(ossl110, ossl111, libressl261))] use crate::ssl::SslVersion; use crate::ssl::{self, NameType, SslConnectorBuilder}; #[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() { static CALLED_BACK: AtomicBool = AtomicBool::new(false); let server = Server::builder().build(); let mut client = server.client(); client .ctx() .set_verify_callback(SslVerifyMode::PEER, |_, x509| { CALLED_BACK.store(true, Ordering::SeqCst); assert!(x509.current_cert().is_some()); true }); client.connect(); assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[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() { static CALLED_BACK: AtomicBool = AtomicBool::new(false); 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| { CALLED_BACK.store(true, Ordering::SeqCst); assert!(x509.current_cert().is_some()); true }); client.connect(); assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[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() { static CALLED_BACK: AtomicBool = AtomicBool::new(false); let server = Server::builder().build(); let mut client = server.client(); client .ctx() .set_verify_callback(SslVerifyMode::PEER, |_, x509| { CALLED_BACK.store(true, Ordering::SeqCst); assert!(x509.current_cert().is_some()); true }); client.connect(); assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[test] fn verify_trusted_get_error_ok() { static CALLED_BACK: AtomicBool = AtomicBool::new(false); 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| { CALLED_BACK.store(true, Ordering::SeqCst); assert_eq!(x509.error(), X509VerifyResult::OK); true }); client.connect(); assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[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] #[cfg(not(boringssl))] 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(); #[cfg(not(boringssl))] assert_eq!(s.ssl().state_string().trim(), "SSLOK"); #[cfg(boringssl)] assert_eq!(s.ssl().state_string(), "!!!!!!"); assert_eq!( s.ssl().state_string_long(), "SSL negotiation finished successfully" ); } // when a connection uses ECDHE P-384 key exchange, then the temp key APIs // return P-384 keys, and the peer and local keys are different. #[test] #[cfg(ossl300)] fn peer_tmp_key_p384() { let mut server = Server::builder(); server.ctx().set_groups_list("P-384").unwrap(); let server = server.build(); let s = server.client().connect(); let peer_temp = s.ssl().peer_tmp_key().unwrap(); assert_eq!(peer_temp.id(), Id::EC); assert_eq!(peer_temp.bits(), 384); let local_temp = s.ssl().tmp_key().unwrap(); assert_eq!(local_temp.id(), Id::EC); assert_eq!(local_temp.bits(), 384); assert_ne!( peer_temp.ec_key().unwrap().public_key_to_der().unwrap(), local_temp.ec_key().unwrap().public_key_to_der().unwrap(), ); } // when a connection uses RSA key exchange, then the peer (server) temp key is // an Error because there is no temp key, and the local (client) temp key is the // temp key sent in the initial key share. #[test] #[cfg(ossl300)] fn peer_tmp_key_rsa() { let mut server = Server::builder(); server.ctx().set_cipher_list("RSA").unwrap(); // RSA key exchange is not allowed in TLS 1.3, so force the connection // to negotiate TLS 1.2 server .ctx() .set_max_proto_version(Some(SslVersion::TLS1_2)) .unwrap(); let server = server.build(); let mut client = server.client(); client.ctx().set_groups_list("P-521").unwrap(); let s = client.connect(); let peer_temp = s.ssl().peer_tmp_key(); assert!(peer_temp.is_err()); // this is the temp key that the client sent in the initial key share let local_temp = s.ssl().tmp_key().unwrap(); assert_eq!(local_temp.id(), Id::EC); assert_eq!(local_temp.bits(), 521); } /// 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(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() { static CALLED_BACK: AtomicBool = AtomicBool::new(false); let mut server = Server::builder(); server.ctx().set_alpn_select_callback(|_, client| { CALLED_BACK.store(true, Ordering::SeqCst); 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()); assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[test] #[cfg(any(boringssl, 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(all(libressl321, not(libressl340)), 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(); ssl.set_ssl_context(&new_ctx_a).unwrap(); } } #[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_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() .connect("fizzbuzz.com", s) .unwrap(); s.read_exact(&mut [0]).unwrap(); } #[test] fn connector_does_use_sni_with_dnsnames() { static CALLED_BACK: AtomicBool = AtomicBool::new(false); let mut builder = Server::builder(); builder.ctx().set_servername_callback(|ssl, _| { assert_eq!(ssl.servername(NameType::HOST_NAME), Some("foobar.com")); CALLED_BACK.store(true, Ordering::SeqCst); Ok(()) }); let 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() .connect("foobar.com", s) .unwrap(); s.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); } #[test] fn connector_doesnt_use_sni_with_ips() { static CALLED_BACK: AtomicBool = AtomicBool::new(false); let mut builder = Server::builder(); builder.ctx().set_servername_callback(|ssl, _| { assert_eq!(ssl.servername(NameType::HOST_NAME), None); CALLED_BACK.store(true, Ordering::SeqCst); Ok(()) }); let server = builder.build(); let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); // The server's cert isn't issued for 127.0.0.1 but we don't care for this test. connector.set_verify(SslVerifyMode::NONE); let s = server.connect_tcp(); let mut s = connector .build() .configure() .unwrap() .connect("127.0.0.1", s) .unwrap(); s.read_exact(&mut [0]).unwrap(); assert!(CALLED_BACK.load(Ordering::SeqCst)); } 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(any(ossl111, libressl340))] 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(any(all(libressl321, not(libressl340)), boringssl), 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(any(ossl111, libressl340))] 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)))] #[allow(deprecated)] 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(any(all(libressl321, not(libressl340)), boringssl), 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(any(ossl111, libressl340))] 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)))] #[allow(deprecated)] 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()); } /// LibreSSL 3.2.1 enabled TLSv1.3 by default for clients and sessions do /// not work due to lack of PSK support. The test passes with NO_TLSV1_3, /// but let's ignore it until LibreSSL supports it out of the box. #[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] #[cfg(not(boringssl))] 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)); } /// LibreSSL 3.2.1 enabled TLSv1.3 by default for clients and sessions do /// not work due to lack of PSK support. The test passes with NO_TLSV1_3, /// but let's ignore it until LibreSSL supports it out of the box. #[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)); } /// LibreSSL 3.2.1 enabled TLSv1.3 by default for clients and sessions do /// not work due to lack of PSK support. The test passes with NO_TLSV1_3, /// but let's ignore it until LibreSSL supports it out of the box. #[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-AES256-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(any(boringssl, 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!(SERVER_CALLED.load(Ordering::SeqCst)); assert!(CLIENT_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()); assert!(ssl .bytes_to_cipher_list(ssl.client_hello_ciphers().unwrap(), ssl.client_hello_isv2()) .is_ok()); 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); } #[test] #[cfg(ossl102)] fn add_chain_cert() { let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); let cert = X509::from_pem(CERT).unwrap(); let mut ssl = Ssl::new(&ctx).unwrap(); assert!(ssl.add_chain_cert(cert).is_ok()); } #[test] #[cfg(ossl111)] fn set_ssl_certificate_key_related_api() { let cert_str: &str = include_str!("../../../test/cert.pem"); let key_str: &str = include_str!("../../../test/key.pem"); let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); let cert_x509 = X509::from_pem(CERT).unwrap(); let mut ssl = Ssl::new(&ctx).unwrap(); assert!(ssl.set_method(SslMethod::tls()).is_ok()); ssl.set_private_key_file("test/key.pem", SslFiletype::PEM) .unwrap(); { let pkey = String::from_utf8( ssl.private_key() .unwrap() .private_key_to_pem_pkcs8() .unwrap(), ) .unwrap(); assert!(pkey.lines().eq(key_str.lines())); } let pkey = PKey::private_key_from_pem(KEY).unwrap(); ssl.set_private_key(pkey.as_ref()).unwrap(); { let pkey = String::from_utf8( ssl.private_key() .unwrap() .private_key_to_pem_pkcs8() .unwrap(), ) .unwrap(); assert!(pkey.lines().eq(key_str.lines())); } ssl.set_certificate(cert_x509.as_ref()).unwrap(); let cert = String::from_utf8(ssl.certificate().unwrap().to_pem().unwrap()).unwrap(); assert!(cert.lines().eq(cert_str.lines())); ssl.add_client_ca(cert_x509.as_ref()).unwrap(); ssl.set_min_proto_version(Some(SslVersion::TLS1_2)).unwrap(); ssl.set_max_proto_version(Some(SslVersion::TLS1_3)).unwrap(); ssl.set_cipher_list("HIGH:!aNULL:!MD5").unwrap(); ssl.set_ciphersuites("TLS_AES_128_GCM_SHA256").unwrap(); let x509 = X509::from_pem(ROOT_CERT).unwrap(); let mut builder = X509StoreBuilder::new().unwrap(); builder.add_cert(x509).unwrap(); let store = builder.build(); ssl.set_verify_cert_store(store).unwrap(); } #[test] #[cfg(ossl110)] fn test_ssl_set_cert_chain_file() { let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); let mut ssl = Ssl::new(&ctx).unwrap(); ssl.set_certificate_chain_file("test/cert.pem").unwrap(); } #[test] #[cfg(ossl111)] fn set_num_tickets() { let mut ctx = SslContext::builder(SslMethod::tls_server()).unwrap(); ctx.set_num_tickets(3).unwrap(); let ctx = ctx.build(); assert_eq!(3, ctx.num_tickets()); let mut ssl = Ssl::new(&ctx).unwrap(); ssl.set_num_tickets(5).unwrap(); let ssl = ssl; assert_eq!(5, ssl.num_tickets()); } #[test] #[cfg(ossl110)] fn set_security_level() { let mut ctx = SslContext::builder(SslMethod::tls_server()).unwrap(); ctx.set_security_level(3); let ctx = ctx.build(); assert_eq!(3, ctx.security_level()); let mut ssl = Ssl::new(&ctx).unwrap(); ssl.set_security_level(4); let ssl = ssl; assert_eq!(4, ssl.security_level()); } #[test] fn ssl_ctx_ex_data_leak() { static DROPS: AtomicUsize = AtomicUsize::new(0); struct DropTest; impl Drop for DropTest { fn drop(&mut self) { DROPS.fetch_add(1, Ordering::Relaxed); } } let idx = SslContext::new_ex_index().unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_ex_data(idx, DropTest); ctx.set_ex_data(idx, DropTest); assert_eq!(DROPS.load(Ordering::Relaxed), 1); drop(ctx); assert_eq!(DROPS.load(Ordering::Relaxed), 2); } #[test] fn ssl_ex_data_leak() { static DROPS: AtomicUsize = AtomicUsize::new(0); struct DropTest; impl Drop for DropTest { fn drop(&mut self) { DROPS.fetch_add(1, Ordering::Relaxed); } } let idx = Ssl::new_ex_index().unwrap(); let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); let mut ssl = Ssl::new(&ctx).unwrap(); ssl.set_ex_data(idx, DropTest); ssl.set_ex_data(idx, DropTest); assert_eq!(DROPS.load(Ordering::Relaxed), 1); drop(ssl); assert_eq!(DROPS.load(Ordering::Relaxed), 2); } openssl-0.10.64/src/ssl/test/server.rs000064400000000000000000000075711046102023000157140ustar 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.64/src/stack.rs000064400000000000000000000230011046102023000137150ustar 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, LenType}; 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 LenType, }; 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 LenType, } } pub fn iter_mut(&mut self) -> IterMut<'_, T> { IterMut { idxs: 0..self.len() as LenType, 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 _) as c_int)?; 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 LenType) 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.64/src/string.rs000064400000000000000000000036541046102023000141320ustar 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) } } #[inline] #[cfg(not(boringssl))] unsafe fn free(buf: *mut c_char) { ffi::OPENSSL_free(buf as *mut c_void); } #[inline] #[cfg(boringssl)] 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.64/src/symm.rs000064400000000000000000001641301046102023000136060ustar 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 crate::cipher::CipherRef; use crate::cipher_ctx::{CipherCtx, CipherCtxRef}; use crate::error::ErrorStack; use crate::nid::Nid; use cfg_if::cfg_if; use foreign_types::ForeignTypeRef; #[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/manmaster/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/manmaster/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/manmaster/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()) } } #[cfg(not(boringssl))] 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()) } } #[cfg(not(boringssl))] 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()) } } #[cfg(not(boringssl))] 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()) } } #[cfg(not(boringssl))] 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(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] 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()) } } #[cfg(not(boringssl))] 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()) } } #[cfg(not(boringssl))] 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()) } } #[cfg(not(boringssl))] 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(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] 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()) } } #[cfg(not(boringssl))] 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()) } } #[cfg(not(boringssl))] 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()) } } #[cfg(not(boringssl))] 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()) } } #[cfg(not(boringssl))] 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(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] 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_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_des_ede3_ecb()) } } #[cfg(not(boringssl))] pub fn des_ede3_cfb64() -> Cipher { unsafe { Cipher(ffi::EVP_des_ede3_cfb64()) } } #[cfg(not(boringssl))] pub fn des_ede3_cfb8() -> Cipher { unsafe { Cipher(ffi::EVP_des_ede3_cfb8()) } } #[cfg(not(boringssl))] pub fn des_ede3_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_des_ede3_ofb()) } } #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn rc4() -> Cipher { unsafe { Cipher(ffi::EVP_rc4()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_128_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_128_cbc()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_128_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_128_ecb()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_128_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_128_ofb()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_128_cfb128() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_128_cfb128()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_192_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_192_cbc()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_192_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_192_ecb()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_192_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_192_ofb()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_192_cfb128() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_192_cfb128()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_256_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_256_cbc()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_256_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_256_ecb()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_256_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_256_ofb()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))] pub fn camellia_256_cfb128() -> Cipher { unsafe { Cipher(ffi::EVP_camellia_256_cfb128()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_cast5_cbc()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_cast5_ecb()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_cast5_ofb()) } } #[cfg(not(osslconf = "OPENSSL_NO_CAST"))] pub fn cast5_cfb64() -> Cipher { unsafe { Cipher(ffi::EVP_cast5_cfb64()) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(all(any(ossl110, libressl310), not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn chacha20() -> Cipher { unsafe { Cipher(ffi::EVP_chacha20()) } } /// Requires OpenSSL 1.1.0 or newer. #[cfg(all(any(ossl110, libressl360), not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn chacha20_poly1305() -> Cipher { unsafe { Cipher(ffi::EVP_chacha20_poly1305()) } } #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_idea_cbc()) } } #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_idea_ecb()) } } #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_idea_ofb()) } } #[cfg(not(osslconf = "OPENSSL_NO_IDEA"))] pub fn idea_cfb64() -> Cipher { unsafe { Cipher(ffi::EVP_idea_cfb64()) } } #[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()) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_ecb() -> Cipher { unsafe { Cipher(ffi::EVP_sm4_ecb()) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_sm4_cbc()) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_ctr() -> Cipher { unsafe { Cipher(ffi::EVP_sm4_ctr()) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_cfb128() -> Cipher { unsafe { Cipher(ffi::EVP_sm4_cfb128()) } } #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] pub fn sm4_ofb() -> Cipher { unsafe { Cipher(ffi::EVP_sm4_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 #[cfg(not(boringssl))] 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() } #[cfg(boringssl)] fn is_ccm(self) -> bool { false } /// Determines whether the cipher is using OCB mode #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] fn is_ocb(self) -> bool { self == Cipher::aes_128_ocb() || self == Cipher::aes_192_ocb() || self == Cipher::aes_256_ocb() } #[cfg(any(not(ossl110), osslconf = "OPENSSL_NO_OCB"))] 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: CipherCtx, } 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 { let mut ctx = CipherCtx::new()?; let f = match mode { Mode::Encrypt => CipherCtxRef::encrypt_init, Mode::Decrypt => CipherCtxRef::decrypt_init, }; f( &mut ctx, Some(unsafe { CipherRef::from_ptr(t.as_ptr() as *mut _) }), None, None, )?; ctx.set_key_length(key.len())?; if let (Some(iv), Some(iv_len)) = (iv, t.iv_len()) { if iv.len() != iv_len { ctx.set_iv_length(iv.len())?; } } f(&mut ctx, None, Some(key), iv)?; Ok(Crypter { ctx }) } /// 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) { self.ctx.set_padding(padding) } /// 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> { self.ctx.set_tag(tag) } /// 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> { self.ctx.set_tag_length(tag_len) } /// 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> { self.ctx.set_data_len(data_len) } /// 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> { self.ctx.cipher_update(input, None)?; Ok(()) } /// 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 { self.ctx.cipher_update(input, Some(output)) } /// 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`. /// /// # Safety /// /// The caller must provide an `output` buffer large enough to contain /// correct number of bytes. For streaming ciphers the output buffer size /// should be at least as big as the input buffer. For block ciphers the /// size of the output buffer depends on the state of partially updated /// blocks. pub unsafe fn update_unchecked( &mut self, input: &[u8], output: &mut [u8], ) -> Result { self.ctx.cipher_update_unchecked(input, Some(output)) } /// 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 { self.ctx.cipher_final(output) } /// 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> { self.ctx.tag(tag) } } /// 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 incrementally , 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 incrementally , 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(boringssl, ossl110, libressl273))] { use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; } else { use crate::LenType; #[allow(bad_style)] pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> LenType { (*ptr).iv_len } #[allow(bad_style)] pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> LenType { (*ptr).block_size } #[allow(bad_style)] pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> LenType { (*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"); } } #[cfg(not(boringssl))] fn cipher_test_nopad(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) { let pt = Vec::from_hex(pt).unwrap(); let ct = Vec::from_hex(ct).unwrap(); let key = Vec::from_hex(key).unwrap(); let iv = Vec::from_hex(iv).unwrap(); let computed = { let mut c = Crypter::new(ciphertype, Mode::Decrypt, &key, Some(&iv)).unwrap(); c.pad(false); let mut out = vec![0; ct.len() + ciphertype.block_size()]; let count = c.update(&ct, &mut out).unwrap(); let rest = c.finalize(&mut out[count..]).unwrap(); out.truncate(count + rest); out }; let expected = pt; if computed != expected { println!("Computed: {}", hex::encode(&computed)); println!("Expected: {}", hex::encode(&expected)); if computed.len() != expected.len() { println!( "Lengths differ: {} in computed vs {} expected", computed.len(), expected.len() ); } panic!("test failure"); } } #[test] fn test_rc4() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "0000000000000000000000000000000000000000000000000000000000000000000000000000"; let ct = "A68686B04D686AA107BD8D4CAB191A3EEC0A6294BC78B60F65C25CB47BD7BB3A48EFC4D26BE4"; let key = "97CD440324DA5FD1F7955C1C13B6B466"; let iv = ""; cipher_test(super::Cipher::rc4(), pt, ct, key, iv); } #[test] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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)] #[cfg(not(boringssl))] fn test_bf_cbc() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); // 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)] #[cfg(not(boringssl))] fn test_bf_ecb() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); 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)] #[cfg(not(boringssl))] fn test_bf_cfb64() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); 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)] #[cfg(not(boringssl))] fn test_bf_ofb() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; let ct = "E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"; let key = "0123456789ABCDEFF0E1D2C3B4A59687"; let iv = "FEDCBA9876543210"; cipher_test_nopad(super::Cipher::bf_ofb(), pt, ct, key, iv); } #[test] fn test_des_cbc() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "54686973206973206120746573742e"; let ct = "6f2867cfefda048a4046ef7e556c7132"; let key = "7cb66337f3d3c0fe"; let iv = "0001020304050607"; cipher_test(super::Cipher::des_cbc(), pt, ct, key, iv); } #[test] fn test_des_ecb() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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] #[cfg(not(boringssl))] 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(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] 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(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] 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, libressl310))] 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, libressl360))] 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() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); 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() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); 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() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); 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() { #[cfg(ossl300)] let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap(); let pt = "5363686f6b6f6c6164656e6b756368656e0a"; let ct = "71d4d25fc1750cb7789259e7f34061930afd"; let key = "41414141414141414141414141414141"; let iv = "41414141414141414141414141414141"; cipher_test(super::Cipher::seed_ofb(), pt, ct, key, iv); } // GB/T 32907-2016 // http://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=7803DE42D3BC5E80B0C3E5D8E873D56A #[test] #[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))] fn test_sm4_ecb() { use std::mem; let key = vec![ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, ]; let pt = vec![ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, ]; let ct = vec![ 0x68, 0x1e, 0xdf, 0x34, 0xd2, 0x06, 0x96, 0x5e, 0x86, 0xb3, 0xe9, 0x4f, 0x53, 0x6e, 0x42, 0x46, ]; let ct1 = vec![ 0x59, 0x52, 0x98, 0xc7, 0xc6, 0xfd, 0x27, 0x1f, 0x04, 0x02, 0xf8, 0x04, 0xc3, 0x3d, 0x3f, 0x66, ]; let block_size = Cipher::sm4_ecb().block_size(); let mut c = Crypter::new(Cipher::sm4_ecb(), Mode::Encrypt, &key, None).unwrap(); c.pad(false); // 1 round let mut r = vec![0; pt.len() + Cipher::sm4_ecb().block_size()]; let count = c.update(&pt, &mut r).unwrap(); assert_eq!(ct, &r[..count]); // 1000000 rounds let mut r1 = vec![0; pt.len() + Cipher::sm4_ecb().block_size()]; for _ in 0..999999 { c.update(&r[..block_size], &mut r1).unwrap(); mem::swap(&mut r, &mut r1); } assert_eq!(ct1, &r[..count]); } } openssl-0.10.64/src/util.rs000064400000000000000000000050441046102023000135740ustar 00000000000000use crate::error::ErrorStack; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_void}; use std::any::Any; use std::panic::{self, AssertUnwindSafe}; use std::slice; /// 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.64/src/version.rs000064400000000000000000000103771046102023000143110ustar 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. // //! Build and version information. use cfg_if::cfg_if; use openssl_macros::corresponds; 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` #[corresponds(OpenSSL_version_num)] 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". #[corresponds(OpenSSL_version)] 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. #[corresponds(OpenSSL_version)] 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. #[corresponds(OpenSSL_version)] 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. #[corresponds(OpenSSL_version)] 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. #[corresponds(OpenSSL_version)] 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(any(libressl, boringssl)))] fn expected_name() -> &'static str { "OpenSSL" } #[cfg(libressl)] fn expected_name() -> &'static str { "LibreSSL" } #[cfg(boringssl)] fn expected_name() -> &'static str { "BoringSSL" } assert!(number() > 0); assert!(version().starts_with(expected_name())); assert!(c_flags().starts_with("compiler:")); // some distributions patch out dates out of openssl so that the builds are reproducible if !built_on().is_empty() { assert!(built_on().starts_with("built on:")); } assert!(dir().starts_with("OPENSSLDIR:")); } openssl-0.10.64/src/x509/extension.rs000064400000000000000000000415711046102023000153450ustar 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::asn1::Asn1Object; use crate::error::ErrorStack; use crate::nid::Nid; use crate::x509::{GeneralName, Stack, X509Extension, X509v3Context}; use foreign_types::ForeignType; /// 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`. // Temporarily silence the deprecation warning - this should be ported to // `X509Extension::new_internal`. #[allow(deprecated)] 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`. // Temporarily silence the deprecation warning - this should be ported to // `X509Extension::new_internal`. #[allow(deprecated)] 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, items: Vec, } impl Default for ExtendedKeyUsage { fn default() -> ExtendedKeyUsage { ExtendedKeyUsage::new() } } impl ExtendedKeyUsage { /// Construct a new `ExtendedKeyUsage` extension. pub fn new() -> ExtendedKeyUsage { ExtendedKeyUsage { critical: false, items: 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.other("serverAuth") } /// Sets the `clientAuth` flag to `true`. pub fn client_auth(&mut self) -> &mut ExtendedKeyUsage { self.other("clientAuth") } /// Sets the `codeSigning` flag to `true`. pub fn code_signing(&mut self) -> &mut ExtendedKeyUsage { self.other("codeSigning") } /// Sets the `emailProtection` flag to `true`. pub fn email_protection(&mut self) -> &mut ExtendedKeyUsage { self.other("emailProtection") } /// Sets the `timeStamping` flag to `true`. pub fn time_stamping(&mut self) -> &mut ExtendedKeyUsage { self.other("timeStamping") } /// Sets the `msCodeInd` flag to `true`. pub fn ms_code_ind(&mut self) -> &mut ExtendedKeyUsage { self.other("msCodeInd") } /// Sets the `msCodeCom` flag to `true`. pub fn ms_code_com(&mut self) -> &mut ExtendedKeyUsage { self.other("msCodeCom") } /// Sets the `msCTLSign` flag to `true`. pub fn ms_ctl_sign(&mut self) -> &mut ExtendedKeyUsage { self.other("msCTLSign") } /// Sets the `msSGC` flag to `true`. pub fn ms_sgc(&mut self) -> &mut ExtendedKeyUsage { self.other("msSGC") } /// Sets the `msEFS` flag to `true`. pub fn ms_efs(&mut self) -> &mut ExtendedKeyUsage { self.other("msEFS") } /// Sets the `nsSGC` flag to `true`. pub fn ns_sgc(&mut self) -> &mut ExtendedKeyUsage { self.other("nsSGC") } /// Sets a flag not already defined. pub fn other(&mut self, other: &str) -> &mut ExtendedKeyUsage { self.items.push(other.to_string()); self } /// Return the `ExtendedKeyUsage` extension as an `X509Extension`. pub fn build(&self) -> Result { let mut stack = Stack::new()?; for item in &self.items { stack.push(Asn1Object::from_str(item)?)?; } unsafe { X509Extension::new_internal(Nid::EXT_KEY_USAGE, self.critical, stack.as_ptr().cast()) } } } /// 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`. // Temporarily silence the deprecation warning - this should be ported to // `X509Extension::new_internal`. #[allow(deprecated)] 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`. // Temporarily silence the deprecation warning - this should be ported to // `X509Extension::new_internal`. #[allow(deprecated)] 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) } } enum RustGeneralName { Dns(String), Email(String), Uri(String), Ip(String), Rid(String), OtherName(Asn1Object, Vec), } /// An extension that allows additional identities to be bound to the subject /// of the certificate. pub struct SubjectAlternativeName { critical: bool, items: Vec, } impl Default for SubjectAlternativeName { fn default() -> SubjectAlternativeName { SubjectAlternativeName::new() } } impl SubjectAlternativeName { /// Construct a new `SubjectAlternativeName` extension. pub fn new() -> SubjectAlternativeName { SubjectAlternativeName { critical: false, items: 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.items.push(RustGeneralName::Email(email.to_string())); self } /// Sets the `uri` flag. pub fn uri(&mut self, uri: &str) -> &mut SubjectAlternativeName { self.items.push(RustGeneralName::Uri(uri.to_string())); self } /// Sets the `dns` flag. pub fn dns(&mut self, dns: &str) -> &mut SubjectAlternativeName { self.items.push(RustGeneralName::Dns(dns.to_string())); self } /// Sets the `rid` flag. pub fn rid(&mut self, rid: &str) -> &mut SubjectAlternativeName { self.items.push(RustGeneralName::Rid(rid.to_string())); self } /// Sets the `ip` flag. pub fn ip(&mut self, ip: &str) -> &mut SubjectAlternativeName { self.items.push(RustGeneralName::Ip(ip.to_string())); self } /// Sets the `dirName` flag. /// /// Not currently actually supported, always panics. #[deprecated = "dir_name is deprecated and always panics. Please file a bug if you have a use case for this."] pub fn dir_name(&mut self, _dir_name: &str) -> &mut SubjectAlternativeName { unimplemented!( "This has not yet been adapted for the new internals. File a bug if you need this." ); } /// Sets the `otherName` flag. /// /// Not currently actually supported, always panics. Please use other_name2 #[deprecated = "other_name is deprecated and always panics. Please use other_name2."] pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName { unimplemented!("This has not yet been adapted for the new internals. Use other_name2."); } /// Sets the `otherName` flag. /// /// `content` must be a valid der encoded ASN1_TYPE /// /// If you want to add just a ia5string use `other_name_ia5string` pub fn other_name2(&mut self, oid: Asn1Object, content: &[u8]) -> &mut SubjectAlternativeName { self.items .push(RustGeneralName::OtherName(oid, content.into())); self } /// Return a `SubjectAlternativeName` extension as an `X509Extension`. pub fn build(&self, _ctx: &X509v3Context<'_>) -> Result { let mut stack = Stack::new()?; for item in &self.items { let gn = match item { RustGeneralName::Dns(s) => GeneralName::new_dns(s.as_bytes())?, RustGeneralName::Email(s) => GeneralName::new_email(s.as_bytes())?, RustGeneralName::Uri(s) => GeneralName::new_uri(s.as_bytes())?, RustGeneralName::Ip(s) => { GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)? } RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?, RustGeneralName::OtherName(oid, content) => { GeneralName::new_other_name(oid.clone(), content)? } }; stack.push(gn)?; } unsafe { X509Extension::new_internal(Nid::SUBJECT_ALT_NAME, self.critical, stack.as_ptr().cast()) } } } 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.64/src/x509/mod.rs000064400000000000000000002506321046102023000141100ustar 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, Opaque}; use libc::{c_int, c_long, c_uint, c_void}; use std::cmp::{self, Ordering}; use std::convert::{TryFrom, TryInto}; use std::error::Error; use std::ffi::{CStr, CString}; use std::fmt; use std::marker::PhantomData; use std::mem; use std::net::IpAddr; use std::path::Path; use std::ptr; use std::slice; use std::str; use crate::asn1::{ Asn1BitStringRef, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, Asn1OctetStringRef, 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, cvt_p_const}; use openssl_macros::corresponds; #[cfg(any(ossl102, boringssl, libressl261))] pub mod verify; pub mod extension; pub mod store; #[cfg(test)] mod tests; /// A type of X509 extension. /// /// # Safety /// The value of NID and Output must match those in OpenSSL so that /// `Output::from_ptr_opt(*_get_ext_d2i(*, NID, ...))` is valid. pub unsafe trait ExtensionType { const NID: Nid; type Output: ForeignType; } 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; /// A reference to an [`X509StoreContext`]. pub struct X509StoreContextRef; } impl X509StoreContext { /// Returns the index which can be used to obtain a reference to the `Ssl` associated with a /// context. #[corresponds(SSL_get_ex_data_X509_STORE_CTX_idx)] 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. #[corresponds(X509_STORE_CTX_new)] 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. #[corresponds(X509_STORE_CTX_get_ex_data)] 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. #[corresponds(X509_STORE_CTX_get_error)] 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/manmaster/crypto/X509_STORE_CTX_init.html /// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/manmaster/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`. #[corresponds(X509_verify_cert)] 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. #[corresponds(X509_STORE_CTX_set_error)] 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. #[corresponds(X509_STORE_CTX_get_current_cert)] 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. #[corresponds(X509_STORE_CTX_get_error_depth)] 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. #[corresponds(X509_STORE_CTX_get0_chain)] 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. #[corresponds(X509_new)] pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::X509_new()).map(|p| X509Builder(X509(p))) } } /// Sets the notAfter constraint on the certificate. #[corresponds(X509_set1_notAfter)] 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. #[corresponds(X509_set1_notBefore)] 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. #[corresponds(X509_set_version)] #[allow(clippy::useless_conversion)] pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_set_version(self.0.as_ptr(), version as c_long)).map(|_| ()) } } /// Sets the serial number of the certificate. #[corresponds(X509_set_serialNumber)] 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. #[corresponds(X509_set_issuer_name)] 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(); /// ``` #[corresponds(X509_set_subject_name)] 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. #[corresponds(X509_set_pubkey)] 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. #[corresponds(X509V3_set_ctx)] 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. #[corresponds(X509_add_ext)] 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. #[corresponds(X509_sign)] 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. #[corresponds(X509_get_subject_name)] 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 #[corresponds(X509_subject_name_hash)] pub fn subject_name_hash(&self) -> u32 { #[allow(clippy::unnecessary_cast)] unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } } /// Returns this certificate's issuer name. #[corresponds(X509_get_issuer_name)] 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 the hash of the certificates issuer #[corresponds(X509_issuer_name_hash)] pub fn issuer_name_hash(&self) -> u32 { #[allow(clippy::unnecessary_cast)] unsafe { ffi::X509_issuer_name_hash(self.as_ptr()) as u32 } } /// Returns this certificate's subject alternative name entries, if they exist. #[corresponds(X509_get_ext_d2i)] 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 CRL distribution points, if they exist. #[corresponds(X509_get_ext_d2i)] pub fn crl_distribution_points(&self) -> Option> { unsafe { let stack = ffi::X509_get_ext_d2i( self.as_ptr(), ffi::NID_crl_distribution_points, ptr::null_mut(), ptr::null_mut(), ); Stack::from_ptr_opt(stack as *mut _) } } /// Returns this certificate's issuer alternative name entries, if they exist. #[corresponds(X509_get_ext_d2i)] 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. /// /// [`authority information access`]: https://tools.ietf.org/html/rfc5280#section-4.2.2.1 #[corresponds(X509_get_ext_d2i)] 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 _) } } /// Retrieves the path length extension from a certificate, if it exists. #[corresponds(X509_get_pathlen)] #[cfg(any(ossl110, boringssl))] pub fn pathlen(&self) -> Option { let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) }; u32::try_from(v).ok() } /// Returns this certificate's subject key id, if it exists. #[corresponds(X509_get0_subject_key_id)] #[cfg(any(ossl110, boringssl))] pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> { unsafe { let data = ffi::X509_get0_subject_key_id(self.as_ptr()); Asn1OctetStringRef::from_const_ptr_opt(data) } } /// Returns this certificate's authority key id, if it exists. #[corresponds(X509_get0_authority_key_id)] #[cfg(any(ossl110, boringssl))] pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> { unsafe { let data = ffi::X509_get0_authority_key_id(self.as_ptr()); Asn1OctetStringRef::from_const_ptr_opt(data) } } /// Returns this certificate's authority issuer name entries, if they exist. #[corresponds(X509_get0_authority_issuer)] #[cfg(ossl111d)] pub fn authority_issuer(&self) -> Option<&StackRef> { unsafe { let stack = ffi::X509_get0_authority_issuer(self.as_ptr()); StackRef::from_const_ptr_opt(stack) } } /// Returns this certificate's authority serial number, if it exists. #[corresponds(X509_get0_authority_serial)] #[cfg(ossl111d)] pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> { unsafe { let r = ffi::X509_get0_authority_serial(self.as_ptr()); Asn1IntegerRef::from_const_ptr_opt(r) } } #[corresponds(X509_get_pubkey)] 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. #[corresponds(X509_digest)] 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 as c_uint; 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. #[corresponds(X509_getm_notAfter)] 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. #[corresponds(X509_getm_notBefore)] 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 #[corresponds(X509_get0_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. #[corresponds(X509_get0_signature)] 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. #[corresponds(X509_get1_ocsp)] 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`. #[corresponds(X509_check_issued)] 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. #[corresponds(X509_get_version)] #[cfg(ossl110)] #[allow(clippy::unnecessary_cast)] pub fn version(&self) -> i32 { 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. #[corresponds(X509_verify)] 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. #[corresponds(X509_get_serialNumber)] 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") } } /// Returns this certificate's "alias". This field is populated by /// OpenSSL in some situations -- specifically OpenSSL will store a /// PKCS#12 `friendlyName` in this field. This is not a part of the X.509 /// certificate itself, OpenSSL merely attaches it to this structure in /// memory. #[corresponds(X509_alias_get0)] pub fn alias(&self) -> Option<&[u8]> { unsafe { let mut len = 0; let ptr = ffi::X509_alias_get0(self.as_ptr(), &mut len); if ptr.is_null() { None } else { Some(slice::from_raw_parts(ptr, len as usize)) } } } to_pem! { /// Serializes the certificate into a PEM-encoded X509 structure. /// /// The output will have a header of `-----BEGIN CERTIFICATE-----`. #[corresponds(PEM_write_bio_X509)] to_pem, ffi::PEM_write_bio_X509 } to_der! { /// Serializes the certificate into a DER-encoded X509 structure. #[corresponds(i2d_X509)] to_der, ffi::i2d_X509 } to_pem! { /// Converts the certificate to human readable text. #[corresponds(X509_print)] to_text, ffi::X509_print } } 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 Ord for X509Ref { fn cmp(&self, other: &Self) -> cmp::Ordering { // X509_cmp returns a number <0 for less than, 0 for equal and >0 for greater than. // It can't fail if both pointers are valid, which we know is true. let cmp = unsafe { ffi::X509_cmp(self.as_ptr(), other.as_ptr()) }; cmp.cmp(&0) } } impl PartialOrd for X509Ref { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PartialOrd for X509Ref { fn partial_cmp(&self, other: &X509) -> Option { >::partial_cmp(self, other) } } impl PartialEq for X509Ref { fn eq(&self, other: &Self) -> bool { self.cmp(other) == cmp::Ordering::Equal } } impl PartialEq for X509Ref { fn eq(&self, other: &X509) -> bool { >::eq(self, other) } } impl Eq for X509Ref {} 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-----`. #[corresponds(PEM_read_bio_X509)] from_pem, X509, ffi::PEM_read_bio_X509 } from_der! { /// Deserializes a DER-encoded X509 structure. #[corresponds(d2i_X509)] from_der, X509, ffi::d2i_X509 } /// Deserializes a list of PEM-formatted certificates. #[corresponds(PEM_read_bio_X509)] 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 e = ErrorStack::get(); if let Some(err) = e.errors().last() { if err.library_code() == ffi::ERR_LIB_PEM as libc::c_int && err.reason_code() == ffi::PEM_R_NO_START_LINE as libc::c_int { break; } } return Err(e); } 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; } impl Ord for X509 { fn cmp(&self, other: &Self) -> cmp::Ordering { X509Ref::cmp(self, other) } } impl PartialOrd for X509 { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl PartialOrd for X509 { fn partial_cmp(&self, other: &X509Ref) -> Option { X509Ref::partial_cmp(self, other) } } impl PartialEq for X509 { fn eq(&self, other: &Self) -> bool { X509Ref::eq(self, other) } } impl PartialEq for X509 { fn eq(&self, other: &X509Ref) -> bool { X509Ref::eq(self, other) } } impl Eq for 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. /// /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL /// mini-language that can read arbitrary files. /// /// See the extension module for builder types which will construct certain common extensions. /// /// This function is deprecated, `X509Extension::new_from_der` or the /// types in `x509::extension` should be used in its place. #[deprecated( note = "Use x509::extension types or new_from_der instead", since = "0.10.51" )] 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(); let mut ctx; unsafe { ffi::init(); let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); let context_ptr = match context { Some(c) => c.as_ptr(), None => { ctx = mem::zeroed(); ffi::X509V3_set_ctx( &mut ctx, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), 0, ); &mut ctx } }; let name = name.as_ptr() as *mut _; let value = value.as_ptr() as *mut _; cvt_p(ffi::X509V3_EXT_nconf(conf, context_ptr, 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. /// /// DO NOT CALL THIS WITH UNTRUSTED `value`: `value` is an OpenSSL /// mini-language that can read arbitrary files. /// /// See the extension module for builder types which will construct certain common extensions. /// /// This function is deprecated, `X509Extension::new_from_der` or the /// types in `x509::extension` should be used in its place. #[deprecated( note = "Use x509::extension types or new_from_der instead", since = "0.10.51" )] pub fn new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, name: Nid, value: &str, ) -> Result { let value = CString::new(value).unwrap(); let mut ctx; unsafe { ffi::init(); let conf = conf.map_or(ptr::null_mut(), ConfRef::as_ptr); let context_ptr = match context { Some(c) => c.as_ptr(), None => { ctx = mem::zeroed(); ffi::X509V3_set_ctx( &mut ctx, ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), ptr::null_mut(), 0, ); &mut ctx } }; let name = name.as_raw(); let value = value.as_ptr() as *mut _; cvt_p(ffi::X509V3_EXT_nconf_nid(conf, context_ptr, name, value)).map(X509Extension) } } /// Constructs a new X509 extension value from its OID, whether it's /// critical, and its DER contents. /// /// The extent structure of the DER value will vary based on the /// extension type, and can generally be found in the RFC defining the /// extension. /// /// For common extension types, there are Rust APIs provided in /// `openssl::x509::extensions` which are more ergonomic. pub fn new_from_der( oid: &Asn1ObjectRef, critical: bool, der_contents: &Asn1OctetStringRef, ) -> Result { unsafe { cvt_p(ffi::X509_EXTENSION_create_by_OBJ( ptr::null_mut(), oid.as_ptr(), critical as _, der_contents.as_ptr(), )) .map(X509Extension) } } pub(crate) unsafe fn new_internal( nid: Nid, critical: bool, value: *mut c_void, ) -> Result { ffi::init(); cvt_p(ffi::X509V3_EXT_i2d(nid.as_raw(), critical as _, value)).map(X509Extension) } /// Adds an alias for an extension /// /// # Safety /// /// This method modifies global state without locking and therefore is not thread safe #[cfg(not(libressl390))] #[corresponds(X509V3_EXT_add_alias)] #[deprecated( note = "Use x509::extension types or new_from_der and then this is not necessary", since = "0.10.51" )] pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> { ffi::init(); cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ()) } } impl X509ExtensionRef { to_der! { /// Serializes the Extension to its standard DER encoding. #[corresponds(i2d_X509_EXTENSION)] to_der, ffi::i2d_X509_EXTENSION } } /// 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 name entry #[corresponds(X509_NAME_add_entry)] #[cfg(any(ossl101, libressl350))] pub fn append_entry(&mut self, ne: &X509NameEntryRef) -> std::result::Result<(), ErrorStack> { unsafe { cvt(ffi::X509_NAME_add_entry( self.0.as_ptr(), ne.as_ptr(), -1, 0, )) .map(|_| ()) } } /// 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/manmaster/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() <= crate::SLenType::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 crate::SLenType, -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/manmaster/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() <= crate::SLenType::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 crate::SLenType, -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/manmaster/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() <= crate::SLenType::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 crate::SLenType, -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/manmaster/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() <= crate::SLenType::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 crate::SLenType, -1, 0, )) .map(|_| ()) } } /// Return an `X509Name`. pub fn build(self) -> X509Name { // Round-trip through bytes because OpenSSL is not const correct and // names in a "modified" state compute various things lazily. This can // lead to data-races because OpenSSL doesn't have locks or anything. X509Name::from_der(&self.0.to_der().unwrap()).unwrap() } } 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)) } } from_der! { /// Deserializes a DER-encoded X509 name structure. /// /// This corresponds to [`d2i_X509_NAME`]. /// /// [`d2i_X509_NAME`]: https://www.openssl.org/docs/manmaster/man3/d2i_X509_NAME.html from_der, X509Name, ffi::d2i_X509_NAME } } 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, } } /// Compare two names, like [`Ord`] but it may fail. /// /// With OpenSSL versions from 3.0.0 this may return an error if the underlying `X509_NAME_cmp` /// call fails. /// For OpenSSL versions before 3.0.0 it will never return an error, but due to a bug it may /// spuriously return `Ordering::Less` if the `X509_NAME_cmp` call fails. #[corresponds(X509_NAME_cmp)] pub fn try_cmp(&self, other: &X509NameRef) -> Result { let cmp = unsafe { ffi::X509_NAME_cmp(self.as_ptr(), other.as_ptr()) }; if cfg!(ossl300) && cmp == -2 { return Err(ErrorStack::get()); } Ok(cmp.cmp(&0)) } /// Copies the name to a new `X509Name`. #[corresponds(X509_NAME_dup)] #[cfg(any(boringssl, ossl110, libressl270))] pub fn to_owned(&self) -> Result { unsafe { cvt_p(ffi::X509_NAME_dup(self.as_ptr())).map(|n| X509Name::from_ptr(n)) } } to_der! { /// Serializes the certificate into a DER-encoded X509 name structure. /// /// This corresponds to [`i2d_X509_NAME`]. /// /// [`i2d_X509_NAME`]: https://www.openssl.org/docs/manmaster/crypto/i2d_X509_NAME.html to_der, ffi::i2d_X509_NAME } } 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/manmaster/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/manmaster/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/manmaster/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/manmaster/crypto/X509_REQ_set_version.html #[allow(clippy::useless_conversion)] pub fn set_version(&mut self, version: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_version( self.0.as_ptr(), version as c_long, )) .map(|_| ()) } } /// Set the issuer name. /// /// This corresponds to [`X509_REQ_set_subject_name`]. /// /// [`X509_REQ_set_subject_name`]: https://www.openssl.org/docs/manmaster/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/manmaster/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/manmaster/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/manmaster/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/manmaster/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/manmaster/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/manmaster/crypto/i2d_X509_REQ.html to_der, ffi::i2d_X509_REQ } to_pem! { /// Converts the request to human readable text. #[corresponds(X509_Req_print)] to_text, ffi::X509_REQ_print } /// 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/manmaster/crypto/X509_REQ_get_version.html #[allow(clippy::unnecessary_cast)] 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/manmaster/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/manmaster/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/manmaster/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 reason that a certificate was revoked. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct CrlReason(c_int); #[allow(missing_docs)] // no need to document the constants impl CrlReason { pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED); pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE); pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE); pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED); pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED); pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION); pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD); pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL); pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN); pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE); /// Constructs an `CrlReason` from a raw OpenSSL value. pub const fn from_raw(value: c_int) -> Self { CrlReason(value) } /// Returns the raw OpenSSL value represented by this type. pub const fn as_raw(&self) -> c_int { self.0 } } foreign_type_and_impl_send_sync! { type CType = ffi::X509_REVOKED; fn drop = ffi::X509_REVOKED_free; /// An `X509` certificate revocation status. pub struct X509Revoked; /// Reference to `X509Revoked`. pub struct X509RevokedRef; } impl Stackable for X509Revoked { type StackType = ffi::stack_st_X509_REVOKED; } impl X509Revoked { from_der! { /// Deserializes a DER-encoded certificate revocation status #[corresponds(d2i_X509_REVOKED)] from_der, X509Revoked, ffi::d2i_X509_REVOKED } } impl X509RevokedRef { to_der! { /// Serializes the certificate request to a DER-encoded certificate revocation status #[corresponds(d2i_X509_REVOKED)] to_der, ffi::i2d_X509_REVOKED } /// Copies the entry to a new `X509Revoked`. #[corresponds(X509_NAME_dup)] #[cfg(any(boringssl, ossl110, libressl270))] pub fn to_owned(&self) -> Result { unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) } } /// Get the date that the certificate was revoked #[corresponds(X509_REVOKED_get0_revocationDate)] pub fn revocation_date(&self) -> &Asn1TimeRef { unsafe { let r = X509_REVOKED_get0_revocationDate(self.as_ptr() as *const _); assert!(!r.is_null()); Asn1TimeRef::from_ptr(r as *mut _) } } /// Get the serial number of the revoked certificate #[corresponds(X509_REVOKED_get0_serialNumber)] pub fn serial_number(&self) -> &Asn1IntegerRef { unsafe { let r = X509_REVOKED_get0_serialNumber(self.as_ptr() as *const _); assert!(!r.is_null()); Asn1IntegerRef::from_ptr(r as *mut _) } } /// Get the criticality and value of an extension. /// /// This returns None if the extension is not present or occurs multiple times. #[corresponds(X509_REVOKED_get_ext_d2i)] pub fn extension(&self) -> Result, ErrorStack> { let mut critical = -1; let out = unsafe { // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED. let ext = ffi::X509_REVOKED_get_ext_d2i( self.as_ptr(), T::NID.as_raw(), &mut critical as *mut _, ptr::null_mut(), ); // SAFETY: Extensions's contract promises that the type returned by // OpenSSL here is T::Output. T::Output::from_ptr_opt(ext as *mut _) }; match (critical, out) { (0, Some(out)) => Ok(Some((false, out))), (1, Some(out)) => Ok(Some((true, out))), // -1 means the extension wasn't found, -2 means multiple were found. (-1 | -2, _) => Ok(None), // A critical value of 0 or 1 suggests success, but a null pointer // was returned so something went wrong. (0 | 1, None) => Err(ErrorStack::get()), (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical), } } } /// The CRL entry extension identifying the reason for revocation see [`CrlReason`], /// this is as defined in RFC 5280 Section 5.3.1. pub enum ReasonCode {} // SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC // and in OpenSSL. unsafe impl ExtensionType for ReasonCode { const NID: Nid = Nid::from_raw(ffi::NID_crl_reason); type Output = Asn1Enumerated; } /// The CRL entry extension identifying the issuer of a certificate used in /// indirect CRLs, as defined in RFC 5280 Section 5.3.3. pub enum CertificateIssuer {} // SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC // and in OpenSSL. unsafe impl ExtensionType for CertificateIssuer { const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer); type Output = Stack; } /// The CRL extension identifying how to access information and services for the issuer of the CRL pub enum AuthorityInformationAccess {} // SAFETY: AuthorityInformationAccess is defined to be a stack of AccessDescription in the RFC // and in OpenSSL. unsafe impl ExtensionType for AuthorityInformationAccess { const NID: Nid = Nid::from_raw(ffi::NID_info_access); type Output = Stack; } foreign_type_and_impl_send_sync! { type CType = ffi::X509_CRL; fn drop = ffi::X509_CRL_free; /// An `X509` certificate revocation list. pub struct X509Crl; /// Reference to `X509Crl`. pub struct X509CrlRef; } /// The status of a certificate in a revoction list /// /// Corresponds to the return value from the [`X509_CRL_get0_by_*`] methods. /// /// [`X509_CRL_get0_by_*`]: https://www.openssl.org/docs/man1.1.0/man3/X509_CRL_get0_by_serial.html pub enum CrlStatus<'a> { /// The certificate is not present in the list NotRevoked, /// The certificate is in the list and is revoked Revoked(&'a X509RevokedRef), /// The certificate is in the list, but has the "removeFromCrl" status. /// /// This can occur if the certificate was revoked with the "CertificateHold" /// reason, and has since been unrevoked. RemoveFromCrl(&'a X509RevokedRef), } impl<'a> CrlStatus<'a> { // Helper used by the X509_CRL_get0_by_* methods to convert their return // value to the status enum. // Safety note: the returned CrlStatus must not outlive the owner of the // revoked_entry pointer. unsafe fn from_ffi_status( status: c_int, revoked_entry: *mut ffi::X509_REVOKED, ) -> CrlStatus<'a> { match status { 0 => CrlStatus::NotRevoked, 1 => { assert!(!revoked_entry.is_null()); CrlStatus::Revoked(X509RevokedRef::from_ptr(revoked_entry)) } 2 => { assert!(!revoked_entry.is_null()); CrlStatus::RemoveFromCrl(X509RevokedRef::from_ptr(revoked_entry)) } _ => unreachable!( "{}", "X509_CRL_get0_by_{{serial,cert}} should only return 0, 1, or 2." ), } } } impl X509Crl { from_pem! { /// Deserializes a PEM-encoded Certificate Revocation List /// /// The input should have a header of `-----BEGIN X509 CRL-----`. #[corresponds(PEM_read_bio_X509_CRL)] from_pem, X509Crl, ffi::PEM_read_bio_X509_CRL } from_der! { /// Deserializes a DER-encoded Certificate Revocation List #[corresponds(d2i_X509_CRL)] from_der, X509Crl, ffi::d2i_X509_CRL } } impl X509CrlRef { to_pem! { /// Serializes the certificate request to a PEM-encoded Certificate Revocation List. /// /// The output will have a header of `-----BEGIN X509 CRL-----`. #[corresponds(PEM_write_bio_X509_CRL)] to_pem, ffi::PEM_write_bio_X509_CRL } to_der! { /// Serializes the certificate request to a DER-encoded Certificate Revocation List. #[corresponds(i2d_X509_CRL)] to_der, ffi::i2d_X509_CRL } /// Get the stack of revocation entries pub fn get_revoked(&self) -> Option<&StackRef> { unsafe { let revoked = X509_CRL_get_REVOKED(self.as_ptr()); if revoked.is_null() { None } else { Some(StackRef::from_ptr(revoked)) } } } /// Returns the CRL's `lastUpdate` time. #[corresponds(X509_CRL_get0_lastUpdate)] pub fn last_update(&self) -> &Asn1TimeRef { unsafe { let date = X509_CRL_get0_lastUpdate(self.as_ptr()); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date as *mut _) } } /// Returns the CRL's `nextUpdate` time. /// /// If the `nextUpdate` field is missing, returns `None`. #[corresponds(X509_CRL_get0_nextUpdate)] pub fn next_update(&self) -> Option<&Asn1TimeRef> { unsafe { let date = X509_CRL_get0_nextUpdate(self.as_ptr()); Asn1TimeRef::from_const_ptr_opt(date) } } /// Get the revocation status of a certificate by its serial number #[corresponds(X509_CRL_get0_by_serial)] pub fn get_by_serial<'a>(&'a self, serial: &Asn1IntegerRef) -> CrlStatus<'a> { unsafe { let mut ret = ptr::null_mut::(); let status = ffi::X509_CRL_get0_by_serial(self.as_ptr(), &mut ret as *mut _, serial.as_ptr()); CrlStatus::from_ffi_status(status, ret) } } /// Get the revocation status of a certificate #[corresponds(X509_CRL_get0_by_cert)] pub fn get_by_cert<'a>(&'a self, cert: &X509) -> CrlStatus<'a> { unsafe { let mut ret = ptr::null_mut::(); let status = ffi::X509_CRL_get0_by_cert(self.as_ptr(), &mut ret as *mut _, cert.as_ptr()); CrlStatus::from_ffi_status(status, ret) } } /// Get the issuer name from the revocation list. #[corresponds(X509_CRL_get_issuer)] pub fn issuer_name(&self) -> &X509NameRef { unsafe { let name = X509_CRL_get_issuer(self.as_ptr()); assert!(!name.is_null()); X509NameRef::from_ptr(name) } } /// Check if the CRL 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. #[corresponds(X509_CRL_verify)] pub fn verify(&self, key: &PKeyRef) -> Result where T: HasPublic, { unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) } } /// Get the criticality and value of an extension. /// /// This returns None if the extension is not present or occurs multiple times. #[corresponds(X509_CRL_get_ext_d2i)] pub fn extension(&self) -> Result, ErrorStack> { let mut critical = -1; let out = unsafe { // SAFETY: self.as_ptr() is a valid pointer to an X509_CRL. let ext = ffi::X509_CRL_get_ext_d2i( self.as_ptr(), T::NID.as_raw(), &mut critical as *mut _, ptr::null_mut(), ); // SAFETY: Extensions's contract promises that the type returned by // OpenSSL here is T::Output. T::Output::from_ptr_opt(ext as *mut _) }; match (critical, out) { (0, Some(out)) => Ok(Some((false, out))), (1, Some(out)) => Ok(Some((true, out))), // -1 means the extension wasn't found, -2 means multiple were found. (-1 | -2, _) => Ok(None), // A critical value of 0 or 1 suggests success, but a null pointer // was returned so something went wrong. (0 | 1, None) => Err(ErrorStack::get()), (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical), } } } /// 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/manmaster/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 certificate 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 GeneralName { unsafe fn new( type_: c_int, asn1_type: Asn1Type, value: &[u8], ) -> Result { ffi::init(); let gn = GeneralName::from_ptr(cvt_p(ffi::GENERAL_NAME_new())?); (*gn.as_ptr()).type_ = type_; let s = cvt_p(ffi::ASN1_STRING_type_new(asn1_type.as_raw()))?; ffi::ASN1_STRING_set(s, value.as_ptr().cast(), value.len().try_into().unwrap()); #[cfg(boringssl)] { (*gn.as_ptr()).d.ptr = s.cast(); } #[cfg(not(boringssl))] { (*gn.as_ptr()).d = s.cast(); } Ok(gn) } pub(crate) fn new_email(email: &[u8]) -> Result { unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) } } pub(crate) fn new_dns(dns: &[u8]) -> Result { unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) } } pub(crate) fn new_uri(uri: &[u8]) -> Result { unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) } } pub(crate) fn new_ip(ip: IpAddr) -> Result { match ip { IpAddr::V4(addr) => unsafe { GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets()) }, IpAddr::V6(addr) => unsafe { GeneralName::new(ffi::GEN_IPADD, Asn1Type::OCTET_STRING, &addr.octets()) }, } } pub(crate) fn new_rid(oid: Asn1Object) -> Result { unsafe { ffi::init(); let gn = cvt_p(ffi::GENERAL_NAME_new())?; (*gn).type_ = ffi::GEN_RID; #[cfg(boringssl)] { (*gn).d.registeredID = oid.as_ptr(); } #[cfg(not(boringssl))] { (*gn).d = oid.as_ptr().cast(); } mem::forget(oid); Ok(GeneralName::from_ptr(gn)) } } pub(crate) fn new_other_name(oid: Asn1Object, value: &[u8]) -> Result { unsafe { ffi::init(); let typ = cvt_p(ffi::d2i_ASN1_TYPE( ptr::null_mut(), &mut value.as_ptr().cast(), value.len().try_into().unwrap(), ))?; let gn = cvt_p(ffi::GENERAL_NAME_new())?; (*gn).type_ = ffi::GEN_OTHERNAME; if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername( gn, oid.as_ptr().cast(), typ, )) { ffi::GENERAL_NAME_free(gn); return Err(e); } mem::forget(oid); Ok(GeneralName::from_ptr(gn)) } } } impl GeneralNameRef { fn ia5_string(&self, ffi_type: c_int) -> Option<&str> { unsafe { if (*self.as_ptr()).type_ != ffi_type { return None; } #[cfg(boringssl)] let d = (*self.as_ptr()).d.ptr; #[cfg(not(boringssl))] let d = (*self.as_ptr()).d; let ptr = ASN1_STRING_get0_data(d as *mut _); let len = ffi::ASN1_STRING_length(d as *mut _); #[allow(clippy::unnecessary_cast)] 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 `directoryName`. pub fn directory_name(&self) -> Option<&X509NameRef> { unsafe { if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME { return None; } #[cfg(boringssl)] let d = (*self.as_ptr()).d.ptr; #[cfg(not(boringssl))] let d = (*self.as_ptr()).d; Some(X509NameRef::from_const_ptr(d as *const _)) } } /// 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; } #[cfg(boringssl)] let d: *const ffi::ASN1_STRING = std::mem::transmute((*self.as_ptr()).d); #[cfg(not(boringssl))] let d = (*self.as_ptr()).d; let ptr = ASN1_STRING_get0_data(d as *mut _); let len = ffi::ASN1_STRING_length(d as *mut _); #[allow(clippy::unnecessary_cast)] 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 address = <[u8; 16]>::try_from(ipaddress) .map(IpAddr::from) .or_else(|_| <[u8; 4]>::try_from(ipaddress).map(IpAddr::from)); match address { Ok(a) => fmt::Debug::fmt(&a, formatter), Err(_) => fmt::Debug::fmt(ipaddress, formatter), } } 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::DIST_POINT; fn drop = ffi::DIST_POINT_free; /// A `X509` distribution point. pub struct DistPoint; /// Reference to `DistPoint`. pub struct DistPointRef; } impl DistPointRef { /// Returns the name of this distribution point if it exists pub fn distpoint(&self) -> Option<&DistPointNameRef> { unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) } } } foreign_type_and_impl_send_sync! { type CType = ffi::DIST_POINT_NAME; fn drop = ffi::DIST_POINT_NAME_free; /// A `X509` distribution point. pub struct DistPointName; /// Reference to `DistPointName`. pub struct DistPointNameRef; } impl DistPointNameRef { /// Returns the contents of this DistPointName if it is a fullname. pub fn fullname(&self) -> Option<&StackRef> { unsafe { if (*self.as_ptr()).type_ != 0 { return None; } StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname) } } } impl Stackable for DistPoint { type StackType = ffi::stack_st_DIST_POINT; } 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(boringssl, 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(any(boringssl, ossl110, libressl350))] { 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, boringssl, 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(any(ossl110, libressl350, boringssl))] { 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); } } } cfg_if! { if #[cfg(any(ossl110, libressl350, boringssl))] { use ffi::{ X509_CRL_get_issuer, X509_CRL_get0_nextUpdate, X509_CRL_get0_lastUpdate, X509_CRL_get_REVOKED, X509_REVOKED_get0_revocationDate, X509_REVOKED_get0_serialNumber, }; } else { #[allow(bad_style)] unsafe fn X509_CRL_get0_lastUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { (*(*x).crl).lastUpdate } #[allow(bad_style)] unsafe fn X509_CRL_get0_nextUpdate(x: *const ffi::X509_CRL) -> *mut ffi::ASN1_TIME { (*(*x).crl).nextUpdate } #[allow(bad_style)] unsafe fn X509_CRL_get_issuer(x: *const ffi::X509_CRL) -> *mut ffi::X509_NAME { (*(*x).crl).issuer } #[allow(bad_style)] unsafe fn X509_CRL_get_REVOKED(x: *const ffi::X509_CRL) -> *mut ffi::stack_st_X509_REVOKED { (*(*x).crl).revoked } #[allow(bad_style)] unsafe fn X509_REVOKED_get0_serialNumber(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_INTEGER { (*x).serialNumber } #[allow(bad_style)] unsafe fn X509_REVOKED_get0_revocationDate(x: *const ffi::X509_REVOKED) -> *mut ffi::ASN1_TIME { (*x).revocationDate } } } #[derive(Copy, Clone, PartialEq, Eq)] pub struct X509PurposeId(c_int); impl X509PurposeId { pub const SSL_CLIENT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_CLIENT); pub const SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SSL_SERVER); pub const NS_SSL_SERVER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_NS_SSL_SERVER); pub const SMIME_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_SIGN); pub const SMIME_ENCRYPT: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_SMIME_ENCRYPT); pub const CRL_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CRL_SIGN); pub const ANY: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_ANY); pub const OCSP_HELPER: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_OCSP_HELPER); pub const TIMESTAMP_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_TIMESTAMP_SIGN); #[cfg(ossl320)] pub const CODE_SIGN: X509PurposeId = X509PurposeId(ffi::X509_PURPOSE_CODE_SIGN); /// Constructs an `X509PurposeId` from a raw OpenSSL value. pub fn from_raw(id: c_int) -> Self { X509PurposeId(id) } /// Returns the raw OpenSSL value represented by this type. pub fn as_raw(&self) -> c_int { self.0 } } /// A reference to an [`X509_PURPOSE`]. pub struct X509PurposeRef(Opaque); /// Implements a wrapper type for the static `X509_PURPOSE` table in OpenSSL. impl ForeignTypeRef for X509PurposeRef { type CType = ffi::X509_PURPOSE; } impl X509PurposeRef { /// Get the internal table index of an X509_PURPOSE for a given short name. Valid short /// names include /// - "sslclient", /// - "sslserver", /// - "nssslserver", /// - "smimesign", /// - "smimeencrypt", /// - "crlsign", /// - "any", /// - "ocsphelper", /// - "timestampsign" /// The index can be used with `X509PurposeRef::from_idx()` to get the purpose. #[allow(clippy::unnecessary_cast)] pub fn get_by_sname(sname: &str) -> Result { unsafe { let sname = CString::new(sname).unwrap(); cfg_if! { if #[cfg(any(ossl110, libressl280, boringssl))] { let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *const _))?; } else { let purpose = cvt_n(ffi::X509_PURPOSE_get_by_sname(sname.as_ptr() as *mut _))?; } } Ok(purpose) } } /// Get an `X509PurposeRef` for a given index value. The index can be obtained from e.g. /// `X509PurposeRef::get_by_sname()`. #[corresponds(X509_PURPOSE_get0)] pub fn from_idx(idx: c_int) -> Result<&'static X509PurposeRef, ErrorStack> { unsafe { let ptr = cvt_p_const(ffi::X509_PURPOSE_get0(idx))?; Ok(X509PurposeRef::from_const_ptr(ptr)) } } /// Get the purpose value from an X509Purpose structure. This value is one of /// - `X509_PURPOSE_SSL_CLIENT` /// - `X509_PURPOSE_SSL_SERVER` /// - `X509_PURPOSE_NS_SSL_SERVER` /// - `X509_PURPOSE_SMIME_SIGN` /// - `X509_PURPOSE_SMIME_ENCRYPT` /// - `X509_PURPOSE_CRL_SIGN` /// - `X509_PURPOSE_ANY` /// - `X509_PURPOSE_OCSP_HELPER` /// - `X509_PURPOSE_TIMESTAMP_SIGN` pub fn purpose(&self) -> X509PurposeId { unsafe { cfg_if! { if #[cfg(any(ossl110, libressl280, boringssl))] { let x509_purpose = self.as_ptr() as *const ffi::X509_PURPOSE; } else { let x509_purpose = self.as_ptr() as *mut ffi::X509_PURPOSE; } } X509PurposeId::from_raw(ffi::X509_PURPOSE_get_id(x509_purpose)) } } } openssl-0.10.64/src/x509/store.rs000064400000000000000000000240341046102023000144600ustar 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::asn1::Asn1Time; //! 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(); //! //! // Sep 27th, 2016 //! let sample_time = Asn1Time::from_unix(1474934400).unwrap(); //! //! 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.set_not_before(&sample_time); //! builder.set_not_after(&sample_time); //! 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::{ForeignType, ForeignTypeRef}; use std::mem; use crate::error::ErrorStack; #[cfg(not(boringssl))] use crate::ssl::SslFiletype; #[cfg(ossl300)] use crate::stack::Stack; use crate::stack::StackRef; use crate::util::ForeignTypeRefExt; #[cfg(any(ossl102, boringssl, libressl261))] use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef}; use crate::x509::{X509Object, X509PurposeId, X509}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; #[cfg(not(boringssl))] use std::ffi::CString; #[cfg(not(boringssl))] use std::path::Path; 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; /// A reference to an [`X509StoreBuilder`]. pub struct X509StoreBuilderRef; } impl X509StoreBuilder { /// Returns a builder for a certificate store. /// /// The store is initially empty. #[corresponds(X509_STORE_new)] 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 #[corresponds(X509_STORE_add_cert)] 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. #[corresponds(X509_STORE_set_default_paths)] 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. #[corresponds(X509_STORE_add_lookup)] 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. #[corresponds(X509_STORE_set_flags)] #[cfg(any(ossl102, boringssl, libressl261))] pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) } } /// Sets the certificate purpose. /// The purpose value can be obtained by `X509PurposeRef::get_by_sname()` #[corresponds(X509_STORE_set_purpose)] pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_STORE_set_purpose(self.as_ptr(), purpose.as_raw())).map(|_| ()) } } /// Sets certificate chain validation related parameters. #[corresponds[X509_STORE_set1_param]] #[cfg(any(ossl102, boringssl, libressl261))] pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())).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; /// A 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/manmaster/crypto/X509_LOOKUP_hash_dir.html // FIXME should be an enum 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. #[corresponds(X509_LOOKUP_hash_dir)] pub fn hash_dir() -> &'static X509LookupMethodRef { unsafe { X509LookupMethodRef::from_const_ptr(ffi::X509_LOOKUP_hash_dir()) } } } #[cfg(not(boringssl))] impl X509LookupRef { /// Specifies a directory from which certificates and CRLs will be loaded /// on-demand. Must be used with `X509Lookup::hash_dir`. #[corresponds(X509_LOOKUP_add_dir)] pub fn add_dir(&mut self, name: &str, file_type: SslFiletype) -> Result<(), ErrorStack> { let name = CString::new(name).unwrap(); unsafe { cvt(ffi::X509_LOOKUP_add_dir( self.as_ptr(), name.as_ptr(), file_type.as_raw(), )) .map(|_| ()) } } } /// Marker type corresponding to the [`X509_LOOKUP_file`] lookup method. /// /// [`X509_LOOKUP_file`]: https://www.openssl.org/docs/man1.1.1/man3/X509_LOOKUP_file.html pub struct File; impl X509Lookup { /// Lookup method loads all the certificates or CRLs present in a file /// into memory at the time the file is added as a lookup source. #[corresponds(X509_LOOKUP_file)] pub fn file() -> &'static X509LookupMethodRef { unsafe { X509LookupMethodRef::from_const_ptr(ffi::X509_LOOKUP_file()) } } } #[cfg(not(boringssl))] impl X509LookupRef { /// Specifies a file from which certificates will be loaded #[corresponds(X509_load_cert_file)] // FIXME should return 'Result>( &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::X509_load_cert_file( self.as_ptr(), file.as_ptr(), file_type.as_raw(), )) .map(|_| ()) } } /// Specifies a file from which certificate revocation lists will be loaded #[corresponds(X509_load_crl_file)] pub fn load_crl_file>( &mut self, file: P, file_type: SslFiletype, ) -> Result { let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap(); unsafe { cvt(ffi::X509_load_crl_file( self.as_ptr(), file.as_ptr(), file_type.as_raw(), )) } } } 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; /// A 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. /// /// This method is deprecated. It is **unsound** and will be removed in a /// future version of rust-openssl. `X509StoreRef::all_certificates` /// should be used instead. #[deprecated( note = "This method is unsound, and will be removed in a future version of rust-openssl. X509StoreRef::all_certificates should be used instead." )] #[corresponds(X509_STORE_get0_objects)] pub fn objects(&self) -> &StackRef { unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) } } /// Returns a stack of all the certificates in this store. #[corresponds(X509_STORE_get1_all_certs)] #[cfg(ossl300)] pub fn all_certificates(&self) -> Stack { unsafe { Stack::from_ptr(ffi::X509_STORE_get1_all_certs(self.as_ptr())) } } } cfg_if! { if #[cfg(any(boringssl, 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.64/src/x509/tests.rs000064400000000000000000001145301046102023000144670ustar 00000000000000use std::cmp::Ordering; use crate::asn1::{Asn1Object, Asn1OctetString, Asn1Time}; use crate::bn::{BigNum, MsbOption}; use crate::hash::MessageDigest; use crate::nid::Nid; use crate::pkey::{PKey, Private}; use crate::rsa::Rsa; #[cfg(not(boringssl))] use crate::ssl::SslFiletype; use crate::stack::Stack; use crate::x509::extension::{ AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, SubjectKeyIdentifier, }; #[cfg(not(boringssl))] use crate::x509::store::X509Lookup; use crate::x509::store::X509StoreBuilder; #[cfg(any(ossl102, boringssl, libressl261))] use crate::x509::verify::{X509VerifyFlags, X509VerifyParam}; #[cfg(any(ossl102, boringssl))] use crate::x509::X509PurposeId; #[cfg(any(ossl102, boringssl, libressl261))] use crate::x509::X509PurposeRef; #[cfg(ossl110)] use crate::x509::{CrlReason, X509Builder}; use crate::x509::{ CrlStatus, X509Crl, X509Extension, X509Name, X509Req, X509StoreContext, X509VerifyResult, X509, }; #[cfg(ossl110)] use foreign_types::ForeignType; use hex::{self, FromHex}; #[cfg(any(ossl102, boringssl, libressl261))] use libc::time_t; use super::{AuthorityInformationAccess, CertificateIssuer, ReasonCode}; 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); #[cfg(boringssl)] assert!(debugged.contains(r#"serial_number: "8771f7bdee982fa5""#)); #[cfg(not(boringssl))] 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] #[cfg(any(ossl110, boringssl))] fn test_retrieve_pathlen() { let cert = include_bytes!("../../test/root-ca.pem"); let cert = X509::from_pem(cert).unwrap(); assert_eq!(cert.pathlen(), None); let cert = include_bytes!("../../test/intermediate-ca.pem"); let cert = X509::from_pem(cert).unwrap(); assert_eq!(cert.pathlen(), Some(0)); let cert = include_bytes!("../../test/alt_name_cert.pem"); let cert = X509::from_pem(cert).unwrap(); assert_eq!(cert.pathlen(), None); } #[test] #[cfg(any(ossl110, boringssl))] fn test_subject_key_id() { let cert = include_bytes!("../../test/certv3.pem"); let cert = X509::from_pem(cert).unwrap(); let subject_key_id = cert.subject_key_id().unwrap(); assert_eq!( subject_key_id.as_slice(), &b"\xB6\x73\x2F\x61\xA5\x4B\xA1\xEF\x48\x2C\x15\xB1\x9F\xF3\xDC\x34\x2F\xBC\xAC\x30"[..] ); } #[test] #[cfg(any(ossl110, boringssl))] fn test_authority_key_id() { let cert = include_bytes!("../../test/certv3.pem"); let cert = X509::from_pem(cert).unwrap(); let authority_key_id = cert.authority_key_id().unwrap(); assert_eq!( authority_key_id.as_slice(), &b"\x6C\xD3\xA5\x03\xAB\x0D\x5F\x2C\xC9\x8D\x8A\x9C\x88\xA7\x88\x77\xB8\x37\xFD\x9A"[..] ); } #[test] #[cfg(ossl111d)] fn test_authority_issuer_and_serial() { let cert = include_bytes!("../../test/authority_key_identifier.pem"); let cert = X509::from_pem(cert).unwrap(); let authority_issuer = cert.authority_issuer().unwrap(); assert_eq!(1, authority_issuer.len()); let dn = authority_issuer[0].directory_name().unwrap(); let mut o = dn.entries_by_nid(Nid::ORGANIZATIONNAME); let o = o.next().unwrap().data().as_utf8().unwrap(); assert_eq!(o.as_bytes(), b"PyCA"); let mut cn = dn.entries_by_nid(Nid::COMMONNAME); let cn = cn.next().unwrap().data().as_utf8().unwrap(); assert_eq!(cn.as_bytes(), b"cryptography.io"); let authority_serial = cert.authority_serial().unwrap(); let serial = authority_serial.to_bn().unwrap(); let expected = BigNum::from_u32(3).unwrap(); assert_eq!(serial, expected); } #[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] // This tests `X509Extension::new`, even though its deprecated. #[allow(deprecated)] fn x509_extension_new() { assert!(X509Extension::new(None, None, "crlDistributionPoints", "section").is_err()); assert!(X509Extension::new(None, None, "proxyCertInfo", "").is_err()); assert!(X509Extension::new(None, None, "certificatePolicies", "").is_err()); assert!(X509Extension::new(None, None, "subjectAltName", "dirName:section").is_err()); } #[test] fn x509_extension_new_from_der() { let ext = X509Extension::new_from_der( &Asn1Object::from_str("2.5.29.19").unwrap(), true, &Asn1OctetString::new_from_bytes(b"\x30\x03\x01\x01\xff").unwrap(), ) .unwrap(); assert_eq!( ext.to_der().unwrap(), b"0\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff" ); } #[test] fn x509_extension_to_der() { let builder = X509::builder().unwrap(); for (ext, expected) in [ ( BasicConstraints::new().critical().ca().build().unwrap(), b"0\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff" as &[u8], ), ( SubjectAlternativeName::new() .dns("example.com,DNS:example2.com") .build(&builder.x509v3_context(None, None)) .unwrap(), b"0'\x06\x03U\x1d\x11\x04 0\x1e\x82\x1cexample.com,DNS:example2.com", ), ( SubjectAlternativeName::new() .rid("1.2.3.4") .uri("https://example.com") .build(&builder.x509v3_context(None, None)) .unwrap(), b"0#\x06\x03U\x1d\x11\x04\x1c0\x1a\x88\x03*\x03\x04\x86\x13https://example.com", ), ( ExtendedKeyUsage::new() .server_auth() .other("2.999.1") .other("clientAuth") .build() .unwrap(), b"0\x22\x06\x03U\x1d%\x04\x1b0\x19\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x03\x887\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x02", ), ] { assert_eq!(&ext.to_der().unwrap(), expected); } } #[test] fn eku_invalid_other() { assert!(ExtendedKeyUsage::new() .other("1.1.1.1.1,2.2.2.2.2") .build() .is_err()); } #[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(0).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, boringssl, 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" ) } #[test] #[cfg(any(ossl102, boringssl, libressl261))] fn test_verify_cert_with_purpose() { 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(); let purpose_idx = X509PurposeRef::get_by_sname("sslserver") .expect("Getting certificate purpose 'sslserver' failed"); let x509_purposeref = X509PurposeRef::from_idx(purpose_idx).expect("Getting certificate purpose failed"); store_bldr .set_purpose(x509_purposeref.purpose()) .expect("Setting certificate purpose failed"); 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, boringssl, libressl261))] fn test_verify_cert_with_wrong_purpose_fails() { 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(); let purpose_idx = X509PurposeRef::get_by_sname("timestampsign") .expect("Getting certificate purpose 'timestampsign' failed"); let x509_purpose = X509PurposeRef::from_idx(purpose_idx).expect("Getting certificate purpose failed"); store_bldr .set_purpose(x509_purpose.purpose()) .expect("Setting certificate purpose failed"); store_bldr.add_cert(ca).unwrap(); let store = store_bldr.build(); let expected_error = ffi::X509_V_ERR_INVALID_PURPOSE; let mut context = X509StoreContext::new().unwrap(); assert_eq!( context .init(&store, &cert, &chain, |c| { c.verify_cert()?; Ok(c.error()) }) .unwrap() .as_raw(), expected_error ) } #[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", ); } #[test] fn test_load_crl() { let ca = include_bytes!("../../test/crl-ca.crt"); let ca = X509::from_pem(ca).unwrap(); let crl = include_bytes!("../../test/test.crl"); let crl = X509Crl::from_der(crl).unwrap(); assert!(crl.verify(&ca.public_key().unwrap()).unwrap()); let cert = include_bytes!("../../test/subca.crt"); let cert = X509::from_pem(cert).unwrap(); let revoked = match crl.get_by_cert(&cert) { CrlStatus::Revoked(revoked) => revoked, _ => panic!("cert should be revoked"), }; assert_eq!( revoked.serial_number().to_bn().unwrap(), cert.serial_number().to_bn().unwrap(), "revoked and cert serial numbers should match" ); } #[test] fn test_crl_entry_extensions() { let crl = include_bytes!("../../test/entry_extensions.crl"); let crl = X509Crl::from_pem(crl).unwrap(); let (critical, access_info) = crl .extension::() .unwrap() .expect("Authority Information Access extension should be present"); assert!( !critical, "Authority Information Access extension is not critical" ); assert_eq!( access_info.len(), 1, "Authority Information Access should have one entry" ); assert_eq!(access_info[0].method().to_string(), "CA Issuers"); assert_eq!( access_info[0].location().uri(), Some("http://www.example.com/ca.crt") ); let revoked_certs = crl.get_revoked().unwrap(); let entry = &revoked_certs[0]; let (critical, issuer) = entry .extension::() .unwrap() .expect("Certificate issuer extension should be present"); assert!(critical, "Certificate issuer extension is critical"); assert_eq!(issuer.len(), 1, "Certificate issuer should have one entry"); let issuer = issuer[0] .directory_name() .expect("Issuer should be a directory name"); assert_eq!( format!("{:?}", issuer), r#"[countryName = "GB", commonName = "Test CA"]"# ); // reason_code can't be inspected without ossl110 #[allow(unused_variables)] let (critical, reason_code) = entry .extension::() .unwrap() .expect("Reason code extension should be present"); assert!(!critical, "Reason code extension is not critical"); #[cfg(ossl110)] assert_eq!( CrlReason::KEY_COMPROMISE, CrlReason::from_raw(reason_code.get_i64().unwrap() as ffi::c_int) ); } #[test] fn test_save_subject_der() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let der = cert.subject_name().to_der().unwrap(); println!("der: {:?}", der); assert!(!der.is_empty()); } #[test] fn test_load_subject_der() { // The subject from ../../test/cert.pem const SUBJECT_DER: &[u8] = &[ 48, 90, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 65, 85, 49, 19, 48, 17, 6, 3, 85, 4, 8, 12, 10, 83, 111, 109, 101, 45, 83, 116, 97, 116, 101, 49, 33, 48, 31, 6, 3, 85, 4, 10, 12, 24, 73, 110, 116, 101, 114, 110, 101, 116, 32, 87, 105, 100, 103, 105, 116, 115, 32, 80, 116, 121, 32, 76, 116, 100, 49, 19, 48, 17, 6, 3, 85, 4, 3, 12, 10, 102, 111, 111, 98, 97, 114, 46, 99, 111, 109, ]; X509Name::from_der(SUBJECT_DER).unwrap(); } #[test] fn test_convert_to_text() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); const SUBSTRINGS: &[&str] = &[ "Certificate:\n", "Serial Number:", "Signature Algorithm:", "Issuer: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd\n", "Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=foobar.com\n", "Subject Public Key Info:", ]; let text = String::from_utf8(cert.to_text().unwrap()).unwrap(); for substring in SUBSTRINGS { assert!( text.contains(substring), "{:?} not found inside {}", substring, text ); } } #[test] fn test_convert_req_to_text() { let csr = include_bytes!("../../test/csr.pem"); let csr = X509Req::from_pem(csr).unwrap(); const SUBSTRINGS: &[&str] = &[ "Certificate Request:\n", "Version:", "Subject: C=AU, ST=Some-State, O=Internet Widgits Pty Ltd, CN=foobar.com\n", "Subject Public Key Info:", "Signature Algorithm:", ]; let text = String::from_utf8(csr.to_text().unwrap()).unwrap(); for substring in SUBSTRINGS { assert!( text.contains(substring), "{:?} not found inside {}", substring, text ); } } #[test] fn test_name_cmp() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let subject = cert.subject_name(); let issuer = cert.issuer_name(); assert_eq!(Ordering::Equal, subject.try_cmp(subject).unwrap()); assert_eq!(Ordering::Greater, subject.try_cmp(issuer).unwrap()); } #[test] #[cfg(any(boringssl, ossl110, libressl270))] fn test_name_to_owned() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let name = cert.subject_name(); let copied_name = name.to_owned().unwrap(); assert_eq!(Ordering::Equal, name.try_cmp(&copied_name).unwrap()); } #[test] #[cfg(any(ossl102, boringssl, libressl261))] fn test_verify_param_set_time_fails_verification() { const TEST_T_2030: time_t = 1893456000; 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 mut verify_params = X509VerifyParam::new().unwrap(); verify_params.set_time(TEST_T_2030); store_bldr.set_param(&verify_params).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(), "certificate has expired" ) } #[test] #[cfg(any(ossl102, boringssl, libressl261))] fn test_verify_param_set_time() { const TEST_T_2020: time_t = 1577836800; 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 mut verify_params = X509VerifyParam::new().unwrap(); verify_params.set_time(TEST_T_2020); store_bldr.set_param(&verify_params).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, boringssl, libressl261))] fn test_verify_param_set_depth() { let cert = include_bytes!("../../test/leaf.pem"); let cert = X509::from_pem(cert).unwrap(); let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem"); let intermediate_ca = X509::from_pem(intermediate_ca).unwrap(); let ca = include_bytes!("../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); let mut chain = Stack::new().unwrap(); chain.push(intermediate_ca).unwrap(); let mut store_bldr = X509StoreBuilder::new().unwrap(); store_bldr.add_cert(ca).unwrap(); let mut verify_params = X509VerifyParam::new().unwrap(); // OpenSSL 1.1.0+ considers the root certificate to not be part of the chain, while 1.0.2 and LibreSSL do let expected_depth = if cfg!(any(ossl110)) { 1 } else { 2 }; verify_params.set_depth(expected_depth); store_bldr.set_param(&verify_params).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, boringssl, libressl261))] #[allow(clippy::bool_to_int_with_if)] fn test_verify_param_set_depth_fails_verification() { let cert = include_bytes!("../../test/leaf.pem"); let cert = X509::from_pem(cert).unwrap(); let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem"); let intermediate_ca = X509::from_pem(intermediate_ca).unwrap(); let ca = include_bytes!("../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); let mut chain = Stack::new().unwrap(); chain.push(intermediate_ca).unwrap(); let mut store_bldr = X509StoreBuilder::new().unwrap(); store_bldr.add_cert(ca).unwrap(); let mut verify_params = X509VerifyParam::new().unwrap(); // OpenSSL 1.1.0+ considers the root certificate to not be part of the chain, while 1.0.2 and LibreSSL do let expected_depth = if cfg!(any(ossl110)) { 0 } else { 1 }; verify_params.set_depth(expected_depth); store_bldr.set_param(&verify_params).unwrap(); let store = store_bldr.build(); // OpenSSL 1.1.0+ added support for X509_V_ERR_CERT_CHAIN_TOO_LONG, while 1.0.2 simply ignores the intermediate let expected_error = if cfg!(any(ossl110, libressl261)) { "certificate chain too long" } else { "unable to get local issuer certificate" }; let mut context = X509StoreContext::new().unwrap(); assert_eq!( context .init(&store, &cert, &chain, |c| { c.verify_cert()?; Ok(c.error()) }) .unwrap() .error_string(), expected_error ) } #[test] #[cfg(not(boringssl))] fn test_load_cert_file() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let chain = Stack::new().unwrap(); let mut store_bldr = X509StoreBuilder::new().unwrap(); let lookup = store_bldr.add_lookup(X509Lookup::file()).unwrap(); lookup .load_cert_file("test/root-ca.pem", SslFiletype::PEM) .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(ossl110)] fn test_verify_param_auth_level() { let mut param = X509VerifyParam::new().unwrap(); let auth_lvl = 2; let auth_lvl_default = -1; assert_eq!(param.auth_level(), auth_lvl_default); param.set_auth_level(auth_lvl); assert_eq!(param.auth_level(), auth_lvl); } #[test] #[cfg(any(ossl102, boringssl))] fn test_set_purpose() { let cert = include_bytes!("../../test/leaf.pem"); let cert = X509::from_pem(cert).unwrap(); let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem"); let intermediate_ca = X509::from_pem(intermediate_ca).unwrap(); let ca = include_bytes!("../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); let mut chain = Stack::new().unwrap(); chain.push(intermediate_ca).unwrap(); let mut store_bldr = X509StoreBuilder::new().unwrap(); store_bldr.add_cert(ca).unwrap(); let mut verify_params = X509VerifyParam::new().unwrap(); verify_params.set_purpose(X509PurposeId::ANY).unwrap(); store_bldr.set_param(&verify_params).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, boringssl))] fn test_set_purpose_fails_verification() { let cert = include_bytes!("../../test/leaf.pem"); let cert = X509::from_pem(cert).unwrap(); let intermediate_ca = include_bytes!("../../test/intermediate-ca.pem"); let intermediate_ca = X509::from_pem(intermediate_ca).unwrap(); let ca = include_bytes!("../../test/root-ca.pem"); let ca = X509::from_pem(ca).unwrap(); let mut chain = Stack::new().unwrap(); chain.push(intermediate_ca).unwrap(); let mut store_bldr = X509StoreBuilder::new().unwrap(); store_bldr.add_cert(ca).unwrap(); let mut verify_params = X509VerifyParam::new().unwrap(); verify_params .set_purpose(X509PurposeId::TIMESTAMP_SIGN) .unwrap(); store_bldr.set_param(&verify_params).unwrap(); let store = store_bldr.build(); let expected_error = ffi::X509_V_ERR_INVALID_PURPOSE; let mut context = X509StoreContext::new().unwrap(); assert_eq!( context .init(&store, &cert, &chain, |c| { c.verify_cert()?; Ok(c.error()) }) .unwrap() .as_raw(), expected_error ) } #[test] #[cfg(any(ossl101, libressl350))] fn test_add_name_entry() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let inp_name = cert.subject_name().entries().next().unwrap(); let mut names = X509Name::builder().unwrap(); names.append_entry(inp_name).unwrap(); let names = names.build(); let mut entries = names.entries(); let outp_name = entries.next().unwrap(); assert_eq!(outp_name.object().nid(), inp_name.object().nid()); assert_eq!(outp_name.data().as_slice(), inp_name.data().as_slice()); assert!(entries.next().is_none()); } #[test] #[cfg(not(boringssl))] fn test_load_crl_file_fail() { let mut store_bldr = X509StoreBuilder::new().unwrap(); let lookup = store_bldr.add_lookup(X509Lookup::file()).unwrap(); let res = lookup.load_crl_file("test/root-ca.pem", SslFiletype::PEM); assert!(res.is_err()); } #[cfg(ossl110)] fn ipaddress_as_subject_alternative_name_is_formatted_in_debug(expected_ip: T) where T: Into, { let expected_ip = format!("{:?}", expected_ip.into()); let mut builder = X509Builder::new().unwrap(); let san = SubjectAlternativeName::new() .ip(&expected_ip) .build(&builder.x509v3_context(None, None)) .unwrap(); builder.append_extension(san).unwrap(); let cert = builder.build(); let actual_ip = cert .subject_alt_names() .into_iter() .flatten() .map(|n| format!("{:?}", *n)) .next() .unwrap(); assert_eq!(actual_ip, expected_ip); } #[cfg(ossl110)] #[test] fn ipv4_as_subject_alternative_name_is_formatted_in_debug() { ipaddress_as_subject_alternative_name_is_formatted_in_debug([8u8, 8, 8, 128]); } #[cfg(ossl110)] #[test] fn ipv6_as_subject_alternative_name_is_formatted_in_debug() { ipaddress_as_subject_alternative_name_is_formatted_in_debug([ 8u8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 128, ]); } #[cfg(ossl110)] #[test] fn other_name_as_subject_alternative_name() { let oid = Asn1Object::from_str("1.3.6.1.5.5.7.8.11").unwrap(); // this is the hex representation of "test" encoded as a ia5string let content = [0x16, 0x04, 0x74, 0x65, 0x73, 0x74]; let mut builder = X509Builder::new().unwrap(); let san = SubjectAlternativeName::new() .other_name2(oid, &content) .build(&builder.x509v3_context(None, None)) .unwrap(); builder.append_extension(san).unwrap(); let cert = builder.build(); let general_name = cert .subject_alt_names() .into_iter() .flatten() .next() .unwrap(); unsafe { assert_eq!((*general_name.as_ptr()).type_, 0); } } #[test] fn test_dist_point() { let cert = include_bytes!("../../test/certv3.pem"); let cert = X509::from_pem(cert).unwrap(); let dps = cert.crl_distribution_points().unwrap(); let dp = dps.get(0).unwrap(); let dp_nm = dp.distpoint().unwrap(); let dp_gns = dp_nm.fullname().unwrap(); let dp_gn = dp_gns.get(0).unwrap(); assert_eq!(dp_gn.uri().unwrap(), "http://example.com/crl.pem"); let dp = dps.get(1).unwrap(); let dp_nm = dp.distpoint().unwrap(); let dp_gns = dp_nm.fullname().unwrap(); let dp_gn = dp_gns.get(0).unwrap(); assert_eq!(dp_gn.uri().unwrap(), "http://example.com/crl2.pem"); assert!(dps.get(2).is_none()) } #[test] fn test_dist_point_null() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); assert!(cert.crl_distribution_points().is_none()); } #[test] #[cfg(ossl300)] fn test_store_all_certificates() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); let store = { let mut b = X509StoreBuilder::new().unwrap(); b.add_cert(cert).unwrap(); b.build() }; assert_eq!(store.all_certificates().len(), 1); } openssl-0.10.64/src/x509/verify.rs000064400000000000000000000176121046102023000146340ustar 00000000000000use bitflags::bitflags; use foreign_types::ForeignTypeRef; use libc::{c_int, c_uint, c_ulong, time_t}; use std::net::IpAddr; use crate::error::ErrorStack; #[cfg(any(ossl102, boringssl))] use crate::x509::X509PurposeId; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; bitflags! { /// Flags used to check an `X509` certificate. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pub struct X509CheckFlags: c_uint { const ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT as _; const NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS as _; const NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS as _; const MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS as _; const SINGLE_LABEL_SUBDOMAINS = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS as _; /// 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 as _; } } bitflags! { /// Flags used to verify an `X509` certificate chain. #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(transparent)] pub struct X509VerifyFlags: c_ulong { const CB_ISSUER_CHECK = ffi::X509_V_FLAG_CB_ISSUER_CHECK as _; const USE_CHECK_TIME = ffi::X509_V_FLAG_USE_CHECK_TIME as _; const CRL_CHECK = ffi::X509_V_FLAG_CRL_CHECK as _; const CRL_CHECK_ALL = ffi::X509_V_FLAG_CRL_CHECK_ALL as _; const IGNORE_CRITICAL = ffi::X509_V_FLAG_IGNORE_CRITICAL as _; const X509_STRICT = ffi::X509_V_FLAG_X509_STRICT as _; const ALLOW_PROXY_CERTS = ffi::X509_V_FLAG_ALLOW_PROXY_CERTS as _; const POLICY_CHECK = ffi::X509_V_FLAG_POLICY_CHECK as _; const EXPLICIT_POLICY = ffi::X509_V_FLAG_EXPLICIT_POLICY as _; const INHIBIT_ANY = ffi::X509_V_FLAG_INHIBIT_ANY as _; const INHIBIT_MAP = ffi::X509_V_FLAG_INHIBIT_MAP as _; const NOTIFY_POLICY = ffi::X509_V_FLAG_NOTIFY_POLICY as _; const EXTENDED_CRL_SUPPORT = ffi::X509_V_FLAG_EXTENDED_CRL_SUPPORT as _; const USE_DELTAS = ffi::X509_V_FLAG_USE_DELTAS as _; const CHECK_SS_SIGNATURE = ffi::X509_V_FLAG_CHECK_SS_SIGNATURE as _; #[cfg(any(ossl102, boringssl))] const TRUSTED_FIRST = ffi::X509_V_FLAG_TRUSTED_FIRST as _; #[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(any(ossl102, boringssl))] const PARTIAL_CHAIN = ffi::X509_V_FLAG_PARTIAL_CHAIN as _; #[cfg(any(ossl110, boringssl))] const NO_ALT_CHAINS = ffi::X509_V_FLAG_NO_ALT_CHAINS as _; #[cfg(any(ossl110, boringssl))] const NO_CHECK_TIME = ffi::X509_V_FLAG_NO_CHECK_TIME as _; } } 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 X509VerifyParam { /// Create an X509VerifyParam #[corresponds(X509_VERIFY_PARAM_new)] pub fn new() -> Result { unsafe { ffi::init(); cvt_p(ffi::X509_VERIFY_PARAM_new()).map(X509VerifyParam) } } } impl X509VerifyParamRef { /// Set the host flags. #[corresponds(X509_VERIFY_PARAM_set_hostflags)] pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) { unsafe { ffi::X509_VERIFY_PARAM_set_hostflags(self.as_ptr(), hostflags.bits()); } } /// Set verification flags. #[corresponds(X509_VERIFY_PARAM_set_flags)] 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. #[corresponds(X509_VERIFY_PARAM_clear_flags)] 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. #[corresponds(X509_VERIFY_PARAM_get_flags)] pub fn flags(&mut self) -> X509VerifyFlags { let bits = unsafe { ffi::X509_VERIFY_PARAM_get_flags(self.as_ptr()) }; X509VerifyFlags::from_bits_retain(bits) } /// Set the expected DNS hostname. #[corresponds(X509_VERIFY_PARAM_set1_host)] pub fn set_host(&mut self, host: &str) -> Result<(), ErrorStack> { unsafe { // len == 0 means "run strlen" :( let raw_host = if host.is_empty() { "\0" } else { host }; cvt(ffi::X509_VERIFY_PARAM_set1_host( self.as_ptr(), raw_host.as_ptr() as *const _, host.len(), )) .map(|_| ()) } } /// Set the expected email address. #[corresponds(X509_VERIFY_PARAM_set1_email)] pub fn set_email(&mut self, email: &str) -> Result<(), ErrorStack> { unsafe { // len == 0 means "run strlen" :( let raw_email = if email.is_empty() { "\0" } else { email }; cvt(ffi::X509_VERIFY_PARAM_set1_email( self.as_ptr(), raw_email.as_ptr() as *const _, email.len(), )) .map(|_| ()) } } /// Set the expected IPv4 or IPv6 address. #[corresponds(X509_VERIFY_PARAM_set1_ip)] 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(|_| ()) } } /// Set the verification time, where time is of type time_t, traditionaly defined as seconds since the epoch #[corresponds(X509_VERIFY_PARAM_set_time)] pub fn set_time(&mut self, time: time_t) { unsafe { ffi::X509_VERIFY_PARAM_set_time(self.as_ptr(), time) } } /// Set the verification depth #[corresponds(X509_VERIFY_PARAM_set_depth)] pub fn set_depth(&mut self, depth: c_int) { unsafe { ffi::X509_VERIFY_PARAM_set_depth(self.as_ptr(), depth) } } /// Sets the authentication security level to auth_level #[corresponds(X509_VERIFY_PARAM_set_auth_level)] #[cfg(ossl110)] pub fn set_auth_level(&mut self, lvl: c_int) { unsafe { ffi::X509_VERIFY_PARAM_set_auth_level(self.as_ptr(), lvl) } } /// Gets the current authentication security level #[corresponds(X509_VERIFY_PARAM_get_auth_level)] #[cfg(ossl110)] pub fn auth_level(&self) -> i32 { unsafe { ffi::X509_VERIFY_PARAM_get_auth_level(self.as_ptr()) } } /// Sets the verification purpose #[corresponds(X509_VERIFY_PARAM_set_purpose)] #[cfg(any(ossl102, boringssl))] pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_VERIFY_PARAM_set_purpose(self.as_ptr(), purpose.0)).map(|_| ()) } } } openssl-0.10.64/test/aia_test_cert.pem000064400000000000000000000024521046102023000157520ustar 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.64/test/alt_name_cert.pem000064400000000000000000000024721046102023000157430ustar 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.64/test/authority_key_identifier.pem000064400000000000000000000021731046102023000202460ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDIjCCAgqgAwIBAgIBAzANBgkqhkiG9w0BAQUFADApMQ0wCwYDVQQKDARQeUNB MRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcNMTUwNTAzMDk0OTU2WhcNMTYw NTAyMDk0OTU2WjApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFw aHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCadi1UZioxdnP ajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLOhjNLz6PO6KeRbjz9GhTA2hdk xtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4cMwMe5NGeeg1tfzbJwldIN+cK vabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr6E9puord3h6Mh8Jfnc3TDAq8 Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk/XhRzt8Xcfc3yAXIwazvLf8b YP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+qUYpxA7ZJ/VAGadMulYbXaO8 Syi39HTpAgMBAAGjVTBTMFEGA1UdIwRKMEiAFDlFPso9Yh3qhkn2WqtAt6RwmPHs oS2kKzApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW+C AQMwDQYJKoZIhvcNAQEFBQADggEBAFbZYy6aZJUK/f7nJx2Rs/ht6hMbM32/RoXZ JGbYapNVqVu/vymcfc/se3FHS5OVmPsnRlo/FIKDn/r5DGl73Sn/FvDJiLJZFucT msyYuHZ+ZRYWzWmN2fcB3cfxj0s3qps6f5OoCOqoINOSe4HRGlw4X9keZSD+3xAt vHNwQdlPC7zWbPdrzLT+FqR0e/O81vFJJS6drHJWqPcR3NQVtZw+UF7A/HKwbfeL Nu2zj6165hzOi9HUxa2/mPr/eLUUV1sTzXp2+TFjt3rVCjW1XnpMLdwNBHzjpyAB dTOX3iw0+BPy3s2jtnCW1PLpc74kvSTaBwhg74sq39EXfIKax00= -----END CERTIFICATE----- openssl-0.10.64/test/ca.crt000064400000000000000000000107271046102023000135420ustar 00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 13:ae:da:d8:f4:18:d7:73:b8:bd:35:c9:ce:8e:b3:fc Signature Algorithm: sha256WithRSAEncryption Issuer: CN=TestCA Validity Not Before: Jun 6 19:11:19 2019 GMT Not After : May 21 19:11:19 2022 GMT Subject: CN=SubCA Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:b0:09:fc:54:e7:6a:9f:0c:bd:ad:5a:8d:ef:94: 4e:11:a6:87:19:4f:bf:a6:e1:62:a5:2d:b7:17:df: 67:53:70:da:fe:7d:99:17:ee:13:47:0b:40:0b:a2: 34:32:a9:d3:bf:20:fc:13:77:a1:d5:26:60:1f:f0: d4:be:dc:76:7c:1e:6c:b4:4c:01:7c:56:cd:5c:53: ec:81:b3:81:2a:b2:35:26:06:5a:79:e0:b3:9e:e4: 57:e1:09:de:ad:7f:c8:cd:87:ee:49:93:30:52:58: b2:bc:0f:c1:b6:10:44:f8:85:d5:5b:0a:9b:28:fe: f4:f4:4a:16:a6:f7:25:e9:96:47:69:73:5b:33:77: 92:7d:61:8d:2a:3d:d5:04:89:40:bf:6b:d2:fd:5d: e2:1a:80:a9:8e:c8:92:f6:e5:4c:00:84:f9:6e:2a: 93:a3:23:ee:28:23:81:f4:54:f0:18:2c:ee:32:8e: 38:9c:a0:c8:33:04:b0:fc:4c:43:1a:5c:04:84:9f: 73:c6:08:c7:1d:64:39:fe:72:19:3b:cc:a5:fd:0b: 43:25:0d:2b:a9:88:77:9e:62:e6:ac:c2:9a:60:42: 4f:4a:54:47:bc:a0:29:72:7c:38:52:c9:ea:27:c5: 3d:d0:81:4a:3e:b8:78:79:4b:89:b8:4e:6d:1b:24: 15:bd Exponent: 65537 (0x10001) X509v3 extensions: X509v3 CRL Distribution Points: Full Name: URI:http://127.0.0.1:8081/pki/test.crl X509v3 Basic Constraints: CA:TRUE X509v3 Subject Key Identifier: FD:82:45:39:A1:91:41:F2:66:CC:0D:75:D5:0D:40:D5:81:A7:A1:43 X509v3 Authority Key Identifier: keyid:C5:CC:F5:A1:8C:D9:E4:A7:BA:EC:21:F5:D1:84:23:EA:0D:C2:C7:30 DirName:/CN=TestCA serial:33:E7:04:87:09:32:87:21:D9:CD:7C:AA:4C:5A:BB:2C:6C:7B:54:28 X509v3 Key Usage: Certificate Sign, CRL Sign Signature Algorithm: sha256WithRSAEncryption 96:a0:ff:8a:4b:bd:45:96:c9:72:3c:63:e3:48:c4:ab:ef:7e: db:76:3f:d9:02:9e:69:c8:d9:36:55:e1:f5:9b:c9:69:d8:69: 02:ac:50:8c:60:94:2c:2e:b9:a8:65:ac:f5:00:b0:8b:96:25: 0b:8a:ef:94:21:57:e2:04:c2:c3:86:bf:06:4e:91:5c:e6:bc: 1b:03:31:8b:64:ea:c5:79:c3:5c:94:e5:aa:67:7e:74:12:07: 14:fd:cd:32:02:26:26:c9:0a:ed:d4:da:ee:2a:84:e3:f1:60: b3:09:77:27:a1:3c:ac:ec:61:18:30:b5:6d:1f:16:0a:24:1a: cf:1c:1b:60:a5:60:e5:2c:8b:cf:37:83:0c:15:e7:79:30:3f: ee:50:45:7c:4b:c6:2c:cd:2c:81:0a:98:f1:65:44:7a:ca:2a: 20:1a:de:19:d9:4b:ca:a1:e2:a4:b5:14:47:bf:b4:68:15:03: c0:55:e5:f4:47:0e:55:9f:fe:85:d8:2c:7d:d0:1a:96:11:b9: 68:b7:74:1e:61:94:c1:ae:87:52:2d:c6:26:ba:51:ed:f1:91: c0:e6:4c:f8:ad:02:23:75:51:fc:f8:69:05:ec:cf:31:50:5a: 41:78:eb:3d:27:4d:9b:68:ef:ba:0e:ba:3a:7d:60:00:9d:53: a5:08:3d:c6 -----BEGIN CERTIFICATE----- MIIDbDCCAlSgAwIBAgIQE67a2PQY13O4vTXJzo6z/DANBgkqhkiG9w0BAQsFADAR MQ8wDQYDVQQDDAZUZXN0Q0EwHhcNMTkwNjA2MTkxMTE5WhcNMjIwNTIxMTkxMTE5 WjAQMQ4wDAYDVQQDDAVTdWJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALAJ/FTnap8Mva1aje+UThGmhxlPv6bhYqUttxffZ1Nw2v59mRfuE0cLQAui NDKp078g/BN3odUmYB/w1L7cdnwebLRMAXxWzVxT7IGzgSqyNSYGWnngs57kV+EJ 3q1/yM2H7kmTMFJYsrwPwbYQRPiF1VsKmyj+9PRKFqb3JemWR2lzWzN3kn1hjSo9 1QSJQL9r0v1d4hqAqY7IkvblTACE+W4qk6Mj7igjgfRU8Bgs7jKOOJygyDMEsPxM QxpcBISfc8YIxx1kOf5yGTvMpf0LQyUNK6mId55i5qzCmmBCT0pUR7ygKXJ8OFLJ 6ifFPdCBSj64eHlLibhObRskFb0CAwEAAaOBwDCBvTAzBgNVHR8ELDAqMCigJqAk hiJodHRwOi8vMTI3LjAuMC4xOjgwODEvcGtpL3Rlc3QuY3JsMAwGA1UdEwQFMAMB Af8wHQYDVR0OBBYEFP2CRTmhkUHyZswNddUNQNWBp6FDMEwGA1UdIwRFMEOAFMXM 9aGM2eSnuuwh9dGEI+oNwscwoRWkEzARMQ8wDQYDVQQDDAZUZXN0Q0GCFDPnBIcJ Moch2c18qkxauyxse1QoMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA lqD/iku9RZbJcjxj40jEq+9+23Y/2QKeacjZNlXh9ZvJadhpAqxQjGCULC65qGWs 9QCwi5YlC4rvlCFX4gTCw4a/Bk6RXOa8GwMxi2TqxXnDXJTlqmd+dBIHFP3NMgIm JskK7dTa7iqE4/Fgswl3J6E8rOxhGDC1bR8WCiQazxwbYKVg5SyLzzeDDBXneTA/ 7lBFfEvGLM0sgQqY8WVEesoqIBreGdlLyqHipLUUR7+0aBUDwFXl9EcOVZ/+hdgs fdAalhG5aLd0HmGUwa6HUi3GJrpR7fGRwOZM+K0CI3VR/PhpBezPMVBaQXjrPSdN m2jvug66On1gAJ1TpQg9xg== -----END CERTIFICATE----- openssl-0.10.64/test/cert.pem000064400000000000000000000021631046102023000141000ustar 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.64/test/certs.pem000064400000000000000000000045001046102023000142600ustar 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.64/test/certv3.pem000064400000000000000000000025231046102023000143510ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDwTCCAqmgAwIBAgIUDeCGNunyJfBd3U/qUtmCcvbMyZwwDQYJKoZIhvcNAQEL BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzAxMjMxMzMzNTJaFw0zMzAx MjAxMzMzNTJaMFoxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmZvb2Jh ci5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo9CWMRLMXo1CF /iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt OzboKgs1AgMBAAGjgZMwgZAwTgYDVR0fBEcwRTAgoB6gHIYaaHR0cDovL2V4YW1w bGUuY29tL2NybC5wZW0wIaAfoB2GG2h0dHA6Ly9leGFtcGxlLmNvbS9jcmwyLnBl bTAdBgNVHQ4EFgQUtnMvYaVLoe9ILBWxn/PcNC+8rDAwHwYDVR0jBBgwFoAUbNOl A6sNXyzJjYqciKeId7g3/ZowDQYJKoZIhvcNAQELBQADggEBAJZyk6Eo4p3JIyOt 7t6ET3K18BKvlRilze+zrGkaQYvKRsP6YzbZWgcIq59hy5VeFCX5O2WP91CPG3MU I9eRiih66/ry3G4I8QEdpRKnn0N5unbGjb5qPT5wXrhU4IO+vn3sGZGM4uIM1/3K N/bOh9CTsu9YqrdHSGeDyNzCy/XZ/j5bP4aNm31ZDNCZDFsbjr3/yTLcpHPL0UP3 mCX8D16BDu1Nep+wK9VRuOEw6Z9tlT/VjTImzoOUoJO/o2UHfSHahX+n2aC5OpI6 BdhaFBuJ1vn+yTWf3zIjhWUdp9TlzgRyFiyetP2FcKwremVVGdDq/Y6dfXaq8CA1 6Fr9KTY= -----END CERTIFICATE----- openssl-0.10.64/test/certv3_extfile000064400000000000000000000001251046102023000153050ustar 00000000000000crlDistributionPoints=URI:http://example.com/crl.pem,URI:http://example.com/crl2.pem openssl-0.10.64/test/cms.p12000064400000000000000000000032551046102023000135510ustar 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.64/test/cms_pubkey.der000064400000000000000000000012601046102023000152720ustar 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.64/test/crl-ca.crt000064400000000000000000000022401046102023000143070ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDPDCCAiSgAwIBAgIUM+cEhwkyhyHZzXyqTFq7LGx7VCgwDQYJKoZIhvcNAQEL BQAwETEPMA0GA1UEAwwGVGVzdENBMB4XDTE5MDYwNjE5MTA1NVoXDTI5MDYwMzE5 MTA1NVowETEPMA0GA1UEAwwGVGVzdENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A MIIBCgKCAQEAtNcFPtD1MHcolhgTHIAx/b9OyawCbVzvgasv8R9+94ZMhoGc/tNc dVg271pCSmj+zYAFYsIwjxW+iq2e5A/fiBc6uqtNfEbU7+77QzxFG5wIbXtmmqEb dVbqBT28NeKTR6X+EHlNgbw90CHy7byA7LMewxbTt2q1eY1RnB0ji8zdGZmIUPeC WxzkxXEd0fg+KwBFN3YHV9CJX2KJ10qv7DvbKHeIVBU7osm6tzvNglNnnT90GFSY zc59b+zS00axcY3Kn08Vt+1qWB9Sl8tixCTGqR538y/ambDr3NCWsiQYWys9KE1L g0nEaIjb84R7b+qNmPtOezd9tanx7j9UzQIDAQABo4GLMIGIMB0GA1UdDgQWBBTF zPWhjNnkp7rsIfXRhCPqDcLHMDBMBgNVHSMERTBDgBTFzPWhjNnkp7rsIfXRhCPq DcLHMKEVpBMwETEPMA0GA1UEAwwGVGVzdENBghQz5wSHCTKHIdnNfKpMWrssbHtU KDAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA gdyQq6F8DO5rn7rZSLehTFx6tbtfncC/BOXZEGLZO0ciTrQ9Q8xHwRhz0W09QE1A /GsBzb++PuvAl9i82WvunyPB5KZh+GPiaaqf466MdQrXj+IyqxeC9Lg9wEUjwRgp ANVd3moKap5IZ9WDvhyEng2Oy8/btP2iqVEmd58rGAodd671eOPD8QkIxSquiIwy Cu5s3IBZ0BOuSG9fWoyPTGMKAhzQPFiXGvWOabCkMz3TsPYVY5ENpq2K8cWn2D/r TD1yPPdINg6HrALGD3S0sD+k588oS7U5oj1L8V4KJQTLSbh6/XcBpasa5Jdv7ZZe lVgt69Gsn5Cf2BkbwhbF2Q== -----END CERTIFICATE----- openssl-0.10.64/test/csr.pem000064400000000000000000000066201046102023000137340ustar 00000000000000Certificate Request: Data: Version: 1 (0x0) Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = foobar.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:a8:f4:25:8c:44:b3:17:a3:50:85:fe:23:91:87: d0:78:36:1b:49:17:ff:2d:47:d3:e5:1b:de:6c:36: fc:96:b9:04:3f:f2:37:de:bf:ef:33:12:ba:65:c5: f2:e4:b7:4a:49:a9:ca:22:64:6f:20:f4:d5:34:91: 4e:a8:e5:3f:bf:d5:08:19:72:50:80:a1:96:92:d0: 9a:b1:9a:8a:36:62:4f:f5:42:c8:f5:ea:99:cc:05: cd:74:b9:20:e4:e9:5f:5a:25:25:f5:bc:ac:0e:35: 53:52:c2:21:c0:d4:c8:57:fa:2e:d6:7f:bf:ca:d2: 78:aa:fa:4e:e1:3a:48:65:78:59:16:81:9b:54:ab: 8d:60:5e:1d:55:7c:eb:a0:91:ae:d4:92:d6:27:93: d9:ab:05:b0:0c:8e:66:a5:a1:93:67:da:93:0c:01: 0c:55:83:84:e1:88:b9:b7:ce:fb:96:aa:f5:c0:49: 6c:d4:65:ce:c8:01:dd:46:6c:de:00:b4:3b:a1:b3: 6e:76:7a:a1:3d:13:88:93:1e:4e:c5:d7:8c:00:4b: 52:56:aa:fe:ba:ea:14:5e:18:7a:e6:64:91:b1:d3: 14:13:33:db:cf:0f:51:cd:e6:dd:94:dc:a4:df:84: ef:e6:4e:50:14:59:5c:a0:f6:d0:ad:3b:36:e8:2a: 0b:35 Exponent: 65537 (0x10001) Attributes: a0:00 Signature Algorithm: sha256WithRSAEncryption 95:26:e1:84:56:e7:80:da:2c:a4:c0:b5:85:43:61:85:34:84: 37:83:c0:bc:cf:70:20:89:46:ce:3d:7e:23:8a:40:a4:a5:fa: c5:e3:3d:ee:e5:05:16:58:93:f9:6c:f3:86:ee:99:cc:e1:04: 5c:68:99:da:66:72:a1:95:31:cd:13:6f:a5:6f:fc:a9:ec:75: 6a:f7:e5:cf:0e:7b:5f:2f:db:8d:45:e6:66:52:12:1d:c9:ac: 3a:86:35:bd:1f:7b:6e:b5:e1:f3:4f:80:6a:06:73:1c:a0:0d: a3:63:b6:40:76:25:b0:e9:96:33:7a:9d:18:7e:5e:93:c0:47: d7:0b:da:b3:03:17:94:d0:0c:78:18:f3:0e:cd:3c:f7:e8:25: 08:c2:13:0a:af:1e:5c:48:5f:17:41:b2:2d:d2:0f:37:2e:b3: 10:fd:2b:c0:77:e1:17:8a:57:0c:95:5e:c8:03:eb:63:14:2e: 46:fd:1e:14:13:9f:38:c1:2f:e9:9b:47:c3:60:a9:d7:6e:a3: d0:af:0b:6f:df:6e:37:f6:d9:a0:1b:dd:1f:a5:a5:33:89:1f: a5:a3:44:14:91:83:c3:c8:b2:6e:fb:3f:f1:6d:d2:51:21:f7: 98:20:0a:40:75:a5:60:c3:59:53:08:62:3d:39:e8:83:55:90: 1a:bf:51:57 -----BEGIN CERTIFICATE REQUEST----- MIICnzCCAYcCAQAwWjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9v YmFyLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxej UIX+I5GH0Hg2G0kX/y1H0+Ub3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD0 1TSRTqjlP7/VCBlyUIChlpLQmrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41 U1LCIcDUyFf6LtZ/v8rSeKr6TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asF sAyOZqWhk2fakwwBDFWDhOGIubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0T iJMeTsXXjABLUlaq/rrqFF4YeuZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD2 0K07NugqCzUCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQCVJuGEVueA2iykwLWF Q2GFNIQ3g8C8z3AgiUbOPX4jikCkpfrF4z3u5QUWWJP5bPOG7pnM4QRcaJnaZnKh lTHNE2+lb/yp7HVq9+XPDntfL9uNReZmUhIdyaw6hjW9H3tuteHzT4BqBnMcoA2j Y7ZAdiWw6ZYzep0Yfl6TwEfXC9qzAxeU0Ax4GPMOzTz36CUIwhMKrx5cSF8XQbIt 0g83LrMQ/SvAd+EXilcMlV7IA+tjFC5G/R4UE584wS/pm0fDYKnXbqPQrwtv3243 9tmgG90fpaUziR+lo0QUkYPDyLJu+z/xbdJRIfeYIApAdaVgw1lTCGI9OeiDVZAa v1FX -----END CERTIFICATE REQUEST----- openssl-0.10.64/test/dhparams.pem000064400000000000000000000006501046102023000147410ustar 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.64/test/dsa.pem000064400000000000000000000012341046102023000137100ustar 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.64/test/dsa.pem.pub000064400000000000000000000012161046102023000144750ustar 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.64/test/dsaparam.pem000064400000000000000000000007071046102023000147350ustar 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.64/test/entry_extensions.crl000064400000000000000000000011551046102023000165620ustar 00000000000000-----BEGIN X509 CRL----- MIIBojCCAUkCAQEwCgYIKoZIzj0EAwIwHTEbMBkGA1UEAwwSY3J5cHRvZ3JhcGh5 LmlvIENBFw0yMzA3MjUxNDA1MzlaFw0yMzA4MDExNDA1MzlaMIGAMH4CFE+Y95/1 pOqa6c9fUEJ8c04kxu2PFw0yMzA3MjUxNDA1MzlaMFcwLwYDVR0dAQH/BCUwI6Qh MB8xCzAJBgNVBAYTAkdCMRAwDgYDVQQDDAdUZXN0IENBMAoGA1UdFQQDCgEBMBgG A1UdGAQRGA8yMDIzMDcyNTE0MDUzOVqgeDB2MB8GA1UdIwQYMBaAFK6qKNgsGefh XexO9WsIwiQ/73R8MAoGA1UdFAQDAgEUMAwGA1UdHAQFMAOEAf8wOQYIKwYBBQUH AQEELTArMCkGCCsGAQUFBzAChh1odHRwOi8vd3d3LmV4YW1wbGUuY29tL2NhLmNy dDAKBggqhkjOPQQDAgNHADBEAiB22SXxFnQUB41uxfyCvg2dAs2nFiR0r8jft/cd G8zcKAIgeYkNOzRn4lyopK6J94rhm8jIIuJRj3Ns9XcH+91N370= -----END X509 CRL----- openssl-0.10.64/test/identity.p12000064400000000000000000000064721046102023000146240ustar 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.64/test/intermediate-ca.key000064400000000000000000000032171046102023000162060ustar 00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA1HsHFTpgKeWL/y6oKtARZm0Dy6J/08E0CujmdpVp0xnkXi/A RARnbMEbOPfmBUMOkVtQT3+l5aCgIAX+Kg6K7sQvio8nQUgOxuO1YpGlYu9EMtc7 5fNxA1T0CuXXx8ClfEqW1ZV7ziQV0J4gzvuI26A7XyUhdk1oP/Al3F/94TmH6dtP SQ2K901O2zknU+bpPheQy08SE20k/nUOJAsiwtsxqY8hHOL1sXZ4K+I311hl0QpD OYf7eBcBdo2Mc5Nzjd9LPGLk1lE3itAXpayFMmfuuA0IdH1gNfy18axFEEVnj6CS 2epGpmAckUEWUOse1WBhDEt6ddowT1iw7X4mWwIDAQABAoIBAGMGXzuudAiymTc5 OFiTlbhlkAJEXkyC201GU7nqUmJ2y651lKZeYxEVQimfpszG/rARnXEfbWKCJH4o LNbO5kL2na12n/XVrkVU9EDW3fwoxGDpXFoDxaSm4AGAMrs+diFh5b/upb9ho+UQ /PtZ0OOCXokuFdU7qB08P3jgJ8LhooqWnZ4AC0rhN85CMNIKs/nrUrnmS3FZLVd/ NWI9Vfjsndd41Gkho0A7tgOSnwRupk/Bv1b0px31h8ucp9/nLuR8vbGSdS/R9Sta pB9KNYYQ3LrhQGjddnEU0gj8qsuWgnoPf7eaWsLVunPLHQzL2hNNKL1eBADm7Lhh avIlnrkCgYEA8Q8UhOeIO0sMU8sB4NPTUf2UT9xjURoowGsGgbDEk21eABH6VC33 VYt5r5xwbZFQvVaTbe+EI1YDpjH1cvpmorEWI47Nm4Vbf9JujW/hoQwuwpzOpdUT 2G4tfMQrmTw/9HJ0l9+1Ib+A93dB8GvR0NE1uueaWanWvXARInwGiscCgYEA4aZ9 mbhuwx88sSRMXwxSZw+R5BRrjdC0CeoimGg4/P84bKgc0YsjAha5jWaC/h8xN2Pb w45b3hQ0/FP8xohP0bp/5eeiDbqb6JuO5bI3CnfBrVpu1CAuIrf7lhkar3a0wluB k03fVHuVLtydACDJBKrZm1F39lpiZiEqlBIp080CgYEAwRwYjwPAEefkHzhQ7+Ah uNwQtQ1TjsQLA2J5mumWAJirphjA1jDgo+oQ+Iq1UkEIUjWJ85bd30TntXruK0bH c+uzVZbvxXfGvhZAtBN9x/svdn4R2a1hsY9J51prpt0qStRp7MSsoTV9xkEGVOi6 87K1fV5OOyggvC+Lunlq8D8CgYAVSCOObPOdWYPa3SaKzFm1OKW00iw2qtlgGgH7 R9EgI14J+W0GYk4B82y6plFycDSvGa7vaazGbDd3GOC9RLvqduF7KHaDPvdXX9yB U2aXiSXuGJpdTU+snJeQ13tJ0zNHJWQ6JV0L1cADNHFmQrFSzF5LpMpgpLOlGDmw z2m8fQKBgQDclFeonyn0zcXqznun9kAKkMij4s6lSdRgi/5Zh1WbJwOso9oWfwz9 SSTP2KBO8B+/yFvuo5SWrbNaTz9/KuzMTv4HXz5ukLbyN9Jjtk73fdBBRSjL+zF5 jU56oXHrwBhEqWQ77Ps60r+FmDjUgUhyJl14ZfkzICUK7NLFxKrvMQ== -----END RSA PRIVATE KEY----- openssl-0.10.64/test/intermediate-ca.pem000064400000000000000000000024761046102023000162050ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDszCCApugAwIBAgIEFSQSITANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 cyBQdHkgTHRkMB4XDTIyMTEwMzA3MDc0OVoXDTI2MDgxMTA3MDc0OVowgYkxCzAJ BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l dCBXaWRnaXRzIFB0eSBMdGQxIDAeBgNVBAsMF0ludGVybWVkaWF0ZSBEZXBhcnRt ZW50MSAwHgYDVQQDDBdpbnRlcm1lZGlhdGUuZm9vYmFyLmNvbTCCASIwDQYJKoZI hvcNAQEBBQADggEPADCCAQoCggEBANR7BxU6YCnli/8uqCrQEWZtA8uif9PBNAro 5naVadMZ5F4vwEQEZ2zBGzj35gVDDpFbUE9/peWgoCAF/ioOiu7EL4qPJ0FIDsbj tWKRpWLvRDLXO+XzcQNU9Arl18fApXxKltWVe84kFdCeIM77iNugO18lIXZNaD/w Jdxf/eE5h+nbT0kNivdNTts5J1Pm6T4XkMtPEhNtJP51DiQLIsLbMamPIRzi9bF2 eCviN9dYZdEKQzmH+3gXAXaNjHOTc43fSzxi5NZRN4rQF6WshTJn7rgNCHR9YDX8 tfGsRRBFZ4+gktnqRqZgHJFBFlDrHtVgYQxLenXaME9YsO1+JlsCAwEAAaNmMGQw HQYDVR0OBBYEFAXJImmmxYXx6L1SRRhgP3Tyq2J6MB8GA1UdIwQYMBaAFGzTpQOr DV8syY2KnIiniHe4N/2aMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQD AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQCnUh7iNbnFBjVa4sFx02r65syxUhcvM/ya DcSe1esGUwjZLyKVl9BTfQ6kfNa/6Z/t5cprp0R3etalN31dxka7xSDwzFNdBczB zYDIVOVlcGLL1Xjozacm6YHo773dqxZS36rVMk3NqNUY6GJJ+CGso2xZShcBg2KG fPlNPiRz3847E3dwouDYcP1MXf2ql/Y7dRbE+8kb3bWkSusJVb/4EHjpR7yZjKmh eXHVVx1dKnCGRldn3+dSNhN6mxNaSeBE2hb158+diQvL5u3f//va7SOpCi0f4d8E UCnLhieyrDlr42XXfz42BqRpqBO1SDjQwzIIc9Fbevwb916OSExp -----END CERTIFICATE----- openssl-0.10.64/test/key.der000064400000000000000000000022511046102023000137220ustar 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.64/test/key.pem000064400000000000000000000032541046102023000137350ustar 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.64/test/key.pem.pub000064400000000000000000000007031046102023000145160ustar 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.64/test/keystore-empty-chain.p12000064400000000000000000000047221046102023000170500ustar 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.64/test/leaf.pem000064400000000000000000000023611046102023000140520ustar 00000000000000-----BEGIN CERTIFICATE----- MIIDejCCAmICBBUkEiQwDQYJKoZIhvcNAQELBQAwgYkxCzAJBgNVBAYTAkFVMRMw EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0 eSBMdGQxIDAeBgNVBAsMF0ludGVybWVkaWF0ZSBEZXBhcnRtZW50MSAwHgYDVQQD DBdpbnRlcm1lZGlhdGUuZm9vYmFyLmNvbTAeFw0yMjExMDMwNzE3NTJaFw0yNjA4 MTEwNzE3NTJaMHkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxGDAWBgNVBAsMD0xlYWYg RGVwYXJ0bWVudDEYMBYGA1UEAwwPbGVhZi5mb29iYXIuY29tMIIBIjANBgkqhkiG 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs9STUHGIcSOtioK6+02k9Jx4JuYVJ0SB7Ebd FAhGiOxBSoOljRVmmALti89QMmRiRqlyJnGJch7AloCCRsLJA0MfUYvauqmKHZFk iqtZ1HocHQ/LGNKfkILcclb4xp2nGYntKAyEqer3Qc6aPWAnQAV/+BshU1vlMfwU T6vOJRG69mft6dkHEWSzZd7++7HmFQGnDmIs5jBJVCOgKVttkN8Bk2EsTvJi9zl2 SXLTcVrTAxEvuawv2ZXvdI/Cpt1WW0litXlFLcYBGwt/N93TX/L3Iyw5HcNd/xf9 QwOr6RR66krQJzKxwcIY934uq6cyTQhexgnffb65qXL4bbV5fwIDAQABMA0GCSqG SIb3DQEBCwUAA4IBAQAZf0/r04AeKN2QhQ7Z0o2Iu/Yj3OD2tnbxVoltYk8CRfp3 7VGl/5PUbmXXBSwMc4Udj88JlreU7iNEPAKtBqFczw0pwNfvxKG4Eh3vsfKrP+5g gtVwDG0mWeKJ7udrmFt8N0uwxVYDKp/gv5+Bw2eMew9Eoyenj6k2yg0nbFKzA3EH DqngETzX0dhdiYwVcoJFUK5ni3tVl9qi6FpmaTE6C5nTQLyH4CI+vo2x/QHINGaJ OzY/rx35iyVqXVqxN/gO/hp6g0nT5zLuMg2rfvcAhdDsD7htYcHiNkofrC8s0oQE W+r01EhxdEVvY1nYWanBCF6tktc5v5qf2WMS4ye5 -----END CERTIFICATE----- openssl-0.10.64/test/nid_test_cert.pem000064400000000000000000000012701046102023000157670ustar 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.64/test/nid_uid_test_cert.pem000064400000000000000000000027101046102023000166300ustar 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.64/test/pkcs1.pem.pub000064400000000000000000000006521046102023000147520ustar 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.64/test/pkcs8-nocrypt.der000064400000000000000000000023001046102023000156510ustar 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.64/test/pkcs8.der000064400000000000000000000024221046102023000141620ustar 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.64/test/root-ca.key000064400000000000000000000032171046102023000145170ustar 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.64/test/root-ca.pem000064400000000000000000000023151046102023000145060ustar 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.64/test/rsa-encrypted.pem000064400000000000000000000033461046102023000157270ustar 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.64/test/rsa.pem000064400000000000000000000032131046102023000137250ustar 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.64/test/rsa.pem.pub000064400000000000000000000007031046102023000145130ustar 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----- openssl-0.10.64/test/subca.crt000064400000000000000000000107271046102023000142540ustar 00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 13:ae:da:d8:f4:18:d7:73:b8:bd:35:c9:ce:8e:b3:fc Signature Algorithm: sha256WithRSAEncryption Issuer: CN=TestCA Validity Not Before: Jun 6 19:11:19 2019 GMT Not After : May 21 19:11:19 2022 GMT Subject: CN=SubCA Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:b0:09:fc:54:e7:6a:9f:0c:bd:ad:5a:8d:ef:94: 4e:11:a6:87:19:4f:bf:a6:e1:62:a5:2d:b7:17:df: 67:53:70:da:fe:7d:99:17:ee:13:47:0b:40:0b:a2: 34:32:a9:d3:bf:20:fc:13:77:a1:d5:26:60:1f:f0: d4:be:dc:76:7c:1e:6c:b4:4c:01:7c:56:cd:5c:53: ec:81:b3:81:2a:b2:35:26:06:5a:79:e0:b3:9e:e4: 57:e1:09:de:ad:7f:c8:cd:87:ee:49:93:30:52:58: b2:bc:0f:c1:b6:10:44:f8:85:d5:5b:0a:9b:28:fe: f4:f4:4a:16:a6:f7:25:e9:96:47:69:73:5b:33:77: 92:7d:61:8d:2a:3d:d5:04:89:40:bf:6b:d2:fd:5d: e2:1a:80:a9:8e:c8:92:f6:e5:4c:00:84:f9:6e:2a: 93:a3:23:ee:28:23:81:f4:54:f0:18:2c:ee:32:8e: 38:9c:a0:c8:33:04:b0:fc:4c:43:1a:5c:04:84:9f: 73:c6:08:c7:1d:64:39:fe:72:19:3b:cc:a5:fd:0b: 43:25:0d:2b:a9:88:77:9e:62:e6:ac:c2:9a:60:42: 4f:4a:54:47:bc:a0:29:72:7c:38:52:c9:ea:27:c5: 3d:d0:81:4a:3e:b8:78:79:4b:89:b8:4e:6d:1b:24: 15:bd Exponent: 65537 (0x10001) X509v3 extensions: X509v3 CRL Distribution Points: Full Name: URI:http://127.0.0.1:8081/pki/test.crl X509v3 Basic Constraints: CA:TRUE X509v3 Subject Key Identifier: FD:82:45:39:A1:91:41:F2:66:CC:0D:75:D5:0D:40:D5:81:A7:A1:43 X509v3 Authority Key Identifier: keyid:C5:CC:F5:A1:8C:D9:E4:A7:BA:EC:21:F5:D1:84:23:EA:0D:C2:C7:30 DirName:/CN=TestCA serial:33:E7:04:87:09:32:87:21:D9:CD:7C:AA:4C:5A:BB:2C:6C:7B:54:28 X509v3 Key Usage: Certificate Sign, CRL Sign Signature Algorithm: sha256WithRSAEncryption 96:a0:ff:8a:4b:bd:45:96:c9:72:3c:63:e3:48:c4:ab:ef:7e: db:76:3f:d9:02:9e:69:c8:d9:36:55:e1:f5:9b:c9:69:d8:69: 02:ac:50:8c:60:94:2c:2e:b9:a8:65:ac:f5:00:b0:8b:96:25: 0b:8a:ef:94:21:57:e2:04:c2:c3:86:bf:06:4e:91:5c:e6:bc: 1b:03:31:8b:64:ea:c5:79:c3:5c:94:e5:aa:67:7e:74:12:07: 14:fd:cd:32:02:26:26:c9:0a:ed:d4:da:ee:2a:84:e3:f1:60: b3:09:77:27:a1:3c:ac:ec:61:18:30:b5:6d:1f:16:0a:24:1a: cf:1c:1b:60:a5:60:e5:2c:8b:cf:37:83:0c:15:e7:79:30:3f: ee:50:45:7c:4b:c6:2c:cd:2c:81:0a:98:f1:65:44:7a:ca:2a: 20:1a:de:19:d9:4b:ca:a1:e2:a4:b5:14:47:bf:b4:68:15:03: c0:55:e5:f4:47:0e:55:9f:fe:85:d8:2c:7d:d0:1a:96:11:b9: 68:b7:74:1e:61:94:c1:ae:87:52:2d:c6:26:ba:51:ed:f1:91: c0:e6:4c:f8:ad:02:23:75:51:fc:f8:69:05:ec:cf:31:50:5a: 41:78:eb:3d:27:4d:9b:68:ef:ba:0e:ba:3a:7d:60:00:9d:53: a5:08:3d:c6 -----BEGIN CERTIFICATE----- MIIDbDCCAlSgAwIBAgIQE67a2PQY13O4vTXJzo6z/DANBgkqhkiG9w0BAQsFADAR MQ8wDQYDVQQDDAZUZXN0Q0EwHhcNMTkwNjA2MTkxMTE5WhcNMjIwNTIxMTkxMTE5 WjAQMQ4wDAYDVQQDDAVTdWJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBALAJ/FTnap8Mva1aje+UThGmhxlPv6bhYqUttxffZ1Nw2v59mRfuE0cLQAui NDKp078g/BN3odUmYB/w1L7cdnwebLRMAXxWzVxT7IGzgSqyNSYGWnngs57kV+EJ 3q1/yM2H7kmTMFJYsrwPwbYQRPiF1VsKmyj+9PRKFqb3JemWR2lzWzN3kn1hjSo9 1QSJQL9r0v1d4hqAqY7IkvblTACE+W4qk6Mj7igjgfRU8Bgs7jKOOJygyDMEsPxM QxpcBISfc8YIxx1kOf5yGTvMpf0LQyUNK6mId55i5qzCmmBCT0pUR7ygKXJ8OFLJ 6ifFPdCBSj64eHlLibhObRskFb0CAwEAAaOBwDCBvTAzBgNVHR8ELDAqMCigJqAk hiJodHRwOi8vMTI3LjAuMC4xOjgwODEvcGtpL3Rlc3QuY3JsMAwGA1UdEwQFMAMB Af8wHQYDVR0OBBYEFP2CRTmhkUHyZswNddUNQNWBp6FDMEwGA1UdIwRFMEOAFMXM 9aGM2eSnuuwh9dGEI+oNwscwoRWkEzARMQ8wDQYDVQQDDAZUZXN0Q0GCFDPnBIcJ Moch2c18qkxauyxse1QoMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEA lqD/iku9RZbJcjxj40jEq+9+23Y/2QKeacjZNlXh9ZvJadhpAqxQjGCULC65qGWs 9QCwi5YlC4rvlCFX4gTCw4a/Bk6RXOa8GwMxi2TqxXnDXJTlqmd+dBIHFP3NMgIm JskK7dTa7iqE4/Fgswl3J6E8rOxhGDC1bR8WCiQazxwbYKVg5SyLzzeDDBXneTA/ 7lBFfEvGLM0sgQqY8WVEesoqIBreGdlLyqHipLUUR7+0aBUDwFXl9EcOVZ/+hdgs fdAalhG5aLd0HmGUwa6HUi3GJrpR7fGRwOZM+K0CI3VR/PhpBezPMVBaQXjrPSdN m2jvug66On1gAJ1TpQg9xg== -----END CERTIFICATE----- openssl-0.10.64/test/test.crl000064400000000000000000000007251046102023000141230ustar 00000000000000000  *H  010 U TestCA 190610165508Z 191207165508Z0#0!s5Ύ 190606192439ZP0N0LU#E0C䧺!ф# 0010 U TestCA3 2!|LZ,l{T(0  *H  ~NO'A\M^nT_=-S˚Kg#mS_[;݃=*ϼȩ\(Oۣ=zT^b/>W*=s *'2RC.}T*bÀU'UV+:ۋ6m ~C۠ރ{Q ?J)&Z"G"GV!Ҷv"--f+/o'Gx1`Ubg9e^߮Q-