aboutsummaryrefslogtreecommitdiff
path: root/openssl/src
diff options
context:
space:
mode:
authorSteven Fackler <[email protected]>2018-03-11 15:27:28 -0700
committerGitHub <[email protected]>2018-03-11 15:27:28 -0700
commitd0329473bd06c72229aef05277f53e0c2fd759c2 (patch)
tree5b4ce5cde1a896abb1b65e9020e689a054777694 /openssl/src
parentGeneric custom extension add fn return type (diff)
parentMerge pull request #863 from rohit-lshift/master (diff)
downloadrust-openssl-d0329473bd06c72229aef05277f53e0c2fd759c2.tar.xz
rust-openssl-d0329473bd06c72229aef05277f53e0c2fd759c2.zip
Merge branch 'master' into custom-extensions
Diffstat (limited to 'openssl/src')
-rw-r--r--openssl/src/derive.rs3
-rw-r--r--openssl/src/ecdsa.rs196
-rw-r--r--openssl/src/hash.rs6
-rw-r--r--openssl/src/lib.rs1
-rw-r--r--openssl/src/pkey.rs37
-rw-r--r--openssl/src/rsa.rs1
-rw-r--r--openssl/src/sign.rs117
-rw-r--r--openssl/src/ssl/mod.rs3
-rw-r--r--openssl/src/symm.rs7
-rw-r--r--openssl/src/x509/mod.rs107
-rw-r--r--openssl/src/x509/tests.rs54
11 files changed, 490 insertions, 42 deletions
diff --git a/openssl/src/derive.rs b/openssl/src/derive.rs
index fb7bbf14..30d7dc25 100644
--- a/openssl/src/derive.rs
+++ b/openssl/src/derive.rs
@@ -11,6 +11,9 @@ use pkey::{HasPrivate, HasPublic, PKeyRef};
/// A type used to derive a shared secret between two keys.
pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>);
+unsafe impl<'a> Sync for Deriver<'a> {}
+unsafe impl<'a> Send for Deriver<'a> {}
+
impl<'a> Deriver<'a> {
/// Creates a new `Deriver` using the provided private key.
///
diff --git a/openssl/src/ecdsa.rs b/openssl/src/ecdsa.rs
new file mode 100644
index 00000000..b220350c
--- /dev/null
+++ b/openssl/src/ecdsa.rs
@@ -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);
+ }
+} \ No newline at end of file
diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs
index 103a7ae3..c6d4c862 100644
--- a/openssl/src/hash.rs
+++ b/openssl/src/hash.rs
@@ -49,6 +49,9 @@ impl MessageDigest {
}
}
+unsafe impl Sync for MessageDigest {}
+unsafe impl Send for MessageDigest {}
+
#[derive(PartialEq, Copy, Clone)]
enum State {
Reset,
@@ -99,6 +102,9 @@ pub struct Hasher {
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> {
diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs
index 321a301f..e4b621ef 100644
--- a/openssl/src/lib.rs
+++ b/openssl/src/lib.rs
@@ -39,6 +39,7 @@ pub mod derive;
pub mod dh;
pub mod dsa;
pub mod ec;
+pub mod ecdsa;
pub mod error;
pub mod ex_data;
#[cfg(not(libressl))]
diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs
index 8f7c4e4e..66ff33d6 100644
--- a/openssl/src/pkey.rs
+++ b/openssl/src/pkey.rs
@@ -70,6 +70,28 @@ pub enum Public {}
/// A tag type indicating that a key has private components.
pub enum Private {}
+/// An identifier of a kind of key.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct Id(c_int);
+
+impl Id {
+ /// 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.
pub unsafe trait HasParams {}
@@ -155,6 +177,17 @@ impl<T> PKeyRef<T> {
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>
@@ -531,6 +564,7 @@ mod tests {
let rsa = Rsa::generate(2048).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
pkey.rsa().unwrap();
+ assert_eq!(pkey.id(), Id::RSA);
assert!(pkey.dsa().is_err());
}
@@ -539,6 +573,7 @@ mod tests {
let dsa = Dsa::generate(2048).unwrap();
let pkey = PKey::from_dsa(dsa).unwrap();
pkey.dsa().unwrap();
+ assert_eq!(pkey.id(), Id::DSA);
assert!(pkey.rsa().is_err());
}
@@ -548,6 +583,7 @@ mod tests {
let dh = Dh::params_from_pem(dh).unwrap();
let pkey = PKey::from_dh(dh).unwrap();
pkey.dh().unwrap();
+ assert_eq!(pkey.id(), Id::DH);
assert!(pkey.rsa().is_err());
}
@@ -556,6 +592,7 @@ mod tests {
let ec_key = EcKey::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
let pkey = PKey::from_ec_key(ec_key).unwrap();
pkey.ec_key().unwrap();
+ assert_eq!(pkey.id(), Id::EC);
assert!(pkey.rsa().is_err());
}
}
diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs
index 02240948..6a591b69 100644
--- a/openssl/src/rsa.rs
+++ b/openssl/src/rsa.rs
@@ -63,6 +63,7 @@ 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);
}
generic_foreign_type_and_impl_send_sync! {
diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs
index a61d883b..6a49cb49 100644
--- a/openssl/src/sign.rs
+++ b/openssl/src/sign.rs
@@ -66,6 +66,7 @@ use foreign_types::ForeignTypeRef;
use std::io::{self, Write};
use std::marker::PhantomData;
use std::ptr;
+use libc::c_int;
use {cvt, cvt_p};
use hash::MessageDigest;
@@ -78,6 +79,28 @@ use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new};
#[cfg(any(ossl101, ossl102))]
use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free};
+/// Salt lengths that must be used with `set_rsa_pss_saltlen`.
+pub struct RsaPssSaltlen(c_int);
+
+impl RsaPssSaltlen {
+ /// Returns the integer representation of `RsaPssSaltlen`.
+ fn as_raw(&self) -> c_int {
+ self.0
+ }
+
+ /// Sets the salt length to the given value.
+ pub fn custom(val: c_int) -> RsaPssSaltlen {
+ RsaPssSaltlen(val)
+ }
+
+ /// The salt length is set to the digest length.
+ /// Corresponds to the special value `-1`.
+ pub const DIGEST_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-1);
+ /// The salt length is set to the maximum permissible value.
+ /// Corresponds to the special value `-2`.
+ pub const MAXIMUM_LENGTH: RsaPssSaltlen = RsaPssSaltlen(-2);
+}
+
/// A type which computes cryptographic signatures of data.
pub struct Signer<'a> {
md_ctx: *mut ffi::EVP_MD_CTX,
@@ -85,6 +108,9 @@ pub struct Signer<'a> {
_p: PhantomData<&'a ()>,
}
+unsafe impl<'a> Sync for Signer<'a> {}
+unsafe impl<'a> Send for Signer<'a> {}
+
impl<'a> Drop for Signer<'a> {
fn drop(&mut self) {
// pkey_ctx is owned by the md_ctx, so no need to explicitly free it.
@@ -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`.
///
/// OpenSSL documentation at [`EVP_DigestUpdate`].
@@ -244,6 +302,9 @@ pub struct Verifier<'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> {
fn drop(&mut self) {
// 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`.
///
/// OpenSSL documentation at [`EVP_DigestUpdate`].
@@ -386,7 +479,7 @@ mod test {
use std::iter;
use hash::MessageDigest;
- use sign::{Signer, Verifier};
+ use sign::{Signer, Verifier, RsaPssSaltlen};
use ec::{EcGroup, EcKey};
use nid::Nid;
use rsa::{Padding, Rsa};
@@ -559,4 +652,26 @@ mod test {
verifier.update(b"hello world").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());
+ }
}
diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs
index 6a140c14..a18ef3a0 100644
--- a/openssl/src/ssl/mod.rs
+++ b/openssl/src/ssl/mod.rs
@@ -305,6 +305,9 @@ impl SslMethod {
}
}
+unsafe impl Sync for SslMethod {}
+unsafe impl Send for SslMethod {}
+
bitflags! {
/// Options controling the behavior of certificate verification.
pub struct SslVerifyMode: i32 {
diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs
index 630f4ab6..1cb2ef81 100644
--- a/openssl/src/symm.rs
+++ b/openssl/src/symm.rs
@@ -223,6 +223,9 @@ impl Cipher {
}
}
+unsafe impl Sync for Cipher {}
+unsafe impl Send for Cipher {}
+
/// Represents a symmetric cipher context.
///
/// Padding is enabled by default.
@@ -288,6 +291,9 @@ pub struct Crypter {
block_size: usize,
}
+unsafe impl Sync for Crypter {}
+unsafe impl Send for Crypter {}
+
impl Crypter {
/// Creates a new `Crypter`. The initialisation vector, `iv`, is not necesarry for certain
/// types of `Cipher`.
@@ -963,7 +969,6 @@ mod tests {
#[test]
fn test_des_ede3_cbc() {
-
let pt = "54686973206973206120746573742e";
let ct = "6f2867cfefda048a4046ef7e556c7132";
let key = "7cb66337f3d3c0fe7cb66337f3d3c0fe7cb66337f3d3c0fe";
diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs
index a4bbb5f0..ef4b57e5 100644
--- a/openssl/src/x509/mod.rs
+++ b/openssl/src/x509/mod.rs
@@ -6,39 +6,6 @@
//! data with the included public key. `X509` certificates are used in many
//! Internet protocols, including SSL/TLS, which is the basis for HTTPS,
//! the secure protocol for browsing the web.
-//!
-//! # 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 ffi;
@@ -100,6 +67,18 @@ impl X509StoreContext {
pub fn ssl_idx() -> Result<Index<X509StoreContext, SslRef>, ErrorStack> {
unsafe { cvt_n(ffi::SSL_get_ex_data_X509_STORE_CTX_idx()).map(|idx| Index::from_raw(idx)) }
}
+
+ /// Creates a new `X509StoreContext` instance.
+ ///
+ /// 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 {
@@ -128,6 +107,68 @@ impl X509StoreContextRef {
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.
///
/// This corresponds to [`X509_STORE_CTX_set_error`].
diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs
index 6f6b430a..ecc7f7de 100644
--- a/openssl/src/x509/tests.rs
+++ b/openssl/src/x509/tests.rs
@@ -7,9 +7,10 @@ use nid::Nid;
use pkey::{PKey, Private};
use rsa::Rsa;
use stack::Stack;
-use x509::{X509, X509Name, X509Req, X509VerifyResult};
+use x509::{X509, X509Name, X509Req, X509StoreContext, X509VerifyResult};
use x509::extension::{AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage,
SubjectAlternativeName, SubjectKeyIdentifier};
+use x509::store::X509StoreBuilder;
fn pkey() -> PKey<Private> {
let rsa = Rsa::generate(2048).unwrap();
@@ -241,15 +242,11 @@ fn test_stack_from_pem() {
assert_eq!(certs.len(), 2);
assert_eq!(
- hex::encode(certs[0]
- .fingerprint(MessageDigest::sha1())
- .unwrap()),
+ hex::encode(certs[0].fingerprint(MessageDigest::sha1()).unwrap()),
"59172d9313e84459bcff27f967e79e6e9217e584"
);
assert_eq!(
- hex::encode(certs[1]
- .fingerprint(MessageDigest::sha1())
- .unwrap()),
+ hex::encode(certs[1].fingerprint(MessageDigest::sha1()).unwrap()),
"c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"
);
}
@@ -291,3 +288,46 @@ fn clone_x509() {
let cert = X509::from_pem(cert).unwrap();
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());
+}