chore: add vendor dependencies for kauma build

This commit is contained in:
0xalivecow 2024-10-23 10:20:38 +02:00
parent 7c94e5d8fb
commit 067ef6141c
No known key found for this signature in database
1758 changed files with 398473 additions and 0 deletions

319
vendor/openssl/src/aes.rs vendored Normal file
View file

@ -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 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 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[..]);
}
}

910
vendor/openssl/src/asn1.rs vendored Normal file
View file

@ -0,0 +1,910 @@
#![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::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, util};
use openssl_macros::corresponds;
foreign_type_and_impl_send_sync! {
type CType = ffi::ASN1_GENERALIZEDTIME;
fn drop = ffi::ASN1_GENERALIZEDTIME_free;
/// Non-UTC representation of time
///
/// If a time can be represented by UTCTime, UTCTime is used
/// otherwise, ASN1_GENERALIZEDTIME is used. This would be, for
/// example outside the year range of 1950-2049.
///
/// [ASN1_GENERALIZEDTIME_set] documentation from OpenSSL provides
/// further details of implementation. Note: these docs are from the master
/// branch as documentation on the 1.1.0 branch did not include this page.
///
/// [ASN1_GENERALIZEDTIME_set]: https://www.openssl.org/docs/manmaster/man3/ASN1_GENERALIZEDTIME_set.html
pub struct Asn1GeneralizedTime;
/// Reference to a [`Asn1GeneralizedTime`]
///
/// [`Asn1GeneralizedTime`]: struct.Asn1GeneralizedTime.html
pub struct Asn1GeneralizedTimeRef;
}
impl fmt::Display for Asn1GeneralizedTimeRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
unsafe {
let mem_bio = match MemBio::new() {
Err(_) => return f.write_str("error"),
Ok(m) => m,
};
let print_result = cvt(ffi::ASN1_GENERALIZEDTIME_print(
mem_bio.as_ptr(),
self.as_ptr(),
));
match print_result {
Err(_) => f.write_str("error"),
Ok(_) => f.write_str(str::from_utf8_unchecked(mem_bio.get_buf())),
}
}
}
}
/// The type of an ASN.1 value.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct Asn1Type(c_int);
#[allow(missing_docs)] // no need to document the constants
impl Asn1Type {
pub const EOC: Asn1Type = Asn1Type(ffi::V_ASN1_EOC);
pub const BOOLEAN: Asn1Type = Asn1Type(ffi::V_ASN1_BOOLEAN);
pub const INTEGER: Asn1Type = Asn1Type(ffi::V_ASN1_INTEGER);
pub const BIT_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_BIT_STRING);
pub const OCTET_STRING: Asn1Type = Asn1Type(ffi::V_ASN1_OCTET_STRING);
pub const NULL: Asn1Type = Asn1Type(ffi::V_ASN1_NULL);
pub const OBJECT: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT);
pub const OBJECT_DESCRIPTOR: Asn1Type = Asn1Type(ffi::V_ASN1_OBJECT_DESCRIPTOR);
pub const EXTERNAL: Asn1Type = Asn1Type(ffi::V_ASN1_EXTERNAL);
pub const REAL: Asn1Type = Asn1Type(ffi::V_ASN1_REAL);
pub const ENUMERATED: Asn1Type = Asn1Type(ffi::V_ASN1_ENUMERATED);
pub const UTF8STRING: Asn1Type = Asn1Type(ffi::V_ASN1_UTF8STRING);
pub const SEQUENCE: Asn1Type = Asn1Type(ffi::V_ASN1_SEQUENCE);
pub const SET: Asn1Type = Asn1Type(ffi::V_ASN1_SET);
pub const NUMERICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_NUMERICSTRING);
pub const PRINTABLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_PRINTABLESTRING);
pub const T61STRING: Asn1Type = Asn1Type(ffi::V_ASN1_T61STRING);
pub const TELETEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_TELETEXSTRING);
pub const VIDEOTEXSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VIDEOTEXSTRING);
pub const IA5STRING: Asn1Type = Asn1Type(ffi::V_ASN1_IA5STRING);
pub const UTCTIME: Asn1Type = Asn1Type(ffi::V_ASN1_UTCTIME);
pub const GENERALIZEDTIME: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALIZEDTIME);
pub const GRAPHICSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GRAPHICSTRING);
pub const ISO64STRING: Asn1Type = Asn1Type(ffi::V_ASN1_ISO64STRING);
pub const VISIBLESTRING: Asn1Type = Asn1Type(ffi::V_ASN1_VISIBLESTRING);
pub const GENERALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_GENERALSTRING);
pub const UNIVERSALSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_UNIVERSALSTRING);
pub const BMPSTRING: Asn1Type = Asn1Type(ffi::V_ASN1_BMPSTRING);
/// Constructs an `Asn1Type` from a raw OpenSSL value.
pub fn from_raw(value: c_int) -> Self {
Asn1Type(value)
}
/// Returns the raw OpenSSL value represented by this type.
pub fn as_raw(&self) -> c_int {
self.0
}
}
/// Difference between two ASN1 times.
///
/// This `struct` is created by the [`diff`] method on [`Asn1TimeRef`]. See its
/// documentation for more.
///
/// [`diff`]: struct.Asn1TimeRef.html#method.diff
/// [`Asn1TimeRef`]: struct.Asn1TimeRef.html
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg(any(ossl102, boringssl))]
pub struct TimeDiff {
/// Difference in days
pub days: c_int,
/// Difference in seconds.
///
/// This is always less than the number of seconds in a day.
pub secs: c_int,
}
foreign_type_and_impl_send_sync! {
type CType = ffi::ASN1_TIME;
fn drop = ffi::ASN1_TIME_free;
/// Time storage and comparison
///
/// Asn1Time should be used to store and share time information
/// using certificates. If Asn1Time is set using a string, it must
/// be in either YYMMDDHHMMSSZ, YYYYMMDDHHMMSSZ, or another ASN.1 format.
///
/// [ASN_TIME_set] documentation at OpenSSL explains the ASN.1 implementation
/// used by OpenSSL.
///
/// [ASN_TIME_set]: https://www.openssl.org/docs/manmaster/crypto/ASN1_TIME_set.html
pub struct Asn1Time;
/// Reference to an [`Asn1Time`]
///
/// [`Asn1Time`]: struct.Asn1Time.html
pub struct Asn1TimeRef;
}
impl Asn1TimeRef {
/// Find difference between two times
#[corresponds(ASN1_TIME_diff)]
#[cfg(any(ossl102, boringssl))]
pub fn diff(&self, compare: &Self) -> Result<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(any(ossl102, boringssl))]
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(any(ossl102, boringssl))]
impl PartialEq for Asn1TimeRef {
fn eq(&self, other: &Asn1TimeRef) -> bool {
self.diff(other)
.map(|t| t.days == 0 && t.secs == 0)
.unwrap_or(false)
}
}
#[cfg(any(ossl102, boringssl))]
impl PartialEq<Asn1Time> for Asn1TimeRef {
fn eq(&self, other: &Asn1Time) -> bool {
self.diff(other)
.map(|t| t.days == 0 && t.secs == 0)
.unwrap_or(false)
}
}
#[cfg(any(ossl102, boringssl))]
impl 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(any(ossl102, boringssl))]
impl PartialOrd for Asn1TimeRef {
fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
self.compare(other).ok()
}
}
#[cfg(any(ossl102, boringssl))]
impl PartialOrd<Asn1Time> for Asn1TimeRef {
fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
self.compare(other).ok()
}
}
#[cfg(any(ossl102, boringssl))]
impl PartialOrd<Asn1Time> for &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 BoringSSL or OpenSSL 1.1.1 or newer.
#[corresponds(ASN1_TIME_set_string_X509)]
#[cfg(any(ossl111, boringssl))]
pub fn from_str_x509(s: &str) -> Result<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(any(ossl102, boringssl))]
impl PartialEq for Asn1Time {
fn eq(&self, other: &Asn1Time) -> bool {
self.diff(other)
.map(|t| t.days == 0 && t.secs == 0)
.unwrap_or(false)
}
}
#[cfg(any(ossl102, boringssl))]
impl PartialEq<Asn1TimeRef> for Asn1Time {
fn eq(&self, other: &Asn1TimeRef) -> bool {
self.diff(other)
.map(|t| t.days == 0 && t.secs == 0)
.unwrap_or(false)
}
}
#[cfg(any(ossl102, boringssl))]
impl<'a> PartialEq<&'a Asn1TimeRef> for Asn1Time {
fn eq(&self, other: &&'a Asn1TimeRef) -> bool {
self.diff(other)
.map(|t| t.days == 0 && t.secs == 0)
.unwrap_or(false)
}
}
#[cfg(any(ossl102, boringssl))]
impl PartialOrd for Asn1Time {
fn partial_cmp(&self, other: &Asn1Time) -> Option<Ordering> {
self.compare(other).ok()
}
}
#[cfg(any(ossl102, boringssl))]
impl PartialOrd<Asn1TimeRef> for Asn1Time {
fn partial_cmp(&self, other: &Asn1TimeRef) -> Option<Ordering> {
self.compare(other).ok()
}
}
#[cfg(any(ossl102, boringssl))]
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 { util::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 { util::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 { util::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());
util::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(any(ossl102, boringssl))]
fn time_eq() {
let a = Asn1Time::from_str("99991231235959Z").unwrap();
let b = Asn1Time::from_str("99991231235959Z").unwrap();
let c = Asn1Time::from_str("99991231235958Z").unwrap();
let a_ref = a.as_ref();
let b_ref = b.as_ref();
let c_ref = c.as_ref();
assert!(a == b);
assert!(a != c);
assert!(a == b_ref);
assert!(a != c_ref);
assert!(b_ref == a);
assert!(c_ref != a);
assert!(a_ref == b_ref);
assert!(a_ref != c_ref);
}
#[test]
#[cfg(any(ossl102, boringssl))]
fn time_ord() {
let a = Asn1Time::from_str("99991231235959Z").unwrap();
let b = Asn1Time::from_str("99991231235959Z").unwrap();
let c = Asn1Time::from_str("99991231235958Z").unwrap();
let a_ref = a.as_ref();
let b_ref = b.as_ref();
let c_ref = c.as_ref();
assert!(a >= b);
assert!(a > c);
assert!(b <= a);
assert!(c < a);
assert!(a_ref >= b);
assert!(a_ref > c);
assert!(b_ref <= a);
assert!(c_ref < a);
assert!(a >= b_ref);
assert!(a > c_ref);
assert!(b <= a_ref);
assert!(c < a_ref);
assert!(a_ref >= b_ref);
assert!(a_ref > c_ref);
assert!(b_ref <= a_ref);
assert!(c_ref < a_ref);
}
#[test]
fn integer_to_owned() {
let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
let b = a.to_owned().unwrap();
assert_eq!(
a.to_bn().unwrap().to_dec_str().unwrap().to_string(),
b.to_bn().unwrap().to_dec_str().unwrap().to_string(),
);
assert_ne!(a.as_ptr(), b.as_ptr());
}
#[test]
fn integer_cmp() {
let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
let b = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap();
let c = Asn1Integer::from_bn(&BigNum::from_dec_str("43").unwrap()).unwrap();
assert!(a == b);
assert!(a != c);
assert!(a < c);
assert!(c > b);
}
#[test]
fn object_from_str() {
let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap();
assert_eq!(object.nid(), Nid::SHA256);
}
#[test]
fn object_from_str_with_invalid_input() {
Asn1Object::from_str("NOT AN OID")
.map(|object| object.to_string())
.expect_err("parsing invalid OID should fail");
}
#[test]
#[cfg(ossl111)]
fn object_to_slice() {
let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap();
assert_eq!(
object.as_slice(),
&[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01],
);
}
#[test]
fn asn1_octet_string() {
let octet_string = Asn1OctetString::new_from_bytes(b"hello world").unwrap();
assert_eq!(octet_string.as_slice(), b"hello world");
assert_eq!(octet_string.len(), 11);
}
}

128
vendor/openssl/src/base64.rs vendored Normal file
View file

@ -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 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 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());
}
}

96
vendor/openssl/src/bio.rs vendored Normal file
View file

@ -0,0 +1,96 @@
use cfg_if::cfg_if;
use libc::c_int;
use std::marker::PhantomData;
use std::ptr;
use crate::cvt_p;
use crate::error::ErrorStack;
use crate::util;
pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>);
impl Drop for MemBioSlice<'_> {
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 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);
util::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)
}
}
}
#[cfg(test)]
mod tests {
use super::MemBio;
#[test]
fn test_mem_bio_get_buf_empty() {
let b = MemBio::new().unwrap();
assert_eq!(b.get_buf(), &[]);
}
}

1523
vendor/openssl/src/bn.rs vendored Normal file

File diff suppressed because it is too large Load diff

597
vendor/openssl/src/cipher.rs vendored Normal file
View file

