Merge branch 'master' into custom-extensions
This commit is contained in:
commit
d0329473bd
|
|
@ -92,7 +92,7 @@ macos_job: &MACOS_JOB
|
||||||
|
|
||||||
openssl_111: &OPENSSL_111
|
openssl_111: &OPENSSL_111
|
||||||
LIBRARY: openssl
|
LIBRARY: openssl
|
||||||
VERSION: 1.1.1-pre1
|
VERSION: 1.1.1-pre2
|
||||||
openssl_110: &OPENSSL_110
|
openssl_110: &OPENSSL_110
|
||||||
LIBRARY: openssl
|
LIBRARY: openssl
|
||||||
VERSION: 1.1.0g
|
VERSION: 1.1.0g
|
||||||
|
|
|
||||||
|
|
@ -228,9 +228,24 @@ pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey;
|
||||||
pub const EVP_PKEY_ALG_CTRL: c_int = 0x1000;
|
pub const EVP_PKEY_ALG_CTRL: c_int = 0x1000;
|
||||||
|
|
||||||
pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1;
|
pub const EVP_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1;
|
||||||
|
pub const EVP_PKEY_CTRL_RSA_PSS_SALTLEN: c_int = EVP_PKEY_ALG_CTRL + 2;
|
||||||
|
|
||||||
|
pub const EVP_PKEY_CTRL_RSA_MGF1_MD: c_int = EVP_PKEY_ALG_CTRL + 5;
|
||||||
pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6;
|
pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6;
|
||||||
|
|
||||||
|
pub const EVP_PKEY_OP_SIGN: c_int = 1 << 3;
|
||||||
|
pub const EVP_PKEY_OP_VERIFY: c_int = 1 << 4;
|
||||||
|
pub const EVP_PKEY_OP_VERIFYRECOVER: c_int = 1 << 5;
|
||||||
|
pub const EVP_PKEY_OP_SIGNCTX: c_int = 1 << 6;
|
||||||
|
pub const EVP_PKEY_OP_VERIFYCTX: c_int = 1 << 7;
|
||||||
|
pub const EVP_PKEY_OP_ENCRYPT: c_int = 1 << 8;
|
||||||
|
pub const EVP_PKEY_OP_DECRYPT: c_int = 1 << 9;
|
||||||
|
|
||||||
|
pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY
|
||||||
|
| EVP_PKEY_OP_VERIFYRECOVER | EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX;
|
||||||
|
|
||||||
|
pub const EVP_PKEY_OP_TYPE_CRYPT: c_int = EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT;
|
||||||
|
|
||||||
pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9;
|
pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9;
|
||||||
pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10;
|
pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10;
|
||||||
pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11;
|
pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11;
|
||||||
|
|
@ -1200,6 +1215,7 @@ pub const RSA_SSLV23_PADDING: c_int = 2;
|
||||||
pub const RSA_NO_PADDING: c_int = 3;
|
pub const RSA_NO_PADDING: c_int = 3;
|
||||||
pub const RSA_PKCS1_OAEP_PADDING: c_int = 4;
|
pub const RSA_PKCS1_OAEP_PADDING: c_int = 4;
|
||||||
pub const RSA_X931_PADDING: c_int = 5;
|
pub const RSA_X931_PADDING: c_int = 5;
|
||||||
|
pub const RSA_PKCS1_PSS_PADDING: c_int = 6;
|
||||||
|
|
||||||
pub const SHA_LBLOCK: c_int = 16;
|
pub const SHA_LBLOCK: c_int = 16;
|
||||||
|
|
||||||
|
|
@ -1483,6 +1499,28 @@ pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx: *mut EVP_PKEY_CTX, len: c_int) -> c_int {
|
||||||
|
EVP_PKEY_CTX_ctrl(
|
||||||
|
ctx,
|
||||||
|
EVP_PKEY_RSA,
|
||||||
|
EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY,
|
||||||
|
EVP_PKEY_CTRL_RSA_PSS_SALTLEN,
|
||||||
|
len,
|
||||||
|
ptr::null_mut(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn EVP_PKEY_CTX_set_rsa_mgf1_md(ctx: *mut EVP_PKEY_CTX, md: *mut EVP_MD) -> c_int {
|
||||||
|
EVP_PKEY_CTX_ctrl(
|
||||||
|
ctx,
|
||||||
|
EVP_PKEY_RSA,
|
||||||
|
EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT,
|
||||||
|
EVP_PKEY_CTRL_RSA_MGF1_MD,
|
||||||
|
0,
|
||||||
|
md as *mut c_void,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long {
|
pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long {
|
||||||
SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut())
|
SSL_CTX_ctrl(ctx, SSL_CTRL_MODE, op, ptr::null_mut())
|
||||||
}
|
}
|
||||||
|
|
@ -1882,6 +1920,12 @@ extern "C" {
|
||||||
ctx: *mut BN_CTX,
|
ctx: *mut BN_CTX,
|
||||||
) -> c_int;
|
) -> c_int;
|
||||||
|
|
||||||
|
pub fn ECDSA_SIG_new() -> *mut ECDSA_SIG;
|
||||||
|
pub fn ECDSA_SIG_free(sig: *mut ECDSA_SIG);
|
||||||
|
pub fn ECDSA_do_verify(dgst: *const c_uchar, dgst_len: c_int,
|
||||||
|
sig: *const ECDSA_SIG, eckey: *mut EC_KEY) -> c_int;
|
||||||
|
pub fn ECDSA_do_sign(dgst: *const c_uchar, dgst_len: c_int, eckey: *mut EC_KEY) -> *mut ECDSA_SIG;
|
||||||
|
|
||||||
pub fn ERR_peek_last_error() -> c_ulong;
|
pub fn ERR_peek_last_error() -> c_ulong;
|
||||||
pub fn ERR_get_error() -> c_ulong;
|
pub fn ERR_get_error() -> c_ulong;
|
||||||
pub fn ERR_get_error_line_data(
|
pub fn ERR_get_error_line_data(
|
||||||
|
|
@ -2029,6 +2073,7 @@ extern "C" {
|
||||||
pub fn EVP_PKEY_get1_DH(k: *mut EVP_PKEY) -> *mut DH;
|
pub fn EVP_PKEY_get1_DH(k: *mut EVP_PKEY) -> *mut DH;
|
||||||
pub fn EVP_PKEY_get1_EC_KEY(k: *mut EVP_PKEY) -> *mut EC_KEY;
|
pub fn EVP_PKEY_get1_EC_KEY(k: *mut EVP_PKEY) -> *mut EC_KEY;
|
||||||
pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int;
|
pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int;
|
||||||
|
pub fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int;
|
||||||
pub fn EVP_PKEY_new_mac_key(
|
pub fn EVP_PKEY_new_mac_key(
|
||||||
type_: c_int,
|
type_: c_int,
|
||||||
e: *mut ENGINE,
|
e: *mut ENGINE,
|
||||||
|
|
@ -2611,6 +2656,7 @@ extern "C" {
|
||||||
pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int;
|
pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int;
|
||||||
pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY;
|
pub fn X509_get_pubkey(x: *mut X509) -> *mut EVP_PKEY;
|
||||||
pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ;
|
pub fn X509_to_X509_REQ(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> *mut X509_REQ;
|
||||||
|
pub fn X509_verify_cert(ctx: *mut X509_STORE_CTX) -> c_int;
|
||||||
pub fn X509_verify_cert_error_string(n: c_long) -> *const c_char;
|
pub fn X509_verify_cert_error_string(n: c_long) -> *const c_char;
|
||||||
pub fn X509_get1_ocsp(x: *mut X509) -> *mut stack_st_OPENSSL_STRING;
|
pub fn X509_get1_ocsp(x: *mut X509) -> *mut stack_st_OPENSSL_STRING;
|
||||||
pub fn X509_check_issued(issuer: *mut X509, subject: *mut X509) -> c_int;
|
pub fn X509_check_issued(issuer: *mut X509, subject: *mut X509) -> c_int;
|
||||||
|
|
@ -2644,6 +2690,9 @@ extern "C" {
|
||||||
pub fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut X509) -> c_int;
|
pub fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut X509) -> c_int;
|
||||||
pub fn X509_STORE_set_default_paths(store: *mut X509_STORE) -> c_int;
|
pub fn X509_STORE_set_default_paths(store: *mut X509_STORE) -> c_int;
|
||||||
|
|
||||||
|
pub fn X509_STORE_CTX_new() -> *mut X509_STORE_CTX;
|
||||||
|
pub fn X509_STORE_CTX_cleanup(ctx: *mut X509_STORE_CTX);
|
||||||
|
pub fn X509_STORE_CTX_init(ctx: *mut X509_STORE_CTX, store: *mut X509_STORE, x509: *mut X509, chain: *mut stack_st_X509) -> c_int;
|
||||||
pub fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX);
|
pub fn X509_STORE_CTX_free(ctx: *mut X509_STORE_CTX);
|
||||||
pub fn X509_STORE_CTX_get_current_cert(ctx: *mut X509_STORE_CTX) -> *mut X509;
|
pub fn X509_STORE_CTX_get_current_cert(ctx: *mut X509_STORE_CTX) -> *mut X509;
|
||||||
pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int;
|
pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int;
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,12 @@ pub struct DSA {
|
||||||
pub engine: *mut ::ENGINE,
|
pub engine: *mut ::ENGINE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ECDSA_SIG {
|
||||||
|
pub r: *mut ::BIGNUM,
|
||||||
|
pub s: *mut ::BIGNUM
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct EVP_PKEY {
|
pub struct EVP_PKEY {
|
||||||
pub type_: c_int,
|
pub type_: c_int,
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,12 @@ pub struct DSA {
|
||||||
pub engine: *mut ::ENGINE,
|
pub engine: *mut ::ENGINE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct ECDSA_SIG {
|
||||||
|
pub r: *mut BIGNUM,
|
||||||
|
pub s: *mut BIGNUM
|
||||||
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct EVP_PKEY {
|
pub struct EVP_PKEY {
|
||||||
pub type_: c_int,
|
pub type_: c_int,
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ pub enum BIO_METHOD {}
|
||||||
pub enum CRYPTO_EX_DATA {}
|
pub enum CRYPTO_EX_DATA {}
|
||||||
pub enum DH {}
|
pub enum DH {}
|
||||||
pub enum DSA {}
|
pub enum DSA {}
|
||||||
|
pub enum ECDSA_SIG {}
|
||||||
pub enum EVP_CIPHER {}
|
pub enum EVP_CIPHER {}
|
||||||
pub enum EVP_MD_CTX {}
|
pub enum EVP_MD_CTX {}
|
||||||
pub enum EVP_PKEY {}
|
pub enum EVP_PKEY {}
|
||||||
|
|
@ -364,4 +365,6 @@ extern "C" {
|
||||||
pub fn X509_REQ_get_version(req: *const X509_REQ) -> c_long;
|
pub fn X509_REQ_get_version(req: *const X509_REQ) -> c_long;
|
||||||
pub fn X509_REQ_get_subject_name(req: *const X509_REQ) -> *mut ::X509_NAME;
|
pub fn X509_REQ_get_subject_name(req: *const X509_REQ) -> *mut ::X509_NAME;
|
||||||
pub fn SSL_extension_supported(ext_type: c_uint) -> c_int;
|
pub fn SSL_extension_supported(ext_type: c_uint) -> c_int;
|
||||||
|
pub fn ECDSA_SIG_get0(sig: *const ECDSA_SIG, pr: *mut *const BIGNUM, ps: *mut *const BIGNUM);
|
||||||
|
pub fn ECDSA_SIG_set0(sig: *mut ECDSA_SIG, pr: *mut BIGNUM, ps: *mut BIGNUM) -> c_int;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@ use pkey::{HasPrivate, HasPublic, PKeyRef};
|
||||||
/// A type used to derive a shared secret between two keys.
|
/// A type used to derive a shared secret between two keys.
|
||||||
pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>);
|
pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>);
|
||||||
|
|
||||||
|
unsafe impl<'a> Sync for Deriver<'a> {}
|
||||||
|
unsafe impl<'a> Send for Deriver<'a> {}
|
||||||
|
|
||||||
impl<'a> Deriver<'a> {
|
impl<'a> Deriver<'a> {
|
||||||
/// Creates a new `Deriver` using the provided private key.
|
/// Creates a new `Deriver` using the provided private key.
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
//! Low level Elliptic Curve Digital Signature Algorithm (ECDSA) functions.
|
||||||
|
//!
|
||||||
|
|
||||||
|
|
||||||
|
use bn::{BigNum, BigNumRef};
|
||||||
|
use {cvt, cvt_n, cvt_p};
|
||||||
|
use ec::EcKeyRef;
|
||||||
|
use error::ErrorStack;
|
||||||
|
use ffi;
|
||||||
|
use foreign_types::{ForeignType, ForeignTypeRef};
|
||||||
|
use pkey::{Private, Public};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
|
|
||||||
|
foreign_type_and_impl_send_sync! {
|
||||||
|
type CType = ffi::ECDSA_SIG;
|
||||||
|
fn drop = ffi::ECDSA_SIG_free;
|
||||||
|
|
||||||
|
/// A low level interface to ECDSA
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`ECDSA_sign`]
|
||||||
|
///
|
||||||
|
/// [`ECDSA_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_sign.html
|
||||||
|
pub struct EcdsaSig;
|
||||||
|
/// Reference to [`EcdsaSig`]
|
||||||
|
///
|
||||||
|
/// [`EcdsaSig`]: struct.EcdsaSig.html
|
||||||
|
pub struct EcdsaSigRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EcdsaSig {
|
||||||
|
|
||||||
|
/// Computes a digital signature of the hash value `data` using the private EC key eckey.
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`ECDSA_do_sign`]
|
||||||
|
///
|
||||||
|
/// [`ECDSA_do_sign`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_sign.html
|
||||||
|
pub fn sign(data: &[u8], eckey: &EcKeyRef<Private>) -> Result<EcdsaSig, ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
let sig = cvt_p(ffi::ECDSA_do_sign(data.as_ptr(), data.len() as i32, eckey.as_ptr()))?;
|
||||||
|
Ok(EcdsaSig::from_ptr(sig as *mut _))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a new `EcdsaSig` by setting the `r` and `s` values associated with a
|
||||||
|
/// ECDSA signature.
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`ECDSA_SIG_set0`]
|
||||||
|
///
|
||||||
|
/// [`ECDSA_SIG_set0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_set0.html
|
||||||
|
pub fn from_private_components(r: BigNum, s: BigNum) -> Result<EcdsaSig, ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
let sig = cvt_p(ffi::ECDSA_SIG_new())?;
|
||||||
|
cvt(compat::set_numbers(sig, r.as_ptr(), s.as_ptr()))?;
|
||||||
|
mem::forget((r, s));
|
||||||
|
Ok(EcdsaSig::from_ptr(sig as *mut _))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies if the signature is a valid ECDSA signature using the given public key
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`ECDSA_do_verify`]
|
||||||
|
///
|
||||||
|
/// [`ECDSA_do_verify`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_do_verify.html
|
||||||
|
pub fn verify(&self, data: &[u8], eckey: &EcKeyRef<Public>) -> Result<bool, ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
let x = cvt_n(ffi::ECDSA_do_verify(data.as_ptr(), data.len() as i32, self.as_ptr(), eckey.as_ptr()))?;
|
||||||
|
Ok(x == 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns internal component: `r` of a `EcdsaSig`. (See X9.62 or FIPS 186-2)
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`ECDSA_SIG_get0`]
|
||||||
|
///
|
||||||
|
/// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html
|
||||||
|
pub fn private_component_r(&self) -> Option<&BigNumRef> {
|
||||||
|
unsafe {
|
||||||
|
let xs = compat::get_numbers(self.as_ptr());
|
||||||
|
let r = if xs[0].is_null() { None } else { Some(BigNumRef::from_ptr(xs[0] as *mut _)) };
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns internal components: `s` of a `EcdsaSig`. (See X9.62 or FIPS 186-2)
|
||||||
|
///
|
||||||
|
/// OpenSSL documentation at [`ECDSA_SIG_get0`]
|
||||||
|
///
|
||||||
|
/// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html
|
||||||
|
pub fn private_component_s(&self) -> Option<&BigNumRef> {
|
||||||
|
unsafe {
|
||||||
|
let xs = compat::get_numbers(self.as_ptr());
|
||||||
|
let s = if xs[1].is_null() { None } else { Some(BigNumRef::from_ptr(xs[1] as *mut _)) };
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl110)]
|
||||||
|
mod compat {
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
|
use libc::c_int;
|
||||||
|
use ffi::{self, BIGNUM, ECDSA_SIG};
|
||||||
|
|
||||||
|
pub unsafe fn set_numbers(sig: *mut ECDSA_SIG, r: *mut BIGNUM, s: *mut BIGNUM) -> c_int {
|
||||||
|
ffi::ECDSA_SIG_set0(sig, r, s)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_numbers(sig: *mut ECDSA_SIG) -> [*const BIGNUM; 2] {
|
||||||
|
let (mut r, mut s) = (ptr::null(), ptr::null());
|
||||||
|
ffi::ECDSA_SIG_get0(sig, &mut r, &mut s);
|
||||||
|
[r, s]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(ossl10x)]
|
||||||
|
mod compat {
|
||||||
|
use libc::c_int;
|
||||||
|
use ffi::{BIGNUM, ECDSA_SIG};
|
||||||
|
|
||||||
|
pub unsafe fn set_numbers(sig: *mut ECDSA_SIG, r: *mut BIGNUM, s: *mut BIGNUM) -> c_int {
|
||||||
|
(*sig).r = r;
|
||||||
|
(*sig).s = s;
|
||||||
|
1
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_numbers(sig: *mut ECDSA_SIG) -> [*const BIGNUM; 2] {
|
||||||
|
[(*sig).r, (*sig).s]
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use nid::Nid;
|
||||||
|
use ec::EcGroup;
|
||||||
|
use ec::EcKey;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[cfg(not(osslconf = "OPENSSL_NO_EC2M"))]
|
||||||
|
static CURVE_IDENTIFER: Nid = Nid::X9_62_PRIME192V1;
|
||||||
|
|
||||||
|
#[cfg(osslconf = "OPENSSL_NO_EC2M")]
|
||||||
|
static CURVE_IDENTIFER: Nid = Nid::X9_62_C2TNB191V1;
|
||||||
|
|
||||||
|
fn get_public_key(group: &EcGroup, x: &EcKey<Private>) -> Result<EcKey<Public>, ErrorStack> {
|
||||||
|
let public_key_point = x.public_key();
|
||||||
|
Ok(EcKey::from_public_key(group, public_key_point)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sign_and_verify() {
|
||||||
|
let group = EcGroup::from_curve_name(CURVE_IDENTIFER).unwrap();
|
||||||
|
let private_key = EcKey::generate(&group).unwrap();
|
||||||
|
let public_key = get_public_key(&group, &private_key).unwrap();
|
||||||
|
|
||||||
|
let private_key2 = EcKey::generate(&group).unwrap();
|
||||||
|
let public_key2 = get_public_key(&group, &private_key2).unwrap();
|
||||||
|
|
||||||
|
let data = String::from("hello");
|
||||||
|
let res = EcdsaSig::sign(data.as_bytes(), &private_key).unwrap();
|
||||||
|
|
||||||
|
// Signature can be verified using the correct data & correct public key
|
||||||
|
let verification = res.verify(data.as_bytes(), &public_key).unwrap();
|
||||||
|
assert!(verification);
|
||||||
|
|
||||||
|
// Signature will not be verified using the incorrect data but the correct public key
|
||||||
|
let verification2 = res.verify(String::from("hello2").as_bytes(), &public_key).unwrap();
|
||||||
|
assert!(verification2 == false);
|
||||||
|
|
||||||
|
// Signature will not be verified using the correct data but the incorrect public key
|
||||||
|
let verification3 = res.verify(data.as_bytes(), &public_key2).unwrap();
|
||||||
|
assert!(verification3 == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_private_components() {
|
||||||
|
let group = EcGroup::from_curve_name(CURVE_IDENTIFER).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.private_component_r().unwrap().to_owned().unwrap();
|
||||||
|
let s = res.private_component_s().unwrap().to_owned().unwrap();
|
||||||
|
|
||||||
|
let res2 = EcdsaSig::from_private_components(r, s).unwrap();
|
||||||
|
let verification2 = res2.verify(data.as_bytes(), &public_key).unwrap();
|
||||||
|
assert!(verification2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -49,6 +49,9 @@ impl MessageDigest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for MessageDigest {}
|
||||||
|
unsafe impl Send for MessageDigest {}
|
||||||
|
|
||||||
#[derive(PartialEq, Copy, Clone)]
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
enum State {
|
enum State {
|
||||||
Reset,
|
Reset,
|
||||||
|
|
@ -99,6 +102,9 @@ pub struct Hasher {
|
||||||
state: State,
|
state: State,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for Hasher {}
|
||||||
|
unsafe impl Send for Hasher {}
|
||||||
|
|
||||||
impl Hasher {
|
impl Hasher {
|
||||||
/// Creates a new `Hasher` with the specified hash type.
|
/// Creates a new `Hasher` with the specified hash type.
|
||||||
pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
|
pub fn new(ty: MessageDigest) -> Result<Hasher, ErrorStack> {
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ pub mod derive;
|
||||||
pub mod dh;
|
pub mod dh;
|
||||||
pub mod dsa;
|
pub mod dsa;
|
||||||
pub mod ec;
|
pub mod ec;
|
||||||
|
pub mod ecdsa;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod ex_data;
|
pub mod ex_data;
|
||||||
#[cfg(not(libressl))]
|
#[cfg(not(libressl))]
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,28 @@ pub enum Public {}
|
||||||
/// A tag type indicating that a key has private components.
|
/// A tag type indicating that a key has private components.
|
||||||
pub enum Private {}
|
pub enum Private {}
|
||||||
|
|
||||||
|
/// An identifier of a kind of key.
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Id(c_int);
|
||||||
|
|
||||||
|
impl Id {
|
||||||
|
/// Creates a `Id` from an integer representation.
|
||||||
|
pub fn from_raw(value: c_int) -> Id {
|
||||||
|
Id(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the integer representation of the `Id`.
|
||||||
|
pub fn as_raw(&self) -> c_int {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const RSA: Id = Id(ffi::EVP_PKEY_RSA);
|
||||||
|
pub const HMAC: Id = Id(ffi::EVP_PKEY_HMAC);
|
||||||
|
pub const DSA: Id = Id(ffi::EVP_PKEY_DSA);
|
||||||
|
pub const DH: Id = Id(ffi::EVP_PKEY_DH);
|
||||||
|
pub const EC: Id = Id(ffi::EVP_PKEY_EC);
|
||||||
|
}
|
||||||
|
|
||||||
/// A trait indicating that a key has parameters.
|
/// A trait indicating that a key has parameters.
|
||||||
pub unsafe trait HasParams {}
|
pub unsafe trait HasParams {}
|
||||||
|
|
||||||
|
|
@ -155,6 +177,17 @@ impl<T> PKeyRef<T> {
|
||||||
Ok(EcKey::from_ptr(ec_key))
|
Ok(EcKey::from_ptr(ec_key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the `Id` that represents the type of this key.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`EVP_PKEY_id`].
|
||||||
|
///
|
||||||
|
/// [`EVP_PKEY_id`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_id.html
|
||||||
|
pub fn id(&self) -> Id {
|
||||||
|
unsafe {
|
||||||
|
Id::from_raw(ffi::EVP_PKEY_id(self.as_ptr()))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> PKeyRef<T>
|
impl<T> PKeyRef<T>
|
||||||
|
|
@ -531,6 +564,7 @@ mod tests {
|
||||||
let rsa = Rsa::generate(2048).unwrap();
|
let rsa = Rsa::generate(2048).unwrap();
|
||||||
let pkey = PKey::from_rsa(rsa).unwrap();
|
let pkey = PKey::from_rsa(rsa).unwrap();
|
||||||
pkey.rsa().unwrap();
|
pkey.rsa().unwrap();
|
||||||
|
assert_eq!(pkey.id(), Id::RSA);
|
||||||
assert!(pkey.dsa().is_err());
|
assert!(pkey.dsa().is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -539,6 +573,7 @@ mod tests {
|
||||||
let dsa = Dsa::generate(2048).unwrap();
|
let dsa = Dsa::generate(2048).unwrap();
|
||||||
let pkey = PKey::from_dsa(dsa).unwrap();
|
let pkey = PKey::from_dsa(dsa).unwrap();
|
||||||
pkey.dsa().unwrap();
|
pkey.dsa().unwrap();
|
||||||
|
assert_eq!(pkey.id(), Id::DSA);
|
||||||
assert!(pkey.rsa().is_err());
|
assert!(pkey.rsa().is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -548,6 +583,7 @@ mod tests {
|
||||||
let dh = Dh::params_from_pem(dh).unwrap();
|
let dh = Dh::params_from_pem(dh).unwrap();
|
||||||
let pkey = PKey::from_dh(dh).unwrap();
|
let pkey = PKey::from_dh(dh).unwrap();
|
||||||
pkey.dh().unwrap();
|
pkey.dh().unwrap();
|
||||||
|
assert_eq!(pkey.id(), Id::DH);
|
||||||
assert!(pkey.rsa().is_err());
|
assert!(pkey.rsa().is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -556,6 +592,7 @@ mod tests {
|
||||||
let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
|
let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
|
||||||
let pkey = PKey::from_ec_key(ec_key).unwrap();
|
let pkey = PKey::from_ec_key(ec_key).unwrap();
|
||||||
pkey.ec_key().unwrap();
|
pkey.ec_key().unwrap();
|
||||||
|
assert_eq!(pkey.id(), Id::EC);
|
||||||
assert!(pkey.rsa().is_err());
|
assert!(pkey.rsa().is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ impl Padding {
|
||||||
pub const NONE: Padding = Padding(ffi::RSA_NO_PADDING);
|
pub const NONE: Padding = Padding(ffi::RSA_NO_PADDING);
|
||||||
pub const PKCS1: Padding = Padding(ffi::RSA_PKCS1_PADDING);
|
pub const PKCS1: Padding = Padding(ffi::RSA_PKCS1_PADDING);
|
||||||
pub const PKCS1_OAEP: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING);
|
pub const PKCS1_OAEP: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING);
|
||||||
|
pub const PKCS1_PSS: Padding = Padding(ffi::RSA_PKCS1_PSS_PADDING);
|
||||||
}
|
}
|
||||||
|
|
||||||
generic_foreign_type_and_impl_send_sync! {
|
generic_foreign_type_and_impl_send_sync! {
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ use foreign_types::ForeignTypeRef;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use libc::c_int;
|
||||||
|
|
||||||
use {cvt, cvt_p};
|
use {cvt, cvt_p};
|
||||||
use hash::MessageDigest;
|
use hash::MessageDigest;
|
||||||
|
|
@ -78,6 +79,28 @@ use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
|
||||||
#[cfg(any(ossl101, ossl102))]
|
#[cfg(any(ossl101, ossl102))]
|
||||||
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
|
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
|
||||||
|
|
||||||
|
/// Salt lengths that must be used with `set_rsa_pss_saltlen`.
|
||||||
|
pub struct RsaPssSaltlen(c_int);
|
||||||
|
|
||||||
|
impl RsaPssSaltlen {
|
||||||
|
/// Returns the integer representation of `RsaPssSaltlen`.
|
||||||
|
fn as_raw(&self) -> c_int {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the salt length to the given value.
|
||||||
|
pub fn custom(val: c_int) -> RsaPssSaltlen {
|
||||||
|
RsaPssSaltlen(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The salt length is set to the digest length.
|
||||||
|
/// Corresponds to the special value `-1`.
|
||||||
|
pub const DIGEST_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-1);
|
||||||
|
/// The salt length is set to the maximum permissible value.
|
||||||
|
/// Corresponds to the special value `-2`.
|
||||||
|
pub const MAXIMUM_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-2);
|
||||||
|
}
|
||||||
|
|
||||||
/// A type which computes cryptographic signatures of data.
|
/// A type which computes cryptographic signatures of data.
|
||||||
pub struct Signer<'a> {
|
pub struct Signer<'a> {
|
||||||
md_ctx: *mut ffi::EVP_MD_CTX,
|
md_ctx: *mut ffi::EVP_MD_CTX,
|
||||||
|
|
@ -85,6 +108,9 @@ pub struct Signer<'a> {
|
||||||
_p: PhantomData<&'a ()>,
|
_p: PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a> Sync for Signer<'a> {}
|
||||||
|
unsafe impl<'a> Send for Signer<'a> {}
|
||||||
|
|
||||||
impl<'a> Drop for Signer<'a> {
|
impl<'a> Drop for Signer<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
|
// pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
|
||||||
|
|
@ -160,6 +186,38 @@ impl<'a> Signer<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the RSA PSS salt length.
|
||||||
|
///
|
||||||
|
/// This is only useful for RSA keys.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`].
|
||||||
|
///
|
||||||
|
/// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html
|
||||||
|
pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen(
|
||||||
|
self.pctx,
|
||||||
|
len.as_raw(),
|
||||||
|
)).map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the RSA MGF1 algorithm.
|
||||||
|
///
|
||||||
|
/// This is only useful for RSA keys.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`].
|
||||||
|
///
|
||||||
|
/// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html
|
||||||
|
pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md(
|
||||||
|
self.pctx,
|
||||||
|
md.as_ptr() as *mut _,
|
||||||
|
)).map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Feeds more data into the `Signer`.
|
/// Feeds more data into the `Signer`.
|
||||||
///
|
///
|
||||||
/// OpenSSL documentation at [`EVP_DigestUpdate`].
|
/// OpenSSL documentation at [`EVP_DigestUpdate`].
|
||||||
|
|
@ -244,6 +302,9 @@ pub struct Verifier<'a> {
|
||||||
pkey_pd: PhantomData<&'a ()>,
|
pkey_pd: PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a> Sync for Verifier<'a> {}
|
||||||
|
unsafe impl<'a> Send for Verifier<'a> {}
|
||||||
|
|
||||||
impl<'a> Drop for Verifier<'a> {
|
impl<'a> Drop for Verifier<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
|
// pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
|
||||||
|
|
@ -320,6 +381,38 @@ impl<'a> Verifier<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets the RSA PSS salt length.
|
||||||
|
///
|
||||||
|
/// This is only useful for RSA keys.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`EVP_PKEY_CTX_set_rsa_pss_saltlen`].
|
||||||
|
///
|
||||||
|
/// [`EVP_PKEY_CTX_set_rsa_pss_saltlen`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_PKEY_CTX_set_rsa_pss_saltlen.html
|
||||||
|
pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen(
|
||||||
|
self.pctx,
|
||||||
|
len.as_raw(),
|
||||||
|
)).map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the RSA MGF1 algorithm.
|
||||||
|
///
|
||||||
|
/// This is only useful for RSA keys.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`EVP_PKEY_CTX_set_rsa_mgf1_md`].
|
||||||
|
///
|
||||||
|
/// [`EVP_PKEY_CTX_set_rsa_mgf1_md`]: https://www.openssl.org/docs/manmaster/man7/RSA-PSS.html
|
||||||
|
pub fn set_rsa_mgf1_md(&mut self, md: MessageDigest) -> Result<(), ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::EVP_PKEY_CTX_set_rsa_mgf1_md(
|
||||||
|
self.pctx,
|
||||||
|
md.as_ptr() as *mut _,
|
||||||
|
)).map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Feeds more data into the `Verifier`.
|
/// Feeds more data into the `Verifier`.
|
||||||
///
|
///
|
||||||
/// OpenSSL documentation at [`EVP_DigestUpdate`].
|
/// OpenSSL documentation at [`EVP_DigestUpdate`].
|
||||||
|
|
@ -386,7 +479,7 @@ mod test {
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use hash::MessageDigest;
|
use hash::MessageDigest;
|
||||||
use sign::{Signer, Verifier};
|
use sign::{Signer, Verifier, RsaPssSaltlen};
|
||||||
use ec::{EcGroup, EcKey};
|
use ec::{EcGroup, EcKey};
|
||||||
use nid::Nid;
|
use nid::Nid;
|
||||||
use rsa::{Padding, Rsa};
|
use rsa::{Padding, Rsa};
|
||||||
|
|
@ -559,4 +652,26 @@ mod test {
|
||||||
verifier.update(b"hello world").unwrap();
|
verifier.update(b"hello world").unwrap();
|
||||||
assert!(verifier.verify(&signature).unwrap());
|
assert!(verifier.verify(&signature).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rsa_sign_verify() {
|
||||||
|
let key = include_bytes!("../test/rsa.pem");
|
||||||
|
let private_key = Rsa::private_key_from_pem(key).unwrap();
|
||||||
|
let pkey = PKey::from_rsa(private_key).unwrap();
|
||||||
|
|
||||||
|
let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||||
|
signer.set_rsa_padding(Padding::PKCS1_PSS).unwrap();
|
||||||
|
assert_eq!(signer.rsa_padding().unwrap(), Padding::PKCS1_PSS);
|
||||||
|
signer.set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH).unwrap();
|
||||||
|
signer.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap();
|
||||||
|
signer.update(&Vec::from_hex(INPUT).unwrap()).unwrap();
|
||||||
|
let signature = signer.sign_to_vec().unwrap();
|
||||||
|
|
||||||
|
let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap();
|
||||||
|
verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap();
|
||||||
|
verifier.set_rsa_pss_saltlen(RsaPssSaltlen::DIGEST_LENGTH).unwrap();
|
||||||
|
verifier.set_rsa_mgf1_md(MessageDigest::sha256()).unwrap();
|
||||||
|
verifier.update(&Vec::from_hex(INPUT).unwrap()).unwrap();
|
||||||
|
assert!(verifier.verify(&signature).unwrap());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -305,6 +305,9 @@ impl SslMethod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for SslMethod {}
|
||||||
|
unsafe impl Send for SslMethod {}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
/// Options controling the behavior of certificate verification.
|
/// Options controling the behavior of certificate verification.
|
||||||
pub struct SslVerifyMode: i32 {
|
pub struct SslVerifyMode: i32 {
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,9 @@ impl Cipher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for Cipher {}
|
||||||
|
unsafe impl Send for Cipher {}
|
||||||
|
|
||||||
/// Represents a symmetric cipher context.
|
/// Represents a symmetric cipher context.
|
||||||
///
|
///
|
||||||
/// Padding is enabled by default.
|
/// Padding is enabled by default.
|
||||||
|
|
@ -288,6 +291,9 @@ pub struct Crypter {
|
||||||
block_size: usize,
|
block_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Sync for Crypter {}
|
||||||
|
unsafe impl Send for Crypter {}
|
||||||
|
|
||||||
impl Crypter {
|
impl Crypter {
|
||||||
/// Creates a new `Crypter`. The initialisation vector, `iv`, is not necesarry for certain
|
/// Creates a new `Crypter`. The initialisation vector, `iv`, is not necesarry for certain
|
||||||
/// types of `Cipher`.
|
/// types of `Cipher`.
|
||||||
|
|
@ -963,7 +969,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_des_ede3_cbc() {
|
fn test_des_ede3_cbc() {
|
||||||
|
|
||||||
let pt = "54686973206973206120746573742e";
|
let pt = "54686973206973206120746573742e";
|
||||||
let ct = "6f2867cfefda048a4046ef7e556c7132";
|
let ct = "6f2867cfefda048a4046ef7e556c7132";
|
||||||
let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe";
|
let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe";
|
||||||
|
|
|
||||||
|
|
@ -6,39 +6,6 @@
|
||||||
//! data with the included public key. `X509` certificates are used in many
|
//! data with the included public key. `X509` certificates are used in many
|
||||||
//! Internet protocols, including SSL/TLS, which is the basis for HTTPS,
|
//! Internet protocols, including SSL/TLS, which is the basis for HTTPS,
|
||||||
//! the secure protocol for browsing the web.
|
//! the secure protocol for browsing the web.
|
||||||
//!
|
|
||||||
//! # Example
|
|
||||||
//!
|
|
||||||
//! Build an `X509` certificate and use a generated RSA key to sign it.
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//!
|
|
||||||
//! extern crate openssl;
|
|
||||||
//!
|
|
||||||
//! use openssl::x509::{X509, X509Name};
|
|
||||||
//! use openssl::pkey::PKey;
|
|
||||||
//! use openssl::hash::MessageDigest;
|
|
||||||
//! use openssl::rsa::Rsa;
|
|
||||||
//! use openssl::nid::Nid;
|
|
||||||
//!
|
|
||||||
//! fn main() {
|
|
||||||
//! let rsa = Rsa::generate(2048).unwrap();
|
|
||||||
//! let pkey = PKey::from_rsa(rsa).unwrap();
|
|
||||||
//!
|
|
||||||
//! let mut name = X509Name::builder().unwrap();
|
|
||||||
//! name.append_entry_by_nid(Nid::COMMONNAME, "foobar.com").unwrap();
|
|
||||||
//! let name = name.build();
|
|
||||||
//!
|
|
||||||
//! let mut builder = X509::builder().unwrap();
|
|
||||||
//! builder.set_version(2).unwrap();
|
|
||||||
//! builder.set_subject_name(&name).unwrap();
|
|
||||||
//! builder.set_issuer_name(&name).unwrap();
|
|
||||||
//! builder.set_pubkey(&pkey).unwrap();
|
|
||||||
//! builder.sign(&pkey, MessageDigest::sha256()).unwrap();
|
|
||||||
//!
|
|
||||||
//! let certificate: X509 = builder.build();
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
use libc::{c_int, c_long};
|
use libc::{c_int, c_long};
|
||||||
use ffi;
|
use ffi;
|
||||||
|
|
@ -100,6 +67,18 @@ impl X509StoreContext {
|
||||||
pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
|
pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
|
||||||
unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
|
unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `X509StoreContext` instance.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`X509_STORE_CTX_new`].
|
||||||
|
///
|
||||||
|
/// [`X509_STORE_CTX_new`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_new.html
|
||||||
|
pub fn new() -> Result<X509StoreContext, ErrorStack> {
|
||||||
|
unsafe {
|
||||||
|
ffi::init();
|
||||||
|
cvt_p(ffi::X509_STORE_CTX_new()).map(|p| X509StoreContext(p))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl X509StoreContextRef {
|
impl X509StoreContextRef {
|
||||||
|
|
@ -128,6 +107,68 @@ impl X509StoreContextRef {
|
||||||
unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
|
unsafe { X509VerifyResult::from_raw(ffi::X509_STORE_CTX_get_error(self.as_ptr())) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initializes this context with the given certificate, certificates chain and certificate
|
||||||
|
/// store. After initializing the context, the `with_context` closure is called with the prepared
|
||||||
|
/// context. As long as the closure is running, the context stays initialized and can be used
|
||||||
|
/// to e.g. verify a certificate. The context will be cleaned up, after the closure finished.
|
||||||
|
///
|
||||||
|
/// * `trust` - The certificate store with the trusted certificates.
|
||||||
|
/// * `cert` - The certificate that should be verified.
|
||||||
|
/// * `cert_chain` - The certificates chain.
|
||||||
|
/// * `with_context` - The closure that is called with the initialized context.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`X509_STORE_CTX_init`] before calling `with_context` and to
|
||||||
|
/// [`X509_STORE_CTX_cleanup`] after calling `with_context`.
|
||||||
|
///
|
||||||
|
/// [`X509_STORE_CTX_init`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_init.html
|
||||||
|
/// [`X509_STORE_CTX_cleanup`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_STORE_CTX_cleanup.html
|
||||||
|
pub fn init<F, T>(
|
||||||
|
&mut self,
|
||||||
|
trust: &store::X509StoreRef,
|
||||||
|
cert: &X509Ref,
|
||||||
|
cert_chain: &StackRef<X509>,
|
||||||
|
with_context: F,
|
||||||
|
) -> Result<T, ErrorStack>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut X509StoreContextRef) -> Result<T, ErrorStack>,
|
||||||
|
{
|
||||||
|
struct Cleanup<'a>(&'a mut X509StoreContextRef);
|
||||||
|
|
||||||
|
impl<'a> Drop for Cleanup<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
ffi::X509_STORE_CTX_cleanup(self.0.as_ptr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
cvt(ffi::X509_STORE_CTX_init(
|
||||||
|
self.as_ptr(),
|
||||||
|
trust.as_ptr(),
|
||||||
|
cert.as_ptr(),
|
||||||
|
cert_chain.as_ptr(),
|
||||||
|
))?;
|
||||||
|
|
||||||
|
let cleanup = Cleanup(self);
|
||||||
|
with_context(cleanup.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the stored certificate.
|
||||||
|
///
|
||||||
|
/// Returns `true` if verification succeeds. The `error` method will return the specific
|
||||||
|
/// validation error if the certificate was not valid.
|
||||||
|
///
|
||||||
|
/// This will only work inside of a call to `init`.
|
||||||
|
///
|
||||||
|
/// This corresponds to [`X509_verify_cert`].
|
||||||
|
///
|
||||||
|
/// [`X509_verify_cert`]: https://www.openssl.org/docs/man1.0.2/crypto/X509_verify_cert.html
|
||||||
|
pub fn verify_cert(&mut self) -> Result<bool, ErrorStack> {
|
||||||
|
unsafe { cvt_n(ffi::X509_verify_cert(self.as_ptr())).map(|n| n != 0) }
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the error code of the context.
|
/// Set the error code of the context.
|
||||||
///
|
///
|
||||||
/// This corresponds to [`X509_STORE_CTX_set_error`].
|
/// This corresponds to [`X509_STORE_CTX_set_error`].
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,10 @@ use nid::Nid;
|
||||||
use pkey::{PKey, Private};
|
use pkey::{PKey, Private};
|
||||||
use rsa::Rsa;
|
use rsa::Rsa;
|
||||||
use stack::Stack;
|
use stack::Stack;
|
||||||
use x509::{X509, X509Name, X509Req, X509VerifyResult};
|
use x509::{X509, X509Name, X509Req, X509StoreContext, X509VerifyResult};
|
||||||
use x509::extension::{AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage,
|
use x509::extension::{AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage,
|
||||||
SubjectAlternativeName, SubjectKeyIdentifier};
|
SubjectAlternativeName, SubjectKeyIdentifier};
|
||||||
|
use x509::store::X509StoreBuilder;
|
||||||
|
|
||||||
fn pkey() -> PKey<Private> {
|
fn pkey() -> PKey<Private> {
|
||||||
let rsa = Rsa::generate(2048).unwrap();
|
let rsa = Rsa::generate(2048).unwrap();
|
||||||
|
|
@ -241,15 +242,11 @@ fn test_stack_from_pem() {
|
||||||
|
|
||||||
assert_eq!(certs.len(), 2);
|
assert_eq!(certs.len(), 2);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex::encode(certs[0]
|
hex::encode(certs[0].fingerprint(MessageDigest::sha1()).unwrap()),
|
||||||
.fingerprint(MessageDigest::sha1())
|
|
||||||
.unwrap()),
|
|
||||||
"59172d9313e84459bcff27f967e79e6e9217e584"
|
"59172d9313e84459bcff27f967e79e6e9217e584"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
hex::encode(certs[1]
|
hex::encode(certs[1].fingerprint(MessageDigest::sha1()).unwrap()),
|
||||||
.fingerprint(MessageDigest::sha1())
|
|
||||||
.unwrap()),
|
|
||||||
"c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"
|
"c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -291,3 +288,46 @@ fn clone_x509() {
|
||||||
let cert = X509::from_pem(cert).unwrap();
|
let cert = X509::from_pem(cert).unwrap();
|
||||||
cert.clone();
|
cert.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_verify_cert() {
|
||||||
|
let cert = include_bytes!("../../test/cert.pem");
|
||||||
|
let cert = X509::from_pem(cert).unwrap();
|
||||||
|
let ca = include_bytes!("../../test/root-ca.pem");
|
||||||
|
let ca = X509::from_pem(ca).unwrap();
|
||||||
|
let chain = Stack::new().unwrap();
|
||||||
|
|
||||||
|
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||||
|
store_bldr.add_cert(ca).unwrap();
|
||||||
|
let store = store_bldr.build();
|
||||||
|
|
||||||
|
let mut context = X509StoreContext::new().unwrap();
|
||||||
|
assert!(
|
||||||
|
context
|
||||||
|
.init(&store, &cert, &chain, |c| c.verify_cert())
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
context
|
||||||
|
.init(&store, &cert, &chain, |c| c.verify_cert())
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_verify_fails() {
|
||||||
|
let cert = include_bytes!("../../test/cert.pem");
|
||||||
|
let cert = X509::from_pem(cert).unwrap();
|
||||||
|
let ca = include_bytes!("../../test/alt_name_cert.pem");
|
||||||
|
let ca = X509::from_pem(ca).unwrap();
|
||||||
|
let chain = Stack::new().unwrap();
|
||||||
|
|
||||||
|
let mut store_bldr = X509StoreBuilder::new().unwrap();
|
||||||
|
store_bldr.add_cert(ca).unwrap();
|
||||||
|
let store = store_bldr.build();
|
||||||
|
|
||||||
|
let mut context = X509StoreContext::new().unwrap();
|
||||||
|
assert!(!context
|
||||||
|
.init(&store, &cert, &chain, |c| c.verify_cert())
|
||||||
|
.unwrap());
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue