summaryrefslogtreecommitdiffstats
path: root/vendor/openssl/src
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/openssl/src')
-rw-r--r--vendor/openssl/src/aes.rs319
-rw-r--r--vendor/openssl/src/asn1.rs911
-rw-r--r--vendor/openssl/src/base64.rs128
-rw-r--r--vendor/openssl/src/bio.rs85
-rw-r--r--vendor/openssl/src/bn.rs1518
-rw-r--r--vendor/openssl/src/cipher.rs536
-rw-r--r--vendor/openssl/src/cipher_ctx.rs1106
-rw-r--r--vendor/openssl/src/cms.rs488
-rw-r--r--vendor/openssl/src/conf.rs65
-rw-r--r--vendor/openssl/src/derive.rs217
-rw-r--r--vendor/openssl/src/dh.rs480
-rw-r--r--vendor/openssl/src/dsa.rs697
-rw-r--r--vendor/openssl/src/ec.rs1345
-rw-r--r--vendor/openssl/src/ecdsa.rs224
-rw-r--r--vendor/openssl/src/encrypt.rs578
-rw-r--r--vendor/openssl/src/envelope.rs181
-rw-r--r--vendor/openssl/src/error.rs418
-rw-r--r--vendor/openssl/src/ex_data.rs32
-rw-r--r--vendor/openssl/src/fips.rs21
-rw-r--r--vendor/openssl/src/hash.rs800
-rw-r--r--vendor/openssl/src/lib.rs222
-rw-r--r--vendor/openssl/src/lib_ctx.rs22
-rw-r--r--vendor/openssl/src/macros.rs270
-rw-r--r--vendor/openssl/src/md.rs235
-rw-r--r--vendor/openssl/src/md_ctx.rs540
-rw-r--r--vendor/openssl/src/memcmp.rs93
-rw-r--r--vendor/openssl/src/nid.rs1179
-rw-r--r--vendor/openssl/src/ocsp.rs352
-rw-r--r--vendor/openssl/src/pkcs12.rs392
-rw-r--r--vendor/openssl/src/pkcs5.rs310
-rw-r--r--vendor/openssl/src/pkcs7.rs448
-rw-r--r--vendor/openssl/src/pkey.rs1173
-rw-r--r--vendor/openssl/src/pkey_ctx.rs1002
-rw-r--r--vendor/openssl/src/provider.rs77
-rw-r--r--vendor/openssl/src/rand.rs60
-rw-r--r--vendor/openssl/src/rsa.rs852
-rw-r--r--vendor/openssl/src/sha.rs463
-rw-r--r--vendor/openssl/src/sign.rs886
-rw-r--r--vendor/openssl/src/srtp.rs66
-rw-r--r--vendor/openssl/src/ssl/bio.rs290
-rw-r--r--vendor/openssl/src/ssl/callbacks.rs707
-rw-r--r--vendor/openssl/src/ssl/connector.rs605
-rw-r--r--vendor/openssl/src/ssl/error.rs185
-rw-r--r--vendor/openssl/src/ssl/mod.rs4211
-rw-r--r--vendor/openssl/src/ssl/test/mod.rs1570
-rw-r--r--vendor/openssl/src/ssl/test/server.rs167
-rw-r--r--vendor/openssl/src/stack.rs380
-rw-r--r--vendor/openssl/src/string.rs96
-rw-r--r--vendor/openssl/src/symm.rs1633
-rw-r--r--vendor/openssl/src/util.rs93
-rw-r--r--vendor/openssl/src/version.rs135
-rw-r--r--vendor/openssl/src/x509/extension.rs562
-rw-r--r--vendor/openssl/src/x509/mod.rs2535
-rw-r--r--vendor/openssl/src/x509/store.rs287
-rw-r--r--vendor/openssl/src/x509/tests.rs1161
-rw-r--r--vendor/openssl/src/x509/verify.rs215
56 files changed, 33623 insertions, 0 deletions
diff --git a/vendor/openssl/src/aes.rs b/vendor/openssl/src/aes.rs
new file mode 100644
index 0000000..cbc4999
--- /dev/null
+++ b/vendor/openssl/src/aes.rs
@@ -0,0 +1,319 @@
+//! 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<AesKey, KeyError> {
+ 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<AesKey, KeyError> {
+ 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<usize, KeyError> {
+ 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<usize, KeyError> {
+ 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[..]);
+ }
+}
diff --git a/vendor/openssl/src/asn1.rs b/vendor/openssl/src/asn1.rs
new file mode 100644
index 0000000..801310d
--- /dev/null
+++ b/vendor/openssl/src/asn1.rs
@@ -0,0 +1,911 @@
+#![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(ossl102)]
+pub struct TimeDiff {
+ /// Difference in days
+ pub days: c_int,
+ /// Difference in seconds.
+ ///
+ /// This is always less than the number of seconds in a day.
+ pub secs: c_int,
+}
+
+foreign_type_and_impl_send_sync! {
+ type CType = ffi::ASN1_TIME;
+ fn drop = ffi::ASN1_TIME_free;
+ /// Time storage and comparison
+ ///
+ /// Asn1Time should be used to store and share time information
+ /// using certificates. If Asn1Time is set using a string, it must
+ /// be in either YYMMDDHHMMSSZ, YYYYMMDDHHMMSSZ, or another ASN.1 format.
+ ///
+ /// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementation
+ /// used by OpenSSL.
+ ///
+ /// [ASN_TIME_set]: https://www.openssl.org/docs/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(ossl102)]
+ pub fn diff(&self, compare: &Self) -> Result<TimeDiff, ErrorStack> {
+ 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(ossl102)]
+ pub fn compare(&self, other: &Self) -> Result<Ordering, ErrorStack> {
+ let d = self.diff(other)?;
+ if d.days > 0 || d.secs > 0 {
+ return Ok(Ordering::Less);
+ }
+ if d.days < 0 || d.secs < 0 {
+ return Ok(Ordering::Greater);
+ }
+
+ Ok(Ordering::Equal)
+ }
+}
+
+#[cfg(ossl102)]
+impl PartialEq for Asn1TimeRef {
+ fn eq(&self, other: &Asn1TimeRef) -> bool {
+ self.diff(other)
+ .map(|t| t.days == 0 && t.secs == 0)
+ .unwrap_or(false)
+ }
+}
+
+#[cfg(ossl102)]
+impl PartialEq<Asn1Time> for Asn1TimeRef {
+ fn eq(&self, other: &Asn1Time) -> bool {
+ self.diff(other)
+ .map(|t| t.days == 0 && t.secs == 0)
+ .unwrap_or(false)
+ }
+}
+
+#[cfg(ossl102)]
+impl<'a> PartialEq<Asn1Time> for &'a Asn1TimeRef {
+ fn eq(&self, other: &Asn1Time) -> bool {
+ self.diff(other)
+ .map(|t| t.days == 0 && t.secs == 0)
+ .unwrap_or(false)
+ }
+}
+
+#[cfg(ossl102)]
+impl PartialOrd for Asn1TimeRef {
+ fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
+ self.compare(other).ok()
+ }
+}
+
+#[cfg(ossl102)]
+impl PartialOrd<Asn1Time> for Asn1TimeRef {
+ fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
+ self.compare(other).ok()
+ }
+}
+
+#[cfg(ossl102)]
+impl<'a> PartialOrd<Asn1Time> for &'a Asn1TimeRef {
+ fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
+ 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<Asn1Time, ErrorStack> {
+ 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<Asn1Time, ErrorStack> {
+ 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, ErrorStack> {
+ 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<Asn1Time, ErrorStack> {
+ 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<Asn1Time, ErrorStack> {
+ 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 OpenSSL 1.1.1 or newer.
+ #[corresponds(ASN1_TIME_set_string_X509)]
+ #[cfg(ossl111)]
+ pub fn from_str_x509(s: &str) -> Result<Asn1Time, ErrorStack> {
+ unsafe {
+ let s = CString::new(s).unwrap();
+
+ let time = Asn1Time::new()?;
+ cvt(ffi::ASN1_TIME_set_string_X509(time.as_ptr(), s.as_ptr()))?;
+
+ Ok(time)
+ }
+ }
+}
+
+#[cfg(ossl102)]
+impl PartialEq for Asn1Time {
+ fn eq(&self, other: &Asn1Time) -> bool {
+ self.diff(other)
+ .map(|t| t.days == 0 && t.secs == 0)
+ .unwrap_or(false)
+ }
+}
+
+#[cfg(ossl102)]
+impl PartialEq<Asn1TimeRef> for Asn1Time {
+ fn eq(&self, other: &Asn1TimeRef) -> bool {
+ self.diff(other)
+ .map(|t| t.days == 0 && t.secs == 0)
+ .unwrap_or(false)
+ }
+}
+
+#[cfg(ossl102)]
+impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time {
+ fn eq(&self, other: &&'a Asn1TimeRef) -> bool {
+ self.diff(other)
+ .map(|t| t.days == 0 && t.secs == 0)
+ .unwrap_or(false)
+ }
+}
+
+#[cfg(ossl102)]
+impl PartialOrd for Asn1Time {
+ fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
+ self.compare(other).ok()
+ }
+}
+
+#[cfg(ossl102)]
+impl PartialOrd<Asn1TimeRef> for Asn1Time {
+ fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
+ self.compare(other).ok()
+ }
+}
+
+#[cfg(ossl102)]
+impl<'a> PartialOrd<&'a Asn1TimeRef> for Asn1Time {
+ fn partial_cmp(&self, other: &&'a Asn1TimeRef) -> Option<Ordering> {
+ 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<OpensslString, ErrorStack> {
+ 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<Self, ErrorStack> {
+ 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<Ordering> {
+ 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<BigNum, ErrorStack> {
+ 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<Asn1Integer, ErrorStack> {
+ 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<Ordering> {
+ 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<Self, ErrorStack> {
+ 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<Asn1Object, ErrorStack> {
+ 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<i64, ErrorStack> {
+ 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(ossl102)]
+ fn time_eq() {
+ let a = Asn1Time::from_str("99991231235959Z").unwrap();
+ let b = Asn1Time::from_str("99991231235959Z").unwrap();
+ let c = Asn1Time::from_str("99991231235958Z").unwrap();
+ let a_ref = a.as_ref();
+ let b_ref = b.as_ref();
+ let c_ref = c.as_ref();
+ assert!(a == b);
+ assert!(a != c);
+ assert!(a == b_ref);
+ assert!(a != c_ref);
+ assert!(b_ref == a);
+ assert!(c_ref != a);
+ assert!(a_ref == b_ref);
+ assert!(a_ref != c_ref);
+ }
+
+ #[test]
+ #[cfg(ossl102)]
+ fn time_ord() {
+ let a = Asn1Time::from_str("99991231235959Z").unwrap();
+ let b = Asn1Time::from_str("99991231235959Z").unwrap();
+ let c = Asn1Time::from_str("99991231235958Z").unwrap();
+ let a_ref = a.as_ref();
+ let b_ref = b.as_ref();
+ let c_ref = c.as_ref();
+ assert!(a >= b);
+ assert!(a > c);
+ assert!(b <= a);
+ assert!(c < a);
+
+ assert!(a_ref >= b);
+ assert!(a_ref > c);
+ assert!(b_ref <= a);
+ assert!(c_ref < a);
+
+ assert!(a >= b_ref);
+ assert!(a > c_ref);
+ assert!(b <= a_ref);
+ assert!(c < a_ref);
+
+ assert!(a_ref >= b_ref);
+ assert!(a_ref > c_ref);
+ assert!(b_ref <= a_ref);
+ assert!(c_ref < a_ref);
+ }
+
+ #[test]
+ fn 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);
+ }
+}
diff --git a/vendor/openssl/src/base64.rs b/vendor/openssl/src/base64.rs
new file mode 100644
index 0000000..bfa8cbc
--- /dev/null
+++ b/vendor/openssl/src/base64.rs
@@ -0,0 +1,128 @@
+//! 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<Vec<u8>, 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<LenType> {
+ 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<LenType> {
+ 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());
+ }
+}
diff --git a/vendor/openssl/src/bio.rs b/vendor/openssl/src/bio.rs
new file mode 100644
index 0000000..0f54935
--- /dev/null
+++ b/vendor/openssl/src/bio.rs
@@ -0,0 +1,85 @@
+use 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<MemBioSlice<'a>, 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<MemBio, ErrorStack> {
+ 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)
+ }
+ }
+}
diff --git a/vendor/openssl/src/bn.rs b/vendor/openssl/src/bn.rs
new file mode 100644
index 0000000..c75fac1
--- /dev/null
+++ b/vendor/openssl/src/bn.rs
@@ -0,0 +1,1518 @@
+//! 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<BigNumContext, ErrorStack> {
+ 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<BigNumContext, ErrorStack> {
+ 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<Target = BigNumRef>`]
+ ///
+ /// OpenSSL documentation at [`BN_new`].
+ ///
+ /// [`new`]: struct.BigNum.html#method.new
+ /// [`Dref<Target = BigNumRef>`]: 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<u64, ErrorStack> {
+ 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<u64, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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)]
+ #[cfg(ossl110)]
+ 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<bool, ErrorStack> {
+ 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<bool, ErrorStack> {
+ 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<u8> {
+ 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<Vec<u8>, 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<OpensslString, ErrorStack> {
+ 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<OpensslString, ErrorStack> {
+ 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<Asn1Integer, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNum, ErrorStack> {
+ 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<BigNumRef> for BigNumRef {
+ fn eq(&self, oth: &BigNumRef) -> bool {
+ self.cmp(oth) == Ordering::Equal
+ }
+}
+
+impl PartialEq<BigNum> 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<BigNumRef> for BigNum {
+ fn eq(&self, oth: &BigNumRef) -> bool {
+ self.deref().eq(oth)
+ }
+}
+
+impl Eq for BigNum {}
+
+impl PartialOrd<BigNumRef> for BigNumRef {
+ fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
+ Some(self.cmp(oth))
+ }
+}
+
+impl PartialOrd<BigNum> for BigNumRef {
+ fn partial_cmp(&self, oth: &BigNum) -> Option<Ordering> {
+ 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<Ordering> {
+ self.deref().partial_cmp(oth.deref())
+ }
+}
+
+impl PartialOrd<BigNumRef> for BigNum {
+ fn partial_cmp(&self, oth: &BigNumRef) -> Option<Ordering> {
+ 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<i32> 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<i32> for &'a BigNum {
+ type Output = BigNum;
+
+ fn shl(self, n: i32) -> BigNum {
+ self.deref().shl(n)
+ }
+}
+
+impl<'a> Shr<i32> 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<i32> 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())
+ }
+
+ #[cfg(ossl110)]
+ #[test]
+ fn test_mod_sqrt() {
+ let mut ctx = BigNumContext::new().unwrap();
+
+ let s = BigNum::from_hex_str("47A8DD7626B9908C80ACD7E0D3344D69").unwrap();
+ let p = BigNum::from_hex_str("81EF47265B58BCE5").unwrap();
+ let mut out = BigNum::new().unwrap();
+
+ out.mod_sqrt(&s, &p, &mut ctx).unwrap();
+ assert_eq!(out, BigNum::from_hex_str("7C6D179E19B97BDD").unwrap());
+ }
+
+ #[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());
+ }
+}
diff --git a/vendor/openssl/src/cipher.rs b/vendor/openssl/src/cipher.rs
new file mode 100644
index 0000000..2b89861
--- /dev/null
+++ b/vendor/openssl/src/cipher.rs
@@ -0,0 +1,536 @@
+//! 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<Self, ErrorStack> {
+ 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_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 _) }
+ }
+
+ #[cfg(not(boringssl))]
+ 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(ossl110)]
+ 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(ossl110)]
+ 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(ossl110)]
+ 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"))]
+ #[cfg(not(boringssl))]
+ pub fn bf_cfb64() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_bf_cfb64() as *mut _) }
+ }
+
+ #[cfg(not(osslconf = "OPENSSL_NO_BF"))]
+ #[cfg(not(boringssl))]
+ 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_cbc() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cbc() 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(osslconf = "OPENSSL_NO_RC4"))]
+ pub fn rc4() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_rc4() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+ pub fn camellia128_cfb128() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_cfb128() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+ pub fn camellia128_ecb() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_ecb() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+ pub fn camellia192_cfb128() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_cfb128() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+ pub fn camellia192_ecb() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_ecb() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+ pub fn camellia256_cfb128() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_cfb128() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAMELLIA")))]
+ pub fn camellia256_ecb() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_ecb() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))]
+ pub fn cast5_cfb64() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cfb64() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_CAST")))]
+ pub fn cast5_ecb() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_cast5_ecb() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_IDEA")))]
+ pub fn idea_cfb64() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_idea_cfb64() as *mut _) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_IDEA")))]
+ pub fn idea_ecb() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_idea_ecb() as *mut _) }
+ }
+
+ #[cfg(all(ossl110, 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"))]
+ #[cfg(not(boringssl))]
+ pub fn seed_cbc() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_seed_cbc() as *mut _) }
+ }
+
+ #[cfg(not(osslconf = "OPENSSL_NO_SEED"))]
+ #[cfg(not(boringssl))]
+ pub fn seed_cfb128() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_seed_cfb128() as *mut _) }
+ }
+
+ #[cfg(not(osslconf = "OPENSSL_NO_SEED"))]
+ #[cfg(not(boringssl))]
+ pub fn seed_ecb() -> &'static CipherRef {
+ unsafe { CipherRef::from_ptr(ffi::EVP_seed_ecb() as *mut _) }
+ }
+
+ #[cfg(not(osslconf = "OPENSSL_NO_SEED"))]
+ #[cfg(not(boringssl))]
+ 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 }
+ }
+}
diff --git a/vendor/openssl/src/cipher_ctx.rs b/vendor/openssl/src/cipher_ctx.rs
new file mode 100644
index 0000000..f9031d2
--- /dev/null
+++ b/vendor/openssl/src/cipher_ctx.rs
@@ -0,0 +1,1106 @@
+//! 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<Self, ErrorStack> {
+ 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<T>(
+ &mut self,
+ type_: Option<&CipherRef>,
+ pub_keys: &[PKey<T>],
+ encrypted_keys: &mut [Vec<u8>],
+ 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::<Vec<_>>();
+ 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<T>(
+ &mut self,
+ type_: Option<&CipherRef>,
+ encrypted_key: &[u8],
+ iv: Option<&[u8]>,
+ priv_key: Option<&PKeyRef<T>>,
+ ) -> 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 as specified by [`Self::minimal_output_size`].
+ #[corresponds(EVP_CipherUpdate)]
+ pub fn cipher_update(
+ &mut self,
+ input: &[u8],
+ output: Option<&mut [u8]>,
+ ) -> Result<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<u8>,
+ ) -> Result<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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);
+ }
+}
diff --git a/vendor/openssl/src/cms.rs b/vendor/openssl/src/cms.rs
new file mode 100644
index 0000000..d11443b
--- /dev/null
+++ b/vendor/openssl/src/cms.rs
@@ -0,0 +1,488 @@
+//! 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<T>(&self, pkey: &PKeyRef<T>, cert: &X509) -> Result<Vec<u8>, 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<T>(&self, pkey: &PKeyRef<T>) -> Result<Vec<u8>, 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<CmsContentInfo, ErrorStack> {
+ 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<T>(
+ signcert: Option<&X509Ref>,
+ pkey: Option<&PKeyRef<T>>,
+ certs: Option<&StackRef<X509>>,
+ data: Option<&[u8]>,
+ flags: CMSOptions,
+ ) -> Result<CmsContentInfo, ErrorStack>
+ 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<X509>,
+ data: &[u8],
+ cipher: Cipher,
+ flags: CMSOptions,
+ ) -> Result<CmsContentInfo, ErrorStack> {
+ 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<X509>>,
+ store: Option<&X509StoreRef>,
+ detached_data: Option<&[u8]>,
+ output_data: Option<&mut Vec<u8>>,
+ 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<u8> = 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;
+ match res {
+ Err(es) => {
+ let error_array = es.errors();
+ assert_eq!(1, error_array.len());
+ let code = error_array[0].code();
+ assert_eq!(ffi::ERR_GET_REASON(code), CMS_R_CERTIFICATE_VERIFY_ERROR);
+ }
+ _ => panic!("expected CMS verification error, got Ok()"),
+ }
+ }
+}
diff --git a/vendor/openssl/src/conf.rs b/vendor/openssl/src/conf.rs
new file mode 100644
index 0000000..715519c
--- /dev/null
+++ b/vendor/openssl/src/conf.rs
@@ -0,0 +1,65 @@
+//! 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<Conf, ErrorStack> {
+ unsafe { cvt_p(ffi::NCONF_new(method.as_ptr())).map(Conf) }
+ }
+ }
+}
+#[cfg(not(boringssl))]
+pub use methods::*;
diff --git a/vendor/openssl/src/derive.rs b/vendor/openssl/src/derive.rs
new file mode 100644
index 0000000..424c5f9
--- /dev/null
+++ b/vendor/openssl/src/derive.rs
@@ -0,0 +1,217 @@
+//! Shared secret derivation.
+//!
+//! # Example
+//!
+//! The following example implements [ECDH] using `NIST P-384` keys:
+//!
+//! ```
+//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
+//! # 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<T>(key: &'a PKeyRef<T>) -> Result<Deriver<'a>, 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<T>(&mut self, key: &'a PKeyRef<T>) -> 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<T>(
+ &mut self,
+ key: &'a PKeyRef<T>,
+ 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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<Vec<u8>, 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());
+ }
+}
diff --git a/vendor/openssl/src/dh.rs b/vendor/openssl/src/dh.rs
new file mode 100644
index 0000000..7445e34
--- /dev/null
+++ b/vendor/openssl/src/dh.rs
@@ -0,0 +1,480 @@
+//! 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<T>;
+
+ pub struct DhRef<T>;
+}
+
+impl<T> DhRef<T>
+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<bool, ErrorStack> {
+ unsafe {
+ let mut codes = 0;
+ cvt(ffi::DH_check(self.as_ptr(), &mut codes))?;
+ Ok(codes == 0)
+ }
+ }
+}
+
+impl Dh<Params> {
+ pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result<Dh<Params>, 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<BigNum>,
+ generator: BigNum,
+ ) -> Result<Dh<Params>, 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<Dh<Public>, 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<Dh<Private>, 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<Dh<Private>, 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<Dh<Params>, 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<Dh<Private>, 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<Params>,
+ ffi::PEM_read_bio_DHparams
+ }
+
+ from_der! {
+ /// Deserializes a DER-encoded PKCS#3 DHparameters structure.
+ #[corresponds(d2i_DHparams)]
+ params_from_der,
+ Dh<Params>,
+ 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<Dh<Params>, 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<Dh<Params>, 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<Dh<Params>, ErrorStack> {
+ unsafe {
+ ffi::init();
+ cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p))
+ }
+ }
+}
+
+impl<T> Dh<T>
+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<T> DhRef<T>
+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<T> DhRef<T>
+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<Vec<u8>, 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;
+ use crate::ssl::{SslContext, SslMethod};
+
+ #[test]
+ #[cfg(ossl102)]
+ fn test_dh_rfc5114() {
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let dh2 = Dh::get_2048_224().unwrap();
+ ctx.set_tmp_dh(&dh2).unwrap();
+ let dh3 = Dh::get_2048_256().unwrap();
+ ctx.set_tmp_dh(&dh3).unwrap();
+ }
+
+ #[test]
+ fn test_dh_params() {
+ let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
+ let prime_p = BigNum::from_hex_str(
+ "87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF\
+ 4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B47\
+ 58C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B6\
+ 3ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5\
+ 140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710\
+ C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597",
+ ).unwrap();
+ let prime_q = BigNum::from_hex_str(
+ "3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED\
+ 4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A\
+ 57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5\
+ 045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E\
+ 052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67E\
+ B6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659",
+ ).unwrap();
+ let generator = BigNum::from_hex_str(
+ "8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3",
+ )
+ .unwrap();
+ let dh = Dh::from_params(
+ prime_p.to_owned().unwrap(),
+ generator.to_owned().unwrap(),
+ prime_q.to_owned().unwrap(),
+ )
+ .unwrap();
+ ctx.set_tmp_dh(&dh).unwrap();
+
+ assert_eq!(dh.prime_p(), &prime_p);
+ assert_eq!(dh.prime_q().unwrap(), &prime_q);
+ assert_eq!(dh.generator(), &generator);
+ }
+
+ #[test]
+ #[cfg(ossl102)]
+ fn test_dh_stored_restored() {
+ let dh1 = Dh::get_2048_256().unwrap();
+ let key1 = dh1.generate_key().unwrap();
+
+ let dh2 = Dh::get_2048_256().unwrap();
+ let key2 = dh2
+ .set_private_key(key1.private_key().to_owned().unwrap())
+ .unwrap();
+
+ assert_eq!(key1.public_key(), key2.public_key());
+ assert_eq!(key1.private_key(), key2.private_key());
+ }
+
+ #[test]
+ #[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!(!dh2.check_key().unwrap());
+ }
+}
diff --git a/vendor/openssl/src/dsa.rs b/vendor/openssl/src/dsa.rs
new file mode 100644
index 0000000..1a63e8a
--- /dev/null
+++ b/vendor/openssl/src/dsa.rs
@@ -0,0 +1,697 @@
+//! 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<Dsa<Private>, ErrorStack> {
+ /// let sign = Dsa::generate(2048)?;
+ /// Ok(sign)
+ /// }
+ /// # fn main() {
+ /// # create_dsa();
+ /// # }
+ /// ```
+ pub struct Dsa<T>;
+ /// Reference to [`Dsa`].
+ ///
+ /// [`Dsa`]: struct.Dsa.html
+ pub struct DsaRef<T>;
+}
+
+impl<T> Clone for Dsa<T> {
+ fn clone(&self) -> Dsa<T> {
+ (**self).to_owned()
+ }
+}
+
+impl<T> ToOwned for DsaRef<T> {
+ type Owned = Dsa<T>;
+
+ fn to_owned(&self) -> Dsa<T> {
+ unsafe {
+ ffi::DSA_up_ref(self.as_ptr());
+ Dsa::from_ptr(self.as_ptr())
+ }
+ }
+}
+
+impl<T> DsaRef<T>
+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<T> DsaRef<T>
+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<T> DsaRef<T>
+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<Params> {
+ /// Creates a DSA params based upon the given parameters.
+ #[corresponds(DSA_set0_pqg)]
+ pub fn from_pqg(p: BigNum, q: BigNum, g: BigNum) -> Result<Dsa<Params>, 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<Dsa<Params>, 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<Dsa<Private>, 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<Private> {
+ /// Generate a DSA key pair.
+ ///
+ /// The `bits` parameter corresponds to the length of the prime `p`.
+ pub fn generate(bits: u32) -> Result<Dsa<Private>, 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<Dsa<Private>, 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<Public> {
+ 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<Public>,
+ 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<Public>,
+ 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<Dsa<Public>, 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<T> fmt::Debug for Dsa<T> {
+ 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<Self, ErrorStack> {
+ 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 }");
+ }
+}
diff --git a/vendor/openssl/src/ec.rs b/vendor/openssl/src/ec.rs
new file mode 100644
index 0000000..d541ddf
--- /dev/null
+++ b/vendor/openssl/src/ec.rs
@@ -0,0 +1,1345 @@
+//! 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<dyn std::error::Error>> {
+ /// 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<EcGroup, ErrorStack> {
+ 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<EcGroup, ErrorStack> {
+ 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(any(boringssl, 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<Nid> {
+ 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<Vec<u8>, 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<OpensslString, ErrorStack> {
+ 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<EcPoint, ErrorStack> {
+ 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<bool, ErrorStack> {
+ 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(any(boringssl, 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<bool, ErrorStack> {
+ 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<EcPoint, ErrorStack> {
+ 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<EcPoint, ErrorStack> {
+ 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<EcPoint, ErrorStack> {
+ 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<T>;
+ /// A reference to an [`EcKey`].
+ pub struct EcKeyRef<T>;
+}
+
+impl<T> EcKeyRef<T>
+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<T> EcKeyRef<T>
+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<T> EcKeyRef<T>
+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<T> ToOwned for EcKeyRef<T> {
+ type Owned = EcKey<T>;
+
+ fn to_owned(&self) -> EcKey<T> {
+ unsafe {
+ let r = ffi::EC_KEY_up_ref(self.as_ptr());
+ assert!(r == 1);
+ EcKey::from_ptr(self.as_ptr())
+ }
+ }
+}
+
+impl EcKey<Params> {
+ /// 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<EcKey<Params>, 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<EcKey<Params>, 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<Public> {
+ /// 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<dyn std::error::Error>> {
+ /// 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<EcKey<Public>, 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<EcKey<Public>, 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<Public>,
+ 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<Public>,
+ ffi::d2i_EC_PUBKEY
+ }
+}
+
+impl EcKey<Private> {
+ /// Generates a new public/private key pair on the specified curve.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
+ /// 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<EcKey<Private>, 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<EcKey<Private>, 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<Private>,
+ ffi::PEM_read_bio_ECPrivateKey
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded elliptic curve private key structure.
+ #[corresponds(d2i_ECPrivateKey)]
+ private_key_from_der,
+ EcKey<Private>,
+ ffi::d2i_ECPrivateKey
+ }
+}
+
+impl<T> Clone for EcKey<T> {
+ fn clone(&self) -> EcKey<T> {
+ (**self).to_owned()
+ }
+}
+
+impl<T> fmt::Debug for EcKey<T> {
+ 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(any(boringssl, 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);
+ }
+}
diff --git a/vendor/openssl/src/ecdsa.rs b/vendor/openssl/src/ecdsa.rs
new file mode 100644
index 0000000..f3b27b3
--- /dev/null
+++ b/vendor/openssl/src/ecdsa.rs
@@ -0,0 +1,224 @@
+//! 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<T>(data: &[u8], eckey: &EcKeyRef<T>) -> Result<EcdsaSig, ErrorStack>
+ 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<EcdsaSig, ErrorStack> {
+ 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<T>(&self, data: &[u8], eckey: &EcKeyRef<T>) -> Result<bool, ErrorStack>
+ 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<Private>) -> Result<EcKey<Public>, ErrorStack> {
+ EcKey::from_public_key(group, x.public_key())
+ }
+
+ #[test]
+ #[cfg_attr(osslconf = "OPENSSL_NO_EC2M", ignore)]
+ fn sign_and_verify() {
+ let group = EcGroup::from_curve_name(Nid::X9_62_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_EC2M", 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_EC2M", 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);
+ }
+}
diff --git a/vendor/openssl/src/encrypt.rs b/vendor/openssl/src/encrypt.rs
new file mode 100644
index 0000000..4522146
--- /dev/null
+++ b/vendor/openssl/src/encrypt.rs
@@ -0,0 +1,578 @@
+//! 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<T>(pkey: &'a PKeyRef<T>) -> Result<Encrypter<'a>, 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<Padding, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<T>(pkey: &'a PKeyRef<T>) -> Result<Decrypter<'a>, 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<Padding, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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());
+ }
+}
diff --git a/vendor/openssl/src/envelope.rs b/vendor/openssl/src/envelope.rs
new file mode 100644
index 0000000..25055ac
--- /dev/null
+++ b/vendor/openssl/src/envelope.rs
@@ -0,0 +1,181 @@
+//! 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<Vec<u8>>,
+ enc_keys: Vec<Vec<u8>>,
+}
+
+impl Seal {
+ /// Creates a new `Seal`.
+ pub fn new<T>(cipher: Cipher, pub_keys: &[PKey<T>]) -> Result<Seal, ErrorStack>
+ 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<u8>] {
+ &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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ self.ctx.cipher_final(output)
+ }
+}
+
+/// Represents an EVP_Open context.
+pub struct Open {
+ ctx: CipherCtx,
+}
+
+impl Open {
+ /// Creates a new `Open`.
+ pub fn new<T>(
+ cipher: Cipher,
+ priv_key: &PKeyRef<T>,
+ iv: Option<&[u8]>,
+ encrypted_key: &[u8],
+ ) -> Result<Open, ErrorStack>
+ 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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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]);
+ }
+}
diff --git a/vendor/openssl/src/error.rs b/vendor/openssl/src/error.rs
new file mode 100644
index 0000000..e097ce6
--- /dev/null
+++ b/vendor/openssl/src/error.rs
@@ -0,0 +1,418 @@
+//! Errors returned by OpenSSL library.
+//!
+//! OpenSSL errors are stored in an `ErrorStack`. Most methods in the crate
+//! returns a `Result<T, ErrorStack>` 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<Error>);
+
+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<ErrorStack> for io::Error {
+ fn from(e: ErrorStack) -> io::Error {
+ io::Error::new(io::ErrorKind::Other, e)
+ }
+}
+
+impl From<ErrorStack> 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<ShimStr>,
+ data: Option<Cow<'static, str>>,
+}
+
+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<Error> {
+ 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<RetStr<'_>> {
+ 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);
+ }
+}
diff --git a/vendor/openssl/src/ex_data.rs b/vendor/openssl/src/ex_data.rs
new file mode 100644
index 0000000..d4f0021
--- /dev/null
+++ b/vendor/openssl/src/ex_data.rs
@@ -0,0 +1,32 @@
+use 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<T, U>(c_int, PhantomData<(T, U)>);
+
+impl<T, U> Copy for Index<T, U> {}
+
+impl<T, U> Clone for Index<T, U> {
+ fn clone(&self) -> Index<T, U> {
+ *self
+ }
+}
+
+impl<T, U> Index<T, U> {
+ /// 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<T, U> {
+ Index(idx, PhantomData)
+ }
+
+ #[allow(clippy::trivially_copy_pass_by_ref)]
+ pub fn as_raw(&self) -> c_int {
+ self.0
+ }
+}
diff --git a/vendor/openssl/src/fips.rs b/vendor/openssl/src/fips.rs
new file mode 100644
index 0000000..2a8a2fe
--- /dev/null
+++ b/vendor/openssl/src/fips.rs
@@ -0,0 +1,21 @@
+//! 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 }
+}
diff --git a/vendor/openssl/src/hash.rs b/vendor/openssl/src/hash.rs
new file mode 100644
index 0000000..52d73de
--- /dev/null
+++ b/vendor/openssl/src/hash.rs
@@ -0,0 +1,800 @@
+//! Message digest (hash) computation support.
+//!
+//! # Examples
+//!
+//! Calculate a hash in one go:
+//!
+//! ```
+//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
+//! 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<dyn std::error::Error>> {
+//! 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))] {
+ 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<MessageDigest> {
+ 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<MessageDigest> {
+ 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(ossl111)]
+ pub fn sha3_224() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha3_224()) }
+ }
+
+ #[cfg(ossl111)]
+ pub fn sha3_256() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha3_256()) }
+ }
+
+ #[cfg(ossl111)]
+ pub fn sha3_384() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha3_384()) }
+ }
+
+ #[cfg(ossl111)]
+ pub fn sha3_512() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_sha3_512()) }
+ }
+
+ #[cfg(ossl111)]
+ pub fn shake_128() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_shake128()) }
+ }
+
+ #[cfg(ossl111)]
+ pub fn shake_256() -> MessageDigest {
+ unsafe { MessageDigest(ffi::EVP_shake256()) }
+ }
+
+ #[cfg(not(any(boringssl, 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<dyn std::error::Error>> {
+/// 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<Hasher, ErrorStack> {
+ 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<DigestBytes, ErrorStack> {
+ 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<usize> {
+ 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<dyn std::error::Error>> {
+/// 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<DigestBytes, ErrorStack> {
+ 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(ossl111)]
+ #[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(ossl111)]
+ #[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(ossl111)]
+ #[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(ossl111)]
+ #[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(boringssl))]
+ #[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()
+ )
+ }
+}
diff --git a/vendor/openssl/src/lib.rs b/vendor/openssl/src/lib.rs
new file mode 100644
index 0000000..fe29d02
--- /dev/null
+++ b/vendor/openssl/src/lib.rs
@@ -0,0 +1,222 @@
+//! 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
+//! ```
+//!
+//! ## 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)]
+
+#[doc(inline)]
+pub use ffi::init;
+
+use libc::c_int;
+
+use crate::error::ErrorStack;
+
+#[macro_use]
+mod macros;
+
+mod bio;
+#[macro_use]
+mod util;
+pub mod aes;
+pub mod asn1;
+pub mod base64;
+pub mod bn;
+pub mod cipher;
+pub mod cipher_ctx;
+#[cfg(all(not(boringssl), 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(any(boringssl, 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<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
+ if r.is_null() {
+ Err(ErrorStack::get())
+ } else {
+ Ok(r)
+ }
+}
+
+#[inline]
+fn cvt(r: c_int) -> Result<c_int, ErrorStack> {
+ if r <= 0 {
+ Err(ErrorStack::get())
+ } else {
+ Ok(r)
+ }
+}
+
+#[inline]
+fn cvt_n(r: c_int) -> Result<c_int, ErrorStack> {
+ if r < 0 {
+ Err(ErrorStack::get())
+ } else {
+ Ok(r)
+ }
+}
diff --git a/vendor/openssl/src/lib_ctx.rs b/vendor/openssl/src/lib_ctx.rs
new file mode 100644
index 0000000..1fcdc65
--- /dev/null
+++ b/vendor/openssl/src/lib_ctx.rs
@@ -0,0 +1,22 @@
+use 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<Self, ErrorStack> {
+ unsafe {
+ let ptr = cvt_p(ffi::OSSL_LIB_CTX_new())?;
+ Ok(LibCtx::from_ptr(ptr))
+ }
+ }
+}
diff --git a/vendor/openssl/src/macros.rs b/vendor/openssl/src/macros.rs
new file mode 100644
index 0000000..671a11b
--- /dev/null
+++ b/vendor/openssl/src/macros.rs
@@ -0,0 +1,270 @@
+macro_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<F>(pem: &[u8], callback: F) -> Result<$t, crate::error::ErrorStack>
+ where F: FnOnce(&mut [u8]) -> Result<usize, crate::error::ErrorStack>
+ {
+ 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::<F>),
+ &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<Vec<u8>, 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<Vec<u8>, 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<Vec<u8>, 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<Vec<u8>, 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<T>;
+ $(#[$borrowed_attr:meta])*
+ pub struct $borrowed:ident<T>;
+ ) => {
+ $(#[$owned_attr])*
+ pub struct $owned<T>(*mut $ctype, ::std::marker::PhantomData<T>);
+
+ $(#[$impl_attr])*
+ impl<T> ::foreign_types::ForeignType for $owned<T> {
+ type CType = $ctype;
+ type Ref = $borrowed<T>;
+
+ #[inline]
+ unsafe fn from_ptr(ptr: *mut $ctype) -> $owned<T> {
+ $owned(ptr, ::std::marker::PhantomData)
+ }
+
+ #[inline]
+ fn as_ptr(&self) -> *mut $ctype {
+ self.0
+ }
+ }
+
+ impl<T> Drop for $owned<T> {
+ #[inline]
+ fn drop(&mut self) {
+ unsafe { $drop(self.0) }
+ }
+ }
+
+ $(
+ impl<T> Clone for $owned<T> {
+ #[inline]
+ fn clone(&self) -> $owned<T> {
+ unsafe {
+ let handle: *mut $ctype = $clone(self.0);
+ ::foreign_types::ForeignType::from_ptr(handle)
+ }
+ }
+ }
+
+ impl<T> ::std::borrow::ToOwned for $borrowed<T> {
+ type Owned = $owned<T>;
+ #[inline]
+ fn to_owned(&self) -> $owned<T> {
+ unsafe {
+ let handle: *mut $ctype =
+ $clone(::foreign_types::ForeignTypeRef::as_ptr(self));
+ $crate::ForeignType::from_ptr(handle)
+ }
+ }
+ }
+ )*
+
+ impl<T> ::std::ops::Deref for $owned<T> {
+ type Target = $borrowed<T>;
+
+ #[inline]
+ fn deref(&self) -> &$borrowed<T> {
+ unsafe { ::foreign_types::ForeignTypeRef::from_ptr(self.0) }
+ }
+ }
+
+ impl<T> ::std::ops::DerefMut for $owned<T> {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut $borrowed<T> {
+ unsafe { ::foreign_types::ForeignTypeRef::from_ptr_mut(self.0) }
+ }
+ }
+
+ impl<T> ::std::borrow::Borrow<$borrowed<T>> for $owned<T> {
+ #[inline]
+ fn borrow(&self) -> &$borrowed<T> {
+ &**self
+ }
+ }
+
+ impl<T> ::std::convert::AsRef<$borrowed<T>> for $owned<T> {
+ #[inline]
+ fn as_ref(&self) -> &$borrowed<T> {
+ &**self
+ }
+ }
+
+ $(#[$borrowed_attr])*
+ pub struct $borrowed<T>(::foreign_types::Opaque, ::std::marker::PhantomData<T>);
+
+ $(#[$impl_attr])*
+ impl<T> ::foreign_types::ForeignTypeRef for $borrowed<T> {
+ type CType = $ctype;
+ }
+
+ unsafe impl<T> Send for $owned<T>{}
+ unsafe impl<T> Send for $borrowed<T>{}
+ unsafe impl<T> Sync for $owned<T>{}
+ unsafe impl<T> Sync for $borrowed<T>{}
+ };
+}
diff --git a/vendor/openssl/src/md.rs b/vendor/openssl/src/md.rs
new file mode 100644
index 0000000..4ade8e8
--- /dev/null
+++ b/vendor/openssl/src/md.rs
@@ -0,0 +1,235 @@
+//! 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<Self, ErrorStack> {
+ 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(ossl111)]
+ #[inline]
+ pub fn sha3_224() -> &'static MdRef {
+ unsafe { MdRef::from_ptr(ffi::EVP_sha3_224() as *mut _) }
+ }
+
+ #[cfg(ossl111)]
+ #[inline]
+ pub fn sha3_256() -> &'static MdRef {
+ unsafe { MdRef::from_ptr(ffi::EVP_sha3_256() as *mut _) }
+ }
+
+ #[cfg(ossl111)]
+ #[inline]
+ pub fn sha3_384() -> &'static MdRef {
+ unsafe { MdRef::from_ptr(ffi::EVP_sha3_384() as *mut _) }
+ }
+
+ #[cfg(ossl111)]
+ #[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]
+ #[cfg(not(boringssl))]
+ 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]
+ #[cfg(not(boringssl))]
+ 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())) }
+ }
+}
diff --git a/vendor/openssl/src/md_ctx.rs b/vendor/openssl/src/md_ctx.rs
new file mode 100644
index 0000000..156f3c2
--- /dev/null
+++ b/vendor/openssl/src/md_ctx.rs
@@ -0,0 +1,540 @@
+//! 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))] {
+ 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<Self, ErrorStack> {
+ 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<T>,
+ ) -> Result<&'a mut PkeyCtxRef<T>, 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<T>,
+ ) -> Result<&'a mut PkeyCtxRef<T>, 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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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<bool, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<u8>,
+ ) -> Result<usize, ErrorStack> {
+ 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<bool, ErrorStack> {
+ 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);
+ }
+}
diff --git a/vendor/openssl/src/memcmp.rs b/vendor/openssl/src/memcmp.rs
new file mode 100644
index 0000000..91281b9
--- /dev/null
+++ b/vendor/openssl/src/memcmp.rs
@@ -0,0 +1,93 @@
+//! 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]);
+ }
+}
diff --git a/vendor/openssl/src/nid.rs b/vendor/openssl/src/nid.rs
new file mode 100644
index 0000000..91fcdec
--- /dev/null
+++ b/vendor/openssl/src/nid.rs
@@ -0,0 +1,1179 @@
+//! 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<Nid, ErrorStack> {
+ 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<SignatureAlgorithms> {
+ 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(ossl110)]
+ pub const BRAINPOOL_P256R1: Nid = Nid(ffi::NID_brainpoolP256r1);
+ #[cfg(ossl110)]
+ pub const BRAINPOOL_P384R1: Nid = Nid(ffi::NID_brainpoolP384r1);
+ #[cfg(ossl110)]
+ 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(ossl111)]
+ pub const SHA3_224: Nid = Nid(ffi::NID_sha3_224);
+ #[cfg(ossl111)]
+ pub const SHA3_256: Nid = Nid(ffi::NID_sha3_256);
+ #[cfg(ossl111)]
+ pub const SHA3_384: Nid = Nid(ffi::NID_sha3_384);
+ #[cfg(ossl111)]
+ 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(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"
+ );
+ }
+ }
+}
diff --git a/vendor/openssl/src/ocsp.rs b/vendor/openssl/src/ocsp.rs
new file mode 100644
index 0000000..93a5d36
--- /dev/null
+++ b/vendor/openssl/src/ocsp.rs
@@ -0,0 +1,352 @@
+use 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<u32>) -> 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<X509>,
+ 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<OcspStatus<'a>> {
+ 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<OcspCertId, ErrorStack> {
+ 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<OcspResponse, ErrorStack> {
+ 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<OcspBasicResponse, ErrorStack> {
+ 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<OcspRequest, ErrorStack> {
+ 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;
+}
diff --git a/vendor/openssl/src/pkcs12.rs b/vendor/openssl/src/pkcs12.rs
new file mode 100644
index 0000000..d74705e
--- /dev/null
+++ b/vendor/openssl/src/pkcs12.rs
@@ -0,0 +1,392 @@
+//! 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<ParsedPkcs12, ErrorStack> {
+ 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<ParsedPkcs12_2, ErrorStack> {
+ 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<Private>,
+ pub cert: X509,
+ pub chain: Option<Stack<X509>>,
+}
+
+pub struct ParsedPkcs12_2 {
+ pub pkey: Option<PKey<Private>>,
+ pub cert: Option<X509>,
+ pub ca: Option<Stack<X509>>,
+}
+
+pub struct Pkcs12Builder {
+ // FIXME borrow
+ name: Option<CString>,
+ pkey: Option<PKey<Private>>,
+ cert: Option<X509>,
+ ca: Option<Stack<X509>>,
+ nid_key: Nid,
+ nid_cert: Nid,
+ iter: c_int,
+ mac_iter: c_int,
+ // FIXME remove
+ #[cfg(not(boringssl))]
+ mac_md: Option<MessageDigest>,
+}
+
+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<T>(&mut self, pkey: &PKeyRef<T>) -> &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<X509>) -> &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<T>(
+ mut self,
+ password: &str,
+ friendly_name: &str,
+ pkey: &PKeyRef<T>,
+ cert: &X509Ref,
+ ) -> Result<Pkcs12, ErrorStack>
+ 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<Pkcs12, ErrorStack> {
+ 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.unwrap().digest(MessageDigest::sha1()).unwrap()),
+ "59172d9313e84459bcff27f967e79e6e9217e584"
+ );
+
+ 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);
+ }
+}
diff --git a/vendor/openssl/src/pkcs5.rs b/vendor/openssl/src/pkcs5.rs
new file mode 100644
index 0000000..cd704e8
--- /dev/null
+++ b/vendor/openssl/src/pkcs5.rs
@@ -0,0 +1,310 @@
+#[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<u8>,
+ pub iv: Option<Vec<u8>>,
+}
+
+/// 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<KeyIvPair, ErrorStack> {
+ 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(any(ossl110, boringssl))]
+#[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);
+ }
+}
diff --git a/vendor/openssl/src/pkcs7.rs b/vendor/openssl/src/pkcs7.rs
new file mode 100644
index 0000000..a272c59
--- /dev/null
+++ b/vendor/openssl/src/pkcs7.rs
@@ -0,0 +1,448 @@
+use bitflags::bitflags;
+use foreign_types::{ForeignType, ForeignTypeRef};
+use libc::c_int;
+use std::mem;
+use std::ptr;
+
+use crate::bio::{MemBio, MemBioSlice};
+use crate::error::ErrorStack;
+use crate::pkey::{HasPrivate, PKeyRef};
+use crate::stack::{Stack, StackRef};
+use crate::symm::Cipher;
+use crate::x509::store::X509StoreRef;
+use crate::x509::{X509Ref, X509};
+use crate::{cvt, cvt_p};
+use openssl_macros::corresponds;
+
+foreign_type_and_impl_send_sync! {
+ type CType = ffi::PKCS7;
+ fn drop = ffi::PKCS7_free;
+
+ /// A PKCS#7 structure.
+ ///
+ /// Contains signed and/or encrypted data.
+ pub struct Pkcs7;
+
+ /// Reference to `Pkcs7`
+ pub struct Pkcs7Ref;
+}
+
+bitflags! {
+ #[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<Vec<u8>>), 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<X509>,
+ input: &[u8],
+ cipher: Cipher,
+ flags: Pkcs7Flags,
+ ) -> Result<Pkcs7, ErrorStack> {
+ 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<PT>(
+ signcert: &X509Ref,
+ pkey: &PKeyRef<PT>,
+ certs: &StackRef<X509>,
+ input: &[u8],
+ flags: Pkcs7Flags,
+ ) -> Result<Pkcs7, ErrorStack>
+ 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<Vec<u8>, 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<PT>(
+ &self,
+ pkey: &PKeyRef<PT>,
+ cert: &X509Ref,
+ flags: Pkcs7Flags,
+ ) -> Result<Vec<u8>, 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<X509>,
+ store: &X509StoreRef,
+ indata: Option<&[u8]>,
+ out: Option<&mut Vec<u8>>,
+ 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<X509>,
+ flags: Pkcs7Flags,
+ ) -> Result<Stack<X509>, 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::<X509>::from_ptr(ptr);
+ for cert in &stack {
+ mem::forget(cert.to_owned());
+ }
+
+ Ok(stack)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::hash::MessageDigest;
+ use crate::pkcs7::{Pkcs7, Pkcs7Flags};
+ use crate::pkey::PKey;
+ use crate::stack::Stack;
+ use crate::symm::Cipher;
+ use crate::x509::store::X509StoreBuilder;
+ use crate::x509::X509;
+
+ #[test]
+ fn encrypt_decrypt_test() {
+ let cert = include_bytes!("../test/certs.pem");
+ let cert = X509::from_pem(cert).unwrap();
+ let mut certs = Stack::new().unwrap();
+ certs.push(cert.clone()).unwrap();
+ let message: String = String::from("foo");
+ let 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");
+
+ let encrypted = pkcs7
+ .to_smime(message.as_bytes(), flags)
+ .expect("should succeed");
+
+ let (pkcs7_decoded, _) = Pkcs7::from_smime(encrypted.as_slice()).expect("should succeed");
+
+ let decoded = pkcs7_decoded
+ .decrypt(&pkey, &cert, Pkcs7Flags::empty())
+ .expect("should succeed");
+
+ assert_eq!(decoded, message.into_bytes());
+ }
+
+ #[test]
+ fn sign_verify_test_detached() {
+ let cert = include_bytes!("../test/cert.pem");
+ let cert = X509::from_pem(cert).unwrap();
+ let certs = Stack::new().unwrap();
+ let message = "foo";
+ let flags = Pkcs7Flags::STREAM | Pkcs7Flags::DETACHED;
+ let pkey = include_bytes!("../test/key.pem");
+ let pkey = PKey::private_key_from_pem(pkey).unwrap();
+ let mut store_builder = X509StoreBuilder::new().expect("should succeed");
+
+ let root_ca = include_bytes!("../test/root-ca.pem");
+ let root_ca = X509::from_pem(root_ca).unwrap();
+ store_builder.add_cert(root_ca).expect("should succeed");
+
+ let store = store_builder.build();
+
+ let pkcs7 =
+ Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
+
+ let signed = pkcs7
+ .to_smime(message.as_bytes(), flags)
+ .expect("should succeed");
+ println!("{:?}", String::from_utf8(signed.clone()).unwrap());
+ let (pkcs7_decoded, content) =
+ Pkcs7::from_smime(signed.as_slice()).expect("should succeed");
+
+ let mut output = Vec::new();
+ pkcs7_decoded
+ .verify(
+ &certs,
+ &store,
+ Some(message.as_bytes()),
+ Some(&mut output),
+ flags,
+ )
+ .expect("should succeed");
+
+ assert_eq!(output, message.as_bytes());
+ assert_eq!(content.expect("should be non-empty"), message.as_bytes());
+ }
+
+ /// 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");
+
+ 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");
+
+ 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());
+ }
+}
diff --git a/vendor/openssl/src/pkey.rs b/vendor/openssl/src/pkey.rs
new file mode 100644
index 0000000..453aeed
--- /dev/null
+++ b/vendor/openssl/src/pkey.rs
@@ -0,0 +1,1173 @@
+//! 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<u8> = 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(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);
+ pub const EC: Id = Id(ffi::EVP_PKEY_EC);
+ #[cfg(ossl111)]
+ pub const SM2: Id = Id(ffi::EVP_PKEY_SM2);
+
+ #[cfg(any(ossl110, boringssl))]
+ 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<T> 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<T> 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<T>;
+ /// Reference to `PKey`.
+ pub struct PKeyRef<T>;
+}
+
+impl<T> ToOwned for PKeyRef<T> {
+ type Owned = PKey<T>;
+
+ fn to_owned(&self) -> PKey<T> {
+ unsafe {
+ EVP_PKEY_up_ref(self.as_ptr());
+ PKey::from_ptr(self.as_ptr())
+ }
+ }
+}
+
+impl<T> PKeyRef<T> {
+ /// Returns a copy of the internal RSA key.
+ #[corresponds(EVP_PKEY_get1_RSA)]
+ pub fn rsa(&self) -> Result<Rsa<T>, 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<Dsa<T>, 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<Dh<T>, 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<EcKey<T>, 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<T> PKeyRef<T>
+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<U>(&self, other: &PKeyRef<U>) -> 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<Vec<u8>, 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<T> PKeyRef<T>
+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<Vec<u8>, 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<Vec<u8>, 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<Vec<u8>, 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<T> fmt::Debug for PKey<T> {
+ 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<T> Clone for PKey<T> {
+ fn clone(&self) -> PKey<T> {
+ PKeyRef::to_owned(self)
+ }
+}
+
+impl<T> PKey<T> {
+ /// Creates a new `PKey` containing an RSA key.
+ #[corresponds(EVP_PKEY_assign_RSA)]
+ pub fn from_rsa(rsa: Rsa<T>) -> Result<PKey<T>, 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<T>) -> Result<PKey<T>, 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<T>) -> Result<PKey<T>, 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 an elliptic curve key.
+ #[corresponds(EVP_PKEY_assign_EC_KEY)]
+ pub fn from_ec_key(ec_key: EcKey<T>) -> Result<PKey<T>, 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<Private> {
+ /// 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<PKey<Private>, 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<PKey<Private>, 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<PKey<Private>, 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<dyn std::error::Error>> {
+ /// 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<PKey<Private>, 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<dyn std::error::Error>> {
+ /// 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<PKey<Private>, 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<dyn std::error::Error>> {
+ /// 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<PKey<Private>, 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<dyn std::error::Error>> {
+ /// 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<PKey<Private>, 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<PKey<Private>, 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<Private>,
+ 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<Private>,
+ 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<PKey<Private>, 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<F>(
+ der: &[u8],
+ callback: F,
+ ) -> Result<PKey<Private>, ErrorStack>
+ where
+ F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
+ {
+ 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::<F>),
+ &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<PKey<Private>, 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<PKey<Private>, 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<Public> {
+ 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,
+ PKey<Public>,
+ ffi::PEM_read_bio_PUBKEY
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded SubjectPublicKeyInfo structure.
+ #[corresponds(d2i_PUBKEY)]
+ public_key_from_der,
+ PKey<Public>,
+ 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<PKey<Public>, 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<T> TryFrom<EcKey<T>> for PKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(ec_key: EcKey<T>) -> Result<PKey<T>, ErrorStack> {
+ PKey::from_ec_key(ec_key)
+ }
+}
+
+impl<T> TryFrom<PKey<T>> for EcKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(pkey: PKey<T>) -> Result<EcKey<T>, ErrorStack> {
+ pkey.ec_key()
+ }
+}
+
+impl<T> TryFrom<Rsa<T>> for PKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(rsa: Rsa<T>) -> Result<PKey<T>, ErrorStack> {
+ PKey::from_rsa(rsa)
+ }
+}
+
+impl<T> TryFrom<PKey<T>> for Rsa<T> {
+ type Error = ErrorStack;
+
+ fn try_from(pkey: PKey<T>) -> Result<Rsa<T>, ErrorStack> {
+ pkey.rsa()
+ }
+}
+
+impl<T> TryFrom<Dsa<T>> for PKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(dsa: Dsa<T>) -> Result<PKey<T>, ErrorStack> {
+ PKey::from_dsa(dsa)
+ }
+}
+
+impl<T> TryFrom<PKey<T>> for Dsa<T> {
+ type Error = ErrorStack;
+
+ fn try_from(pkey: PKey<T>) -> Result<Dsa<T>, ErrorStack> {
+ pkey.dsa()
+ }
+}
+
+#[cfg(not(boringssl))]
+impl<T> TryFrom<Dh<T>> for PKey<T> {
+ type Error = ErrorStack;
+
+ fn try_from(dh: Dh<T>) -> Result<PKey<T>, ErrorStack> {
+ PKey::from_dh(dh)
+ }
+}
+
+impl<T> TryFrom<PKey<T>> for Dh<T> {
+ type Error = ErrorStack;
+
+ fn try_from(pkey: PKey<T>) -> Result<Dh<T>, 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<Private> = rsa.clone().try_into().unwrap();
+ let rsa_: Rsa<Private> = 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<Private> = dsa.clone().try_into().unwrap();
+ let dsa_: Dsa<Private> = 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<Private> = ec_key.clone().try_into().unwrap();
+ let ec_key_: EcKey<Private> = 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<Private> = 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<Private> = dh.try_into().unwrap();
+ let dh_: Dh<Private> = 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<PKey<Private>, 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<PKey<Private>, 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());
+ }
+}
diff --git a/vendor/openssl/src/pkey_ctx.rs b/vendor/openssl/src/pkey_ctx.rs
new file mode 100644
index 0000000..4ac32a8
--- /dev/null
+++ b/vendor/openssl/src/pkey_ctx.rs
@@ -0,0 +1,1002 @@
+//! 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;
+use openssl_macros::corresponds;
+use std::convert::TryFrom;
+use std::ptr;
+
+/// HKDF modes of operation.
+#[cfg(ossl111)]
+pub struct HkdfMode(c_int);
+
+#[cfg(ossl111)]
+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);
+}
+
+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<T>;
+ /// A reference to a [`PkeyCtx`].
+ pub struct PkeyCtxRef<T>;
+}
+
+impl<T> PkeyCtx<T> {
+ /// Creates a new pkey context using the provided key.
+ #[corresponds(EVP_PKEY_CTX_new)]
+ #[inline]
+ pub fn new(pkey: &PKeyRef<T>) -> Result<Self, ErrorStack> {
+ 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<Self, ErrorStack> {
+ unsafe {
+ let ptr = cvt_p(ffi::EVP_PKEY_CTX_new_id(id.as_raw(), ptr::null_mut()))?;
+ Ok(PkeyCtx::from_ptr(ptr))
+ }
+ }
+}
+
+impl<T> PkeyCtxRef<T>
+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<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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<bool, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<T> PkeyCtxRef<T>
+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<U>(&mut self, key: &PKeyRef<U>) -> 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<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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<T> PkeyCtxRef<T> {
+ /// 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<Padding, ErrorStack> {
+ 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))]
+ #[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(ossl111)]
+ #[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))]
+ #[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))]
+ #[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))]
+ #[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<usize, ErrorStack> {
+ 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<u8>) -> Result<usize, ErrorStack> {
+ 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<PKey<Private>, ErrorStack> {
+ unsafe {
+ let mut key = ptr::null_mut();
+ cvt(ffi::EVP_PKEY_keygen(self.as_ptr(), &mut key))?;
+ Ok(PKey::from_ptr(key))
+ }
+ }
+}
+
+#[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))]
+ 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(ossl111)]
+ 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(ossl111)]
+ 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);
+ }
+}
diff --git a/vendor/openssl/src/provider.rs b/vendor/openssl/src/provider.rs
new file mode 100644
index 0000000..147fadf
--- /dev/null
+++ b/vendor/openssl/src/provider.rs
@@ -0,0 +1,77 @@
+use 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<Self, ErrorStack> {
+ 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<Self, ErrorStack> {
+ 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 _,
+ ))?;
+
+ 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(|_| ())
+ }
+ }
+}
diff --git a/vendor/openssl/src/rand.rs b/vendor/openssl/src/rand.rs
new file mode 100644
index 0000000..8317951
--- /dev/null
+++ b/vendor/openssl/src/rand.rs
@@ -0,0 +1,60 @@
+//! 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(|_| ())
+ }
+}
+
+/// 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 {
+ use super::rand_bytes;
+
+ #[test]
+ fn test_rand_bytes() {
+ let mut buf = [0; 32];
+ rand_bytes(&mut buf).unwrap();
+ }
+}
diff --git a/vendor/openssl/src/rsa.rs b/vendor/openssl/src/rsa.rs
new file mode 100644
index 0000000..f155b12
--- /dev/null
+++ b/vendor/openssl/src/rsa.rs
@@ -0,0 +1,852 @@
+//! 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<T>;
+
+ /// Reference to `RSA`
+ pub struct RsaRef<T>;
+}
+
+impl<T> Clone for Rsa<T> {
+ fn clone(&self) -> Rsa<T> {
+ (**self).to_owned()
+ }
+}
+
+impl<T> ToOwned for RsaRef<T> {
+ type Owned = Rsa<T>;
+
+ fn to_owned(&self) -> Rsa<T> {
+ unsafe {
+ ffi::RSA_up_ref(self.as_ptr());
+ Rsa::from_ptr(self.as_ptr())
+ }
+ }
+}
+
+impl<T> RsaRef<T>
+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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<bool, ErrorStack> {
+ unsafe {
+ let result = ffi::RSA_check_key(self.as_ptr()) as i32;
+ if result == -1 {
+ Err(ErrorStack::get())
+ } else {
+ Ok(result == 1)
+ }
+ }
+ }
+}
+
+impl<T> RsaRef<T>
+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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<Public> {
+ /// 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<Rsa<Public>, 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<Public>,
+ 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<Public>,
+ 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<Public>,
+ ffi::d2i_RSA_PUBKEY
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded PKCS#1 RSAPublicKey structure.
+ #[corresponds(d2i_RSAPublicKey)]
+ public_key_from_der_pkcs1,
+ Rsa<Public>,
+ ffi::d2i_RSAPublicKey
+ }
+}
+
+pub struct RsaPrivateKeyBuilder {
+ rsa: Rsa<Private>,
+}
+
+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<RsaPrivateKeyBuilder, ErrorStack> {
+ 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<RsaPrivateKeyBuilder, ErrorStack> {
+ 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<RsaPrivateKeyBuilder, ErrorStack> {
+ 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<Private> {
+ self.rsa
+ }
+}
+
+impl Rsa<Private> {
+ /// 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<dyn std::error::Error>> {
+ /// # 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<Rsa<Private>, 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<Rsa<Private>, 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<Rsa<Private>, 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<Private>,
+ ffi::PEM_read_bio_RSAPrivateKey
+ }
+
+ from_der! {
+ /// Decodes a DER-encoded PKCS#1 RSAPrivateKey structure.
+ #[corresponds(d2i_RSAPrivateKey)]
+ private_key_from_der,
+ Rsa<Private>,
+ ffi::d2i_RSAPrivateKey
+ }
+}
+
+impl<T> fmt::Debug for Rsa<T> {
+ 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();
+ }
+}
diff --git a/vendor/openssl/src/sha.rs b/vendor/openssl/src/sha.rs
new file mode 100644
index 0000000..2412890
--- /dev/null
+++ b/vendor/openssl/src/sha.rs
@@ -0,0 +1,463 @@
+//! 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);
+ }
+}
diff --git a/vendor/openssl/src/sign.rs b/vendor/openssl/src/sign.rs
new file mode 100644
index 0000000..1c770d1
--- /dev/null
+++ b/vendor/openssl/src/sign.rs
@@ -0,0 +1,886 @@
+//! 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(ossl110)] {
+ use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
+ } else {
+ use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
+ }
+}
+
+/// Salt lengths that must be used with `set_rsa_pss_saltlen`.
+pub struct RsaPssSaltlen(c_int);
+
+impl RsaPssSaltlen {
+ /// Returns the integer representation of `RsaPssSaltlen`.
+ 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<T>) -> Result<Signer<'a>, 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<T>) -> Result<Signer<'a>, ErrorStack>
+ where
+ T: HasPrivate,
+ {
+ Self::new_intern(None, pkey)
+ }
+
+ fn new_intern<'a, T>(
+ type_: Option<MessageDigest>,
+ pkey: &PKeyRef<T>,
+ ) -> Result<Signer<'a>, 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<Padding, ErrorStack> {
+ 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<usize, ErrorStack> {
+ self.len_intern()
+ }
+
+ #[cfg(all(not(ossl111), not(boringssl), not(libressl370)))]
+ fn len_intern(&self) -> Result<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<usize, ErrorStack> {
+ 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<Vec<u8>, 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<usize, ErrorStack> {
+ 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<Vec<u8>, 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<usize> {
+ 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<T>(type_: MessageDigest, pkey: &'a PKeyRef<T>) -> Result<Verifier<'a>, 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<T>(pkey: &'a PKeyRef<T>) -> Result<Verifier<'a>, ErrorStack>
+ where
+ T: HasPublic,
+ {
+ Verifier::new_intern(None, pkey)
+ }
+
+ fn new_intern<T>(
+ type_: Option<MessageDigest>,
+ pkey: &'a PKeyRef<T>,
+ ) -> Result<Verifier<'a>, 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<Padding, ErrorStack> {
+ 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<bool, ErrorStack> {
+ 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<bool, ErrorStack> {
+ 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<usize> {
+ 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<u8>, Vec<u8>, Vec<u8>)]) {
+ 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<u8>, Vec<u8>, Vec<u8>); 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<u8>, Vec<u8>, Vec<u8>); 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());
+ }
+}
diff --git a/vendor/openssl/src/srtp.rs b/vendor/openssl/src/srtp.rs
new file mode 100644
index 0000000..595757d
--- /dev/null
+++ b/vendor/openssl/src/srtp.rs
@@ -0,0 +1,66 @@
+use 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
+ }
+}
diff --git a/vendor/openssl/src/ssl/bio.rs b/vendor/openssl/src/ssl/bio.rs
new file mode 100644
index 0000000..36cea23
--- /dev/null
+++ b/vendor/openssl/src/ssl/bio.rs
@@ -0,0 +1,290 @@
+use 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<S> {
+ pub stream: S,
+ pub error: Option<io::Error>,
+ pub panic: Option<Box<dyn Any + Send>>,
+ pub dtls_mtu_size: c_long,
+}
+
+/// Safe wrapper for `BIO_METHOD`
+pub struct BioMethod(BIO_METHOD);
+
+impl BioMethod {
+ fn new<S: Read + Write>() -> Result<BioMethod, ErrorStack> {
+ BIO_METHOD::new::<S>().map(BioMethod)
+ }
+}
+
+unsafe impl Sync for BioMethod {}
+unsafe impl Send for BioMethod {}
+
+pub fn new<S: Read + Write>(stream: S) -> Result<(*mut BIO, BioMethod), ErrorStack> {
+ let method = BioMethod::new::<S>()?;
+
+ 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<S>(bio: *mut BIO) -> Option<io::Error> {
+ let state = state::<S>(bio);
+ state.error.take()
+}
+
+pub unsafe fn take_panic<S>(bio: *mut BIO) -> Option<Box<dyn Any + Send>> {
+ let state = state::<S>(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<S>);
+ &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<S>(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::<S>(bio).dtls_mtu_size = mtu_size as c_long;
+}
+
+unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState<S> {
+ &mut *(BIO_get_data(bio) as *mut _)
+}
+
+unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int {
+ BIO_clear_retry_flags(bio);
+
+ let state = state::<S>(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<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int {
+ BIO_clear_retry_flags(bio);
+
+ let state = state::<S>(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<S: Write>(bio: *mut BIO, s: *const c_char) -> c_int {
+ bwrite::<S>(bio, s, strlen(s) as c_int)
+}
+
+unsafe extern "C" fn ctrl<S: Write>(
+ bio: *mut BIO,
+ cmd: c_int,
+ _num: c_long,
+ _ptr: *mut c_void,
+) -> c_long {
+ let state = state::<S>(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<S>(bio: *mut BIO) -> c_int {
+ if bio.is_null() {
+ return 0;
+ }
+
+ let data = BIO_get_data(bio);
+ assert!(!data.is_null());
+ let _ = Box::<StreamState<S>>::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<S: Read + Write>() -> Result<BIO_METHOD, ErrorStack> {
+ 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::<S>)))?;
+ cvt(ffi::BIO_meth_set_read__fixed_rust(method.0, Some(bread::<S>)))?;
+ cvt(ffi::BIO_meth_set_puts__fixed_rust(method.0, Some(bputs::<S>)))?;
+ cvt(ffi::BIO_meth_set_ctrl__fixed_rust(method.0, Some(ctrl::<S>)))?;
+ cvt(ffi::BIO_meth_set_create__fixed_rust(method.0, Some(create)))?;
+ cvt(ffi::BIO_meth_set_destroy__fixed_rust(method.0, Some(destroy::<S>)))?;
+ 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<S: Read + Write>() -> Result<BIO_METHOD, ErrorStack> {
+ let ptr = Box::new(ffi::BIO_METHOD {
+ type_: ffi::BIO_TYPE_NONE,
+ name: b"rust\0".as_ptr() as *const _,
+ bwrite: Some(bwrite::<S>),
+ bread: Some(bread::<S>),
+ bputs: Some(bputs::<S>),
+ bgets: None,
+ ctrl: Some(ctrl::<S>),
+ create: Some(create),
+ destroy: Some(destroy::<S>),
+ 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::<ffi::BIO_METHOD>::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;
+ }
+ }
+}
diff --git a/vendor/openssl/src/ssl/callbacks.rs b/vendor/openssl/src/ssl/callbacks.rs
new file mode 100644
index 0000000..c6414fb
--- /dev/null
+++ b/vendor/openssl/src/ssl/callbacks.rs
@@ -0,0 +1,707 @@
+use 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<F>(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::<F>();
+
+ // 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<F>(
+ 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<usize, ErrorStack>
+ + 'static
+ + Sync
+ + Send,
+{
+ unsafe {
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback_idx = SslContext::cached_ex_index::<F>();
+
+ 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<F>(
+ 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<usize, ErrorStack>
+ + 'static
+ + Sync
+ + Send,
+{
+ unsafe {
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback_idx = SslContext::cached_ex_index::<F>();
+
+ 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<F>(
+ 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::<Arc<F>>();
+
+ 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<F>(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<F>(
+ 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::<F>())
+ .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<F>(
+ ssl: *mut ffi::SSL,
+ is_export: c_int,
+ keylength: c_int,
+) -> *mut ffi::DH
+where
+ F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
+{
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl
+ .ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .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<F>(
+ ssl: *mut ffi::SSL,
+ is_export: c_int,
+ keylength: c_int,
+) -> *mut ffi::EC_KEY
+where
+ F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
+{
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl
+ .ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .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<F>(
+ ssl: *mut ffi::SSL,
+ is_export: c_int,
+ keylength: c_int,
+) -> *mut ffi::DH
+where
+ F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
+{
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl
+ .ex_data(Ssl::cached_ex_index::<Arc<F>>())
+ .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<F>(
+ ssl: *mut ffi::SSL,
+ is_export: c_int,
+ keylength: c_int,
+) -> *mut ffi::EC_KEY
+where
+ F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
+{
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl
+ .ex_data(Ssl::cached_ex_index::<Arc<F>>())
+ .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<F>(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int
+where
+ F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,
+{
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl
+ .ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .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<F>(
+ 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::<F>())
+ .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<F>(
+ 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::<F>())
+ .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<F>(
+ ssl: *mut ffi::SSL,
+ data: DataPtr,
+ len: c_int,
+ copy: *mut c_int,
+) -> *mut ffi::SSL_SESSION
+where
+ F: Fn(&mut SslRef, &[u8]) -> Option<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::<F>())
+ .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<F>(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::<F>())
+ .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<F>(
+ ssl: *mut ffi::SSL,
+ cookie: *mut c_uchar,
+ cookie_len: *mut size_t,
+) -> c_int
+where
+ F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
+{
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl
+ .ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .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<F>(
+ 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::<F>())
+ .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<F>(
+ ssl: *mut ffi::SSL,
+ cookie: *mut c_uchar,
+ cookie_len: *mut c_uint,
+) -> c_int
+where
+ F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
+{
+ unsafe {
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl
+ .ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .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<F>(
+ 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::<F>())
+ .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<T>(Option<T>);
+
+#[cfg(ossl111)]
+pub extern "C" fn raw_custom_ext_add<F, T>(
+ 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<Option<T>, 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::<F>())
+ .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::<CustomExtAddState<T>>();
+ 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<T>(
+ 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::<CustomExtAddState<T>>();
+ if let Some(state) = ssl.ex_data_mut(idx) {
+ state.0 = None;
+ }
+ }
+}
+
+#[cfg(ossl111)]
+pub extern "C" fn raw_custom_ext_parse<F>(
+ 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::<F>())
+ .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<F>(
+ ssl: *mut ffi::SSL,
+ al: *mut c_int,
+ arg: *mut c_void,
+) -> c_int
+where
+ F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack>
+ + '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
+ }
+ }
+}
diff --git a/vendor/openssl/src/ssl/connector.rs b/vendor/openssl/src/ssl/connector.rs
new file mode 100644
index 0000000..66d1bd8
--- /dev/null
+++ b/vendor/openssl/src/ssl/connector.rs
@@ -0,0 +1,605 @@
+use 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<SslContextBuilder, ErrorStack> {
+ 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<SslConnectorBuilder, ErrorStack> {
+ 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<S>(&self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ 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<ConnectConfiguration, ErrorStack> {
+ 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<Ssl, ErrorStack> {
+ if self.sni && domain.parse::<IpAddr>().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<S>(self, domain: &str, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ 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<SslAcceptorBuilder, ErrorStack> {
+ 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<SslAcceptorBuilder, ErrorStack> {
+ 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<SslAcceptorBuilder, ErrorStack> {
+ 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<SslAcceptorBuilder, ErrorStack> {
+ 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<S>(&self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ 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<Index<Ssl, String>> = OnceCell::new();
+
+ pub fn try_get_hostname_idx() -> Result<&'static Index<Ssl, String>, 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<GeneralName>) -> 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::<IpAddr>() {
+ Ok(ip) => pattern
+ .parse::<IpAddr>()
+ .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<bool> {
+ 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.
+ }
+ }
+ }
+}
diff --git a/vendor/openssl/src/ssl/error.rs b/vendor/openssl/src/ssl/error.rs
new file mode 100644
index 0000000..5565833
--- /dev/null
+++ b/vendor/openssl/src/ssl/error.rs
@@ -0,0 +1,185 @@
+use 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<InnerError>,
+}
+
+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<io::Error, Error> {
+ 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<ErrorStack> 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<S> {
+ /// Setup failed.
+ SetupFailure(ErrorStack),
+ /// The handshake failed.
+ Failure(MidHandshakeSslStream<S>),
+ /// The handshake encountered a `WouldBlock` error midway through.
+ ///
+ /// This error will never be returned for blocking streams.
+ WouldBlock(MidHandshakeSslStream<S>),
+}
+
+impl<S: fmt::Debug> StdError for HandshakeError<S> {
+ 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<S: fmt::Debug> fmt::Display for HandshakeError<S> {
+ 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<S> From<ErrorStack> for HandshakeError<S> {
+ fn from(e: ErrorStack) -> HandshakeError<S> {
+ HandshakeError::SetupFailure(e)
+ }
+}
diff --git a/vendor/openssl/src/ssl/mod.rs b/vendor/openssl/src/ssl/mod.rs
new file mode 100644
index 0000000..bdfbfc1
--- /dev/null
+++ b/vendor/openssl/src/ssl/mod.rs
@@ -0,0 +1,4211 @@
+//! 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<TcpStream>) {
+//! // ...
+//! }
+//!
+//! for stream in listener.incoming() {
+//! match stream {
+//! Ok(stream) => {
+//! let acceptor = acceptor.clone();
+//! thread::spawn(move || {
+//! let stream = acceptor.accept(stream).unwrap();
+//! handle_client(stream);
+//! });
+//! }
+//! Err(e) => { /* connection failed */ }
+//! }
+//! }
+//! ```
+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};
+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, 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::cmp;
+use std::collections::HashMap;
+use std::ffi::{CStr, CString};
+use std::fmt;
+use std::io;
+use std::io::prelude::*;
+use std::marker::PhantomData;
+use std::mem::{self, ManuallyDrop};
+use std::ops::{Deref, DerefMut};
+use std::panic::resume_unwind;
+use std::path::Path;
+use std::ptr;
+use std::slice;
+use std::str;
+use std::sync::{Arc, Mutex};
+
+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<Mutex<HashMap<TypeId, c_int>>> = Lazy::new(|| Mutex::new(HashMap::new()));
+static SSL_INDEXES: Lazy<Mutex<HashMap<TypeId, c_int>>> = Lazy::new(|| Mutex::new(HashMap::new()));
+static SESSION_CTX_INDEX: OnceCell<Index<Ssl, SslContext>> = OnceCell::new();
+
+fn try_get_session_ctx_index() -> Result<&'static Index<Ssl, SslContext>, ErrorStack> {
+ SESSION_CTX_INDEX.get_or_try_init(Ssl::new_ex_index)
+}
+
+unsafe extern "C" fn free_data_box<T>(
+ _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::<T>::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 OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
+ #[cfg(any(ossl111, libressl340))]
+ 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))]
+ 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<SslContextBuilder, ErrorStack> {
+ 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<F>(&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::<F>(), verify);
+ ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits() as c_int, Some(raw_verify::<F>));
+ }
+ }
+
+ /// 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<F>(&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::<F>(), 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::<F>));
+ #[cfg(not(boringssl))]
+ ffi::SSL_CTX_set_tlsext_servername_callback__fixed_rust(
+ self.as_ptr(),
+ Some(raw_sni::<F>),
+ );
+ }
+ }
+
+ /// 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<Params>) -> 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+
+ #[cfg(not(boringssl))]
+ ffi::SSL_CTX_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh::<F>));
+ #[cfg(boringssl)]
+ ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh::<F>));
+ }
+ }
+
+ /// 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<Params>) -> 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_tmp_ecdh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_ecdh::<F>));
+ }
+ }
+
+ /// 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<P: AsRef<Path>>(&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<X509Name>) {
+ 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<P: AsRef<Path>>(
+ &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<P: AsRef<Path>>(
+ &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<P: AsRef<Path>>(
+ &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<T>(&mut self, key: &PKeyRef<T>) -> 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 OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer.
+ #[corresponds(SSL_CTX_set_min_proto_version)]
+ #[cfg(any(ossl110, libressl261))]
+ pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> 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 OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer.
+ #[corresponds(SSL_CTX_set_max_proto_version)]
+ #[cfg(any(ossl110, libressl261))]
+ pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> 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<SslVersion> {
+ 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<SslVersion> {
+ 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 OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
+ #[corresponds(SSL_CTX_set_alpn_protos)]
+ #[cfg(any(ossl102, libressl261))]
+ pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
+ unsafe {
+ assert!(protocols.len() <= c_uint::max_value() as usize);
+ let r = ffi::SSL_CTX_set_alpn_protos(
+ self.as_ptr(),
+ protocols.as_ptr(),
+ protocols.len() as c_uint,
+ );
+ // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D:
+ if r == 0 {
+ Ok(())
+ } else {
+ Err(ErrorStack::get())
+ }
+ }
+ }
+
+ /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
+ #[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<F>(&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::<F>(), callback);
+ ffi::SSL_CTX_set_alpn_select_cb__fixed_rust(
+ self.as_ptr(),
+ Some(callbacks::raw_alpn_select::<F>),
+ 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 OpenSSL 1.0.2 or newer.
+ #[corresponds(SSL_CTX_get0_param)]
+ #[cfg(any(ossl102, libressl261))]
+ pub fn verify_param(&self) -> &X509VerifyParamRef {
+ unsafe { X509VerifyParamRef::from_ptr(ffi::SSL_CTX_get0_param(self.as_ptr())) }
+ }
+
+ /// Returns a mutable reference to the X509 verification configuration.
+ ///
+ /// Requires OpenSSL 1.0.2 or newer.
+ #[corresponds(SSL_CTX_get0_param)]
+ #[cfg(any(ossl102, libressl261))]
+ pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
+ unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_CTX_get0_param(self.as_ptr())) }
+ }
+
+ /// Sets the callback dealing with OCSP stapling.
+ ///
+ /// On the client side, this callback is responsible for validating the OCSP status response
+ /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method.
+ /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of
+ /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be
+ /// terminated.
+ ///
+ /// On the server side, this callback is 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<F>(&mut self, callback: F) -> Result<(), ErrorStack>
+ where
+ F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ cvt(
+ ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(raw_tlsext_status::<F>))
+ 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
+ + 'static
+ + Sync
+ + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_client_psk::<F>));
+ }
+ }
+
+ #[deprecated(since = "0.10.10", note = "renamed to `set_psk_client_callback`")]
+ #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
+ pub fn set_psk_callback<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
+ + '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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result<usize, ErrorStack>
+ + 'static
+ + Sync
+ + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_psk_server_callback(self.as_ptr(), Some(raw_server_psk::<F>));
+ }
+ }
+
+ /// 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), Some(callbacks::raw_new_session::<F>));
+ }
+ }
+
+ /// 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_sess_set_remove_cb(
+ self.as_ptr(),
+ Some(callbacks::raw_remove_session::<F>),
+ );
+ }
+ }
+
+ /// 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, &[u8]) -> Option<SslSession> + 'static + Sync + Send,
+ {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_sess_set_get_cb(self.as_ptr(), Some(callbacks::raw_get_session::<F>));
+ }
+
+ /// 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&SslRef, &str) + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_keylog_callback(self.as_ptr(), Some(callbacks::raw_keylog::<F>));
+ }
+ }
+
+ /// 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_stateless_cookie_generate_cb(
+ self.as_ptr(),
+ Some(raw_stateless_cookie_generate::<F>),
+ );
+ }
+ }
+
+ /// 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_stateless_cookie_verify_cb(
+ self.as_ptr(),
+ Some(raw_stateless_cookie_verify::<F>),
+ )
+ }
+ }
+
+ /// 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_cookie_generate_cb(self.as_ptr(), Some(raw_cookie_generate::<F>));
+ }
+ }
+
+ /// 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
+ {
+ unsafe {
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_cookie_verify_cb(self.as_ptr(), Some(raw_cookie_verify::<F>));
+ }
+ }
+
+ /// 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`.
+ #[corresponds(SSL_CTX_set_ex_data)]
+ pub fn set_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) {
+ self.set_ex_data_inner(index, data);
+ }
+
+ fn set_ex_data_inner<T>(&mut self, index: Index<SslContext, T>, data: T) -> *mut c_void {
+ unsafe {
+ let data = Box::into_raw(Box::new(data)) as *mut c_void;
+ ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data);
+ data
+ }
+ }
+
+ /// Adds a custom extension for a TLS/DTLS client or server for all supported protocol versions.
+ ///
+ /// Requires OpenSSL 1.1.1 or newer.
+ #[corresponds(SSL_CTX_add_custom_ext)]
+ #[cfg(ossl111)]
+ pub fn add_custom_ext<AddFn, ParseFn, T>(
+ &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<Option<T>, 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::<AddFn>(), add_cb);
+ self.set_ex_data(SslContext::cached_ex_index::<ParseFn>(), parse_cb);
+
+ ffi::SSL_CTX_add_custom_ext(
+ self.as_ptr(),
+ ext_type as c_uint,
+ context.bits(),
+ Some(raw_custom_ext_add::<AddFn, T>),
+ Some(raw_custom_ext_free::<T>),
+ ptr::null_mut(),
+ Some(raw_custom_ext_parse::<ParseFn>),
+ 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack>
+ + 'static
+ + Sync
+ + Send,
+ {
+ unsafe {
+ let ptr = self.set_ex_data_inner(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_client_hello_cb(
+ self.as_ptr(),
+ Some(callbacks::raw_client_hello::<F>),
+ 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 OpenSSL 1.1.1 or LibreSSL 2.5.1 or newer.
+ #[corresponds(SSL_CTX_set1_groups_list)]
+ #[cfg(any(ossl111, 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(|_| ()) }
+ }
+
+ /// 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, ErrorStack> {
+ 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<T>() -> Result<Index<SslContext, T>, ErrorStack>
+ where
+ T: 'static + Sync + Send,
+ {
+ unsafe {
+ ffi::init();
+ #[cfg(boringssl)]
+ let idx = cvt_n(get_new_idx(Some(free_data_box::<T>)))?;
+ #[cfg(not(boringssl))]
+ let idx = cvt_n(get_new_idx(free_data_box::<T>))?;
+ Ok(Index::from_raw(idx))
+ }
+ }
+
+ // FIXME should return a result?
+ fn cached_ex_index<T>() -> Index<SslContext, T>
+ where
+ T: 'static + Sync + Send,
+ {
+ unsafe {
+ let idx = *INDEXES
+ .lock()
+ .unwrap_or_else(|e| e.into_inner())
+ .entry(TypeId::of::<T>())
+ .or_insert_with(|| SslContext::new_ex_index::<T>().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<Private>> {
+ 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<X509> {
+ 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<T>(&self, index: Index<SslContext, T>) -> 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()) }
+ }
+}
+
+/// 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<MessageDigest> {
+ 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<Nid> {
+ 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<SslCipher>,
+ pub signalling_suites: Stack<SslCipher>,
+}
+
+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<T>() -> Result<Index<Ssl, T>, ErrorStack>
+ where
+ T: 'static + Sync + Send,
+ {
+ unsafe {
+ ffi::init();
+ #[cfg(boringssl)]
+ let idx = cvt_n(get_new_ssl_idx(Some(free_data_box::<T>)))?;
+ #[cfg(not(boringssl))]
+ let idx = cvt_n(get_new_ssl_idx(free_data_box::<T>))?;
+ Ok(Index::from_raw(idx))
+ }
+ }
+
+ // FIXME should return a result?
+ fn cached_ex_index<T>() -> Index<Ssl, T>
+ where
+ T: 'static + Sync + Send,
+ {
+ unsafe {
+ let idx = *SSL_INDEXES
+ .lock()
+ .unwrap_or_else(|e| e.into_inner())
+ .entry(TypeId::of::<T>())
+ .or_insert_with(|| Ssl::new_ex_index::<T>().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<Ssl, ErrorStack> {
+ 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<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ 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<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ where
+ S: Read + Write,
+ {
+ SslStreamBuilder::new(self, stream).accept()
+ }
+}
+
+impl fmt::Debug for SslRef {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_struct("Ssl")
+ .field("state", &self.state_string_long())
+ .field("verify_result", &self.verify_result())
+ .finish()
+ }
+}
+
+impl SslRef {
+ fn get_raw_rbio(&self) -> *mut ffi::BIO {
+ unsafe { ffi::SSL_get_rbio(self.as_ptr()) }
+ }
+
+ fn read(&mut self, buf: &mut [u8]) -> c_int {
+ let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+ unsafe { ffi::SSL_read(self.as_ptr(), buf.as_ptr() as *mut c_void, len) }
+ }
+
+ fn peek(&mut self, buf: &mut [u8]) -> c_int {
+ let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+ unsafe { ffi::SSL_peek(self.as_ptr(), buf.as_ptr() as *mut c_void, len) }
+ }
+
+ fn write(&mut self, buf: &[u8]) -> c_int {
+ let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
+ unsafe { ffi::SSL_write(self.as_ptr(), buf.as_ptr() as *const c_void, len) }
+ }
+
+ fn get_error(&self, ret: c_int) -> ErrorCode {
+ unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) }
+ }
+
+ /// Configure as an outgoing stream from a client.
+ #[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<F>(&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::<F>),
+ );
+ }
+ }
+
+ /// 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<Params>) -> 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, 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::<F>));
+ #[cfg(not(boringssl))]
+ ffi::SSL_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh_ssl::<F>));
+ }
+ }
+
+ /// 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<Params>) -> 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<F>(&mut self, callback: F)
+ where
+ F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, 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::<F>));
+ }
+ }
+
+ /// 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 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))]
+ pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
+ unsafe {
+ assert!(protocols.len() <= c_uint::max_value() as usize);
+ let r = ffi::SSL_set_alpn_protos(
+ self.as_ptr(),
+ protocols.as_ptr(),
+ protocols.len() as c_uint,
+ );
+ // fun fact, SSL_set_alpn_protos has a reversed return code D:
+ if r == 0 {
+ Ok(())
+ } else {
+ Err(ErrorStack::get())
+ }
+ }
+ }
+
+ /// Returns the current cipher if the session is active.
+ #[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<X509> {
+ 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<X509>> {
+ 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<X509>> {
+ 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<Private>> {
+ 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<SslVersion> {
+ 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 OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
+ #[corresponds(SSL_get0_alpn_selected)]
+ #[cfg(any(ossl102, libressl261))]
+ pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
+ unsafe {
+ let mut data: *const c_uchar = ptr::null();
+ let mut len: c_uint = 0;
+ // Get the negotiated protocol from the SSL instance.
+ // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
+ ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len);
+
+ if data.is_null() {
+ None
+ } else {
+ Some(slice::from_raw_parts(data, len as usize))
+ }
+ }
+ }
+
+ /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
+ ///
+ /// This corresponds to [`SSL_set_tlsext_use_srtp`].
+ ///
+ /// [`SSL_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html
+ #[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<SrtpProtectionProfile>> {
+ 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 OpenSSL 1.0.2 or newer.
+ #[corresponds(SSL_get0_param)]
+ #[cfg(any(ossl102, libressl261))]
+ pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
+ unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
+ }
+
+ /// Returns the certificate verification result.
+ #[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<bool> {
+ 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`.
+ #[corresponds(SSL_set_ex_data)]
+ pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) {
+ unsafe {
+ let data = Box::new(data);
+ ffi::SSL_set_ex_data(
+ self.as_ptr(),
+ index.as_raw(),
+ Box::into_raw(data) as *mut c_void,
+ );
+ }
+ }
+
+ /// Returns a reference to the extra data at the specified index.
+ #[corresponds(SSL_get_ex_data)]
+ pub fn ex_data<T>(&self, index: Index<Ssl, T>) -> 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<T>(&mut self, index: Index<Ssl, T>) -> 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<SslVersion> {
+ 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<CipherLists, ErrorStack> {
+ 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<P: AsRef<Path>>(
+ &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<Private>) -> 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<P: AsRef<Path>>(
+ &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<X509Name>) {
+ 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 OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer.
+ #[corresponds(SSL_set_min_proto_version)]
+ #[cfg(any(ossl110, libressl261))]
+ pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> 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 OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer.
+ #[corresponds(SSL_set_max_proto_version)]
+ #[cfg(any(ossl110, libressl261))]
+ pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> 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()) }
+ }
+}
+
+/// An SSL stream midway through the handshake process.
+#[derive(Debug)]
+pub struct MidHandshakeSslStream<S> {
+ stream: SslStream<S>,
+ error: Error,
+}
+
+impl<S> MidHandshakeSslStream<S> {
+ /// 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<S> MidHandshakeSslStream<S>
+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<SslStream<S>, HandshakeError<S>> {
+ 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<S> {
+ ssl: ManuallyDrop<Ssl>,
+ method: ManuallyDrop<BioMethod>,
+ _p: PhantomData<S>,
+}
+
+impl<S> Drop for SslStream<S> {
+ 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<S> fmt::Debug for SslStream<S>
+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<S: Read + Write> SslStream<S> {
+ /// 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<Self, ErrorStack> {
+ 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<usize, Error> {
+ 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<usize, Error> {
+ 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<bool, ErrorStack> {
+ match unsafe { ffi::SSL_stateless(self.ssl.as_ptr()) } {
+ 1 => Ok(true),
+ 0 => Ok(false),
+ -1 => Err(ErrorStack::get()),
+ _ => unreachable!(),
+ }
+ }
+
+ /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
+ ///
+ /// It is particularly useful with a non-blocking socket, where the error value will identify if
+ /// OpenSSL is waiting on read or write readiness.
+ #[corresponds(SSL_read)]
+ pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
+ // The interpretation of the return code here is a little odd with a
+ // zero-length write. OpenSSL will likely correctly report back to us
+ // that it read zero bytes, but zero is also the sentinel for "error".
+ // To avoid that confusion short-circuit that logic and return quickly
+ // if `buf` has a length of zero.
+ if buf.is_empty() {
+ return Ok(0);
+ }
+
+ let ret = self.ssl.read(buf);
+ if ret > 0 {
+ Ok(ret as usize)
+ } else {
+ Err(self.make_error(ret))
+ }
+ }
+
+ /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
+ ///
+ /// It is particularly useful with a non-blocking socket, where the error value will identify if
+ /// OpenSSL is waiting on read or write readiness.
+ #[corresponds(SSL_write)]
+ pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
+ // See above for why we short-circuit on zero-length buffers
+ if buf.is_empty() {
+ return Ok(0);
+ }
+
+ let ret = self.ssl.write(buf);
+ if ret > 0 {
+ Ok(ret as usize)
+ } else {
+ Err(self.make_error(ret))
+ }
+ }
+
+ /// Reads data from the stream, without removing it from the queue.
+ #[corresponds(SSL_peek)]
+ pub fn ssl_peek(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
+ // See above for why we short-circuit on zero-length buffers
+ if buf.is_empty() {
+ return Ok(0);
+ }
+
+ let ret = self.ssl.peek(buf);
+ if ret > 0 {
+ Ok(ret as usize)
+ } else {
+ Err(self.make_error(ret))
+ }
+ }
+
+ /// Shuts down the session.
+ ///
+ /// The shutdown process consists of two steps. The first step sends a close notify message to
+ /// the peer, after which `ShutdownResult::Sent` is returned. The second step awaits the receipt
+ /// of a close notify message from the peer, after which `ShutdownResult::Received` is returned.
+ ///
+ /// While the connection may be closed after the first step, it is recommended to fully shut the
+ /// session down. In particular, it must be fully shut down if the connection is to be used for
+ /// further communication in the future.
+ #[corresponds(SSL_shutdown)]
+ pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
+ 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<S> SslStream<S> {
+ 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::<S>(self.ssl.get_raw_rbio()) } {
+ resume_unwind(err)
+ }
+ }
+
+ fn get_bio_error(&mut self) -> Option<io::Error> {
+ unsafe { bio::take_error::<S>(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<S: Read + Write> Read for SslStream<S> {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ loop {
+ match self.ssl_read(buf) {
+ Ok(n) => return Ok(n),
+ Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => return Ok(0),
+ Err(ref e) if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() => {
+ return Ok(0);
+ }
+ Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
+ Err(e) => {
+ return Err(e
+ .into_io_error()
+ .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e)));
+ }
+ }
+ }
+ }
+}
+
+impl<S: Read + Write> Write for SslStream<S> {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ 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<S> {
+ inner: SslStream<S>,
+}
+
+#[allow(deprecated)]
+impl<S> SslStreamBuilder<S>
+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<bool, ErrorStack> {
+ 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<SslStream<S>, HandshakeError<S>> {
+ 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<SslStream<S>, HandshakeError<S>> {
+ 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<SslStream<S>, HandshakeError<S>> {
+ 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<usize, Error> {
+ 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<usize, Error> {
+ self.inner.write_early_data(buf)
+ }
+}
+
+#[allow(deprecated)]
+impl<S> SslStreamBuilder<S> {
+ /// 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::<S>(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);
+ }
+ }
+}
diff --git a/vendor/openssl/src/ssl/test/mod.rs b/vendor/openssl/src/ssl/test/mod.rs
new file mode 100644
index 0000000..7707af2
--- /dev/null
+++ b/vendor/openssl/src/ssl/test/mod.rs
@@ -0,0 +1,1570 @@
+#![allow(unused_imports)]
+
+use std::env;
+use std::fs::File;
+use std::io::prelude::*;
+use std::io::{self, BufReader};
+use std::iter;
+use std::mem;
+use std::net::UdpSocket;
+use std::net::{SocketAddr, TcpListener, TcpStream};
+use std::path::Path;
+use std::process::{Child, ChildStdin, Command, Stdio};
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::thread;
+use std::time::Duration;
+
+use crate::dh::Dh;
+use crate::error::ErrorStack;
+use crate::hash::MessageDigest;
+#[cfg(not(boringssl))]
+use crate::ocsp::{OcspResponse, OcspResponseStatus};
+use crate::pkey::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"
+ );
+}
+
+/// 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(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<usize> {
+ self.0.read(buf)
+ }
+ }
+
+ impl Write for ExplodingStream {
+ fn write(&mut self, _: &[u8]) -> io::Result<usize> {
+ 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<usize> {
+ panic!("blammo");
+ }
+ }
+
+ impl Write for ExplodingStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ 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<usize> {
+ self.0.read(buf)
+ }
+ }
+
+ impl Write for ExplodingStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ 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"</HTML>\r\n") || result.ends_with(b"</html>"));
+}
+
+#[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<SslAcceptorBuilder, ErrorStack>) {
+ 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());
+}
+
+/// possible LibreSSL bug since 3.2.1
+#[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));
+}
+
+/// possible LibreSSL bug since 3.2.1
+#[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));
+}
+
+/// possible LibreSSL bug since 3.2.1
+#[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<Option<&'static [u8]>, _> { 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<T: Send>() {}
+ fn is_sync<T: Sync>() {}
+
+ is_send::<SslStream<TcpStream>>();
+ is_sync::<SslStream<TcpStream>>();
+}
+
+#[test]
+#[cfg(ossl111)]
+fn stateless() {
+ use super::SslOptions;
+
+ #[derive(Debug)]
+ struct MemoryStream {
+ incoming: io::Cursor<Vec<u8>>,
+ outgoing: Vec<u8>,
+ }
+
+ 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<usize> {
+ 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<usize> {
+ self.outgoing.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+ }
+
+ pub struct Outgoing<'a>(&'a mut Vec<u8>);
+
+ 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());
+}
diff --git a/vendor/openssl/src/ssl/test/server.rs b/vendor/openssl/src/ssl/test/server.rs
new file mode 100644
index 0000000..41677e5
--- /dev/null
+++ b/vendor/openssl/src/ssl/test/server.rs
@@ -0,0 +1,167 @@
+use 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<JoinHandle<()>>,
+ 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<dyn FnMut(&mut SslRef) + Send>,
+ io_cb: Box<dyn FnMut(SslStream<TcpStream>) + Send>,
+ should_error: bool,
+}
+
+impl Builder {
+ pub fn ctx(&mut self) -> &mut SslContextBuilder {
+ &mut self.ctx
+ }
+
+ pub fn ssl_cb<F>(&mut self, cb: F)
+ where
+ F: 'static + FnMut(&mut SslRef) + Send,
+ {
+ self.ssl_cb = Box::new(cb);
+ }
+
+ pub fn io_cb<F>(&mut self, cb: F)
+ where
+ F: 'static + FnMut(SslStream<TcpStream>) + 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<TcpStream> {
+ 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<TcpStream> {
+ let socket = TcpStream::connect(self.addr).unwrap();
+ let mut s = self.ssl.connect(socket).unwrap();
+ s.read_exact(&mut [0]).unwrap();
+ s
+ }
+
+ pub fn connect_err(self) {
+ let socket = TcpStream::connect(self.addr).unwrap();
+ self.ssl.connect(socket).unwrap_err();
+ }
+}
diff --git a/vendor/openssl/src/stack.rs b/vendor/openssl/src/stack.rs
new file mode 100644
index 0000000..416efd5
--- /dev/null
+++ b/vendor/openssl/src/stack.rs
@@ -0,0 +1,380 @@
+use 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<T: Stackable>(*mut T::StackType);
+
+unsafe impl<T: Stackable + Send> Send for Stack<T> {}
+unsafe impl<T: Stackable + Sync> Sync for Stack<T> {}
+
+impl<T> fmt::Debug for Stack<T>
+where
+ T: Stackable,
+ T::Ref: fmt::Debug,
+{
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt.debug_list().entries(self).finish()
+ }
+}
+impl<T: Stackable> Drop for Stack<T> {
+ fn drop(&mut self) {
+ unsafe {
+ while self.pop().is_some() {}
+ OPENSSL_sk_free(self.0 as *mut _);
+ }
+ }
+}
+
+impl<T: Stackable> Stack<T> {
+ pub fn new() -> Result<Stack<T>, ErrorStack> {
+ unsafe {
+ ffi::init();
+ let ptr = cvt_p(OPENSSL_sk_new_null())?;
+ Ok(Stack(ptr as *mut _))
+ }
+ }
+}
+
+impl<T: Stackable> iter::IntoIterator for Stack<T> {
+ type IntoIter = IntoIter<T>;
+ type Item = T;
+
+ fn into_iter(self) -> IntoIter<T> {
+ let it = IntoIter {
+ stack: self.0,
+ idxs: 0..self.len() as LenType,
+ };
+ mem::forget(self);
+ it
+ }
+}
+
+impl<T: Stackable> AsRef<StackRef<T>> for Stack<T> {
+ fn as_ref(&self) -> &StackRef<T> {
+ self
+ }
+}
+
+impl<T: Stackable> Borrow<StackRef<T>> for Stack<T> {
+ fn borrow(&self) -> &StackRef<T> {
+ self
+ }
+}
+
+impl<T: Stackable> ForeignType for Stack<T> {
+ type CType = T::StackType;
+ type Ref = StackRef<T>;
+
+ #[inline]
+ unsafe fn from_ptr(ptr: *mut T::StackType) -> Stack<T> {
+ 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<T: Stackable> Deref for Stack<T> {
+ type Target = StackRef<T>;
+
+ fn deref(&self) -> &StackRef<T> {
+ unsafe { StackRef::from_ptr(self.0) }
+ }
+}
+
+impl<T: Stackable> DerefMut for Stack<T> {
+ fn deref_mut(&mut self) -> &mut StackRef<T> {
+ unsafe { StackRef::from_ptr_mut(self.0) }
+ }
+}
+
+pub struct IntoIter<T: Stackable> {
+ stack: *mut T::StackType,
+ idxs: Range<LenType>,
+}
+
+impl<T: Stackable> Drop for IntoIter<T> {
+ 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<T: Stackable> Iterator for IntoIter<T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<T> {
+ 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<usize>) {
+ self.idxs.size_hint()
+ }
+}
+
+impl<T: Stackable> DoubleEndedIterator for IntoIter<T> {
+ fn next_back(&mut self) -> Option<T> {
+ unsafe {
+ self.idxs
+ .next_back()
+ .map(|i| T::from_ptr(OPENSSL_sk_value(self.stack as *mut _, i) as *mut _))
+ }
+ }
+}
+
+impl<T: Stackable> ExactSizeIterator for IntoIter<T> {}
+
+pub struct StackRef<T: Stackable>(Opaque, PhantomData<T>);
+
+unsafe impl<T: Stackable + Send> Send for StackRef<T> {}
+unsafe impl<T: Stackable + Sync> Sync for StackRef<T> {}
+
+impl<T: Stackable> ForeignTypeRef for StackRef<T> {
+ type CType = T::StackType;
+}
+
+impl<T: Stackable> StackRef<T> {
+ 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<T> {
+ 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<T: Stackable> Index<usize> for StackRef<T> {
+ type Output = T::Ref;
+
+ fn index(&self, index: usize) -> &T::Ref {
+ self.get(index).unwrap()
+ }
+}
+
+impl<T: Stackable> IndexMut<usize> for StackRef<T> {
+ fn index_mut(&mut self, index: usize) -> &mut T::Ref {
+ self.get_mut(index).unwrap()
+ }
+}
+
+impl<'a, T: Stackable> iter::IntoIterator for &'a StackRef<T> {
+ 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<T> {
+ 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<T> {
+ 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<T> {
+ 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<T>,
+ idxs: Range<LenType>,
+}
+
+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<usize>) {
+ 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<T>,
+ idxs: Range<LenType>,
+}
+
+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<usize>) {
+ 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> {}
diff --git a/vendor/openssl/src/string.rs b/vendor/openssl/src/string.rs
new file mode 100644
index 0000000..95494b5
--- /dev/null
+++ b/vendor/openssl/src/string.rs
@@ -0,0 +1,96 @@
+use foreign_types::ForeignTypeRef;
+use libc::{c_char, c_void};
+use std::convert::AsRef;
+use std::ffi::CStr;
+use std::fmt;
+use std::ops::Deref;
+use std::str;
+
+use 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<str> 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<str> 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,
+ );
+}
diff --git a/vendor/openssl/src/symm.rs b/vendor/openssl/src/symm.rs
new file mode 100644
index 0000000..7ebb703
--- /dev/null
+++ b/vendor/openssl/src/symm.rs
@@ -0,0 +1,1633 @@
+//! 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<Cipher> {
+ 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(any(boringssl, osslconf = "OPENSSL_NO_BF")))]
+ pub fn bf_cfb64() -> Cipher {
+ unsafe { Cipher(ffi::EVP_bf_cfb64()) }
+ }
+
+ #[cfg(not(any(boringssl, 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()) }
+ }
+
+ #[cfg(not(boringssl))]
+ pub fn des_ede3_cfb64() -> Cipher {
+ unsafe { Cipher(ffi::EVP_des_ede3_cfb64()) }
+ }
+
+ #[cfg(not(osslconf = "OPENSSL_NO_RC4"))]
+ pub fn rc4() -> Cipher {
+ unsafe { Cipher(ffi::EVP_rc4()) }
+ }
+
+ /// Requires OpenSSL 1.1.0 or newer.
+ #[cfg(all(ossl110, 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(any(boringssl, osslconf = "OPENSSL_NO_SEED")))]
+ pub fn seed_cbc() -> Cipher {
+ unsafe { Cipher(ffi::EVP_seed_cbc()) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED")))]
+ pub fn seed_cfb128() -> Cipher {
+ unsafe { Cipher(ffi::EVP_seed_cfb128()) }
+ }
+
+ #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_SEED")))]
+ pub fn seed_ecb() -> Cipher {
+ unsafe { Cipher(ffi::EVP_seed_ecb()) }
+ }
+
+ #[cfg(not(any(boringssl, 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<usize> {
+ 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<Crypter, ErrorStack> {
+ 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<usize, ErrorStack> {
+ self.ctx.cipher_update(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<usize, ErrorStack> {
+ 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<Vec<u8>, 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<Vec<u8>, ErrorStack> {
+ cipher(t, Mode::Decrypt, key, iv, data)
+}
+
+fn cipher(
+ t: Cipher,
+ mode: Mode,
+ key: &[u8],
+ iv: Option<&[u8]>,
+ data: &[u8],
+) -> Result<Vec<u8>, 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<Vec<u8>, 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<Vec<u8>, 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(ossl110)]
+ fn test_chacha20() {
+ let key = "0000000000000000000000000000000000000000000000000000000000000000";
+ let iv = "00000000000000000000000000000000";
+ let pt =
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000\
+ 00000000000000000000000000000000000000000000000";
+ let ct =
+ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7\
+ 724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586";
+
+ cipher_test(Cipher::chacha20(), pt, ct, key, iv);
+ }
+
+ #[test]
+ #[cfg(any(ossl110, 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(boringssl, 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(boringssl, 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(boringssl, 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(boringssl, 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]);
+ }
+}
diff --git a/vendor/openssl/src/util.rs b/vendor/openssl/src/util.rs
new file mode 100644
index 0000000..d852a4b
--- /dev/null
+++ b/vendor/openssl/src/util.rs
@@ -0,0 +1,93 @@
+use 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<F> {
+ /// The user callback. Taken out of the `Option` when called.
+ cb: Option<F>,
+ /// If the callback panics, we place the panic object here, to be re-thrown once OpenSSL
+ /// returns.
+ panic: Option<Box<dyn Any + Send + 'static>>,
+}
+
+impl<F> CallbackState<F> {
+ pub fn new(callback: F) -> Self {
+ CallbackState {
+ cb: Some(callback),
+ panic: None,
+ }
+ }
+}
+
+impl<F> Drop for CallbackState<F> {
+ 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<F>(
+ buf: *mut c_char,
+ size: c_int,
+ _rwflag: c_int,
+ cb_state: *mut c_void,
+) -> c_int
+where
+ F: FnOnce(&mut [u8]) -> Result<usize, ErrorStack>,
+{
+ let callback = &mut *(cb_state as *mut CallbackState<F>);
+
+ 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<Self> {
+ if ptr.is_null() {
+ None
+ } else {
+ Some(Self::from_ptr(ptr))
+ }
+ }
+}
+impl<FT: ForeignType> 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<FT: ForeignTypeRef> ForeignTypeRefExt for FT {}
diff --git a/vendor/openssl/src/version.rs b/vendor/openssl/src/version.rs
new file mode 100644
index 0000000..f1a324c
--- /dev/null
+++ b/vendor/openssl/src/version.rs
@@ -0,0 +1,135 @@
+// 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:"));
+}
diff --git a/vendor/openssl/src/x509/extension.rs b/vendor/openssl/src/x509/extension.rs
new file mode 100644
index 0000000..11e0151
--- /dev/null
+++ b/vendor/openssl/src/x509/extension.rs
@@ -0,0 +1,562 @@
+//! 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<u32>,
+}
+
+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<X509Extension, ErrorStack> {
+ 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<X509Extension, ErrorStack> {
+ 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<String>,
+}
+
+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<X509Extension, ErrorStack> {
+ 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<X509Extension, ErrorStack> {
+ 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<bool>,
+ issuer: Option<bool>,
+}
+
+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<X509Extension, ErrorStack> {
+ 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<u8>),
+}
+
+/// An extension that allows additional identities to be bound to the subject
+/// of the certificate.
+pub struct SubjectAlternativeName {
+ critical: bool,
+ items: Vec<RustGeneralName>,
+}
+
+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<X509Extension, ErrorStack> {
+ 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);
+}
diff --git a/vendor/openssl/src/x509/mod.rs b/vendor/openssl/src/x509/mod.rs
new file mode 100644
index 0000000..24605df
--- /dev/null
+++ b/vendor/openssl/src/x509/mod.rs
@@ -0,0 +1,2535 @@
+//! 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};
+use openssl_macros::corresponds;
+
+#[cfg(any(ossl102, 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<Index<X509StoreContext, SslRef>, 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<X509StoreContext, ErrorStack> {
+ 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<T>(&self, index: Index<X509StoreContext, T>) -> 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<F, T>(
+ &mut self,
+ trust: &store::X509StoreRef,
+ cert: &X509Ref,
+ cert_chain: &StackRef<X509>,
+ with_context: F,
+ ) -> Result<T, ErrorStack>
+ where
+ F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
+ {
+ 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<bool, ErrorStack> {
+ 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<X509>> {
+ 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<X509Builder, ErrorStack> {
+ 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<T>(&mut self, key: &PKeyRef<T>) -> 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<T>(&mut self, key: &PKeyRef<T>, 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;
+}
+
+#[cfg(boringssl)]
+type X509LenTy = c_uint;
+#[cfg(not(boringssl))]
+type X509LenTy = c_int;
+
+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<Stack<GeneralName>> {
+ 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<Stack<DistPoint>> {
+ 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<Stack<GeneralName>> {
+ 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<Stack<AccessDescription>> {
+ 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(ossl110)]
+ pub fn pathlen(&self) -> Option<u32> {
+ 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(ossl110)]
+ 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(ossl110)]
+ 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<GeneralName>> {
+ 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<PKey<Public>, 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<DigestBytes, ErrorStack> {
+ 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<Vec<u8>, 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<Stack<OpensslString>, 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<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
+ 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")
+ }
+ }
+
+ 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<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl PartialOrd<X509> for X509Ref {
+ fn partial_cmp(&self, other: &X509) -> Option<cmp::Ordering> {
+ <X509Ref as PartialOrd<X509Ref>>::partial_cmp(self, other)
+ }
+}
+
+impl PartialEq for X509Ref {
+ fn eq(&self, other: &Self) -> bool {
+ self.cmp(other) == cmp::Ordering::Equal
+ }
+}
+
+impl PartialEq<X509> for X509Ref {
+ fn eq(&self, other: &X509) -> bool {
+ <X509Ref as PartialEq<X509Ref>>::eq(self, other)
+ }
+}
+
+impl Eq for X509Ref {}
+
+impl X509 {
+ /// Returns a new builder.
+ pub fn builder() -> Result<X509Builder, ErrorStack> {
+ 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<Vec<X509>, ErrorStack> {
+ unsafe {
+ ffi::init();
+ let bio = MemBioSlice::new(pem)?;
+
+ let mut certs = vec![];
+ loop {
+ let r =
+ ffi::PEM_read_bio_X509(bio.as_ptr(), ptr::null_mut(), None, ptr::null_mut());
+ if r.is_null() {
+ let err = ffi::ERR_peek_last_error();
+ if ffi::ERR_GET_LIB(err) as X509LenTy == ffi::ERR_LIB_PEM
+ && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE
+ {
+ ffi::ERR_clear_error();
+ break;
+ }
+
+ return Err(ErrorStack::get());
+ } else {
+ certs.push(X509(r));
+ }
+ }
+
+ Ok(certs)
+ }
+ }
+}
+
+impl Clone for X509 {
+ fn clone(&self) -> X509 {
+ X509Ref::to_owned(self)
+ }
+}
+
+impl fmt::Debug for X509 {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let serial = match &self.serial_number().to_bn() {
+ Ok(bn) => match bn.to_hex_str() {
+ Ok(hex) => hex.to_string(),
+ Err(_) => "".to_string(),
+ },
+ Err(_) => "".to_string(),
+ };
+ let mut debug_struct = formatter.debug_struct("X509");
+ debug_struct.field("serial_number", &serial);
+ debug_struct.field("signature_algorithm", &self.signature_algorithm().object());
+ debug_struct.field("issuer", &self.issuer_name());
+ debug_struct.field("subject", &self.subject_name());
+ if let Some(subject_alt_names) = &self.subject_alt_names() {
+ debug_struct.field("subject_alt_names", subject_alt_names);
+ }
+ debug_struct.field("not_before", &self.not_before());
+ debug_struct.field("not_after", &self.not_after());
+
+ if let Ok(public_key) = &self.public_key() {
+ debug_struct.field("public_key", public_key);
+ };
+ // TODO: Print extensions once they are supported on the X509 struct.
+
+ debug_struct.finish()
+ }
+}
+
+impl AsRef<X509Ref> 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<cmp::Ordering> {
+ X509Ref::partial_cmp(self, other)
+ }
+}
+
+impl PartialOrd<X509Ref> for X509 {
+ fn partial_cmp(&self, other: &X509Ref) -> Option<cmp::Ordering> {
+ X509Ref::partial_cmp(self, other)
+ }
+}
+
+impl PartialEq for X509 {
+ fn eq(&self, other: &Self) -> bool {
+ X509Ref::eq(self, other)
+ }
+}
+
+impl PartialEq<X509Ref> 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<X509Extension, ErrorStack> {
+ 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<X509Extension, ErrorStack> {
+ 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<X509Extension, ErrorStack> {
+ 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<X509Extension, ErrorStack> {
+ 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
+ #[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<X509NameBuilder, ErrorStack> {
+ 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, ErrorStack> {
+ 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<P: AsRef<Path>>(file: P) -> Result<Stack<X509Name>, 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<Ordering, ErrorStack> {
+ 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<X509Name, ErrorStack> {
+ 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<Nid>,
+ 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<X509ReqBuilder, ErrorStack> {
+ 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<T>(&mut self, key: &PKeyRef<T>) -> 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<X509Extension>,
+ ) -> 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<T>(&mut self, key: &PKeyRef<T>, 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, ErrorStack> {
+ 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<PKey<Public>, 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<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
+ 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<Stack<X509Extension>, 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<X509Revoked, ErrorStack> {
+ 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<T: ExtensionType>(&self) -> Result<Option<(bool, T::Output)>, 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<GeneralName>;
+}
+
+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<X509Revoked>> {
+ 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::<ffi::X509_REVOKED>();
+ 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::<ffi::X509_REVOKED>();
+ 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<T>(&self, key: &PKeyRef<T>) -> Result<bool, ErrorStack>
+ where
+ T: HasPublic,
+ {
+ unsafe { cvt_n(ffi::X509_CRL_verify(self.as_ptr(), key.as_ptr())).map(|n| n != 0) }
+ }
+}
+
+/// 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<GeneralName, ErrorStack> {
+ 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<GeneralName, ErrorStack> {
+ unsafe { GeneralName::new(ffi::GEN_EMAIL, Asn1Type::IA5STRING, email) }
+ }
+
+ pub(crate) fn new_dns(dns: &[u8]) -> Result<GeneralName, ErrorStack> {
+ unsafe { GeneralName::new(ffi::GEN_DNS, Asn1Type::IA5STRING, dns) }
+ }
+
+ pub(crate) fn new_uri(uri: &[u8]) -> Result<GeneralName, ErrorStack> {
+ unsafe { GeneralName::new(ffi::GEN_URI, Asn1Type::IA5STRING, uri) }
+ }
+
+ pub(crate) fn new_ip(ip: IpAddr) -> Result<GeneralName, ErrorStack> {
+ 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<GeneralName, ErrorStack> {
+ 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: &Vec<u8>,
+ ) -> Result<GeneralName, ErrorStack> {
+ 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<GeneralName>> {
+ 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))] {
+ use ffi::X509_OBJECT_free;
+ } else if #[cfg(boringssl)] {
+ use ffi::X509_OBJECT_free_contents as 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);
+
+ /// 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<c_int, ErrorStack> {
+ unsafe {
+ let sname = CString::new(sname).unwrap();
+ cfg_if! {
+ if #[cfg(any(ossl110, libressl280))] {
+ 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(ffi::X509_PURPOSE_get0(idx))?;
+ Ok(X509PurposeRef::from_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 {
+ let x509_purpose: *mut ffi::X509_PURPOSE = self.as_ptr();
+ X509PurposeId::from_raw((*x509_purpose).purpose)
+ }
+ }
+}
diff --git a/vendor/openssl/src/x509/store.rs b/vendor/openssl/src/x509/store.rs
new file mode 100644
index 0000000..a90bf35
--- /dev/null
+++ b/vendor/openssl/src/x509/store.rs
@@ -0,0 +1,287 @@
+//! 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::ForeignTypeRef;
+use std::mem;
+
+use crate::error::ErrorStack;
+#[cfg(not(boringssl))]
+use crate::ssl::SslFiletype;
+use crate::stack::StackRef;
+#[cfg(any(ossl102, 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<X509StoreBuilder, ErrorStack> {
+ 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<T>(
+ &mut self,
+ method: &'static X509LookupMethodRef<T>,
+ ) -> Result<&mut X509LookupRef<T>, 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, 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, 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<T>;
+ /// A reference to an [`X509Lookup`].
+ pub struct X509LookupRef<T>;
+}
+
+/// 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<HashDir> {
+ /// 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<HashDir> {
+ unsafe { X509LookupMethodRef::from_ptr(ffi::X509_LOOKUP_hash_dir()) }
+ }
+}
+
+#[cfg(not(boringssl))]
+impl X509LookupRef<HashDir> {
+ /// 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<File> {
+ /// 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<File> {
+ unsafe { X509LookupMethodRef::from_ptr(ffi::X509_LOOKUP_file()) }
+ }
+}
+
+#[cfg(not(boringssl))]
+impl X509LookupRef<File> {
+ /// Specifies a file from which certificates will be loaded
+ #[corresponds(X509_load_cert_file)]
+ // FIXME should return 'Result<i32, ErrorStack' like load_crl_file
+ pub fn load_cert_file<P: AsRef<Path>>(
+ &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<P: AsRef<Path>>(
+ &mut self,
+ file: P,
+ file_type: SslFiletype,
+ ) -> Result<i32, ErrorStack> {
+ 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<T>;
+ /// A reference to an [`X509LookupMethod`].
+ pub struct X509LookupMethodRef<T>;
+}
+
+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.
+ #[corresponds(X509_STORE_get0_objects)]
+ pub fn objects(&self) -> &StackRef<X509Object> {
+ unsafe { StackRef::from_ptr(X509_STORE_get0_objects(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) {}
+ }
+}
diff --git a/vendor/openssl/src/x509/tests.rs b/vendor/openssl/src/x509/tests.rs
new file mode 100644
index 0000000..da3ce2f
--- /dev/null
+++ b/vendor/openssl/src/x509/tests.rs
@@ -0,0 +1,1161 @@
+use 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, libressl261))]
+use crate::x509::verify::{X509VerifyFlags, X509VerifyParam};
+#[cfg(ossl102)]
+use crate::x509::X509PurposeId;
+#[cfg(any(ossl102, 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, libressl261))]
+use libc::time_t;
+
+use super::{CertificateIssuer, ReasonCode};
+
+fn pkey() -> PKey<Private> {
+ 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(ossl110)]
+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(ossl110)]
+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(ossl110)]
+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, 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, 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, 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 revoked_certs = crl.get_revoked().unwrap();
+ let entry = &revoked_certs[0];
+
+ let (critical, issuer) = entry
+ .extension::<CertificateIssuer>()
+ .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::<ReasonCode>()
+ .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, 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, 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, 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, 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(ossl102)]
+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(ossl102)]
+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<T>(expected_ip: T)
+where
+ T: Into<std::net::IpAddr>,
+{
+ 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());
+}
diff --git a/vendor/openssl/src/x509/verify.rs b/vendor/openssl/src/x509/verify.rs
new file mode 100644
index 0000000..541cd82
--- /dev/null
+++ b/vendor/openssl/src/x509/verify.rs
@@ -0,0 +1,215 @@
+use 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(ossl102)]
+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;
+ const NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS;
+ const NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS;
+ const MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS;
+ const SINGLE_LABEL_SUBDOMAINS = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS;
+ /// Requires OpenSSL 1.1.0 or newer.
+ #[cfg(any(ossl110))]
+ const NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT;
+
+ #[deprecated(since = "0.10.6", note = "renamed to NO_WILDCARDS")]
+ const FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS;
+ }
+}
+
+bitflags! {
+ /// Flags used to verify an `X509` certificate chain.
+ #[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;
+ const USE_CHECK_TIME = ffi::X509_V_FLAG_USE_CHECK_TIME;
+ const CRL_CHECK = ffi::X509_V_FLAG_CRL_CHECK;
+ const CRL_CHECK_ALL = ffi::X509_V_FLAG_CRL_CHECK_ALL;
+ const IGNORE_CRITICAL = ffi::X509_V_FLAG_IGNORE_CRITICAL;
+ const X509_STRICT = ffi::X509_V_FLAG_X509_STRICT;
+ const ALLOW_PROXY_CERTS = ffi::X509_V_FLAG_ALLOW_PROXY_CERTS;
+ const POLICY_CHECK = ffi::X509_V_FLAG_POLICY_CHECK;
+ const EXPLICIT_POLICY = ffi::X509_V_FLAG_EXPLICIT_POLICY;
+ const INHIBIT_ANY = ffi::X509_V_FLAG_INHIBIT_ANY;
+ const INHIBIT_MAP = ffi::X509_V_FLAG_INHIBIT_MAP;
+ const NOTIFY_POLICY = ffi::X509_V_FLAG_NOTIFY_POLICY;
+ const EXTENDED_CRL_SUPPORT = ffi::X509_V_FLAG_EXTENDED_CRL_SUPPORT;
+ const USE_DELTAS = ffi::X509_V_FLAG_USE_DELTAS;
+ const CHECK_SS_SIGNATURE = ffi::X509_V_FLAG_CHECK_SS_SIGNATURE;
+ #[cfg(ossl102)]
+ const TRUSTED_FIRST = ffi::X509_V_FLAG_TRUSTED_FIRST;
+ #[cfg(ossl102)]
+ const SUITEB_128_LOS_ONLY = ffi::X509_V_FLAG_SUITEB_128_LOS_ONLY;
+ #[cfg(ossl102)]
+ const SUITEB_192_LOS = ffi::X509_V_FLAG_SUITEB_128_LOS;
+ #[cfg(ossl102)]
+ const SUITEB_128_LOS = ffi::X509_V_FLAG_SUITEB_192_LOS;
+ #[cfg(ossl102)]
+ const PARTIAL_CHAIN = ffi::X509_V_FLAG_PARTIAL_CHAIN;
+ #[cfg(ossl110)]
+ const NO_ALT_CHAINS = ffi::X509_V_FLAG_NO_ALT_CHAINS;
+ #[cfg(ossl110)]
+ const NO_CHECK_TIME = ffi::X509_V_FLAG_NO_CHECK_TIME;
+ }
+}
+
+foreign_type_and_impl_send_sync! {
+ type CType = ffi::X509_VERIFY_PARAM;
+ fn drop = ffi::X509_VERIFY_PARAM_free;
+
+ /// Adjust parameters associated with certificate verification.
+ pub struct X509VerifyParam;
+ /// Reference to `X509VerifyParam`.
+ pub struct X509VerifyParamRef;
+}
+
+impl X509VerifyParam {
+ /// Create an X509VerifyParam
+ #[corresponds(X509_VERIFY_PARAM_new)]
+ pub fn new() -> Result<X509VerifyParam, ErrorStack> {
+ 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(ossl102)]
+ pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> {
+ unsafe { cvt(ffi::X509_VERIFY_PARAM_set_purpose(self.as_ptr(), purpose.0)).map(|_| ()) }
+ }
+}