@ -0,0 +1,597 @@
//! 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_256_xts() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_xts() as *mut _) }
}
pub fn aes_128_ctr() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ctr() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_128_cfb1() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb1() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_128_cfb128() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb128() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_128_cfb8() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb8() as *mut _) }
}
pub fn aes_128_gcm() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_gcm() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_128_ccm() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ccm() as *mut _) }
}
pub fn aes_128_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ofb() as *mut _) }
}
/// Requires OpenSSL 1.1.0 or newer.
#[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))]
pub fn aes_128_ocb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ocb() as *mut _) }
}
/// Requires OpenSSL 1.0.2 or newer.
#[cfg(ossl102)]
pub fn aes_128_wrap() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_wrap() as *mut _) }
}
/// Requires OpenSSL 1.1.0 or newer.
#[cfg(ossl110)]
pub fn aes_128_wrap_pad() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_wrap_pad() as *mut _) }
}
pub fn aes_192_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ecb() as *mut _) }
}
pub fn aes_192_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cbc() as *mut _) }
}
pub fn aes_192_ctr() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ctr() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_192_cfb1() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb1() as *mut _) }
}
pub fn aes_192_cfb128() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb128() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_192_cfb8() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_cfb8() as *mut _) }
}
pub fn aes_192_gcm() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_gcm() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_192_ccm() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ccm() as *mut _) }
}
pub fn aes_192_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ofb() as *mut _) }
}
/// Requires OpenSSL 1.1.0 or newer.
#[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))]
pub fn aes_192_ocb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ocb() as *mut _) }
}
/// Requires OpenSSL 1.0.2 or newer.
#[cfg(ossl102)]
pub fn aes_192_wrap() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_wrap() as *mut _) }
}
/// Requires OpenSSL 1.1.0 or newer.
#[cfg(ossl110)]
pub fn aes_192_wrap_pad() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_wrap_pad() as *mut _) }
}
pub fn aes_256_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ecb() as *mut _) }
}
pub fn aes_256_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cbc() as *mut _) }
}
pub fn aes_256_ctr() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ctr() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_256_cfb1() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb1() as *mut _) }
}
pub fn aes_256_cfb128() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb128() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_256_cfb8() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_cfb8() as *mut _) }
}
pub fn aes_256_gcm() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_gcm() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn aes_256_ccm() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ccm() as *mut _) }
}
pub fn aes_256_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ofb() as *mut _) }
}
/// Requires OpenSSL 1.1.0 or newer.
#[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))]
pub fn aes_256_ocb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ocb() as *mut _) }
}
/// Requires OpenSSL 1.0.2 or newer.
#[cfg(ossl102)]
pub fn aes_256_wrap() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_wrap() as *mut _) }
}
/// Requires OpenSSL 1.1.0 or newer.
#[cfg(ossl110)]
pub fn aes_256_wrap_pad() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_wrap_pad() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_BF"))]
pub fn bf_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_bf_cbc() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_BF"))]
pub fn bf_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_bf_ecb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_BF"))]
pub fn bf_cfb64() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_bf_cfb64() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_BF"))]
pub fn bf_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_bf_ofb() as *mut _) }
}
pub fn des_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_des_cbc() as *mut _) }
}
pub fn des_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_des_ecb() as *mut _) }
}
pub fn des_ede3() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3() as *mut _) }
}
pub fn des_ede3_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_ecb() as *mut _) }
}
pub fn des_ede3_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cbc() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn des_ede3_cfb8() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cfb8() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn des_ede3_cfb64() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cfb64() as *mut _) }
}
#[cfg(not(boringssl))]
pub fn des_ede3_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_ofb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_RC4"))]
pub fn rc4() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_rc4() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia128_cfb128() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_cfb128() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia128_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_ecb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia128_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_cbc() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia128_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_128_ofb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia192_cfb128() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_cfb128() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia192_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_ecb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia192_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_cbc() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia192_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_192_ofb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia256_cfb128() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_cfb128() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia256_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_ecb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia256_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_cbc() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAMELLIA"))]
pub fn camellia256_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_camellia_256_ofb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAST"))]
pub fn cast5_cfb64() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cfb64() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAST"))]
pub fn cast5_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_cast5_ecb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAST"))]
pub fn cast5_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_cast5_cbc() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_CAST"))]
pub fn cast5_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_cast5_ofb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_IDEA"))]
pub fn idea_cfb64() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_idea_cfb64() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_IDEA"))]
pub fn idea_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_idea_ecb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_IDEA"))]
pub fn idea_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_idea_cbc() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_IDEA"))]
pub fn idea_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_idea_ofb() as *mut _) }
}
#[cfg(all(any(ossl110, libressl310), not(osslconf = "OPENSSL_NO_CHACHA")))]
pub fn chacha20() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_chacha20() as *mut _) }
}
#[cfg(all(any(ossl110, libressl360), not(osslconf = "OPENSSL_NO_CHACHA")))]
pub fn chacha20_poly1305() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_chacha20_poly1305() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_SEED"))]
pub fn seed_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_seed_cbc() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_SEED"))]
pub fn seed_cfb128() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_seed_cfb128() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_SEED"))]
pub fn seed_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_seed_ecb() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_SEED"))]
pub fn seed_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_seed_ofb() as *mut _) }
}
#[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
pub fn sm4_ecb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ecb() as *mut _) }
}
#[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
pub fn sm4_cbc() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_sm4_cbc() as *mut _) }
}
#[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
pub fn sm4_ctr() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ctr() as *mut _) }
}
#[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
pub fn sm4_cfb128() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_sm4_cfb128() as *mut _) }
}
#[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM4")))]
pub fn sm4_ofb() -> &'static CipherRef {
unsafe { CipherRef::from_ptr(ffi::EVP_sm4_ofb() as *mut _) }
}
}
/// A reference to a [`Cipher`].
pub struct CipherRef(Opaque);
impl ForeignTypeRef for CipherRef {
type CType = ffi::EVP_CIPHER;
}
unsafe impl Sync for CipherRef {}
unsafe impl Send for CipherRef {}
impl CipherRef {
/// Returns the cipher's Nid.
#[corresponds(EVP_CIPHER_nid)]
pub fn nid(&self) -> Nid {
let nid = unsafe { ffi::EVP_CIPHER_nid(self.as_ptr()) };
Nid::from_raw(nid)
}
/// Returns the length of keys used with this cipher.
#[corresponds(EVP_CIPHER_key_length)]
pub fn key_length(&self) -> usize {
unsafe { EVP_CIPHER_key_length(self.as_ptr()) as usize }
}
/// Returns the length of the IV used with this cipher.
///
/// # Note
///
/// Ciphers that do not use an IV have an IV length of 0.
#[corresponds(EVP_CIPHER_iv_length)]
pub fn iv_length(&self) -> usize {
unsafe { EVP_CIPHER_iv_length(self.as_ptr()) as usize }
}
/// Returns the block size of the cipher.
///
/// # Note
///
/// Stream ciphers have a block size of 1.
#[corresponds(EVP_CIPHER_block_size)]
pub fn block_size(&self) -> usize {
unsafe { EVP_CIPHER_block_size(self.as_ptr()) as usize }
}
}

1106
vendor/openssl/src/cipher_ctx.rs vendored Normal file

File diff suppressed because it is too large Load diff

484
vendor/openssl/src/cms.rs vendored Normal file
View file

@ -0,0 +1,484 @@
//! 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;
let es = res.unwrap_err();
let error_array = es.errors();
assert_eq!(1, error_array.len());
let code = error_array[0].reason_code();
assert_eq!(code, CMS_R_CERTIFICATE_VERIFY_ERROR);
}
}

65
vendor/openssl/src/conf.rs vendored Normal file
View file

@ -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(any(boringssl, libressl400)))]
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(any(boringssl, libressl400)))]
pub use methods::*;

217
vendor/openssl/src/derive.rs vendored Normal file
View file

@ -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 Sync for Deriver<'_> {}
unsafe impl Send for Deriver<'_> {}
#[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 Drop for Deriver<'_> {
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());
}
}

499
vendor/openssl/src/dh.rs vendored Normal file
View file

@ -0,0 +1,499 @@
//! 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;
#[cfg(all(not(boringssl), ossl110))]
use crate::pkey::PKey;
use crate::ssl::{SslContext, SslMethod};
#[test]
#[cfg(ossl102)]
fn test_dh_rfc5114() {
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
let dh2 = Dh::get_2048_224().unwrap();
ctx.set_tmp_dh(&dh2).unwrap();
let dh3 = Dh::get_2048_256().unwrap();
ctx.set_tmp_dh(&dh3).unwrap();
}
#[test]
fn test_dh_params() {
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
let prime_p = BigNum::from_hex_str(
"87A8E61DB4B6663CFFBBD19C651959998CEEF608660DD0F25D2CEED4435E3B00E00DF8F1D61957D4FAF7DF\
4561B2AA3016C3D91134096FAA3BF4296D830E9A7C209E0C6497517ABD5A8A9D306BCF67ED91F9E6725B47\
58C022E0B1EF4275BF7B6C5BFC11D45F9088B941F54EB1E59BB8BC39A0BF12307F5C4FDB70C581B23F76B6\
3ACAE1CAA6B7902D52526735488A0EF13C6D9A51BFA4AB3AD8347796524D8EF6A167B5A41825D967E144E5\
140564251CCACB83E6B486F6B3CA3F7971506026C0B857F689962856DED4010ABD0BE621C3A3960A54E710\
C375F26375D7014103A4B54330C198AF126116D2276E11715F693877FAD7EF09CADB094AE91E1A1597",
).unwrap();
let prime_q = BigNum::from_hex_str(
"3FB32C9B73134D0B2E77506660EDBD484CA7B18F21EF205407F4793A1A0BA12510DBC15077BE463FFF4FED\
4AAC0BB555BE3A6C1B0C6B47B1BC3773BF7E8C6F62901228F8C28CBB18A55AE31341000A650196F931C77A\
57F2DDF463E5E9EC144B777DE62AAAB8A8628AC376D282D6ED3864E67982428EBC831D14348F6F2F9193B5\
045AF2767164E1DFC967C1FB3F2E55A4BD1BFFE83B9C80D052B985D182EA0ADB2A3B7313D3FE14C8484B1E\
052588B9B7D2BBD2DF016199ECD06E1557CD0915B3353BBB64E0EC377FD028370DF92B52C7891428CDC67E\
B6184B523D1DB246C32F63078490F00EF8D647D148D47954515E2327CFEF98C582664B4C0F6CC41659",
).unwrap();
let generator = BigNum::from_hex_str(
"8CF83642A709A097B447997640129DA299B1A47D1EB3750BA308B0FE64F5FBD3",
)
.unwrap();
let dh = Dh::from_params(
prime_p.to_owned().unwrap(),
generator.to_owned().unwrap(),
prime_q.to_owned().unwrap(),
)
.unwrap();
ctx.set_tmp_dh(&dh).unwrap();
assert_eq!(dh.prime_p(), &prime_p);
assert_eq!(dh.prime_q().unwrap(), &prime_q);
assert_eq!(dh.generator(), &generator);
}
#[test]
#[cfg(all(not(boringssl), ossl110))]
fn test_from_dhx_serializes_q() {
let p = BigNum::from_hex_str("00ad107e1e9123a9d0d660faa79559c51fa20d64e5683b9fd1b54b1597b61d0a75e6fa141df95a56dbaf9a3c407ba1df15eb3d688a309c180e1de6b85a1274a0a66d3f8152ad6ac2129037c9edefda4df8d91e8fef55b7394b7ad5b7d0b6c12207c9f98d11ed34dbf6c6ba0b2c8bbc27be6a00e0a0b9c49708b3bf8a317091883681286130bc8985db1602e714415d9330278273c7de31efdc7310f7121fd5a07415987d9adc0a486dcdf93acc44328387315d75e198c641a480cd86a1b9e587e8be60e69cc928b2b9c52172e413042e9b23f10b0e16e79763c9b53dcf4ba80a29e3fb73c16b8e75b97ef363e2ffa31f71cf9de5384e71b81c0ac4dffe0c10e64f").unwrap();
let g = BigNum::from_hex_str("00ac4032ef4f2d9ae39df30b5c8ffdac506cdebe7b89998caf74866a08cfe4ffe3a6824a4e10b9a6f0dd921f01a70c4afaab739d7700c29f52c57db17c620a8652be5e9001a8d66ad7c17669101999024af4d027275ac1348bb8a762d0521bc98ae247150422ea1ed409939d54da7460cdb5f6c6b250717cbef180eb34118e98d119529a45d6f834566e3025e316a330efbb77a86f0c1ab15b051ae3d428c8f8acb70a8137150b8eeb10e183edd19963ddd9e263e4770589ef6aa21e7f5f2ff381b539cce3409d13cd566afbb48d6c019181e1bcfe94b30269edfe72fe9b6aa4bd7b5a0f1c71cfff4c19c418e1f6ec017981bc087f2a7065b384b890d3191f2bfa").unwrap();
let q = BigNum::from_hex_str("00801c0d34c58d93fe997177101f80535a4738cebcbf389a99b36371eb")
.unwrap();
let y = BigNum::from_hex_str("0082c165bb576243ecf46d58c3d1501616955fca0320fa95ea11d2e6c1b9cf217676720dc1c08c85bf20c4d232b60a29a1e51c7b773bc645014587c525c86151b30d75486ec7b6c98efb5f74955b83116d01d0af1232af89213c2de574369d701aba9357300b920d3d8b98252d46c46952c16a5f33554b38317809c7b9add4701f5c158c1b7035e9fe39366ececb90d2896b78c523c4a577287ef5ba7a2663ed58aa20b5ec66e30f316610dfaa38583e495ab6af771c284387e660edbef4edb872e2e80e1d244ee95622e76d028e61c1e887c2aa792717362139f4dd26eafd49b2366eeb2350b01fe1b56022a2809e379559c37b375ba01c4eaacc14fd1b247837").unwrap();
let dh = Dh::from_params(p, g, q).unwrap();
let dh = dh.set_public_key(y).unwrap();
// Verify that 'q' is serialized in the public key.
let pkey = PKey::from_dhx(dh).unwrap();
assert_eq!(pkey.public_key_to_der().unwrap(), b"\x30\x82\x03\x44\x30\x82\x02\x36\x06\x07\x2a\x86\x48\xce\x3e\x02\x01\x30\x82\x02\x29\x02\x82\x01\x01\x00\xad\x10\x7e\x1e\x91\x23\xa9\xd0\xd6\x60\xfa\xa7\x95\x59\xc5\x1f\xa2\x0d\x64\xe5\x68\x3b\x9f\xd1\xb5\x4b\x15\x97\xb6\x1d\x0a\x75\xe6\xfa\x14\x1d\xf9\x5a\x56\xdb\xaf\x9a\x3c\x40\x7b\xa1\xdf\x15\xeb\x3d\x68\x8a\x30\x9c\x18\x0e\x1d\xe6\xb8\x5a\x12\x74\xa0\xa6\x6d\x3f\x81\x52\xad\x6a\xc2\x12\x90\x37\xc9\xed\xef\xda\x4d\xf8\xd9\x1e\x8f\xef\x55\xb7\x39\x4b\x7a\xd5\xb7\xd0\xb6\xc1\x22\x07\xc9\xf9\x8d\x11\xed\x34\xdb\xf6\xc6\xba\x0b\x2c\x8b\xbc\x27\xbe\x6a\x00\xe0\xa0\xb9\xc4\x97\x08\xb3\xbf\x8a\x31\x70\x91\x88\x36\x81\x28\x61\x30\xbc\x89\x85\xdb\x16\x02\xe7\x14\x41\x5d\x93\x30\x27\x82\x73\xc7\xde\x31\xef\xdc\x73\x10\xf7\x12\x1f\xd5\xa0\x74\x15\x98\x7d\x9a\xdc\x0a\x48\x6d\xcd\xf9\x3a\xcc\x44\x32\x83\x87\x31\x5d\x75\xe1\x98\xc6\x41\xa4\x80\xcd\x86\xa1\xb9\xe5\x87\xe8\xbe\x60\xe6\x9c\xc9\x28\xb2\xb9\xc5\x21\x72\xe4\x13\x04\x2e\x9b\x23\xf1\x0b\x0e\x16\xe7\x97\x63\xc9\xb5\x3d\xcf\x4b\xa8\x0a\x29\xe3\xfb\x73\xc1\x6b\x8e\x75\xb9\x7e\xf3\x63\xe2\xff\xa3\x1f\x71\xcf\x9d\xe5\x38\x4e\x71\xb8\x1c\x0a\xc4\xdf\xfe\x0c\x10\xe6\x4f\x02\x82\x01\x01\x00\xac\x40\x32\xef\x4f\x2d\x9a\xe3\x9d\xf3\x0b\x5c\x8f\xfd\xac\x50\x6c\xde\xbe\x7b\x89\x99\x8c\xaf\x74\x86\x6a\x08\xcf\xe4\xff\xe3\xa6\x82\x4a\x4e\x10\xb9\xa6\xf0\xdd\x92\x1f\x01\xa7\x0c\x4a\xfa\xab\x73\x9d\x77\x00\xc2\x9f\x52\xc5\x7d\xb1\x7c\x62\x0a\x86\x52\xbe\x5e\x90\x01\xa8\xd6\x6a\xd7\xc1\x76\x69\x10\x19\x99\x02\x4a\xf4\xd0\x27\x27\x5a\xc1\x34\x8b\xb8\xa7\x62\xd0\x52\x1b\xc9\x8a\xe2\x47\x15\x04\x22\xea\x1e\xd4\x09\x93\x9d\x54\xda\x74\x60\xcd\xb5\xf6\xc6\xb2\x50\x71\x7c\xbe\xf1\x80\xeb\x34\x11\x8e\x98\xd1\x19\x52\x9a\x45\xd6\xf8\x34\x56\x6e\x30\x25\xe3\x16\xa3\x30\xef\xbb\x77\xa8\x6f\x0c\x1a\xb1\x5b\x05\x1a\xe3\xd4\x28\xc8\xf8\xac\xb7\x0a\x81\x37\x15\x0b\x8e\xeb\x10\xe1\x83\xed\xd1\x99\x63\xdd\xd9\xe2\x63\xe4\x77\x05\x89\xef\x6a\xa2\x1e\x7f\x5f\x2f\xf3\x81\xb5\x39\xcc\xe3\x40\x9d\x13\xcd\x56\x6a\xfb\xb4\x8d\x6c\x01\x91\x81\xe1\xbc\xfe\x94\xb3\x02\x69\xed\xfe\x72\xfe\x9b\x6a\xa4\xbd\x7b\x5a\x0f\x1c\x71\xcf\xff\x4c\x19\xc4\x18\xe1\xf6\xec\x01\x79\x81\xbc\x08\x7f\x2a\x70\x65\xb3\x84\xb8\x90\xd3\x19\x1f\x2b\xfa\x02\x1d\x00\x80\x1c\x0d\x34\xc5\x8d\x93\xfe\x99\x71\x77\x10\x1f\x80\x53\x5a\x47\x38\xce\xbc\xbf\x38\x9a\x99\xb3\x63\x71\xeb\x03\x82\x01\x06\x00\x02\x82\x01\x01\x00\x82\xc1\x65\xbb\x57\x62\x43\xec\xf4\x6d\x58\xc3\xd1\x50\x16\x16\x95\x5f\xca\x03\x20\xfa\x95\xea\x11\xd2\xe6\xc1\xb9\xcf\x21\x76\x76\x72\x0d\xc1\xc0\x8c\x85\xbf\x20\xc4\xd2\x32\xb6\x0a\x29\xa1\xe5\x1c\x7b\x77\x3b\xc6\x45\x01\x45\x87\xc5\x25\xc8\x61\x51\xb3\x0d\x75\x48\x6e\xc7\xb6\xc9\x8e\xfb\x5f\x74\x95\x5b\x83\x11\x6d\x01\xd0\xaf\x12\x32\xaf\x89\x21\x3c\x2d\xe5\x74\x36\x9d\x70\x1a\xba\x93\x57\x30\x0b\x92\x0d\x3d\x8b\x98\x25\x2d\x46\xc4\x69\x52\xc1\x6a\x5f\x33\x55\x4b\x38\x31\x78\x09\xc7\xb9\xad\xd4\x70\x1f\x5c\x15\x8c\x1b\x70\x35\xe9\xfe\x39\x36\x6e\xce\xcb\x90\xd2\x89\x6b\x78\xc5\x23\xc4\xa5\x77\x28\x7e\xf5\xba\x7a\x26\x63\xed\x58\xaa\x20\xb5\xec\x66\xe3\x0f\x31\x66\x10\xdf\xaa\x38\x58\x3e\x49\x5a\xb6\xaf\x77\x1c\x28\x43\x87\xe6\x60\xed\xbe\xf4\xed\xb8\x72\xe2\xe8\x0e\x1d\x24\x4e\xe9\x56\x22\xe7\x6d\x02\x8e\x61\xc1\xe8\x87\xc2\xaa\x79\x27\x17\x36\x21\x39\xf4\xdd\x26\xea\xfd\x49\xb2\x36\x6e\xeb\x23\x50\xb0\x1f\xe1\xb5\x60\x22\xa2\x80\x9e\x37\x95\x59\xc3\x7b\x37\x5b\xa0\x1c\x4e\xaa\xcc\x14\xfd\x1b\x24\x78\x37");
}
#[test]
#[cfg(ossl102)]
fn test_dh_stored_restored() {
let dh1 = Dh::get_2048_256().unwrap();
let key1 = dh1.generate_key().unwrap();
let dh2 = Dh::get_2048_256().unwrap();
let key2 = dh2
.set_private_key(key1.private_key().to_owned().unwrap())
.unwrap();
assert_eq!(key1.public_key(), key2.public_key());
assert_eq!(key1.private_key(), key2.private_key());
}
#[test]
#[cfg(ossl102)]
fn test_set_keys() {
let dh1 = Dh::get_2048_256().unwrap();
let key1 = dh1.generate_key().unwrap();
let dh2 = Dh::get_2048_256().unwrap();
let key2 = dh2
.set_public_key(key1.public_key().to_owned().unwrap())
.unwrap();
assert_eq!(key1.public_key(), key2.public_key());
let dh3 = Dh::get_2048_256().unwrap();
let key3 = dh3
.set_key(
key1.public_key().to_owned().unwrap(),
key1.private_key().to_owned().unwrap(),
)
.unwrap();
assert_eq!(key1.public_key(), key3.public_key());
assert_eq!(key1.private_key(), key3.private_key());
}
#[test]
fn test_dh_from_pem() {
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
let params = include_bytes!("../test/dhparams.pem");
let dh = Dh::params_from_pem(params).unwrap();
ctx.set_tmp_dh(&dh).unwrap();
}
#[test]
fn test_dh_from_der() {
let params = include_bytes!("../test/dhparams.pem");
let dh = Dh::params_from_pem(params).unwrap();
let der = dh.params_to_der().unwrap();
Dh::params_from_der(&der).unwrap();
}
#[test]
#[cfg(ossl102)]
fn test_dh_generate_key_compute_key() {
let dh1 = Dh::get_2048_224().unwrap().generate_key().unwrap();
let dh2 = Dh::get_2048_224().unwrap().generate_key().unwrap();
let shared_a = dh1.compute_key(dh2.public_key()).unwrap();
let shared_b = dh2.compute_key(dh1.public_key()).unwrap();
assert_eq!(shared_a, shared_b);
}
#[test]
fn test_dh_generate_params_generate_key_compute_key() {
let dh_params1 = Dh::generate_params(512, 2).unwrap();
let dh_params2 = Dh::from_pqg(
dh_params1.prime_p().to_owned().unwrap(),
None,
dh_params1.generator().to_owned().unwrap(),
)
.unwrap();
let dh1 = dh_params1.generate_key().unwrap();
let dh2 = dh_params2.generate_key().unwrap();
let shared_a = dh1.compute_key(dh2.public_key()).unwrap();
let shared_b = dh2.compute_key(dh1.public_key()).unwrap();
assert_eq!(shared_a, shared_b);
}
#[test]
fn test_dh_check_key() {
let dh1 = Dh::generate_params(512, 2).unwrap();
let p = BigNum::from_hex_str("04").unwrap();
let g = BigNum::from_hex_str("02").unwrap();
let dh2 = Dh::from_pqg(p, None, g).unwrap();
assert!(dh1.check_key().unwrap());
assert!(matches!(dh2.check_key(), Ok(false) | Err(_)));
}
}

697
vendor/openssl/src/dsa.rs vendored Normal file
View file

@ -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 }");
}
}

1345
vendor/openssl/src/ec.rs vendored Normal file

File diff suppressed because it is too large Load diff

224
vendor/openssl/src/ecdsa.rs vendored Normal file
View file

@ -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 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 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_EC", ignore)]
fn sign_and_verify() {
let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
let private_key = EcKey::generate(&group).unwrap();
let public_key = get_public_key(&group, &private_key).unwrap();
let private_key2 = EcKey::generate(&group).unwrap();
let public_key2 = get_public_key(&group, &private_key2).unwrap();
let data = String::from("hello");
let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap();
// Signature can be verified using the correct data & correct public key
let verification = res.verify(data.as_bytes(), &public_key).unwrap();
assert!(verification);
// Signature will not be verified using the incorrect data but the correct public key
let verification2 = res
.verify(String::from("hello2").as_bytes(), &public_key)
.unwrap();
assert!(!verification2);
// Signature will not be verified using the correct data but the incorrect public key
let verification3 = res.verify(data.as_bytes(), &public_key2).unwrap();
assert!(!verification3);
}
#[test]
#[cfg_attr(osslconf = "OPENSSL_NO_EC", ignore)]
fn check_private_components() {
let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
let private_key = EcKey::generate(&group).unwrap();
let public_key = get_public_key(&group, &private_key).unwrap();
let data = String::from("hello");
let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap();
let verification = res.verify(data.as_bytes(), &public_key).unwrap();
assert!(verification);
let r = res.r().to_owned().unwrap();
let s = res.s().to_owned().unwrap();
let res2 = EcdsaSig::from_private_components(r, s).unwrap();
let verification2 = res2.verify(data.as_bytes(), &public_key).unwrap();
assert!(verification2);
}
#[test]
#[cfg_attr(osslconf = "OPENSSL_NO_EC", ignore)]
fn serialize_deserialize() {
let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
let private_key = EcKey::generate(&group).unwrap();
let public_key = get_public_key(&group, &private_key).unwrap();
let data = String::from("hello");
let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap();
let der = res.to_der().unwrap();
let sig = EcdsaSig::from_der(&der).unwrap();
let verification = sig.verify(data.as_bytes(), &public_key).unwrap();
assert!(verification);
}
}

578
vendor/openssl/src/encrypt.rs vendored Normal file
View file

@ -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 Sync for Encrypter<'_> {}
unsafe impl Send for Encrypter<'_> {}
impl Drop for Encrypter<'_> {
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 Sync for Decrypter<'_> {}
unsafe impl Send for Decrypter<'_> {}
impl Drop for Decrypter<'_> {
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());
}
}

181
vendor/openssl/src/envelope.rs vendored Normal file
View file

@ -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`.
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`.
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]);
}
}

418
vendor/openssl/src/error.rs vendored Normal file
View file

@ -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);
}
}

32
vendor/openssl/src/ex_data.rs vendored Normal file
View file

@ -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
}
}

21
vendor/openssl/src/fips.rs vendored Normal file
View file

@ -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 }
}

796
vendor/openssl/src/hash.rs vendored Normal file
View file

@ -0,0 +1,796 @@
//! 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};
use openssl_macros::corresponds;
cfg_if! {
if #[cfg(any(ossl110, boringssl, libressl382))] {
use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
} else {
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
}
}
/// A message digest algorithm.
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct MessageDigest(*const ffi::EVP_MD);
impl MessageDigest {
/// Creates a `MessageDigest` from a raw OpenSSL pointer.
///
/// # Safety
///
/// The caller must ensure the pointer is valid.
pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self {
MessageDigest(x)
}
/// Returns the `MessageDigest` corresponding to an `Nid`.
#[corresponds(EVP_get_digestbynid)]
pub fn from_nid(type_: Nid) -> Option<MessageDigest> {
ffi::init();
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.
#[corresponds(EVP_get_digestbyname)]
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(any(ossl111, libressl380))]
pub fn sha3_224() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_sha3_224()) }
}
#[cfg(any(ossl111, libressl380))]
pub fn sha3_256() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_sha3_256()) }
}
#[cfg(any(ossl111, libressl380))]
pub fn sha3_384() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_sha3_384()) }
}
#[cfg(any(ossl111, libressl380))]
pub fn sha3_512() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_sha3_512()) }
}
#[cfg(ossl111)]
pub fn shake_128() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_shake128()) }
}
#[cfg(ossl111)]
pub fn shake_256() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_shake256()) }
}
#[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
pub fn ripemd160() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_ripemd160()) }
}
#[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
pub fn sm3() -> MessageDigest {
unsafe { MessageDigest(ffi::EVP_sm3()) }
}
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn as_ptr(&self) -> *const ffi::EVP_MD {
self.0
}
/// The block size of the digest in bytes.
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn block_size(&self) -> usize {
unsafe { ffi::EVP_MD_block_size(self.0) as usize }
}
/// The size of the digest in bytes.
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn size(&self) -> usize {
unsafe { ffi::EVP_MD_size(self.0) as usize }
}
/// The name of the digest.
#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn type_(&self) -> Nid {
Nid::from_raw(unsafe { ffi::EVP_MD_type(self.0) })
}
}
unsafe impl Sync for MessageDigest {}
unsafe impl Send for MessageDigest {}
#[derive(PartialEq, Copy, Clone)]
enum State {
Reset,
Updated,
Finalized,
}
use self::State::*;
/// Provides message digest (hash) computation.
///
/// # Examples
///
/// ```
/// use openssl::hash::{Hasher, MessageDigest};
///
/// # fn main() -> Result<(), Box<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(any(ossl111, libressl380))]
#[test]
fn test_sha3_224() {
let tests = [(
"416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
"1de092dd9fbcbbf450f26264f4778abd48af851f2832924554c56913",
)];
for test in tests.iter() {
hash_test(MessageDigest::sha3_224(), test);
}
assert_eq!(MessageDigest::sha3_224().block_size(), 144);
assert_eq!(MessageDigest::sha3_224().size(), 28);
assert_eq!(
MessageDigest::sha3_224().type_().as_raw(),
Nid::SHA3_224.as_raw()
);
}
#[cfg(any(ossl111, libressl380))]
#[test]
fn test_sha3_256() {
let tests = [(
"416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
"b38e38f08bc1c0091ed4b5f060fe13e86aa4179578513ad11a6e3abba0062f61",
)];
for test in tests.iter() {
hash_test(MessageDigest::sha3_256(), test);
}
assert_eq!(MessageDigest::sha3_256().block_size(), 136);
assert_eq!(MessageDigest::sha3_256().size(), 32);
assert_eq!(
MessageDigest::sha3_256().type_().as_raw(),
Nid::SHA3_256.as_raw()
);
}
#[cfg(any(ossl111, libressl380))]
#[test]
fn test_sha3_384() {
let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
"966ee786ab3482dd811bf7c8fa8db79aa1f52f6c3c369942ef14240ebd857c6ff626ec35d9e131ff64d328\
ef2008ff16"
)];
for test in tests.iter() {
hash_test(MessageDigest::sha3_384(), test);
}
assert_eq!(MessageDigest::sha3_384().block_size(), 104);
assert_eq!(MessageDigest::sha3_384().size(), 48);
assert_eq!(
MessageDigest::sha3_384().type_().as_raw(),
Nid::SHA3_384.as_raw()
);
}
#[cfg(any(ossl111, libressl380))]
#[test]
fn test_sha3_512() {
let tests = [("416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
"c072288ef728cd53a029c47687960b9225893532f42b923156e37020bdc1eda753aafbf30af859d4f4c3a1\
807caee3a79f8eb02dcd61589fbbdf5f40c8787a72"
)];
for test in tests.iter() {
hash_test(MessageDigest::sha3_512(), test);
}
assert_eq!(MessageDigest::sha3_512().block_size(), 72);
assert_eq!(MessageDigest::sha3_512().size(), 64);
assert_eq!(
MessageDigest::sha3_512().type_().as_raw(),
Nid::SHA3_512.as_raw()
);
}
#[cfg(ossl111)]
#[test]
fn test_shake_128() {
let tests = [(
"416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
"49d0697ff508111d8b84f15e46daf135",
)];
for test in tests.iter() {
hash_xof_test(MessageDigest::shake_128(), test);
}
assert_eq!(MessageDigest::shake_128().block_size(), 168);
assert_eq!(MessageDigest::shake_128().size(), 16);
assert_eq!(
MessageDigest::shake_128().type_().as_raw(),
Nid::SHAKE128.as_raw()
);
}
#[cfg(ossl111)]
#[test]
fn test_shake_256() {
let tests = [(
"416c6c20796f75722062617365206172652062656c6f6e6720746f207573",
"4e2dfdaa75d1e049d0eaeffe28e76b17cea47b650fb8826fe48b94664326a697",
)];
for test in tests.iter() {
hash_xof_test(MessageDigest::shake_256(), test);
}
assert_eq!(MessageDigest::shake_256().block_size(), 136);
assert_eq!(MessageDigest::shake_256().size(), 32);
assert_eq!(
MessageDigest::shake_256().type_().as_raw(),
Nid::SHAKE256.as_raw()
);
}
#[test]
#[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
#[cfg_attr(ossl300, ignore)]
fn test_ripemd160() {
#[cfg(ossl300)]
let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap();
let tests = [("616263", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc")];
for test in tests.iter() {
hash_test(MessageDigest::ripemd160(), test);
}
assert_eq!(MessageDigest::ripemd160().block_size(), 64);
assert_eq!(MessageDigest::ripemd160().size(), 20);
assert_eq!(
MessageDigest::ripemd160().type_().as_raw(),
Nid::RIPEMD160.as_raw()
);
}
#[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
#[test]
fn test_sm3() {
let tests = [(
"616263",
"66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0",
)];
for test in tests.iter() {
hash_test(MessageDigest::sm3(), test);
}
assert_eq!(MessageDigest::sm3().block_size(), 64);
assert_eq!(MessageDigest::sm3().size(), 32);
assert_eq!(MessageDigest::sm3().type_().as_raw(), Nid::SM3.as_raw());
}
#[test]
fn from_nid() {
assert_eq!(
MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(),
MessageDigest::sha256().as_ptr()
);
}
#[test]
fn from_name() {
assert_eq!(
MessageDigest::from_name("SHA256").unwrap().as_ptr(),
MessageDigest::sha256().as_ptr()
)
}
}

176
vendor/openssl/src/kdf.rs vendored Normal file
View file

@ -0,0 +1,176 @@
#[cfg(ossl320)]
struct EvpKdf(*mut ffi::EVP_KDF);
#[cfg(ossl320)]
impl Drop for EvpKdf {
fn drop(&mut self) {
unsafe {
ffi::EVP_KDF_free(self.0);
}
}
}
#[cfg(ossl320)]
struct EvpKdfCtx(*mut ffi::EVP_KDF_CTX);
#[cfg(ossl320)]
impl Drop for EvpKdfCtx {
fn drop(&mut self) {
unsafe {
ffi::EVP_KDF_CTX_free(self.0);
}
}
}
cfg_if::cfg_if! {
if #[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))] {
use std::cmp;
use std::ffi::c_void;
use std::mem::MaybeUninit;
use std::ptr;
use foreign_types::ForeignTypeRef;
use libc::c_char;
use crate::{cvt, cvt_p};
use crate::lib_ctx::LibCtxRef;
use crate::error::ErrorStack;
/// Derives a key using the argon2id algorithm.
///
/// To use multiple cores to process the lanes in parallel you must
/// set a global max thread count using `OSSL_set_max_threads`. On
/// builds with no threads all lanes will be processed sequentially.
///
/// Requires OpenSSL 3.2.0 or newer.
#[allow(clippy::too_many_arguments)]
pub fn argon2id(
ctx: Option<&LibCtxRef>,
pass: &[u8],
salt: &[u8],
ad: Option<&[u8]>,
secret: Option<&[u8]>,
mut iter: u32,
mut lanes: u32,
mut memcost: u32,
out: &mut [u8],
) -> Result<(), ErrorStack> {
unsafe {
ffi::init();
let libctx = ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr);
let max_threads = ffi::OSSL_get_max_threads(libctx);
let mut threads = 1;
// If max_threads is 0, then this isn't a threaded build.
// If max_threads is > u32::MAX we need to clamp since
// argon2id's threads parameter is a u32.
if max_threads > 0 {
threads = cmp::min(lanes, cmp::min(max_threads, u32::MAX as u64) as u32);
}
let mut params: [ffi::OSSL_PARAM; 10] =
core::array::from_fn(|_| MaybeUninit::<ffi::OSSL_PARAM>::zeroed().assume_init());
let mut idx = 0;
params[idx] = ffi::OSSL_PARAM_construct_octet_string(
b"pass\0".as_ptr() as *const c_char,
pass.as_ptr() as *mut c_void,
pass.len(),
);
idx += 1;
params[idx] = ffi::OSSL_PARAM_construct_octet_string(
b"salt\0".as_ptr() as *const c_char,
salt.as_ptr() as *mut c_void,
salt.len(),
);
idx += 1;
params[idx] =
ffi::OSSL_PARAM_construct_uint(b"threads\0".as_ptr() as *const c_char, &mut threads);
idx += 1;
params[idx] =
ffi::OSSL_PARAM_construct_uint(b"lanes\0".as_ptr() as *const c_char, &mut lanes);
idx += 1;
params[idx] =
ffi::OSSL_PARAM_construct_uint(b"memcost\0".as_ptr() as *const c_char, &mut memcost);
idx += 1;
params[idx] =
ffi::OSSL_PARAM_construct_uint(b"iter\0".as_ptr() as *const c_char, &mut iter);
idx += 1;
let mut size = out.len() as u32;
params[idx] =
ffi::OSSL_PARAM_construct_uint(b"size\0".as_ptr() as *const c_char, &mut size);
idx += 1;
if let Some(ad) = ad {
params[idx] = ffi::OSSL_PARAM_construct_octet_string(
b"ad\0".as_ptr() as *const c_char,
ad.as_ptr() as *mut c_void,
ad.len(),
);
idx += 1;
}
if let Some(secret) = secret {
params[idx] = ffi::OSSL_PARAM_construct_octet_string(
b"secret\0".as_ptr() as *const c_char,
secret.as_ptr() as *mut c_void,
secret.len(),
);
idx += 1;
}
params[idx] = ffi::OSSL_PARAM_construct_end();
let argon2 = EvpKdf(cvt_p(ffi::EVP_KDF_fetch(
libctx,
b"ARGON2ID\0".as_ptr() as *const c_char,
ptr::null(),
))?);
let ctx = EvpKdfCtx(cvt_p(ffi::EVP_KDF_CTX_new(argon2.0))?);
cvt(ffi::EVP_KDF_derive(
ctx.0,
out.as_mut_ptr(),
out.len(),
params.as_ptr(),
))
.map(|_| ())
}
}
}
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))]
fn argon2id() {
// RFC 9106 test vector for argon2id
let pass = hex::decode("0101010101010101010101010101010101010101010101010101010101010101")
.unwrap();
let salt = hex::decode("02020202020202020202020202020202").unwrap();
let secret = hex::decode("0303030303030303").unwrap();
let ad = hex::decode("040404040404040404040404").unwrap();
let expected = "0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659";
let mut actual = [0u8; 32];
super::argon2id(
None,
&pass,
&salt,
Some(&ad),
Some(&secret),
3,
4,
32,
&mut actual,
)
.unwrap();
assert_eq!(hex::encode(&actual[..]), expected);
}
#[test]
#[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))]
fn argon2id_no_ad_secret() {
// Test vector from OpenSSL
let pass = b"";
let salt = hex::decode("02020202020202020202020202020202").unwrap();
let expected = "0a34f1abde67086c82e785eaf17c68382259a264f4e61b91cd2763cb75ac189a";
let mut actual = [0u8; 32];
super::argon2id(None, pass, &salt, None, None, 3, 4, 32, &mut actual).unwrap();
assert_eq!(hex::encode(&actual[..]), expected);
}
}

257
vendor/openssl/src/lib.rs vendored Normal file
View file

@ -0,0 +1,257 @@
//! 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 be configured to automatically find a configuration and root certificates at `/usr/local/ssl`.
//! This path can be overridden with an environment variable (see the manual section below).
//! Alternatively, the `openssl-probe` crate can be used to find root certificates at runtime.
//!
//! ## 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 pkgconf openssl
//!
//! # Debian and Ubuntu
//! $ sudo apt-get install pkg-config libssl-dev
//!
//! # Fedora
//! $ sudo dnf install pkgconf perl-FindBin perl-IPC-Cmd openssl-devel
//!
//! # Alpine Linux
//! $ apk add pkgconf openssl-dev
//!
//! # openSUSE
//! $ sudo zypper in libopenssl-devel
//! ```
//!
//! ## Manual
//!
//! A set of environment variables can be used to point `openssl-sys` towards an OpenSSL installation. They will
//! override the automatic detection logic.
//!
//! * `OPENSSL_DIR` - If specified, the directory of an OpenSSL installation. The directory should contain `lib` and
//! `include` subdirectories containing the libraries and headers respectively.
//! * `OPENSSL_LIB_DIR` and `OPENSSL_INCLUDE_DIR` - If specified, the directories containing the OpenSSL libraries and
//! headers respectively. This can be used if the OpenSSL installation is split in a nonstandard directory layout.
//! * `OPENSSL_STATIC` - If set, the crate will statically link to OpenSSL rather than dynamically link.
//! * `OPENSSL_LIBS` - If set, a `:`-separated list of library names to link to (e.g. `ssl:crypto`). This can be used
//! if nonstandard library names were used for whatever reason.
//! * `OPENSSL_NO_VENDOR` - If set, always find OpenSSL in the system, even if the `vendored` feature is enabled.
//!
//! If the `vendored` Cargo feature is enabled, the following environment variable can also be used to further configure
//! the OpenSSL build.
//!
//! * `OPENSSL_CONFIG_DIR` - If set, the copy of OpenSSL built by the `openssl-src` crate will be configured to look for
//! configuration files and root certificates in this directory.
//!
//! Additionally, these variables can be prefixed with the upper-cased target architecture (e.g.
//! `X86_64_UNKNOWN_LINUX_GNU_OPENSSL_DIR`), which can be useful when cross compiling.
//!
//! # Feature Detection
//!
//! APIs have been added to and removed from the various supported OpenSSL versions, and this library exposes the
//! functionality available in the version being linked against. This means that methods, constants, and even modules
//! will be present when building against one version of OpenSSL but not when building against another! APIs will
//! document any version-specific availability restrictions.
//!
//! A build script can be used to detect the OpenSSL or LibreSSL version at compile time if needed. The `openssl-sys`
//! crate propagates the version via the `DEP_OPENSSL_VERSION_NUMBER` and `DEP_OPENSSL_LIBRESSL_VERSION_NUMBER`
//! environment variables to build scripts. The version format is a hex-encoding of the OpenSSL release version:
//! `0xMNNFFPPS`. For example, version 1.0.2g's encoding is `0x1_00_02_07_0`.
//!
//! For example, let's say we want to adjust the TLSv1.3 cipher suites used by a client, but also want to compile
//! against OpenSSL versions that don't support TLSv1.3:
//!
//! Cargo.toml:
//!
//! ```toml
//! [dependencies]
//! openssl-sys = "0.9"
//! openssl = "0.10"
//! ```
//!
//! build.rs:
//!
//! ```
//! use std::env;
//!
//! fn main() {
//! if let Ok(v) = env::var("DEP_OPENSSL_VERSION_NUMBER") {
//! let version = u64::from_str_radix(&v, 16).unwrap();
//!
//! if version >= 0x1_01_01_00_0 {
//! println!("cargo:rustc-cfg=openssl111");
//! }
//! }
//! }
//! ```
//!
//! lib.rs:
//!
//! ```
//! use openssl::ssl::{SslConnector, SslMethod};
//!
//! let mut ctx = SslConnector::builder(SslMethod::tls()).unwrap();
//!
//! // set_ciphersuites was added in OpenSSL 1.1.1, so we can only call it when linking against that version
//! #[cfg(openssl111)]
//! ctx.set_ciphersuites("TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256").unwrap();
//! ```
#![doc(html_root_url = "https://docs.rs/openssl/0.10")]
#![warn(rust_2018_idioms)]
#![allow(clippy::uninlined_format_args, clippy::needless_doctest_main)]
#[doc(inline)]
pub use ffi::init;
use libc::c_int;
#[cfg(ossl300)]
use libc::c_long;
use crate::error::ErrorStack;
#[macro_use]
mod macros;
mod bio;
#[macro_use]
mod util;
pub mod aes;
pub mod asn1;
pub mod base64;
pub mod bn;
pub mod cipher;
pub mod cipher_ctx;
#[cfg(all(not(libressl), not(osslconf = "OPENSSL_NO_CMS")))]
pub mod cms;
pub mod conf;
pub mod derive;
pub mod dh;
pub mod dsa;
pub mod ec;
pub mod ecdsa;
pub mod encrypt;
#[cfg(not(boringssl))]
pub mod envelope;
pub mod error;
pub mod ex_data;
#[cfg(not(any(libressl, ossl300)))]
pub mod fips;
pub mod hash;
pub mod kdf;
#[cfg(ossl300)]
pub mod lib_ctx;
pub mod md;
pub mod md_ctx;
pub mod memcmp;
pub mod nid;
#[cfg(not(osslconf = "OPENSSL_NO_OCSP"))]
pub mod ocsp;
pub mod pkcs12;
pub mod pkcs5;
#[cfg(not(boringssl))]
pub mod pkcs7;
pub mod pkey;
pub mod pkey_ctx;
#[cfg(ossl300)]
pub mod provider;
pub mod rand;
pub mod rsa;
pub mod sha;
pub mod sign;
pub mod srtp;
pub mod ssl;
pub mod stack;
pub mod string;
pub mod symm;
pub mod version;
pub mod x509;
#[cfg(boringssl)]
type LenType = libc::size_t;
#[cfg(not(boringssl))]
type LenType = libc::c_int;
#[cfg(boringssl)]
type SLenType = libc::ssize_t;
#[cfg(not(boringssl))]
type SLenType = libc::c_int;
#[inline]
fn cvt_p<T>(r: *mut T) -> Result<*mut T, ErrorStack> {
if r.is_null() {
Err(ErrorStack::get())
} else {
Ok(r)
}
}
#[inline]
fn cvt_p_const<T>(r: *const T) -> Result<*const 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)
}
}
// cvt_long is currently only used in functions that require openssl >= 3.0.0,
// so this cfg statement is used to avoid "unused function" errors when
// compiling with openssl < 3.0.0
#[inline]
#[cfg(ossl300)]
fn cvt_long(r: c_long) -> Result<c_long, 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)
}
}

22
vendor/openssl/src/lib_ctx.rs vendored Normal file
View file

@ -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))
}
}
}

270
vendor/openssl/src/macros.rs vendored Normal file
View file

@ -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 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 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>{}
};
}

235
vendor/openssl/src/md.rs vendored Normal file
View file

@ -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> {
ffi::init();
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> {
ffi::init();
let algorithm = CString::new(algorithm).unwrap();
let properties = properties.map(|s| CString::new(s).unwrap());
unsafe {
let ptr = cvt_p(ffi::EVP_MD_fetch(
ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
algorithm.as_ptr(),
properties.map_or(ptr::null_mut(), |s| s.as_ptr()),
))?;
Ok(Md::from_ptr(ptr))
}
}
#[inline]
#[cfg(not(boringssl))]
pub fn null() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_md_null() as *mut _) }
}
#[inline]
pub fn md5() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_md5() as *mut _) }
}
#[inline]
pub fn sha1() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha1() as *mut _) }
}
#[inline]
pub fn sha224() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha224() as *mut _) }
}
#[inline]
pub fn sha256() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha256() as *mut _) }
}
#[inline]
pub fn sha384() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha384() as *mut _) }
}
#[inline]
pub fn sha512() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha512() as *mut _) }
}
#[cfg(any(ossl111, libressl380))]
#[inline]
pub fn sha3_224() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha3_224() as *mut _) }
}
#[cfg(any(ossl111, libressl380))]
#[inline]
pub fn sha3_256() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha3_256() as *mut _) }
}
#[cfg(any(ossl111, libressl380))]
#[inline]
pub fn sha3_384() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha3_384() as *mut _) }
}
#[cfg(any(ossl111, libressl380))]
#[inline]
pub fn sha3_512() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sha3_512() as *mut _) }
}
#[cfg(ossl111)]
#[inline]
pub fn shake128() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_shake128() as *mut _) }
}
#[cfg(ossl111)]
#[inline]
pub fn shake256() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_shake256() as *mut _) }
}
#[cfg(not(osslconf = "OPENSSL_NO_RMD160"))]
#[inline]
pub fn ripemd160() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_ripemd160() as *mut _) }
}
#[cfg(all(any(ossl111, libressl291), not(osslconf = "OPENSSL_NO_SM3")))]
#[inline]
pub fn sm3() -> &'static MdRef {
unsafe { MdRef::from_ptr(ffi::EVP_sm3() as *mut _) }
}
}
/// A reference to an [`Md`].
pub struct MdRef(Opaque);
impl ForeignTypeRef for MdRef {
type CType = ffi::EVP_MD;
}
unsafe impl Sync for MdRef {}
unsafe impl Send for MdRef {}
impl MdRef {
/// Returns the block size of the digest in bytes.
#[corresponds(EVP_MD_block_size)]
#[inline]
pub fn block_size(&self) -> usize {
unsafe { ffi::EVP_MD_block_size(self.as_ptr()) as usize }
}
/// Returns the size of the digest in bytes.
#[corresponds(EVP_MD_size)]
#[inline]
pub fn size(&self) -> usize {
unsafe { ffi::EVP_MD_size(self.as_ptr()) as usize }
}
/// Returns the [`Nid`] of the digest.
#[corresponds(EVP_MD_type)]
#[inline]
pub fn type_(&self) -> Nid {
unsafe { Nid::from_raw(ffi::EVP_MD_type(self.as_ptr())) }
}
}

552
vendor/openssl/src/md_ctx.rs vendored Normal file
View file

@ -0,0 +1,552 @@
//! 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_p};
use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
use openssl_macros::corresponds;
use std::convert::TryFrom;
use std::ptr;
cfg_if! {
if #[cfg(any(ossl110, boringssl, libressl382))] {
use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
} else {
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
}
}
foreign_type_and_impl_send_sync! {
type CType = ffi::EVP_MD_CTX;
fn drop = EVP_MD_CTX_free;
pub struct MdCtx;
/// A reference to an [`MdCtx`].
pub struct MdCtxRef;
}
impl MdCtx {
/// Creates a new context.
#[corresponds(EVP_MD_CTX_new)]
#[inline]
pub fn new() -> Result<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 = ffi::EVP_DigestVerifyFinal(
self.as_ptr(),
signature.as_ptr() as *mut _,
signature.len(),
);
if r == 1 {
Ok(true)
} else {
let errors = ErrorStack::get();
if errors.errors().is_empty() {
Ok(false)
} else {
Err(errors)
}
}
}
}
/// 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();
assert!(matches!(
ctx.digest_verify_final(&signature),
Ok(false) | Err(_)
));
assert!(ErrorStack::get().errors().is_empty());
}
#[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);
}
}

93
vendor/openssl/src/memcmp.rs vendored Normal file
View file

@ -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]);
}
}

1181
vendor/openssl/src/nid.rs vendored Normal file

File diff suppressed because it is too large Load diff

352
vendor/openssl/src/ocsp.rs vendored Normal file
View file

@ -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 OcspStatus<'_> {
/// 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;
}

403
vendor/openssl/src/pkcs12.rs vendored Normal file
View file

@ -0,0 +1,403 @@
//! 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
.as_ref()
.unwrap()
.digest(MessageDigest::sha1())
.unwrap()
),
"59172d9313e84459bcff27f967e79e6e9217e584"
);
assert_eq!(
parsed.cert.as_ref().unwrap().alias(),
Some(b"foobar.com" as &[u8])
);
let chain = parsed.ca.unwrap();
assert_eq!(chain.len(), 1);
assert_eq!(
hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()),
"c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"
);
}
#[test]
fn parse_empty_chain() {
#[cfg(ossl300)]
let _provider = crate::provider::Provider::try_load(None, "legacy", true).unwrap();
let der = include_bytes!("../test/keystore-empty-chain.p12");
let pkcs12 = Pkcs12::from_der(der).unwrap();
let parsed = pkcs12.parse2("cassandra").unwrap();
if let Some(stack) = parsed.ca {
assert_eq!(stack.len(), 0);
}
}
#[test]
fn create() {
let subject_name = "ns.example.com";
let rsa = Rsa::generate(2048).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
let mut name = X509Name::builder().unwrap();
name.append_entry_by_nid(Nid::COMMONNAME, subject_name)
.unwrap();
let name = name.build();
let key_usage = KeyUsage::new().digital_signature().build().unwrap();
let mut builder = X509::builder().unwrap();
builder.set_version(2).unwrap();
builder
.set_not_before(&Asn1Time::days_from_now(0).unwrap())
.unwrap();
builder
.set_not_after(&Asn1Time::days_from_now(365).unwrap())
.unwrap();
builder.set_subject_name(&name).unwrap();
builder.set_issuer_name(&name).unwrap();
builder.append_extension(key_usage).unwrap();
builder.set_pubkey(&pkey).unwrap();
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
let cert = builder.build();
let pkcs12 = Pkcs12::builder()
.name(subject_name)
.pkey(&pkey)
.cert(&cert)
.build2("mypass")
.unwrap();
let der = pkcs12.to_der().unwrap();
let pkcs12 = Pkcs12::from_der(&der).unwrap();
let parsed = pkcs12.parse2("mypass").unwrap();
assert_eq!(
&*parsed.cert.unwrap().digest(MessageDigest::sha1()).unwrap(),
&*cert.digest(MessageDigest::sha1()).unwrap()
);
assert!(parsed.pkey.unwrap().public_eq(&pkey));
}
#[test]
fn create_only_ca() {
let ca = include_bytes!("../test/root-ca.pem");
let ca = X509::from_pem(ca).unwrap();
let mut chain = Stack::new().unwrap();
chain.push(ca).unwrap();
let pkcs12 = Pkcs12::builder().ca(chain).build2("hunter2").unwrap();
let parsed = pkcs12.parse2("hunter2").unwrap();
assert!(parsed.cert.is_none());
assert!(parsed.pkey.is_none());
assert_eq!(parsed.ca.unwrap().len(), 1);
}
}

310
vendor/openssl/src/pkcs5.rs vendored Normal file
View file

@ -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 as usize);
let salt_ptr = match salt {
Some(salt) => {
assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
salt.as_ptr()
}
None => ptr::null(),
};
ffi::init();
let mut iv = cipher.iv_len().map(|l| vec![0; l]);
let cipher = cipher.as_ptr();
let digest = digest.as_ptr();
let len = cvt(ffi::EVP_BytesToKey(
cipher,
digest,
salt_ptr,
ptr::null(),
data.len() as c_int,
count.into(),
ptr::null_mut(),
ptr::null_mut(),
))?;
let mut key = vec![0; len as usize];
let iv_ptr = iv
.as_mut()
.map(|v| v.as_mut_ptr())
.unwrap_or(ptr::null_mut());
cvt(ffi::EVP_BytesToKey(
cipher,
digest,
salt_ptr,
data.as_ptr(),
data.len() as c_int,
count as c_int,
key.as_mut_ptr(),
iv_ptr,
))?;
Ok(KeyIvPair { key, iv })
}
}
/// Derives a key from a password and salt using the PBKDF2-HMAC algorithm with a digest function.
#[corresponds(PKCS5_PBKDF2_HMAC)]
pub fn pbkdf2_hmac(
pass: &[u8],
salt: &[u8],
iter: usize,
hash: MessageDigest,
key: &mut [u8],
) -> Result<(), ErrorStack> {
unsafe {
ffi::init();
cvt(ffi::PKCS5_PBKDF2_HMAC(
pass.as_ptr() as *const _,
pass.len().try_into().unwrap(),
salt.as_ptr(),
salt.len().try_into().unwrap(),
iter.try_into().unwrap(),
hash.as_ptr(),
key.len().try_into().unwrap(),
key.as_mut_ptr(),
))
.map(|_| ())
}
}
/// Derives a key from a password and salt using the scrypt algorithm.
///
/// Requires OpenSSL 1.1.0 or newer.
#[corresponds(EVP_PBE_scrypt)]
#[cfg(all(any(ossl110, boringssl), not(osslconf = "OPENSSL_NO_SCRYPT")))]
#[allow(clippy::useless_conversion)]
pub fn scrypt(
pass: &[u8],
salt: &[u8],
n: u64,
r: u64,
p: u64,
maxmem: u64,
key: &mut [u8],
) -> Result<(), ErrorStack> {
unsafe {
ffi::init();
cvt(ffi::EVP_PBE_scrypt(
pass.as_ptr() as *const _,
pass.len(),
salt.as_ptr() as *const _,
salt.len(),
n,
r,
p,
maxmem.try_into().unwrap(),
key.as_mut_ptr() as *mut _,
key.len(),
))
.map(|_| ())
}
}
#[cfg(test)]
mod tests {
use crate::hash::MessageDigest;
#[cfg(not(boringssl))]
use crate::symm::Cipher;
// Test vectors from
// https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
#[test]
fn pbkdf2_hmac_sha256() {
let mut buf = [0; 16];
super::pbkdf2_hmac(b"passwd", b"salt", 1, MessageDigest::sha256(), &mut buf).unwrap();
assert_eq!(
buf,
&[
0x55_u8, 0xac_u8, 0x04_u8, 0x6e_u8, 0x56_u8, 0xe3_u8, 0x08_u8, 0x9f_u8, 0xec_u8,
0x16_u8, 0x91_u8, 0xc2_u8, 0x25_u8, 0x44_u8, 0xb6_u8, 0x05_u8,
][..]
);
super::pbkdf2_hmac(
b"Password",
b"NaCl",
80000,
MessageDigest::sha256(),
&mut buf,
)
.unwrap();
assert_eq!(
buf,
&[
0x4d_u8, 0xdc_u8, 0xd8_u8, 0xf6_u8, 0x0b_u8, 0x98_u8, 0xbe_u8, 0x21_u8, 0x83_u8,
0x0c_u8, 0xee_u8, 0x5e_u8, 0xf2_u8, 0x27_u8, 0x01_u8, 0xf9_u8,
][..]
);
}
// Test vectors from
// https://git.lysator.liu.se/nettle/nettle/blob/nettle_3.1.1_release_20150424/testsuite/pbkdf2-test.c
#[test]
fn pbkdf2_hmac_sha512() {
let mut buf = [0; 64];
super::pbkdf2_hmac(b"password", b"NaCL", 1, MessageDigest::sha512(), &mut buf).unwrap();
assert_eq!(
&buf[..],
&[
0x73_u8, 0xde_u8, 0xcf_u8, 0xa5_u8, 0x8a_u8, 0xa2_u8, 0xe8_u8, 0x4f_u8, 0x94_u8,
0x77_u8, 0x1a_u8, 0x75_u8, 0x73_u8, 0x6b_u8, 0xb8_u8, 0x8b_u8, 0xd3_u8, 0xc7_u8,
0xb3_u8, 0x82_u8, 0x70_u8, 0xcf_u8, 0xb5_u8, 0x0c_u8, 0xb3_u8, 0x90_u8, 0xed_u8,
0x78_u8, 0xb3_u8, 0x05_u8, 0x65_u8, 0x6a_u8, 0xf8_u8, 0x14_u8, 0x8e_u8, 0x52_u8,
0x45_u8, 0x2b_u8, 0x22_u8, 0x16_u8, 0xb2_u8, 0xb8_u8, 0x09_u8, 0x8b_u8, 0x76_u8,
0x1f_u8, 0xc6_u8, 0x33_u8, 0x60_u8, 0x60_u8, 0xa0_u8, 0x9f_u8, 0x76_u8, 0x41_u8,
0x5e_u8, 0x9f_u8, 0x71_u8, 0xea_u8, 0x47_u8, 0xf9_u8, 0xe9_u8, 0x06_u8, 0x43_u8,
0x06_u8,
][..]
);
super::pbkdf2_hmac(
b"pass\0word",
b"sa\0lt",
1,
MessageDigest::sha512(),
&mut buf,
)
.unwrap();
assert_eq!(
&buf[..],
&[
0x71_u8, 0xa0_u8, 0xec_u8, 0x84_u8, 0x2a_u8, 0xbd_u8, 0x5c_u8, 0x67_u8, 0x8b_u8,
0xcf_u8, 0xd1_u8, 0x45_u8, 0xf0_u8, 0x9d_u8, 0x83_u8, 0x52_u8, 0x2f_u8, 0x93_u8,
0x36_u8, 0x15_u8, 0x60_u8, 0x56_u8, 0x3c_u8, 0x4d_u8, 0x0d_u8, 0x63_u8, 0xb8_u8,
0x83_u8, 0x29_u8, 0x87_u8, 0x10_u8, 0x90_u8, 0xe7_u8, 0x66_u8, 0x04_u8, 0xa4_u8,
0x9a_u8, 0xf0_u8, 0x8f_u8, 0xe7_u8, 0xc9_u8, 0xf5_u8, 0x71_u8, 0x56_u8, 0xc8_u8,
0x79_u8, 0x09_u8, 0x96_u8, 0xb2_u8, 0x0f_u8, 0x06_u8, 0xbc_u8, 0x53_u8, 0x5e_u8,
0x5a_u8, 0xb5_u8, 0x44_u8, 0x0d_u8, 0xf7_u8, 0xe8_u8, 0x78_u8, 0x29_u8, 0x6f_u8,
0xa7_u8,
][..]
);
super::pbkdf2_hmac(
b"passwordPASSWORDpassword",
b"salt\0\0\0",
50,
MessageDigest::sha512(),
&mut buf,
)
.unwrap();
assert_eq!(
&buf[..],
&[
0x01_u8, 0x68_u8, 0x71_u8, 0xa4_u8, 0xc4_u8, 0xb7_u8, 0x5f_u8, 0x96_u8, 0x85_u8,
0x7f_u8, 0xd2_u8, 0xb9_u8, 0xf8_u8, 0xca_u8, 0x28_u8, 0x02_u8, 0x3b_u8, 0x30_u8,
0xee_u8, 0x2a_u8, 0x39_u8, 0xf5_u8, 0xad_u8, 0xca_u8, 0xc8_u8, 0xc9_u8, 0x37_u8,
0x5f_u8, 0x9b_u8, 0xda_u8, 0x1c_u8, 0xcd_u8, 0x1b_u8, 0x6f_u8, 0x0b_u8, 0x2f_u8,
0xc3_u8, 0xad_u8, 0xda_u8, 0x50_u8, 0x54_u8, 0x12_u8, 0xe7_u8, 0x9d_u8, 0x89_u8,
0x00_u8, 0x56_u8, 0xc6_u8, 0x2e_u8, 0x52_u8, 0x4c_u8, 0x7d_u8, 0x51_u8, 0x15_u8,
0x4b_u8, 0x1a_u8, 0x85_u8, 0x34_u8, 0x57_u8, 0x5b_u8, 0xd0_u8, 0x2d_u8, 0xee_u8,
0x39_u8,
][..]
);
}
#[test]
#[cfg(not(boringssl))]
fn bytes_to_key() {
let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8];
let data = [
143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, 241_u8, 242_u8, 31_u8, 154_u8,
56_u8, 198_u8, 145_u8, 192_u8, 64_u8, 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8,
233_u8, 136_u8, 139_u8, 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8,
];
let expected_key = vec![
249_u8, 115_u8, 114_u8, 97_u8, 32_u8, 213_u8, 165_u8, 146_u8, 58_u8, 87_u8, 234_u8,
3_u8, 43_u8, 250_u8, 97_u8, 114_u8, 26_u8, 98_u8, 245_u8, 246_u8, 238_u8, 177_u8,
229_u8, 161_u8, 183_u8, 224_u8, 174_u8, 3_u8, 6_u8, 244_u8, 236_u8, 255_u8,
];
let expected_iv = vec![
4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8,
107_u8, 208_u8, 14_u8, 236_u8, 60_u8,
];
assert_eq!(
super::bytes_to_key(
Cipher::aes_256_cbc(),
MessageDigest::sha1(),
&data,
Some(&salt),
1,
)
.unwrap(),
super::KeyIvPair {
key: expected_key,
iv: Some(expected_iv),
}
);
}
#[test]
#[cfg(any(ossl110, boringssl))]
fn scrypt() {
let pass = "pleaseletmein";
let salt = "SodiumChloride";
let expected =
"7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613\
f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887";
let mut actual = [0; 64];
super::scrypt(
pass.as_bytes(),
salt.as_bytes(),
16384,
8,
1,
0,
&mut actual,
)
.unwrap();
assert_eq!(hex::encode(&actual[..]), expected);
}
}

573
vendor/openssl/src/pkcs7.rs vendored Normal file
View file

@ -0,0 +1,573 @@
use bitflags::bitflags;
use foreign_types::{ForeignType, ForeignTypeRef};
use libc::c_int;
use std::mem;
use std::ptr;
use crate::asn1::Asn1ObjectRef;
use crate::bio::{MemBio, MemBioSlice};
use crate::error::ErrorStack;
use crate::nid::Nid;
use crate::pkey::{HasPrivate, PKeyRef};
use crate::stack::{Stack, StackRef, Stackable};
use crate::symm::Cipher;
use crate::util::ForeignTypeRefExt;
use crate::x509::store::X509StoreRef;
use crate::x509::{X509Ref, X509};
use crate::{cvt, cvt_p};
use openssl_macros::corresponds;
foreign_type_and_impl_send_sync! {
type CType = ffi::PKCS7_SIGNER_INFO;
fn drop = ffi::PKCS7_SIGNER_INFO_free;
pub struct Pkcs7SignerInfo;
pub struct Pkcs7SignerInfoRef;
}
impl Stackable for Pkcs7SignerInfo {
type StackType = ffi::stack_st_PKCS7_SIGNER_INFO;
}
foreign_type_and_impl_send_sync! {
type CType = ffi::PKCS7;
fn drop = ffi::PKCS7_free;
/// A PKCS#7 structure.
///
/// Contains signed and/or encrypted data.
pub struct Pkcs7;
/// Reference to `Pkcs7`
pub struct Pkcs7Ref;
}
foreign_type_and_impl_send_sync! {
type CType = ffi::PKCS7_SIGNED;
fn drop = ffi::PKCS7_SIGNED_free;
/// A PKCS#7 signed data structure.
///
/// Contains signed data.
pub struct Pkcs7Signed;
/// Reference to `Pkcs7Signed`
pub struct Pkcs7SignedRef;
}
bitflags! {
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct Pkcs7Flags: c_int {
const TEXT = ffi::PKCS7_TEXT;
const NOCERTS = ffi::PKCS7_NOCERTS;
const NOSIGS = ffi::PKCS7_NOSIGS;
const NOCHAIN = ffi::PKCS7_NOCHAIN;
const NOINTERN = ffi::PKCS7_NOINTERN;
const NOVERIFY = ffi::PKCS7_NOVERIFY;
const DETACHED = ffi::PKCS7_DETACHED;
const BINARY = ffi::PKCS7_BINARY;
const NOATTR = ffi::PKCS7_NOATTR;
const NOSMIMECAP = ffi::PKCS7_NOSMIMECAP;
const NOOLDMIMETYPE = ffi::PKCS7_NOOLDMIMETYPE;
const CRLFEOL = ffi::PKCS7_CRLFEOL;
const STREAM = ffi::PKCS7_STREAM;
const NOCRL = ffi::PKCS7_NOCRL;
const PARTIAL = ffi::PKCS7_PARTIAL;
const REUSE_DIGEST = ffi::PKCS7_REUSE_DIGEST;
#[cfg(not(any(ossl101, ossl102, libressl)))]
const NO_DUAL_CONTENT = ffi::PKCS7_NO_DUAL_CONTENT;
}
}
impl Pkcs7 {
from_pem! {
/// Deserializes a PEM-encoded PKCS#7 signature
///
/// The input should have a header of `-----BEGIN PKCS7-----`.
#[corresponds(PEM_read_bio_PKCS7)]
from_pem,
Pkcs7,
ffi::PEM_read_bio_PKCS7
}
from_der! {
/// Deserializes a DER-encoded PKCS#7 signature
#[corresponds(d2i_PKCS7)]
from_der,
Pkcs7,
ffi::d2i_PKCS7
}
/// Parses a message in S/MIME format.
///
/// Returns the loaded signature, along with the cleartext message (if
/// available).
#[corresponds(SMIME_read_PKCS7)]
pub fn from_smime(input: &[u8]) -> Result<(Pkcs7, Option<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)
}
}
/// Return the type of a PKCS#7 structure as an Asn1Object
pub fn type_(&self) -> Option<&Asn1ObjectRef> {
unsafe {
let ptr = (*self.as_ptr()).type_;
Asn1ObjectRef::from_const_ptr_opt(ptr)
}
}
/// Get the signed data of a PKCS#7 structure of type PKCS7_SIGNED
pub fn signed(&self) -> Option<&Pkcs7SignedRef> {
unsafe {
if self.type_().map(|x| x.nid()) != Some(Nid::PKCS7_SIGNED) {
return None;
}
let signed_data = (*self.as_ptr()).d.sign;
Pkcs7SignedRef::from_const_ptr_opt(signed_data)
}
}
}
impl Pkcs7SignedRef {
/// Get the stack of certificates from the PKCS7_SIGNED object
pub fn certificates(&self) -> Option<&StackRef<X509>> {
unsafe {
self.as_ptr()
.as_ref()
.and_then(|x| x.cert.as_mut())
.and_then(|x| StackRef::<X509>::from_const_ptr_opt(x))
}
}
}
#[cfg(test)]
mod tests {
use crate::hash::MessageDigest;
use crate::nid::Nid;
use crate::pkcs7::{Pkcs7, Pkcs7Flags};
use crate::pkey::PKey;
use crate::stack::Stack;
use crate::symm::Cipher;
use crate::x509::store::X509StoreBuilder;
use crate::x509::X509;
#[test]
fn encrypt_decrypt_test() {
let cert = include_bytes!("../test/certs.pem");
let cert = X509::from_pem(cert).unwrap();
let mut certs = Stack::new().unwrap();
certs.push(cert.clone()).unwrap();
let message: String = String::from("foo");
let cipher = Cipher::des_ede3_cbc();
let flags = Pkcs7Flags::STREAM;
let pkey = include_bytes!("../test/key.pem");
let pkey = PKey::private_key_from_pem(pkey).unwrap();
let pkcs7 =
Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_ENVELOPED
);
let encrypted = pkcs7
.to_smime(message.as_bytes(), flags)
.expect("should succeed");
let (pkcs7_decoded, _) = Pkcs7::from_smime(encrypted.as_slice()).expect("should succeed");
let decoded = pkcs7_decoded
.decrypt(&pkey, &cert, Pkcs7Flags::empty())
.expect("should succeed");
assert_eq!(decoded, message.into_bytes());
}
#[test]
fn sign_verify_test_detached() {
let cert = include_bytes!("../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let certs = Stack::new().unwrap();
let message = "foo";
let flags = Pkcs7Flags::STREAM | Pkcs7Flags::DETACHED;
let pkey = include_bytes!("../test/key.pem");
let pkey = PKey::private_key_from_pem(pkey).unwrap();
let mut store_builder = X509StoreBuilder::new().expect("should succeed");
let root_ca = include_bytes!("../test/root-ca.pem");
let root_ca = X509::from_pem(root_ca).unwrap();
store_builder.add_cert(root_ca).expect("should succeed");
let store = store_builder.build();
let pkcs7 =
Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_SIGNED
);
let signed = pkcs7
.to_smime(message.as_bytes(), flags)
.expect("should succeed");
println!("{:?}", String::from_utf8(signed.clone()).unwrap());
let (pkcs7_decoded, content) =
Pkcs7::from_smime(signed.as_slice()).expect("should succeed");
let mut output = Vec::new();
pkcs7_decoded
.verify(
&certs,
&store,
Some(message.as_bytes()),
Some(&mut output),
flags,
)
.expect("should succeed");
assert_eq!(output, message.as_bytes());
assert_eq!(content.expect("should be non-empty"), message.as_bytes());
}
/// https://marc.info/?l=openbsd-cvs&m=166602943014106&w=2
#[test]
#[cfg_attr(all(libressl360, not(libressl361)), ignore)]
fn sign_verify_test_normal() {
let cert = include_bytes!("../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let certs = Stack::new().unwrap();
let message = "foo";
let flags = Pkcs7Flags::STREAM;
let pkey = include_bytes!("../test/key.pem");
let pkey = PKey::private_key_from_pem(pkey).unwrap();
let mut store_builder = X509StoreBuilder::new().expect("should succeed");
let root_ca = include_bytes!("../test/root-ca.pem");
let root_ca = X509::from_pem(root_ca).unwrap();
store_builder.add_cert(root_ca).expect("should succeed");
let store = store_builder.build();
let pkcs7 =
Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_SIGNED
);
let signed = pkcs7
.to_smime(message.as_bytes(), flags)
.expect("should succeed");
let (pkcs7_decoded, content) =
Pkcs7::from_smime(signed.as_slice()).expect("should succeed");
let mut output = Vec::new();
pkcs7_decoded
.verify(&certs, &store, None, Some(&mut output), flags)
.expect("should succeed");
assert_eq!(output, message.as_bytes());
assert!(content.is_none());
}
/// https://marc.info/?l=openbsd-cvs&m=166602943014106&w=2
#[test]
#[cfg_attr(all(libressl360, not(libressl361)), ignore)]
fn signers() {
let cert = include_bytes!("../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let cert_digest = cert.digest(MessageDigest::sha256()).unwrap();
let certs = Stack::new().unwrap();
let message = "foo";
let flags = Pkcs7Flags::STREAM;
let pkey = include_bytes!("../test/key.pem");
let pkey = PKey::private_key_from_pem(pkey).unwrap();
let mut store_builder = X509StoreBuilder::new().expect("should succeed");
let root_ca = include_bytes!("../test/root-ca.pem");
let root_ca = X509::from_pem(root_ca).unwrap();
store_builder.add_cert(root_ca).expect("should succeed");
let pkcs7 =
Pkcs7::sign(&cert, &pkey, &certs, message.as_bytes(), flags).expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_SIGNED
);
let signed = pkcs7
.to_smime(message.as_bytes(), flags)
.expect("should succeed");
let (pkcs7_decoded, _) = Pkcs7::from_smime(signed.as_slice()).expect("should succeed");
let empty_certs = Stack::new().unwrap();
let signer_certs = pkcs7_decoded
.signers(&empty_certs, flags)
.expect("should succeed");
assert_eq!(empty_certs.len(), 0);
assert_eq!(signer_certs.len(), 1);
let signer_digest = signer_certs[0].digest(MessageDigest::sha256()).unwrap();
assert_eq!(*cert_digest, *signer_digest);
}
#[test]
fn invalid_from_smime() {
let input = String::from("Invalid SMIME Message");
let result = Pkcs7::from_smime(input.as_bytes());
assert!(result.is_err());
}
#[test]
fn signed_data_certificates() {
let cert = include_bytes!("../test/cert.pem");
let cert = X509::from_pem(cert).unwrap();
let mut extra_certs = Stack::<X509>::new().unwrap();
for cert in
X509::stack_from_pem(include_bytes!("../test/certs.pem")).expect("should succeed")
{
extra_certs.push(cert).expect("should succeed");
}
let message = "foo";
let flags = Pkcs7Flags::STREAM;
let pkey = include_bytes!("../test/key.pem");
let pkey = PKey::private_key_from_pem(pkey).unwrap();
let pkcs7 = Pkcs7::sign(&cert, &pkey, &extra_certs, message.as_bytes(), flags)
.expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_SIGNED
);
let signed_data_certs = pkcs7.signed().and_then(|x| x.certificates());
assert_eq!(signed_data_certs.expect("should succeed").len(), 3);
}
#[test]
fn signed_data_certificates_no_signed_data() {
let cert = include_bytes!("../test/certs.pem");
let cert = X509::from_pem(cert).unwrap();
let mut certs = Stack::new().unwrap();
certs.push(cert).unwrap();
let message: String = String::from("foo");
let cipher = Cipher::des_ede3_cbc();
let flags = Pkcs7Flags::STREAM;
// Use `Pkcs7::encrypt` since it populates the PKCS7_ENVELOPE struct rather than
// PKCS7_SIGNED
let pkcs7 =
Pkcs7::encrypt(&certs, message.as_bytes(), cipher, flags).expect("should succeed");
assert_eq!(
pkcs7.type_().expect("PKCS7 should have a type").nid(),
Nid::PKCS7_ENVELOPED
);
let signed_data_certs = pkcs7.signed().and_then(|x| x.certificates());
assert!(signed_data_certs.is_none())
}
}

1202
vendor/openssl/src/pkey.rs vendored Normal file

File diff suppressed because it is too large Load diff

1110
vendor/openssl/src/pkey_ctx.rs vendored Normal file

File diff suppressed because it is too large Load diff

81
vendor/openssl/src/provider.rs vendored Normal file
View file

@ -0,0 +1,81 @@
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 _,
))?;
// OSSL_PROVIDER_try_load seems to leave errors on the stack, even
// when it succeeds.
let _ = ErrorStack::get();
Ok(Provider::from_ptr(p))
}
}
/// Specifies the default search path that is to be used for looking for providers in the specified library context.
/// If left unspecified, an environment variable and a fall back default value will be used instead
///
/// If `ctx` is `None`, the provider will be loaded into the default library context.
#[corresponds(OSSL_PROVIDER_set_default_search_path)]
pub fn set_default_search_path(ctx: Option<&LibCtxRef>, path: &str) -> Result<(), ErrorStack> {
let path = CString::new(path).unwrap();
unsafe {
cvt(ffi::OSSL_PROVIDER_set_default_search_path(
ctx.map_or(ptr::null_mut(), ForeignTypeRef::as_ptr),
path.as_ptr(),
))
.map(|_| ())
}
}
}

90
vendor/openssl/src/rand.rs vendored Normal file
View file

@ -0,0 +1,90 @@
//! 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 as usize);
cvt(ffi::RAND_bytes(buf.as_mut_ptr(), buf.len() as LenType)).map(|_| ())
}
}
/// Fill buffer with cryptographically strong pseudo-random bytes. It is
/// intended to be used for generating values that should remain private.
///
/// # Examples
///
/// To generate a buffer with cryptographically strong random bytes:
///
/// ```
/// use openssl::rand::rand_priv_bytes;
///
/// let mut buf = [0; 256];
/// rand_priv_bytes(&mut buf).unwrap();
/// ```
///
/// Requires OpenSSL 1.1.1 or newer.
#[corresponds(RAND_priv_bytes)]
#[cfg(ossl111)]
pub fn rand_priv_bytes(buf: &mut [u8]) -> Result<(), ErrorStack> {
unsafe {
ffi::init();
assert!(buf.len() <= c_int::MAX as usize);
cvt(ffi::RAND_priv_bytes(buf.as_mut_ptr(), buf.len() as LenType)).map(|_| ())
}
}
/// Controls random device file descriptor behavior.
///
/// Requires OpenSSL 1.1.1 or newer.
#[corresponds(RAND_keep_random_devices_open)]
#[cfg(ossl111)]
pub fn keep_random_devices_open(keep: bool) {
unsafe {
ffi::RAND_keep_random_devices_open(keep as LenType);
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_rand_bytes() {
let mut buf = [0; 32];
super::rand_bytes(&mut buf).unwrap();
}
#[test]
#[cfg(ossl111)]
fn test_rand_priv_bytes() {
let mut buf = [0; 32];
super::rand_priv_bytes(&mut buf).unwrap();
}
}

873
vendor/openssl/src/rsa.rs vendored Normal file
View file

@ -0,0 +1,873 @@
//! RivestShamirAdleman 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 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 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)]
pub fn check_key(&self) -> Result<bool, ErrorStack> {
unsafe {
let result = ffi::RSA_check_key(self.as_ptr());
if result != 1 {
let errors = ErrorStack::get();
if errors.errors().is_empty() {
Ok(false)
} else {
Err(errors)
}
} else {
Ok(true)
}
}
}
}
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 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 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();
}
#[test]
fn test_check_key() {
let k = Rsa::private_key_from_pem_passphrase(
include_bytes!("../test/rsa-encrypted.pem"),
b"mypass",
)
.unwrap();
assert!(matches!(k.check_key(), Ok(true)));
assert!(ErrorStack::get().errors().is_empty());
// BoringSSL simply rejects this key, because its corrupted!
if let Ok(k) = Rsa::private_key_from_pem(include_bytes!("../test/corrupted-rsa.pem")) {
assert!(matches!(k.check_key(), Ok(false) | Err(_)));
assert!(ErrorStack::get().errors().is_empty());
}
}
}

463
vendor/openssl/src/sha.rs vendored Normal file
View file

@ -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);
}
}

834
vendor/openssl/src/sign.rs vendored Normal file
View file

@ -0,0 +1,834 @@
//! 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};
use openssl_macros::corresponds;
cfg_if! {
if #[cfg(any(ossl110, libressl382))] {
use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
} else {
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
}
}
/// Salt lengths that must be used with `set_rsa_pss_saltlen`.
pub struct RsaPssSaltlen(c_int);
impl RsaPssSaltlen {
/// Returns the integer representation of `RsaPssSaltlen`.
pub(crate) fn as_raw(&self) -> c_int {
self.0
}
/// Sets the salt length to the given value.
pub fn custom(val: c_int) -> RsaPssSaltlen {
RsaPssSaltlen(val)
}
/// The salt length is set to the digest length.
/// Corresponds to the special value `-1`.
pub const DIGEST_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-1);
/// The salt length is set to the maximum permissible value.
/// Corresponds to the special value `-2`.
pub const MAXIMUM_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-2);
}
/// A type which computes cryptographic signatures of data.
pub struct Signer<'a> {
md_ctx: *mut ffi::EVP_MD_CTX,
pctx: *mut ffi::EVP_PKEY_CTX,
_p: PhantomData<&'a ()>,
}
unsafe impl Sync for Signer<'_> {}
unsafe impl Send for Signer<'_> {}
impl Drop for Signer<'_> {
fn drop(&mut self) {
// pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
unsafe {
EVP_MD_CTX_free(self.md_ctx);
}
}
}
#[allow(clippy::len_without_is_empty)]
impl Signer<'_> {
/// Creates a new `Signer`.
///
/// This cannot be used with Ed25519 or Ed448 keys. Please refer to
/// `new_without_digest`.
#[corresponds(EVP_DigestSignInit)]
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.
#[corresponds(EVP_DigestSignInit)]
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.
#[corresponds(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.
#[corresponds(EVP_PKEY_CTX_set_rsa_padding)]
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.
#[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)]
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.
#[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)]
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.
#[corresponds(EVP_DigestUpdate)]
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.
#[corresponds(EVP_DigestSignFinal)]
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.
#[corresponds(EVP_DigestSignFinal)]
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.
#[corresponds(EVP_DigestSign)]
#[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 Write for Signer<'_> {
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 Sync for Verifier<'_> {}
unsafe impl Send for Verifier<'_> {}
impl Drop for Verifier<'_> {
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`].
#[corresponds(EVP_DigestVerifyInit)]
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.
#[corresponds(EVP_DigestVerifyInit)]
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.
#[corresponds(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.
#[corresponds(EVP_PKEY_CTX_set_rsa_padding)]
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.
#[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)]
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.
#[corresponds(EVP_PKEY_CTX_set_rsa_mgf1_md)]
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.
#[corresponds(EVP_DigestUpdate)]
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.
#[corresponds(EVP_DigestVerifyFinal)]
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.
#[corresponds(EVP_DigestVerify)]
#[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 Write for Verifier<'_> {
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());
}
}

66
vendor/openssl/src/srtp.rs vendored Normal file
View file

@ -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
}
}

289
vendor/openssl/src/ssl/bio.rs vendored Normal file
View file

@ -0,0 +1,289 @@
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 crate::error::ErrorStack;
use crate::{cvt_p, util};
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 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 = util::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 = util::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;
}
}
}

707
vendor/openssl/src/ssl/callbacks.rs vendored Normal file
View file

@ -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;
#[cfg(any(ossl111, boringssl))]
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};
use crate::util;
#[cfg(any(ossl111, boringssl))]
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 = util::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize);
#[allow(clippy::unnecessary_cast)]
let psk_sl = util::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 = util::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 = util::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 = util::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(any(ossl111, boringssl))]
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 = util::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 = util::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 =
util::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 =
util::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 = util::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
}
}
}

605
vendor/openssl/src/ssl/connector.rs vendored Normal file
View file

@ -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.
}
}
}
}

185
vendor/openssl/src/ssl/error.rs vendored Normal file
View file

@ -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)
}
}

4345
vendor/openssl/src/ssl/mod.rs vendored Normal file

File diff suppressed because it is too large Load diff

1687
vendor/openssl/src/ssl/test/mod.rs vendored Normal file

File diff suppressed because it is too large Load diff

167
vendor/openssl/src/ssl/test/server.rs vendored Normal file
View file

@ -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();
}
}

380
vendor/openssl/src/stack.rs vendored Normal file
View file

@ -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(any(ossl110, boringssl))] {
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<T: Stackable> ExactSizeIterator for Iter<'_, 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<T: Stackable> ExactSizeIterator for IterMut<'_, T> {}

96
vendor/openssl/src/string.rs vendored Normal file
View file

@ -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,
);
}

1763
vendor/openssl/src/symm.rs vendored Normal file

File diff suppressed because it is too large Load diff

118
vendor/openssl/src/util.rs vendored Normal file
View file

@ -0,0 +1,118 @@
use crate::error::ErrorStack;
use crate::util;
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 = util::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 {}
/// The same as `slice::from_raw_parts`, except that `data` may be `NULL` if
/// `len` is 0.
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
if len == 0 {
&[]
} else {
// Using this to implement the preferred API
#[allow(clippy::disallowed_methods)]
slice::from_raw_parts(data, len)
}
}
/// The same as `slice::from_raw_parts_mut`, except that `data` may be `NULL`
/// if `len` is 0.
pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
if len == 0 {
&mut []
} else {
// Using this to implement the preferred API
#[allow(clippy::disallowed_methods)]
slice::from_raw_parts_mut(data, len)
}
}

134
vendor/openssl/src/version.rs vendored Normal file
View file

@ -0,0 +1,134 @@
// 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:"));
}
}

562
vendor/openssl/src/x509/extension.rs vendored Normal file
View file

@ -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);
}

2546
vendor/openssl/src/x509/mod.rs vendored Normal file

File diff suppressed because it is too large Load diff

304
vendor/openssl/src/x509/store.rs vendored Normal file
View file

@ -0,0 +1,304 @@
//! Describe a context in which to verify an `X509` certificate.
//!
//! The `X509` certificate store holds trusted CA certificates used to verify
//! peer certificates.
//!
//! # Example
//!
//! ```rust
//! use openssl::x509::store::{X509StoreBuilder, X509Store};
//! use openssl::x509::{X509, X509Name};
//! use openssl::asn1::Asn1Time;
//! use openssl::pkey::PKey;
//! use openssl::hash::MessageDigest;
//! use openssl::rsa::Rsa;
//! use openssl::nid::Nid;
//!
//! let rsa = Rsa::generate(2048).unwrap();
//! let pkey = PKey::from_rsa(rsa).unwrap();
//!
//! let mut name = X509Name::builder().unwrap();
//! name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap();
//! let name = name.build();
//!
//! // Sep 27th, 2016
//! let sample_time = Asn1Time::from_unix(1474934400).unwrap();
//!
//! let mut builder = X509::builder().unwrap();
//! builder.set_version(2).unwrap();
//! builder.set_subject_name(&name).unwrap();
//! builder.set_issuer_name(&name).unwrap();
//! builder.set_pubkey(&pkey).unwrap();
//! builder.set_not_before(&sample_time);
//! builder.set_not_after(&sample_time);
//! builder.sign(&pkey, MessageDigest::sha256()).unwrap();
//!
//! let certificate: X509 = builder.build();
//!
//! let mut builder = X509StoreBuilder::new().unwrap();
//! let _ = builder.add_cert(certificate);
//!
//! let store: X509Store = builder.build();
//! ```
use cfg_if::cfg_if;
use foreign_types::{ForeignType, ForeignTypeRef};
use std::mem;
use crate::error::ErrorStack;
#[cfg(not(boringssl))]
use crate::ssl::SslFiletype;
#[cfg(ossl300)]
use crate::stack::Stack;
use crate::stack::StackRef;
use crate::util::ForeignTypeRefExt;
#[cfg(any(ossl102, boringssl, libressl261))]
use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef};
use crate::x509::{X509Object, X509PurposeId, X509};
use crate::{cvt, cvt_p};
use openssl_macros::corresponds;
#[cfg(not(boringssl))]
use std::ffi::CString;
#[cfg(not(boringssl))]
use std::path::Path;
foreign_type_and_impl_send_sync! {
type CType = ffi::X509_STORE;
fn drop = ffi::X509_STORE_free;
/// A builder type used to construct an `X509Store`.
pub struct X509StoreBuilder;
/// A reference to an [`X509StoreBuilder`].
pub struct X509StoreBuilderRef;
}
impl X509StoreBuilder {
/// Returns a builder for a certificate store.
///
/// The store is initially empty.
#[corresponds(X509_STORE_new)]
pub fn new() -> Result<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, boringssl, libressl261))]
pub fn set_flags(&mut self, flags: X509VerifyFlags) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::X509_STORE_set_flags(self.as_ptr(), flags.bits())).map(|_| ()) }
}
/// Sets the certificate purpose.
/// The purpose value can be obtained by `X509PurposeRef::get_by_sname()`
#[corresponds(X509_STORE_set_purpose)]
pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::X509_STORE_set_purpose(self.as_ptr(), purpose.as_raw())).map(|_| ()) }
}
/// Sets certificate chain validation related parameters.
#[corresponds[X509_STORE_set1_param]]
#[cfg(any(ossl102, boringssl, libressl261))]
pub fn set_param(&mut self, param: &X509VerifyParamRef) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::X509_STORE_set1_param(self.as_ptr(), param.as_ptr())).map(|_| ()) }
}
}
generic_foreign_type_and_impl_send_sync! {
type CType = ffi::X509_LOOKUP;
fn drop = ffi::X509_LOOKUP_free;
/// Information used by an `X509Store` to look up certificates and CRLs.
pub struct X509Lookup<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_const_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_const_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.
///
/// This method is deprecated. It is **unsound** and will be removed in a
/// future version of rust-openssl. `X509StoreRef::all_certificates`
/// should be used instead.
#[deprecated(
note = "This method is unsound, and will be removed in a future version of rust-openssl. X509StoreRef::all_certificates should be used instead."
)]
#[corresponds(X509_STORE_get0_objects)]
pub fn objects(&self) -> &StackRef<X509Object> {
unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) }
}
/// Returns a stack of all the certificates in this store.
#[corresponds(X509_STORE_get1_all_certs)]
#[cfg(ossl300)]
pub fn all_certificates(&self) -> Stack<X509> {
unsafe { Stack::from_ptr(ffi::X509_STORE_get1_all_certs(self.as_ptr())) }
}
}
cfg_if! {
if #[cfg(any(boringssl, ossl110, libressl270))] {
use ffi::X509_STORE_get0_objects;
} else {
#[allow(bad_style)]
unsafe fn X509_STORE_get0_objects(x: *mut ffi::X509_STORE) -> *mut ffi::stack_st_X509_OBJECT {
(*x).objs
}
}
}
cfg_if! {
if #[cfg(ossl110)] {
use ffi::X509_LOOKUP_meth_free;
} else {
#[allow(bad_style)]
unsafe fn X509_LOOKUP_meth_free(_x: *mut ffi::X509_LOOKUP_METHOD) {}
}
}

1194
vendor/openssl/src/x509/tests.rs vendored Normal file

File diff suppressed because it is too large Load diff

215
vendor/openssl/src/x509/verify.rs vendored Normal file
View file

@ -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(any(ossl102, boringssl))]
use crate::x509::X509PurposeId;
use crate::{cvt, cvt_p};
use openssl_macros::corresponds;
bitflags! {
/// Flags used to check an `X509` certificate.
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct X509CheckFlags: c_uint {
const ALWAYS_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT as _;
const NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS as _;
const NO_PARTIAL_WILDCARDS = ffi::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS as _;
const MULTI_LABEL_WILDCARDS = ffi::X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS as _;
const SINGLE_LABEL_SUBDOMAINS = ffi::X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS as _;
/// Requires OpenSSL 1.1.0 or newer.
#[cfg(any(ossl110))]
const NEVER_CHECK_SUBJECT = ffi::X509_CHECK_FLAG_NEVER_CHECK_SUBJECT;
#[deprecated(since = "0.10.6", note = "renamed to NO_WILDCARDS")]
const FLAG_NO_WILDCARDS = ffi::X509_CHECK_FLAG_NO_WILDCARDS as _;
}
}
bitflags! {
/// Flags used to verify an `X509` certificate chain.
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct X509VerifyFlags: c_ulong {
const CB_ISSUER_CHECK = ffi::X509_V_FLAG_CB_ISSUER_CHECK as _;
const USE_CHECK_TIME = ffi::X509_V_FLAG_USE_CHECK_TIME as _;
const CRL_CHECK = ffi::X509_V_FLAG_CRL_CHECK as _;
const CRL_CHECK_ALL = ffi::X509_V_FLAG_CRL_CHECK_ALL as _;
const IGNORE_CRITICAL = ffi::X509_V_FLAG_IGNORE_CRITICAL as _;
const X509_STRICT = ffi::X509_V_FLAG_X509_STRICT as _;
const ALLOW_PROXY_CERTS = ffi::X509_V_FLAG_ALLOW_PROXY_CERTS as _;
const POLICY_CHECK = ffi::X509_V_FLAG_POLICY_CHECK as _;
const EXPLICIT_POLICY = ffi::X509_V_FLAG_EXPLICIT_POLICY as _;
const INHIBIT_ANY = ffi::X509_V_FLAG_INHIBIT_ANY as _;
const INHIBIT_MAP = ffi::X509_V_FLAG_INHIBIT_MAP as _;
const NOTIFY_POLICY = ffi::X509_V_FLAG_NOTIFY_POLICY as _;
const EXTENDED_CRL_SUPPORT = ffi::X509_V_FLAG_EXTENDED_CRL_SUPPORT as _;
const USE_DELTAS = ffi::X509_V_FLAG_USE_DELTAS as _;
const CHECK_SS_SIGNATURE = ffi::X509_V_FLAG_CHECK_SS_SIGNATURE as _;
#[cfg(any(ossl102, boringssl))]
const TRUSTED_FIRST = ffi::X509_V_FLAG_TRUSTED_FIRST as _;
#[cfg(ossl102)]
const SUITEB_128_LOS_ONLY = ffi::X509_V_FLAG_SUITEB_128_LOS_ONLY;
#[cfg(ossl102)]
const SUITEB_192_LOS = ffi::X509_V_FLAG_SUITEB_128_LOS;
#[cfg(ossl102)]
const SUITEB_128_LOS = ffi::X509_V_FLAG_SUITEB_192_LOS;
#[cfg(any(ossl102, boringssl))]
const PARTIAL_CHAIN = ffi::X509_V_FLAG_PARTIAL_CHAIN as _;
#[cfg(any(ossl110, boringssl))]
const NO_ALT_CHAINS = ffi::X509_V_FLAG_NO_ALT_CHAINS as _;
#[cfg(any(ossl110, boringssl))]
const NO_CHECK_TIME = ffi::X509_V_FLAG_NO_CHECK_TIME as _;
}
}
foreign_type_and_impl_send_sync! {
type CType = ffi::X509_VERIFY_PARAM;
fn drop = ffi::X509_VERIFY_PARAM_free;
/// Adjust parameters associated with certificate verification.
pub struct X509VerifyParam;
/// Reference to `X509VerifyParam`.
pub struct X509VerifyParamRef;
}
impl X509VerifyParam {
/// Create an X509VerifyParam
#[corresponds(X509_VERIFY_PARAM_new)]
pub fn new() -> Result<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(any(ossl102, boringssl))]
pub fn set_purpose(&mut self, purpose: X509PurposeId) -> Result<(), ErrorStack> {
unsafe { cvt(ffi::X509_VERIFY_PARAM_set_purpose(self.as_ptr(), purpose.0)).map(|_| ()) }
}
}