From b022bd2d213e296ef9951b43cad842c966933e5c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Nov 2016 10:16:48 +0000 Subject: [PATCH 001/140] Don't recommend light version on Windows Closes #516 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3f17a571..0b49534c 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ brew install openssl On MSVC it's unfortunately not always a trivial process acquiring OpenSSL. Perhaps the easiest way to do this right now is to download [precompiled binaries] and install them on your system. Currently it's recommended to -install the 1.1.0b light installation if you're choosing this route. +install the 1.1.0 (non-light) installation if you're choosing this route. [precompiled binaries]: http://slproweb.com/products/Win32OpenSSL.html From 203a02c3e6472330160bb1746d46202d5e8c78fe Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Nov 2016 20:25:57 +0000 Subject: [PATCH 002/140] Actually support AES GCM This is an AEAD cipher, so we need some extra functionality. As another bonus, we no longer panic if provided an IV with a different length than the cipher's default. --- openssl-sys/src/lib.rs | 5 +++ openssl/src/symm.rs | 98 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 100 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 496cc379..70e627ca 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -114,6 +114,10 @@ pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; pub const EVP_PKEY_HMAC: c_int = NID_hmac; pub const EVP_PKEY_DSA: c_int = NID_dsa; +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_SET_TAG: c_int = 0x11; + pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; pub const MBSTRING_FLAG: c_int = 0x1000; @@ -1400,6 +1404,7 @@ extern { pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int) -> c_int; pub fn EVP_CIPHER_CTX_set_key_length(ctx: *mut EVP_CIPHER_CTX, keylen: c_int) -> c_int; + pub fn EVP_CIPHER_CTX_ctrl(ctx: *mut EVP_CIPHER_CTX, type_: c_int, arg: c_int, ptr: *mut c_void) -> c_int; pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX); pub fn EVP_CipherInit(ctx: *mut EVP_CIPHER_CTX, evp: *const EVP_CIPHER, diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index d4b15f28..0f384399 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -135,8 +135,7 @@ impl Crypter { /// /// # Panics /// - /// Panics if an IV is required by the cipher but not provided, or if the - /// IV's length does not match the expected length (see `Cipher::iv_len`). + /// Panics if an IV is required by the cipher but not provided. pub fn new(t: Cipher, mode: Mode, key: &[u8], @@ -169,7 +168,13 @@ impl Crypter { let key = key.as_ptr() as *mut _; let iv = match (iv, t.iv_len()) { (Some(iv), Some(len)) => { - assert!(iv.len() == len); + if iv.len() != len { + assert!(iv.len() <= c_int::max_value() as usize); + try!(cvt(ffi::EVP_CIPHER_CTX_ctrl(crypter.ctx, + ffi::EVP_CTRL_GCM_SET_IVLEN, + iv.len() as c_int, + ptr::null_mut()))); + } iv.as_ptr() as *mut _ } (Some(_), None) | (None, None) => ptr::null_mut(), @@ -196,6 +201,39 @@ impl Crypter { } } + /// Sets the tag used to authenticate ciphertext in AEAD ciphers such as AES GCM. + /// + /// When decrypting cipher text using an AEAD cipher, this must be called before `finalize`. + pub fn set_tag(&mut self, tag: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(tag.len() <= c_int::max_value() as usize); + // NB: this constant is actually more general than just GCM. + cvt(ffi::EVP_CIPHER_CTX_ctrl(self.ctx, + ffi::EVP_CTRL_GCM_SET_TAG, + tag.len() as c_int, + tag.as_ptr() as *mut _)) + .map(|_| ()) + } + } + + /// Feeds Additional Authenticated Data (AAD) through the cipher. + /// + /// This can only be used with AEAD ciphers such as AES GCM. Data fed in is not encrypted, but + /// is factored into the authentication tag. It must be called before the first call to + /// `update`. + pub fn aad_update(&mut self, input: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(input.len() <= c_int::max_value() as usize); + let mut len = 0; + cvt(ffi::EVP_CipherUpdate(self.ctx, + ptr::null_mut(), + &mut len, + input.as_ptr(), + input.len() as c_int)) + .map(|_| ()) + } + } + /// Feeds data from `input` through the cipher, writing encrypted/decrypted /// bytes into `output`. /// @@ -244,6 +282,21 @@ impl Crypter { Ok(outl as usize) } } + + /// Retrieves the authentication tag used to authenticate ciphertext in AEAD ciphers such + /// as AES GCM. + /// + /// When encrypting data with an AEAD cipher, this must be called after `finalize`. + pub fn get_tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(tag.len() <= c_int::max_value() as usize); + cvt(ffi::EVP_CIPHER_CTX_ctrl(self.ctx, + ffi::EVP_CTRL_GCM_GET_TAG, + tag.len() as c_int, + tag.as_mut_ptr() as *mut _)) + .map(|_| ()) + } + } } impl Drop for Crypter { @@ -319,6 +372,7 @@ use self::compat::*; #[cfg(test)] mod tests { use serialize::hex::{FromHex, ToHex}; + use super::*; // Test vectors from FIPS-197: // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf @@ -534,4 +588,42 @@ mod tests { cipher_test(super::Cipher::des_ecb(), pt, ct, key, iv); } + + #[test] + fn test_aes128_gcm() { + let key = "0e00c76561d2bd9b40c3c15427e2b08f"; + let iv = + "492cadaccd3ca3fbc9cf9f06eb3325c4e159850b0dbe98199b89b7af528806610b6f63998e1eae80c348e7\ + 4cbb921d8326631631fc6a5d304f39166daf7ea15fa1977f101819adb510b50fe9932e12c5a85aa3fd1e73\ + d8d760af218be829903a77c63359d75edd91b4f6ed5465a72662f5055999e059e7654a8edc921aa0d496"; + let pt = + "fef03c2d7fb15bf0d2df18007d99f967c878ad59359034f7bb2c19af120685d78e32f6b8b83b032019956c\ + a9c0195721476b85"; + let aad = + "d8f1163d8c840292a2b2dacf4ac7c36aff8733f18fabb4fa5594544125e03d1e6e5d6d0fd61656c8d8f327\ + c92839ae5539bb469c9257f109ebff85aad7bd220fdaa95c022dbd0c7bb2d878ad504122c943045d3c5eba\ + 8f1f56c0"; + let ct = + "4f6cf471be7cbd2575cd5a1747aea8fe9dea83e51936beac3e68f66206922060c697ffa7af80ad6bb68f2c\ + f4fc97416ee52abe"; + let tag = "e20b6655"; + + let mut crypter = Crypter::new(Cipher::aes_128_gcm(), Mode::Encrypt, &key.from_hex().unwrap(), Some(&iv.from_hex().unwrap())).unwrap(); + let mut out = [0; 1024]; + crypter.aad_update(&aad.from_hex().unwrap()).unwrap(); + let mut nwritten = crypter.update(&pt.from_hex().unwrap(), &mut out).unwrap(); + nwritten += crypter.finalize(&mut out[nwritten..]).unwrap(); + assert_eq!(ct, out[..nwritten].to_hex()); + let mut actual_tag = [0; 4]; + crypter.get_tag(&mut actual_tag).unwrap(); + assert_eq!(tag, actual_tag.to_hex()); + + let mut crypter = Crypter::new(Cipher::aes_128_gcm(), Mode::Decrypt, &key.from_hex().unwrap(), Some(&iv.from_hex().unwrap())).unwrap(); + let mut out = [0; 1024]; + crypter.aad_update(&aad.from_hex().unwrap()).unwrap(); + let mut nwritten = crypter.update(&ct.from_hex().unwrap(), &mut out).unwrap(); + crypter.set_tag(&tag.from_hex().unwrap()).unwrap(); + nwritten += crypter.finalize(&mut out[nwritten..]).unwrap(); + assert_eq!(pt, out[..nwritten].to_hex()); + } } From 913723997bc12281d2851c91f402871391810553 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Nov 2016 22:35:16 +0000 Subject: [PATCH 003/140] Add convenience functions for AEAD encryption/decryption --- openssl/src/symm.rs | 71 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 0f384399..07235e24 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -345,6 +345,48 @@ fn cipher(t: Cipher, Ok(out) } +/// Like `encrypt`, but for AEAD ciphers such as AES GCM. +/// +/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag +/// will be copied into the `tag` field. +pub fn encrypt_aead(t: Cipher, + key: &[u8], + iv: Option<&[u8]>, + aad: &[u8], + data: &[u8], + tag: &mut [u8]) + -> Result, ErrorStack> { + let mut c = try!(Crypter::new(t, Mode::Encrypt, key, iv)); + let mut out = vec![0; data.len() + t.block_size()]; + try!(c.aad_update(aad)); + let count = try!(c.update(data, &mut out)); + let rest = try!(c.finalize(&mut out[count..])); + try!(c.get_tag(tag)); + out.truncate(count + rest); + Ok(out) +} + +/// Like `decrypt`, but for AEAD ciphers such as AES GCM. +/// +/// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag +/// should be provided in the `tag` field. +pub fn decrypt_aead(t: Cipher, + key: &[u8], + iv: Option<&[u8]>, + aad: &[u8], + data: &[u8], + tag: &[u8]) + -> Result, ErrorStack> { + let mut c = try!(Crypter::new(t, Mode::Decrypt, key, iv)); + let mut out = vec![0; data.len() + t.block_size()]; + try!(c.aad_update(aad)); + let count = try!(c.update(data, &mut out)); + try!(c.set_tag(tag)); + let rest = try!(c.finalize(&mut out[count..])); + out.truncate(count + rest); + Ok(out) +} + #[cfg(ossl110)] use ffi::{EVP_CIPHER_iv_length, EVP_CIPHER_block_size, EVP_CIPHER_key_length}; @@ -608,22 +650,23 @@ mod tests { f4fc97416ee52abe"; let tag = "e20b6655"; - let mut crypter = Crypter::new(Cipher::aes_128_gcm(), Mode::Encrypt, &key.from_hex().unwrap(), Some(&iv.from_hex().unwrap())).unwrap(); - let mut out = [0; 1024]; - crypter.aad_update(&aad.from_hex().unwrap()).unwrap(); - let mut nwritten = crypter.update(&pt.from_hex().unwrap(), &mut out).unwrap(); - nwritten += crypter.finalize(&mut out[nwritten..]).unwrap(); - assert_eq!(ct, out[..nwritten].to_hex()); let mut actual_tag = [0; 4]; - crypter.get_tag(&mut actual_tag).unwrap(); + let out = encrypt_aead(Cipher::aes_128_gcm(), + &key.from_hex().unwrap(), + Some(&iv.from_hex().unwrap()), + &aad.from_hex().unwrap(), + &pt.from_hex().unwrap(), + &mut actual_tag) + .unwrap(); + assert_eq!(ct, out.to_hex()); assert_eq!(tag, actual_tag.to_hex()); - let mut crypter = Crypter::new(Cipher::aes_128_gcm(), Mode::Decrypt, &key.from_hex().unwrap(), Some(&iv.from_hex().unwrap())).unwrap(); - let mut out = [0; 1024]; - crypter.aad_update(&aad.from_hex().unwrap()).unwrap(); - let mut nwritten = crypter.update(&ct.from_hex().unwrap(), &mut out).unwrap(); - crypter.set_tag(&tag.from_hex().unwrap()).unwrap(); - nwritten += crypter.finalize(&mut out[nwritten..]).unwrap(); - assert_eq!(pt, out[..nwritten].to_hex()); + let out = decrypt_aead(Cipher::aes_128_gcm(), + &key.from_hex().unwrap(), + Some(&iv.from_hex().unwrap()), + &aad.from_hex().unwrap(), + &ct.from_hex().unwrap(), + &tag.from_hex().unwrap()).unwrap(); + assert_eq!(pt, out.to_hex()); } } From aa7c27536ad56def21afad4043d6d658f517ecc4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Nov 2016 22:38:48 +0000 Subject: [PATCH 004/140] Make sure to override SslContext verify callback always The 1.0.1 code has to override this to setup hostname validation, and don't want behavior to silently change depending on the OpenSSL version you're building against. --- openssl/src/ssl/connector.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 55177767..c5189c9e 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -255,7 +255,9 @@ impl SslAcceptor { #[cfg(any(ossl102, ossl110))] fn setup_verify(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { - ssl.set_verify(SSL_VERIFY_PEER); + // pass a noop closure in here to ensure that we consistently override any callback on the + // context + ssl.set_verify_callback(SSL_VERIFY_PEER, |p, _| p); let param = ssl._param_mut(); param.set_hostflags(::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS); param.set_host(domain) From 7c8ae5f664ee9d36cc42527208362c9bfe5b25ab Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Nov 2016 18:54:29 +0000 Subject: [PATCH 005/140] Better docs for AEAD tag --- openssl/src/symm.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 07235e24..6e9c5796 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -287,6 +287,10 @@ impl Crypter { /// as AES GCM. /// /// When encrypting data with an AEAD cipher, this must be called after `finalize`. + /// + /// The size of the buffer indicates the required size of the tag. While some ciphers support a + /// range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 + /// bytes, for example. pub fn get_tag(&self, tag: &mut [u8]) -> Result<(), ErrorStack> { unsafe { assert!(tag.len() <= c_int::max_value() as usize); @@ -370,6 +374,10 @@ pub fn encrypt_aead(t: Cipher, /// /// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag /// should be provided in the `tag` field. +/// +/// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support +/// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes, +/// for example. pub fn decrypt_aead(t: Cipher, key: &[u8], iv: Option<&[u8]>, @@ -650,6 +658,8 @@ mod tests { f4fc97416ee52abe"; let tag = "e20b6655"; + // this tag is smaller than you'd normally want, but I pulled this test from the part of + // the NIST test vectors that cover 4 byte tags. let mut actual_tag = [0; 4]; let out = encrypt_aead(Cipher::aes_128_gcm(), &key.from_hex().unwrap(), From a42c6e8713702175001686c6f146bb4b99023613 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Nov 2016 20:35:23 +0000 Subject: [PATCH 006/140] Drop rustc-serialize dependency --- openssl/Cargo.toml | 2 +- openssl/src/hash.rs | 12 ++++++------ openssl/src/lib.rs | 3 +-- openssl/src/pkcs12.rs | 2 +- openssl/src/sign.rs | 34 +++++++++++++++++----------------- openssl/src/ssl/tests/mod.rs | 9 ++++----- openssl/src/symm.rs | 30 ++++++++++++++---------------- openssl/src/x509/tests.rs | 4 ++-- 8 files changed, 46 insertions(+), 50 deletions(-) diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 1417bea7..ef2443aa 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -23,7 +23,7 @@ libc = "0.2" openssl-sys = { version = "0.9", path = "../openssl-sys" } [dev-dependencies] -rustc-serialize = "0.3" tempdir = "0.3" winapi = "0.2" ws2_32-sys = "0.2" +hex = "0.2" diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index 6a13371d..1d2089ef 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -208,17 +208,17 @@ pub fn hash(t: MessageDigest, data: &[u8]) -> Result, ErrorStack> { #[cfg(test)] mod tests { - use serialize::hex::{FromHex, ToHex}; + use hex::{FromHex, ToHex}; use super::{hash, Hasher, MessageDigest}; use std::io::prelude::*; fn hash_test(hashtype: MessageDigest, hashtest: &(&str, &str)) { - let res = hash(hashtype, &*hashtest.0.from_hex().unwrap()).unwrap(); + let res = hash(hashtype, &Vec::from_hex(hashtest.0).unwrap()).unwrap(); assert_eq!(res.to_hex(), hashtest.1); } fn hash_recycle_test(h: &mut Hasher, hashtest: &(&str, &str)) { - let _ = h.write_all(&*hashtest.0.from_hex().unwrap()).unwrap(); + let _ = h.write_all(&Vec::from_hex(hashtest.0).unwrap()).unwrap(); let res = h.finish().unwrap(); assert_eq!(res.to_hex(), hashtest.1); } @@ -258,7 +258,7 @@ mod tests { #[test] fn test_finish_twice() { let mut h = Hasher::new(MessageDigest::md5()).unwrap(); - h.write_all(&*md5_tests[6].0.from_hex().unwrap()).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(); @@ -268,7 +268,7 @@ mod tests { #[test] fn test_clone() { let i = 7; - let inp = md5_tests[i].0.from_hex().unwrap(); + 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(); @@ -289,7 +289,7 @@ mod tests { println!("Clone a finished hasher"); let mut h3 = h1.clone(); - h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()).unwrap(); + h3.write_all(&Vec::from_hex(md5_tests[i + 1].0).unwrap()).unwrap(); let res = h3.finish().unwrap(); assert_eq!(res.to_hex(), md5_tests[i + 1].1); } diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index a9d937ba..51097733 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -8,8 +8,7 @@ extern crate lazy_static; extern crate openssl_sys as ffi; #[cfg(test)] -extern crate rustc_serialize as serialize; - +extern crate hex; #[cfg(test)] extern crate tempdir; diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index 1ef0bf3f..9c224ccd 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -66,7 +66,7 @@ pub struct ParsedPkcs12 { #[cfg(test)] mod test { use hash::MessageDigest; - use serialize::hex::ToHex; + use hex::ToHex; use super::*; diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index 4ca551b6..679a30aa 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -205,7 +205,7 @@ unsafe fn EVP_DigestVerifyFinal(ctx: *mut ffi::EVP_MD_CTX, #[cfg(test)] mod test { - use serialize::hex::FromHex; + use hex::FromHex; use std::iter; use hash::MessageDigest; @@ -339,27 +339,27 @@ mod test { let tests: [(Vec, Vec, Vec); 7] = [(iter::repeat(0x0b_u8).take(16).collect(), b"Hi There".to_vec(), - "9294727a3638bb1c13f48ef8158bfc9d".from_hex().unwrap()), + Vec::from_hex("9294727a3638bb1c13f48ef8158bfc9d").unwrap()), (b"Jefe".to_vec(), b"what do ya want for nothing?".to_vec(), - "750c783e6ab0b503eaa86e310a5db738".from_hex().unwrap()), + Vec::from_hex("750c783e6ab0b503eaa86e310a5db738").unwrap()), (iter::repeat(0xaa_u8).take(16).collect(), iter::repeat(0xdd_u8).take(50).collect(), - "56be34521d144c88dbb8c733f0e8b3f6".from_hex().unwrap()), - ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(), + Vec::from_hex("56be34521d144c88dbb8c733f0e8b3f6").unwrap()), + (Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(), iter::repeat(0xcd_u8).take(50).collect(), - "697eaf0aca3a3aea3a75164746ffaa79".from_hex().unwrap()), + Vec::from_hex("697eaf0aca3a3aea3a75164746ffaa79").unwrap()), (iter::repeat(0x0c_u8).take(16).collect(), b"Test With Truncation".to_vec(), - "56461ef2342edc00f9bab995690efd4c".from_hex().unwrap()), + 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(), - "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap()), + 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(), - "6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())]; + Vec::from_hex("6f630fad67cda0ee1fb1f562db3aa53e").unwrap())]; test_hmac(MessageDigest::md5(), &tests); } @@ -370,27 +370,27 @@ mod test { let tests: [(Vec, Vec, Vec); 7] = [(iter::repeat(0x0b_u8).take(20).collect(), b"Hi There".to_vec(), - "b617318655057264e28bc0b6fb378c8ef146be00".from_hex().unwrap()), + Vec::from_hex("b617318655057264e28bc0b6fb378c8ef146be00").unwrap()), (b"Jefe".to_vec(), b"what do ya want for nothing?".to_vec(), - "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79".from_hex().unwrap()), + Vec::from_hex("effcdf6ae5eb2fa2d27416d5f184df9c259a7c79").unwrap()), (iter::repeat(0xaa_u8).take(20).collect(), iter::repeat(0xdd_u8).take(50).collect(), - "125d7342b9ac11cd91a39af48aa17b4f63f175d3".from_hex().unwrap()), - ("0102030405060708090a0b0c0d0e0f10111213141516171819".from_hex().unwrap(), + Vec::from_hex("125d7342b9ac11cd91a39af48aa17b4f63f175d3").unwrap()), + (Vec::from_hex("0102030405060708090a0b0c0d0e0f10111213141516171819").unwrap(), iter::repeat(0xcd_u8).take(50).collect(), - "4c9007f4026250c6bc8414f9bf50c86c2d7235da".from_hex().unwrap()), + Vec::from_hex("4c9007f4026250c6bc8414f9bf50c86c2d7235da").unwrap()), (iter::repeat(0x0c_u8).take(20).collect(), b"Test With Truncation".to_vec(), - "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04".from_hex().unwrap()), + 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(), - "aa4ae5e15272d00e95705637ce8a3b55ed402112".from_hex().unwrap()), + 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(), - "e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())]; + Vec::from_hex("e8e99d0f45237d786d6bbaa7965c7808bbff1a91").unwrap())]; test_hmac(MessageDigest::sha1(), &tests); } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 146d0806..96c0d585 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -11,7 +11,6 @@ use std::path::Path; use std::process::{Command, Child, Stdio, ChildStdin}; use std::thread; use std::time::Duration; - use tempdir::TempDir; use hash::MessageDigest; @@ -170,7 +169,7 @@ macro_rules! run_test( use ssl::SSL_VERIFY_PEER; use hash::MessageDigest; use x509::X509StoreContext; - use serialize::hex::FromHex; + use hex::FromHex; use types::OpenSslTypeRef; use super::Server; @@ -302,7 +301,7 @@ run_test!(verify_callback_data, |method, stream| { // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 // Please update if "test/cert.pem" will ever change let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = node_hash_str.from_hex().unwrap(); + let node_id = Vec::from_hex(node_hash_str).unwrap(); ctx.set_verify_callback(SSL_VERIFY_PEER, move |_preverify_ok, x509_ctx| { let cert = x509_ctx.current_cert(); match cert { @@ -330,7 +329,7 @@ run_test!(ssl_verify_callback, |method, stream| { let mut ssl = Ssl::new(&ctx.build()).unwrap(); let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = node_hash_str.from_hex().unwrap(); + let node_id = Vec::from_hex(node_hash_str).unwrap(); ssl.set_verify_callback(SSL_VERIFY_PEER, move |_, x509| { CHECKED.store(1, Ordering::SeqCst); match x509.current_cert() { @@ -427,7 +426,7 @@ run_test!(get_peer_certificate, |method, stream| { let cert = stream.ssl().peer_certificate().unwrap(); let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let node_id = node_hash_str.from_hex().unwrap(); + let node_id = Vec::from_hex(node_hash_str).unwrap(); assert_eq!(node_id, fingerprint) }); diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 6e9c5796..f94a8d70 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -421,7 +421,7 @@ use self::compat::*; #[cfg(test)] mod tests { - use serialize::hex::{FromHex, ToHex}; + use hex::{FromHex, ToHex}; use super::*; // Test vectors from FIPS-197: @@ -489,12 +489,10 @@ mod tests { } fn cipher_test(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) { - use serialize::hex::ToHex; - - let pt = pt.from_hex().unwrap(); - let ct = ct.from_hex().unwrap(); - let key = key.from_hex().unwrap(); - let iv = iv.from_hex().unwrap(); + let pt = Vec::from_hex(pt).unwrap(); + let ct = Vec::from_hex(ct).unwrap(); + let key = Vec::from_hex(key).unwrap(); + let iv = Vec::from_hex(iv).unwrap(); let computed = super::decrypt(ciphertype, &key, Some(&iv), &ct).unwrap(); let expected = pt; @@ -662,21 +660,21 @@ mod tests { // the NIST test vectors that cover 4 byte tags. let mut actual_tag = [0; 4]; let out = encrypt_aead(Cipher::aes_128_gcm(), - &key.from_hex().unwrap(), - Some(&iv.from_hex().unwrap()), - &aad.from_hex().unwrap(), - &pt.from_hex().unwrap(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), &mut actual_tag) .unwrap(); assert_eq!(ct, out.to_hex()); assert_eq!(tag, actual_tag.to_hex()); let out = decrypt_aead(Cipher::aes_128_gcm(), - &key.from_hex().unwrap(), - Some(&iv.from_hex().unwrap()), - &aad.from_hex().unwrap(), - &ct.from_hex().unwrap(), - &tag.from_hex().unwrap()).unwrap(); + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap()).unwrap(); assert_eq!(pt, out.to_hex()); } } diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 2527d538..16ad661d 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1,4 +1,4 @@ -use serialize::hex::FromHex; +use hex::FromHex; use hash::MessageDigest; use pkey::PKey; @@ -85,7 +85,7 @@ fn test_cert_loading() { let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; - let hash_vec = hash_str.from_hex().unwrap(); + let hash_vec = Vec::from_hex(hash_str).unwrap(); assert_eq!(fingerprint, hash_vec); } From 374144807f641437ba628112e9e1b6f2fffe0933 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Nov 2016 20:50:09 +0000 Subject: [PATCH 007/140] Bump minimum version rustc-serialize dropped 1.9 support --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 55ba716d..e1258da9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ matrix: - binfmt-support # Minimum version supported - - rust: 1.9.0 + - rust: 1.10.0 # beta/nightly channels - rust: beta From ee5ad0b257986f4ec48f61e7f334f88e2a1a6f79 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 08:17:05 +0000 Subject: [PATCH 008/140] Update to 1.1.0c for tests --- .travis.yml | 6 +++--- appveyor.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index e1258da9..61b1a14d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ matrix: - binfmt-support - env: > TARGET=arm-unknown-linux-gnueabihf - BUILD_OPENSSL_VERSION=1.1.0b + BUILD_OPENSSL_VERSION=1.1.0c CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf RUST_TEST_THREADS=1 @@ -46,7 +46,7 @@ matrix: # 64-bit version compat - env: BUILD_OPENSSL_VERSION=1.0.2h - - env: BUILD_OPENSSL_VERSION=1.1.0b + - env: BUILD_OPENSSL_VERSION=1.1.0c # 32-bit version compat - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u @@ -59,7 +59,7 @@ matrix: apt: packages: - gcc-multilib - - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0b + - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0c addons: apt: packages: diff --git a/appveyor.yml b/appveyor.yml index 3e23044e..9b4a3f02 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,10 +5,10 @@ environment: - TARGET: i686-pc-windows-gnu BITS: 32 MSYS2: 1 - OPENSSL_VERSION: 1_1_0b + OPENSSL_VERSION: 1_1_0c - TARGET: x86_64-pc-windows-msvc BITS: 64 - OPENSSL_VERSION: 1_1_0b + OPENSSL_VERSION: 1_1_0c OPENSSL_DIR: C:\OpenSSL # 1.0.2, 64/32 bit From 898e7f02df5ca722f4b4b42a8e116f96f72b9452 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 15:10:30 +0000 Subject: [PATCH 009/140] Fix EOF detection See https://github.com/openssl/openssl/issues/1903 for details --- openssl/src/ssl/mod.rs | 54 +++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 1e7efc63..c92bf56b 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1323,10 +1323,14 @@ impl SslStream { /// value will identify if OpenSSL is waiting on read or write readiness. pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { let ret = self.ssl.read(buf); - if ret >= 0 { + if ret > 0 { Ok(ret as usize) } else { - Err(self.make_error(ret)) + match self.make_error(ret) { + // Don't treat unexpected EOFs as errors when reading + Error::Stream(ref e) if e.kind() == io::ErrorKind::ConnectionAborted => Ok(0), + e => Err(e), + } } } @@ -1336,7 +1340,7 @@ impl SslStream { /// value will identify if OpenSSL is waiting on read or write readiness. pub fn ssl_write(&mut self, buf: &[u8]) -> Result { let ret = self.ssl.write(buf); - if ret >= 0 { + if ret > 0 { Ok(ret as usize) } else { Err(self.make_error(ret)) @@ -1373,19 +1377,38 @@ impl SslStream { ffi::SSL_ERROR_SYSCALL => { let errs = ErrorStack::get(); if errs.errors().is_empty() { - if ret == 0 { - Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted, - "unexpected EOF observed")) - } else { - Error::Stream(self.get_bio_error()) + match self.get_bio_error() { + Some(err) => Error::Stream(err), + None => { + Error::Stream(io::Error::new(io::ErrorKind::ConnectionAborted, + "unexpected EOF observed")) + } } } else { Error::Ssl(errs) } } ffi::SSL_ERROR_ZERO_RETURN => Error::ZeroReturn, - ffi::SSL_ERROR_WANT_WRITE => Error::WantWrite(self.get_bio_error()), - ffi::SSL_ERROR_WANT_READ => Error::WantRead(self.get_bio_error()), + ffi::SSL_ERROR_WANT_WRITE => { + let err = match self.get_bio_error() { + Some(err) => err, + None => { + io::Error::new(io::ErrorKind::Other, + "BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO") + } + }; + Error::WantWrite(err) + }, + ffi::SSL_ERROR_WANT_READ => { + let err = match self.get_bio_error() { + Some(err) => err, + None => { + io::Error::new(io::ErrorKind::Other, + "BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO") + } + }; + Error::WantRead(err) + }, err => { Error::Stream(io::Error::new(io::ErrorKind::InvalidData, format!("unexpected error {}", err))) @@ -1399,15 +1422,8 @@ impl SslStream { } } - fn get_bio_error(&mut self) -> io::Error { - let error = unsafe { bio::take_error::(self.ssl.get_raw_rbio()) }; - match error { - Some(error) => error, - None => { - io::Error::new(io::ErrorKind::Other, - "BUG: got an ErrorSyscall without an error in the BIO?") - } - } + fn get_bio_error(&mut self) -> Option { + unsafe { bio::take_error::(self.ssl.get_raw_rbio()) } } /// Returns a reference to the underlying stream. From 2dbe27d4b0782e7269656934658fb94bc97e9485 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 15:41:55 +0000 Subject: [PATCH 010/140] Move osx builds to top of list They take the longest, so let's get them going early on. --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 61b1a14d..314ee4ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,13 @@ env: - BUILD_OPENSSL_VERSION=1.0.1u matrix: include: + # osx 32/64 + - os: osx + env: TARGET=x86_64-apple-darwin + - os: osx + env: TARGET=i686-apple-darwin + install: brew uninstall openssl && brew install openssl --universal + # ARM-bit version compat - env: > TARGET=arm-unknown-linux-gnueabihf @@ -65,13 +72,6 @@ matrix: packages: - gcc-multilib - # osx 32/64 - - os: osx - env: TARGET=x86_64-apple-darwin - - os: osx - env: TARGET=i686-apple-darwin - install: brew uninstall openssl && brew install openssl --universal - before_install: - ./openssl/test/build.sh From 95ae05c8a1f3903dbc4e9998618e5a966defdc78 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 15:42:51 +0000 Subject: [PATCH 011/140] Don't test 32 bit osx openssl install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 314ee4ef..1b79c5b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ matrix: env: TARGET=x86_64-apple-darwin - os: osx env: TARGET=i686-apple-darwin - install: brew uninstall openssl && brew install openssl --universal + install: brew uninstall openssl && brew install openssl --universal --without-test # ARM-bit version compat - env: > From 0d2d4865e5d98dcc19968b8428a7aee2a747091a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 16:44:19 +0000 Subject: [PATCH 012/140] Release v0.9.1 --- README.md | 8 ++++---- openssl-sys/Cargo.toml | 2 +- openssl-sys/src/lib.rs | 2 +- openssl/Cargo.toml | 4 ++-- openssl/src/lib.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 0b49534c..e297fcf9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) -[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl). +[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.9.1/openssl). ## Warning @@ -37,9 +37,9 @@ compiling to a separate target, you'll typically need to compile OpenSSL from source. That can normally be done with: ``` -curl -O https://www.openssl.org/source/openssl-1.1.0b.tar.gz -tar xf openssl-1.1.0b.tar.gz -cd openssl-1.1.0b +curl -O https://www.openssl.org/source/openssl-1.1.0c.tar.gz +tar xf openssl-1.1.0c.tar.gz +cd openssl-1.1.0c export CC=... ./Configure --prefix=... linux-x86_64 -fPIC make -j$(nproc) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 11c20a1c..094cd094 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-sys" -version = "0.9.0" +version = "0.9.1" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 70e627ca..4a10dd34 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code, overflowing_literals)] -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.0")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.1")] extern crate libc; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index ef2443aa..050b99e1 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.9.0" +version = "0.9.1" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" @@ -20,7 +20,7 @@ v110 = [] bitflags = "0.7" lazy_static = "0.2" libc = "0.2" -openssl-sys = { version = "0.9", path = "../openssl-sys" } +openssl-sys = { version = "0.9.1", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 51097733..d3f99de7 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.0")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.1")] #[macro_use] extern crate bitflags; From 609a09ebb90cf44524ce299b968ce19173583ce8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 18:52:27 +0000 Subject: [PATCH 013/140] Add PKey::dsa Closes #501 --- openssl-sys/src/lib.rs | 1 + openssl/src/pkey.rs | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 4a10dd34..d8743859 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1455,6 +1455,7 @@ extern { pub fn EVP_PKEY_copy_parameters(to: *mut EVP_PKEY, from: *const EVP_PKEY) -> c_int; pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; + pub fn EVP_PKEY_get1_DSA(k: *mut EVP_PKEY) -> *mut DSA; pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int; pub fn EVP_PKEY_new_mac_key(type_: c_int, e: *mut ENGINE, diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index a1ebd695..24f4b308 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -14,15 +14,22 @@ use types::{OpenSslType, OpenSslTypeRef}; type_!(PKey, PKeyRef, ffi::EVP_PKEY, ffi::EVP_PKEY_free); impl PKeyRef { - /// Get a reference to the interal RSA key for direct access to the key components + /// Returns a copy of the internal RSA key. pub fn rsa(&self) -> Result { unsafe { let rsa = try!(cvt_p(ffi::EVP_PKEY_get1_RSA(self.as_ptr()))); - // this is safe as the ffi increments a reference counter to the internal key Ok(Rsa::from_ptr(rsa)) } } + /// Returns a copy of the internal DSA key. + pub fn dsa(&self) -> Result { + unsafe { + let dsa = try!(cvt_p(ffi::EVP_PKEY_get1_DSA(self.as_ptr()))); + Ok(Dsa::from_ptr(dsa)) + } + } + /// Stores private key as a PEM // FIXME: also add password and encryption pub fn private_key_to_pem(&self) -> Result, ErrorStack> { @@ -150,22 +157,27 @@ impl PKey { #[cfg(test)] mod tests { + use rsa::Rsa; + use dsa::Dsa; + + use super::*; + #[test] fn test_private_key_from_pem() { let key = include_bytes!("../test/key.pem"); - super::PKey::private_key_from_pem(key).unwrap(); + PKey::private_key_from_pem(key).unwrap(); } #[test] fn test_public_key_from_pem() { let key = include_bytes!("../test/key.pem.pub"); - super::PKey::public_key_from_pem(key).unwrap(); + PKey::public_key_from_pem(key).unwrap(); } #[test] fn test_pem() { let key = include_bytes!("../test/key.pem"); - let key = super::PKey::private_key_from_pem(key).unwrap(); + let key = PKey::private_key_from_pem(key).unwrap(); let priv_key = key.private_key_to_pem().unwrap(); let pub_key = key.public_key_to_pem().unwrap(); @@ -175,4 +187,20 @@ mod tests { assert!(priv_key.windows(11).any(|s| s == b"PRIVATE KEY")); assert!(pub_key.windows(10).any(|s| s == b"PUBLIC KEY")); } + + #[test] + fn test_rsa_accessor() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + pkey.rsa().unwrap(); + assert!(pkey.dsa().is_err()); + } + + #[test] + fn test_dsa_accessor() { + let dsa = Dsa::generate(2048).unwrap(); + let pkey = PKey::from_dsa(dsa).unwrap(); + pkey.dsa().unwrap(); + assert!(pkey.rsa().is_err()); + } } From 32cbed0782d47b036938316805f63ed6cc2ea759 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 19:04:54 +0000 Subject: [PATCH 014/140] PKey <-> DH conversions Closes #498 --- openssl-sys/src/lib.rs | 2 ++ openssl/src/pkey.rs | 38 ++++++++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index d8743859..16ba529e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -113,6 +113,7 @@ pub const EVP_MAX_MD_SIZE: c_uint = 64; pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; pub const EVP_PKEY_HMAC: c_int = NID_hmac; pub const EVP_PKEY_DSA: c_int = NID_dsa; +pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9; pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10; @@ -1456,6 +1457,7 @@ extern { pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; pub fn EVP_PKEY_get1_DSA(k: *mut EVP_PKEY) -> *mut DSA; + pub fn EVP_PKEY_get1_DH(k: *mut EVP_PKEY) -> *mut DH; pub fn EVP_PKEY_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int; pub fn EVP_PKEY_new_mac_key(type_: c_int, e: *mut ENGINE, diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 24f4b308..72e73017 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -5,6 +5,7 @@ use ffi; use {cvt, cvt_p}; use bio::{MemBio, MemBioSlice}; +use dh::Dh; use dsa::Dsa; use rsa::Rsa; use error::ErrorStack; @@ -30,6 +31,14 @@ impl PKeyRef { } } + /// Returns a copy of the internal DH key. + pub fn dh(&self) -> Result { + unsafe { + let dh = try!(cvt_p(ffi::EVP_PKEY_get1_DH(self.as_ptr()))); + Ok(Dh::from_ptr(dh)) + } + } + /// Stores private key as a PEM // FIXME: also add password and encryption pub fn private_key_to_pem(&self) -> Result, ErrorStack> { @@ -74,7 +83,7 @@ unsafe impl Send for PKey {} unsafe impl Sync for PKey {} impl PKey { - /// Create a new `PKey` containing an RSA key. + /// Creates a new `PKey` containing an RSA key. pub fn from_rsa(rsa: Rsa) -> Result { unsafe { let evp = try!(cvt_p(ffi::EVP_PKEY_new())); @@ -85,7 +94,7 @@ impl PKey { } } - /// Create a new `PKey` containing a DSA key. + /// Creates a new `PKey` containing a DSA key. pub fn from_dsa(dsa: Dsa) -> Result { unsafe { let evp = try!(cvt_p(ffi::EVP_PKEY_new())); @@ -96,7 +105,18 @@ impl PKey { } } - /// Create a new `PKey` containing an HMAC key. + /// Creates a new `PKey` containing a DH key. + pub fn from_dh(dh: Dh) -> Result { + unsafe { + let evp = try!(cvt_p(ffi::EVP_PKEY_new())); + let pkey = PKey(evp); + try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_DH, dh.as_ptr() as *mut _))); + mem::forget(dh); + Ok(pkey) + } + } + + /// Creates a new `PKey` containing an HMAC key. pub fn hmac(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize); @@ -157,8 +177,9 @@ impl PKey { #[cfg(test)] mod tests { - use rsa::Rsa; + use dh::Dh; use dsa::Dsa; + use rsa::Rsa; use super::*; @@ -203,4 +224,13 @@ mod tests { pkey.dsa().unwrap(); assert!(pkey.rsa().is_err()); } + + #[test] + fn test_dh_accessor() { + let dh = include_bytes!("../test/dhparams.pem"); + let dh = Dh::from_pem(dh).unwrap(); + let pkey = PKey::from_dh(dh).unwrap(); + pkey.dh().unwrap(); + assert!(pkey.rsa().is_err()); + } } From 15490a43e399ce0f6e3838c96c609abf08b1c5db Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 19:17:26 +0000 Subject: [PATCH 015/140] Add EcKey <-> PKey conversions Closes #499 --- openssl-sys/src/lib.rs | 2 ++ openssl/src/ec_key.rs | 7 +++++-- openssl/src/pkey.rs | 32 +++++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 16ba529e..bdfe9b8c 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -114,6 +114,7 @@ pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; pub const EVP_PKEY_HMAC: c_int = NID_hmac; pub const EVP_PKEY_DSA: c_int = NID_dsa; pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; +pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey; pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9; pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10; @@ -1458,6 +1459,7 @@ extern { pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; pub fn EVP_PKEY_get1_DSA(k: *mut EVP_PKEY) -> *mut DSA; 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_cmp(a: *const EVP_PKEY, b: *const EVP_PKEY) -> c_int; pub fn EVP_PKEY_new_mac_key(type_: c_int, e: *mut ENGINE, diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 41501c14..ad85dc5e 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -1,6 +1,6 @@ use ffi; -use cvt_p; +use {cvt_p, init}; use error::ErrorStack; use nid::Nid; @@ -8,7 +8,10 @@ type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); impl EcKey { pub fn new_by_curve_name(nid: Nid) -> Result { - unsafe { cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) } + unsafe { + init(); + cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) + } } } diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 72e73017..f424e337 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -7,6 +7,7 @@ use {cvt, cvt_p}; use bio::{MemBio, MemBioSlice}; use dh::Dh; use dsa::Dsa; +use ec_key::EcKey; use rsa::Rsa; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb}; @@ -39,6 +40,14 @@ impl PKeyRef { } } + /// Returns a copy of the internal elliptic curve key. + pub fn ec_key(&self) -> Result { + unsafe { + let ec_key = try!(cvt_p(ffi::EVP_PKEY_get1_EC_KEY(self.as_ptr()))); + Ok(EcKey::from_ptr(ec_key)) + } + } + /// Stores private key as a PEM // FIXME: also add password and encryption pub fn private_key_to_pem(&self) -> Result, ErrorStack> { @@ -105,7 +114,7 @@ impl PKey { } } - /// Creates a new `PKey` containing a DH key. + /// Creates a new `PKey` containing a Diffie-Hellman key. pub fn from_dh(dh: Dh) -> Result { unsafe { let evp = try!(cvt_p(ffi::EVP_PKEY_new())); @@ -116,6 +125,17 @@ impl PKey { } } + /// Creates a new `PKey` containing an elliptic curve key. + pub fn from_ec_key(ec_key: EcKey) -> Result { + unsafe { + let evp = try!(cvt_p(ffi::EVP_PKEY_new())); + let pkey = PKey(evp); + try!(cvt(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_EC, ec_key.as_ptr() as *mut _))); + mem::forget(ec_key); + Ok(pkey) + } + } + /// Creates a new `PKey` containing an HMAC key. pub fn hmac(key: &[u8]) -> Result { unsafe { @@ -179,7 +199,9 @@ impl PKey { mod tests { use dh::Dh; use dsa::Dsa; + use ec_key::EcKey; use rsa::Rsa; + use nid; use super::*; @@ -233,4 +255,12 @@ mod tests { pkey.dh().unwrap(); assert!(pkey.rsa().is_err()); } + + #[test] + fn test_ec_key_accessor() { + let ec_key = EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + pkey.ec_key().unwrap(); + assert!(pkey.rsa().is_err()); + } } From 6b7279eb5224a422860d0adb38becd5bca19763f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 19:49:00 +0000 Subject: [PATCH 016/140] Consistently support both PEM and DER encodings Closes #500 --- openssl-sys/src/lib.rs | 9 ++++++++ openssl/src/dh.rs | 48 +++++++++++++++++++++++++++++++++-------- openssl/src/dsa.rs | 49 ++++++++++++++++++++++++++++++++++++++---- openssl/src/pkey.rs | 19 +++++++++++----- openssl/src/rsa.rs | 47 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 153 insertions(+), 19 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index bdfe9b8c..7b94361b 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1713,11 +1713,20 @@ extern { name: *const c_char, namelen: size_t) -> c_int; + pub fn d2i_DHparams(k: *mut *mut DH, pp: *mut *const c_uchar, length: c_long) -> *mut DH; + pub fn i2d_DHparams(dh: *const DH, pp: *mut *mut c_uchar) -> c_int; + + pub fn d2i_DSAPublicKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA; + pub fn i2d_DSAPublicKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; + pub fn d2i_DSAPrivateKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA; + pub fn i2d_DSAPrivateKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; + pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509; pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int; pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int; pub fn i2d_PUBKEY_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int; + pub fn i2d_PrivateKey_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int; pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *mut *mut u8) -> c_int; pub fn d2i_RSA_PUBKEY(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index 5a07e50f..ad1ebf9f 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -1,11 +1,12 @@ -use ffi; use error::ErrorStack; -use bio::MemBioSlice; -use std::ptr; +use ffi; +use libc::c_long; +use std::cmp; use std::mem; +use std::ptr; -use {cvt, cvt_p}; -use bio::MemBio; +use {cvt, cvt_p, init}; +use bio::{MemBio, MemBioSlice}; use bn::BigNum; use types::OpenSslTypeRef; @@ -15,18 +16,27 @@ impl DhRef { /// Encodes the parameters to PEM. pub fn to_pem(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); - unsafe { try!(cvt(ffi::PEM_write_bio_DHparams(mem_bio.as_ptr(), self.as_ptr()))); } - Ok(mem_bio.get_buf().to_owned()) } + + /// Encodes the parameters to DER. + pub fn to_der(&self) -> Result, ErrorStack> { + unsafe { + let len = try!(cvt(ffi::i2d_DHparams(self.as_ptr(), ptr::null_mut()))); + let mut buf = vec![0; len as usize]; + try!(cvt(ffi::i2d_DHparams(self.as_ptr(), &mut buf.as_mut_ptr()))); + Ok(buf) + } + } } impl Dh { pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result { unsafe { + init(); let dh = Dh(try!(cvt_p(ffi::DH_new()))); try!(cvt(compat::DH_set0_pqg(dh.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))); mem::forget((p, g, q)); @@ -34,9 +44,11 @@ impl Dh { } } + /// Reads Diffie-Hellman parameters from PEM. pub fn from_pem(buf: &[u8]) -> Result { - let mem_bio = try!(MemBioSlice::new(buf)); unsafe { + init(); + let mem_bio = try!(MemBioSlice::new(buf)); cvt_p(ffi::PEM_read_bio_DHparams(mem_bio.as_ptr(), ptr::null_mut(), None, @@ -45,6 +57,16 @@ impl Dh { } } + /// Reads Diffie-Hellman parameters from DER. + pub fn from_der(buf: &[u8]) -> Result { + unsafe { + init(); + let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; + let dh = try!(cvt_p(ffi::d2i_DHparams(ptr::null_mut(), &mut buf.as_ptr(), len))); + Ok(Dh(dh)) + } + } + /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] pub fn get_1024_160() -> Result { @@ -139,7 +161,15 @@ mod tests { fn test_dh_from_pem() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); let params = include_bytes!("../test/dhparams.pem"); - let dh = Dh::from_pem(params).ok().expect("Failed to load PEM"); + let dh = Dh::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::from_pem(params).unwrap(); + let der = dh.to_der().unwrap(); + Dh::from_der(&der).unwrap(); + } } diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 9dd5669c..81e551ab 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -1,8 +1,9 @@ use error::ErrorStack; use ffi; -use libc::{c_int, c_char, c_void}; +use libc::{c_int, c_char, c_void, c_long}; use std::fmt; use std::ptr; +use std::cmp; use bio::{MemBio, MemBioSlice}; use bn::BigNumRef; @@ -13,7 +14,7 @@ use util::{CallbackState, invoke_passwd_cb}; type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free); impl DsaRef { - /// Writes an DSA private key as unencrypted PEM formatted data + /// Encodes a DSA private key as unencrypted PEM formatted data. pub fn private_key_to_pem(&self) -> Result, ErrorStack> { assert!(self.has_private_key()); let mem_bio = try!(MemBio::new()); @@ -27,7 +28,7 @@ impl DsaRef { Ok(mem_bio.get_buf().to_owned()) } - /// Writes an DSA public key as PEM formatted data + /// Encodes a DSA public key as PEM formatted data. pub fn public_key_to_pem(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { @@ -36,6 +37,26 @@ impl DsaRef { Ok(mem_bio.get_buf().to_owned()) } + /// Encodes a DSA private key as unencrypted DER formatted data. + pub fn private_key_to_der(&self) -> Result, ErrorStack> { + unsafe { + let len = try!(cvt(ffi::i2d_DSAPrivateKey(self.as_ptr(), ptr::null_mut()))); + let mut buf = vec![0; len as usize]; + try!(cvt(ffi::i2d_DSAPrivateKey(self.as_ptr(), &mut buf.as_mut_ptr()))); + Ok(buf) + } + } + + /// Encodes a DSA public key as DER formatted data. + pub fn public_key_to_der(&self) -> Result, ErrorStack> { + unsafe { + let len = try!(cvt(ffi::i2d_DSAPublicKey(self.as_ptr(), ptr::null_mut()))); + let mut buf = vec![0; len as usize]; + try!(cvt(ffi::i2d_DSAPublicKey(self.as_ptr(), &mut buf.as_mut_ptr()))); + Ok(buf) + } + } + pub fn size(&self) -> Option { if self.q().is_some() { unsafe { Some(ffi::DSA_size(self.as_ptr()) as u32) } @@ -139,7 +160,7 @@ impl Dsa { } } - /// Reads an DSA public key from PEM formatted data. + /// Reads a DSA public key from PEM formatted data. pub fn public_key_from_pem(buf: &[u8]) -> Result { ffi::init(); @@ -152,6 +173,26 @@ impl Dsa { Ok(Dsa(dsa)) } } + + /// Reads a DSA private key from DER formatted data. + pub fn private_key_from_der(buf: &[u8]) -> Result { + unsafe { + ffi::init(); + let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; + let dsa = try!(cvt_p(ffi::d2i_DSAPrivateKey(ptr::null_mut(), &mut buf.as_ptr(), len))); + Ok(Dsa(dsa)) + } + } + + /// Reads a DSA public key from DER formatted data. + pub fn public_key_from_der(buf: &[u8]) -> Result { + unsafe { + ffi::init(); + let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; + let dsa = try!(cvt_p(ffi::d2i_DSAPublicKey(ptr::null_mut(), &mut buf.as_ptr(), len))); + Ok(Dsa(dsa)) + } + } } impl fmt::Debug for Dsa { diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index f424e337..b1c196bd 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -48,7 +48,7 @@ impl PKeyRef { } } - /// Stores private key as a PEM + /// Encodes the private key in the PEM format. // FIXME: also add password and encryption pub fn private_key_to_pem(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); @@ -65,7 +65,7 @@ impl PKeyRef { Ok(mem_bio.get_buf().to_owned()) } - /// Encode public key in PEM format + /// Encodes the public key in the PEM format. pub fn public_key_to_pem(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { @@ -74,7 +74,7 @@ impl PKeyRef { Ok(mem_bio.get_buf().to_owned()) } - /// Encode public key in DER format + /// Encodes the public key in the DER format. pub fn public_key_to_der(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); unsafe { @@ -83,6 +83,15 @@ impl PKeyRef { Ok(mem_bio.get_buf().to_owned()) } + /// Encodes the private key in the DER format + pub fn private_key_to_der(&self) -> Result, ErrorStack> { + let mem_bio = try!(MemBio::new()); + unsafe { + try!(cvt(ffi::i2d_PrivateKey_bio(mem_bio.as_ptr(), self.as_ptr()))); + } + Ok(mem_bio.get_buf().to_owned()) + } + pub fn public_eq(&self, other: &PKeyRef) -> bool { unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } } @@ -148,7 +157,7 @@ impl PKey { } } - /// Reads private key from PEM, takes ownership of handle + /// Reads a private key from PEM. pub fn private_key_from_pem(buf: &[u8]) -> Result { ffi::init(); let mem_bio = try!(MemBioSlice::new(buf)); @@ -181,7 +190,7 @@ impl PKey { } } - /// Reads public key from PEM, takes ownership of handle + /// Reads a public key from PEM. pub fn public_key_from_pem(buf: &[u8]) -> Result { ffi::init(); let mem_bio = try!(MemBioSlice::new(buf)); diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index bd1d16d3..70d41997 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -1,8 +1,9 @@ use ffi; +use std::cmp; use std::fmt; use std::ptr; use std::mem; -use libc::{c_int, c_void, c_char}; +use libc::{c_int, c_void, c_char, c_long}; use {cvt, cvt_p, cvt_n}; use bn::{BigNum, BigNumRef}; @@ -49,6 +50,26 @@ impl RsaRef { Ok(mem_bio.get_buf().to_owned()) } + /// Encodes an RSA private key as unencrypted DER formatted data. + pub fn private_key_to_der(&self) -> Result, ErrorStack> { + unsafe { + let len = try!(cvt(ffi::i2d_RSAPrivateKey(self.as_ptr(), ptr::null_mut()))); + let mut buf = vec![0; len as usize]; + try!(cvt(ffi::i2d_RSAPrivateKey(self.as_ptr(), &mut buf.as_mut_ptr()))); + Ok(buf) + } + } + + /// Encodes an RSA public key as DER formatted data. + pub fn public_key_to_der(&self) -> Result, ErrorStack> { + unsafe { + let len = try!(cvt(ffi::i2d_RSA_PUBKEY(self.as_ptr(), ptr::null_mut()))); + let mut buf = vec![0; len as usize]; + try!(cvt(ffi::i2d_RSA_PUBKEY(self.as_ptr(), &mut buf.as_mut_ptr()))); + Ok(buf) + } + } + pub fn size(&self) -> usize { unsafe { assert!(self.n().is_some()); @@ -250,6 +271,7 @@ impl Rsa { /// /// The public exponent will be 65537. pub fn generate(bits: u32) -> Result { + ffi::init(); unsafe { let rsa = Rsa(try!(cvt_p(ffi::RSA_new()))); let e = try!(BigNum::from_u32(ffi::RSA_F4 as u32)); @@ -260,6 +282,7 @@ impl Rsa { /// Reads an RSA private key from PEM formatted data. pub fn private_key_from_pem(buf: &[u8]) -> Result { + ffi::init(); let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(), @@ -274,6 +297,7 @@ impl Rsa { pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result where F: FnOnce(&mut [c_char]) -> usize { + ffi::init(); let mut cb = CallbackState::new(pass_cb); let mem_bio = try!(MemBioSlice::new(buf)); @@ -289,6 +313,7 @@ impl Rsa { /// Reads an RSA public key from PEM formatted data. pub fn public_key_from_pem(buf: &[u8]) -> Result { + ffi::init(); let mem_bio = try!(MemBioSlice::new(buf)); unsafe { let rsa = try!(cvt_p(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.as_ptr(), @@ -298,6 +323,26 @@ impl Rsa { Ok(Rsa(rsa)) } } + + /// Reads an RSA private key from DER formatted data. + pub fn private_key_from_der(buf: &[u8]) -> Result { + unsafe { + ffi::init(); + let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; + let dsa = try!(cvt_p(ffi::d2i_RSAPrivateKey(ptr::null_mut(), &mut buf.as_ptr(), len))); + Ok(Rsa(dsa)) + } + } + + /// Reads an RSA public key from DER formatted data. + pub fn public_key_from_der(buf: &[u8]) -> Result { + unsafe { + ffi::init(); + let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; + let dsa = try!(cvt_p(ffi::d2i_RSA_PUBKEY(ptr::null_mut(), &mut buf.as_ptr(), len))); + Ok(Rsa(dsa)) + } + } } impl fmt::Debug for Rsa { From 26a3358a2b70b46bf06403b2810c379f5299a551 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 00:24:12 +0000 Subject: [PATCH 017/140] Add basic X509_STORE access There's more to do here, but this enabled addition of trusted CAs from X509 objects. Closes #394 --- openssl-sys/src/lib.rs | 5 +++++ openssl/src/ssl/mod.rs | 11 +++++++++++ openssl/src/ssl/tests/mod.rs | 14 ++++++++++++++ openssl/src/x509/mod.rs | 1 + openssl/src/x509/store.rs | 20 ++++++++++++++++++++ 5 files changed, 51 insertions(+) create mode 100644 openssl/src/x509/store.rs diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 7b94361b..eca08b70 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -38,6 +38,7 @@ pub enum X509_EXTENSION {} pub enum X509_NAME {} pub enum X509_NAME_ENTRY {} pub enum X509_REQ {} +pub enum X509_STORE {} pub enum X509_STORE_CTX {} pub enum bio_st {} pub enum PKCS12 {} @@ -1622,6 +1623,7 @@ extern { pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int; pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int; pub fn SSL_CTX_set_client_CA_list(ctx: *mut SSL_CTX, list: *mut stack_st_X509_NAME); + pub fn SSL_CTX_get_cert_store(ctx: *mut SSL_CTX) -> *mut X509_STORE; #[cfg(not(ossl101))] pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; @@ -1693,6 +1695,9 @@ extern { pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + pub fn X509_STORE_free(store: *mut X509_STORE); + pub fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut X509) -> c_int; + 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_error(ctx: *mut X509_STORE_CTX) -> c_int; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index c92bf56b..1e0d2e66 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -94,6 +94,7 @@ use {init, cvt, cvt_p}; use dh::DhRef; use ec_key::EcKeyRef; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; +use x509::store::X509StoreBuilderRef; #[cfg(any(ossl102, ossl110))] use verify::X509VerifyParamRef; use pkey::PKeyRef; @@ -739,6 +740,16 @@ impl SslContextBuilder { unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) } } + /// Returns a shared reference to the context's certificate store. + pub fn cert_store(&self) -> &X509StoreBuilderRef { + unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } + } + + /// Returns a mutable reference to the context's certificate store. + pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef { + unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } + } + pub fn build(self) -> SslContext { let ctx = SslContext(self.0); mem::forget(self); diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 96c0d585..fa7c6024 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -28,6 +28,7 @@ use std::net::UdpSocket; mod select; +static ROOT_CERT: &'static [u8] = include_bytes!("../../../test/root-ca.pem"); static CERT: &'static [u8] = include_bytes!("../../../test/cert.pem"); static KEY: &'static [u8] = include_bytes!("../../../test/key.pem"); @@ -1192,6 +1193,19 @@ fn client_ca_list() { ctx.set_client_ca_list(names); } +#[test] +fn cert_store() { + let (_s, tcp) = Server::new(); + + let cert = X509::from_pem(ROOT_CERT).unwrap(); + + let mut ctx = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); + ctx.builder_mut().cert_store_mut().add_cert(cert).unwrap(); + let ctx = ctx.build(); + + ctx.connect("foobar.com", tcp).unwrap(); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index e98e6006..e7c633d0 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -36,6 +36,7 @@ pub mod verify; use x509::extension::{ExtensionType, Extension}; pub mod extension; +pub mod store; #[cfg(test)] mod tests; diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs new file mode 100644 index 00000000..01eb0e2f --- /dev/null +++ b/openssl/src/x509/store.rs @@ -0,0 +1,20 @@ +use ffi; +use std::mem; + +use cvt; +use error::ErrorStack; +use types::OpenSslTypeRef; +use x509::X509; + +type_!(X509StoreBuilder, X509StoreBuilderRef, ffi::X509_STORE, ffi::X509_STORE_free); + +impl X509StoreBuilderRef { + /// Adds a certificate to the certificate store. + pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { + unsafe { + let ptr = cert.as_ptr(); + mem::forget(cert); // the cert will be freed inside of X509_STORE_add_cert on error + cvt(ffi::X509_STORE_add_cert(self.as_ptr(), ptr)).map(|_| ()) + } + } +} From 7c9afd8c99505ccaa3381990448f225f123ad764 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 10:29:31 +0000 Subject: [PATCH 018/140] Fix function signature --- openssl-sys/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index eca08b70..17c2864d 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1623,7 +1623,7 @@ extern { pub fn SSL_CTX_use_PrivateKey(ctx: *mut SSL_CTX, key: *mut EVP_PKEY) -> c_int; pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int; pub fn SSL_CTX_set_client_CA_list(ctx: *mut SSL_CTX, list: *mut stack_st_X509_NAME); - pub fn SSL_CTX_get_cert_store(ctx: *mut SSL_CTX) -> *mut X509_STORE; + pub fn SSL_CTX_get_cert_store(ctx: *const SSL_CTX) -> *mut X509_STORE; #[cfg(not(ossl101))] pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; From 9b5c62b053fb84dc233c69ba1700bee9b8a4387f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 11:00:15 +0000 Subject: [PATCH 019/140] Add PKey::bits --- openssl-sys/src/ossl10x.rs | 1 + openssl-sys/src/ossl110.rs | 1 + openssl/src/pkey.rs | 9 +++++++++ 3 files changed, 11 insertions(+) diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 0cc75fca..baab16ac 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -600,6 +600,7 @@ extern { line: c_int) -> c_int; pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); + pub fn EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int; pub fn sk_num(st: *const _STACK) -> c_int; pub fn sk_value(st: *const _STACK, n: c_int) -> *mut c_void; diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index e8d62d73..46df2d0e 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -147,6 +147,7 @@ extern { pub fn X509_STORE_CTX_get0_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX; pub fn EVP_MD_CTX_free(ctx: *mut EVP_MD_CTX); + pub fn EVP_PKEY_bits(key: *const EVP_PKEY) -> c_int; pub fn OpenSSL_version_num() -> c_ulong; pub fn OpenSSL_version(key: c_int) -> *const c_char; diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index b1c196bd..c9772d52 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -92,6 +92,15 @@ impl PKeyRef { Ok(mem_bio.get_buf().to_owned()) } + /// Returns the size of the key. + /// + /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the + /// group order for an elliptic curve key, for example. + pub fn bits(&self) -> usize { + unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as usize } + } + + /// Compares the public component of this key with another. pub fn public_eq(&self, other: &PKeyRef) -> bool { unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } } From b14d68f715b3ba02e671d9c3e158abcf89237ef9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 11:14:05 +0000 Subject: [PATCH 020/140] Drop bits to u32 --- openssl/src/pkey.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index c9772d52..43eadd43 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -96,8 +96,8 @@ impl PKeyRef { /// /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the /// group order for an elliptic curve key, for example. - pub fn bits(&self) -> usize { - unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as usize } + pub fn bits(&self) -> u32 { + unsafe { ffi::EVP_PKEY_bits(self.as_ptr()) as u32 } } /// Compares the public component of this key with another. From 563754fb0892ebf8021bb6043f4540c98f3b86a6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 12:43:44 +0000 Subject: [PATCH 021/140] Add SslContextBuilder::set_tmp_{ec,}dh_callback --- openssl-sys/src/lib.rs | 10 ++++ openssl-sys/src/ossl10x.rs | 10 ++++ openssl/src/dsa.rs | 1 + openssl/src/rsa.rs | 1 + openssl/src/ssl/mod.rs | 91 +++++++++++++++++++++++++++++++++--- openssl/src/ssl/tests/mod.rs | 65 ++++++++++++++++++++++++++ 6 files changed, 172 insertions(+), 6 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 17c2864d..7fda34d4 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1592,6 +1592,11 @@ extern { #[cfg(not(ossl101))] pub fn SSL_get_privatekey(ssl: *const SSL) -> *mut EVP_PKEY; pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; + pub fn SSL_set_tmp_dh_callback(ctx: *mut SSL, + dh: unsafe extern fn(ssl: *mut SSL, + is_export: c_int, + keylength: c_int) + -> *mut DH); #[cfg(not(osslconf = "OPENSSL_NO_COMP"))] pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; @@ -1624,6 +1629,11 @@ extern { pub fn SSL_CTX_check_private_key(ctx: *const SSL_CTX) -> c_int; pub fn SSL_CTX_set_client_CA_list(ctx: *mut SSL_CTX, list: *mut stack_st_X509_NAME); pub fn SSL_CTX_get_cert_store(ctx: *const SSL_CTX) -> *mut X509_STORE; + pub fn SSL_CTX_set_tmp_dh_callback(ctx: *mut SSL_CTX, + dh: unsafe extern fn(ssl: *mut SSL, + is_export: c_int, + keylength: c_int) + -> *mut DH); #[cfg(not(ossl101))] pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index baab16ac..ad7d065c 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -576,12 +576,22 @@ extern { dup_func: Option<::CRYPTO_EX_dup>, free_func: Option<::CRYPTO_EX_free>) -> c_int; + pub fn SSL_set_tmp_ecdh_callback(ssl: *mut ::SSL, + ecdh: unsafe extern fn(ssl: *mut ::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ::EC_KEY); pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *mut c_char; pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *mut c_void, new_func: Option<::CRYPTO_EX_new>, dup_func: Option<::CRYPTO_EX_dup>, free_func: Option<::CRYPTO_EX_free>) -> c_int; + pub fn SSL_CTX_set_tmp_ecdh_callback(ctx: *mut ::SSL_CTX, + ecdh: unsafe extern fn(ssl: *mut ::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ::EC_KEY); pub fn X509_get_subject_name(x: *mut ::X509) -> *mut ::X509_NAME; pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; pub fn X509_set_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 81e551ab..72076775 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -57,6 +57,7 @@ impl DsaRef { } } + // FIXME should return u32 pub fn size(&self) -> Option { if self.q().is_some() { unsafe { Some(ffi::DSA_size(self.as_ptr()) as u32) } diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 70d41997..bd36570d 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -70,6 +70,7 @@ impl RsaRef { } } + // FIXME should return u32 pub fn size(&self) -> usize { unsafe { assert!(self.n().is_some()); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 1e0d2e66..ed3f023c 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -91,8 +91,10 @@ use std::str; use std::sync::Mutex; use {init, cvt, cvt_p}; -use dh::DhRef; +use dh::{Dh, DhRef}; use ec_key::EcKeyRef; +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +use ec_key::EcKey; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; use x509::store::X509StoreBuilderRef; #[cfg(any(ossl102, ossl110))] @@ -219,7 +221,7 @@ lazy_static! { // Creates a static index for user data of type T // Registers a destructor for the data which will be called // when context is freed -fn get_verify_data_idx() -> c_int { +fn get_callback_idx() -> c_int { *INDEXES.lock().unwrap().entry(TypeId::of::()).or_insert_with(|| get_new_idx::()) } @@ -272,7 +274,7 @@ extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_ let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); - let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::()); + let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); let verify: &F = &*(verify as *mut F); let ctx = X509StoreContextRef::from_ptr(x509_ctx); @@ -301,7 +303,7 @@ extern "C" fn raw_sni(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) { unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); - let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::()); + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); let callback: &F = &*(callback as *mut F); let ssl = SslRef::from_ptr_mut(ssl); @@ -373,6 +375,55 @@ extern "C" fn raw_alpn_select_cb(ssl: *mut ffi::SSL, unsafe { select_proto_using(ssl, out as *mut _, outlen, inbuf, inlen, *ALPN_PROTOS_IDX) } } +unsafe extern fn raw_tmp_dh(ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ffi::DH + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send +{ + let ctx = ffi::SSL_get_SSL_CTX(ssl); + let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + match callback(ssl, is_export != 0, keylength as u32) { + Ok(dh) => { + let ptr = dh.as_ptr(); + mem::forget(dh); + ptr + } + Err(_) => { + // FIXME reset error stack + ptr::null_mut() + } + } +} + +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +unsafe extern fn raw_tmp_ecdh(ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ffi::EC_KEY + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send +{ + let ctx = ffi::SSL_get_SSL_CTX(ssl); + let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + match callback(ssl, is_export != 0, keylength as u32) { + Ok(ec_key) => { + let ptr = ec_key.as_ptr(); + mem::forget(ec_key); + ptr + } + Err(_) => { + // FIXME reset error stack + ptr::null_mut() + } + } +} + /// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. /// /// It causes the parameter `out` to point at a `*const c_uchar` instance that @@ -472,7 +523,7 @@ impl SslContextBuilder { unsafe { let verify = Box::new(verify); ffi::SSL_CTX_set_ex_data(self.as_ptr(), - get_verify_data_idx::(), + get_callback_idx::(), mem::transmute(verify)); ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::)); } @@ -488,7 +539,7 @@ impl SslContextBuilder { unsafe { let callback = Box::new(callback); ffi::SSL_CTX_set_ex_data(self.as_ptr(), - get_verify_data_idx::(), + get_callback_idx::(), mem::transmute(callback)); let f: extern "C" fn(_, _, _) -> _ = raw_sni::; let f: extern "C" fn() = mem::transmute(f); @@ -520,10 +571,38 @@ impl SslContextBuilder { unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } } + pub fn set_tmp_dh_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_CTX_set_ex_data(self.as_ptr(), + get_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn (_, _, _) -> _ = raw_tmp_dh::; + ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), f); + } + } + pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } } + /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. + #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] + pub fn set_tmp_ecdh_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_CTX_set_ex_data(self.as_ptr(), + get_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn(_, _, _) -> _ = raw_tmp_ecdh::; + ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), f); + } + } + /// Use the default locations of trusted certificates for verification. /// /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index fa7c6024..d79e5386 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -9,10 +9,12 @@ use std::mem; use std::net::{TcpStream, TcpListener, SocketAddr}; use std::path::Path; use std::process::{Command, Child, Stdio, ChildStdin}; +use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering}; use std::thread; use std::time::Duration; use tempdir::TempDir; +use dh::Dh; use hash::MessageDigest; use ssl; use ssl::SSL_VERIFY_PEER; @@ -1206,6 +1208,69 @@ fn cert_store() { ctx.connect("foobar.com", tcp).unwrap(); } +#[test] +fn tmp_dh_callback() { + static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + thread::spawn(move ||{ + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::from_pem(dh) + }); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_cipher_list("DHE").unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +fn tmp_ecdh_callback() { + use ec_key::EcKey; + use nid; + + static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + thread::spawn(move ||{ + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::new_by_curve_name(nid::X9_62_PRIME256V1) + }); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_cipher_list("ECDHE").unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} From 780c46e0e722f683ba6a8b7a8b2a7924e49695c3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 12:56:58 +0000 Subject: [PATCH 022/140] Add SslRef::set_tmp_{ec,}dh_calback --- openssl/src/ssl/mod.rs | 81 ++++++++++++++++++++++++++++++++++-- openssl/src/ssl/tests/mod.rs | 63 ++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 3 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ed3f023c..bcaa4c74 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -225,7 +225,7 @@ fn get_callback_idx() -> c_int { *INDEXES.lock().unwrap().entry(TypeId::of::()).or_insert_with(|| get_new_idx::()) } -fn get_ssl_verify_data_idx() -> c_int { +fn get_ssl_callback_idx() -> c_int { *SSL_INDEXES.lock().unwrap().entry(TypeId::of::()).or_insert_with(|| get_new_ssl_idx::()) } @@ -289,7 +289,7 @@ extern "C" fn ssl_raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_ST unsafe { let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); - let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_verify_data_idx::()); + let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_callback_idx::()); let verify: &F = &*(verify as *mut F); let ctx = X509StoreContextRef::from_ptr(x509_ctx); @@ -424,6 +424,53 @@ unsafe extern fn raw_tmp_ecdh(ssl: *mut ffi::SSL, } } +unsafe extern fn raw_tmp_dh_ssl(ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ffi::DH + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send +{ + let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + match callback(ssl, is_export != 0, keylength as u32) { + Ok(dh) => { + let ptr = dh.as_ptr(); + mem::forget(dh); + ptr + } + Err(_) => { + // FIXME reset error stack + ptr::null_mut() + } + } +} + +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +unsafe extern fn raw_tmp_ecdh_ssl(ssl: *mut ffi::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ffi::EC_KEY + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send +{ + let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + match callback(ssl, is_export != 0, keylength as u32) { + Ok(ec_key) => { + let ptr = ec_key.as_ptr(); + mem::forget(ec_key); + ptr + } + Err(_) => { + // FIXME reset error stack + ptr::null_mut() + } + } +} + /// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. /// /// It causes the parameter `out` to point at a `*const c_uchar` instance that @@ -1030,12 +1077,40 @@ impl SslRef { unsafe { let verify = Box::new(verify); ffi::SSL_set_ex_data(self.as_ptr(), - get_ssl_verify_data_idx::(), + get_ssl_callback_idx::(), mem::transmute(verify)); ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::)); } } + pub fn set_tmp_dh_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_set_ex_data(self.as_ptr(), + get_ssl_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn (_, _, _) -> _ = raw_tmp_dh_ssl::; + ffi::SSL_set_tmp_dh_callback(self.as_ptr(), f); + } + } + + /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. + #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] + pub fn set_tmp_ecdh_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_set_ex_data(self.as_ptr(), + get_ssl_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn(_, _, _) -> _ = raw_tmp_ecdh_ssl::; + ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), f); + } + } + pub fn current_cipher(&self) -> Option<&SslCipherRef> { unsafe { let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index d79e5386..e2afb6f7 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1271,6 +1271,69 @@ fn tmp_ecdh_callback() { assert!(CALLED_BACK.load(Ordering::SeqCst)); } +#[test] +fn tmp_dh_callback_ssl() { + static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + thread::spawn(move ||{ + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tmp_dh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + let dh = include_bytes!("../../../test/dhparams.pem"); + Dh::from_pem(dh) + }); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_cipher_list("DHE").unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +#[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] +fn tmp_ecdh_callback_ssl() { + use ec_key::EcKey; + use nid; + + static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + thread::spawn(move ||{ + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_tmp_ecdh_callback(|_, _, _| { + CALLED_BACK.store(true, Ordering::SeqCst); + EcKey::new_by_curve_name(nid::X9_62_PRIME256V1) + }); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_cipher_list("ECDHE").unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} From 93253ba5991414a86fe10db4e74c4a7bfeae19fc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:09:12 +0000 Subject: [PATCH 023/140] Adjust cipher lists to work on older versions --- openssl/src/ssl/tests/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index e2afb6f7..becf4fd3 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1231,7 +1231,7 @@ fn tmp_dh_callback() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("DHE").unwrap(); + ctx.set_cipher_list("EDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1264,7 +1264,7 @@ fn tmp_ecdh_callback() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("ECDHE").unwrap(); + ctx.set_cipher_list("kECDHe").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1294,7 +1294,7 @@ fn tmp_dh_callback_ssl() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("DHE").unwrap(); + ctx.set_cipher_list("EDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1327,7 +1327,7 @@ fn tmp_ecdh_callback_ssl() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("ECDHE").unwrap(); + ctx.set_cipher_list("kECDHe").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); From 2a1d7b2bcb229283c85a991dd97aa83f59b02ed2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:35:51 +0000 Subject: [PATCH 024/140] Pick different cipher lists on 1.0.1 and 1.0.2 --- openssl/src/ssl/tests/mod.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index becf4fd3..50299aa8 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1264,7 +1264,11 @@ fn tmp_ecdh_callback() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("kECDHe").unwrap(); + if cfg!(ossl101) { + ctx.set_cipher_list("kECDHe").unwrap(); + } else { + ctx.set_cipher_list("ECDHE").unwrap(); + } let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1327,7 +1331,11 @@ fn tmp_ecdh_callback_ssl() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - ctx.set_cipher_list("kECDHe").unwrap(); + if cfg!(ossl101) { + ctx.set_cipher_list("kECDHe").unwrap(); + } else { + ctx.set_cipher_list("ECDHE").unwrap(); + } let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); From 96d24c89575c4d2e193f31de67e1ba273f15d6b0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:45:54 +0000 Subject: [PATCH 025/140] Add SslRef::set_{tmp_dh,tmp_ecdh,ecdh_auto} --- openssl-sys/src/lib.rs | 8 ++++++++ openssl-sys/src/ossl10x.rs | 6 ++++++ openssl/src/ssl/mod.rs | 18 ++++++++++++++++++ 3 files changed, 32 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 7fda34d4..f3ecdf8b 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1233,6 +1233,14 @@ pub unsafe fn SSL_CTX_set_tmp_ecdh(ctx: *mut SSL_CTX, key: *mut EC_KEY) -> c_lon SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void) } +pub unsafe fn SSL_set_tmp_dh(ssl: *mut SSL, dh: *mut DH) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_TMP_DH, 0, dh as *mut c_void) +} + +pub unsafe fn SSL_set_tmp_ecdh(ssl: *mut SSL, key: *mut EC_KEY) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_TMP_ECDH, 0, key as *mut c_void) +} + pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) -> c_long { SSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, x509 as *mut c_void) } diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index ad7d065c..eb305228 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -533,11 +533,17 @@ fn set_id_callback() { fn set_id_callback() {} // macros + #[cfg(ossl102)] pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { ::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int } +#[cfg(ossl102)] +pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { + ::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int +} + extern { pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; pub fn BIO_s_file() -> *mut BIO_METHOD; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index bcaa4c74..2c444400 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1083,6 +1083,10 @@ impl SslRef { } } + pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) } + } + pub fn set_tmp_dh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result + Any + 'static + Sync + Send { @@ -1096,6 +1100,10 @@ impl SslRef { } } + pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) } + } + /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2. #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] pub fn set_tmp_ecdh_callback(&mut self, callback: F) @@ -1111,6 +1119,16 @@ impl SslRef { } } + /// If `onoff` is set to `true`, enable ECDHE for key exchange with + /// compatible clients, and automatically select an appropriate elliptic + /// curve. + /// + /// Requires the `v102` feature and OpenSSL 1.0.2. + #[cfg(all(feature = "v102", ossl102))] + pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } + } + pub fn current_cipher(&self) -> Option<&SslCipherRef> { unsafe { let ptr = ffi::SSL_get_current_cipher(self.as_ptr()); From 796d7b4deb547f1cd0bce0d54dea2dc5cdf650bb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 14:14:56 +0000 Subject: [PATCH 026/140] Add constructors for various standard primes --- openssl-sys/src/ossl10x.rs | 10 ++++++ openssl-sys/src/ossl110.rs | 12 +++++++ openssl/src/bn.rs | 73 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index eb305228..4f418f14 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -548,6 +548,16 @@ extern { pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; pub fn BIO_s_file() -> *mut BIO_METHOD; pub fn BIO_s_mem() -> *mut BIO_METHOD; + + pub fn get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn CRYPTO_free(buf: *mut c_void); pub fn CRYPTO_num_locks() -> c_int; pub fn CRYPTO_set_locking_callback(func: unsafe extern "C" fn(mode: c_int, diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index 46df2d0e..bb4fa19b 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -52,9 +52,21 @@ extern { pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; pub fn BIO_s_file() -> *const BIO_METHOD; pub fn BIO_s_mem() -> *const BIO_METHOD; + + pub fn BN_get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn CRYPTO_free(buf: *mut c_void, file: *const c_char, line: c_int); + pub fn HMAC_CTX_new() -> *mut HMAC_CTX; pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX); + pub fn TLS_method() -> *const ::SSL_METHOD; pub fn DTLS_method() -> *const ::SSL_METHOD; pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *const c_char; diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index d52be884..73482432 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -10,6 +10,21 @@ use crypto::CryptoString; use error::ErrorStack; use types::{OpenSslType, OpenSslTypeRef}; +#[cfg(ossl10x)] +use ffi::{get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, + get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, + get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, + get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, + get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, + get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, + get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, + get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192}; + +#[cfg(ossl110)] +use ffi::{BN_get_rfc2409_prime_768, BN_get_rfc2409_prime_1024, BN_get_rfc3526_prime_1536, + BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096, + BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192}; + /// Options for the most significant bits of a randomly generated `BigNum`. pub struct MsbOption(c_int); @@ -516,6 +531,7 @@ impl BigNum { /// Creates a `BigNum` from a decimal string. pub fn from_dec_str(s: &str) -> Result { unsafe { + ffi::init(); let c_str = CString::new(s.as_bytes()).unwrap(); let mut bn = ptr::null_mut(); try!(cvt(ffi::BN_dec2bn(&mut bn, c_str.as_ptr() as *const _))); @@ -526,6 +542,7 @@ impl BigNum { /// Creates a `BigNum` from a hexadecimal string. pub fn from_hex_str(s: &str) -> Result { unsafe { + ffi::init(); let c_str = CString::new(s.as_bytes()).unwrap(); let mut bn = ptr::null_mut(); try!(cvt(ffi::BN_hex2bn(&mut bn, c_str.as_ptr() as *const _))); @@ -533,6 +550,62 @@ impl BigNum { } } + pub fn get_rfc2409_prime_768() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc2409_prime_768(ptr::null_mut())).map(BigNum) + } + } + + pub fn get_rfc2409_prime_1024() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc2409_prime_1024(ptr::null_mut())).map(BigNum) + } + } + + pub fn get_rfc3526_prime_1536() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_1536(ptr::null_mut())).map(BigNum) + } + } + + pub fn get_rfc3526_prime_2048() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_2048(ptr::null_mut())).map(BigNum) + } + } + + pub fn get_rfc3526_prime_3072() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_3072(ptr::null_mut())).map(BigNum) + } + } + + pub fn get_rfc3526_prime_4096() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_4096(ptr::null_mut())).map(BigNum) + } + } + + pub fn get_rfc3526_prime_6144() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_6144(ptr::null_mut())).map(BigNum) + } + } + + pub fn get_rfc3526_prime_8192() -> Result { + unsafe { + ffi::init(); + cvt_p(BN_get_rfc3526_prime_8192(ptr::null_mut())).map(BigNum) + } + } + /// Creates a new `BigNum` from an unsigned, big-endian encoded number of arbitrary length. /// /// ``` From 157034d995f9bcb930b186acb2dbcddb5efada8b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 14:30:53 +0000 Subject: [PATCH 027/140] Add a missing init --- openssl/src/bn.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index 73482432..a8bb9619 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -616,6 +616,7 @@ impl BigNum { /// ``` pub fn from_slice(n: &[u8]) -> Result { unsafe { + ffi::init(); assert!(n.len() <= c_int::max_value() as usize); cvt_p(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, ptr::null_mut())) .map(|p| BigNum::from_ptr(p)) From 7cdb58bc47fdc8060593b48d5624e7d14b5ac285 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 14:42:48 +0000 Subject: [PATCH 028/140] Simplify test logic a bit --- openssl/src/ssl/tests/mod.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 50299aa8..3cc3a28c 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1264,11 +1264,7 @@ fn tmp_ecdh_callback() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - if cfg!(ossl101) { - ctx.set_cipher_list("kECDHe").unwrap(); - } else { - ctx.set_cipher_list("ECDHE").unwrap(); - } + ctx.set_cipher_list("ECDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); @@ -1331,11 +1327,7 @@ fn tmp_ecdh_callback_ssl() { let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); - if cfg!(ossl101) { - ctx.set_cipher_list("kECDHe").unwrap(); - } else { - ctx.set_cipher_list("ECDHE").unwrap(); - } + ctx.set_cipher_list("ECDH").unwrap(); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.connect(stream).unwrap(); From 6b3599d319977ac3c60677638d29783a9e9f4f60 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 16:45:18 +0000 Subject: [PATCH 029/140] Add a connect method that does not perform hostname verification The method name is intentionally painful to type to discourage its use --- openssl/src/ssl/connector.rs | 17 +++++++++++++++++ openssl/src/ssl/tests/mod.rs | 36 ++++++++++++++++++++++++++++++++---- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index c5189c9e..f838edf4 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -61,6 +61,7 @@ impl SslConnectorBuilder { try!(ctx.set_cipher_list("ECDH+AESGCM:ECDH+CHACHA20:DH+AESGCM:DH+CHACHA20:ECDH+AES256:\ DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:RSA+AESGCM:\ RSA+AES:RSA+HIGH:!aNULL:!eNULL:!MD5:!3DES")); + ctx.set_verify(SSL_VERIFY_PEER); Ok(SslConnectorBuilder(ctx)) } @@ -103,6 +104,22 @@ impl SslConnector { ssl.connect(stream) } + + /// Initiates a client-side TLS session on a stream without performing hostname verification. + /// + /// The verification configuration of the connector's `SslContext` is not overridden. + /// + /// # 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 connect_without_providing_domain_for_certificate_verification_and_server_name_indication( + &self, stream: S) -> Result, HandshakeError> + where S: Read + Write + { + try!(Ssl::new(&self.0)).connect(stream) + } } /// A builder for `SslAcceptor`s. diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 3cc3a28c..855903c9 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -17,10 +17,8 @@ use tempdir::TempDir; use dh::Dh; use hash::MessageDigest; use ssl; -use ssl::SSL_VERIFY_PEER; -use ssl::{SslMethod, HandshakeError}; -use ssl::{SslContext, SslStream, Ssl, ShutdownResult, SslConnectorBuilder, SslAcceptorBuilder, - Error}; +use ssl::{SslMethod, HandshakeError, SslContext, SslStream, Ssl, ShutdownResult, + SslConnectorBuilder, SslAcceptorBuilder, Error, SSL_VERIFY_PEER, SSL_VERIFY_NONE}; use x509::{X509StoreContext, X509, X509Name, X509_FILETYPE_PEM}; #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] use x509::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; @@ -1090,6 +1088,36 @@ fn connector_invalid_hostname() { assert!(connector.connect("foobar.com", s).is_err()); } +#[test] +fn connector_invalid_no_hostname_verification() { + let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + + let s = TcpStream::connect("google.com:443").unwrap(); + connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s) + .unwrap(); +} + +#[test] +fn connector_no_hostname_still_verifies() { + let (_s, tcp) = Server::new(); + + let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + + assert!(connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp) + .is_err()); +} + +#[test] +fn connector_no_hostname_can_disable_verify() { + let (_s, tcp) = Server::new(); + + let mut connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap(); + connector.builder_mut().set_verify(SSL_VERIFY_NONE); + let connector = connector.build(); + + connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp).unwrap(); +} + #[test] fn connector_client_server_mozilla_intermediate() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); From 2f8301fc63114120b930fbb5779e383f1b100635 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 16:51:26 +0000 Subject: [PATCH 030/140] Be a bit more emphatic about the danger --- openssl/src/ssl/connector.rs | 2 +- openssl/src/ssl/tests/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index f838edf4..39c19841 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -114,7 +114,7 @@ impl SslConnector { /// 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 connect_without_providing_domain_for_certificate_verification_and_server_name_indication( + pub fn danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication( &self, stream: S) -> Result, HandshakeError> where S: Read + Write { diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 855903c9..fb9a96b9 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1093,7 +1093,7 @@ fn connector_invalid_no_hostname_verification() { let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); let s = TcpStream::connect("google.com:443").unwrap(); - connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s) + connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s) .unwrap(); } @@ -1103,7 +1103,7 @@ fn connector_no_hostname_still_verifies() { let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); - assert!(connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp) + assert!(connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp) .is_err()); } @@ -1115,7 +1115,7 @@ fn connector_no_hostname_can_disable_verify() { connector.builder_mut().set_verify(SSL_VERIFY_NONE); let connector = connector.build(); - connector.connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp).unwrap(); + connector.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(tcp).unwrap(); } #[test] From 64e9932ac92bdb63896b49922146c602769e066d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 17:52:58 +0000 Subject: [PATCH 031/140] Use ffdhe2048 in mozilla_intermediate --- openssl/src/ssl/connector.rs | 50 ++++++------------------------------ 1 file changed, 8 insertions(+), 42 deletions(-) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 39c19841..213c90b7 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -7,21 +7,15 @@ use ssl::{self, SslMethod, SslContextBuilder, SslContext, Ssl, SSL_VERIFY_PEER, use pkey::PKeyRef; use x509::X509Ref; -// Serialized form of DH_get_2048_256 -#[cfg(any(ossl101, all(test, any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))))] +// ffdhe2048 from https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe2048 const DHPARAM_PEM: &'static str = r#" -----BEGIN DH PARAMETERS----- -MIICCQKCAQEAh6jmHbS2Zjz/u9GcZRlZmYzu9ghmDdDyXSzu1ENeOwDgDfjx1hlX -1Pr330VhsqowFsPZETQJb6o79Cltgw6afCCeDGSXUXq9WoqdMGvPZ+2R+eZyW0dY -wCLgse9Cdb97bFv8EdRfkIi5QfVOseWbuLw5oL8SMH9cT9twxYGyP3a2Osrhyqa3 -kC1SUmc1SIoO8TxtmlG/pKs62DR3llJNjvahZ7WkGCXZZ+FE5RQFZCUcysuD5rSG -9rPKP3lxUGAmwLhX9omWKFbe1AEKvQvmIcOjlgpU5xDDdfJjddcBQQOktUMwwZiv -EmEW0iduEXFfaTh3+tfvCcrbCUrpHhoVlwKCAQA/syybcxNNCy53UGZg7b1ITKex -jyHvIFQH9Hk6GguhJRDbwVB3vkY//0/tSqwLtVW+OmwbDGtHsbw3c79+jG9ikBIo -+MKMuxilWuMTQQAKZQGW+THHelfy3fRj5ensFEt3feYqqrioYorDdtKC1u04ZOZ5 -gkKOvIMdFDSPby+Rk7UEWvJ2cWTh38lnwfs/LlWkvRv/6DucgNBSuYXRguoK2yo7 -cxPT/hTISEseBSWIubfSu9LfAWGZ7NBuFVfNCRWzNTu7ZODsN3/QKDcN+StSx4kU -KM3GfrYYS1I9HbJGwy9jB4SQ8A741kfRSNR5VFFeIyfP75jFgmZLTA9sxBZZ +MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz ++8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a +87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7 +YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi +7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD +ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS----- "#; @@ -142,7 +136,7 @@ impl SslAcceptorBuilder { I::Item: AsRef { let mut ctx = try!(ctx(method)); - let dh = try!(get_dh()); + let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes())); try!(ctx.set_tmp_dh(&dh)); try!(setup_curves(&mut ctx)); try!(ctx.set_cipher_list("ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:\ @@ -219,22 +213,6 @@ impl SslAcceptorBuilder { } } -#[cfg(ossl101)] -fn get_dh() -> Result { - Dh::from_pem(DHPARAM_PEM.as_bytes()) -} - -#[cfg(not(ossl101))] -fn get_dh() -> Result { - use ffi; - - use cvt_p; - use types::OpenSslType; - - // manually call into ffi to avoid forcing the features - unsafe { cvt_p(ffi::DH_get_2048_256()).map(|p| Dh::from_ptr(p)) } -} - #[cfg(ossl101)] fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { use ec_key::EcKey; @@ -456,15 +434,3 @@ mod verify { } } } - -#[cfg(test)] -mod test { - #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] - #[test] - fn check_dhparam() { - use dh::Dh; - - let expected = String::from_utf8(Dh::get_2048_256().unwrap().to_pem().unwrap()).unwrap(); - assert_eq!(expected.trim(), super::DHPARAM_PEM.trim()); - } -} From 85c1474ce68932d4fad0e53144cf43428b5e12c7 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 12:19:31 +0000 Subject: [PATCH 032/140] No need to use a raw string anymore --- openssl/src/ssl/connector.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 213c90b7..07c44ce7 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -8,7 +8,7 @@ use pkey::PKeyRef; use x509::X509Ref; // ffdhe2048 from https://wiki.mozilla.org/Security/Server_Side_TLS#ffdhe2048 -const DHPARAM_PEM: &'static str = r#" +const DHPARAM_PEM: &'static str = " -----BEGIN DH PARAMETERS----- MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz +8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a @@ -17,7 +17,7 @@ YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi 7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg== -----END DH PARAMETERS----- -"#; +"; fn ctx(method: SslMethod) -> Result { let mut ctx = try!(SslContextBuilder::new(method)); From 08e0c4ca9061c3dc0c951db0c08909689b04a310 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 15:02:38 +0000 Subject: [PATCH 033/140] Some serialization support for EcKey --- openssl-sys/src/lib.rs | 15 ++++++-- openssl/src/dsa.rs | 35 ++++--------------- openssl/src/ec_key.rs | 28 ++++++++++++++- openssl/src/lib.rs | 42 ++--------------------- openssl/src/macros.rs | 77 ++++++++++++++++++++++++++++++++++++++++++ openssl/src/pkey.rs | 23 +++---------- openssl/src/rsa.rs | 30 ++++------------ openssl/src/util.rs | 31 ++++++++++++++--- 8 files changed, 161 insertions(+), 120 deletions(-) create mode 100644 openssl/src/macros.rs diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index f3ecdf8b..1b84b690 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1513,11 +1513,19 @@ extern { user_data: *mut c_void) -> c_int; pub fn PEM_write_bio_DSA_PUBKEY(bp: *mut BIO, dsa: *mut DSA) -> c_int; - - pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; pub fn PEM_write_bio_X509_REQ(bio: *mut BIO, x509: *mut X509_REQ) -> c_int; + pub fn PEM_write_bio_ECPrivateKey(bio: *mut BIO, + key: *mut EC_KEY, + cipher: *const EVP_CIPHER, + kstr: *mut c_uchar, + klen: c_int, + callback: Option, + user_data: *mut c_void) + -> c_int; + pub fn PEM_read_bio_ECPrivateKey(bio: *mut BIO, key: *mut *mut EC_KEY, callback: Option, user_data: *mut c_void) -> *mut EC_KEY; + pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const c_char, passlen: c_int, salt: *const u8, saltlen: c_int, iter: c_int, keylen: c_int, @@ -1744,6 +1752,9 @@ extern { pub fn d2i_DSAPrivateKey(a: *mut *mut DSA, pp: *mut *const c_uchar, length: c_long) -> *mut DSA; pub fn i2d_DSAPrivateKey(a: *const DSA, pp: *mut *mut c_uchar) -> c_int; + pub fn d2i_ECPrivateKey(k: *mut *mut EC_KEY, pp: *mut *const c_uchar, length: c_long) -> *mut EC_KEY; + pub fn i2d_ECPrivateKey(ec_key: *mut EC_KEY, pp: *mut *mut c_uchar) -> c_int; + pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509; pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int; pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int; diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 72076775..962fcc9c 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -9,7 +9,7 @@ use bio::{MemBio, MemBioSlice}; use bn::BigNumRef; use {cvt, cvt_p}; use types::OpenSslTypeRef; -use util::{CallbackState, invoke_passwd_cb}; +use util::{CallbackState, invoke_passwd_cb_old}; type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free); @@ -125,25 +125,9 @@ impl Dsa { } } - /// Reads a DSA private key from PEM formatted data. - pub fn private_key_from_pem(buf: &[u8]) -> Result { - ffi::init(); - let mem_bio = try!(MemBioSlice::new(buf)); + private_key_from_pem!(Dsa, ffi::PEM_read_bio_DSAPrivateKey); - unsafe { - let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut()))); - Ok(Dsa(dsa)) - } - } - - /// Read a private key from PEM supplying a password callback to be invoked if the private key - /// is encrypted. - /// - /// The callback will be passed the password buffer and should return the number of characters - /// placed into the buffer. + #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result where F: FnOnce(&mut [c_char]) -> usize { @@ -155,7 +139,7 @@ impl Dsa { let cb_ptr = &mut cb as *mut _ as *mut c_void; let dsa = try!(cvt_p(ffi::PEM_read_bio_DSAPrivateKey(mem_bio.as_ptr(), ptr::null_mut(), - Some(invoke_passwd_cb::), + Some(invoke_passwd_cb_old::), cb_ptr))); Ok(Dsa(dsa)) } @@ -235,8 +219,6 @@ mod compat { #[cfg(test)] mod test { - use libc::c_char; - use super::*; #[test] @@ -248,14 +230,9 @@ mod test { pub fn test_password() { let mut password_queried = false; let key = include_bytes!("../test/dsa-encrypted.pem"); - Dsa::private_key_from_pem_cb(key, |password| { + Dsa::private_key_from_pem_callback(key, |password| { password_queried = true; - password[0] = b'm' as c_char; - password[1] = b'y' as c_char; - password[2] = b'p' as c_char; - password[3] = b'a' as c_char; - password[4] = b's' as c_char; - password[5] = b's' as c_char; + password[..6].copy_from_slice(b"mypass"); 6 }) .unwrap(); diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index ad85dc5e..99d62ad3 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -1,11 +1,27 @@ use ffi; +use std::cmp; +use libc::c_long; +use std::ptr; -use {cvt_p, init}; +use {cvt, cvt_p, init}; use error::ErrorStack; use nid::Nid; +use types::OpenSslTypeRef; type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); +impl EcKeyRef { + /// Serializes the private key components to DER. + pub fn private_key_to_der(&self) -> Result, ErrorStack> { + unsafe { + let len = try!(cvt(ffi::i2d_ECPrivateKey(self.as_ptr(), ptr::null_mut()))); + let mut buf = vec![0; len as usize]; + try!(cvt(ffi::i2d_ECPrivateKey(self.as_ptr(), &mut buf.as_mut_ptr()))); + Ok(buf) + } + } +} + impl EcKey { pub fn new_by_curve_name(nid: Nid) -> Result { unsafe { @@ -13,6 +29,16 @@ impl EcKey { cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) } } + /// Deserializes a DER-encoded private key. + pub fn private_key_from_der(der: &[u8]) -> Result { + unsafe { + init(); + let len = cmp::min(der.len(), c_long::max_value() as usize) as c_long; + cvt_p(ffi::d2i_ECPrivateKey(ptr::null_mut(), &mut der.as_ptr(), len)).map(EcKey) + } + } + + private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); } #[cfg(test)] diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index d3f99de7..c2c559dc 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -19,46 +19,8 @@ use libc::c_int; use error::ErrorStack; -macro_rules! type_ { - ($n:ident, $r:ident, $c:path, $d:path) => { - pub struct $n(*mut $c); - - impl ::types::OpenSslType for $n { - type CType = $c; - type Ref = $r; - - unsafe fn from_ptr(ptr: *mut $c) -> $n { - $n(ptr) - } - } - - impl Drop for $n { - fn drop(&mut self) { - unsafe { $d(self.0) } - } - } - - impl ::std::ops::Deref for $n { - type Target = $r; - - fn deref(&self) -> &$r { - unsafe { ::types::OpenSslTypeRef::from_ptr(self.0) } - } - } - - impl ::std::ops::DerefMut for $n { - fn deref_mut(&mut self) -> &mut $r { - unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.0) } - } - } - - pub struct $r(::util::Opaque); - - impl ::types::OpenSslTypeRef for $r { - type CType = $c; - } - } -} +#[macro_use] +mod macros; mod bio; mod util; diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs new file mode 100644 index 00000000..0db3401c --- /dev/null +++ b/openssl/src/macros.rs @@ -0,0 +1,77 @@ + +macro_rules! type_ { + ($n:ident, $r:ident, $c:path, $d:path) => { + pub struct $n(*mut $c); + + impl ::types::OpenSslType for $n { + type CType = $c; + type Ref = $r; + + unsafe fn from_ptr(ptr: *mut $c) -> $n { + $n(ptr) + } + } + + impl Drop for $n { + fn drop(&mut self) { + unsafe { $d(self.0) } + } + } + + impl ::std::ops::Deref for $n { + type Target = $r; + + fn deref(&self) -> &$r { + unsafe { ::types::OpenSslTypeRef::from_ptr(self.0) } + } + } + + impl ::std::ops::DerefMut for $n { + fn deref_mut(&mut self) -> &mut $r { + unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.0) } + } + } + + pub struct $r(::util::Opaque); + + impl ::types::OpenSslTypeRef for $r { + type CType = $c; + } + } +} + +macro_rules! private_key_from_pem { + ($t:ident, $f:path) => { + /// Deserializes a PEM-formatted private key. + pub fn private_key_from_pem(pem: &[u8]) -> Result<$t, ::error::ErrorStack> { + unsafe { + ::init(); + let bio = try!(::bio::MemBioSlice::new(pem)); + cvt_p($f(bio.as_ptr(), ::std::ptr::null_mut(), None, ::std::ptr::null_mut())) + .map($t) + } + } + + /// Deserializes a PEM-formatted private key, using a callback to retrieve a password if the + /// key is encrypted. + /// + /// The callback should copy the password into the provided buffer and return the number of + /// bytes written. + pub fn private_key_from_pem_callback(pem: &[u8], + callback: F) + -> Result<$t, ::error::ErrorStack> + where F: FnOnce(&mut [u8]) -> usize + { + unsafe { + ffi::init(); + let mut cb = ::util::CallbackState::new(callback); + let bio = try!(::bio::MemBioSlice::new(pem)); + cvt_p($f(bio.as_ptr(), + ptr::null_mut(), + Some(::util::invoke_passwd_cb::), + &mut cb as *mut _ as *mut ::libc::c_void)) + .map($t) + } + } + } +} diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 43eadd43..a56633a2 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -10,7 +10,7 @@ use dsa::Dsa; use ec_key::EcKey; use rsa::Rsa; use error::ErrorStack; -use util::{CallbackState, invoke_passwd_cb}; +use util::{CallbackState, invoke_passwd_cb_old}; use types::{OpenSslType, OpenSslTypeRef}; type_!(PKey, PKeyRef, ffi::EVP_PKEY, ffi::EVP_PKEY_free); @@ -166,24 +166,9 @@ impl PKey { } } - /// Reads a private key from PEM. - pub fn private_key_from_pem(buf: &[u8]) -> Result { - ffi::init(); - let mem_bio = try!(MemBioSlice::new(buf)); - unsafe { - let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut()))); - Ok(PKey::from_ptr(evp)) - } - } + private_key_from_pem!(PKey, ffi::PEM_read_bio_PrivateKey); - /// Read a private key from PEM, supplying a password callback to be invoked if the private key - /// is encrypted. - /// - /// The callback will be passed the password buffer and should return the number of characters - /// placed into the buffer. + #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result where F: FnOnce(&mut [c_char]) -> usize { @@ -193,7 +178,7 @@ impl PKey { unsafe { let evp = try!(cvt_p(ffi::PEM_read_bio_PrivateKey(mem_bio.as_ptr(), ptr::null_mut(), - Some(invoke_passwd_cb::), + Some(invoke_passwd_cb_old::), &mut cb as *mut _ as *mut c_void))); Ok(PKey::from_ptr(evp)) } diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index bd36570d..22668e19 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -9,7 +9,7 @@ use {cvt, cvt_p, cvt_n}; use bn::{BigNum, BigNumRef}; use bio::{MemBio, MemBioSlice}; use error::ErrorStack; -use util::{CallbackState, invoke_passwd_cb}; +use util::{CallbackState, invoke_passwd_cb_old}; use types::OpenSslTypeRef; /// Type of encryption padding to use. @@ -281,20 +281,9 @@ impl Rsa { } } - /// Reads an RSA private key from PEM formatted data. - pub fn private_key_from_pem(buf: &[u8]) -> Result { - ffi::init(); - let mem_bio = try!(MemBioSlice::new(buf)); - unsafe { - let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut()))); - Ok(Rsa(rsa)) - } - } + private_key_from_pem!(Rsa, ffi::PEM_read_bio_RSAPrivateKey); - /// Reads an RSA private key from PEM formatted data and supplies a password callback. + #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result where F: FnOnce(&mut [c_char]) -> usize { @@ -306,7 +295,7 @@ impl Rsa { let cb_ptr = &mut cb as *mut _ as *mut c_void; let rsa = try!(cvt_p(ffi::PEM_read_bio_RSAPrivateKey(mem_bio.as_ptr(), ptr::null_mut(), - Some(invoke_passwd_cb::), + Some(invoke_passwd_cb_old::), cb_ptr))); Ok(Rsa(rsa)) } @@ -429,22 +418,15 @@ mod compat { #[cfg(test)] mod test { - use libc::c_char; - use super::*; #[test] pub fn test_password() { let mut password_queried = false; let key = include_bytes!("../test/rsa-encrypted.pem"); - Rsa::private_key_from_pem_cb(key, |password| { + Rsa::private_key_from_pem_callback(key, |password| { password_queried = true; - password[0] = b'm' as c_char; - password[1] = b'y' as c_char; - password[2] = b'p' as c_char; - password[3] = b'a' as c_char; - password[4] = b's' as c_char; - password[5] = b's' as c_char; + password[..6].copy_from_slice(b"mypass"); 6 }) .unwrap(); diff --git a/openssl/src/util.rs b/openssl/src/util.rs index 302bd316..dea94668 100644 --- a/openssl/src/util.rs +++ b/openssl/src/util.rs @@ -33,10 +33,7 @@ impl Drop for CallbackState { } } -/// Password callback function, passed to private key loading functions. -/// -/// `cb_state` is expected to be a pointer to a `CallbackState`. -pub unsafe extern "C" fn invoke_passwd_cb(buf: *mut c_char, +pub unsafe extern fn invoke_passwd_cb_old(buf: *mut c_char, size: c_int, _rwflag: c_int, cb_state: *mut c_void) @@ -46,9 +43,33 @@ pub unsafe extern "C" fn invoke_passwd_cb(buf: *mut c_char, let callback = &mut *(cb_state as *mut CallbackState); let result = panic::catch_unwind(AssertUnwindSafe(|| { - // build a `i8` slice to pass to the user callback let pass_slice = slice::from_raw_parts_mut(buf, size as usize); + callback.cb.take().unwrap()(pass_slice) + })); + match result { + Ok(len) => len as c_int, + Err(err) => { + callback.panic = Some(err); + 0 + } + } +} + +/// Password callback function, passed to private key loading functions. +/// +/// `cb_state` is expected to be a pointer to a `CallbackState`. +pub unsafe extern fn invoke_passwd_cb(buf: *mut c_char, + size: c_int, + _rwflag: c_int, + cb_state: *mut c_void) + -> c_int + where F: FnOnce(&mut [u8]) -> usize +{ + let callback = &mut *(cb_state as *mut CallbackState); + + let result = panic::catch_unwind(AssertUnwindSafe(|| { + let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize); callback.cb.take().unwrap()(pass_slice) })); From 2a8923c05073d533175ed94d2931a3a79273a684 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 15:12:50 +0000 Subject: [PATCH 034/140] Macro-implement private_key_to_pem --- openssl/src/dsa.rs | 14 +------------- openssl/src/macros.rs | 19 +++++++++++++++++++ openssl/src/pkey.rs | 17 +---------------- openssl/src/rsa.rs | 16 +--------------- 4 files changed, 22 insertions(+), 44 deletions(-) diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 962fcc9c..53d7babf 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -14,19 +14,7 @@ use util::{CallbackState, invoke_passwd_cb_old}; type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free); impl DsaRef { - /// Encodes a DSA private key as unencrypted PEM formatted data. - pub fn private_key_to_pem(&self) -> Result, ErrorStack> { - assert!(self.has_private_key()); - let mem_bio = try!(MemBio::new()); - - unsafe { - try!(cvt(ffi::PEM_write_bio_DSAPrivateKey(mem_bio.as_ptr(), self.as_ptr(), - ptr::null(), ptr::null_mut(), 0, - None, ptr::null_mut()))) - }; - - Ok(mem_bio.get_buf().to_owned()) - } + private_key_to_pem!(ffi::PEM_write_bio_DSAPrivateKey); /// Encodes a DSA public key as PEM formatted data. pub fn public_key_to_pem(&self) -> Result, ErrorStack> { diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 0db3401c..b225f322 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -75,3 +75,22 @@ macro_rules! private_key_from_pem { } } } + +macro_rules! private_key_to_pem { + ($f:path) => { + /// Serializes the private key to PEM. + pub fn private_key_to_pem(&self) -> Result, ::error::ErrorStack> { + unsafe { + let bio = try!(MemBio::new()); + try!(cvt($f(bio.as_ptr(), + self.as_ptr(), + ptr::null(), + ptr::null_mut(), + -1, + None, + ptr::null_mut()))); + Ok(bio.get_buf().to_owned()) + } + } + } +} diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index a56633a2..27b36c4b 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -48,22 +48,7 @@ impl PKeyRef { } } - /// Encodes the private key in the PEM format. - // FIXME: also add password and encryption - pub fn private_key_to_pem(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - try!(cvt(ffi::PEM_write_bio_PrivateKey(mem_bio.as_ptr(), - self.as_ptr(), - ptr::null(), - ptr::null_mut(), - -1, - None, - ptr::null_mut()))); - - } - Ok(mem_bio.get_buf().to_owned()) - } + private_key_to_pem!(ffi::PEM_write_bio_PrivateKey); /// Encodes the public key in the PEM format. pub fn public_key_to_pem(&self) -> Result, ErrorStack> { diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 22668e19..3ebbe542 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -23,21 +23,7 @@ pub const PKCS1_OAEP_PADDING: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING); type_!(Rsa, RsaRef, ffi::RSA, ffi::RSA_free); impl RsaRef { - /// Writes an RSA private key as unencrypted PEM formatted data - pub fn private_key_to_pem(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - - unsafe { - try!(cvt(ffi::PEM_write_bio_RSAPrivateKey(mem_bio.as_ptr(), - self.as_ptr(), - ptr::null(), - ptr::null_mut(), - 0, - None, - ptr::null_mut()))); - } - Ok(mem_bio.get_buf().to_owned()) - } + private_key_to_pem!(ffi::PEM_write_bio_RSAPrivateKey); /// Writes an RSA public key as PEM formatted data pub fn public_key_to_pem(&self) -> Result, ErrorStack> { From 7d411c7975cf578205f81c2e1440c1b482a8a1a8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 15:27:39 +0000 Subject: [PATCH 035/140] Add private_key_from_pem_passphrase --- openssl/src/dsa.rs | 6 ++++++ openssl/src/ec_key.rs | 2 ++ openssl/src/macros.rs | 25 +++++++++++++++++++++++-- openssl/src/rsa.rs | 6 ++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 53d7babf..86476aac 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -216,6 +216,12 @@ mod test { #[test] pub fn test_password() { + let key = include_bytes!("../test/dsa-encrypted.pem"); + Dsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); + } + + #[test] + pub fn test_password_callback() { let mut password_queried = false; let key = include_bytes!("../test/dsa-encrypted.pem"); Dsa::private_key_from_pem_callback(key, |password| { diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 99d62ad3..7406572a 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -11,6 +11,8 @@ use types::OpenSslTypeRef; type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); impl EcKeyRef { + private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); + /// Serializes the private key components to DER. pub fn private_key_to_der(&self) -> Result, ErrorStack> { unsafe { diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index b225f322..9f1d7746 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -52,6 +52,27 @@ macro_rules! private_key_from_pem { } } + /// Deserializes a PEM-formatted private key, using the supplied password if the key is + /// encrypted. + /// + /// # Panics + /// + /// Panics if `passphrase` contains an embedded null. + pub fn private_key_from_pem_passphrase(pem: &[u8], + passphrase: &[u8]) + -> Result<$t, ::error::ErrorStack> { + unsafe { + ffi::init(); + let bio = try!(::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($t) + } + } + /// Deserializes a PEM-formatted private key, using a callback to retrieve a password if the /// key is encrypted. /// @@ -69,7 +90,7 @@ macro_rules! private_key_from_pem { cvt_p($f(bio.as_ptr(), ptr::null_mut(), Some(::util::invoke_passwd_cb::), - &mut cb as *mut _ as *mut ::libc::c_void)) + &mut cb as *mut _ as *mut _)) .map($t) } } @@ -81,7 +102,7 @@ macro_rules! private_key_to_pem { /// Serializes the private key to PEM. pub fn private_key_to_pem(&self) -> Result, ::error::ErrorStack> { unsafe { - let bio = try!(MemBio::new()); + let bio = try!(::bio::MemBio::new()); try!(cvt($f(bio.as_ptr(), self.as_ptr(), ptr::null(), diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 3ebbe542..bf127abe 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -408,6 +408,12 @@ mod test { #[test] pub fn test_password() { + let key = include_bytes!("../test/rsa-encrypted.pem"); + Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); + } + + #[test] + pub fn test_password_callback() { let mut password_queried = false; let key = include_bytes!("../test/rsa-encrypted.pem"); Rsa::private_key_from_pem_callback(key, |password| { From 387e78257b578fef5933142085aefa1c76722b49 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 16:09:52 +0000 Subject: [PATCH 036/140] Support serialization of encrypted private keys Switch to PEM_write_bio_PKCS8PrivateKey since the other function outputs nonstandard PEM when encrypting. --- openssl-sys/src/lib.rs | 4 ++++ openssl/src/dsa.rs | 10 ++++++++++ openssl/src/macros.rs | 20 ++++++++++++++++++++ openssl/src/pkey.rs | 12 +++++++++++- openssl/src/rsa.rs | 16 +++++++++++++--- 5 files changed, 58 insertions(+), 4 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 1b84b690..63714b7e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1496,6 +1496,10 @@ extern { kstr: *mut c_uchar, klen: c_int, callback: Option, user_data: *mut c_void) -> c_int; + pub fn PEM_write_bio_PKCS8PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER, + kstr: *mut c_char, klen: c_int, + callback: Option, + user_data: *mut c_void) -> c_int; pub fn PEM_write_bio_PUBKEY(bp: *mut BIO, x: *mut EVP_PKEY) -> c_int; pub fn PEM_write_bio_RSAPrivateKey(bp: *mut BIO, rsa: *mut RSA, cipher: *const EVP_CIPHER, kstr: *mut c_uchar, klen: c_int, diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 86476aac..39f98475 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -207,6 +207,8 @@ mod compat { #[cfg(test)] mod test { + use symm::Cipher; + use super::*; #[test] @@ -220,6 +222,14 @@ mod test { Dsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); } + #[test] + fn test_to_password() { + let key = Dsa::generate(2048).unwrap(); + let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar").unwrap(); + Dsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); + assert!(Dsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); + } + #[test] pub fn test_password_callback() { let mut password_queried = false; diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 9f1d7746..6c37f7b0 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -113,5 +113,25 @@ macro_rules! private_key_to_pem { Ok(bio.get_buf().to_owned()) } } + + /// Serializes the private key to PEM, encrypting it with the specified symmetric cipher and + /// passphrase. + pub fn private_key_to_pem_passphrase(&self, + cipher: ::symm::Cipher, + passphrase: &[u8]) + -> Result, ::error::ErrorStack> { + unsafe { + let bio = try!(::bio::MemBio::new()); + assert!(passphrase.len() <= ::libc::c_int::max_value() as usize); + try!(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()) + } + } } } diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 27b36c4b..079a04cc 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -48,7 +48,7 @@ impl PKeyRef { } } - private_key_to_pem!(ffi::PEM_write_bio_PrivateKey); + private_key_to_pem!(ffi::PEM_write_bio_PKCS8PrivateKey); /// Encodes the public key in the PEM format. pub fn public_key_to_pem(&self) -> Result, ErrorStack> { @@ -185,6 +185,7 @@ impl PKey { #[cfg(test)] mod tests { + use symm::Cipher; use dh::Dh; use dsa::Dsa; use ec_key::EcKey; @@ -193,6 +194,15 @@ mod tests { use super::*; + #[test] + fn test_to_password() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + let pem = pkey.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar").unwrap(); + PKey::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); + assert!(PKey::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); + } + #[test] fn test_private_key_from_pem() { let key = include_bytes!("../test/key.pem"); diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index bf127abe..5f94fd82 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -404,16 +404,18 @@ mod compat { #[cfg(test)] mod test { + use symm::Cipher; + use super::*; #[test] - pub fn test_password() { + fn test_from_password() { let key = include_bytes!("../test/rsa-encrypted.pem"); Rsa::private_key_from_pem_passphrase(key, b"mypass").unwrap(); } #[test] - pub fn test_password_callback() { + 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| { @@ -427,7 +429,15 @@ mod test { } #[test] - pub fn test_public_encrypt_private_decrypt_with_padding() { + 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(); From ed9f600e2889906bb928150d7e892370062f6ca1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 16:18:52 +0000 Subject: [PATCH 037/140] Make password callback return a Result --- openssl/src/dsa.rs | 2 +- openssl/src/macros.rs | 2 +- openssl/src/rsa.rs | 2 +- openssl/src/util.rs | 10 ++++++++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 39f98475..9afb952e 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -237,7 +237,7 @@ mod test { Dsa::private_key_from_pem_callback(key, |password| { password_queried = true; password[..6].copy_from_slice(b"mypass"); - 6 + Ok(6) }) .unwrap(); diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 6c37f7b0..0be5ff17 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -81,7 +81,7 @@ macro_rules! private_key_from_pem { pub fn private_key_from_pem_callback(pem: &[u8], callback: F) -> Result<$t, ::error::ErrorStack> - where F: FnOnce(&mut [u8]) -> usize + where F: FnOnce(&mut [u8]) -> Result { unsafe { ffi::init(); diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 5f94fd82..f2dd8d00 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -421,7 +421,7 @@ mod test { Rsa::private_key_from_pem_callback(key, |password| { password_queried = true; password[..6].copy_from_slice(b"mypass"); - 6 + Ok(6) }) .unwrap(); diff --git a/openssl/src/util.rs b/openssl/src/util.rs index dea94668..f4883976 100644 --- a/openssl/src/util.rs +++ b/openssl/src/util.rs @@ -4,6 +4,8 @@ use std::cell::UnsafeCell; use std::panic::{self, AssertUnwindSafe}; use std::slice; +use error::ErrorStack; + /// Wraps a user-supplied callback and a slot for panics thrown inside the callback (while FFI /// frames are on the stack). /// @@ -64,7 +66,7 @@ pub unsafe extern fn invoke_passwd_cb(buf: *mut c_char, _rwflag: c_int, cb_state: *mut c_void) -> c_int - where F: FnOnce(&mut [u8]) -> usize + where F: FnOnce(&mut [u8]) -> Result { let callback = &mut *(cb_state as *mut CallbackState); @@ -74,7 +76,11 @@ pub unsafe extern fn invoke_passwd_cb(buf: *mut c_char, })); match result { - Ok(len) => len as c_int, + Ok(Ok(len)) => len as c_int, + Ok(Err(_)) => { + // FIXME restore error stack + 0 + } Err(err) => { callback.panic = Some(err); 0 From b0415f466c4b62f949b1e47e6b1e703d1b24122b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 16:52:19 +0000 Subject: [PATCH 038/140] Macroise to_der --- openssl-sys/src/lib.rs | 4 ++++ openssl/src/dh.rs | 10 +--------- openssl/src/dsa.rs | 21 ++------------------- openssl/src/ec_key.rs | 12 ++---------- openssl/src/macros.rs | 35 +++++++++++++++++++++++++++++++++++ openssl/src/pkey.rs | 21 +++------------------ openssl/src/rsa.rs | 21 ++------------------- openssl/src/x509/mod.rs | 18 ++---------------- 8 files changed, 51 insertions(+), 91 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 63714b7e..517707c3 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1761,10 +1761,14 @@ extern { pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509; pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int; + pub fn i2d_X509(x: *mut X509, buf: *mut *mut u8) -> c_int; pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int; + pub fn i2d_X509_REQ(x: *mut X509_REQ, buf: *mut *mut u8) -> c_int; pub fn i2d_PUBKEY_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int; pub fn i2d_PrivateKey_bio(b: *mut BIO, x: *mut EVP_PKEY) -> c_int; + pub fn i2d_PUBKEY(k: *mut EVP_PKEY, buf: *mut *mut u8) -> c_int; + pub fn i2d_PrivateKey(k: *mut EVP_PKEY, buf: *mut *mut u8) -> c_int; pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *mut *mut u8) -> c_int; pub fn d2i_RSA_PUBKEY(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index ad1ebf9f..2b0a1508 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -22,15 +22,7 @@ impl DhRef { Ok(mem_bio.get_buf().to_owned()) } - /// Encodes the parameters to DER. - pub fn to_der(&self) -> Result, ErrorStack> { - unsafe { - let len = try!(cvt(ffi::i2d_DHparams(self.as_ptr(), ptr::null_mut()))); - let mut buf = vec![0; len as usize]; - try!(cvt(ffi::i2d_DHparams(self.as_ptr(), &mut buf.as_mut_ptr()))); - Ok(buf) - } - } + to_der!(ffi::i2d_DHparams); } impl Dh { diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 9afb952e..0444ed9f 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -25,25 +25,8 @@ impl DsaRef { Ok(mem_bio.get_buf().to_owned()) } - /// Encodes a DSA private key as unencrypted DER formatted data. - pub fn private_key_to_der(&self) -> Result, ErrorStack> { - unsafe { - let len = try!(cvt(ffi::i2d_DSAPrivateKey(self.as_ptr(), ptr::null_mut()))); - let mut buf = vec![0; len as usize]; - try!(cvt(ffi::i2d_DSAPrivateKey(self.as_ptr(), &mut buf.as_mut_ptr()))); - Ok(buf) - } - } - - /// Encodes a DSA public key as DER formatted data. - pub fn public_key_to_der(&self) -> Result, ErrorStack> { - unsafe { - let len = try!(cvt(ffi::i2d_DSAPublicKey(self.as_ptr(), ptr::null_mut()))); - let mut buf = vec![0; len as usize]; - try!(cvt(ffi::i2d_DSAPublicKey(self.as_ptr(), &mut buf.as_mut_ptr()))); - Ok(buf) - } - } + private_key_to_der!(ffi::i2d_DSAPrivateKey); + public_key_to_der!(ffi::i2d_DSAPublicKey); // FIXME should return u32 pub fn size(&self) -> Option { diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 7406572a..706265ef 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -12,16 +12,7 @@ type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); impl EcKeyRef { private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); - - /// Serializes the private key components to DER. - pub fn private_key_to_der(&self) -> Result, ErrorStack> { - unsafe { - let len = try!(cvt(ffi::i2d_ECPrivateKey(self.as_ptr(), ptr::null_mut()))); - let mut buf = vec![0; len as usize]; - try!(cvt(ffi::i2d_ECPrivateKey(self.as_ptr(), &mut buf.as_mut_ptr()))); - Ok(buf) - } - } + private_key_to_der!(ffi::i2d_ECPrivateKey); } impl EcKey { @@ -31,6 +22,7 @@ impl EcKey { cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) } } + /// Deserializes a DER-encoded private key. pub fn private_key_from_der(der: &[u8]) -> Result { unsafe { diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 0be5ff17..7fa15d1f 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -135,3 +135,38 @@ macro_rules! private_key_to_pem { } } } + +macro_rules! to_der_inner { + (#[$m:meta] $n:ident, $f:path) => { + #[$m] + pub fn $n(&self) -> Result, ::error::ErrorStack> { + unsafe { + let len = try!(::cvt($f(::types::OpenSslTypeRef::as_ptr(self), ptr::null_mut()))); + let mut buf = vec![0; len as usize]; + try!(::cvt($f(::types::OpenSslTypeRef::as_ptr(self), &mut buf.as_mut_ptr()))); + Ok(buf) + } + } + }; +} + +macro_rules! to_der { + ($f:path) => { + to_der_inner!(/// Serializes this value to DER. + to_der, $f); + } +} + +macro_rules! private_key_to_der { + ($f:path) => { + to_der_inner!(/// Serializes the private key to DER. + private_key_to_der, $f); + } +} + +macro_rules! public_key_to_der { + ($f:path) => { + to_der_inner!(/// Serializes the public key to DER. + public_key_to_der, $f); + } +} diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 079a04cc..05df2f4b 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -50,6 +50,9 @@ impl PKeyRef { private_key_to_pem!(ffi::PEM_write_bio_PKCS8PrivateKey); + private_key_to_der!(ffi::i2d_PrivateKey); + public_key_to_der!(ffi::i2d_PUBKEY); + /// Encodes the public key in the PEM format. pub fn public_key_to_pem(&self) -> Result, ErrorStack> { let mem_bio = try!(MemBio::new()); @@ -59,24 +62,6 @@ impl PKeyRef { Ok(mem_bio.get_buf().to_owned()) } - /// Encodes the public key in the DER format. - pub fn public_key_to_der(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - try!(cvt(ffi::i2d_PUBKEY_bio(mem_bio.as_ptr(), self.as_ptr()))); - } - Ok(mem_bio.get_buf().to_owned()) - } - - /// Encodes the private key in the DER format - pub fn private_key_to_der(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - try!(cvt(ffi::i2d_PrivateKey_bio(mem_bio.as_ptr(), self.as_ptr()))); - } - Ok(mem_bio.get_buf().to_owned()) - } - /// Returns the size of the key. /// /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index f2dd8d00..89c0bb85 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -36,25 +36,8 @@ impl RsaRef { Ok(mem_bio.get_buf().to_owned()) } - /// Encodes an RSA private key as unencrypted DER formatted data. - pub fn private_key_to_der(&self) -> Result, ErrorStack> { - unsafe { - let len = try!(cvt(ffi::i2d_RSAPrivateKey(self.as_ptr(), ptr::null_mut()))); - let mut buf = vec![0; len as usize]; - try!(cvt(ffi::i2d_RSAPrivateKey(self.as_ptr(), &mut buf.as_mut_ptr()))); - Ok(buf) - } - } - - /// Encodes an RSA public key as DER formatted data. - pub fn public_key_to_der(&self) -> Result, ErrorStack> { - unsafe { - let len = try!(cvt(ffi::i2d_RSA_PUBKEY(self.as_ptr(), ptr::null_mut()))); - let mut buf = vec![0; len as usize]; - try!(cvt(ffi::i2d_RSA_PUBKEY(self.as_ptr(), &mut buf.as_mut_ptr()))); - Ok(buf) - } - } + private_key_to_der!(ffi::i2d_RSAPrivateKey); + public_key_to_der!(ffi::i2d_RSA_PUBKEY); // FIXME should return u32 pub fn size(&self) -> usize { diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index e7c633d0..74f586c2 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -425,14 +425,7 @@ impl X509Ref { Ok(mem_bio.get_buf().to_owned()) } - /// Returns a DER serialized form of the certificate - pub fn to_der(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - ffi::i2d_X509_bio(mem_bio.as_ptr(), self.as_ptr()); - } - Ok(mem_bio.get_buf().to_owned()) - } + to_der!(ffi::i2d_X509); } impl ToOwned for X509Ref { @@ -575,14 +568,7 @@ impl X509ReqRef { Ok(mem_bio.get_buf().to_owned()) } - /// Returns a DER serialized form of the CSR - pub fn to_der(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - ffi::i2d_X509_REQ_bio(mem_bio.as_ptr(), self.as_ptr()); - } - Ok(mem_bio.get_buf().to_owned()) - } + to_der!(ffi::i2d_X509_REQ); } impl X509Req { From 48c0009418cbbf7c69c24b35d56e80edb0c80d45 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 17:06:50 +0000 Subject: [PATCH 039/140] Macroise from_der --- openssl-sys/src/lib.rs | 1 + openssl/src/dh.rs | 12 +----------- openssl/src/dsa.rs | 25 +++---------------------- openssl/src/ec_key.rs | 12 +----------- openssl/src/macros.rs | 35 +++++++++++++++++++++++++++++++++++ openssl/src/pkcs12.rs | 22 ++++++---------------- openssl/src/rsa.rs | 25 +++---------------------- openssl/src/x509/mod.rs | 13 +++---------- 8 files changed, 53 insertions(+), 92 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 517707c3..4ba706f9 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1760,6 +1760,7 @@ extern { pub fn i2d_ECPrivateKey(ec_key: *mut EC_KEY, pp: *mut *mut c_uchar) -> c_int; pub fn d2i_X509(a: *mut *mut X509, pp: *mut *const c_uchar, length: c_long) -> *mut X509; + pub fn d2i_X509_REQ(a: *mut *mut X509_REQ, pp: *mut *const c_uchar, length: c_long) -> *mut X509_REQ; pub fn i2d_X509_bio(b: *mut BIO, x: *mut X509) -> c_int; pub fn i2d_X509(x: *mut X509, buf: *mut *mut u8) -> c_int; pub fn i2d_X509_REQ_bio(b: *mut BIO, x: *mut X509_REQ) -> c_int; diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index 2b0a1508..604d4f5a 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -1,7 +1,5 @@ use error::ErrorStack; use ffi; -use libc::c_long; -use std::cmp; use std::mem; use std::ptr; @@ -49,15 +47,7 @@ impl Dh { } } - /// Reads Diffie-Hellman parameters from DER. - pub fn from_der(buf: &[u8]) -> Result { - unsafe { - init(); - let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; - let dh = try!(cvt_p(ffi::d2i_DHparams(ptr::null_mut(), &mut buf.as_ptr(), len))); - Ok(Dh(dh)) - } - } + from_der!(Dh, ffi::d2i_DHparams); /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 0444ed9f..478272c8 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -1,9 +1,8 @@ use error::ErrorStack; use ffi; -use libc::{c_int, c_char, c_void, c_long}; +use libc::{c_int, c_char, c_void}; use std::fmt; use std::ptr; -use std::cmp; use bio::{MemBio, MemBioSlice}; use bn::BigNumRef; @@ -97,6 +96,8 @@ impl Dsa { } private_key_from_pem!(Dsa, ffi::PEM_read_bio_DSAPrivateKey); + private_key_from_der!(Dsa, ffi::d2i_DSAPrivateKey); + public_key_from_der!(Dsa, ffi::d2i_DSAPublicKey); #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result @@ -129,26 +130,6 @@ impl Dsa { Ok(Dsa(dsa)) } } - - /// Reads a DSA private key from DER formatted data. - pub fn private_key_from_der(buf: &[u8]) -> Result { - unsafe { - ffi::init(); - let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; - let dsa = try!(cvt_p(ffi::d2i_DSAPrivateKey(ptr::null_mut(), &mut buf.as_ptr(), len))); - Ok(Dsa(dsa)) - } - } - - /// Reads a DSA public key from DER formatted data. - pub fn public_key_from_der(buf: &[u8]) -> Result { - unsafe { - ffi::init(); - let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; - let dsa = try!(cvt_p(ffi::d2i_DSAPublicKey(ptr::null_mut(), &mut buf.as_ptr(), len))); - Ok(Dsa(dsa)) - } - } } impl fmt::Debug for Dsa { diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 706265ef..268a6fd2 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -1,6 +1,4 @@ use ffi; -use std::cmp; -use libc::c_long; use std::ptr; use {cvt, cvt_p, init}; @@ -23,16 +21,8 @@ impl EcKey { } } - /// Deserializes a DER-encoded private key. - pub fn private_key_from_der(der: &[u8]) -> Result { - unsafe { - init(); - let len = cmp::min(der.len(), c_long::max_value() as usize) as c_long; - cvt_p(ffi::d2i_ECPrivateKey(ptr::null_mut(), &mut der.as_ptr(), len)).map(EcKey) - } - } - private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); + private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); } #[cfg(test)] diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 7fa15d1f..39944124 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -170,3 +170,38 @@ macro_rules! public_key_to_der { public_key_to_der, $f); } } + +macro_rules! from_der_inner { + (#[$m:meta] $n:ident, $t:ident, $f:path) => { + #[$m] + pub fn $n(der: &[u8]) -> Result<$t, ::error::ErrorStack> { + unsafe { + ::ffi::init(); + let len = ::std::cmp::min(der.len(), ::libc::c_long::max_value() as usize) as ::libc::c_long; + ::cvt_p($f(::std::ptr::null_mut(), &mut der.as_ptr(), len)) + .map($t) + } + } + } +} + +macro_rules! from_der { + ($t:ident, $f:path) => { + from_der_inner!(/// Deserializes a value from DER-formatted data. + from_der, $t, $f); + } +} + +macro_rules! private_key_from_der { + ($t:ident, $f:path) => { + from_der_inner!(/// Deserializes a private key from DER-formatted data. + private_key_from_der, $t, $f); + } +} + +macro_rules! public_key_from_der { + ($t:ident, $f:path) => { + from_der_inner!(/// Deserializes a public key from DER-formatted data. + public_key_from_der, $t, $f); + } +} diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index 9c224ccd..ee9ae124 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -1,12 +1,10 @@ //! PKCS #12 archives. use ffi; -use libc::{c_long, c_uchar}; -use std::cmp; use std::ptr; use std::ffi::CString; -use {cvt, cvt_p}; +use cvt; use pkey::PKey; use error::ErrorStack; use x509::X509; @@ -15,21 +13,9 @@ use stack::Stack; type_!(Pkcs12, Pkcs12Ref, ffi::PKCS12, ffi::PKCS12_free); -impl Pkcs12 { - /// Deserializes a `Pkcs12` structure from DER-encoded data. - pub fn from_der(der: &[u8]) -> Result { - unsafe { - ffi::init(); - let mut ptr = der.as_ptr() as *const c_uchar; - let length = cmp::min(der.len(), c_long::max_value() as usize) as c_long; - let p12 = try!(cvt_p(ffi::d2i_PKCS12(ptr::null_mut(), &mut ptr, length))); - Ok(Pkcs12(p12)) - } - } -} - impl Pkcs12Ref { /// Extracts the contents of the `Pkcs12`. + // FIXME should take an &[u8] pub fn parse(&self, pass: &str) -> Result { unsafe { let pass = CString::new(pass).unwrap(); @@ -57,6 +43,10 @@ impl Pkcs12Ref { } } +impl Pkcs12 { + from_der!(Pkcs12, ffi::d2i_PKCS12); +} + pub struct ParsedPkcs12 { pub pkey: PKey, pub cert: X509, diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 89c0bb85..5090f6ad 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -1,9 +1,8 @@ use ffi; -use std::cmp; use std::fmt; use std::ptr; use std::mem; -use libc::{c_int, c_void, c_char, c_long}; +use libc::{c_int, c_void, c_char}; use {cvt, cvt_p, cvt_n}; use bn::{BigNum, BigNumRef}; @@ -251,6 +250,8 @@ impl Rsa { } private_key_from_pem!(Rsa, ffi::PEM_read_bio_RSAPrivateKey); + private_key_from_der!(Rsa, ffi::d2i_RSAPrivateKey); + public_key_from_der!(Rsa, ffi::d2i_RSA_PUBKEY); #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result @@ -282,26 +283,6 @@ impl Rsa { Ok(Rsa(rsa)) } } - - /// Reads an RSA private key from DER formatted data. - pub fn private_key_from_der(buf: &[u8]) -> Result { - unsafe { - ffi::init(); - let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; - let dsa = try!(cvt_p(ffi::d2i_RSAPrivateKey(ptr::null_mut(), &mut buf.as_ptr(), len))); - Ok(Rsa(dsa)) - } - } - - /// Reads an RSA public key from DER formatted data. - pub fn public_key_from_der(buf: &[u8]) -> Result { - unsafe { - ffi::init(); - let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; - let dsa = try!(cvt_p(ffi::d2i_RSA_PUBKEY(ptr::null_mut(), &mut buf.as_ptr(), len))); - Ok(Rsa(dsa)) - } - } } impl fmt::Debug for Rsa { diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 74f586c2..0a5a6c4d 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -1,6 +1,5 @@ use libc::{c_char, c_int, c_long, c_ulong}; use std::borrow::Borrow; -use std::cmp; use std::collections::HashMap; use std::error::Error; use std::ffi::{CStr, CString}; @@ -440,15 +439,7 @@ impl ToOwned for X509Ref { } impl X509 { - /// Reads a certificate from DER. - pub fn from_der(buf: &[u8]) -> Result { - unsafe { - let mut ptr = buf.as_ptr(); - let len = cmp::min(buf.len(), c_long::max_value() as usize) as c_long; - let x509 = try!(cvt_p(ffi::d2i_X509(ptr::null_mut(), &mut ptr, len))); - Ok(X509::from_ptr(x509)) - } - } + from_der!(X509, ffi::d2i_X509); /// Reads a certificate from PEM. pub fn from_pem(buf: &[u8]) -> Result { @@ -583,6 +574,8 @@ impl X509Req { Ok(X509Req::from_ptr(handle)) } } + + from_der!(X509Req, ffi::d2i_X509_REQ); } /// A collection of X.509 extensions. From df9666c334f29d4d0887919c2b35c45092960d3a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 17:42:45 +0000 Subject: [PATCH 040/140] Macroise to_pem --- openssl/src/dh.rs | 12 ++---------- openssl/src/macros.rs | 27 +++++++++++++++++++++++++++ openssl/src/x509/mod.rs | 30 +++++++----------------------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index 604d4f5a..37663ac0 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -4,22 +4,14 @@ use std::mem; use std::ptr; use {cvt, cvt_p, init}; -use bio::{MemBio, MemBioSlice}; +use bio::MemBioSlice; use bn::BigNum; use types::OpenSslTypeRef; type_!(Dh, DhRef, ffi::DH, ffi::DH_free); impl DhRef { - /// Encodes the parameters to PEM. - pub fn to_pem(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - try!(cvt(ffi::PEM_write_bio_DHparams(mem_bio.as_ptr(), self.as_ptr()))); - } - Ok(mem_bio.get_buf().to_owned()) - } - + to_pem!(ffi::PEM_write_bio_DHparams); to_der!(ffi::i2d_DHparams); } diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index 39944124..a57f36eb 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -136,6 +136,33 @@ macro_rules! private_key_to_pem { } } +macro_rules! to_pem_inner { + (#[$m:meta] $n:ident, $f:path) => { + #[$m] + pub fn $n(&self) -> Result, ::error::ErrorStack> { + unsafe { + let bio = try!(::bio::MemBio::new()); + try!(cvt($f(bio.as_ptr(), self.as_ptr()))); + Ok(bio.get_buf().to_owned()) + } + } + } +} + +macro_rules! public_key_to_pem { + ($f:path) => { + to_pem_inner!(/// Serializes a public key to PEM. + public_key_to_pem, $f); + } +} + +macro_rules! to_pem { + ($f:path) => { + to_pem_inner!(/// Serializes this value to PEM. + to_pem, $f); + } +} + macro_rules! to_der_inner { (#[$m:meta] $n:ident, $f:path) => { #[$m] diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 0a5a6c4d..8a739ec6 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -12,7 +12,7 @@ use std::str; use {cvt, cvt_p}; use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef}; -use bio::{MemBio, MemBioSlice}; +use bio::MemBioSlice; use hash::MessageDigest; use pkey::{PKey, PKeyRef}; use rand::rand_bytes; @@ -415,15 +415,7 @@ impl X509Ref { } } - /// Writes certificate as PEM - pub fn to_pem(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - try!(cvt(ffi::PEM_write_bio_X509(mem_bio.as_ptr(), self.as_ptr()))); - } - Ok(mem_bio.get_buf().to_owned()) - } - + to_pem!(ffi::PEM_write_bio_X509); to_der!(ffi::i2d_X509); } @@ -549,19 +541,6 @@ impl X509NameEntryRef { type_!(X509Req, X509ReqRef, ffi::X509_REQ, ffi::X509_REQ_free); -impl X509ReqRef { - /// Writes CSR as PEM - pub fn to_pem(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - if unsafe { ffi::PEM_write_bio_X509_REQ(mem_bio.as_ptr(), self.as_ptr()) } != 1 { - return Err(ErrorStack::get()); - } - Ok(mem_bio.get_buf().to_owned()) - } - - to_der!(ffi::i2d_X509_REQ); -} - impl X509Req { /// Reads CSR from PEM pub fn from_pem(buf: &[u8]) -> Result { @@ -578,6 +557,11 @@ impl X509Req { from_der!(X509Req, ffi::d2i_X509_REQ); } +impl X509ReqRef { + to_pem!(ffi::PEM_write_bio_X509_REQ); + to_der!(ffi::i2d_X509_REQ); +} + /// A collection of X.509 extensions. /// /// Upholds the invariant that a certificate MUST NOT include more than one From ccef9e339dc3717761fc9e70c34f1df86b608579 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 17:56:48 +0000 Subject: [PATCH 041/140] Macroise from_pem --- openssl/src/dh.rs | 15 +-------------- openssl/src/dsa.rs | 15 +-------------- openssl/src/macros.rs | 39 ++++++++++++++++++++++++++++++--------- openssl/src/pkey.rs | 14 +------------- openssl/src/rsa.rs | 14 +------------- openssl/src/x509/mod.rs | 13 +------------ 6 files changed, 35 insertions(+), 75 deletions(-) diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index 37663ac0..64494f95 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -4,7 +4,6 @@ use std::mem; use std::ptr; use {cvt, cvt_p, init}; -use bio::MemBioSlice; use bn::BigNum; use types::OpenSslTypeRef; @@ -26,19 +25,7 @@ impl Dh { } } - /// Reads Diffie-Hellman parameters from PEM. - pub fn from_pem(buf: &[u8]) -> Result { - unsafe { - init(); - let mem_bio = try!(MemBioSlice::new(buf)); - cvt_p(ffi::PEM_read_bio_DHparams(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut())) - .map(Dh) - } - } - + from_pem!(Dh, ffi::PEM_read_bio_DHparams); from_der!(Dh, ffi::d2i_DHparams); /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0. diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 478272c8..fbef2c18 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -97,6 +97,7 @@ impl Dsa { private_key_from_pem!(Dsa, ffi::PEM_read_bio_DSAPrivateKey); private_key_from_der!(Dsa, ffi::d2i_DSAPrivateKey); + public_key_from_pem!(Dsa, ffi::PEM_read_bio_DSA_PUBKEY); public_key_from_der!(Dsa, ffi::d2i_DSAPublicKey); #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] @@ -116,20 +117,6 @@ impl Dsa { Ok(Dsa(dsa)) } } - - /// Reads a DSA public key from PEM formatted data. - pub fn public_key_from_pem(buf: &[u8]) -> Result { - ffi::init(); - - let mem_bio = try!(MemBioSlice::new(buf)); - unsafe { - let dsa = try!(cvt_p(ffi::PEM_read_bio_DSA_PUBKEY(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut()))); - Ok(Dsa(dsa)) - } - } } impl fmt::Debug for Dsa { diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index a57f36eb..b36e8319 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -42,15 +42,8 @@ macro_rules! type_ { macro_rules! private_key_from_pem { ($t:ident, $f:path) => { - /// Deserializes a PEM-formatted private key. - pub fn private_key_from_pem(pem: &[u8]) -> Result<$t, ::error::ErrorStack> { - unsafe { - ::init(); - let bio = try!(::bio::MemBioSlice::new(pem)); - cvt_p($f(bio.as_ptr(), ::std::ptr::null_mut(), None, ::std::ptr::null_mut())) - .map($t) - } - } + from_pem_inner!(/// Deserializes a PEM-formatted private key. + private_key_from_pem, $t, $f); /// Deserializes a PEM-formatted private key, using the supplied password if the key is /// encrypted. @@ -232,3 +225,31 @@ macro_rules! public_key_from_der { public_key_from_der, $t, $f); } } + +macro_rules! from_pem_inner { + (#[$m:meta] $n:ident, $t:ident, $f:path) => { + #[$m] + pub fn $n(pem: &[u8]) -> Result<$t, ::error::ErrorStack> { + unsafe { + ::init(); + let bio = try!(::bio::MemBioSlice::new(pem)); + cvt_p($f(bio.as_ptr(), ::std::ptr::null_mut(), None, ::std::ptr::null_mut())) + .map($t) + } + } + } +} + +macro_rules! public_key_from_pem { + ($t:ident, $f:path) => { + from_pem_inner!(/// Deserializes a public key from PEM-formatted data. + public_key_from_pem, $t, $f); + } +} + +macro_rules! from_pem { + ($t:ident, $f:path) => { + from_pem_inner!(/// Deserializes a value from PEM-formatted data. + from_pem, $t, $f); + } +} diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 05df2f4b..b5ccd3cc 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -137,6 +137,7 @@ impl PKey { } private_key_from_pem!(PKey, ffi::PEM_read_bio_PrivateKey); + public_key_from_pem!(PKey, ffi::PEM_read_bio_PUBKEY); #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] pub fn private_key_from_pem_cb(buf: &[u8], pass_cb: F) -> Result @@ -153,19 +154,6 @@ impl PKey { Ok(PKey::from_ptr(evp)) } } - - /// Reads a public key from PEM. - pub fn public_key_from_pem(buf: &[u8]) -> Result { - ffi::init(); - let mem_bio = try!(MemBioSlice::new(buf)); - unsafe { - let evp = try!(cvt_p(ffi::PEM_read_bio_PUBKEY(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut()))); - Ok(PKey::from_ptr(evp)) - } - } } #[cfg(test)] diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 5090f6ad..68fc9584 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -251,6 +251,7 @@ impl Rsa { private_key_from_pem!(Rsa, ffi::PEM_read_bio_RSAPrivateKey); private_key_from_der!(Rsa, ffi::d2i_RSAPrivateKey); + public_key_from_pem!(Rsa, ffi::PEM_read_bio_RSA_PUBKEY); public_key_from_der!(Rsa, ffi::d2i_RSA_PUBKEY); #[deprecated(since = "0.9.2", note = "use private_key_from_pem_callback")] @@ -270,19 +271,6 @@ impl Rsa { Ok(Rsa(rsa)) } } - - /// Reads an RSA public key from PEM formatted data. - pub fn public_key_from_pem(buf: &[u8]) -> Result { - ffi::init(); - let mem_bio = try!(MemBioSlice::new(buf)); - unsafe { - let rsa = try!(cvt_p(ffi::PEM_read_bio_RSA_PUBKEY(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut()))); - Ok(Rsa(rsa)) - } - } } impl fmt::Debug for Rsa { diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 8a739ec6..68652f8e 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -431,19 +431,8 @@ impl ToOwned for X509Ref { } impl X509 { + from_pem!(X509, ffi::PEM_read_bio_X509); from_der!(X509, ffi::d2i_X509); - - /// Reads a certificate from PEM. - pub fn from_pem(buf: &[u8]) -> Result { - let mem_bio = try!(MemBioSlice::new(buf)); - unsafe { - let handle = try!(cvt_p(ffi::PEM_read_bio_X509(mem_bio.as_ptr(), - ptr::null_mut(), - None, - ptr::null_mut()))); - Ok(X509::from_ptr(handle)) - } - } } impl Clone for X509 { From 7dbef567e6cec78adb1d7ec55735935ca7de20fd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 18:00:42 +0000 Subject: [PATCH 042/140] Remove some stray manual impls --- openssl/src/dsa.rs | 12 ++---------- openssl/src/pkey.rs | 12 ++---------- openssl/src/rsa.rs | 14 ++------------ 3 files changed, 6 insertions(+), 32 deletions(-) diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index fbef2c18..a4a8bf30 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -4,7 +4,7 @@ use libc::{c_int, c_char, c_void}; use std::fmt; use std::ptr; -use bio::{MemBio, MemBioSlice}; +use bio::MemBioSlice; use bn::BigNumRef; use {cvt, cvt_p}; use types::OpenSslTypeRef; @@ -14,15 +14,7 @@ type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free); impl DsaRef { private_key_to_pem!(ffi::PEM_write_bio_DSAPrivateKey); - - /// Encodes a DSA public key as PEM formatted data. - pub fn public_key_to_pem(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - try!(cvt(ffi::PEM_write_bio_DSA_PUBKEY(mem_bio.as_ptr(), self.as_ptr()))); - } - Ok(mem_bio.get_buf().to_owned()) - } + public_key_to_pem!(ffi::PEM_write_bio_DSA_PUBKEY); private_key_to_der!(ffi::i2d_DSAPrivateKey); public_key_to_der!(ffi::i2d_DSAPublicKey); diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index b5ccd3cc..ee564836 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -4,7 +4,7 @@ use std::mem; use ffi; use {cvt, cvt_p}; -use bio::{MemBio, MemBioSlice}; +use bio::MemBioSlice; use dh::Dh; use dsa::Dsa; use ec_key::EcKey; @@ -48,20 +48,12 @@ impl PKeyRef { } } + public_key_to_pem!(ffi::PEM_write_bio_PUBKEY); private_key_to_pem!(ffi::PEM_write_bio_PKCS8PrivateKey); private_key_to_der!(ffi::i2d_PrivateKey); public_key_to_der!(ffi::i2d_PUBKEY); - /// Encodes the public key in the PEM format. - pub fn public_key_to_pem(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - unsafe { - try!(cvt(ffi::PEM_write_bio_PUBKEY(mem_bio.as_ptr(), self.as_ptr()))); - } - Ok(mem_bio.get_buf().to_owned()) - } - /// Returns the size of the key. /// /// This corresponds to the bit length of the modulus of an RSA key, and the bit length of the diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 68fc9584..8c3507f4 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -6,7 +6,7 @@ use libc::{c_int, c_void, c_char}; use {cvt, cvt_p, cvt_n}; use bn::{BigNum, BigNumRef}; -use bio::{MemBio, MemBioSlice}; +use bio::MemBioSlice; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; use types::OpenSslTypeRef; @@ -23,17 +23,7 @@ type_!(Rsa, RsaRef, ffi::RSA, ffi::RSA_free); impl RsaRef { private_key_to_pem!(ffi::PEM_write_bio_RSAPrivateKey); - - /// Writes an RSA public key as PEM formatted data - pub fn public_key_to_pem(&self) -> Result, ErrorStack> { - let mem_bio = try!(MemBio::new()); - - unsafe { - try!(cvt(ffi::PEM_write_bio_RSA_PUBKEY(mem_bio.as_ptr(), self.as_ptr()))); - } - - Ok(mem_bio.get_buf().to_owned()) - } + public_key_to_pem!(ffi::PEM_write_bio_RSA_PUBKEY); private_key_to_der!(ffi::i2d_RSAPrivateKey); public_key_to_der!(ffi::i2d_RSA_PUBKEY); From b2de36049a7687da00870e714c2e299ac5a903cd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:19:38 +0000 Subject: [PATCH 043/140] Add Some more elliptic curve functionality --- openssl-sys/src/lib.rs | 25 +++++++++ openssl/src/ec_key.rs | 114 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 4ba706f9..11fa46df 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -26,6 +26,9 @@ pub enum BN_GENCB {} pub enum CONF {} pub enum COMP_METHOD {} pub enum EC_KEY {} +pub enum EC_GROUP {} +pub enum EC_METHOD {} +pub enum EC_POINT {} pub enum ENGINE {} pub enum EVP_CIPHER_CTX {} pub enum EVP_MD {} @@ -1372,8 +1375,30 @@ extern { pub fn DH_get_2048_256() -> *mut DH; pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY; + pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP; + pub fn EC_KEY_get0_public_key(key: *const EC_KEY) -> *const EC_POINT; + pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; pub fn EC_KEY_free(key: *mut EC_KEY); + pub fn EC_GFp_simple_method() -> *const EC_METHOD; + pub fn EC_GFp_mont_method() -> *const EC_METHOD; + pub fn EC_GFp_nist_method() -> *const EC_METHOD; + pub fn EC_GFp_nistp224_method() -> *const EC_METHOD; + pub fn EC_GFp_nistp256_method() -> *const EC_METHOD; + pub fn EC_GFp_nistp521_method() -> *const EC_METHOD; + + pub fn EC_GF2m_simple_method() -> *const EC_METHOD; + + pub fn EC_GROUP_new(meth: *const EC_METHOD) -> *mut EC_GROUP; + pub fn EC_GROUP_new_curve_GFp(p: *const BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> *mut EC_GROUP; + pub fn EC_GROUP_new_curve_GF2m(p: *const BIGNUM, a: *const BIGNUM, b: *const BIGNUM, ctx: *mut BN_CTX) -> *mut EC_GROUP; + pub fn EC_GROUP_new_by_curve_name(nid: c_int) -> *mut EC_GROUP; + pub fn EC_GROUP_get_curve_GFp(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_get_curve_GF2m(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_free(group: *mut EC_GROUP); + + pub fn EC_POINT_free(point: *mut EC_POINT); + pub fn ERR_get_error() -> c_ulong; pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 268a6fd2..3b6349b5 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -2,15 +2,115 @@ use ffi; use std::ptr; use {cvt, cvt_p, init}; +use bn::{BigNumRef, BigNumContextRef}; use error::ErrorStack; use nid::Nid; use types::OpenSslTypeRef; +type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); + +impl EcGroup { + /// Returns the group of a standard named curve. + pub fn from_curve_name(nid: Nid) -> Result { + unsafe { + init(); + cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) + } + } + + /// Constructs a curve over a prime field from its components. + pub fn from_components_gfp(p: &BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + cvt_p(ffi::EC_GROUP_new_curve_GFp(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) + .map(EcGroup) + } + } + + /// Constructs a curve over a binary field from its components. + pub fn from_components_gf2m(p: &BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + cvt_p(ffi::EC_GROUP_new_curve_GF2m(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) + .map(EcGroup) + } + } + + /// Places the components of a curve over a prime field in the provided `BigNum`s. + pub fn components_gfp(&self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GFp(self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Places the components of a curve over a binary field in the provided `BigNum`s. + pub fn components_gf2m(&self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GF2m(self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } +} + +type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); + type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); impl EcKeyRef { private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); private_key_to_der!(ffi::i2d_ECPrivateKey); + + pub fn group(&self) -> &EcGroupRef { + unsafe { + let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); + assert!(!ptr.is_null()); + EcGroupRef::from_ptr(ptr as *mut _) + } + } + + pub fn public_key(&self) -> &EcPointRef { + unsafe { + let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); + assert!(!ptr.is_null()); + EcPointRef::from_ptr(ptr as *mut _) + } + } + + pub fn private_key(&self) -> Option<&BigNumRef> { + unsafe { + let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(BigNumRef::from_ptr(ptr as *mut _)) + } + } + } } impl EcKey { @@ -27,11 +127,23 @@ impl EcKey { #[cfg(test)] mod test { + use bn::{BigNum, BigNumContext}; use nid; use super::*; #[test] - fn new_by_curve_name() { + fn key_new_by_curve_name() { EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap(); } + + #[test] + fn round_trip_prime256v1() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let mut p = BigNum::new().unwrap(); + let mut a = BigNum::new().unwrap(); + let mut b = BigNum::new().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); + EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); + } } From 0d0b5080e25fb0a2f9ada042810b98d28f5e0414 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:21:44 +0000 Subject: [PATCH 044/140] Rename new_by_curve_name to from_curve_name --- openssl/src/ec_key.rs | 9 +++++++-- openssl/src/pkey.rs | 2 +- openssl/src/ssl/connector.rs | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 3b6349b5..ba9ed762 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -114,13 +114,18 @@ impl EcKeyRef { } impl EcKey { - pub fn new_by_curve_name(nid: Nid) -> Result { + pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) } } + #[deprecated(since = "0.9.2", note = "use from_curve_name")] + pub fn new_by_curve_name(nid: Nid) -> Result { + EcKey::from_curve_name(nid) + } + private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); } @@ -133,7 +138,7 @@ mod test { #[test] fn key_new_by_curve_name() { - EcKey::new_by_curve_name(nid::X9_62_PRIME256V1).unwrap(); + EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); } #[test] diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index ee564836..5739a5ed 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -221,7 +221,7 @@ mod tests { #[test] fn test_ec_key_accessor() { - let ec_key = EcKey::new_by_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(); pkey.ec_key().unwrap(); assert!(pkey.rsa().is_err()); diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 07c44ce7..c002b966 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -218,7 +218,7 @@ fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { use ec_key::EcKey; use nid; - let curve = try!(EcKey::new_by_curve_name(nid::X9_62_PRIME256V1)); + let curve = try!(EcKey::from_curve_name(nid::X9_62_PRIME256V1)); ctx.set_tmp_ecdh(&curve) } From 3d31539ba9f0c1f57869d7e50e433a0ef5850138 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:31:44 +0000 Subject: [PATCH 045/140] Public keys are not always present --- openssl/src/ec_key.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index ba9ed762..22082b42 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -93,7 +93,7 @@ impl EcKeyRef { } } - pub fn public_key(&self) -> &EcPointRef { + pub fn public_key(&self) -> Option<&EcPointRef> { unsafe { let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); assert!(!ptr.is_null()); From 1a52649516e5b3924917314ee503523d59ed528b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:46:01 +0000 Subject: [PATCH 046/140] More functionality --- openssl-sys/src/lib.rs | 5 +++++ openssl/src/ec_key.rs | 28 ++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 11fa46df..230c0148 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1374,10 +1374,15 @@ extern { #[cfg(not(ossl101))] pub fn DH_get_2048_256() -> *mut DH; + pub fn EC_KEY_new() -> *mut EC_KEY; pub fn EC_KEY_new_by_curve_name(nid: c_int) -> *mut EC_KEY; + pub fn EC_KEY_set_group(key: *mut EC_KEY, group: *const EC_GROUP) -> c_int; pub fn EC_KEY_get0_group(key: *const EC_KEY) -> *const EC_GROUP; + pub fn EC_KEY_set_public_key(key: *mut EC_KEY, key: *const EC_POINT) -> c_int; pub fn EC_KEY_get0_public_key(key: *const EC_KEY) -> *const EC_POINT; + pub fn EC_KEY_set_private_key(key: *mut EC_KEY, key: *const BIGNUM) -> c_int; pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; + pub fn EC_KEY_generate_key(key: *mut EC_KEY) -> c_int; pub fn EC_KEY_free(key: *mut EC_KEY); pub fn EC_GFp_simple_method() -> *const EC_METHOD; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 22082b42..e7e92d7a 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -96,8 +96,11 @@ impl EcKeyRef { pub fn public_key(&self) -> Option<&EcPointRef> { unsafe { let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); - assert!(!ptr.is_null()); - EcPointRef::from_ptr(ptr as *mut _) + if ptr.is_null() { + None + } else { + Some(EcPointRef::from_ptr(ptr as *mut _)) + } } } @@ -114,6 +117,9 @@ impl EcKeyRef { } impl EcKey { + /// Constructs an `EcKey` corresponding to a known curve. + /// + /// It will not have an associated public or private key. pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); @@ -121,6 +127,16 @@ impl EcKey { } } + /// Generates a new public/private key pair on the specified curve. + pub fn generate(group: &EcGroupRef) -> Result { + unsafe { + let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); + try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); + try!(cvt(ffi::EC_KEY_generate_key(key.as_ptr()))); + Ok(key) + } + } + #[deprecated(since = "0.9.2", note = "use from_curve_name")] pub fn new_by_curve_name(nid: Nid) -> Result { EcKey::from_curve_name(nid) @@ -151,4 +167,12 @@ mod test { group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); } + + #[test] + fn generate() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + key.public_key().unwrap(); + key.private_key().unwrap(); + } } From 35f11d555eefd4a122b7d4688d589dcc1e918fcf Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 22:06:18 +0000 Subject: [PATCH 047/140] More functionality --- openssl-sys/src/lib.rs | 17 +++++ openssl/src/ec_key.rs | 157 ++++++++++++++++++++++++++++++++++++++++- systest/build.rs | 2 +- 3 files changed, 173 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 230c0148..6ba8668e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -60,6 +60,14 @@ pub enum BN_BLINDING {} pub enum DSA_METHOD {} pub enum EVP_PKEY_ASN1_METHOD {} +#[repr(C)] +#[derive(Copy, Clone)] +pub enum point_conversion_form_t { + POINT_CONVERSION_COMPRESSED = 2, + POINT_CONVERSION_UNCOMPRESSED = 4, + POINT_CONVERSION_HYBRID = 6, +} + #[repr(C)] pub struct GENERAL_NAME { pub type_: c_int, @@ -1400,8 +1408,17 @@ extern { pub fn EC_GROUP_new_by_curve_name(nid: c_int) -> *mut EC_GROUP; pub fn EC_GROUP_get_curve_GFp(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; pub fn EC_GROUP_get_curve_GF2m(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_get_degree(group: *const EC_GROUP) -> c_int; + pub fn EC_GROUP_get_order(group: *const EC_GROUP, order: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_free(group: *mut EC_GROUP); + pub fn EC_POINT_new(group: *const EC_GROUP) -> *mut EC_POINT; + pub fn EC_POINT_add(group: *const EC_GROUP, r: *mut EC_POINT, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; + pub fn EC_POINT_mul(group: *const EC_GROUP, r: *mut EC_POINT, n: *const BIGNUM, q: *const EC_POINT, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_POINT_point2oct(group: *const EC_GROUP, p: *const EC_POINT, form: point_conversion_form_t, buf: *mut c_uchar, len: size_t, ctx: *mut BN_CTX) -> size_t; + pub fn EC_POINT_oct2point(group: *const EC_GROUP, p: *mut EC_POINT, buf: *const c_uchar, len: size_t, ctx: *mut BN_CTX) -> c_int; + pub fn EC_POINT_cmp(group: *const EC_GROUP, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_free(point: *mut EC_POINT); pub fn ERR_get_error() -> c_ulong; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index e7e92d7a..f9b8f58c 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -1,12 +1,24 @@ use ffi; use std::ptr; -use {cvt, cvt_p, init}; +use {cvt, cvt_n, cvt_p, init}; use bn::{BigNumRef, BigNumContextRef}; use error::ErrorStack; use nid::Nid; use types::OpenSslTypeRef; +pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); + +pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); + +pub const POINT_CONVERSION_HYBRID: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); + +#[derive(Copy, Clone)] +pub struct PointConversionForm(ffi::point_conversion_form_t); + type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); impl EcGroup { @@ -75,10 +87,133 @@ impl EcGroup { .map(|_| ()) } } + + /// Returns the degree of the curve. + pub fn degree(&self) -> u32 { + unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } + } + + /// Places the order of the curve in the provided `BigNum`. + pub fn order(&self, + order: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_order(self.as_ptr(), order.as_ptr(), ctx.as_ptr())).map(|_| ()) + } + } } type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); +impl EcPointRef { + /// Computes `a + b`, storing the result in `self`. + pub fn add(&mut self, + group: &EcGroupRef, + a: &EcPointRef, + b: &EcPointRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_add(group.as_ptr(), + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `generator * n + q * m`, storing the result in `self`. + /// + /// If `n` is `None`, `q * m` will be computed instead. + pub fn mul(&mut self, + group: &EcGroupRef, + n: Option<&BigNumRef>, + q: &EcPointRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + n.map_or(ptr::null(), |n| n.as_ptr()), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Serializes the point to a binary representation. + pub fn to_bytes(&self, + group: &EcGroupRef, + form: PointConversionForm, + ctx: &mut BigNumContextRef) + -> Result, ErrorStack> { + unsafe { + let len = ffi::EC_POINT_point2oct(group.as_ptr(), + self.as_ptr(), + form.0, + ptr::null_mut(), + 0, + ctx.as_ptr()); + if len == 0 { + return Err(ErrorStack::get()); + } + let mut buf = vec![0; len]; + let len = ffi::EC_POINT_point2oct(group.as_ptr(), + self.as_ptr(), + form.0, + buf.as_mut_ptr(), + len, + ctx.as_ptr()); + if len == 0 { + Err(ErrorStack::get()) + } else { + Ok(buf) + } + } + } + + /// Determines if this point is equal to another. + pub fn eq(&self, + group: &EcGroupRef, + other: &EcPointRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + let res = try!(cvt_n(ffi::EC_POINT_cmp(group.as_ptr(), + self.as_ptr(), + other.as_ptr(), + ctx.as_ptr()))); + Ok(res == 0) + } + } +} + +impl EcPoint { + /// Creates a new point on the specified curve. + pub fn new(group: &EcGroupRef) -> Result { + unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } + } + + pub fn from_bytes(group: &EcGroupRef, + buf: &[u8], + ctx: &mut BigNumContextRef) + -> Result { + let point = try!(EcPoint::new(group)); + unsafe { + try!(cvt(ffi::EC_POINT_oct2point(group.as_ptr(), + point.as_ptr(), + buf.as_ptr(), + buf.len(), + ctx.as_ptr()))); + } + Ok(point) + } +} + type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); impl EcKeyRef { @@ -119,7 +254,8 @@ impl EcKeyRef { impl EcKey { /// Constructs an `EcKey` corresponding to a known curve. /// - /// It will not have an associated public or private key. + /// It will not have an associated public or private key. This kind of key is primarily useful + /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. pub fn from_curve_name(nid: Nid) -> Result { unsafe { init(); @@ -175,4 +311,21 @@ mod test { key.public_key().unwrap(); key.private_key().unwrap(); } + + #[test] + fn point_new() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + EcPoint::new(&group).unwrap(); + } + + #[test] + fn point_bytes() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let point = key.public_key().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let bytes = point.to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap(); + let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); + assert!(point.eq(&group, &point2, &mut ctx).unwrap()); + } } diff --git a/systest/build.rs b/systest/build.rs index 81907a57..120f103e 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -52,7 +52,7 @@ fn main() { format!("bio_info_cb*") } else if s == "_STACK" { format!("struct stack_st") - } else if is_struct && s.chars().next().unwrap().is_lowercase() { + } else if is_struct && s != "point_conversion_form_t" && s.chars().next().unwrap().is_lowercase() { format!("struct {}", s) } else { format!("{}", s) From 82eb3c4f516e1457ec2fec56a4233aa4542957cc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 22:10:52 +0000 Subject: [PATCH 048/140] Add EcKey::check_key --- openssl-sys/src/lib.rs | 1 + openssl/src/ec_key.rs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 6ba8668e..74d1d03f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1391,6 +1391,7 @@ extern { pub fn EC_KEY_set_private_key(key: *mut EC_KEY, key: *const BIGNUM) -> c_int; pub fn EC_KEY_get0_private_key(key: *const EC_KEY) -> *const BIGNUM; pub fn EC_KEY_generate_key(key: *mut EC_KEY) -> c_int; + pub fn EC_KEY_check_key(key: *const EC_KEY) -> c_int; pub fn EC_KEY_free(key: *mut EC_KEY); pub fn EC_GFp_simple_method() -> *const EC_METHOD; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index f9b8f58c..6cc95d11 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -249,6 +249,11 @@ impl EcKeyRef { } } } + + /// Checks the key for validity. + pub fn check_key(&self) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } + } } impl EcKey { From e9e58b27dcbac5d456d4a080b0df31d9b8a5e236 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 22:14:10 +0000 Subject: [PATCH 049/140] Remove EC_METHOD functions Some appear not to be defined anywhere and they're not used anyway --- openssl-sys/src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 74d1d03f..5e90ed4f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1394,13 +1394,6 @@ extern { pub fn EC_KEY_check_key(key: *const EC_KEY) -> c_int; pub fn EC_KEY_free(key: *mut EC_KEY); - pub fn EC_GFp_simple_method() -> *const EC_METHOD; - pub fn EC_GFp_mont_method() -> *const EC_METHOD; - pub fn EC_GFp_nist_method() -> *const EC_METHOD; - pub fn EC_GFp_nistp224_method() -> *const EC_METHOD; - pub fn EC_GFp_nistp256_method() -> *const EC_METHOD; - pub fn EC_GFp_nistp521_method() -> *const EC_METHOD; - pub fn EC_GF2m_simple_method() -> *const EC_METHOD; pub fn EC_GROUP_new(meth: *const EC_METHOD) -> *mut EC_GROUP; From 4c60aa005d1bcce1a0cb41df82422d9ac7c55815 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 19:20:08 +0100 Subject: [PATCH 050/140] Fix non-static EcGroup method locations --- openssl/src/ec_key.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 6cc95d11..215a89b5 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -53,7 +53,9 @@ impl EcGroup { .map(EcGroup) } } +} +impl EcGroupRef { /// Places the components of a curve over a prime field in the provided `BigNum`s. pub fn components_gfp(&self, p: &mut BigNumRef, From e929e092169dba0dfda26a957a38c61fa3e33eb2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 19:44:20 +0100 Subject: [PATCH 051/140] Add EcPoint::invert --- openssl-sys/src/lib.rs | 1 + openssl/src/ec_key.rs | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 5e90ed4f..33d06e4e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1410,6 +1410,7 @@ extern { pub fn EC_POINT_new(group: *const EC_GROUP) -> *mut EC_POINT; pub fn EC_POINT_add(group: *const EC_GROUP, r: *mut EC_POINT, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_mul(group: *const EC_GROUP, r: *mut EC_POINT, n: *const BIGNUM, q: *const EC_POINT, m: *const BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_POINT_invert(group: *const EC_GROUP, r: *mut EC_POINT, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_point2oct(group: *const EC_GROUP, p: *const EC_POINT, form: point_conversion_form_t, buf: *mut c_uchar, len: size_t, ctx: *mut BN_CTX) -> size_t; pub fn EC_POINT_oct2point(group: *const EC_GROUP, p: *mut EC_POINT, buf: *const c_uchar, len: size_t, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_cmp(group: *const EC_GROUP, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 215a89b5..3b40496a 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -147,6 +147,13 @@ impl EcPointRef { } } + /// Inverts `self`. + pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_invert(group.as_ptr(), self.as_ptr(), ctx.as_ptr())).map(|_| ()) + } + } + /// Serializes the point to a binary representation. pub fn to_bytes(&self, group: &EcGroupRef, From 90acfaea513ad079119e7b3485a9a2e35702ad33 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 22:08:04 +0100 Subject: [PATCH 052/140] Split EcKey::mul --- openssl/src/ec_key.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index 3b40496a..ae712430 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -126,20 +126,36 @@ impl EcPointRef { } } - /// Computes `generator * n + q * m`, storing the result in `self`. - /// - /// If `n` is `None`, `q * m` will be computed instead. + /// Computes `q * m`, storing the result in `self`. pub fn mul(&mut self, group: &EcGroupRef, - n: Option<&BigNumRef>, q: &EcPointRef, m: &BigNumRef, - ctx: &mut BigNumContextRef) + ctx: &BigNumContextRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_mul(group.as_ptr(), self.as_ptr(), - n.map_or(ptr::null(), |n| n.as_ptr()), + ptr::null(), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `generator * n + q * m`, storing the result in `self`. + pub fn mul_generator(&mut self, + group: &EcGroupRef, + n: &BigNumRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + n.as_ptr(), q.as_ptr(), m.as_ptr(), ctx.as_ptr())) From 6794a45d602def6812a70841f8b012445f62c7ac Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 22:37:01 +0100 Subject: [PATCH 053/140] Rename ec_key to ec --- openssl/src/ec.rs | 361 ++++++++++++++++++++++++++++++++++ openssl/src/ec_key.rs | 362 +---------------------------------- openssl/src/lib.rs | 1 + openssl/src/pkey.rs | 4 +- openssl/src/ssl/connector.rs | 2 +- openssl/src/ssl/mod.rs | 4 +- openssl/src/ssl/tests/mod.rs | 4 +- 7 files changed, 371 insertions(+), 367 deletions(-) create mode 100644 openssl/src/ec.rs diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs new file mode 100644 index 00000000..ae712430 --- /dev/null +++ b/openssl/src/ec.rs @@ -0,0 +1,361 @@ +use ffi; +use std::ptr; + +use {cvt, cvt_n, cvt_p, init}; +use bn::{BigNumRef, BigNumContextRef}; +use error::ErrorStack; +use nid::Nid; +use types::OpenSslTypeRef; + +pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); + +pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); + +pub const POINT_CONVERSION_HYBRID: PointConversionForm = + PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); + +#[derive(Copy, Clone)] +pub struct PointConversionForm(ffi::point_conversion_form_t); + +type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); + +impl EcGroup { + /// Returns the group of a standard named curve. + pub fn from_curve_name(nid: Nid) -> Result { + unsafe { + init(); + cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) + } + } + + /// Constructs a curve over a prime field from its components. + pub fn from_components_gfp(p: &BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + cvt_p(ffi::EC_GROUP_new_curve_GFp(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) + .map(EcGroup) + } + } + + /// Constructs a curve over a binary field from its components. + pub fn from_components_gf2m(p: &BigNumRef, + a: &BigNumRef, + b: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + cvt_p(ffi::EC_GROUP_new_curve_GF2m(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) + .map(EcGroup) + } + } +} + +impl EcGroupRef { + /// Places the components of a curve over a prime field in the provided `BigNum`s. + pub fn components_gfp(&self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GFp(self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Places the components of a curve over a binary field in the provided `BigNum`s. + pub fn components_gf2m(&self, + p: &mut BigNumRef, + a: &mut BigNumRef, + b: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_curve_GF2m(self.as_ptr(), + p.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Returns the degree of the curve. + pub fn degree(&self) -> u32 { + unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } + } + + /// Places the order of the curve in the provided `BigNum`. + pub fn order(&self, + order: &mut BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_GROUP_get_order(self.as_ptr(), order.as_ptr(), ctx.as_ptr())).map(|_| ()) + } + } +} + +type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); + +impl EcPointRef { + /// Computes `a + b`, storing the result in `self`. + pub fn add(&mut self, + group: &EcGroupRef, + a: &EcPointRef, + b: &EcPointRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_add(group.as_ptr(), + self.as_ptr(), + a.as_ptr(), + b.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `q * m`, storing the result in `self`. + pub fn mul(&mut self, + group: &EcGroupRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + ptr::null(), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `generator * n + q * m`, storing the result in `self`. + pub fn mul_generator(&mut self, + group: &EcGroupRef, + n: &BigNumRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + n.as_ptr(), + q.as_ptr(), + m.as_ptr(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Inverts `self`. + pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_invert(group.as_ptr(), self.as_ptr(), ctx.as_ptr())).map(|_| ()) + } + } + + /// Serializes the point to a binary representation. + pub fn to_bytes(&self, + group: &EcGroupRef, + form: PointConversionForm, + ctx: &mut BigNumContextRef) + -> Result, ErrorStack> { + unsafe { + let len = ffi::EC_POINT_point2oct(group.as_ptr(), + self.as_ptr(), + form.0, + ptr::null_mut(), + 0, + ctx.as_ptr()); + if len == 0 { + return Err(ErrorStack::get()); + } + let mut buf = vec![0; len]; + let len = ffi::EC_POINT_point2oct(group.as_ptr(), + self.as_ptr(), + form.0, + buf.as_mut_ptr(), + len, + ctx.as_ptr()); + if len == 0 { + Err(ErrorStack::get()) + } else { + Ok(buf) + } + } + } + + /// Determines if this point is equal to another. + pub fn eq(&self, + group: &EcGroupRef, + other: &EcPointRef, + ctx: &mut BigNumContextRef) + -> Result { + unsafe { + let res = try!(cvt_n(ffi::EC_POINT_cmp(group.as_ptr(), + self.as_ptr(), + other.as_ptr(), + ctx.as_ptr()))); + Ok(res == 0) + } + } +} + +impl EcPoint { + /// Creates a new point on the specified curve. + pub fn new(group: &EcGroupRef) -> Result { + unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } + } + + pub fn from_bytes(group: &EcGroupRef, + buf: &[u8], + ctx: &mut BigNumContextRef) + -> Result { + let point = try!(EcPoint::new(group)); + unsafe { + try!(cvt(ffi::EC_POINT_oct2point(group.as_ptr(), + point.as_ptr(), + buf.as_ptr(), + buf.len(), + ctx.as_ptr()))); + } + Ok(point) + } +} + +type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); + +impl EcKeyRef { + private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); + private_key_to_der!(ffi::i2d_ECPrivateKey); + + pub fn group(&self) -> &EcGroupRef { + unsafe { + let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); + assert!(!ptr.is_null()); + EcGroupRef::from_ptr(ptr as *mut _) + } + } + + pub fn public_key(&self) -> Option<&EcPointRef> { + unsafe { + let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(EcPointRef::from_ptr(ptr as *mut _)) + } + } + } + + pub fn private_key(&self) -> Option<&BigNumRef> { + unsafe { + let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(BigNumRef::from_ptr(ptr as *mut _)) + } + } + } + + /// Checks the key for validity. + pub fn check_key(&self) -> Result<(), ErrorStack> { + unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } + } +} + +impl EcKey { + /// Constructs an `EcKey` corresponding to a known curve. + /// + /// It will not have an associated public or private key. This kind of key is primarily useful + /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. + pub fn from_curve_name(nid: Nid) -> Result { + unsafe { + init(); + cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) + } + } + + /// Generates a new public/private key pair on the specified curve. + pub fn generate(group: &EcGroupRef) -> Result { + unsafe { + let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); + try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); + try!(cvt(ffi::EC_KEY_generate_key(key.as_ptr()))); + Ok(key) + } + } + + #[deprecated(since = "0.9.2", note = "use from_curve_name")] + pub fn new_by_curve_name(nid: Nid) -> Result { + EcKey::from_curve_name(nid) + } + + private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); + private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); +} + +#[cfg(test)] +mod test { + use bn::{BigNum, BigNumContext}; + use nid; + use super::*; + + #[test] + fn key_new_by_curve_name() { + EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + } + + #[test] + fn round_trip_prime256v1() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let mut p = BigNum::new().unwrap(); + let mut a = BigNum::new().unwrap(); + let mut b = BigNum::new().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); + EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); + } + + #[test] + fn generate() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + key.public_key().unwrap(); + key.private_key().unwrap(); + } + + #[test] + fn point_new() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + EcPoint::new(&group).unwrap(); + } + + #[test] + fn point_bytes() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let point = key.public_key().unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let bytes = point.to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap(); + let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); + assert!(point.eq(&group, &point2, &mut ctx).unwrap()); + } +} diff --git a/openssl/src/ec_key.rs b/openssl/src/ec_key.rs index ae712430..cb7c4996 100644 --- a/openssl/src/ec_key.rs +++ b/openssl/src/ec_key.rs @@ -1,361 +1,3 @@ -use ffi; -use std::ptr; +#![deprecated(since = "0.9.2", note = "renamed to `ec`")] -use {cvt, cvt_n, cvt_p, init}; -use bn::{BigNumRef, BigNumContextRef}; -use error::ErrorStack; -use nid::Nid; -use types::OpenSslTypeRef; - -pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); - -pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_UNCOMPRESSED); - -pub const POINT_CONVERSION_HYBRID: PointConversionForm = - PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); - -#[derive(Copy, Clone)] -pub struct PointConversionForm(ffi::point_conversion_form_t); - -type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); - -impl EcGroup { - /// Returns the group of a standard named curve. - pub fn from_curve_name(nid: Nid) -> Result { - unsafe { - init(); - cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) - } - } - - /// Constructs a curve over a prime field from its components. - pub fn from_components_gfp(p: &BigNumRef, - a: &BigNumRef, - b: &BigNumRef, - ctx: &mut BigNumContextRef) - -> Result { - unsafe { - cvt_p(ffi::EC_GROUP_new_curve_GFp(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) - .map(EcGroup) - } - } - - /// Constructs a curve over a binary field from its components. - pub fn from_components_gf2m(p: &BigNumRef, - a: &BigNumRef, - b: &BigNumRef, - ctx: &mut BigNumContextRef) - -> Result { - unsafe { - cvt_p(ffi::EC_GROUP_new_curve_GF2m(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) - .map(EcGroup) - } - } -} - -impl EcGroupRef { - /// Places the components of a curve over a prime field in the provided `BigNum`s. - pub fn components_gfp(&self, - p: &mut BigNumRef, - a: &mut BigNumRef, - b: &mut BigNumRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_GROUP_get_curve_GFp(self.as_ptr(), - p.as_ptr(), - a.as_ptr(), - b.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Places the components of a curve over a binary field in the provided `BigNum`s. - pub fn components_gf2m(&self, - p: &mut BigNumRef, - a: &mut BigNumRef, - b: &mut BigNumRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_GROUP_get_curve_GF2m(self.as_ptr(), - p.as_ptr(), - a.as_ptr(), - b.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Returns the degree of the curve. - pub fn degree(&self) -> u32 { - unsafe { ffi::EC_GROUP_get_degree(self.as_ptr()) as u32 } - } - - /// Places the order of the curve in the provided `BigNum`. - pub fn order(&self, - order: &mut BigNumRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_GROUP_get_order(self.as_ptr(), order.as_ptr(), ctx.as_ptr())).map(|_| ()) - } - } -} - -type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); - -impl EcPointRef { - /// Computes `a + b`, storing the result in `self`. - pub fn add(&mut self, - group: &EcGroupRef, - a: &EcPointRef, - b: &EcPointRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_POINT_add(group.as_ptr(), - self.as_ptr(), - a.as_ptr(), - b.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Computes `q * m`, storing the result in `self`. - pub fn mul(&mut self, - group: &EcGroupRef, - q: &EcPointRef, - m: &BigNumRef, - ctx: &BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_POINT_mul(group.as_ptr(), - self.as_ptr(), - ptr::null(), - q.as_ptr(), - m.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Computes `generator * n + q * m`, storing the result in `self`. - pub fn mul_generator(&mut self, - group: &EcGroupRef, - n: &BigNumRef, - q: &EcPointRef, - m: &BigNumRef, - ctx: &mut BigNumContextRef) - -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_POINT_mul(group.as_ptr(), - self.as_ptr(), - n.as_ptr(), - q.as_ptr(), - m.as_ptr(), - ctx.as_ptr())) - .map(|_| ()) - } - } - - /// Inverts `self`. - pub fn invert(&mut self, group: &EcGroupRef, ctx: &BigNumContextRef) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::EC_POINT_invert(group.as_ptr(), self.as_ptr(), ctx.as_ptr())).map(|_| ()) - } - } - - /// Serializes the point to a binary representation. - pub fn to_bytes(&self, - group: &EcGroupRef, - form: PointConversionForm, - ctx: &mut BigNumContextRef) - -> Result, ErrorStack> { - unsafe { - let len = ffi::EC_POINT_point2oct(group.as_ptr(), - self.as_ptr(), - form.0, - ptr::null_mut(), - 0, - ctx.as_ptr()); - if len == 0 { - return Err(ErrorStack::get()); - } - let mut buf = vec![0; len]; - let len = ffi::EC_POINT_point2oct(group.as_ptr(), - self.as_ptr(), - form.0, - buf.as_mut_ptr(), - len, - ctx.as_ptr()); - if len == 0 { - Err(ErrorStack::get()) - } else { - Ok(buf) - } - } - } - - /// Determines if this point is equal to another. - pub fn eq(&self, - group: &EcGroupRef, - other: &EcPointRef, - ctx: &mut BigNumContextRef) - -> Result { - unsafe { - let res = try!(cvt_n(ffi::EC_POINT_cmp(group.as_ptr(), - self.as_ptr(), - other.as_ptr(), - ctx.as_ptr()))); - Ok(res == 0) - } - } -} - -impl EcPoint { - /// Creates a new point on the specified curve. - pub fn new(group: &EcGroupRef) -> Result { - unsafe { cvt_p(ffi::EC_POINT_new(group.as_ptr())).map(EcPoint) } - } - - pub fn from_bytes(group: &EcGroupRef, - buf: &[u8], - ctx: &mut BigNumContextRef) - -> Result { - let point = try!(EcPoint::new(group)); - unsafe { - try!(cvt(ffi::EC_POINT_oct2point(group.as_ptr(), - point.as_ptr(), - buf.as_ptr(), - buf.len(), - ctx.as_ptr()))); - } - Ok(point) - } -} - -type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); - -impl EcKeyRef { - private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); - private_key_to_der!(ffi::i2d_ECPrivateKey); - - pub fn group(&self) -> &EcGroupRef { - unsafe { - let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); - assert!(!ptr.is_null()); - EcGroupRef::from_ptr(ptr as *mut _) - } - } - - pub fn public_key(&self) -> Option<&EcPointRef> { - unsafe { - let ptr = ffi::EC_KEY_get0_public_key(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(EcPointRef::from_ptr(ptr as *mut _)) - } - } - } - - pub fn private_key(&self) -> Option<&BigNumRef> { - unsafe { - let ptr = ffi::EC_KEY_get0_private_key(self.as_ptr()); - if ptr.is_null() { - None - } else { - Some(BigNumRef::from_ptr(ptr as *mut _)) - } - } - } - - /// Checks the key for validity. - pub fn check_key(&self) -> Result<(), ErrorStack> { - unsafe { cvt(ffi::EC_KEY_check_key(self.as_ptr())).map(|_| ()) } - } -} - -impl EcKey { - /// Constructs an `EcKey` corresponding to a known curve. - /// - /// It will not have an associated public or private key. This kind of key is primarily useful - /// to be provided to the `set_tmp_ecdh` methods on `Ssl` and `SslContextBuilder`. - pub fn from_curve_name(nid: Nid) -> Result { - unsafe { - init(); - cvt_p(ffi::EC_KEY_new_by_curve_name(nid.as_raw())).map(EcKey) - } - } - - /// Generates a new public/private key pair on the specified curve. - pub fn generate(group: &EcGroupRef) -> Result { - unsafe { - let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); - try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); - try!(cvt(ffi::EC_KEY_generate_key(key.as_ptr()))); - Ok(key) - } - } - - #[deprecated(since = "0.9.2", note = "use from_curve_name")] - pub fn new_by_curve_name(nid: Nid) -> Result { - EcKey::from_curve_name(nid) - } - - private_key_from_pem!(EcKey, ffi::PEM_read_bio_ECPrivateKey); - private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); -} - -#[cfg(test)] -mod test { - use bn::{BigNum, BigNumContext}; - use nid; - use super::*; - - #[test] - fn key_new_by_curve_name() { - EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - } - - #[test] - fn round_trip_prime256v1() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let mut p = BigNum::new().unwrap(); - let mut a = BigNum::new().unwrap(); - let mut b = BigNum::new().unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); - EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); - } - - #[test] - fn generate() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let key = EcKey::generate(&group).unwrap(); - key.public_key().unwrap(); - key.private_key().unwrap(); - } - - #[test] - fn point_new() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - EcPoint::new(&group).unwrap(); - } - - #[test] - fn point_bytes() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let key = EcKey::generate(&group).unwrap(); - let point = key.public_key().unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - let bytes = point.to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap(); - let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); - assert!(point.eq(&group, &point2, &mut ctx).unwrap()); - } -} +pub use ec::{EcKey, EcKeyRef}; diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index c2c559dc..995df34d 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -29,6 +29,7 @@ pub mod bn; pub mod crypto; pub mod dh; pub mod dsa; +pub mod ec; pub mod ec_key; pub mod error; pub mod hash; diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 5739a5ed..7f031244 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -7,7 +7,7 @@ use {cvt, cvt_p}; use bio::MemBioSlice; use dh::Dh; use dsa::Dsa; -use ec_key::EcKey; +use ec::EcKey; use rsa::Rsa; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; @@ -153,7 +153,7 @@ mod tests { use symm::Cipher; use dh::Dh; use dsa::Dsa; - use ec_key::EcKey; + use ec::EcKey; use rsa::Rsa; use nid; diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index c002b966..043014c4 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -215,7 +215,7 @@ impl SslAcceptorBuilder { #[cfg(ossl101)] fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - use ec_key::EcKey; + use ec::EcKey; use nid; let curve = try!(EcKey::from_curve_name(nid::X9_62_PRIME256V1)); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 2c444400..ac41dec6 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -92,9 +92,9 @@ use std::sync::Mutex; use {init, cvt, cvt_p}; use dh::{Dh, DhRef}; -use ec_key::EcKeyRef; +use ec::EcKeyRef; #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] -use ec_key::EcKey; +use ec::EcKey; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; use x509::store::X509StoreBuilderRef; #[cfg(any(ossl102, ossl110))] diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index fb9a96b9..2f6bbe1f 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1269,7 +1269,7 @@ fn tmp_dh_callback() { #[test] #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] fn tmp_ecdh_callback() { - use ec_key::EcKey; + use ec::EcKey; use nid; static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; @@ -1332,7 +1332,7 @@ fn tmp_dh_callback_ssl() { #[test] #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] fn tmp_ecdh_callback_ssl() { - use ec_key::EcKey; + use ec::EcKey; use nid; static CALLED_BACK: AtomicBool = ATOMIC_BOOL_INIT; From 6026396423c7239bd230a7bf9eb64c5d1b892799 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Nov 2016 10:34:32 +0100 Subject: [PATCH 054/140] Add a note that the systest logic is kind of busted --- systest/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/systest/build.rs b/systest/build.rs index 120f103e..b0ca3250 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -52,6 +52,7 @@ fn main() { format!("bio_info_cb*") } else if s == "_STACK" { format!("struct stack_st") + // This logic should really be cleaned up } else if is_struct && s != "point_conversion_form_t" && s.chars().next().unwrap().is_lowercase() { format!("struct {}", s) } else { From b914f779e83647df0cfeb9444de0a2eed18a1eb5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Nov 2016 21:20:06 +0100 Subject: [PATCH 055/140] Turns out yet another variant of EC_POINT_mul is allowed! --- openssl/src/ec.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index ae712430..a4470b2c 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -144,14 +144,31 @@ impl EcPointRef { } } - /// Computes `generator * n + q * m`, storing the result in `self`. + /// Computes `generator * n`, storing the result ing `self`. pub fn mul_generator(&mut self, group: &EcGroupRef, n: &BigNumRef, - q: &EcPointRef, - m: &BigNumRef, - ctx: &mut BigNumContextRef) + ctx: &BigNumContextRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EC_POINT_mul(group.as_ptr(), + self.as_ptr(), + n.as_ptr(), + ptr::null(), + ptr::null(), + ctx.as_ptr())) + .map(|_| ()) + } + } + + /// Computes `generator * n + q * m`, storing the result in `self`. + pub fn mul_full(&mut self, + group: &EcGroupRef, + n: &BigNumRef, + q: &EcPointRef, + m: &BigNumRef, + ctx: &mut BigNumContextRef) + -> Result<(), ErrorStack> { unsafe { cvt(ffi::EC_POINT_mul(group.as_ptr(), self.as_ptr(), From ec0fa36714a082ac7529dac7e0a8928f95a5bef0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Nov 2016 21:24:34 +0100 Subject: [PATCH 056/140] Add a test for mul_generator --- openssl/src/ec.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index a4470b2c..08272363 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -375,4 +375,14 @@ mod test { let point2 = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); assert!(point.eq(&group, &point2, &mut ctx).unwrap()); } + + #[test] + fn mul_generator() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let mut public_key = EcPoint::new(&group).unwrap(); + public_key.mul_generator(&group, key.private_key().unwrap(), &mut ctx).unwrap(); + assert!(public_key.eq(&group, key.public_key().unwrap(), &mut ctx).unwrap()); + } } From 7515510125396db580d3aaa4efd28c51b02aa708 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Nov 2016 22:06:20 +0100 Subject: [PATCH 057/140] Test elliptic curve signatures --- openssl/src/sign.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index 679a30aa..ca7986ca 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -210,6 +210,8 @@ mod test { use hash::MessageDigest; use sign::{Signer, Verifier}; + use ec::{EcGroup, EcKey}; + use nid; use rsa::Rsa; use dsa::Dsa; use pkey::PKey; @@ -394,4 +396,19 @@ mod test { test_hmac(MessageDigest::sha1(), &tests); } + + #[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.finish().unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha256(), &key).unwrap(); + verifier.update(b"hello world").unwrap(); + assert!(verifier.finish(&signature).unwrap()); + } } From e58dda89900dd30c14811b981b43f24352c683bd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 16 Nov 2016 13:53:03 +0100 Subject: [PATCH 058/140] Remove EcGroup constructors You also need a generator and possibly other stuff. Let's hold off on construction until someone has a concrete requirement for them. --- openssl/src/ec.rs | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index 08272363..fc3240f1 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -29,30 +29,6 @@ impl EcGroup { cvt_p(ffi::EC_GROUP_new_by_curve_name(nid.as_raw())).map(EcGroup) } } - - /// Constructs a curve over a prime field from its components. - pub fn from_components_gfp(p: &BigNumRef, - a: &BigNumRef, - b: &BigNumRef, - ctx: &mut BigNumContextRef) - -> Result { - unsafe { - cvt_p(ffi::EC_GROUP_new_curve_GFp(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) - .map(EcGroup) - } - } - - /// Constructs a curve over a binary field from its components. - pub fn from_components_gf2m(p: &BigNumRef, - a: &BigNumRef, - b: &BigNumRef, - ctx: &mut BigNumContextRef) - -> Result { - unsafe { - cvt_p(ffi::EC_GROUP_new_curve_GF2m(p.as_ptr(), a.as_ptr(), b.as_ptr(), ctx.as_ptr())) - .map(EcGroup) - } - } } impl EcGroupRef { @@ -331,7 +307,7 @@ impl EcKey { #[cfg(test)] mod test { - use bn::{BigNum, BigNumContext}; + use bn::BigNumContext; use nid; use super::*; @@ -340,17 +316,6 @@ mod test { EcKey::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); } - #[test] - fn round_trip_prime256v1() { - let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); - let mut p = BigNum::new().unwrap(); - let mut a = BigNum::new().unwrap(); - let mut b = BigNum::new().unwrap(); - let mut ctx = BigNumContext::new().unwrap(); - group.components_gfp(&mut p, &mut a, &mut b, &mut ctx).unwrap(); - EcGroup::from_components_gfp(&p, &a, &b, &mut ctx).unwrap(); - } - #[test] fn generate() { let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); From 8b60d4a3c2822ab20988439c46f973ae86367d48 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 16 Nov 2016 15:45:15 -0800 Subject: [PATCH 059/140] Return Option from group --- openssl/src/ec.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index fc3240f1..607c30e0 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -238,11 +238,14 @@ impl EcKeyRef { private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); private_key_to_der!(ffi::i2d_ECPrivateKey); - pub fn group(&self) -> &EcGroupRef { + pub fn group(&self) -> Option<&EcGroupRef> { unsafe { let ptr = ffi::EC_KEY_get0_group(self.as_ptr()); - assert!(!ptr.is_null()); - EcGroupRef::from_ptr(ptr as *mut _) + if ptr.is_null() { + None + } else { + Some(EcGroupRef::from_ptr(ptr as *mut _)) + } } } From 234f126d7d9718bd95655aca5fa6f57dc2c4270a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Nov 2016 10:19:52 -0800 Subject: [PATCH 060/140] Cleanup --- openssl/src/ssl/bio.rs | 13 ++++--------- openssl/src/ssl/connector.rs | 4 ++-- openssl/src/ssl/mod.rs | 3 ++- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index 486b4dba..c5152a41 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -5,6 +5,7 @@ use std::any::Any; use std::io; use std::io::prelude::*; use std::mem; +use std::panic::{AssertUnwindSafe, catch_unwind}; use std::ptr; use std::slice; @@ -70,19 +71,13 @@ unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { mem::transmute(compat::BIO_get_data(bio)) } -fn catch_unwind(f: F) -> Result> - where F: FnOnce() -> T -{ - ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(f)) -} - unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); let buf = slice::from_raw_parts(buf as *const _, len as usize); - match catch_unwind(|| state.stream.write(buf)) { + match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) { Ok(Ok(len)) => len as c_int, Ok(Err(err)) => { if retriable_error(&err) { @@ -104,7 +99,7 @@ unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) let state = state::(bio); let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize); - match catch_unwind(|| state.stream.read(buf)) { + match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) { Ok(Ok(len)) => len as c_int, Ok(Err(err)) => { if retriable_error(&err) { @@ -140,7 +135,7 @@ unsafe extern "C" fn ctrl(bio: *mut BIO, if cmd == BIO_CTRL_FLUSH { let state = state::(bio); - match catch_unwind(|| state.stream.flush()) { + match catch_unwind(AssertUnwindSafe(|| state.stream.flush())) { Ok(Ok(())) => 1, Ok(Err(err)) => { state.error = Some(err); diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 043014c4..9ff89c0e 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -23,10 +23,10 @@ fn ctx(method: SslMethod) -> Result { let mut ctx = try!(SslContextBuilder::new(method)); let mut opts = ssl::SSL_OP_ALL; - opts |= ssl::SSL_OP_NO_TICKET; - opts |= ssl::SSL_OP_NO_COMPRESSION; opts &= !ssl::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; opts &= !ssl::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + opts |= ssl::SSL_OP_NO_TICKET; + opts |= ssl::SSL_OP_NO_COMPRESSION; opts |= ssl::SSL_OP_NO_SSLV2; opts |= ssl::SSL_OP_NO_SSLV3; opts |= ssl::SSL_OP_SINGLE_DH_USE; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ac41dec6..6e0c92c3 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -84,6 +84,7 @@ use std::io::prelude::*; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; +use std::panic::resume_unwind; use std::path::Path; use std::ptr; use std::slice; @@ -1601,7 +1602,7 @@ impl SslStream { fn check_panic(&mut self) { if let Some(err) = unsafe { bio::take_panic::(self.ssl.get_raw_rbio()) } { - ::std::panic::resume_unwind(err) + resume_unwind(err) } } From 146512099b484928e9b9396d4b8a476b1c47ee54 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 27 Nov 2016 21:35:35 -0800 Subject: [PATCH 061/140] Implement Clone for SslConnector and SslAcceptor --- openssl/src/ssl/connector.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 9ff89c0e..cc5c5273 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -83,6 +83,7 @@ impl SslConnectorBuilder { /// /// 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)] pub struct SslConnector(SslContext); impl SslConnector { @@ -236,6 +237,7 @@ fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { /// /// 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 { From 0602712bf4e4e0451fcd527edc4e50a768e9b8d3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 27 Nov 2016 22:23:32 -0800 Subject: [PATCH 062/140] Release v0.9.2 --- README.md | 2 +- openssl-sys/Cargo.toml | 4 ++-- openssl-sys/src/lib.rs | 2 +- openssl/Cargo.toml | 6 +++--- openssl/src/lib.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e297fcf9..342cc5a6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) -[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.9.1/openssl). +[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.9.2/openssl). ## Warning diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 094cd094..e533054f 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "openssl-sys" -version = "0.9.1" +version = "0.9.2" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl_sys" +documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.2/openssl_sys" links = "openssl" build = "build.rs" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 33d06e4e..8e427c7a 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code, overflowing_literals)] -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.1")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.2")] extern crate libc; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 050b99e1..da7802f6 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "openssl" -version = "0.9.1" +version = "0.9.2" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.0/openssl" +documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.2/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] build = "build.rs" @@ -20,7 +20,7 @@ v110 = [] bitflags = "0.7" lazy_static = "0.2" libc = "0.2" -openssl-sys = { version = "0.9.1", path = "../openssl-sys" } +openssl-sys = { version = "0.9.2", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 995df34d..75d88483 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.1")] +#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.2")] #[macro_use] extern crate bitflags; From e2331b29d388c5594f4283de415c961828779eeb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 2 Dec 2016 11:11:24 -0800 Subject: [PATCH 063/140] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 342cc5a6..30b92e8e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ## Warning -This README does not correspond to rust-openssl 0.7.x. See +This README does not correspond to rust-openssl 0.7.x or 0.8.x. See [here](https://github.com/sfackler/rust-openssl/blob/b8fb29db5c246175a096260eacca38180cd77dd0/README.md) for that README. From 00816653399ceb3a06a35c3b7c3fb161891f5763 Mon Sep 17 00:00:00 2001 From: 0xa Date: Fri, 9 Dec 2016 17:06:15 +0000 Subject: [PATCH 064/140] Add Blowfish support --- openssl-sys/src/lib.rs | 4 ++++ openssl/src/symm.rs | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 8e427c7a..142ec09b 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1445,6 +1445,10 @@ extern { pub fn EVP_aes_256_cfb1() -> *const EVP_CIPHER; pub fn EVP_aes_256_cfb128() -> *const EVP_CIPHER; pub fn EVP_aes_256_cfb8() -> *const EVP_CIPHER; + pub fn EVP_bf_cbc() -> *const EVP_CIPHER; + pub fn EVP_bf_ecb() -> *const EVP_CIPHER; + pub fn EVP_bf_cfb() -> *const EVP_CIPHER; + pub fn EVP_bf_ofb() -> *const EVP_CIPHER; pub fn EVP_rc4() -> *const EVP_CIPHER; pub fn EVP_des_cbc() -> *const EVP_CIPHER; diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index f94a8d70..2704bae7 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -80,6 +80,22 @@ impl Cipher { unsafe { Cipher(ffi::EVP_aes_256_gcm()) } } + pub fn bf_cbc() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_cbc()) } + } + + pub fn bf_ecb() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_ecb()) } + } + + pub fn bf_cfb() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_cfb()) } + } + + pub fn bf_ofb() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_ofb()) } + } + pub fn des_cbc() -> Cipher { unsafe { Cipher(ffi::EVP_des_cbc()) } } From 0850f605b1fcb686bae341a4763d072af4c67e50 Mon Sep 17 00:00:00 2001 From: 0xa Date: Fri, 9 Dec 2016 18:42:10 +0000 Subject: [PATCH 065/140] Use EVP_bf_cfb64 instead of EVP_bf_cfb --- openssl-sys/src/lib.rs | 2 +- openssl/src/symm.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 142ec09b..3ac3c2c2 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1447,7 +1447,7 @@ extern { pub fn EVP_aes_256_cfb8() -> *const EVP_CIPHER; pub fn EVP_bf_cbc() -> *const EVP_CIPHER; pub fn EVP_bf_ecb() -> *const EVP_CIPHER; - pub fn EVP_bf_cfb() -> *const EVP_CIPHER; + pub fn EVP_bf_cfb64() -> *const EVP_CIPHER; pub fn EVP_bf_ofb() -> *const EVP_CIPHER; pub fn EVP_rc4() -> *const EVP_CIPHER; diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 2704bae7..1a46411d 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -88,8 +88,8 @@ impl Cipher { unsafe { Cipher(ffi::EVP_bf_ecb()) } } - pub fn bf_cfb() -> Cipher { - unsafe { Cipher(ffi::EVP_bf_cfb()) } + pub fn bf_cfb64() -> Cipher { + unsafe { Cipher(ffi::EVP_bf_cfb64()) } } pub fn bf_ofb() -> Cipher { From 5340895249164e0761996b5adbdb4587122880dc Mon Sep 17 00:00:00 2001 From: 0xa Date: Fri, 9 Dec 2016 21:26:58 +0000 Subject: [PATCH 066/140] Add Blowfish tests --- openssl/src/symm.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 1a46411d..d2cb0cc8 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -525,6 +525,35 @@ mod tests { } } + fn cipher_test_nopad(ciphertype: super::Cipher, pt: &str, ct: &str, key: &str, iv: &str) { + let pt = Vec::from_hex(pt).unwrap(); + let ct = Vec::from_hex(ct).unwrap(); + let key = Vec::from_hex(key).unwrap(); + let iv = Vec::from_hex(iv).unwrap(); + + let computed = { + let mut c = Crypter::new(ciphertype, Mode::Decrypt, &key, Some(&iv)).unwrap(); + c.pad(false); + let mut out = vec![0; ct.len() + ciphertype.block_size()]; + let count = c.update(&ct, &mut out).unwrap(); + let rest = c.finalize(&mut out[count..]).unwrap(); + out.truncate(count + rest); + out + }; + let expected = pt; + + if computed != expected { + println!("Computed: {}", computed.to_hex()); + println!("Expected: {}", expected.to_hex()); + if computed.len() != expected.len() { + println!("Lengths differ: {} in computed vs {} expected", + computed.len(), + expected.len()); + } + panic!("test failure"); + } + } + #[test] fn test_rc4() { @@ -631,6 +660,51 @@ mod tests { cipher_test(super::Cipher::aes_256_cfb8(), pt, ct, key, iv); } + #[test] + fn test_bf_cbc() { + // https://www.schneier.com/code/vectors.txt + + let pt = "37363534333231204E6F77206973207468652074696D6520666F722000000000"; + let ct = "6B77B4D63006DEE605B156E27403979358DEB9E7154616D959F1652BD5FF92CC"; + let key = "0123456789ABCDEFF0E1D2C3B4A59687"; + let iv = "FEDCBA9876543210"; + + cipher_test_nopad(super::Cipher::bf_cbc(), pt, ct, key, iv); + } + + #[test] + fn test_bf_ecb() { + + let pt = "5CD54CA83DEF57DA"; + let ct = "B1B8CC0B250F09A0"; + let key = "0131D9619DC1376E"; + let iv = "0000000000000000"; + + cipher_test_nopad(super::Cipher::bf_ecb(), pt, ct, key, iv); + } + + #[test] + fn test_bf_cfb64() { + + let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; + let ct = "E73214A2822139CAF26ECF6D2EB9E76E3DA3DE04D1517200519D57A6C3"; + let key = "0123456789ABCDEFF0E1D2C3B4A59687"; + let iv = "FEDCBA9876543210"; + + cipher_test_nopad(super::Cipher::bf_cfb64(), pt, ct, key, iv); + } + + #[test] + fn test_bf_ofb() { + + let pt = "37363534333231204E6F77206973207468652074696D6520666F722000"; + let ct = "E73214A2822139CA62B343CC5B65587310DD908D0C241B2263C2CF80DA"; + let key = "0123456789ABCDEFF0E1D2C3B4A59687"; + let iv = "FEDCBA9876543210"; + + cipher_test_nopad(super::Cipher::bf_ofb(), pt, ct, key, iv); + } + #[test] fn test_des_cbc() { From 152d7889981f2f25a8134c9f8082e5024ba9073e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 9 Dec 2016 21:32:28 -0800 Subject: [PATCH 067/140] Fix ErrorStack display --- openssl/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/error.rs b/openssl/src/error.rs index 4dd219af..26b96408 100644 --- a/openssl/src/error.rs +++ b/openssl/src/error.rs @@ -32,11 +32,11 @@ impl fmt::Display for ErrorStack { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let mut first = true; for err in &self.0 { - if first { + if !first { try!(fmt.write_str(", ")); - first = false; } try!(write!(fmt, "{}", err)); + first = false; } Ok(()) } From 26cefe7d97595db76be9a5b76ac12834096454cd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 9 Dec 2016 21:52:43 -0800 Subject: [PATCH 068/140] Switch to docs.rs for docs --- README.md | 2 +- openssl-sys/Cargo.toml | 2 +- openssl-sys/src/lib.rs | 2 +- openssl/Cargo.toml | 2 +- openssl/src/lib.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 30b92e8e..6f4c1f94 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) -[Documentation](https://sfackler.github.io/rust-openssl/doc/v0.9.2/openssl). +[Documentation](https://docs.rs/openssl/0.9.2/openssl). ## Warning diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index e533054f..9deae1ec 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -6,7 +6,7 @@ authors = ["Alex Crichton ", license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.2/openssl_sys" +documentation = "https://docs.rs/openssl-sys/0.9.2/openssl_sys" links = "openssl" build = "build.rs" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 3ac3c2c2..f287290d 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code, overflowing_literals)] -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.2")] +#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.2")] extern crate libc; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index da7802f6..315c1fad 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://sfackler.github.io/rust-openssl/doc/v0.9.2/openssl" +documentation = "https://docs.rs/openssl/0.9.2/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] build = "build.rs" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 75d88483..366a0a99 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/v0.9.2")] +#![doc(html_root_url="https://docs.rs/openssl/0.9.2")] #[macro_use] extern crate bitflags; From 791f2c8f4d70f49f2face6ea56ef924a784c12fb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 9 Dec 2016 21:54:06 -0800 Subject: [PATCH 069/140] Release v0.9.3 --- README.md | 2 +- openssl-sys/Cargo.toml | 4 ++-- openssl-sys/src/lib.rs | 2 +- openssl/Cargo.toml | 6 +++--- openssl/src/lib.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6f4c1f94..eee09f52 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) -[Documentation](https://docs.rs/openssl/0.9.2/openssl). +[Documentation](https://docs.rs/openssl/0.9.3/openssl). ## Warning diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 9deae1ec..7e827ed6 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "openssl-sys" -version = "0.9.2" +version = "0.9.3" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://docs.rs/openssl-sys/0.9.2/openssl_sys" +documentation = "https://docs.rs/openssl-sys/0.9.3/openssl_sys" links = "openssl" build = "build.rs" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index f287290d..e65bc447 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code, overflowing_literals)] -#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.2")] +#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.3")] extern crate libc; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 315c1fad..9de27903 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "openssl" -version = "0.9.2" +version = "0.9.3" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://docs.rs/openssl/0.9.2/openssl" +documentation = "https://docs.rs/openssl/0.9.3/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] build = "build.rs" @@ -20,7 +20,7 @@ v110 = [] bitflags = "0.7" lazy_static = "0.2" libc = "0.2" -openssl-sys = { version = "0.9.2", path = "../openssl-sys" } +openssl-sys = { version = "0.9.3", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 366a0a99..5d881d64 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://docs.rs/openssl/0.9.2")] +#![doc(html_root_url="https://docs.rs/openssl/0.9.3")] #[macro_use] extern crate bitflags; From b090804227596b1814bbb6c6cdcf89347270371e Mon Sep 17 00:00:00 2001 From: Aidan Hobson Sayers Date: Mon, 12 Dec 2016 17:51:35 +0000 Subject: [PATCH 070/140] Allow OPENSSL_{LIB,INCLUDE}_DIR to override OPENSSL_DIR --- README.md | 6 ++++++ openssl-sys/build.rs | 20 ++++++++++++++------ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 30b92e8e..9c3e30a2 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,12 @@ The build script can be configured via environment variables: * `OPENSSL_DIR` - If specified, a directory that will be used to find OpenSSL installation. It's expected that under this directory the `include` folder has header files and a `lib` folder has the runtime libraries. +* `OPENSSL_LIB_DIR` - If specified, a directory that will be used to find + OpenSSL libraries. Overrides the `lib` folder implied by `OPENSSL_DIR` + (if specified). +* `OPENSSL_INCLUDE_DIR` - If specified, a directory that will be used to find + OpenSSL header files. Overrides the `include` folder implied by `OPENSSL_DIR` + (if specified). * `OPENSSL_STATIC` - If specified, OpenSSL libraries will be statically rather than dynamically linked. diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index b6c8c2de..ce173192 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -11,17 +11,25 @@ use std::process::Command; fn main() { let target = env::var("TARGET").unwrap(); - let openssl_dir = env::var_os("OPENSSL_DIR").unwrap_or_else(|| { - find_openssl_dir(&target) - }); + let lib_dir = env::var_os("OPENSSL_LIB_DIR").map(PathBuf::from); + let include_dir = env::var_os("OPENSSL_INCLUDE_DIR").map(PathBuf::from); + + let (lib_dir, include_dir) = if lib_dir.is_none() || include_dir.is_none() { + let openssl_dir = env::var_os("OPENSSL_DIR").unwrap_or_else(|| { + find_openssl_dir(&target) + }); + let openssl_dir = Path::new(&openssl_dir); + let lib_dir = lib_dir.unwrap_or_else(|| openssl_dir.join("lib")); + let include_dir = include_dir.unwrap_or_else(|| openssl_dir.join("include")); + (lib_dir, include_dir) + } else { + (lib_dir.unwrap(), include_dir.unwrap()) + }; - let lib_dir = Path::new(&openssl_dir).join("lib"); - let include_dir = Path::new(&openssl_dir).join("include"); if !Path::new(&lib_dir).exists() { panic!("OpenSSL library directory does not exist: {}", lib_dir.to_string_lossy()); } - if !Path::new(&include_dir).exists() { panic!("OpenSSL include directory does not exist: {}", include_dir.to_string_lossy()); From 65d45bcad8766b335f50979a285e36d3e00cdc21 Mon Sep 17 00:00:00 2001 From: Philipp Keck Date: Wed, 14 Dec 2016 17:55:07 +0100 Subject: [PATCH 071/140] Explain how to install trusted root certificates The slproweb.com OpenSSL distribution does not contain root certificates, so they need to be downloaded and installed manually to avoid certificate warnings when making requests. --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 9c3e30a2..0f1eb435 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,18 @@ installation via an environment variable: set OPENSSL_DIR=C:\OpenSSL-Win64 ``` +Note that this OpenSSL distribution does not ship with any root certificates. +So to make requests to servers on the internet, you have to install them +manually. Download the [cacert.pem file from here], copy it somewhere safe +(`C:\OpenSSL-Win64\certs` is a good place) and point the `SSL_CERT_FILE` +environment variable there: + +``` +set SSL_CERT_FILE=C:\OpenSSL-Win64\certs\cacert.pem +``` + +[cacert.pem file from here]: https://curl.haxx.se/docs/caextract.html + After that, you're just a `cargo build` away! ### Windows GNU (MinGW) From 8e01f8d2502098497e642ee477d926a99ee619a8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 20 Dec 2016 14:04:10 -0800 Subject: [PATCH 072/140] Handle zero-length reads/writes This commit adds some short-circuits for zero-length reads/writes to `SslStream`. Because OpenSSL returns 0 on error, then we could mistakenly confuse a 0-length success as an actual error, so we avoid writing or reading 0 bytes by returning quickly with a success. --- openssl/src/ssl/mod.rs | 14 ++++++++++++++ openssl/src/ssl/tests/mod.rs | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6e0c92c3..47c83453 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1506,6 +1506,15 @@ impl SslStream { /// This is particularly useful with a nonblocking socket, where the error /// value will identify if OpenSSL is waiting on read or write readiness. pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result { + // The intepretation of the return code here is a little odd with a + // zero-length write. OpenSSL will likely correctly report back to us + // that it read zero bytes, but zero is also the sentinel for "error". + // To avoid that confusion short-circuit that logic and return quickly + // if `buf` has a length of zero. + if buf.len() == 0 { + return Ok(0) + } + let ret = self.ssl.read(buf); if ret > 0 { Ok(ret as usize) @@ -1523,6 +1532,11 @@ impl SslStream { /// This is particularly useful with a nonblocking socket, where the error /// value will identify if OpenSSL is waiting on read or write readiness. pub fn ssl_write(&mut self, buf: &[u8]) -> Result { + // See above for why we short-circuit on zero-length buffers + if buf.len() == 0 { + return Ok(0) + } + let ret = self.ssl.write(buf); if ret > 0 { Ok(ret as usize) diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 2f6bbe1f..66f9dca9 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -421,6 +421,16 @@ fn test_write() { stream.flush().unwrap(); } +#[test] +fn zero_length_buffers() { + let (_s, stream) = Server::new(); + let ctx = SslContext::builder(SslMethod::tls()).unwrap(); + let mut stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); + + assert_eq!(stream.write(b"").unwrap(), 0); + assert_eq!(stream.read(&mut []).unwrap(), 0); +} + run_test!(get_peer_certificate, |method, stream| { let ctx = SslContext::builder(method).unwrap(); let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); From 53c470c71a92067f0404561ac2610e5219626943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 21 Dec 2016 08:39:25 +0100 Subject: [PATCH 073/140] duplicate ossl10x.rs to libressl.rs --- openssl-sys/src/libressl.rs | 639 ++++++++++++++++++++++++++++++++++++ 1 file changed, 639 insertions(+) create mode 100644 openssl-sys/src/libressl.rs diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs new file mode 100644 index 00000000..4f418f14 --- /dev/null +++ b/openssl-sys/src/libressl.rs @@ -0,0 +1,639 @@ +use std::sync::{Mutex, MutexGuard}; +use std::sync::{Once, ONCE_INIT}; +use std::mem; + +use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; +#[cfg(not(ossl101))] +use libc::time_t; + +#[repr(C)] +pub struct stack_st_ASN1_OBJECT { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_X509 { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_X509_NAME { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_X509_ATTRIBUTE { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_X509_EXTENSION { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_GENERAL_NAME { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_void { + pub stack: _STACK, +} + +#[repr(C)] +pub struct _STACK { + pub num: c_int, + pub data: *mut *mut c_char, + pub sorted: c_int, + pub num_alloc: c_int, + pub comp: Option c_int>, +} + +#[repr(C)] +pub struct BIO_METHOD { + pub type_: c_int, + pub name: *const c_char, + pub bwrite: Option c_int>, + pub bread: Option c_int>, + pub bputs: Option c_int>, + pub bgets: Option c_int>, + pub ctrl: Option c_long>, + pub create: Option c_int>, + pub destroy: Option c_int>, + pub callback_ctrl: Option c_long>, +} + +#[repr(C)] +pub struct RSA { + pub pad: c_int, + pub version: c_long, + pub meth: *const ::RSA_METHOD, + + pub engine: *mut ::ENGINE, + pub n: *mut ::BIGNUM, + pub e: *mut ::BIGNUM, + pub d: *mut ::BIGNUM, + pub p: *mut ::BIGNUM, + pub q: *mut ::BIGNUM, + pub dmp1: *mut ::BIGNUM, + pub dmq1: *mut ::BIGNUM, + pub iqmp: *mut ::BIGNUM, + + pub ex_data: ::CRYPTO_EX_DATA, + pub references: c_int, + pub flags: c_int, + + pub _method_mod_n: *mut ::BN_MONT_CTX, + pub _method_mod_p: *mut ::BN_MONT_CTX, + pub _method_mod_q: *mut ::BN_MONT_CTX, + + pub bignum_data: *mut c_char, + pub blinding: *mut ::BN_BLINDING, + pub mt_blinding: *mut ::BN_BLINDING, +} + +#[repr(C)] +pub struct DSA { + pub pad: c_int, + pub version: c_long, + pub write_params: c_int, + + pub p: *mut ::BIGNUM, + pub q: *mut ::BIGNUM, + pub g: *mut ::BIGNUM, + pub pub_key: *mut ::BIGNUM, + pub priv_key: *mut ::BIGNUM, + pub kinv: *mut ::BIGNUM, + pub r: *mut ::BIGNUM, + + pub flags: c_int, + pub method_mont_p: *mut ::BN_MONT_CTX, + pub references: c_int, + pub ex_data: ::CRYPTO_EX_DATA, + pub meth: *const ::DSA_METHOD, + pub engine: *mut ::ENGINE, +} + +#[repr(C)] +pub struct EVP_PKEY { + pub type_: c_int, + pub save_type: c_int, + pub references: c_int, + pub ameth: *const ::EVP_PKEY_ASN1_METHOD, + pub engine: *mut ::ENGINE, + pub pkey: *mut c_void, + pub save_parameters: c_int, + pub attributes: *mut stack_st_X509_ATTRIBUTE, +} + +#[repr(C)] +pub struct BIO { + pub method: *mut ::BIO_METHOD, + pub callback: Option c_long>, + pub cb_arg: *mut c_char, + pub init: c_int, + pub shutdown: c_int, + pub flags: c_int, + pub retry_reason: c_int, + pub num: c_int, + pub ptr: *mut c_void, + pub next_bio: *mut ::BIO, + pub prev_bio: *mut ::BIO, + pub references: c_int, + pub num_read: c_ulong, + pub num_write: c_ulong, + pub ex_data: ::CRYPTO_EX_DATA, +} + +#[repr(C)] +pub struct CRYPTO_EX_DATA { + pub sk: *mut ::stack_st_void, + pub dummy: c_int, +} + +#[repr(C)] +pub struct EVP_MD_CTX { + digest: *mut ::EVP_MD, + engine: *mut ::ENGINE, + flags: c_ulong, + md_data: *mut c_void, + pctx: *mut ::EVP_PKEY_CTX, + update: *mut c_void +} + +#[repr(C)] +pub struct EVP_CIPHER { + pub nid: c_int, + pub block_size: c_int, + pub key_len: c_int, + pub iv_len: c_int, + pub flags: c_ulong, + pub init: Option c_int>, + pub do_cipher: Option c_int>, + pub cleanup: Option c_int>, + pub ctx_size: c_int, + pub set_asn1_parameters: Option c_int>, + pub get_asn1_parameters: Option c_int>, + pub ctrl: Option c_int>, + pub app_data: *mut c_void, +} + +#[repr(C)] +pub struct HMAC_CTX { + md: *mut ::EVP_MD, + md_ctx: ::EVP_MD_CTX, + i_ctx: ::EVP_MD_CTX, + o_ctx: ::EVP_MD_CTX, + key_length: c_uint, + key: [c_uchar; 128] +} + +#[repr(C)] +pub struct BIGNUM { + pub d: *mut ::BN_ULONG, + pub top: c_int, + pub dmax: c_int, + pub neg: c_int, + pub flags: c_int, +} + +#[repr(C)] +pub struct DH { + pub pad: c_int, + pub version: c_int, + pub p: *mut ::BIGNUM, + pub g: *mut ::BIGNUM, + pub length: c_long, + pub pub_key: *mut ::BIGNUM, + pub priv_key: *mut ::BIGNUM, + pub flags: c_int, + pub method_mont_p: *mut ::BN_MONT_CTX, + pub q: *mut ::BIGNUM, + pub j: *mut ::BIGNUM, + pub seed: *mut c_uchar, + pub seedlen: c_int, + pub counter: *mut ::BIGNUM, + pub references: c_int, + pub ex_data: ::CRYPTO_EX_DATA, + pub meth: *const ::DH_METHOD, + pub engine: *mut ::ENGINE, +} + +#[repr(C)] +pub struct X509 { + pub cert_info: *mut X509_CINF, + sig_alg: *mut c_void, + signature: *mut c_void, + pub valid: c_int, + pub references: c_int, + pub name: *mut c_char, + pub ex_data: ::CRYPTO_EX_DATA, + pub ex_pathlen: c_long, + pub ex_pcpathlen: c_long, + pub ex_flags: c_ulong, + pub ex_kusage: c_ulong, + pub ex_xkusage: c_ulong, + pub ex_nscert: c_ulong, + skid: *mut c_void, + akid: *mut c_void, + policy_cache: *mut c_void, + crldp: *mut c_void, + altname: *mut c_void, + nc: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] + rfc3779_addr: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] + rfc3779_asid: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] + sha1_hash: [c_uchar; 20], + aux: *mut c_void, +} + +#[repr(C)] +pub struct X509_CINF { + version: *mut c_void, + serialNumber: *mut c_void, + signature: *mut c_void, + issuer: *mut c_void, + pub validity: *mut X509_VAL, + subject: *mut c_void, + key: *mut c_void, + issuerUID: *mut c_void, + subjectUID: *mut c_void, + pub extensions: *mut stack_st_X509_EXTENSION, + enc: ASN1_ENCODING, +} + +#[repr(C)] +pub struct ASN1_ENCODING { + pub enc: *mut c_uchar, + pub len: c_long, + pub modified: c_int, +} + +#[repr(C)] +pub struct X509_VAL { + pub notBefore: *mut ::ASN1_TIME, + pub notAfter: *mut ::ASN1_TIME, +} + +#[repr(C)] +pub struct SSL_CTX { + method: *mut c_void, + cipher_list: *mut c_void, + cipher_list_by_id: *mut c_void, + cert_store: *mut c_void, + sessions: *mut c_void, + session_cache_size: c_ulong, + session_cache_head: *mut c_void, + session_cache_tail: *mut c_void, + session_cache_mode: c_int, + session_timeout: c_long, + new_session_cb: *mut c_void, + remove_session_cb: *mut c_void, + get_session_cb: *mut c_void, + stats: [c_int; 11], + pub references: c_int, + app_verify_callback: *mut c_void, + app_verify_arg: *mut c_void, + default_passwd_callback: *mut c_void, + default_passwd_callback_userdata: *mut c_void, + client_cert_cb: *mut c_void, + app_gen_cookie_cb: *mut c_void, + app_verify_cookie_cb: *mut c_void, + ex_dat: ::CRYPTO_EX_DATA, + rsa_md5: *mut c_void, + md5: *mut c_void, + sha1: *mut c_void, + extra_certs: *mut c_void, + comp_methods: *mut c_void, + info_callback: *mut c_void, + client_CA: *mut c_void, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + cert: *mut c_void, + read_ahead: c_int, + msg_callback: *mut c_void, + msg_callback_arg: *mut c_void, + verify_mode: c_int, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; 32], + default_verify_callback: *mut c_void, + generate_session_id: *mut c_void, + param: *mut c_void, + quiet_shutdown: c_int, + max_send_fragment: c_uint, + + #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] + client_cert_engine: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_servername_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsect_servername_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_key_name: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_hmac_key: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_aes_key: [c_uchar; 16], + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticket_key_cb: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_cb: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_callback_arg: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity_hint: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_client_callback: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_server_callback: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + freelist_max_len: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + wbuf_freelist: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] + rbuf_freelist: *mut c_void, + + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_ctx: SRP_CTX, + + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_protos_advertised_cb: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_protos_advertised_cb_arg: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_proto_select_cb: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_proto_select_cb_arg: *mut c_void, + + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl101))] + srtp_profiles: *mut c_void, + + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + srtp_profiles: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_select_cb: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_select_cb_arg: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list: *mut c_void, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list_len: c_uint, + + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] + tlsext_ellipticcurvelist: *mut c_uchar, +} + +#[repr(C)] +pub struct SRP_CTX { + SRP_cb_arg: *mut c_void, + TLS_ext_srp_username_callback: *mut c_void, + SRP_verify_param_callback: *mut c_void, + SRP_give_srp_client_pwd_callback: *mut c_void, + login: *mut c_void, + N: *mut c_void, + g: *mut c_void, + s: *mut c_void, + B: *mut c_void, + A: *mut c_void, + a: *mut c_void, + b: *mut c_void, + v: *mut c_void, + info: *mut c_void, + stringth: c_int, + srp_Mask: c_ulong, +} + +#[repr(C)] +#[cfg(not(ossl101))] +pub struct X509_VERIFY_PARAM { + pub name: *mut c_char, + pub check_time: time_t, + pub inh_flags: c_ulong, + pub flags: c_ulong, + pub purpose: c_int, + pub trust: c_int, + pub depth: c_int, + pub policies: *mut stack_st_ASN1_OBJECT, + pub id: *mut X509_VERIFY_PARAM_ID, +} + +#[cfg(not(ossl101))] +pub enum X509_VERIFY_PARAM_ID {} + +pub const SSL_CTRL_OPTIONS: c_int = 32; +pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; +#[cfg(ossl102)] +pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; + +pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000001; +pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000002; +pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x00000008; +pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x00000020; +pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x00000080; +pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x00000100; +pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x00000200; +pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; +pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; +pub const SSL_OP_NO_SSLv2: c_ulong = 0x01000000; + +pub const SSLEAY_VERSION : c_int = 0; +pub const SSLEAY_CFLAGS : c_int = 2; +pub const SSLEAY_BUILT_ON : c_int = 3; +pub const SSLEAY_PLATFORM : c_int = 4; +pub const SSLEAY_DIR : c_int = 5; + +pub const CRYPTO_LOCK_X509: c_int = 3; +pub const CRYPTO_LOCK_SSL_CTX: c_int = 12; + +static mut MUTEXES: *mut Vec> = 0 as *mut Vec>; +static mut GUARDS: *mut Vec>> = 0 as *mut Vec>>; + +unsafe extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, + _line: c_int) { + let mutex = &(*MUTEXES)[n as usize]; + + if mode & ::CRYPTO_LOCK != 0 { + (*GUARDS)[n as usize] = Some(mutex.lock().unwrap()); + } else { + &(*GUARDS)[n as usize].take(); + } +} + +pub fn init() { + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + unsafe { + SSL_library_init(); + SSL_load_error_strings(); + OPENSSL_add_all_algorithms_noconf(); + + let num_locks = ::CRYPTO_num_locks(); + let mut mutexes = Box::new(Vec::new()); + for _ in 0..num_locks { + mutexes.push(Mutex::new(())); + } + MUTEXES = mem::transmute(mutexes); + let guards: Box>>> = + Box::new((0..num_locks).map(|_| None).collect()); + GUARDS = mem::transmute(guards); + + CRYPTO_set_locking_callback(locking_function); + set_id_callback(); + } + }) +} + +#[cfg(unix)] +fn set_id_callback() { + unsafe extern fn thread_id() -> c_ulong { + ::libc::pthread_self() as c_ulong + } + + unsafe { + CRYPTO_set_id_callback(thread_id); + } +} + +#[cfg(not(unix))] +fn set_id_callback() {} + +// macros + +#[cfg(ossl102)] +pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { + ::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int +} + +#[cfg(ossl102)] +pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { + ::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int +} + +extern { + pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; + pub fn BIO_s_file() -> *mut BIO_METHOD; + pub fn BIO_s_mem() -> *mut BIO_METHOD; + + pub fn get_rfc2409_prime_768(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc2409_prime_1024(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_1536(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_2048(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_3072(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_4096(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + + pub fn CRYPTO_free(buf: *mut c_void); + pub fn CRYPTO_num_locks() -> c_int; + pub fn CRYPTO_set_locking_callback(func: unsafe extern "C" fn(mode: c_int, + n: c_int, + file: *const c_char, + line: c_int)); + pub fn CRYPTO_set_id_callback(func: unsafe extern "C" fn() -> c_ulong); + + pub fn ERR_load_crypto_strings(); + + pub fn RSA_generate_key(modsz: c_int, + e: c_ulong, + cb: Option, + cbarg: *mut c_void) -> *mut RSA; + + pub fn SSL_library_init() -> c_int; + pub fn SSL_load_error_strings(); + pub fn OPENSSL_add_all_algorithms_noconf(); + pub fn HMAC_CTX_init(ctx: *mut ::HMAC_CTX); + pub fn HMAC_CTX_cleanup(ctx: *mut ::HMAC_CTX); + #[cfg(not(osslconf = "OPENSSL_NO_SSL3_METHOD"))] + pub fn SSLv3_method() -> *const ::SSL_METHOD; + pub fn TLSv1_method() -> *const ::SSL_METHOD; + pub fn SSLv23_method() -> *const ::SSL_METHOD; + pub fn TLSv1_1_method() -> *const ::SSL_METHOD; + pub fn TLSv1_2_method() -> *const ::SSL_METHOD; + pub fn DTLSv1_method() -> *const ::SSL_METHOD; + #[cfg(ossl102)] + pub fn DTLSv1_2_method() -> *const ::SSL_METHOD; + pub fn SSL_get_ex_new_index(argl: c_long, argp: *mut c_void, + new_func: Option<::CRYPTO_EX_new>, + dup_func: Option<::CRYPTO_EX_dup>, + free_func: Option<::CRYPTO_EX_free>) + -> c_int; + pub fn SSL_set_tmp_ecdh_callback(ssl: *mut ::SSL, + ecdh: unsafe extern fn(ssl: *mut ::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ::EC_KEY); + pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *mut c_char; + pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *mut c_void, + new_func: Option<::CRYPTO_EX_new>, + dup_func: Option<::CRYPTO_EX_dup>, + free_func: Option<::CRYPTO_EX_free>) + -> c_int; + pub fn SSL_CTX_set_tmp_ecdh_callback(ctx: *mut ::SSL_CTX, + ecdh: unsafe extern fn(ssl: *mut ::SSL, + is_export: c_int, + keylength: c_int) + -> *mut ::EC_KEY); + pub fn X509_get_subject_name(x: *mut ::X509) -> *mut ::X509_NAME; + pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_set_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; + pub fn X509_get_ext_d2i(x: *mut ::X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; + pub fn X509_NAME_get_entry(n: *mut ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; + pub fn X509_NAME_ENTRY_get_data(ne: *mut ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; + pub fn X509_STORE_CTX_get_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; + pub fn X509V3_EXT_nconf_nid(conf: *mut ::CONF, ctx: *mut ::X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut ::X509_EXTENSION; + pub fn X509V3_EXT_nconf(conf: *mut ::CONF, ctx: *mut ::X509V3_CTX, name: *mut c_char, value: *mut c_char) -> *mut ::X509_EXTENSION; + pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: *mut ::ASN1_STRING) -> c_int; + pub fn ASN1_STRING_data(x: *mut ::ASN1_STRING) -> *mut c_uchar; + pub fn CRYPTO_add_lock(pointer: *mut c_int, + amount: c_int, + type_: c_int, + file: *const c_char, + line: c_int) -> c_int; + pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; + pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); + pub fn EVP_PKEY_bits(key: *mut EVP_PKEY) -> c_int; + + pub fn sk_num(st: *const _STACK) -> c_int; + pub fn sk_value(st: *const _STACK, n: c_int) -> *mut c_void; + pub fn sk_free(st: *mut _STACK); + pub fn sk_pop_free(st: *mut _STACK, free: Option); + pub fn sk_pop(st: *mut _STACK) -> *mut c_void; + + pub fn SSLeay() -> c_ulong; + pub fn SSLeay_version(key: c_int) -> *const c_char; +} From b3526cbd2b8ca9e4eff4d4a0f1c3461cedcae776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Wed, 21 Dec 2016 08:58:16 +0100 Subject: [PATCH 074/140] Add LibreSSL 2.5.0 support --- openssl-sys/build.rs | 9 +++ openssl-sys/src/lib.rs | 55 +++++++++++------ openssl-sys/src/libressl.rs | 111 +++++------------------------------ openssl/build.rs | 4 ++ openssl/src/ssl/mod.rs | 3 + openssl/src/ssl/tests/mod.rs | 8 +-- openssl/src/version.rs | 7 ++- systest/build.rs | 6 +- 8 files changed, 81 insertions(+), 122 deletions(-) diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index ce173192..ce990be3 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -247,6 +247,15 @@ fn validate_headers(include_dirs: &[PathBuf], } else if version_text.contains("0x10100") { println!("cargo:rustc-cfg=ossl110"); println!("cargo:version=110"); + } else if version_text.contains("0x20000000L") { + // Check if it is really LibreSSL + if version_header.lines().any(|l| { + l.contains("define ") && l.contains("LIBRESSL_VERSION_NUMBER") + }) { + println!("cargo:rustc-cfg=libressl"); + println!("cargo:libressl=true"); + println!("cargo:version=101"); + } } else { panic!(" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 3ac3c2c2..8c4d1acf 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -17,6 +17,11 @@ mod ossl110; #[cfg(ossl110)] pub use ossl110::*; +#[cfg(libressl)] +mod libressl; +#[cfg(libressl)] +pub use libressl::*; + pub enum ASN1_INTEGER {} pub enum ASN1_STRING {} pub enum ASN1_TIME {} @@ -1075,8 +1080,11 @@ pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: c_long = 0x2; pub const SSL_MODE_AUTO_RETRY: c_long = 0x4; pub const SSL_MODE_NO_AUTO_CHAIN: c_long = 0x8; pub const SSL_MODE_RELEASE_BUFFERS: c_long = 0x10; +#[cfg(not(libressl))] pub const SSL_MODE_SEND_CLIENTHELLO_TIME: c_long = 0x20; +#[cfg(not(libressl))] pub const SSL_MODE_SEND_SERVERHELLO_TIME: c_long = 0x40; +#[cfg(not(libressl))] pub const SSL_MODE_SEND_FALLBACK_SCSV: c_long = 0x80; pub const SSL_ERROR_NONE: c_int = 0; @@ -1095,26 +1103,31 @@ pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; #[cfg(not(ossl101))] pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x00000010; pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_ulong = 0x00000800; +#[cfg(not(libressl))] pub const SSL_OP_ALL: c_ulong = 0x80000BFF; pub const SSL_OP_NO_QUERY_MTU: c_ulong = 0x00001000; pub const SSL_OP_COOKIE_EXCHANGE: c_ulong = 0x00002000; pub const SSL_OP_NO_TICKET: c_ulong = 0x00004000; +#[cfg(not(libressl))] pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x00008000; pub const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: c_ulong = 0x00010000; +#[cfg(not(libressl))] pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x00020000; +#[cfg(not(libressl))] pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x00040000; pub const SSL_OP_CIPHER_SERVER_PREFERENCE: c_ulong = 0x00400000; pub const SSL_OP_TLS_ROLLBACK_BUG: c_ulong = 0x00800000; +#[cfg(not(libressl))] pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000; pub const SSL_OP_NO_TLSv1: c_ulong = 0x04000000; pub const SSL_OP_NO_TLSv1_2: c_ulong = 0x08000000; pub const SSL_OP_NO_TLSv1_1: c_ulong = 0x10000000; -#[cfg(not(ossl101))] +#[cfg(not(any(ossl101, libressl)))] pub const SSL_OP_NO_DTLSv1: c_ulong = 0x04000000; -#[cfg(not(ossl101))] +#[cfg(not(any(ossl101, libressl)))] pub const SSL_OP_NO_DTLSv1_2: c_ulong = 0x08000000; -#[cfg(not(ossl101))] +#[cfg(not(any(ossl101, libressl)))] pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; @@ -1292,9 +1305,9 @@ extern { pub fn BIO_new_socket(sock: c_int, close_flag: c_int) -> *mut BIO; pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; - #[cfg(ossl101)] + #[cfg(any(ossl101, libressl))] pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO; - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO; pub fn BIO_set_flags(b: *mut BIO, flags: c_int); pub fn BIO_clear_flags(b: *mut BIO, flags: c_int); @@ -1375,11 +1388,11 @@ extern { pub fn DH_new() -> *mut DH; pub fn DH_free(dh: *mut DH); - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn DH_get_1024_160() -> *mut DH; - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn DH_get_2048_224() -> *mut DH; - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn DH_get_2048_256() -> *mut DH; pub fn EC_KEY_new() -> *mut EC_KEY; @@ -1495,11 +1508,11 @@ extern { type_: *const EVP_MD, e: *mut ENGINE, pkey: *mut EVP_PKEY) -> c_int; - #[cfg(ossl101)] + #[cfg(any(ossl101, libressl))] pub fn EVP_DigestVerifyFinal(ctx: *mut EVP_MD_CTX, sigret: *mut c_uchar, siglen: size_t) -> c_int; - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn EVP_DigestVerifyFinal(ctx: *mut EVP_MD_CTX, sigret: *const c_uchar, siglen: size_t) -> c_int; @@ -1634,8 +1647,10 @@ extern { pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; pub fn SSL_get_SSL_CTX(ssl: *const SSL) -> *mut SSL_CTX; pub fn SSL_set_SSL_CTX(ssl: *mut SSL, ctx: *mut SSL_CTX) -> *mut SSL_CTX; - #[cfg(not(osslconf = "OPENSSL_NO_COMP"))] + #[cfg(not(any(osslconf = "OPENSSL_NO_COMP", libressl)))] pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; + #[cfg(libressl)] + pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const libc::c_void; pub fn SSL_get_peer_certificate(ssl: *const SSL) -> *mut X509; pub fn SSL_get_ssl_method(ssl: *mut SSL) -> *const SSL_METHOD; pub fn SSL_get_version(ssl: *const SSL) -> *const c_char; @@ -1648,14 +1663,14 @@ extern { pub fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void; pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER; - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long; pub fn SSL_shutdown(ssl: *mut SSL) -> c_int; pub fn SSL_get_certificate(ssl: *const SSL) -> *mut X509; - #[cfg(ossl101)] + #[cfg(any(ossl101, libressl))] pub fn SSL_get_privatekey(ssl: *mut SSL) -> *mut EVP_PKEY; - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn SSL_get_privatekey(ssl: *const SSL) -> *mut EVP_PKEY; pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; pub fn SSL_set_tmp_dh_callback(ctx: *mut SSL, @@ -1664,8 +1679,10 @@ extern { keylength: c_int) -> *mut DH); - #[cfg(not(osslconf = "OPENSSL_NO_COMP"))] + #[cfg(not(any(osslconf = "OPENSSL_NO_COMP", libressl)))] pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; + #[cfg(libressl)] + pub fn SSL_COMP_get_name(comp: *const libc::c_void) -> *const c_char; pub fn SSL_CIPHER_get_name(cipher: *const SSL_CIPHER) -> *const c_char; pub fn SSL_CIPHER_get_bits(cipher: *const SSL_CIPHER, alg_bits: *mut c_int) -> c_int; @@ -1701,9 +1718,9 @@ extern { keylength: c_int) -> *mut DH); - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn SSL_CTX_get0_privatekey(ctx: *const SSL_CTX) -> *mut EVP_PKEY; pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; @@ -1787,9 +1804,9 @@ extern { #[cfg(not(ossl101))] pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM); - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn X509_VERIFY_PARAM_set_hostflags(param: *mut X509_VERIFY_PARAM, flags: c_uint); - #[cfg(not(ossl101))] + #[cfg(not(any(ossl101, libressl)))] pub fn X509_VERIFY_PARAM_set1_host(param: *mut X509_VERIFY_PARAM, name: *const c_char, namelen: size_t) -> c_int; diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index 4f418f14..0f20713e 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -3,7 +3,6 @@ use std::sync::{Once, ONCE_INIT}; use std::mem; use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; -#[cfg(not(ossl101))] use libc::time_t; #[repr(C)] @@ -88,7 +87,6 @@ pub struct RSA { pub _method_mod_p: *mut ::BN_MONT_CTX, pub _method_mod_q: *mut ::BN_MONT_CTX, - pub bignum_data: *mut c_char, pub blinding: *mut ::BN_BLINDING, pub mt_blinding: *mut ::BN_BLINDING, } @@ -155,7 +153,6 @@ pub struct BIO { #[repr(C)] pub struct CRYPTO_EX_DATA { pub sk: *mut ::stack_st_void, - pub dummy: c_int, } #[repr(C)] @@ -258,10 +255,6 @@ pub struct X509 { crldp: *mut c_void, altname: *mut c_void, nc: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] - rfc3779_addr: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_RFC3779"))] - rfc3779_asid: *mut c_void, #[cfg(not(osslconf = "OPENSSL_NO_SHA"))] sha1_hash: [c_uchar; 20], aux: *mut c_void, @@ -346,99 +339,26 @@ pub struct SSL_CTX { #[cfg(not(osslconf = "OPENSSL_NO_ENGINE"))] client_cert_engine: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_servername_callback: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsect_servername_arg: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_tick_key_name: [c_uchar; 16], - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_tick_hmac_key: [c_uchar; 16], - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_tick_aes_key: [c_uchar; 16], - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_ticket_key_cb: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_status_cb: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_status_arg: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_opaque_prf_input_callback: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] tlsext_opaque_prf_input_callback_arg: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_identity_hint: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_client_callback: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] - psk_server_callback: *mut c_void, - - #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] - freelist_max_len: c_uint, - #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] - wbuf_freelist: *mut c_void, - #[cfg(not(osslconf = "OPENSSL_NO_BUF_FREELISTS"))] - rbuf_freelist: *mut c_void, - - #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] - srp_ctx: SRP_CTX, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] next_protos_advertised_cb: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] next_protos_advertised_cb_arg: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] next_proto_select_cb: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] next_proto_select_cb_arg: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl101))] srtp_profiles: *mut c_void, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - srtp_profiles: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_select_cb: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_select_cb_arg: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_client_proto_list: *mut c_void, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - alpn_client_proto_list_len: c_uint, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] - tlsext_ecpointformatlist_length: size_t, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] - tlsext_ecpointformatlist: *mut c_uchar, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] - tlsext_ellipticcurvelist_length: size_t, - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC"), ossl102))] - tlsext_ellipticcurvelist: *mut c_uchar, } #[repr(C)] -pub struct SRP_CTX { - SRP_cb_arg: *mut c_void, - TLS_ext_srp_username_callback: *mut c_void, - SRP_verify_param_callback: *mut c_void, - SRP_give_srp_client_pwd_callback: *mut c_void, - login: *mut c_void, - N: *mut c_void, - g: *mut c_void, - s: *mut c_void, - B: *mut c_void, - A: *mut c_void, - a: *mut c_void, - b: *mut c_void, - v: *mut c_void, - info: *mut c_void, - stringth: c_int, - srp_Mask: c_ulong, -} - -#[repr(C)] -#[cfg(not(ossl101))] pub struct X509_VERIFY_PARAM { pub name: *mut c_char, pub check_time: time_t, @@ -448,27 +368,30 @@ pub struct X509_VERIFY_PARAM { pub trust: c_int, pub depth: c_int, pub policies: *mut stack_st_ASN1_OBJECT, - pub id: *mut X509_VERIFY_PARAM_ID, + //pub id: *mut X509_VERIFY_PARAM_ID, } -#[cfg(not(ossl101))] pub enum X509_VERIFY_PARAM_ID {} pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; -#[cfg(ossl102)] pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; -pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000001; -pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000002; -pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x00000008; -pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x00000020; -pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x00000080; -pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x00000100; -pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x00000200; +pub const SSL_OP_ALL: c_ulong = 0x80000014; +pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x0; +pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x0; +pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x0; +pub const SSL_OP_NO_SSLv3: c_ulong = 0x0; +pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x0; +pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x0; +pub const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: c_ulong = 0x0; +pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x0; +pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x0; +pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x0; +pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x0; pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; -pub const SSL_OP_NO_SSLv2: c_ulong = 0x01000000; +pub const SSL_OP_NO_SSLv2: c_ulong = 0x0; pub const SSLEAY_VERSION : c_int = 0; pub const SSLEAY_CFLAGS : c_int = 2; @@ -534,12 +457,10 @@ fn set_id_callback() {} // macros -#[cfg(ossl102)] pub unsafe fn SSL_CTX_set_ecdh_auto(ctx: *mut SSL_CTX, onoff: c_int) -> c_int { ::SSL_CTX_ctrl(ctx, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int } -#[cfg(ossl102)] pub unsafe fn SSL_set_ecdh_auto(ssl: *mut ::SSL, onoff: c_int) -> c_int { ::SSL_ctrl(ssl, SSL_CTRL_SET_ECDH_AUTO, onoff as c_long, ::std::ptr::null_mut()) as c_int } @@ -578,15 +499,11 @@ extern { pub fn OPENSSL_add_all_algorithms_noconf(); pub fn HMAC_CTX_init(ctx: *mut ::HMAC_CTX); pub fn HMAC_CTX_cleanup(ctx: *mut ::HMAC_CTX); - #[cfg(not(osslconf = "OPENSSL_NO_SSL3_METHOD"))] - pub fn SSLv3_method() -> *const ::SSL_METHOD; pub fn TLSv1_method() -> *const ::SSL_METHOD; pub fn SSLv23_method() -> *const ::SSL_METHOD; pub fn TLSv1_1_method() -> *const ::SSL_METHOD; pub fn TLSv1_2_method() -> *const ::SSL_METHOD; pub fn DTLSv1_method() -> *const ::SSL_METHOD; - #[cfg(ossl102)] - pub fn DTLSv1_2_method() -> *const ::SSL_METHOD; pub fn SSL_get_ex_new_index(argl: c_long, argp: *mut c_void, new_func: Option<::CRYPTO_EX_new>, dup_func: Option<::CRYPTO_EX_dup>, diff --git a/openssl/build.rs b/openssl/build.rs index 7a0c60dc..954e9b0c 100644 --- a/openssl/build.rs +++ b/openssl/build.rs @@ -16,6 +16,10 @@ fn main() { _ => panic!("Unable to detect OpenSSL version"), } + if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { + println!("cargo:rustc-cfg=libressl"); + } + if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { for var in vars.split(",") { println!("cargo:rustc-cfg=osslconf=\"{}\"", var); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6e0c92c3..9803949d 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -166,8 +166,11 @@ bitflags! { const SSL_MODE_AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY, const SSL_MODE_NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN, const SSL_MODE_RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS, + #[cfg(not(libressl))] const SSL_MODE_SEND_CLIENTHELLO_TIME = ffi::SSL_MODE_SEND_CLIENTHELLO_TIME, + #[cfg(not(libressl))] const SSL_MODE_SEND_SERVERHELLO_TIME = ffi::SSL_MODE_SEND_SERVERHELLO_TIME, + #[cfg(not(libressl))] const SSL_MODE_SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV, } } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 2f6bbe1f..437bec8a 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -181,7 +181,7 @@ macro_rules! run_test( } #[test] - #[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467) + #[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) fn dtlsv1() { let (_s, stream) = Server::new_dtlsv1(Some("hello")); $blk(SslMethod::dtls(), stream); @@ -432,7 +432,7 @@ run_test!(get_peer_certificate, |method, stream| { }); #[test] -#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467) +#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) fn test_write_dtlsv1() { let (_s, stream) = Server::new_dtlsv1(iter::repeat("y\n")); let ctx = SslContext::builder(SslMethod::dtls()).unwrap(); @@ -771,7 +771,7 @@ fn test_alpn_server_select_none() { } #[test] -#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467) +#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) fn test_read_dtlsv1() { let (_s, stream) = Server::new_dtlsv1(Some("hello")); @@ -849,7 +849,7 @@ fn test_write_nonblocking() { } #[test] -#[cfg_attr(any(windows, target_arch = "arm"), ignore)] // FIXME(#467) +#[cfg_attr(any(libressl, windows, target_arch = "arm"), ignore)] // FIXME(#467) fn test_read_nonblocking() { let (_s, stream) = Server::new(); stream.set_nonblocking(true).unwrap(); diff --git a/openssl/src/version.rs b/openssl/src/version.rs index d7db39a7..2604914e 100644 --- a/openssl/src/version.rs +++ b/openssl/src/version.rs @@ -92,8 +92,13 @@ fn test_versions() { println!("Platform: '{}'", platform()); println!("Dir: '{}'", dir()); + #[cfg(not(libressl))] + fn expected_name() -> &'static str { "OpenSSL" } + #[cfg(libressl)] + fn expected_name() -> &'static str { "LibreSSL" } + assert!(number() > 0); - assert!(version().starts_with("OpenSSL")); + assert!(version().starts_with(expected_name())); assert!(c_flags().starts_with("compiler:")); assert!(built_on().starts_with("built on:")); assert!(dir().starts_with("OPENSSLDIR:")); diff --git a/systest/build.rs b/systest/build.rs index b0ca3250..2f0fd136 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -22,7 +22,11 @@ fn main() { } } - cfg.cfg(&format!("ossl{}", env::var("DEP_OPENSSL_VERSION").unwrap()), None); + if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { + cfg.cfg("libressl", None); + } else if let Ok(version) = env::var("DEP_OPENSSL_VERSION") { + cfg.cfg(&format!("ossl{}", version), None); + } if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { for var in vars.split(",") { cfg.cfg("osslconf", Some(var)); From a70e27ae646834619c7abf4a3aef95bfd87666b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Marie?= Date: Tue, 20 Dec 2016 20:07:41 +0100 Subject: [PATCH 075/140] Add Travis build against LibreSSL --- .travis.yml | 3 +++ openssl/test/build.sh | 50 +++++++++++++++++++++++++++---------------- openssl/test/run.sh | 16 +++++++++----- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1b79c5b0..e8d89347 100644 --- a/.travis.yml +++ b/.travis.yml @@ -72,6 +72,8 @@ matrix: packages: - gcc-multilib + # LibreSSL + - env: BUILD_LIBRESSL_VERSION=2.5.0 before_install: - ./openssl/test/build.sh @@ -83,4 +85,5 @@ script: cache: cargo: true directories: + - $HOME/libressl - $HOME/openssl diff --git a/openssl/test/build.sh b/openssl/test/build.sh index 106a38d3..cd740895 100755 --- a/openssl/test/build.sh +++ b/openssl/test/build.sh @@ -3,21 +3,29 @@ set -ex MAX_REDIRECTS=5 -OPENSSL=openssl-$BUILD_OPENSSL_VERSION.tar.gz -OUT=/tmp/$OPENSSL -me=$0 -myname=`basename $me` - -cmp --silent $me $HOME/openssl/$myname && exit 0 || echo "cache is busted" - -rm -rf $HOME/openssl - -if [ "$TRAVIS_OS_NAME" == "osx" ]; then +if [ -n "${BUILD_LIBRESSL_VERSION}" ]; then + NAME=libressl + URL1="http://ftp3.usa.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${BUILD_LIBRESSL_VERSION}.tar.gz" + URL2="http://ftp.eu.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${BUILD_LIBRESSL_VERSION}.tar.gz" + OUT="/tmp/libressl-${BUILD_OPENSSL_VERSION}.tar.gz" +elif [ -n "${BUILD_OPENSSL_VERSION}" ]; then + NAME=openssl + URL1="https://openssl.org/source/openssl-${BUILD_OPENSSL_VERSION}.tar.gz" + URL2="http://mirrors.ibiblio.org/openssl/source/openssl-${BUILD_OPENSSL_VERSION}.tar.gz" + OUT="/tmp/openssl-${BUILD_OPENSSL_VERSION}.tar.gz" +else exit 0 fi -if [ "$BUILD_OPENSSL_VERSION" == "" ]; then +me=$0 +myname=`basename ${me}` + +cmp --silent ${me} ${HOME}/${NAME}/${myname} && exit 0 || echo "cache is busted" + +rm -rf "${HOME}/${NAME}" + +if [ "${TRAVIS_OS_NAME}" == "osx" ]; then exit 0 fi @@ -32,17 +40,21 @@ else OS_COMPILER=linux-x86_64 fi -mkdir -p /tmp/openssl -cp $me /tmp/openssl/$myname -cd /tmp/openssl +mkdir -p /tmp/build +cp ${me} /tmp/build/${myname} +cd /tmp/build -curl -o $OUT -L --max-redirs $MAX_REDIRECTS https://openssl.org/source/$OPENSSL \ - || curl -o $OUT -L --max-redirs ${MAX_REDIRECTS} http://mirrors.ibiblio.org/openssl/source/$OPENSSL +curl -o ${OUT} -L --max-redirs ${MAX_REDIRECTS} ${URL1} \ + || curl -o ${OUT} -L --max-redirs ${MAX_REDIRECTS} ${URL2} -tar --strip-components=1 -xzf $OUT +tar --strip-components=1 -xzf ${OUT} -./Configure --prefix=$HOME/openssl $OS_COMPILER -fPIC $OS_FLAGS +if [ -n "${BUILD_LIBRESSL_VERSION}" ]; then + ./configure --prefix=${HOME}/libressl +else + ./Configure --prefix=${HOME}/openssl ${OS_COMPILER} -fPIC ${OS_FLAGS} +fi make -j$(nproc) make install -cp $myname $HOME/openssl/$myname +cp ${myname} ${HOME}/${NAME}/${myname} diff --git a/openssl/test/run.sh b/openssl/test/run.sh index 4d3397a6..b07b8e4b 100755 --- a/openssl/test/run.sh +++ b/openssl/test/run.sh @@ -12,15 +12,21 @@ esac echo Using features: $FEATURES -if [ -d "$HOME/openssl/lib" ]; then - export OPENSSL_DIR=$HOME/openssl - export PATH=$HOME/openssl/bin:$PATH +if [ -n "${BUILD_LIBRESSL_VERSION}" -a -d "$HOME/libressl/lib" ]; then + echo "Testing build libressl-${BUILD_LIBRESSL_VERSION}" + export OPENSSL_DIR=${HOME}/libressl + export PATH="${HOME}/libressl/bin:${PATH}" + +elif [ -n "${BUILD_OPENSSL_VERSION}" -a -d "$HOME/openssl/lib" ]; then + echo "Testing build openssl-${BUILD_LIBRESSL_VERSION}" + export OPENSSL_DIR="${HOME}/openssl" + export PATH="${HOME}/openssl/bin:${PATH}" fi if [ "$TARGET" == "arm-unknown-linux-gnueabihf" ]; then FLAGS="--no-run" fi -cargo run --manifest-path systest/Cargo.toml --target $TARGET +cargo run --manifest-path systest/Cargo.toml --target $TARGET -v exec cargo test --manifest-path openssl/Cargo.toml --target $TARGET \ - --features "$FEATURES" $FLAGS + --features "$FEATURES" -v $FLAGS From 762510a5faf8c38d0aab6b86d19bc0c7c24e8e78 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 23 Dec 2016 13:38:00 -0500 Subject: [PATCH 076/140] Release v0.9.4 --- README.md | 2 +- openssl-sys/Cargo.toml | 4 ++-- openssl-sys/src/lib.rs | 2 +- openssl/Cargo.toml | 6 +++--- openssl/src/lib.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 9a6d41c8..dfa48266 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) -[Documentation](https://docs.rs/openssl/0.9.3/openssl). +[Documentation](https://docs.rs/openssl/0.9.4/openssl). ## Warning diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 7e827ed6..24a16f56 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "openssl-sys" -version = "0.9.3" +version = "0.9.4" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://docs.rs/openssl-sys/0.9.3/openssl_sys" +documentation = "https://docs.rs/openssl-sys/0.9.4/openssl_sys" links = "openssl" build = "build.rs" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index c67c2f2d..9b733402 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code, overflowing_literals)] -#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.3")] +#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.4")] extern crate libc; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 9de27903..e2b89c85 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "openssl" -version = "0.9.3" +version = "0.9.4" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://docs.rs/openssl/0.9.3/openssl" +documentation = "https://docs.rs/openssl/0.9.4/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] build = "build.rs" @@ -20,7 +20,7 @@ v110 = [] bitflags = "0.7" lazy_static = "0.2" libc = "0.2" -openssl-sys = { version = "0.9.3", path = "../openssl-sys" } +openssl-sys = { version = "0.9.4", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 5d881d64..074d468d 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://docs.rs/openssl/0.9.3")] +#![doc(html_root_url="https://docs.rs/openssl/0.9.4")] #[macro_use] extern crate bitflags; From 9ff3ce4687a04ba2e59560583600779f4d10621b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 24 Dec 2016 02:38:51 -0800 Subject: [PATCH 077/140] Use metadeps to specify pkg-config dependencies declaratively This makes it easier for distribution packaging tools to generate appropriate package dependencies. --- openssl-sys/Cargo.toml | 5 ++++- openssl-sys/build.rs | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 24a16f56..b3e672d6 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -14,8 +14,11 @@ build = "build.rs" libc = "0.2" [build-dependencies] -pkg-config = "0.3" +metadeps = "1" [target.'cfg(windows)'.dependencies] user32-sys = "0.2" gdi32-sys = "0.2" + +[package.metadata.pkg-config] +openssl = "1.0.1" diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index ce990be3..b530c2e3 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -1,4 +1,4 @@ -extern crate pkg_config; +extern crate metadeps; use std::collections::HashSet; use std::env; @@ -172,8 +172,8 @@ fn try_pkg_config() { // cflags dirs for showing us lots of `-I`. env::set_var("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS", "1"); - let lib = match pkg_config::find_library("openssl") { - Ok(lib) => lib, + let lib = match metadeps::probe() { + Ok(mut libs) => libs.remove("openssl").unwrap(), Err(_) => return, }; From 5c49b58a88e5e30c695b0f5a5fc6bb267efe8a84 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 31 Dec 2016 09:44:57 -0800 Subject: [PATCH 078/140] Indicate that memcmp::eq should be used for HMACs --- openssl/src/sign.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index ca7986ca..ec37c885 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -35,12 +35,13 @@ //! assert!(verifier.finish(&signature).unwrap()); //! ``` //! -//! Compute an HMAC (note that `Verifier` cannot be used with HMACs): +//! Compute an HMAC: //! //! ```rust -//! use openssl::sign::Signer; -//! use openssl::pkey::PKey; //! 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(); @@ -53,6 +54,12 @@ //! signer.update(data).unwrap(); //! signer.update(data2).unwrap(); //! let hmac = signer.finish().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 ffi; use std::io::{self, Write}; From 444c00955a5622ff694eaefd75f047e7eabbad2a Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Sat, 31 Dec 2016 10:40:56 -0800 Subject: [PATCH 079/140] add EcKey creation from EcPoint, public_key --- openssl/src/ec.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index 607c30e0..94b11e93 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -289,6 +289,38 @@ impl EcKey { } } + /// Constructs an `EcKey` from the specified group with the associated `EcPoint`, public_key. + /// + /// This will only have the associated public_key. + /// + /// # Example + /// + /// ``` + /// use openssl::bn::BigNumContext; + /// use openssl::ec::*; + /// use openssl::nid; + /// use openssl::pkey::PKey; + /// + /// // get bytes from somewhere, i.e. this will not produce a valid key + /// let public_key: Vec = vec![]; + /// + /// // create a PKey from the binary form of a EcPoint + /// EcGroup::from_curve_name(nid::SECP256K1) + /// .and_then(|group| BigNumContext::new().map(|ctx| (group, ctx))) + /// .and_then(|(group, mut ctx)| EcPoint::from_bytes(&group, &public_key, &mut ctx) + /// .map(|point| (group, point) )) + /// .and_then(|(group, point)| EcKey::from_public_key(&group, &point)) + /// .and_then(|ec_key| PKey::from_ec_key(ec_key)); + /// ``` + pub fn from_public_key(group: &EcGroupRef, public_key: &EcPointRef) -> Result { + unsafe { + let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); + try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); + try!(cvt(ffi::EC_KEY_set_public_key(key.as_ptr(), public_key.as_ptr()))); + Ok(key) + } + } + /// Generates a new public/private key pair on the specified curve. pub fn generate(group: &EcGroupRef) -> Result { unsafe { @@ -353,4 +385,19 @@ mod test { public_key.mul_generator(&group, key.private_key().unwrap(), &mut ctx).unwrap(); assert!(public_key.eq(&group, key.public_key().unwrap(), &mut ctx).unwrap()); } + + #[test] + fn key_from_public_key() { + let group = EcGroup::from_curve_name(nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let mut ctx = BigNumContext::new().unwrap(); + let bytes = key.public_key().unwrap().to_bytes(&group, POINT_CONVERSION_COMPRESSED, &mut ctx).unwrap(); + + drop(key); + let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap(); + let ec_key = EcKey::from_public_key(&group, &public_key).unwrap(); + assert!(ec_key.check_key().is_ok()); + assert!(ec_key.public_key().is_some()); + assert!(ec_key.private_key().is_none()); + } } From 85a6e8acca7af3a86ad609de8347af6ef7e17b48 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 09:53:08 -0800 Subject: [PATCH 080/140] Fix doc reference --- openssl/src/pkcs5.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/pkcs5.rs b/openssl/src/pkcs5.rs index 8d6dcce8..9e1c2d26 100644 --- a/openssl/src/pkcs5.rs +++ b/openssl/src/pkcs5.rs @@ -22,7 +22,7 @@ pub struct KeyIvPair { /// v1.5 or PBKDF1 from PKCS#5 v2.0. /// /// New applications should not use this and instead use -/// `pkcs5_pbkdf2_hmac_sha1` or another more modern key derivation algorithm. +/// `pbkdf2_hmac` or another more modern key derivation algorithm. pub fn bytes_to_key(cipher: Cipher, digest: MessageDigest, data: &[u8], From cdabc1b3e3fb57874df1a31e01cf6019433fea9c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 10:07:32 -0800 Subject: [PATCH 081/140] Fix docs --- openssl/src/hash.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index 1d2089ef..47d6dc7a 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -60,7 +60,7 @@ use self::State::*; /// /// # Examples /// -/// Calculate a hash in one go. +/// Calculate a hash in one go: /// /// ``` /// use openssl::hash::{hash, MessageDigest}; @@ -71,7 +71,7 @@ use self::State::*; /// assert_eq!(res, spec); /// ``` /// -/// Use the `Write` trait to supply the input in chunks. +/// Supply the input in chunks: /// /// ``` /// use openssl::hash::{Hasher, MessageDigest}; From 7e75c76bb4c1bbf7b21181aeb7aab919dcee2576 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 10:13:34 -0800 Subject: [PATCH 082/140] Stick tag description on the right function --- openssl/src/symm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index d2cb0cc8..99ee4c67 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -369,6 +369,10 @@ fn cipher(t: Cipher, /// /// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag /// will be copied into the `tag` field. +/// +/// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support +/// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes, +/// for example. pub fn encrypt_aead(t: Cipher, key: &[u8], iv: Option<&[u8]>, @@ -390,10 +394,6 @@ pub fn encrypt_aead(t: Cipher, /// /// Additional Authenticated Data can be provided in the `aad` field, and the authentication tag /// should be provided in the `tag` field. -/// -/// The size of the `tag` buffer indicates the required size of the tag. While some ciphers support -/// a range of tag sizes, it is recommended to pick the maximum size. For AES GCM, this is 16 bytes, -/// for example. pub fn decrypt_aead(t: Cipher, key: &[u8], iv: Option<&[u8]>, From 0e0bee50a59ab65c310122dc6300416eadfea851 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 10:18:43 -0800 Subject: [PATCH 083/140] Clean up bio --- openssl/src/ssl/bio.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index c5152a41..4dc7cbd4 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -68,10 +68,10 @@ pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { } unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { - mem::transmute(compat::BIO_get_data(bio)) + &mut *(compat::BIO_get_data(bio) as *mut _) } -unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { +unsafe extern fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); @@ -93,7 +93,7 @@ unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_ } } -unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { +unsafe extern fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) -> c_int { BIO_clear_retry_flags(bio); let state = state::(bio); @@ -123,11 +123,11 @@ fn retriable_error(err: &io::Error) -> bool { } } -unsafe extern "C" fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { +unsafe extern fn bputs(bio: *mut BIO, s: *const c_char) -> c_int { bwrite::(bio, s, strlen(s) as c_int) } -unsafe extern "C" fn ctrl(bio: *mut BIO, +unsafe extern fn ctrl(bio: *mut BIO, cmd: c_int, _num: c_long, _ptr: *mut c_void) @@ -151,7 +151,7 @@ unsafe extern "C" fn ctrl(bio: *mut BIO, } } -unsafe extern "C" fn create(bio: *mut BIO) -> c_int { +unsafe extern fn create(bio: *mut BIO) -> c_int { compat::BIO_set_init(bio, 0); compat::BIO_set_num(bio, 0); compat::BIO_set_data(bio, ptr::null_mut()); @@ -159,7 +159,7 @@ unsafe extern "C" fn create(bio: *mut BIO) -> c_int { 1 } -unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { +unsafe extern fn destroy(bio: *mut BIO) -> c_int { if bio.is_null() { return 0; } From 0483ea767cf51615e22f7730df31aeca55bca455 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 11:05:54 -0800 Subject: [PATCH 084/140] Little cleanup --- openssl/src/version.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/openssl/src/version.rs b/openssl/src/version.rs index 2604914e..bf47695b 100644 --- a/openssl/src/version.rs +++ b/openssl/src/version.rs @@ -20,11 +20,8 @@ use ffi::{SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, SSLeay_version as OpenSSL_version}; #[cfg(ossl110)] -use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS}; -#[cfg(ossl110)] -use ffi::{OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR}; -#[cfg(ossl110)] -use ffi::{OpenSSL_version_num, OpenSSL_version}; +use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, + OpenSSL_version_num, OpenSSL_version}; /// OPENSSL_VERSION_NUMBER is a numeric release version identifier: /// From f9404947a3260a4c86cdf49d6af366fcfeb292a9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 11:30:31 -0800 Subject: [PATCH 085/140] Some readme tweaks --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index dfa48266..21b5ae60 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,8 @@ for that README. ## Building -rust-openssl depends on the OpenSSL runtime libraries version 1.0.1 or above. -Currently the libraries need to be present in the build environment before this +rust-openssl depends on OpenSSL version 1.0.1 or above, or LibreSSL. Both the +libraries and headers need to be present in the build environment before this crate is compiled, and some instructions of how to do this are in the sections below. @@ -49,14 +49,17 @@ make install ### OSX Although OpenSSL 0.9.8 is preinstalled on OSX this library is being phased out -of OSX and this crate also does not support this version of OpenSSL. To use this +of OSX and this crate also does not support that version of OpenSSL. To use this crate on OSX you'll need to install OpenSSL via some alternate means, typically -homebrew: +Homebrew: ```bash brew install openssl ``` +If Homebrew is installed to the default location of `/usr/local`, OpenSSL will be +automatically detected. + ### Windows MSVC On MSVC it's unfortunately not always a trivial process acquiring OpenSSL. From cfb2539ed45fd11cec1af850256078ec494d8987 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 2 Jan 2017 09:37:31 -0800 Subject: [PATCH 086/140] Typo --- openssl/src/ssl/connector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index cc5c5273..43dad17d 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -379,7 +379,7 @@ mod verify { // the same thing we do here. // // The Public Suffix (https://www.publicsuffix.org/) list could - // potentically be used here, but it's both huge and updated frequently + // 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; From d9e3d6ea213e558c46565c2e4958e5dc989dd1ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Tue, 3 Jan 2017 11:56:32 +0100 Subject: [PATCH 087/140] Improving missing OpenSSL message on Linux --- openssl-sys/build.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index b530c2e3..c59a76d4 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -184,9 +184,20 @@ Used pkg-config to discover the OpenSSL installation, but pkg-config did not return any include paths for the installation. This crate needs to take a peek at the header files so it cannot proceed unless they're found. -You can try fixing this by setting the `OPENSSL_DIR` environment variable -pointing to your OpenSSL installation. +You can try fixing this setting the `OPENSSL_DIR` environment variable +pointing to your OpenSSL installation or installing OpenSSL headers package +specific to your distribution: + # On Ubuntu + sudo apt-get install libssl-dev + # On Arch Linux + sudo pacman -S openssl + # On Fedora + sudo dnf install openssl-devel + +See rust-openssl README for more information: + + https://github.com/sfackler/rust-openssl#linux "); } From 1767cd5464c18c37730eddeba6f74dc5721c7bf1 Mon Sep 17 00:00:00 2001 From: Philipp Keck Date: Tue, 3 Jan 2017 14:48:46 +0100 Subject: [PATCH 088/140] Pointer from PKey docs to sign module. Could even add a link, but I don't know how. Someone who wants to use OpenSSL to compute an HMAC won't find a "hmac" module and won't find HMACs in the "hash" module. Unless the person knows that HMACs are used to "sign" messages (the usual term in this context would be "authenticate"), they will probably use the search function and look for "hmac", then they'll find this method. So it's helpful to include a pointer to the right API to use. Without such a pointer, the API user is left with a seemingly useless Pkey instance. Similar pointers could be helpful from the other creator methods in this file. And/or from the top-level documentation or the hash documentation towards the sign module. Another idea would be a trivial `hmac` module with a few helper functions that internally just use Pkey. If many users who just want a simple HMAC value can use that API, there are fewer dependencies on `Pkey` and `sign`, which is probably a good thing. --- openssl/src/pkey.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 7f031244..6973154f 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -117,6 +117,7 @@ impl PKey { } /// Creates a new `PKey` containing an HMAC key. + /// Note: To compute HMAC values, use the `sign` module. pub fn hmac(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize); From e2f1569500b8d66f6a1f69923676df816430a27d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Jan 2017 12:35:52 -0800 Subject: [PATCH 089/140] Tweak layout a little bit --- openssl/src/pkey.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 6973154f..7a32692b 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -117,7 +117,9 @@ impl PKey { } /// Creates a new `PKey` containing an HMAC key. - /// Note: To compute HMAC values, use the `sign` module. + /// + /// # Note + /// To compute HMAC values, use the `sign` module. pub fn hmac(key: &[u8]) -> Result { unsafe { assert!(key.len() <= c_int::max_value() as usize); From 6291407b177dfb8bee0b50974cad57c98da110f8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Jan 2017 14:56:00 -0800 Subject: [PATCH 090/140] Add X509::stack_from_pem Implementation is a clone of SSL_CTX_use_certificate_chain_file --- openssl-sys/src/lib.rs | 5 +++++ openssl/src/x509/mod.rs | 30 +++++++++++++++++++++++++++++ openssl/src/x509/tests.rs | 14 +++++++++++++- openssl/test/certs.pem | 40 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 openssl/test/certs.pem diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 9b733402..80cfc47e 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -126,6 +126,9 @@ pub const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08; pub const CRYPTO_LOCK: c_int = 1; +pub const ERR_LIB_PEM: c_int = 9; +pub const PEM_R_NO_START_LINE: c_int = 108; + pub const EVP_MAX_MD_SIZE: c_uint = 64; pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; pub const EVP_PKEY_HMAC: c_int = NID_hmac; @@ -1429,10 +1432,12 @@ extern { pub fn EC_POINT_cmp(group: *const EC_GROUP, a: *const EC_POINT, b: *const EC_POINT, ctx: *mut BN_CTX) -> c_int; pub fn EC_POINT_free(point: *mut EC_POINT); + pub fn ERR_peek_last_error() -> c_ulong; pub fn ERR_get_error() -> c_ulong; pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char; + pub fn ERR_clear_error(); pub fn EVP_md5() -> *const EVP_MD; pub fn EVP_ripemd160() -> *const EVP_MD; diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 68652f8e..d90cee22 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -433,6 +433,36 @@ impl ToOwned for X509Ref { impl X509 { from_pem!(X509, ffi::PEM_read_bio_X509); from_der!(X509, ffi::d2i_X509); + + /// Deserializes a list of PEM-formatted certificates. + pub fn stack_from_pem(pem: &[u8]) -> Result, ErrorStack> { + unsafe { + ffi::init(); + let bio = try!(MemBioSlice::new(pem)); + + let mut certs = vec![]; + loop { + let r = ffi::PEM_read_bio_X509(bio.as_ptr(), + ptr::null_mut(), + None, + ptr::null_mut()); + if r.is_null() { + let err = ffi::ERR_peek_last_error(); + if ffi::ERR_GET_LIB(err) == ffi::ERR_LIB_PEM + && ffi::ERR_GET_REASON(err) == ffi::PEM_R_NO_START_LINE { + ffi::ERR_clear_error(); + break; + } + + return Err(ErrorStack::get()); + } else { + certs.push(X509(r)); + } + } + + Ok(certs) + } + } } impl Clone for X509 { diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 16ad661d..0843b19f 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1,4 +1,4 @@ -use hex::FromHex; +use hex::{FromHex, ToHex}; use hash::MessageDigest; use pkey::PKey; @@ -174,3 +174,15 @@ fn test_subject_alt_name_iter() { Some(&b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01"[..])); assert!(subject_alt_names_iter.next().is_none()); } + +#[test] +fn test_stack_from_pem() { + let certs = include_bytes!("../../test/certs.pem"); + let certs = X509::stack_from_pem(certs).unwrap(); + + assert_eq!(certs.len(), 2); + assert_eq!(certs[0].fingerprint(MessageDigest::sha1()).unwrap().to_hex(), + "59172d9313e84459bcff27f967e79e6e9217e584"); + assert_eq!(certs[1].fingerprint(MessageDigest::sha1()).unwrap().to_hex(), + "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"); +} diff --git a/openssl/test/certs.pem b/openssl/test/certs.pem new file mode 100644 index 00000000..9d351662 --- /dev/null +++ b/openssl/test/certs.pem @@ -0,0 +1,40 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB +VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 +cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG +A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 +IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub +3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ +mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 +TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI +ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y +euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq +hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM +6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE +wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY +oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 +dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp +HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIJAOIvDiVb18eVMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTYwODE0MTY1NjExWhcNMjYwODEyMTY1NjExWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEArVHWFn52Lbl1l59exduZntVSZyDYpzDND+S2LUcO6fRBWhV/1Kzox+2G +ZptbuMGmfI3iAnb0CFT4uC3kBkQQlXonGATSVyaFTFR+jq/lc0SP+9Bd7SBXieIV +eIXlY1TvlwIvj3Ntw9zX+scTA4SXxH6M0rKv9gTOub2vCMSHeF16X8DQr4XsZuQr +7Cp7j1I4aqOJyap5JTl5ijmG8cnu0n+8UcRlBzy99dLWJG0AfI3VRJdWpGTNVZ92 +aFff3RpK3F/WI2gp3qV1ynRAKuvmncGC3LDvYfcc2dgsc1N6Ffq8GIrkgRob6eBc +klDHp1d023Lwre+VaVDSo1//Y72UFwIDAQABo1AwTjAdBgNVHQ4EFgQUbNOlA6sN +XyzJjYqciKeId7g3/ZowHwYDVR0jBBgwFoAUbNOlA6sNXyzJjYqciKeId7g3/Zow +DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAVVaR5QWLZIRR4Dw6TSBn +BQiLpBSXN6oAxdDw6n4PtwW6CzydaA+creiK6LfwEsiifUfQe9f+T+TBSpdIYtMv +Z2H2tjlFX8VrjUFvPrvn5c28CuLI0foBgY8XGSkR2YMYzWw2jPEq3Th/KM5Catn3 +AFm3bGKWMtGPR4v+90chEN0jzaAmJYRrVUh9vea27bOCn31Nse6XXQPmSI6Gyncy +OAPUsvPClF3IjeL1tmBotWqSGn1cYxLo+Lwjk22A9h6vjcNQRyZF2VLVvtwYrNU3 +mwJ6GCLsLHpwW/yjyvn8iEltnJvByM/eeRnfXV6WDObyiZsE/n6DxIRJodQzFqy9 +GA== +-----END CERTIFICATE----- From dbd6134fd66ef5947013c185f3fa44d8ee8e288e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Jan 2017 15:33:45 -0800 Subject: [PATCH 091/140] Clean up EcKey example a bit --- openssl/src/ec.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index 94b11e93..592c4026 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -295,7 +295,7 @@ impl EcKey { /// /// # Example /// - /// ``` + /// ```no_run /// use openssl::bn::BigNumContext; /// use openssl::ec::*; /// use openssl::nid; @@ -304,13 +304,11 @@ impl EcKey { /// // get bytes from somewhere, i.e. this will not produce a valid key /// let public_key: Vec = vec![]; /// - /// // create a PKey from the binary form of a EcPoint - /// EcGroup::from_curve_name(nid::SECP256K1) - /// .and_then(|group| BigNumContext::new().map(|ctx| (group, ctx))) - /// .and_then(|(group, mut ctx)| EcPoint::from_bytes(&group, &public_key, &mut ctx) - /// .map(|point| (group, point) )) - /// .and_then(|(group, point)| EcKey::from_public_key(&group, &point)) - /// .and_then(|ec_key| PKey::from_ec_key(ec_key)); + /// // create an EcKey from the binary form of a EcPoint + /// let group = EcGroup::from_curve_name(nid::SECP256K1).unwrap(); + /// let mut ctx = BigNumContext::new().unwrap(); + /// let point = EcPoint::from_bytes(&group, &public_key, &mut ctx).unwrap(); + /// let key = EcKey::from_public_key(&group, &point); /// ``` pub fn from_public_key(group: &EcGroupRef, public_key: &EcPointRef) -> Result { unsafe { From cdf388e3f44b49a5ea4255b9674d8e1ded2ba472 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Jan 2017 16:09:24 -0800 Subject: [PATCH 092/140] Release v0.9.5 --- README.md | 2 +- openssl-sys/Cargo.toml | 4 ++-- openssl-sys/src/lib.rs | 2 +- openssl/Cargo.toml | 6 +++--- openssl/src/lib.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 21b5ae60..3a5b266b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/sfackler/rust-openssl.svg?branch=master)](https://travis-ci.org/sfackler/rust-openssl) -[Documentation](https://docs.rs/openssl/0.9.4/openssl). +[Documentation](https://docs.rs/openssl). ## Warning diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index b3e672d6..d4ed5bfb 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "openssl-sys" -version = "0.9.4" +version = "0.9.5" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://docs.rs/openssl-sys/0.9.4/openssl_sys" +documentation = "https://docs.rs/openssl-sys/0.9.5/openssl_sys" links = "openssl" build = "build.rs" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 80cfc47e..22af7c96 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code, overflowing_literals)] -#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.4")] +#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.5")] extern crate libc; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index e2b89c85..950fca9b 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "openssl" -version = "0.9.4" +version = "0.9.5" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://docs.rs/openssl/0.9.4/openssl" +documentation = "https://docs.rs/openssl/0.9.5/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] build = "build.rs" @@ -20,7 +20,7 @@ v110 = [] bitflags = "0.7" lazy_static = "0.2" libc = "0.2" -openssl-sys = { version = "0.9.4", path = "../openssl-sys" } +openssl-sys = { version = "0.9.5", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 074d468d..8b773ff6 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://docs.rs/openssl/0.9.4")] +#![doc(html_root_url="https://docs.rs/openssl/0.9.5")] #[macro_use] extern crate bitflags; From 336175990cb3584b85385a093b2d1e245ffdb1f1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 20:54:53 -0800 Subject: [PATCH 093/140] Add SSL_SESSION --- openssl-sys/src/libressl.rs | 36 +++++++++++++++++++++ openssl-sys/src/ossl10x.rs | 63 +++++++++++++++++++++++++++++++++++-- openssl-sys/src/ossl110.rs | 1 + 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index 0f20713e..83c5aee6 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -358,6 +358,38 @@ pub struct SSL_CTX { srtp_profiles: *mut c_void, } +#[repr(C)] +pub struct SSL_SESSION { + ssl_version: c_int, + master_key_length: c_int, + master_key: [c_uchar; SSL_MAX_MASTER_KEY_LENGTH as usize], + session_id_length: c_uint, + session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + not_resumable: c_int, + sess_cert: *mut c_void, + peer: *mut X509, + verify_result: c_long, + timeout: c_long, + time: time_t, + references: c_int, + cipher: *const c_void, + cipher_id: c_ulong, + ciphers: *mut c_void, + ex_data: ::CRYPTO_EX_DATA, + prev: *mut c_void, + next: *mut c_void, + tlsext_hostname: *mut c_char, + tlsext_ecpointformatlist_length: size_t, + tlsext_ecpointformatlist: *mut u8, + tlsext_ellipticcurvelist_length: size_t, + tlsext_ellipticcurvelist: *mut u16, + tlsext_tick: *mut c_uchar, + tlsext_ticklen: size_t, + tlsext_tick_lifetime_hint: c_long, +} + #[repr(C)] pub struct X509_VERIFY_PARAM { pub name: *mut c_char, @@ -393,6 +425,10 @@ pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; pub const SSL_OP_NO_SSLv2: c_ulong = 0x0; +pub const SSL_MAX_SSL_SESSION_ID_LENGTH: c_int = 32; +pub const SSL_MAX_SID_CTX_LENGTH: c_int = 32; +pub const SSL_MAX_MASTER_KEY_LENGTH: c_int = 48; + pub const SSLEAY_VERSION : c_int = 0; pub const SSLEAY_CFLAGS : c_int = 2; pub const SSLEAY_BUILT_ON : c_int = 3; diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 4f418f14..5b0ca3d5 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -2,9 +2,7 @@ use std::sync::{Mutex, MutexGuard}; use std::sync::{Once, ONCE_INIT}; use std::mem; -use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; -#[cfg(not(ossl101))] -use libc::time_t; +use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong, time_t}; #[repr(C)] pub struct stack_st_ASN1_OBJECT { @@ -417,6 +415,59 @@ pub struct SSL_CTX { tlsext_ellipticcurvelist: *mut c_uchar, } +#[repr(C)] +pub struct SSL_SESSION { + ssl_version: c_int, + key_arg_length: c_uint, + key_arg: [c_uchar; SSL_MAX_KEY_ARG_LENGTH as usize], + master_key_length: c_uint, + master_key: [c_uchar; SSL_MAX_MASTER_KEY_LENGTH as usize], + session_id_length: c_uint, + session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; SSL_MAX_SID_CTX_LENGTH as usize], + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + krb5_client_princ_len: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + krb5_client_princ: [c_uchar; SSL_MAX_KRB5_PRINCIPAL_LENGTH], + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity_hint: *mut c_char, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_identity: *mut c_char, + not_resumable: c_int, + sess_cert: *mut c_void, + peer: *mut X509, + verify_result: c_long, + references: c_int, + timeout: c_long, + time: time_t, + compress_meth: c_uint, + cipher: *const c_void, + cipher_id: c_ulong, + ciphers: *mut c_void, + ex_data: ::CRYPTO_EX_DATA, + prev: *mut c_void, + next: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hostname: *mut c_char, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] + tlsext_ellipticcurvelist: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticklen: size_t, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_tick_lifetime_hint: c_long, + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_username: *mut c_char, +} + #[repr(C)] pub struct SRP_CTX { SRP_cb_arg: *mut c_void, @@ -470,6 +521,12 @@ pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; pub const SSL_OP_NO_SSLv2: c_ulong = 0x01000000; +pub const SSL_MAX_SSL_SESSION_ID_LENGTH: c_int = 32; +pub const SSL_MAX_SID_CTX_LENGTH: c_int = 32; +pub const SSL_MAX_KEY_ARG_LENGTH: c_int = 8; +pub const SSL_MAX_MASTER_KEY_LENGTH: c_int = 48; +pub const SSL_MAX_KRB5_PRINCIPAL_LENGTH: c_int = 256; + pub const SSLEAY_VERSION : c_int = 0; pub const SSLEAY_CFLAGS : c_int = 2; pub const SSLEAY_BUILT_ON : c_int = 3; diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index bb4fa19b..9a5d287b 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -13,6 +13,7 @@ pub enum HMAC_CTX {} pub enum OPENSSL_STACK {} pub enum RSA {} pub enum SSL_CTX {} +pub enum SSL_SESSION {} pub enum stack_st_ASN1_OBJECT {} pub enum stack_st_GENERAL_NAME {} pub enum stack_st_OPENSSL_STRING {} From 1ffe57429885f935c10301e7838fa9871c35c95b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 20:57:50 -0800 Subject: [PATCH 094/140] Add SSL_SESSION functions --- openssl-sys/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 22af7c96..a8ac9ba1 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1748,6 +1748,9 @@ extern { inbuf: *const c_uchar, inlen: c_uint, client: *const c_uchar, client_len: c_uint) -> c_int; pub fn SSL_get0_next_proto_negotiated(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); + pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; + + pub fn SSL_SESSION_free(s: *mut SSL_SESSION); #[cfg(not(ossl101))] pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; From 88a7032f4b78895eaeeb72d3837dd698e571e882 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 20:59:46 -0800 Subject: [PATCH 095/140] Types and accessor for SslSession --- openssl/src/ssl/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 3eead8f2..d1ed55fe 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1334,6 +1334,11 @@ impl SslRef { pub fn verify_result(&self) -> Option { unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr())) } } + + /// Returns the SSL session. + pub fn session(&self) -> &SslSessionRef { + unsafe { SslSessionRef::from_ptr(ffi::SSL_get_session(self.as_ptr())) } + } } unsafe impl Sync for Ssl {} @@ -1345,6 +1350,8 @@ impl fmt::Debug for Ssl { } } +type_!(SslSession, SslSessionRef, ffi::SSL_SESSION, ffi::SSL_SESSION_free); + impl Ssl { pub fn new(ctx: &SslContext) -> Result { unsafe { From 5d53405597f2e8dc3a6543e8c4a56705b0ecd47a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:07:51 -0800 Subject: [PATCH 096/140] Provide access to the session ID --- openssl-sys/src/lib.rs | 1 + openssl/src/ssl/mod.rs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index a8ac9ba1..0ea0e5d8 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1751,6 +1751,7 @@ extern { pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; pub fn SSL_SESSION_free(s: *mut SSL_SESSION); + pub fn SSL_SESSION_get_id(s: *const SSL_SESSION, len: *mut c_uint) -> *const c_uchar; #[cfg(not(ossl101))] pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index d1ed55fe..3949210d 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1029,6 +1029,19 @@ impl SslCipherRef { } } +type_!(SslSession, SslSessionRef, ffi::SSL_SESSION, ffi::SSL_SESSION_free); + +impl SslSessionRef { + /// Returns the SSL session ID. + pub fn id(&self) -> &[u8] { + unsafe { + let mut len = 0; + let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len); + slice::from_raw_parts(p as *const u8, len as usize) + } + } +} + type_!(Ssl, SslRef, ffi::SSL, ffi::SSL_free); impl fmt::Debug for SslRef { @@ -1350,8 +1363,6 @@ impl fmt::Debug for Ssl { } } -type_!(SslSession, SslSessionRef, ffi::SSL_SESSION, ffi::SSL_SESSION_free); - impl Ssl { pub fn new(ctx: &SslContext) -> Result { unsafe { From 0b1bfee46d6c986d6cb073c922045ae98b598900 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:15:09 -0800 Subject: [PATCH 097/140] session is nullable --- openssl/src/ssl/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 3949210d..ce9d65ef 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1349,8 +1349,15 @@ impl SslRef { } /// Returns the SSL session. - pub fn session(&self) -> &SslSessionRef { - unsafe { SslSessionRef::from_ptr(ffi::SSL_get_session(self.as_ptr())) } + pub fn session(&self) -> Option<&SslSessionRef> { + unsafe { + let p = ffi::SSL_get_session(self.as_ptr()); + if p.is_null() { + None + } else { + Some(SslSessionRef::from_ptr(p)) + } + } } } From a2c118bf82ac4fbb13d5dd32b931490862ccd930 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:18:13 -0800 Subject: [PATCH 098/140] Add basic session tests --- openssl/src/ssl/tests/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index e685d658..744b2688 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1372,6 +1372,22 @@ fn tmp_ecdh_callback_ssl() { assert!(CALLED_BACK.load(Ordering::SeqCst)); } +#[test] +fn idle_session() { + let ctx = SslContext::builder(SslMethod::tls()).unwrap().build(); + let ssl = Ssl::new(&ctx).unwrap(); + assert!(ssl.session().is_none()); +} + +#[test] +fn active_session() { + let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build(); + + let s = TcpStream::connect("google.com:443").unwrap(); + let socket = connector.connect("google.com", s).unwrap(); + assert!(socket.ssl().session().is_some()); +} + fn _check_kinds() { fn is_send() {} fn is_sync() {} From 404e0341d82d5aab58daaa48b864eaf1a281d101 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:33:47 -0800 Subject: [PATCH 099/140] Provide master key access --- openssl-sys/src/libressl.rs | 4 ++-- openssl-sys/src/ossl10x.rs | 6 +++--- openssl-sys/src/ossl110.rs | 6 +++++- openssl/src/ssl/mod.rs | 28 +++++++++++++++++++++++++++- openssl/src/ssl/tests/mod.rs | 10 +++++++++- 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index 83c5aee6..2c747ffe 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -361,8 +361,8 @@ pub struct SSL_CTX { #[repr(C)] pub struct SSL_SESSION { ssl_version: c_int, - master_key_length: c_int, - master_key: [c_uchar; SSL_MAX_MASTER_KEY_LENGTH as usize], + pub master_key_length: c_int, + pub master_key: [c_uchar; 48], session_id_length: c_uint, session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], sid_ctx_length: c_uint, diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 5b0ca3d5..4d37d2a1 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -420,8 +420,8 @@ pub struct SSL_SESSION { ssl_version: c_int, key_arg_length: c_uint, key_arg: [c_uchar; SSL_MAX_KEY_ARG_LENGTH as usize], - master_key_length: c_uint, - master_key: [c_uchar; SSL_MAX_MASTER_KEY_LENGTH as usize], + pub master_key_length: c_int, + pub master_key: [c_uchar; 48], session_id_length: c_uint, session_id: [c_uchar; SSL_MAX_SSL_SESSION_ID_LENGTH as usize], sid_ctx_length: c_uint, @@ -429,7 +429,7 @@ pub struct SSL_SESSION { #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] krb5_client_princ_len: c_uint, #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] - krb5_client_princ: [c_uchar; SSL_MAX_KRB5_PRINCIPAL_LENGTH], + krb5_client_princ: [c_uchar; SSL_MAX_KRB5_PRINCIPAL_LENGTH as usize], #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] psk_identity_hint: *mut c_char, #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index 9a5d287b..898ad4a2 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_void, c_char, c_uchar, c_ulong, c_long, c_uint}; +use libc::{c_int, c_void, c_char, c_uchar, c_ulong, c_long, c_uint, size_t}; pub enum BIGNUM {} pub enum BIO {} @@ -156,6 +156,10 @@ extern { -> c_int; pub fn X509_up_ref(x: *mut X509) -> c_int; pub fn SSL_CTX_up_ref(x: *mut SSL_CTX) -> c_int; + pub fn SSL_SESSION_get_master_key(session: *const SSL_SESSION, + out: *mut c_uchar, + outlen: size_t) + -> size_t; pub fn X509_get0_extensions(req: *const ::X509) -> *const stack_st_X509_EXTENSION; pub fn X509_STORE_CTX_get0_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; pub fn EVP_MD_CTX_new() -> *mut EVP_MD_CTX; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index ce9d65ef..6d49f2b1 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -1040,6 +1040,18 @@ impl SslSessionRef { slice::from_raw_parts(p as *const u8, len as usize) } } + + /// Returns the length of the master key. + pub fn master_key_len(&self) -> usize { + unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } + } + + /// Copies the master key into the provided buffer. + /// + /// Returns the number of bytes written. + pub fn master_key(&self, buf: &mut [u8]) -> usize { + unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } + } } type_!(Ssl, SslRef, ffi::SSL, ffi::SSL_free); @@ -1728,6 +1740,7 @@ mod compat { pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options}; pub use ffi::{SSL_CTX_clear_options, SSL_CTX_up_ref}; + pub use ffi::SSL_SESSION_get_master_key; pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { ffi::CRYPTO_get_ex_new_index(ffi::CRYPTO_EX_INDEX_SSL_CTX, @@ -1762,7 +1775,7 @@ mod compat { use std::ptr; use ffi; - use libc::{self, c_long, c_ulong, c_int}; + use libc::{self, c_long, c_ulong, c_int, size_t, c_uchar}; pub unsafe fn SSL_CTX_get_options(ctx: *const ffi::SSL_CTX) -> c_ulong { ffi::SSL_CTX_ctrl(ctx as *mut _, ffi::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong @@ -1799,6 +1812,19 @@ mod compat { 0 } + pub unsafe fn SSL_SESSION_get_master_key(session: *const ffi::SSL_SESSION, + out: *mut c_uchar, + mut outlen: size_t) -> size_t { + if outlen == 0 { + return (*session).master_key_length as size_t; + } + if outlen > (*session).master_key_length as size_t { + outlen = (*session).master_key_length as size_t; + } + ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); + outlen + } + pub fn tls_method() -> *const ffi::SSL_METHOD { unsafe { ffi::SSLv23_method() } } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 744b2688..14bb2f71 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -1385,7 +1385,15 @@ fn active_session() { let s = TcpStream::connect("google.com:443").unwrap(); let socket = connector.connect("google.com", s).unwrap(); - assert!(socket.ssl().session().is_some()); + let session = socket.ssl().session().unwrap(); + let len = session.master_key_len(); + let mut buf = vec![0; len - 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, buf.len()); + let mut buf = vec![0; len + 1]; + let copied = session.master_key(&mut buf); + assert_eq!(copied, len); + } fn _check_kinds() { From c6ea4f3e2a8b6159d4772ee5274001cff7caff2f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 22:34:50 -0800 Subject: [PATCH 100/140] Fix time type --- openssl-sys/src/ossl10x.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 4d37d2a1..037298c1 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -2,7 +2,9 @@ use std::sync::{Mutex, MutexGuard}; use std::sync::{Once, ONCE_INIT}; use std::mem; -use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong, time_t}; +use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong}; +#[cfg(not(ossl101))] +use libc::time_t; #[repr(C)] pub struct stack_st_ASN1_OBJECT { @@ -440,7 +442,7 @@ pub struct SSL_SESSION { verify_result: c_long, references: c_int, timeout: c_long, - time: time_t, + time: c_long, compress_meth: c_uint, cipher: *const c_void, cipher_id: c_ulong, From 524e8e3c5a59dd8ca6290c2fe7e338d8a7587a25 Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Thu, 5 Jan 2017 16:15:25 +0100 Subject: [PATCH 101/140] libressl: mark unavailable flags as such These flags are not available in libressl (at least for version 2.4.4 which is the last stable version) Signed-off-by: Marc-Antoine Perennou --- openssl-sys/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 22af7c96..23fa032b 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1206,15 +1206,15 @@ pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; pub const X509_V_OK: c_int = 0; -#[cfg(not(ossl101))] +#[cfg(not(any(ossl101, libressl)))] pub const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT: c_uint = 0x1; -#[cfg(not(ossl101))] +#[cfg(not(any(ossl101, libressl)))] pub const X509_CHECK_FLAG_NO_WILDCARDS: c_uint = 0x2; -#[cfg(not(ossl101))] +#[cfg(not(any(ossl101, libressl)))] pub const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4; -#[cfg(not(ossl101))] +#[cfg(not(any(ossl101, libressl)))] pub const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS: c_uint = 0x8; -#[cfg(not(ossl101))] +#[cfg(not(any(ossl101, libressl)))] pub const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS: c_uint = 0x10; pub const GEN_OTHERNAME: c_int = 0; From 0978f870956ff06dee2e7dcbb6a30c6cbfce6e1e Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Thu, 5 Jan 2017 16:15:53 +0100 Subject: [PATCH 102/140] libressl: make set_ecdh_auto available Signed-off-by: Marc-Antoine Perennou --- openssl/src/ssl/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 3eead8f2..722225e7 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -774,12 +774,12 @@ impl SslContextBuilder { /// curve. /// /// Requires the `v102` feature and OpenSSL 1.0.2. - #[cfg(all(feature = "v102", ossl102))] + #[cfg(all(feature = "v102", any(ossl102, libressl)))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { self._set_ecdh_auto(onoff) } - #[cfg(ossl102)] + #[cfg(any(ossl102,libressl))] fn _set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } } From 192c08cdee0e856f41380b754ebb7b5284b5e700 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 7 Jan 2017 13:13:53 -0800 Subject: [PATCH 103/140] Adjust minimum pkg-config version Closes #551 --- openssl-sys/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index d4ed5bfb..6c55a83a 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -21,4 +21,4 @@ user32-sys = "0.2" gdi32-sys = "0.2" [package.metadata.pkg-config] -openssl = "1.0.1" +openssl = "1.0.0" # We actually need 1.0.1, but OpenBSD reports as 1.0.0 From 1942977408a6483770332f316fc012e06ad757b9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 8 Jan 2017 10:57:04 -0800 Subject: [PATCH 104/140] Add methods to construct SslAcceptorBuilder without key and cert This will allow, in particular, initialization directly from files rather than having to load and parse them manually. --- openssl/src/ssl/connector.rs | 56 ++++++++++++++++++++++-------------- openssl/src/ssl/mod.rs | 27 ++++++++++------- 2 files changed, 51 insertions(+), 32 deletions(-) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 43dad17d..458eace0 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -136,6 +136,30 @@ impl SslAcceptorBuilder { where I: IntoIterator, I::Item: AsRef { + let builder = try!(SslAcceptorBuilder::mozilla_intermedia_raw(method)); + builder.finish_setup(private_key, certificate, chain) + } + + /// Creates a new builder configured to connect to modern clients. + /// + /// This corresponds to the modern configuration 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_modern(method: SslMethod, + private_key: &PKeyRef, + certificate: &X509Ref, + chain: I) + -> Result + where I: IntoIterator, + I::Item: AsRef + { + let builder = try!(SslAcceptorBuilder::mozilla_modern_raw(method)); + builder.finish_setup(private_key, certificate, chain) + } + + /// Like `mozilla_intermediate`, but does not load the certificate chain and private key. + pub fn mozilla_intermedia_raw(method: SslMethod) -> Result { let mut ctx = try!(ctx(method)); let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes())); try!(ctx.set_tmp_dh(&dh)); @@ -154,23 +178,11 @@ impl SslAcceptorBuilder { EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:\ AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:\ DES-CBC3-SHA:!DSS")); - SslAcceptorBuilder::finish_setup(ctx, private_key, certificate, chain) + Ok(SslAcceptorBuilder(ctx)) } - /// Creates a new builder configured to connect to modern clients. - /// - /// This corresponds to the modern configuration 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_modern(method: SslMethod, - private_key: &PKeyRef, - certificate: &X509Ref, - chain: I) - -> Result - where I: IntoIterator, - I::Item: AsRef - { + /// Like `mozilla_modern`, but does not load the certificate chain and private key. + pub fn mozilla_modern_raw(method: SslMethod) -> Result { let mut ctx = try!(ctx(method)); try!(setup_curves(&mut ctx)); try!(ctx.set_cipher_list("ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:\ @@ -178,10 +190,10 @@ impl SslAcceptorBuilder { 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")); - SslAcceptorBuilder::finish_setup(ctx, private_key, certificate, chain) + Ok(SslAcceptorBuilder(ctx)) } - fn finish_setup(mut ctx: SslContextBuilder, + fn finish_setup(mut self, private_key: &PKeyRef, certificate: &X509Ref, chain: I) @@ -189,13 +201,13 @@ impl SslAcceptorBuilder { where I: IntoIterator, I::Item: AsRef { - try!(ctx.set_private_key(private_key)); - try!(ctx.set_certificate(certificate)); - try!(ctx.check_private_key()); + try!(self.0.set_private_key(private_key)); + try!(self.0.set_certificate(certificate)); + try!(self.0.check_private_key()); for cert in chain { - try!(ctx.add_extra_chain_cert(cert.as_ref().to_owned())); + try!(self.0.add_extra_chain_cert(cert.as_ref().to_owned())); } - Ok(SslAcceptorBuilder(ctx)) + Ok(self) } /// Returns a shared reference to the inner `SslContextBuilder`. diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 6d49f2b1..f412ca93 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -702,7 +702,7 @@ impl SslContextBuilder { } } - /// Specifies the file that contains certificate + /// Loads a certificate from a file. pub fn set_certificate_file>(&mut self, file: P, file_type: X509FileType) @@ -716,7 +716,11 @@ impl SslContextBuilder { } } - /// Specifies the file that contains certificate chain + /// Loads a certificate chain from a file. + /// + /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf + /// certificate, and the remainder forming the chain of certificates up to and including the + /// trusted root certificate. pub fn set_certificate_chain_file>(&mut self, file: P) -> Result<(), ErrorStack> { @@ -727,13 +731,15 @@ impl SslContextBuilder { } } - /// Specifies the certificate + /// Sets the certificate. pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } - /// Adds a certificate to the certificate chain presented together with the - /// certificate specified using set_certificate() + /// Appends a certificate to the certificate chain. + /// + /// This chain should contain all certificates necessary to go from the certificate specified by + /// `set_certificate` to a trusted root. pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { unsafe { try!(cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)); @@ -742,7 +748,7 @@ impl SslContextBuilder { } } - /// Specifies the file that contains private key + /// Loads the private key from a file. pub fn set_private_key_file>(&mut self, file: P, file_type: X509FileType) @@ -756,11 +762,14 @@ impl SslContextBuilder { } } - /// Specifies the private key + /// Sets the private key. pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) } } + /// Sets the cipher configuration. + /// + /// See `man 1 ciphers` for details on the format. pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { let cipher_list = CString::new(cipher_list).unwrap(); unsafe { @@ -769,9 +778,7 @@ impl SslContextBuilder { } } - /// If `onoff` is set to `true`, enable ECDHE for key exchange with - /// compatible clients, and automatically select an appropriate elliptic - /// curve. + /// Enables ECDHE key exchange with an automatically chosen curve list. /// /// Requires the `v102` feature and OpenSSL 1.0.2. #[cfg(all(feature = "v102", ossl102))] From 1fbe8f8d71b2559d901c6cc1f5a1a754634a966d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 8 Jan 2017 11:04:47 -0800 Subject: [PATCH 105/140] Fix typo --- openssl/src/ssl/connector.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 458eace0..73d7b675 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -136,7 +136,7 @@ impl SslAcceptorBuilder { where I: IntoIterator, I::Item: AsRef { - let builder = try!(SslAcceptorBuilder::mozilla_intermedia_raw(method)); + let builder = try!(SslAcceptorBuilder::mozilla_intermediate_raw(method)); builder.finish_setup(private_key, certificate, chain) } @@ -159,7 +159,7 @@ impl SslAcceptorBuilder { } /// Like `mozilla_intermediate`, but does not load the certificate chain and private key. - pub fn mozilla_intermedia_raw(method: SslMethod) -> Result { + pub fn mozilla_intermediate_raw(method: SslMethod) -> Result { let mut ctx = try!(ctx(method)); let dh = try!(Dh::from_pem(DHPARAM_PEM.as_bytes())); try!(ctx.set_tmp_dh(&dh)); From 9942643ab6fbdecb0561fcdc08565d4f154865b3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 9 Jan 2017 20:50:26 -0800 Subject: [PATCH 106/140] Release v0.9.6 --- openssl-sys/Cargo.toml | 4 ++-- openssl-sys/src/lib.rs | 2 +- openssl/Cargo.toml | 6 +++--- openssl/src/lib.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 6c55a83a..3ce84e30 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,12 +1,12 @@ [package] name = "openssl-sys" -version = "0.9.5" +version = "0.9.6" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://docs.rs/openssl-sys/0.9.5/openssl_sys" +documentation = "https://docs.rs/openssl-sys/0.9.6/openssl_sys" links = "openssl" build = "build.rs" diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0ea0e5d8..df6d1d14 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code, overflowing_literals)] -#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.5")] +#![doc(html_root_url="https://docs.rs/openssl-sys/0.9.6")] extern crate libc; diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 950fca9b..a4baa79d 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "openssl" -version = "0.9.5" +version = "0.9.6" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" repository = "https://github.com/sfackler/rust-openssl" -documentation = "https://docs.rs/openssl/0.9.5/openssl" +documentation = "https://docs.rs/openssl/0.9.6/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] build = "build.rs" @@ -20,7 +20,7 @@ v110 = [] bitflags = "0.7" lazy_static = "0.2" libc = "0.2" -openssl-sys = { version = "0.9.5", path = "../openssl-sys" } +openssl-sys = { version = "0.9.6", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 8b773ff6..dc1d794f 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url="https://docs.rs/openssl/0.9.5")] +#![doc(html_root_url="https://docs.rs/openssl/0.9.6")] #[macro_use] extern crate bitflags; From 920ab0d6fb60c17077f43d7f08ad3ff391201689 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 13 Jan 2017 19:38:12 -0800 Subject: [PATCH 107/140] OCSP functionality --- openssl-sys/src/lib.rs | 125 ++++++++++++++-- openssl-sys/src/libressl.rs | 107 ++++++++++++++ openssl-sys/src/ossl10x.rs | 150 +++++++++++++++++++ openssl-sys/src/ossl110.rs | 5 + openssl/src/asn1.rs | 20 ++- openssl/src/bn.rs | 14 +- openssl/src/crypto.rs | 60 +------- openssl/src/lib.rs | 6 +- openssl/src/ocsp.rs | 274 +++++++++++++++++++++++++++++++++++ openssl/src/ssl/mod.rs | 144 +++++++++++++++++- openssl/src/ssl/tests/mod.rs | 45 +++++- openssl/src/string.rs | 74 ++++++++++ openssl/src/x509/mod.rs | 20 +++ openssl/src/x509/store.rs | 35 ++++- openssl/src/x509/tests.rs | 13 +- systest/build.rs | 5 +- 16 files changed, 1007 insertions(+), 90 deletions(-) create mode 100644 openssl/src/ocsp.rs create mode 100644 openssl/src/string.rs diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index df6d1d14..0cbd0da7 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -6,6 +6,7 @@ extern crate libc; use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t, FILE}; use std::ptr; +use std::mem; #[cfg(any(ossl101, ossl102))] mod ossl10x; @@ -23,6 +24,7 @@ mod libressl; pub use libressl::*; pub enum ASN1_INTEGER {} +pub enum ASN1_GENERALIZEDTIME {} pub enum ASN1_STRING {} pub enum ASN1_TIME {} pub enum ASN1_TYPE {} @@ -38,7 +40,11 @@ pub enum ENGINE {} pub enum EVP_CIPHER_CTX {} pub enum EVP_MD {} pub enum EVP_PKEY_CTX {} -pub enum SSL {} +pub enum OCSP_BASICRESP {} +pub enum OCSP_CERTID {} +pub enum OCSP_RESPONSE {} +pub enum OCSP_REQUEST {} +pub enum OCSP_ONEREQ {} pub enum SSL_CIPHER {} pub enum SSL_METHOD {} pub enum X509_CRL {} @@ -51,20 +57,17 @@ pub enum X509_STORE_CTX {} pub enum bio_st {} pub enum PKCS12 {} pub enum DH_METHOD {} - -pub type bio_info_cb = Option; - pub enum RSA_METHOD {} pub enum BN_MONT_CTX {} pub enum BN_BLINDING {} pub enum DSA_METHOD {} pub enum EVP_PKEY_ASN1_METHOD {} +pub type bio_info_cb = Option; +pub type GEN_SESSION_CB = Option c_int>; +pub type tls_session_ticket_ext_cb_fn = Option c_int>; +pub type tls_session_secret_cb_fn = Option c_int>; + #[repr(C)] #[derive(Copy, Clone)] pub enum point_conversion_form_t { @@ -1059,6 +1062,40 @@ pub const NID_aes_128_cbc_hmac_sha1: c_int = 916; pub const NID_aes_192_cbc_hmac_sha1: c_int = 917; pub const NID_aes_256_cbc_hmac_sha1: c_int = 918; +pub const OCSP_NOCERTS: c_ulong = 0x1; +pub const OCSP_NOINTERN: c_ulong = 0x2; +pub const OCSP_NOSIGS: c_ulong = 0x4; +pub const OCSP_NOCHAIN: c_ulong = 0x8; +pub const OCSP_NOVERIFY: c_ulong = 0x10; +pub const OCSP_NOEXPLICIT: c_ulong = 0x20; +pub const OCSP_NOCASIGN: c_ulong = 0x40; +pub const OCSP_NODELEGATED: c_ulong = 0x80; +pub const OCSP_NOCHECKS: c_ulong = 0x100; +pub const OCSP_TRUSTOTHER: c_ulong = 0x200; +pub const OCSP_RESPID_KEY: c_ulong = 0x400; +pub const OCSP_NOTIME: c_ulong = 0x800; + +pub const V_OCSP_CERTSTATUS_GOOD: c_int = 0; +pub const V_OCSP_CERTSTATUS_REVOKED: c_int = 1; +pub const V_OCSP_CERTSTATUS_UNKNOWN: c_int = 2; + +pub const OCSP_REVOKED_STATUS_NOSTATUS: c_int = -1; +pub const OCSP_REVOKED_STATUS_UNSPECIFIED: c_int = 0; +pub const OCSP_REVOKED_STATUS_KEYCOMPROMISE: c_int = 1; +pub const OCSP_REVOKED_STATUS_CACOMPROMISE: c_int = 2; +pub const OCSP_REVOKED_STATUS_AFFILIATIONCHANGED: c_int = 3; +pub const OCSP_REVOKED_STATUS_SUPERSEDED: c_int = 4; +pub const OCSP_REVOKED_STATUS_CESSATIONOFOPERATION: c_int = 5; +pub const OCSP_REVOKED_STATUS_CERTIFICATEHOLD: c_int = 6; +pub const OCSP_REVOKED_STATUS_REMOVEFROMCRL: c_int = 8; + +pub const OCSP_RESPONSE_STATUS_SUCCESSFUL: c_int = 0; +pub const OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: c_int = 1; +pub const OCSP_RESPONSE_STATUS_INTERNALERROR: c_int = 2; +pub const OCSP_RESPONSE_STATUS_TRYLATER: c_int = 3; +pub const OCSP_RESPONSE_STATUS_SIGREQUIRED: c_int = 5; +pub const OCSP_RESPONSE_STATUS_UNAUTHORIZED: c_int = 6; + pub const PKCS5_SALT_LEN: c_int = 8; pub const RSA_F4: c_long = 0x10001; @@ -1077,6 +1114,12 @@ pub const SSL_CTRL_SET_READ_AHEAD: c_int = 41; pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53; pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54; pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB: c_int = 63; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG: c_int = 64; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE: c_int = 65; +pub const SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 70; +pub const SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP: c_int = 71; +pub const SSL_CTRL_GET_EXTRA_CHAIN_CERTS: c_int = 82; pub const SSL_MODE_ENABLE_PARTIAL_WRITE: c_long = 0x1; pub const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER: c_long = 0x2; @@ -1136,6 +1179,8 @@ pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | pub const TLSEXT_NAMETYPE_host_name: c_int = 0; +pub const TLSEXT_STATUSTYPE_ocsp: c_int = 1; + pub const SSL_TLSEXT_ERR_OK: c_int = 0; pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1; pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2; @@ -1273,7 +1318,7 @@ pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) - } pub unsafe fn SSL_CTX_set_tlsext_servername_callback(ctx: *mut SSL_CTX, - cb: Option) + cb: Option) -> c_long { SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, cb) } @@ -1284,6 +1329,32 @@ pub unsafe fn SSL_set_tlsext_host_name(s: *mut SSL, name: *mut c_char) -> c_long name as *mut c_void) } +pub unsafe fn SSL_set_tlsext_status_type(s: *mut SSL, type_: c_int) -> c_long { + SSL_ctrl(s, SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE, type_ as c_long, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_set_tlsext_status_cb(ctx: *mut SSL_CTX, + cb: Option c_int>) + -> c_long { + SSL_CTX_callback_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB, mem::transmute(cb)) +} + +pub unsafe fn SSL_CTX_set_tlsext_status_arg(ctx: *mut SSL_CTX, arg: *mut c_void) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB_ARG, 0, arg) +} + +pub unsafe fn SSL_CTX_get_extra_chain_certs(ctx: *mut SSL_CTX, chain: *mut *mut stack_st_X509) -> c_long { + SSL_CTX_ctrl(ctx, SSL_CTRL_GET_EXTRA_CHAIN_CERTS, 0, chain as *mut c_void) +} + +pub unsafe fn SSL_get_tlsext_status_ocsp_resp(ssl: *mut SSL, resp: *mut *mut c_uchar) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_GET_TLSEXT_STATUS_REQ_OCSP_RESP, 0, resp as *mut c_void) +} + +pub unsafe fn SSL_set_tlsext_status_ocsp_resp(ssl: *mut SSL, resp: *mut c_uchar, len: c_long) -> c_long { + SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP, len, resp as *mut c_void) +} + pub fn ERR_GET_LIB(l: c_ulong) -> c_int { ((l >> 24) & 0x0FF) as c_int } @@ -1298,6 +1369,8 @@ pub fn ERR_GET_REASON(l: c_ulong) -> c_int { extern { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; + pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); + pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); pub fn ASN1_TIME_print(b: *mut BIO, tm: *const ASN1_TIME) -> c_int; @@ -1541,6 +1614,30 @@ extern { pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int; + pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP; + pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP); + pub fn OCSP_basic_verify(bs: *mut OCSP_BASICRESP, certs: *mut stack_st_X509, st: *mut X509_STORE, flags: c_ulong) -> c_int; + pub fn OCSP_resp_find_status(bs: *mut OCSP_BASICRESP, id: *mut OCSP_CERTID, status: *mut c_int, reason: *mut c_int, revtime: *mut *mut ASN1_GENERALIZEDTIME, thisupd: *mut *mut ASN1_GENERALIZEDTIME, nextupd: *mut *mut ASN1_GENERALIZEDTIME) -> c_int; + pub fn OCSP_check_validity(thisupd: *mut ASN1_GENERALIZEDTIME, nextupd: *mut ASN1_GENERALIZEDTIME, sec: c_long, maxsec: c_long) -> c_int; + + pub fn OCSP_CERTID_free(id: *mut OCSP_CERTID); + + pub fn OCSP_RESPONSE_new() -> *mut OCSP_RESPONSE; + pub fn OCSP_RESPONSE_free(r: *mut OCSP_RESPONSE); + pub fn i2d_OCSP_RESPONSE(a: *mut OCSP_RESPONSE, pp: *mut *mut c_uchar) -> c_int; + pub fn d2i_OCSP_RESPONSE(a: *mut *mut OCSP_RESPONSE, pp: *mut *const c_uchar, length: c_long) -> *mut OCSP_RESPONSE; + pub fn OCSP_response_create(status: c_int, bs: *mut OCSP_BASICRESP) -> *mut OCSP_RESPONSE; + pub fn OCSP_response_status(resp: *mut OCSP_RESPONSE) -> c_int; + pub fn OCSP_response_get1_basic(resp: *mut OCSP_RESPONSE) -> *mut OCSP_BASICRESP; + + pub fn OCSP_REQUEST_new() -> *mut OCSP_REQUEST; + pub fn OCSP_REQUEST_free(r: *mut OCSP_REQUEST); + pub fn i2d_OCSP_REQUEST(a: *mut OCSP_REQUEST, pp: *mut *mut c_uchar) -> c_int; + pub fn d2i_OCSP_REQUEST(a: *mut *mut OCSP_REQUEST, pp: *mut *const c_uchar, length: c_long) -> *mut OCSP_REQUEST; + pub fn OCSP_request_add0_id(r: *mut OCSP_REQUEST, id: *mut OCSP_CERTID) -> *mut OCSP_ONEREQ; + + pub fn OCSP_ONEREQ_free(r: *mut OCSP_ONEREQ); + pub fn PEM_read_bio_DHparams(bio: *mut BIO, out: *mut *mut DH, callback: Option, user_data: *mut c_void) -> *mut DH; pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option, @@ -1696,7 +1793,7 @@ extern { pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; pub fn SSL_CTX_free(ctx: *mut SSL_CTX); pub fn SSL_CTX_ctrl(ctx: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; - pub fn SSL_CTX_callback_ctrl(ctx: *mut SSL_CTX, cmd: c_int, fp: Option) -> c_long; + pub fn SSL_CTX_callback_ctrl(ctx: *mut SSL_CTX, cmd: c_int, fp: Option) -> c_long; pub fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int, verify_callback: Option c_int>); pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int); @@ -1749,6 +1846,8 @@ extern { client: *const c_uchar, client_len: c_uint) -> c_int; pub fn SSL_get0_next_proto_negotiated(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; + #[cfg(not(any(ossl101, libressl)))] + pub fn SSL_is_server(s: *mut SSL) -> c_int; pub fn SSL_SESSION_free(s: *mut SSL_SESSION); pub fn SSL_SESSION_get_id(s: *const SSL_SESSION, len: *mut c_uint) -> *const c_uchar; @@ -1785,6 +1884,8 @@ extern { 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_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_check_issued(issuer: *mut X509, subject: *mut X509) -> c_int; pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); @@ -1797,8 +1898,10 @@ extern { pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + pub fn X509_STORE_new() -> *mut X509_STORE; pub fn X509_STORE_free(store: *mut X509_STORE); 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_CTX_free(ctx: *mut X509_STORE_CTX); pub fn X509_STORE_CTX_get_current_cert(ctx: *mut X509_STORE_CTX) -> *mut X509; diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index 2c747ffe..c1411e60 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -40,6 +40,16 @@ pub struct stack_st_void { pub stack: _STACK, } +#[repr(C)] +pub struct stack_st_SSL_CIPHER { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_OPENSSL_STRING { + pub stack: _STACK, +} + #[repr(C)] pub struct _STACK { pub num: c_int, @@ -288,6 +298,100 @@ pub struct X509_VAL { pub notAfter: *mut ::ASN1_TIME, } +#[repr(C)] +pub struct SSL { + version: c_int, + type_: c_int, + method: *const ::SSL_METHOD, + rbio: *mut c_void, + wbio: *mut c_void, + bbio: *mut c_void, + rwstate: c_int, + in_handshake: c_int, + handshake_func: Option c_int>, + pub server: c_int, + new_session: c_int, + quiet_shutdown: c_int, + shutdown: c_int, + state: c_int, + rstate: c_int, + init_buf: *mut c_void, + init_msg: *mut c_void, + init_num: c_int, + init_off: c_int, + packet: *mut c_uchar, + packet_length: c_uint, + s3: *mut c_void, + d1: *mut c_void, + read_ahead: c_int, + msg_callback: Option, + msg_callback_arg: *mut c_void, + hit: c_int, + param: *mut c_void, + cipher_list: *mut stack_st_SSL_CIPHER, + cipher_list_by_id: *mut stack_st_SSL_CIPHER, + mac_flags: c_int, + aead_read_ctx: *mut c_void, + enc_read_ctx: *mut ::EVP_CIPHER_CTX, + read_hash: *mut ::EVP_MD_CTX, + aead_write_ctx: *mut c_void, + enc_write_ctx: *mut ::EVP_CIPHER_CTX, + write_hash: *mut ::EVP_MD_CTX, + cert: *mut c_void, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut ::SSL_SESSION, + generate_session_id: ::GEN_SESSION_CB, + verify_mode: c_int, + verify_callback: Option c_int>, + info_callback: Option, + error: c_int, + error_code: c_int, + ctx: *mut ::SSL_CTX, + debug: c_int, + verify_result: c_long, + ex_data: ::CRYPTO_EX_DATA, + client_CA: *mut stack_st_X509_NAME, + references: c_int, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + first_packet: c_int, + client_version: c_int, + max_send_fragment: c_uint, + tlsext_debug_cb: Option, + tlsext_debug_arg: *mut c_void, + tlsext_hostname: *mut c_char, + servername_done: c_int, + tlsext_status_type: c_int, + tlsext_status_expected: c_int, + tlsext_ocsp_ids: *mut c_void, + tlsext_ocsp_exts: *mut c_void, + tlsext_ocsp_resp: *mut c_uchar, + tlsext_ocsp_resplen: c_int, + tlsext_ticket_expected: c_int, + tlsext_ecpointformatlist_length: size_t, + tlsext_ecpointformatlist: *mut c_uchar, + tlsext_ellipticcurvelist_length: size_t, + tlsext_ellipticcurvelist: *mut c_uchar, + tlsext_session_ticket: *mut c_void, + tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn, + tls_session_ticket_ext_cb_arg: *mut c_void, + tls_session_secret_cb: ::tls_session_secret_cb_fn, + tls_session_secret_cb_arg: *mut c_void, + initial_ctx: *mut ::SSL_CTX, + next_proto_negotiated: *mut c_uchar, + next_proto_negotiated_len: c_uchar, + srtp_profiles: *mut c_void, + srtp_profile: *mut c_void, + tlsext_heartbeat: c_uint, + tlsext_hb_pending: c_uint, + tlsext_hb_seq: c_uint, + alpn_client_proto_list: *mut c_uchar, + alpn_client_proto_list_len: c_uint, + renegotiate: c_int, +} + #[repr(C)] pub struct SSL_CTX { method: *mut c_void, @@ -515,6 +619,7 @@ extern { pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn CRYPTO_malloc(num: c_int, file: *const c_char, line: c_int) -> *mut c_void; pub fn CRYPTO_free(buf: *mut c_void); pub fn CRYPTO_num_locks() -> c_int; pub fn CRYPTO_set_locking_callback(func: unsafe extern "C" fn(mode: c_int, @@ -530,6 +635,8 @@ extern { cb: Option, cbarg: *mut c_void) -> *mut RSA; + pub fn OCSP_cert_to_id(dgst: *const ::EVP_MD, subject: *mut ::X509, issuer: *mut ::X509) -> *mut ::OCSP_CERTID; + pub fn SSL_library_init() -> c_int; pub fn SSL_load_error_strings(); pub fn OPENSSL_add_all_algorithms_noconf(); diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 037298c1..f721daaa 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -41,6 +41,16 @@ pub struct stack_st_void { pub stack: _STACK, } +#[repr(C)] +pub struct stack_st_SSL_CIPHER { + pub stack: _STACK, +} + +#[repr(C)] +pub struct stack_st_OPENSSL_STRING { + pub stack: _STACK, +} + #[repr(C)] pub struct _STACK { pub num: c_int, @@ -295,6 +305,143 @@ pub struct X509_VAL { pub notAfter: *mut ::ASN1_TIME, } +#[repr(C)] +pub struct SSL { + version: c_int, + type_: c_int, + method: *const ::SSL_METHOD, + rbio: *mut c_void, + wbio: *mut c_void, + bbio: *mut c_void, + rwstate: c_int, + in_handshake: c_int, + handshake_func: Option c_int>, + pub server: c_int, + new_session: c_int, + quiet_session: c_int, + shutdown: c_int, + state: c_int, + rstate: c_int, + init_buf: *mut c_void, + init_msg: *mut c_void, + init_num: c_int, + init_off: c_int, + packet: *mut c_uchar, + packet_length: c_uint, + s2: *mut c_void, + s3: *mut c_void, + d1: *mut c_void, + read_ahead: c_int, + msg_callback: Option, + msg_callback_arg: *mut c_void, + hit: c_int, + param: *mut c_void, + cipher_list: *mut stack_st_SSL_CIPHER, + cipher_list_by_id: *mut stack_st_SSL_CIPHER, + mac_flags: c_int, + enc_read_ctx: *mut ::EVP_CIPHER_CTX, + read_hash: *mut ::EVP_MD_CTX, + expand: *mut c_void, + enc_write_ctx: *mut ::EVP_CIPHER_CTX, + write_hash: *mut ::EVP_MD_CTX, + compress: *mut c_void, + cert: *mut c_void, + sid_ctx_length: c_uint, + sid_ctx: [c_uchar; ::SSL_MAX_SID_CTX_LENGTH as usize], + session: *mut ::SSL_SESSION, + generate_session_id: ::GEN_SESSION_CB, + verify_mode: c_int, + verify_callback: Option c_int>, + info_callback: Option, + error: c_int, + error_code: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_KRB5"))] + kssl_ctx: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_client_callback: Option c_uint>, + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] + psk_server_callback: Option c_uint>, + ctx: *mut ::SSL_CTX, + debug: c_int, + verify_result: c_long, + ex_data: ::CRYPTO_EX_DATA, + client_CA: *mut stack_st_X509_NAME, + references: c_int, + options: c_ulong, + mode: c_ulong, + max_cert_list: c_long, + first_packet: c_int, + client_version: c_int, + max_send_fragment: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_debug_cb: Option, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_debug_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hostname: *mut c_char, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + servername_done: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_type: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_status_expected: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_ids: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_exts: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_resp: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ocsp_resplen: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_ticket_expected: c_int, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] + tlsext_ecpointformatlist_length: size_t, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] + tlsext_ecpointformatlist: *mut c_uchar, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] + tlsext_ellipticcurvelist_length: size_t, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_EC")))] + tlsext_ellipticcurvelist: *mut c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_opaque_prf_input_len: size_t, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_session_ticket: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_session_ticket_ext_cb: ::tls_session_ticket_ext_cb_fn, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_ticket_ext_cb_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_secret_cb: ::tls_session_secret_cb_fn, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tls_session_secret_cb_arg: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + initial_ctx: *mut ::SSL_CTX, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_proto_negotiated: *mut c_uchar, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), not(osslconf = "OPENSSL_NO_NEXTPROTONEG")))] + next_proto_negotiated_len: c_uchar, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + srtp_profiles: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + srtp_profile: *mut c_void, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_heartbeat: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hb_pending: c_uint, + #[cfg(not(osslconf = "OPENSSL_NO_TLSEXT"))] + tlsext_hb_seq: c_uint, + renegotiate: c_int, + #[cfg(not(osslconf = "OPENSSL_NO_SRP"))] + srp_ctx: ::SRP_CTX, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list: *mut c_uchar, + #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] + alpn_client_proto_list_len: c_uint, +} + #[repr(C)] pub struct SSL_CTX { method: *mut c_void, @@ -617,6 +764,7 @@ extern { pub fn get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; pub fn get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn CRYPTO_malloc(num: c_int, file: *const c_char, line: c_int) -> *mut c_void; pub fn CRYPTO_free(buf: *mut c_void); pub fn CRYPTO_num_locks() -> c_int; pub fn CRYPTO_set_locking_callback(func: unsafe extern "C" fn(mode: c_int, @@ -632,6 +780,8 @@ extern { cb: Option, cbarg: *mut c_void) -> *mut RSA; + pub fn OCSP_cert_to_id(dgst: *const ::EVP_MD, subject: *mut ::X509, issuer: *mut ::X509) -> *mut ::OCSP_CERTID; + pub fn SSL_library_init() -> c_int; pub fn SSL_load_error_strings(); pub fn OPENSSL_add_all_algorithms_noconf(); diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index 898ad4a2..925b0d8a 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -12,6 +12,7 @@ pub enum EVP_PKEY {} pub enum HMAC_CTX {} pub enum OPENSSL_STACK {} pub enum RSA {} +pub enum SSL {} pub enum SSL_CTX {} pub enum SSL_SESSION {} pub enum stack_st_ASN1_OBJECT {} @@ -22,6 +23,7 @@ pub enum stack_st_X509 {} pub enum stack_st_X509_NAME {} pub enum stack_st_X509_ATTRIBUTE {} pub enum stack_st_X509_EXTENSION {} +pub enum stack_st_SSL_CIPHER {} pub enum X509 {} pub enum X509_VERIFY_PARAM {} @@ -63,11 +65,14 @@ extern { pub fn BN_get_rfc3526_prime_6144(bn: *mut BIGNUM) -> *mut BIGNUM; pub fn BN_get_rfc3526_prime_8192(bn: *mut BIGNUM) -> *mut BIGNUM; + pub fn CRYPTO_malloc(num: size_t, file: *const c_char, line: c_int) -> *mut c_void; pub fn CRYPTO_free(buf: *mut c_void, file: *const c_char, line: c_int); pub fn HMAC_CTX_new() -> *mut HMAC_CTX; pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX); + pub fn OCSP_cert_to_id(dgst: *const ::EVP_MD, subject: *const ::X509, issuer: *const ::X509) -> *mut ::OCSP_CERTID; + pub fn TLS_method() -> *const ::SSL_METHOD; pub fn DTLS_method() -> *const ::SSL_METHOD; pub fn SSL_CIPHER_get_version(cipher: *const ::SSL_CIPHER) -> *const c_char; diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index c0a23591..d177885e 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -1,5 +1,5 @@ use ffi; -use libc::c_long; +use libc::{c_long, c_char}; use std::fmt; use std::ptr; use std::slice; @@ -7,9 +7,21 @@ use std::str; use {cvt, cvt_p}; use bio::MemBio; -use crypto::CryptoString; use error::ErrorStack; use types::{OpenSslType, OpenSslTypeRef}; +use string::OpensslString; + +type_!(Asn1GeneralizedTime, Asn1GeneralizedTimeRef, ffi::ASN1_GENERALIZEDTIME, ffi::ASN1_GENERALIZEDTIME_free); + +impl fmt::Display for Asn1GeneralizedTimeRef { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + unsafe { + let mem_bio = try!(MemBio::new()); + try!(cvt(ffi::ASN1_GENERALIZEDTIME_print(mem_bio.as_ptr(), self.as_ptr()))); + write!(f, "{}", str::from_utf8_unchecked(mem_bio.get_buf())) + } + } +} type_!(Asn1Time, Asn1TimeRef, ffi::ASN1_TIME, ffi::ASN1_TIME_free); @@ -42,7 +54,7 @@ impl Asn1Time { type_!(Asn1String, Asn1StringRef, ffi::ASN1_STRING, ffi::ASN1_STRING_free); impl Asn1StringRef { - pub fn as_utf8(&self) -> Result { + pub fn as_utf8(&self) -> Result { unsafe { let mut ptr = ptr::null_mut(); let len = ffi::ASN1_STRING_to_UTF8(&mut ptr, self.as_ptr()); @@ -50,7 +62,7 @@ impl Asn1StringRef { return Err(ErrorStack::get()); } - Ok(CryptoString::from_raw_parts(ptr, len as usize)) + Ok(OpensslString::from_ptr(ptr as *mut c_char)) } } diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index a8bb9619..01c0b428 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -6,8 +6,8 @@ use std::{fmt, ptr}; use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref}; use {cvt, cvt_p, cvt_n}; -use crypto::CryptoString; use error::ErrorStack; +use string::OpensslString; use types::{OpenSslType, OpenSslTypeRef}; #[cfg(ossl10x)] @@ -484,12 +484,12 @@ impl BigNumRef { /// # use openssl::bn::BigNum; /// let s = -BigNum::from_u32(12345).unwrap(); /// - /// assert_eq!(&*s.to_dec_str().unwrap(), "-12345"); + /// assert_eq!(&**s.to_dec_str().unwrap(), "-12345"); /// ``` - pub fn to_dec_str(&self) -> Result { + pub fn to_dec_str(&self) -> Result { unsafe { let buf = try!(cvt_p(ffi::BN_bn2dec(self.as_ptr()))); - Ok(CryptoString::from_null_terminated(buf)) + Ok(OpensslString::from_ptr(buf)) } } @@ -499,12 +499,12 @@ impl BigNumRef { /// # use openssl::bn::BigNum; /// let s = -BigNum::from_u32(0x99ff).unwrap(); /// - /// assert_eq!(&*s.to_hex_str().unwrap(), "-99FF"); + /// assert_eq!(&**s.to_hex_str().unwrap(), "-99FF"); /// ``` - pub fn to_hex_str(&self) -> Result { + pub fn to_hex_str(&self) -> Result { unsafe { let buf = try!(cvt_p(ffi::BN_bn2hex(self.as_ptr()))); - Ok(CryptoString::from_null_terminated(buf)) + Ok(OpensslString::from_ptr(buf)) } } } diff --git a/openssl/src/crypto.rs b/openssl/src/crypto.rs index ce83cbae..49029318 100644 --- a/openssl/src/crypto.rs +++ b/openssl/src/crypto.rs @@ -1,59 +1,5 @@ -use libc::{c_char, c_int, c_void}; -use std::fmt; -use std::ffi::CStr; -use std::slice; -use std::ops::Deref; -use std::str; +use string::OpensslString; -pub struct CryptoString(&'static str); +#[deprecated(note = "renamed to OpensslString", since = "0.9.7")] +pub type CryptoString = OpensslString; -impl Drop for CryptoString { - fn drop(&mut self) { - unsafe { - CRYPTO_free(self.0.as_ptr() as *mut c_void, - concat!(file!(), "\0").as_ptr() as *const c_char, - line!() as c_int); - } - } -} - -impl Deref for CryptoString { - type Target = str; - - fn deref(&self) -> &str { - self.0 - } -} - -impl CryptoString { - pub unsafe fn from_raw_parts(buf: *mut u8, len: usize) -> CryptoString { - let slice = slice::from_raw_parts(buf, len); - CryptoString(str::from_utf8_unchecked(slice)) - } - - pub unsafe fn from_null_terminated(buf: *mut c_char) -> CryptoString { - let slice = CStr::from_ptr(buf).to_bytes(); - CryptoString(str::from_utf8_unchecked(slice)) - } -} - -impl fmt::Display for CryptoString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(self.0, f) - } -} - -impl fmt::Debug for CryptoString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self.0, f) - } -} - -#[cfg(not(ossl110))] -#[allow(non_snake_case)] -unsafe fn CRYPTO_free(buf: *mut c_void, _: *const c_char, _: c_int) { - ::ffi::CRYPTO_free(buf); -} - -#[cfg(ossl110)] -use ffi::CRYPTO_free; diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index dc1d794f..9138896b 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -35,18 +35,20 @@ pub mod error; pub mod hash; pub mod memcmp; pub mod nid; +pub mod ocsp; pub mod pkcs12; pub mod pkcs5; pub mod pkey; pub mod rand; -pub mod types; pub mod rsa; pub mod sign; pub mod ssl; +pub mod stack; +pub mod string; pub mod symm; +pub mod types; pub mod version; pub mod x509; -pub mod stack; #[cfg(any(ossl102, ossl110))] mod verify; diff --git a/openssl/src/ocsp.rs b/openssl/src/ocsp.rs new file mode 100644 index 00000000..bba5c561 --- /dev/null +++ b/openssl/src/ocsp.rs @@ -0,0 +1,274 @@ +use ffi; +use libc::{c_int, c_long, c_ulong}; +use std::ptr; +use std::mem; + +use {cvt, cvt_p}; +use asn1::Asn1GeneralizedTimeRef; +use error::ErrorStack; +use hash::MessageDigest; +use stack::StackRef; +use types::OpenSslTypeRef; +use x509::store::X509StoreRef; +use x509::{X509, X509Ref}; + +bitflags! { + pub flags Flag: c_ulong { + const FLAG_NO_CERTS = ffi::OCSP_NOCERTS, + const FLAG_NO_INTERN = ffi::OCSP_NOINTERN, + const FLAG_NO_CHAIN = ffi::OCSP_NOCHAIN, + const FLAG_NO_VERIFY = ffi::OCSP_NOVERIFY, + const FLAG_NO_EXPLICIT = ffi::OCSP_NOEXPLICIT, + const FLAG_NO_CA_SIGN = ffi::OCSP_NOCASIGN, + const FLAG_NO_DELEGATED = ffi::OCSP_NODELEGATED, + const FLAG_NO_CHECKS = ffi::OCSP_NOCHECKS, + const FLAG_TRUST_OTHER = ffi::OCSP_TRUSTOTHER, + const FLAG_RESPID_KEY = ffi::OCSP_RESPID_KEY, + const FLAG_NO_TIME = ffi::OCSP_NOTIME, + } +} + +pub const RESPONSE_STATUS_SUCCESSFUL: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SUCCESSFUL); +pub const RESPONSE_STATUS_MALFORMED_REQUEST: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_MALFORMEDREQUEST); +pub const RESPONSE_STATUS_INTERNAL_ERROR: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_INTERNALERROR); +pub const RESPONSE_STATUS_TRY_LATER: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_TRYLATER); +pub const RESPONSE_STATUS_SIG_REQUIRED: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_SIGREQUIRED); +pub const RESPONSE_STATUS_UNAUTHORIZED: OcspResponseStatus = + OcspResponseStatus(ffi::OCSP_RESPONSE_STATUS_UNAUTHORIZED); + +pub const CERT_STATUS_GOOD: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_GOOD); +pub const CERT_STATUS_REVOKED: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_REVOKED); +pub const CERT_STATUS_UNKNOWN: OcspCertStatus = OcspCertStatus(ffi::V_OCSP_CERTSTATUS_UNKNOWN); + +pub const REVOKED_STATUS_NO_STATUS: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_NOSTATUS); +pub const REVOKED_STATUS_UNSPECIFIED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_UNSPECIFIED); +pub const REVOKED_STATUS_KEY_COMPROMISE: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_KEYCOMPROMISE); +pub const REVOKED_STATUS_CA_COMPROMISE: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CACOMPROMISE); +pub const REVOKED_STATUS_AFFILIATION_CHANGED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_AFFILIATIONCHANGED); +pub const REVOKED_STATUS_SUPERSEDED: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_SUPERSEDED); +pub const REVOKED_STATUS_CESSATION_OF_OPERATION: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CESSATIONOFOPERATION); +pub const REVOKED_STATUS_CERTIFICATE_HOLD: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_CERTIFICATEHOLD); +pub const REVOKED_STATUS_REMOVE_FROM_CRL: OcspRevokedStatus = + OcspRevokedStatus(ffi::OCSP_REVOKED_STATUS_REMOVEFROMCRL); + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct OcspResponseStatus(c_int); + +impl OcspResponseStatus { + pub fn from_raw(raw: c_int) -> OcspResponseStatus { + OcspResponseStatus(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct OcspCertStatus(c_int); + +impl OcspCertStatus { + pub fn from_raw(raw: c_int) -> OcspCertStatus { + OcspCertStatus(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct OcspRevokedStatus(c_int); + +impl OcspRevokedStatus { + pub fn from_raw(raw: c_int) -> OcspRevokedStatus { + OcspRevokedStatus(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } +} + +pub struct Status<'a> { + /// The overall status of the response. + pub status: OcspCertStatus, + /// If `status` is `CERT_STATUS_REVOKED`, the reason for the revocation. + pub reason: OcspRevokedStatus, + /// If `status` is `CERT_STATUS_REVOKED`, the time at which the certificate was revoked. + pub revocation_time: Option<&'a Asn1GeneralizedTimeRef>, + /// The time that this revocation check was performed. + pub this_update: &'a Asn1GeneralizedTimeRef, + /// The time at which this revocation check expires. + pub next_update: &'a Asn1GeneralizedTimeRef, +} + +impl<'a> Status<'a> { + /// Checks validity of the `this_update` and `next_update` fields. + /// + /// The `nsec` parameter specifies an amount of slack time that will be used when comparing + /// those times with the current time to account for delays and clock skew. + /// + /// The `maxsec` parameter limits the maximum age of the `this_update` parameter to prohibit + /// very old responses. + pub fn check_validity(&self, nsec: u32, maxsec: Option) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::OCSP_check_validity(self.this_update.as_ptr(), + self.next_update.as_ptr(), + nsec as c_long, + maxsec.map(|n| n as c_long).unwrap_or(-1))) + .map(|_| ()) + } + } +} + +type_!(OcspBasicResponse, OcspBasicResponseRef, ffi::OCSP_BASICRESP, ffi::OCSP_BASICRESP_free); + +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 to not include this in the response. + pub fn verify(&self, + certs: &StackRef, + store: &X509StoreRef, + flags: Flag) + -> 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. + pub fn find_status<'a>(&'a self, id: &OcspCertIdRef) -> Option> { + unsafe { + let mut status = ffi::V_OCSP_CERTSTATUS_UNKNOWN; + let mut reason = ffi::OCSP_REVOKED_STATUS_NOSTATUS; + let mut revocation_time = ptr::null_mut(); + let mut this_update = ptr::null_mut(); + let mut next_update = ptr::null_mut(); + + let r = ffi::OCSP_resp_find_status(self.as_ptr(), + id.as_ptr(), + &mut status, + &mut reason, + &mut revocation_time, + &mut this_update, + &mut next_update); + if r == 1 { + let revocation_time = if revocation_time.is_null() { + None + } else { + Some(Asn1GeneralizedTimeRef::from_ptr(revocation_time)) + }; + Some(Status { + status: OcspCertStatus(status), + reason: OcspRevokedStatus(status), + revocation_time: revocation_time, + this_update: Asn1GeneralizedTimeRef::from_ptr(this_update), + next_update: Asn1GeneralizedTimeRef::from_ptr(next_update), + }) + } else { + None + } + } + } +} + +type_!(OcspCertId, OcspCertIdRef, ffi::OCSP_CERTID, ffi::OCSP_CERTID_free); + +impl OcspCertId { + /// Constructs a certificate ID for certificate `subject`. + pub fn from_cert(digest: MessageDigest, + subject: &X509Ref, + issuer: &X509Ref) + -> Result { + unsafe { + cvt_p(ffi::OCSP_cert_to_id(digest.as_ptr(), subject.as_ptr(), issuer.as_ptr())) + .map(OcspCertId) + } + } +} + +type_!(OcspResponse, OcspResponseRef, ffi::OCSP_RESPONSE, ffi::OCSP_RESPONSE_free); + +impl OcspResponse { + /// Creates an OCSP response from the status and optional body. + /// + /// A body should only be provided if `status` is `RESPONSE_STATUS_SUCCESSFUL`. + pub fn create(status: OcspResponseStatus, + body: Option<&OcspBasicResponseRef>) + -> Result { + unsafe { + ffi::init(); + + cvt_p(ffi::OCSP_response_create(status.as_raw(), + body.map(|r| r.as_ptr()).unwrap_or(ptr::null_mut()))) + .map(OcspResponse) + } + } + + from_der!(OcspResponse, ffi::d2i_OCSP_RESPONSE); +} + +impl OcspResponseRef { + to_der!(ffi::i2d_OCSP_RESPONSE); + + /// Returns the status of the response. + 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`. + pub fn basic(&self) -> Result { + unsafe { + cvt_p(ffi::OCSP_response_get1_basic(self.as_ptr())).map(OcspBasicResponse) + } + } +} + +type_!(OcspRequest, OcspRequestRef, ffi::OCSP_REQUEST, ffi::OCSP_REQUEST_free); + +impl OcspRequest { + pub fn new() -> Result { + unsafe { + ffi::init(); + + cvt_p(ffi::OCSP_REQUEST_new()).map(OcspRequest) + } + } + + from_der!(OcspRequest, ffi::d2i_OCSP_REQUEST); +} + +impl OcspRequestRef { + to_der!(ffi::i2d_OCSP_REQUEST); + + pub fn add_id(&mut self, id: OcspCertId) -> Result<&mut OcspOneReqRef, ErrorStack> { + unsafe { + let ptr = try!(cvt_p(ffi::OCSP_request_add0_id(self.as_ptr(), id.as_ptr()))); + mem::forget(id); + Ok(OcspOneReqRef::from_ptr_mut(ptr)) + } + } +} + +type_!(OcspOneReq, OcspOneReqRef, ffi::OCSP_ONEREQ, ffi::OCSP_ONEREQ_free); diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index f412ca93..2fc7605a 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -97,14 +97,14 @@ use ec::EcKeyRef; #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))] use ec::EcKey; use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name}; -use x509::store::X509StoreBuilderRef; +use x509::store::{X509StoreBuilderRef, X509StoreRef}; #[cfg(any(ossl102, ossl110))] use verify::X509VerifyParamRef; use pkey::PKeyRef; use error::ErrorStack; use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; -use stack::Stack; +use stack::{Stack, StackRef}; mod error; mod connector; @@ -217,6 +217,22 @@ bitflags! { } } +#[derive(Copy, Clone)] +pub struct StatusType(c_int); + +impl StatusType { + pub fn from_raw(raw: c_int) -> StatusType { + StatusType(raw) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } +} + +/// An OSCP status. +pub const STATUS_TYPE_OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp); + lazy_static! { static ref INDEXES: Mutex> = Mutex::new(HashMap::new()); static ref SSL_INDEXES: Mutex> = Mutex::new(HashMap::new()); @@ -475,6 +491,37 @@ unsafe extern fn raw_tmp_ecdh_ssl(ssl: *mut ffi::SSL, } } +unsafe extern fn raw_tlsext_status(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int + where F: Fn(&mut SslRef) -> Result + Any + 'static + Sync + Send +{ + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); + let callback = &*(callback as *mut F); + + let ssl = SslRef::from_ptr_mut(ssl); + 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(_) => { + // FIXME reset error stack + ffi::SSL_TLSEXT_ERR_ALERT_FATAL + } + } + } else { + match ret { + Ok(true) => 1, + Ok(false) => 0, + Err(_) => { + // FIXME reset error stack + -1 + } + } + } +} + /// The function is given as the callback to `SSL_CTX_set_next_protos_advertised_cb`. /// /// It causes the parameter `out` to point at a `*const c_uchar` instance that @@ -887,6 +934,31 @@ impl SslContextBuilder { unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) } } + /// Sets the callback dealing with OCSP stapling. + /// + /// On the client side, this callback is responsible for validating the OCSP status response + /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method. + /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of + /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be + /// terminated. + /// + /// On the server side, this callback is resopnsible for setting the OCSP status response to be + /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A + /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and + /// `Ok(false)` indicates that the status should not be returned to the client. + pub fn set_status_callback(&mut self, callback: F) -> Result<(), ErrorStack> + where F: Fn(&mut SslRef) -> Result + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_CTX_set_ex_data(self.as_ptr(), + get_callback_idx::(), + Box::into_raw(callback) as *mut c_void); + let f: unsafe extern fn (_, _) -> _ = raw_tlsext_status::; + cvt(ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(f)) as c_int).map(|_| ()) + } + } + pub fn build(self) -> SslContext { let ctx = SslContext(self.0); mem::forget(self); @@ -951,6 +1023,22 @@ impl SslContextRef { } } } + + /// Returns the certificate store used for verification. + pub fn cert_store(&self) -> &X509StoreRef { + unsafe { + X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) + } + } + + pub fn extra_chain_certs(&self) -> &StackRef { + unsafe { + let mut chain = ptr::null_mut(); + ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain); + assert!(!chain.is_null()); + StackRef::from_ptr(chain) + } + } } pub struct CipherBits { @@ -1378,6 +1466,49 @@ impl SslRef { } } } + + /// Sets the status response a client wishes the server to reply with. + pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ()) + } + } + + /// Returns the server's OCSP response, if present. + pub fn ocsp_status(&self) -> Option<&[u8]> { + unsafe { + let mut p = ptr::null_mut(); + let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p); + + if len < 0 { + None + } else { + Some(slice::from_raw_parts(p as *const u8, len as usize)) + } + } + } + + /// Sets the OCSP response to be returned to the client. + pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> { + unsafe { + assert!(response.len() <= c_int::max_value() as usize); + let p = try!(cvt_p(ffi::CRYPTO_malloc(response.len() as _, + concat!(file!(), "\0").as_ptr() as *const _, + line!() as c_int))); + ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len()); + cvt(ffi::SSL_set_tlsext_status_ocsp_resp(self.as_ptr(), + p as *mut c_uchar, + response.len() as c_long) as c_int) + .map(|_| ()) + } + } + + /// Determines if this `Ssl` is configured for server-side or client-side use. + pub fn is_server(&self) -> bool { + unsafe { + compat::SSL_is_server(self.as_ptr()) != 0 + } + } } unsafe impl Sync for Ssl {} @@ -1745,9 +1876,8 @@ mod compat { use ffi; use libc::c_int; - pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options}; - pub use ffi::{SSL_CTX_clear_options, SSL_CTX_up_ref}; - pub use ffi::SSL_SESSION_get_master_key; + pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_clear_options, SSL_CTX_up_ref, + SSL_SESSION_get_master_key, SSL_is_server}; pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { ffi::CRYPTO_get_ex_new_index(ffi::CRYPTO_EX_INDEX_SSL_CTX, @@ -1839,4 +1969,8 @@ mod compat { pub fn dtls_method() -> *const ffi::SSL_METHOD { unsafe { ffi::DTLSv1_method() } } + + pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { + (*s).server + } } diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 14bb2f71..349c7a4d 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -16,9 +16,11 @@ use tempdir::TempDir; use dh::Dh; use hash::MessageDigest; +use ocsp::{OcspResponse, RESPONSE_STATUS_UNAUTHORIZED}; use ssl; use ssl::{SslMethod, HandshakeError, SslContext, SslStream, Ssl, ShutdownResult, - SslConnectorBuilder, SslAcceptorBuilder, Error, SSL_VERIFY_PEER, SSL_VERIFY_NONE}; + SslConnectorBuilder, SslAcceptorBuilder, Error, SSL_VERIFY_PEER, SSL_VERIFY_NONE, + STATUS_TYPE_OCSP}; use x509::{X509StoreContext, X509, X509Name, X509_FILETYPE_PEM}; #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))] use x509::verify::X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS; @@ -1393,7 +1395,48 @@ fn active_session() { let mut buf = vec![0; len + 1]; let copied = session.master_key(&mut buf); assert_eq!(copied, len); +} +#[test] +fn status_callbacks() { + static CALLED_BACK_SERVER: AtomicBool = ATOMIC_BOOL_INIT; + static CALLED_BACK_CLIENT: AtomicBool = ATOMIC_BOOL_INIT; + + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let port = listener.local_addr().unwrap().port(); + + let guard = thread::spawn(move || { + let stream = listener.accept().unwrap().0; + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_certificate_file(&Path::new("test/cert.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_private_key_file(&Path::new("test/key.pem"), X509_FILETYPE_PEM).unwrap(); + ctx.set_status_callback(|ssl| { + CALLED_BACK_SERVER.store(true, Ordering::SeqCst); + let response = OcspResponse::create(RESPONSE_STATUS_UNAUTHORIZED, None).unwrap(); + let response = response.to_der().unwrap(); + ssl.set_ocsp_status(&response).unwrap(); + Ok(true) + }).unwrap(); + let ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.accept(stream).unwrap(); + }); + + let stream = TcpStream::connect(("127.0.0.1", port)).unwrap(); + let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); + ctx.set_status_callback(|ssl| { + CALLED_BACK_CLIENT.store(true, Ordering::SeqCst); + let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); + assert_eq!(response.status(), RESPONSE_STATUS_UNAUTHORIZED); + Ok(true) + }); + let mut ssl = Ssl::new(&ctx.build()).unwrap(); + ssl.set_status_type(STATUS_TYPE_OCSP).unwrap(); + ssl.connect(stream).unwrap(); + + assert!(CALLED_BACK_SERVER.load(Ordering::SeqCst)); + assert!(CALLED_BACK_CLIENT.load(Ordering::SeqCst)); + + guard.join().unwrap(); } fn _check_kinds() { diff --git a/openssl/src/string.rs b/openssl/src/string.rs new file mode 100644 index 00000000..37d44d16 --- /dev/null +++ b/openssl/src/string.rs @@ -0,0 +1,74 @@ +use ffi; +use libc::{c_char, c_void}; +use std::fmt; +use std::ffi::CStr; +use std::ops::Deref; +use std::str; + +use types::{OpenSslType, OpenSslTypeRef}; +use stack::Stackable; + +type_!(OpensslString, OpensslStringRef, c_char, free); + +impl OpensslString { + #[deprecated(note = "use from_ptr", since = "0.9.7")] + pub unsafe fn from_raw_parts(buf: *mut u8, _: usize) -> OpensslString { + OpensslString::from_ptr(buf as *mut c_char) + } + + #[deprecated(note = "use from_ptr", since = "0.9.7")] + pub unsafe fn from_null_terminated(buf: *mut c_char) -> OpensslString { + OpensslString::from_ptr(buf) + } +} + +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 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 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) + } +} + +#[cfg(not(ossl110))] +unsafe fn free(buf: *mut c_char) { + ::ffi::CRYPTO_free(buf as *mut c_void); +} + +#[cfg(ossl110)] +unsafe fn free(buf: *mut c_char) { + ::ffi::CRYPTO_free(buf as *mut c_void, + concat!(file!(), "\0").as_ptr() as *const c_char, + line!() as ::libc::c_int); +} diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index d90cee22..e75dcf5d 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -20,6 +20,7 @@ use error::ErrorStack; use ffi; use nid::Nid; use types::{OpenSslType, OpenSslTypeRef}; +use string::OpensslString; use stack::{Stack, StackRef, Stackable}; #[cfg(ossl10x)] @@ -415,6 +416,25 @@ impl X509Ref { } } + /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information + /// Access field. + pub fn ocsp_responders(&self) -> Result, ErrorStack> { + unsafe { + cvt_p(ffi::X509_get1_ocsp(self.as_ptr())).map(|p| Stack::from_ptr(p)) + } + } + + /// Checks that this certificate issued `subject`. + pub fn issued(&self, subject: &X509Ref) -> Result<(), X509VerifyError> { + unsafe { + let r = ffi::X509_check_issued(self.as_ptr(), subject.as_ptr()); + match X509VerifyError::from_raw(r as c_long) { + Some(e) => Err(e), + None => Ok(()), + } + } + } + to_pem!(ffi::PEM_write_bio_X509); to_der!(ffi::i2d_X509); } diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs index 01eb0e2f..dd08a49b 100644 --- a/openssl/src/x509/store.rs +++ b/openssl/src/x509/store.rs @@ -1,13 +1,33 @@ use ffi; use std::mem; -use cvt; +use {cvt, cvt_p}; use error::ErrorStack; use types::OpenSslTypeRef; use x509::X509; type_!(X509StoreBuilder, X509StoreBuilderRef, ffi::X509_STORE, ffi::X509_STORE_free); +impl X509StoreBuilder { + /// Returns a builder for a certificate store. + /// + /// The store is initially empty. + pub fn new() -> Result { + unsafe { + ffi::init(); + + cvt_p(ffi::X509_STORE_new()).map(X509StoreBuilder) + } + } + + /// Constructs the `X509Store`. + pub fn build(self) -> X509Store { + let store = X509Store(self.0); + mem::forget(self); + store + } +} + impl X509StoreBuilderRef { /// Adds a certificate to the certificate store. pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { @@ -17,4 +37,17 @@ impl X509StoreBuilderRef { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), 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. + pub fn set_default_paths(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_STORE_set_default_paths(self.as_ptr())).map(|_| ()) + } + } } + +type_!(X509Store, X509StoreRef, ffi::X509_STORE, ffi::X509_STORE_free); diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 0843b19f..f89b7267 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -132,7 +132,7 @@ fn test_nid_values() { assert_eq!(email.data().as_slice(), b"test@example.com"); let friendly = subject.entries_by_nid(nid::FRIENDLYNAME).next().unwrap(); - assert_eq!(&*friendly.data().as_utf8().unwrap(), "Example"); + assert_eq!(&**friendly.data().as_utf8().unwrap(), "Example"); } #[test] @@ -186,3 +186,14 @@ fn test_stack_from_pem() { assert_eq!(certs[1].fingerprint(MessageDigest::sha1()).unwrap().to_hex(), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"); } + +#[test] +fn issued() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let ca = include_bytes!("../../test/root-ca.pem"); + let ca = X509::from_pem(ca).unwrap(); + + ca.issued(&cert).unwrap(); + cert.issued(&cert).err().unwrap(); +} diff --git a/systest/build.rs b/systest/build.rs index 2f0fd136..b12739f0 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -46,7 +46,8 @@ fn main() { .header("openssl/err.h") .header("openssl/rand.h") .header("openssl/pkcs12.h") - .header("openssl/bn.h"); + .header("openssl/bn.h") + .header("openssl/ocsp.h"); cfg.type_name(|s, is_struct| { // Add some `*` on some callback parameters to get function pointer to // typecheck in C, especially on MSVC. @@ -90,6 +91,8 @@ fn main() { }); cfg.skip_signededness(|s| { s.ends_with("_cb") || + s.ends_with("_CB") || + s.ends_with("_cb_fn") || s.starts_with("CRYPTO_") || s == "PasswordCallback" }); From a1122197f87511cdc70a09b37df643e90dcd2d31 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 20 Jan 2017 16:35:43 +0000 Subject: [PATCH 108/140] Add categories Closes #557 --- openssl-sys/Cargo.toml | 1 + openssl/Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 3ce84e30..fe484a79 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -7,6 +7,7 @@ license = "MIT" description = "FFI bindings to OpenSSL" repository = "https://github.com/sfackler/rust-openssl" documentation = "https://docs.rs/openssl-sys/0.9.6/openssl_sys" +categories = ["cryptography", "external-ffi-bindings"] links = "openssl" build = "build.rs" diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index a4baa79d..d1893fe8 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -8,6 +8,7 @@ repository = "https://github.com/sfackler/rust-openssl" documentation = "https://docs.rs/openssl/0.9.6/openssl" readme = "../README.md" keywords = ["crypto", "tls", "ssl", "dtls"] +categories = ["cryptography", "api-bindings"] build = "build.rs" exclude = ["test/*"] From d353b366811023049eb77189234abc8196f9372f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 20 Jan 2017 22:34:30 +0000 Subject: [PATCH 109/140] Support AES IGE This is a special snowflake used only by Telegram apparently. Closes #523 --- openssl-sys/src/lib.rs | 17 ++++++ openssl/src/aes.rs | 115 +++++++++++++++++++++++++++++++++++++++++ openssl/src/lib.rs | 1 + systest/build.rs | 1 + 4 files changed, 134 insertions(+) create mode 100644 openssl/src/aes.rs diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0cbd0da7..865061ee 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -76,6 +76,13 @@ pub enum point_conversion_form_t { POINT_CONVERSION_HYBRID = 6, } +#[repr(C)] +pub struct AES_KEY { + // There is some business with AES_LONG which is there to ensure the values here are 32 bits + rd_key: [u32; 4 * (AES_MAXNR as usize + 1)], + rounds: c_int, +} + #[repr(C)] pub struct GENERAL_NAME { pub type_: c_int, @@ -114,6 +121,12 @@ pub type PasswordCallback = unsafe extern fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; +pub const AES_ENCRYPT: c_int = 1; +pub const AES_DECRYPT: c_int = 0; + +pub const AES_MAXNR: c_int = 14; +pub const AES_BLOCK_SIZE: c_int = 16; + pub const BIO_TYPE_NONE: c_int = 0; pub const BIO_CTRL_EOF: c_int = 2; @@ -1368,6 +1381,10 @@ pub fn ERR_GET_REASON(l: c_ulong) -> c_int { } extern { + pub fn AES_set_encrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; + pub fn AES_set_decrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; + pub fn AES_ige_encrypt(in_: *const c_uchar, out: *mut c_uchar, length: size_t, key: *const AES_KEY, ivec: *mut c_uchar, enc: c_int); + pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; diff --git a/openssl/src/aes.rs b/openssl/src/aes.rs new file mode 100644 index 00000000..d226c515 --- /dev/null +++ b/openssl/src/aes.rs @@ -0,0 +1,115 @@ +//! Low level AES functionality +//! +//! The `symm` module should be used in preference to this module in most cases. +use ffi; +use std::mem; +use libc::c_int; + +use symm::Mode; + +#[derive(Debug)] +pub struct KeyError(()); + +pub struct AesKey(ffi::AES_KEY); + +impl AesKey { + /// Prepares a key for encryption. + /// + /// # Failure + /// + /// Returns an error if the key is not 128, 192, or 256 bits. + pub fn new_encrypt(key: &[u8]) -> Result { + unsafe { + assert!(key.len() <= c_int::max_value() as usize / 8); + + let mut aes_key = mem::uninitialized(); + let r = ffi::AES_set_encrypt_key(key.as_ptr() as *const _, + key.len() as c_int * 8, + &mut aes_key); + if r == 0 { + Ok(AesKey(aes_key)) + } else { + Err(KeyError(())) + } + } + } + + /// Prepares a key for decryption. + /// + /// # Failure + /// + /// Returns an error if the key is not 128, 192, or 256 bits. + pub fn new_decrypt(key: &[u8]) -> Result { + unsafe { + assert!(key.len() <= c_int::max_value() as usize / 8); + + let mut aes_key = mem::uninitialized(); + let r = ffi::AES_set_decrypt_key(key.as_ptr() as *const _, + key.len() as c_int * 8, + &mut aes_key); + + if r == 0 { + Ok(AesKey(aes_key)) + } else { + Err(KeyError(())) + } + } + } +} + +/// Performs AES IGE encryption or decryption +/// +/// # 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. +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); + } +} + +#[cfg(test)] +mod test { + use hex::FromHex; + + use symm::Mode; + use super::*; + + // From https://www.mgp25.com/AESIGE/ + #[test] + 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); + } +} diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index 9138896b..ea71a269 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -24,6 +24,7 @@ mod macros; mod bio; mod util; +pub mod aes; pub mod asn1; pub mod bn; pub mod crypto; diff --git a/systest/build.rs b/systest/build.rs index b12739f0..548d6080 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -47,6 +47,7 @@ fn main() { .header("openssl/rand.h") .header("openssl/pkcs12.h") .header("openssl/bn.h") + .header("openssl/aes.h") .header("openssl/ocsp.h"); cfg.type_name(|s, is_struct| { // Add some `*` on some callback parameters to get function pointer to From 26e159a5f07a36be24fc35221154fdaebcabdf02 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 21 Jan 2017 11:11:24 +0000 Subject: [PATCH 110/140] Support chacha20 and chacha20_poly1305 --- openssl-sys/src/ossl110.rs | 3 ++ openssl/src/crypto.rs | 1 - openssl/src/ocsp.rs | 2 +- openssl/src/symm.rs | 60 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index 925b0d8a..75c6253e 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -68,6 +68,9 @@ extern { pub fn CRYPTO_malloc(num: size_t, file: *const c_char, line: c_int) -> *mut c_void; pub fn CRYPTO_free(buf: *mut c_void, file: *const c_char, line: c_int); + pub fn EVP_chacha20() -> *const ::EVP_CIPHER; + pub fn EVP_chacha20_poly1305() -> *const ::EVP_CIPHER; + pub fn HMAC_CTX_new() -> *mut HMAC_CTX; pub fn HMAC_CTX_free(ctx: *mut HMAC_CTX); diff --git a/openssl/src/crypto.rs b/openssl/src/crypto.rs index 49029318..9853d99c 100644 --- a/openssl/src/crypto.rs +++ b/openssl/src/crypto.rs @@ -2,4 +2,3 @@ use string::OpensslString; #[deprecated(note = "renamed to OpensslString", since = "0.9.7")] pub type CryptoString = OpensslString; - diff --git a/openssl/src/ocsp.rs b/openssl/src/ocsp.rs index bba5c561..708c3561 100644 --- a/openssl/src/ocsp.rs +++ b/openssl/src/ocsp.rs @@ -141,7 +141,7 @@ 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 to not include this in the response. + /// OCSP response signing certificate. Some responders do not include this in the response. pub fn verify(&self, certs: &StackRef, store: &X509StoreRef, diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 99ee4c67..5cf1ce0b 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -108,6 +108,18 @@ impl Cipher { unsafe { Cipher(ffi::EVP_rc4()) } } + /// Requires the `v110` feature and OpenSSL 1.1.0. + #[cfg(all(ossl110, feature = "v110"))] + pub fn chacha20() -> Cipher { + unsafe { Cipher(ffi::EVP_chacha20()) } + } + + /// Requires the `v110` feature and OpenSSL 1.1.0. + #[cfg(all(ossl110, feature = "v110"))] + pub fn chacha20_poly1305() -> Cipher { + unsafe { Cipher(ffi::EVP_chacha20_poly1305()) } + } + pub unsafe fn from_ptr(ptr: *const ffi::EVP_CIPHER) -> Cipher { Cipher(ptr) } @@ -767,4 +779,52 @@ mod tests { &Vec::from_hex(tag).unwrap()).unwrap(); assert_eq!(pt, out.to_hex()); } + + #[test] + #[cfg(all(ossl110, feature = "v110"))] + fn test_chacha20() { + let key = "0000000000000000000000000000000000000000000000000000000000000000"; + let iv = "00000000000000000000000000000000"; + let pt = "000000000000000000000000000000000000000000000000000000000000000000000000000000000\ + 00000000000000000000000000000000000000000000000"; + let ct = "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7\ + 724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586"; + + cipher_test(Cipher::chacha20(), pt, ct, key, iv); + } + + #[test] + #[cfg(all(ossl110, feature = "v110"))] + fn test_chacha20_poly1305() { + let key = "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"; + let iv = "070000004041424344454647"; + let aad = "50515253c0c1c2c3c4c5c6c7"; + let pt = "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393\ + a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f722074\ + 6865206675747572652c2073756e73637265656e20776f756c642062652069742e"; + let ct = "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca967128\ + 2fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fa\ + b324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116"; + let tag = "1ae10b594f09e26a7e902ecbd0600691"; + + let mut actual_tag = [0; 16]; + let out = encrypt_aead(Cipher::chacha20_poly1305(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(pt).unwrap(), + &mut actual_tag) + .unwrap(); + assert_eq!(ct, out.to_hex()); + assert_eq!(tag, actual_tag.to_hex()); + + let out = decrypt_aead(Cipher::chacha20_poly1305(), + &Vec::from_hex(key).unwrap(), + Some(&Vec::from_hex(iv).unwrap()), + &Vec::from_hex(aad).unwrap(), + &Vec::from_hex(ct).unwrap(), + &Vec::from_hex(tag).unwrap()) + .unwrap(); + assert_eq!(pt, out.to_hex()); + } } From 1ffdf8a1ab75f49b95bae96d4dac31ab6cd3f526 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 21 Jan 2017 14:43:43 +0000 Subject: [PATCH 111/140] Fix test warnings --- openssl/src/ssl/tests/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 349c7a4d..536088ab 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -100,6 +100,7 @@ impl Server { Server::new_tcp(&["-www"]) } + #[allow(dead_code)] fn new_alpn() -> (Server, TcpStream) { Server::new_tcp(&["-www", "-nextprotoneg", @@ -1428,7 +1429,7 @@ fn status_callbacks() { let response = OcspResponse::from_der(ssl.ocsp_status().unwrap()).unwrap(); assert_eq!(response.status(), RESPONSE_STATUS_UNAUTHORIZED); Ok(true) - }); + }).unwrap(); let mut ssl = Ssl::new(&ctx.build()).unwrap(); ssl.set_status_type(STATUS_TYPE_OCSP).unwrap(); ssl.connect(stream).unwrap(); From 54900976bb76d3cef4a78df48a3645b0ac49bb46 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 22 Jan 2017 10:44:59 +0000 Subject: [PATCH 112/140] Support EC_GROUP_set_asn1_flag Closes #561 --- openssl-sys/src/lib.rs | 3 ++ openssl/src/ec.rs | 84 +++++++++++++++++++++++++++++++++------ openssl/src/x509/tests.rs | 23 +++++++++++ 3 files changed, 97 insertions(+), 13 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 865061ee..970539d7 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1109,6 +1109,8 @@ pub const OCSP_RESPONSE_STATUS_TRYLATER: c_int = 3; pub const OCSP_RESPONSE_STATUS_SIGREQUIRED: c_int = 5; pub const OCSP_RESPONSE_STATUS_UNAUTHORIZED: c_int = 6; +pub const OPENSSL_EC_NAMED_CURVE: c_int = 1; + pub const PKCS5_SALT_LEN: c_int = 8; pub const RSA_F4: c_long = 0x10001; @@ -1510,6 +1512,7 @@ extern { pub fn EC_GROUP_get_curve_GF2m(group: *const EC_GROUP, p: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; pub fn EC_GROUP_get_degree(group: *const EC_GROUP) -> c_int; pub fn EC_GROUP_get_order(group: *const EC_GROUP, order: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn EC_GROUP_set_asn1_flag(key: *mut EC_GROUP, flag: c_int); pub fn EC_GROUP_free(group: *mut EC_GROUP); diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index 592c4026..ebb631e8 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -1,11 +1,13 @@ use ffi; use std::ptr; +use std::mem; +use libc::c_int; use {cvt, cvt_n, cvt_p, init}; use bn::{BigNumRef, BigNumContextRef}; use error::ErrorStack; use nid::Nid; -use types::OpenSslTypeRef; +use types::{OpenSslType, OpenSslTypeRef}; pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); @@ -16,9 +18,17 @@ pub const POINT_CONVERSION_UNCOMPRESSED: PointConversionForm = pub const POINT_CONVERSION_HYBRID: PointConversionForm = PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_HYBRID); +// OPENSSL_EC_EXPLICIT_CURVE, but that was only added in 1.1. +// Man page documents that 0 can be used in older versions. +pub const EXPLICIT_CURVE: Asn1Flag = Asn1Flag(0); +pub const NAMED_CURVE: Asn1Flag = Asn1Flag(ffi::OPENSSL_EC_NAMED_CURVE); + #[derive(Copy, Clone)] pub struct PointConversionForm(ffi::point_conversion_form_t); +#[derive(Copy, Clone)] +pub struct Asn1Flag(c_int); + type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); impl EcGroup { @@ -80,6 +90,17 @@ impl EcGroupRef { cvt(ffi::EC_GROUP_get_order(self.as_ptr(), order.as_ptr(), ctx.as_ptr())).map(|_| ()) } } + + /// Sets the flag determining if the group corresponds to a named curve or must be explicitly + /// parameterized. + /// + /// This defaults to `EXPLICIT_CURVE` in OpenSSL 1.0.1 and 1.0.2, but `NAMED_CURVE` in OpenSSL + /// 1.1.0. + pub fn set_asn1_flag(&mut self, flag: Asn1Flag) { + unsafe { + ffi::EC_GROUP_set_asn1_flag(self.as_ptr(), flag.0); + } + } } type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); @@ -311,22 +332,18 @@ impl EcKey { /// let key = EcKey::from_public_key(&group, &point); /// ``` pub fn from_public_key(group: &EcGroupRef, public_key: &EcPointRef) -> Result { - unsafe { - let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); - try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); - try!(cvt(ffi::EC_KEY_set_public_key(key.as_ptr(), public_key.as_ptr()))); - Ok(key) - } + let mut builder = try!(EcKeyBuilder::new()); + try!(builder.set_group(group)); + try!(builder.set_public_key(public_key)); + Ok(builder.build()) } /// Generates a new public/private key pair on the specified curve. pub fn generate(group: &EcGroupRef) -> Result { - unsafe { - let key = EcKey(try!(cvt_p(ffi::EC_KEY_new()))); - try!(cvt(ffi::EC_KEY_set_group(key.as_ptr(), group.as_ptr()))); - try!(cvt(ffi::EC_KEY_generate_key(key.as_ptr()))); - Ok(key) - } + let mut builder = try!(EcKeyBuilder::new()); + try!(builder.set_group(group)); + try!(builder.generate_key()); + Ok(builder.build()) } #[deprecated(since = "0.9.2", note = "use from_curve_name")] @@ -338,6 +355,47 @@ impl EcKey { private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); } +type_!(EcKeyBuilder, EcKeyBuilderRef, ffi::EC_KEY, ffi::EC_KEY_free); + +impl EcKeyBuilder { + pub fn new() -> Result { + unsafe { + init(); + cvt_p(ffi::EC_KEY_new()).map(EcKeyBuilder) + } + } + + pub fn build(self) -> EcKey { + unsafe { + let key = EcKey::from_ptr(self.as_ptr()); + mem::forget(self); + key + } + } +} + +impl EcKeyBuilderRef { + pub fn set_group(&mut self, group: &EcGroupRef) -> Result<&mut EcKeyBuilderRef, ErrorStack> { + unsafe { + cvt(ffi::EC_KEY_set_group(self.as_ptr(), group.as_ptr())).map(|_| self) + } + } + + pub fn set_public_key(&mut self, + public_key: &EcPointRef) + -> Result<&mut EcKeyBuilderRef, ErrorStack> { + unsafe { + cvt(ffi::EC_KEY_set_public_key(self.as_ptr(), public_key.as_ptr())).map(|_| self) + } + } + + pub fn generate_key(&mut self) -> Result<&mut EcKeyBuilderRef, ErrorStack> { + unsafe { + cvt(ffi::EC_KEY_generate_key(self.as_ptr())).map(|_| self) + } + } +} + #[cfg(test)] mod test { use bn::BigNumContext; diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index f89b7267..01cbf2ec 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1,8 +1,11 @@ use hex::{FromHex, ToHex}; +use ec::{NAMED_CURVE, EcGroup, EcKey}; use hash::MessageDigest; +use nid::X9_62_PRIME256V1; use pkey::PKey; use rsa::Rsa; +use ssl::{SslMethod, SslContextBuilder}; use x509::{X509, X509Generator}; use x509::extension::Extension::{KeyUsage, ExtKeyUsage, SubjectAltName, OtherNid, OtherStr}; use x509::extension::AltNameOption as SAN; @@ -197,3 +200,23 @@ fn issued() { ca.issued(&cert).unwrap(); cert.issued(&cert).err().unwrap(); } + +#[test] +fn ecdsa_cert() { + let mut group = EcGroup::from_curve_name(X9_62_PRIME256V1).unwrap(); + group.set_asn1_flag(NAMED_CURVE); + let key = EcKey::generate(&group).unwrap(); + let key = PKey::from_ec_key(key).unwrap(); + + let cert = X509Generator::new() + .set_valid_period(365) + .add_name("CN".to_owned(), "TestServer".to_owned()) + .set_sign_hash(MessageDigest::sha256()) + .sign(&key) + .unwrap(); + + let mut ctx = SslContextBuilder::new(SslMethod::tls()).unwrap(); + ctx.set_certificate(&cert).unwrap(); + ctx.set_private_key(&key).unwrap(); + ctx.check_private_key().unwrap(); +} From 52c7868bb615b04feb01be88cd1f47af866f12ad Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Sun, 22 Jan 2017 21:27:31 -0800 Subject: [PATCH 113/140] add pkcs12_create and to_der funcs --- openssl-sys/src/lib.rs | 12 ++++ openssl/src/pkcs12.rs | 129 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 139 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0cbd0da7..0af15251 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1951,7 +1951,19 @@ extern { pub fn i2d_RSAPrivateKey(k: *const RSA, buf: *mut *mut u8) -> c_int; pub fn d2i_RSAPrivateKey(k: *mut *mut RSA, buf: *mut *const u8, len: c_long) -> *mut RSA; + pub fn i2d_PKCS12_bio(b: *mut BIO, a: *mut PKCS12) -> c_int; + pub fn i2d_PKCS12(a: *mut PKCS12, buf: *mut *mut u8) -> c_int; pub fn d2i_PKCS12(a: *mut *mut PKCS12, pp: *mut *const u8, length: c_long) -> *mut PKCS12; + pub fn PKCS12_create(pass: *const c_char, + friendly_name: *const c_char, + pkey: *const EVP_PKEY, + cert: *const X509, + ca: *const stack_st_X509, + nid_key: c_int, + nid_cert: c_int, + iter: c_int, + mac_iter: c_int, + keytype: c_int) -> *mut PKCS12; pub fn PKCS12_parse(p12: *mut PKCS12, pass: *const c_char, pkey: *mut *mut EVP_PKEY, diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index ee9ae124..c248df2e 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -1,19 +1,23 @@ //! PKCS #12 archives. use ffi; +use libc::c_int; use std::ptr; use std::ffi::CString; use cvt; -use pkey::PKey; +use pkey::{PKey, PKeyRef}; use error::ErrorStack; use x509::X509; use types::{OpenSslType, OpenSslTypeRef}; -use stack::Stack; +use stack::{Stack, StackRef}; +use nid; type_!(Pkcs12, Pkcs12Ref, ffi::PKCS12, ffi::PKCS12_free); impl Pkcs12Ref { + to_der!(ffi::i2d_PKCS12); + /// Extracts the contents of the `Pkcs12`. // FIXME should take an &[u8] pub fn parse(&self, pass: &str) -> Result { @@ -53,11 +57,107 @@ pub struct ParsedPkcs12 { pub chain: Stack, } +pub struct Pkcs12Builder<'a, 'b, 'c, 'd> { + password: &'a str, + friendly_name: &'b str, + pkey: &'c PKeyRef, + cert: &'d X509, + chain: Option>, + nid_key: nid::Nid, + nid_cert: nid::Nid, + iter: usize, + mac_iter: usize, +} + +impl<'a, 'b, 'c, 'd> Pkcs12Builder<'a, 'b, 'c, 'd> { + /// Creates a new builder for a protected pkcs12 certificate. + /// + /// This uses the defaults from the OpenSSL library: + /// + /// * `nid_key` - `nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` + /// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC` + /// * `iter` - `2048` + /// * `mac_iter` - `2048` + pub fn new(password: &'a str, + friendly_name: &'b str, + pkey: &'c PKeyRef, + cert: &'d X509) -> Self { + Pkcs12Builder { + password: password, + friendly_name: friendly_name, + pkey: pkey, + cert: cert, + chain: None, + nid_key: nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC, + nid_cert: nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC, + iter: 0, // 2048 + mac_iter: 0, // 2048 + } + } + + /// The encryption algorithm that should be used for the key + pub fn nid_key(&mut self, nid: nid::Nid) { + self.nid_key = nid; + } + + /// The encryption algorithm that should be used for the cert + pub fn nid_cert(&mut self, nid: nid::Nid) { + self.nid_cert = nid; + } + + pub fn iter(&mut self, iter: usize) { + self.iter = iter; + } + + pub fn mac_iter(&mut self, mac_iter: usize) { + self.mac_iter = mac_iter; + } + + pub fn build(self) -> Result { + unsafe { + let pass = CString::new(self.password).unwrap(); + let friendly_name = CString::new(self.friendly_name).unwrap(); + let pkey = self.pkey.as_ptr(); + let cert = self.cert.as_ptr(); + let ca = self.chain.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/man1.0.2/crypto/PKCS12_create.html + let keytype = 0; + + let pkcs12_ptr = ffi::PKCS12_create(pass.as_ptr(), + friendly_name.as_ptr(), + pkey, + cert, + ca, + nid_key, + nid_cert, + self.iter as c_int, + self.mac_iter as c_int, + keytype); + + if pkcs12_ptr.is_null() { + Err(ErrorStack::get()) + } else { + Ok(Pkcs12::from_ptr(pkcs12_ptr)) + } + } + } +} + #[cfg(test)] mod test { use hash::MessageDigest; use hex::ToHex; + use ::rsa::Rsa; + use ::pkey::*; + use ::x509::*; + use ::x509::extension::*; + use super::*; #[test] @@ -73,4 +173,29 @@ mod test { assert_eq!(parsed.chain[0].fingerprint(MessageDigest::sha1()).unwrap().to_hex(), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875"); } + + #[test] + fn create() { + let subject_name = "ns.example.com"; + let rsa = Rsa::generate(2048).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + + let gen = X509Generator::new() + .set_valid_period(365*2) + .add_name("CN".to_owned(), subject_name.to_string()) + .set_sign_hash(MessageDigest::sha256()) + .add_extension(Extension::KeyUsage(vec![KeyUsageOption::DigitalSignature])); + + let cert = gen.sign(&pkey).unwrap(); + + let pkcs12_builder = Pkcs12Builder::new("mypass", subject_name, &pkey, &cert); + let pkcs12 = pkcs12_builder.build().unwrap(); + let der = pkcs12.to_der().unwrap(); + + let pkcs12 = Pkcs12::from_der(&der).unwrap(); + let parsed = pkcs12.parse("mypass").unwrap(); + + assert_eq!(parsed.cert.fingerprint(MessageDigest::sha1()).unwrap(), cert.fingerprint(MessageDigest::sha1()).unwrap()); + assert!(parsed.pkey.public_eq(&pkey)); + } } From fbfecd63aeb0cd1ee24d017df2d89078a53bf0fe Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Sun, 22 Jan 2017 22:23:21 -0800 Subject: [PATCH 114/140] add some documentation --- openssl-sys/src/lib.rs | 1 + openssl/src/pkcs12.rs | 67 ++++++++++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 0af15251..cf158601 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1097,6 +1097,7 @@ pub const OCSP_RESPONSE_STATUS_SIGREQUIRED: c_int = 5; pub const OCSP_RESPONSE_STATUS_UNAUTHORIZED: c_int = 6; pub const PKCS5_SALT_LEN: c_int = 8; +pub const PKCS12_DEFAULT_ITER: c_int = 2048; pub const RSA_F4: c_long = 0x10001; diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index c248df2e..fecef27a 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -49,6 +49,40 @@ impl Pkcs12Ref { impl 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` - `nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` + /// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC` + /// * `iter` - `2048` + /// * `mac_iter` - `2048` + /// + /// # Arguments + /// + /// * `password` - the password used to encrypt the key and certificate + /// * `friendly_name` - user defined name for the certificate + /// * `pkey` - key to store + /// * `cert` - certificate to store + pub fn builder<'a, 'b, 'c, 'd>(password: &'a str, + friendly_name: &'b str, + pkey: &'c PKeyRef, + cert: &'d X509) -> Pkcs12Builder<'a, 'b, 'c, 'd> { + ffi::init(); + + Pkcs12Builder { + password: password, + friendly_name: friendly_name, + pkey: pkey, + cert: cert, + chain: None, + nid_key: nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC, + nid_cert: nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC, + iter: ffi::PKCS12_DEFAULT_ITER as usize, // 2048 + mac_iter: ffi::PKCS12_DEFAULT_ITER as usize, // 2048 + } + } } pub struct ParsedPkcs12 { @@ -69,32 +103,8 @@ pub struct Pkcs12Builder<'a, 'b, 'c, 'd> { mac_iter: usize, } +// TODO: add chain option impl<'a, 'b, 'c, 'd> Pkcs12Builder<'a, 'b, 'c, 'd> { - /// Creates a new builder for a protected pkcs12 certificate. - /// - /// This uses the defaults from the OpenSSL library: - /// - /// * `nid_key` - `nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC` - /// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC` - /// * `iter` - `2048` - /// * `mac_iter` - `2048` - pub fn new(password: &'a str, - friendly_name: &'b str, - pkey: &'c PKeyRef, - cert: &'d X509) -> Self { - Pkcs12Builder { - password: password, - friendly_name: friendly_name, - pkey: pkey, - cert: cert, - chain: None, - nid_key: nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC, - nid_cert: nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC, - iter: 0, // 2048 - mac_iter: 0, // 2048 - } - } - /// The encryption algorithm that should be used for the key pub fn nid_key(&mut self, nid: nid::Nid) { self.nid_key = nid; @@ -105,10 +115,15 @@ impl<'a, 'b, 'c, 'd> Pkcs12Builder<'a, 'b, 'c, 'd> { self.nid_cert = nid; } + /// Key iteration count, default is 2048 as of this writing pub fn iter(&mut self, iter: usize) { self.iter = iter; } + /// Mac iteration count, default is the same as key_iter default. + /// + /// Old implementation 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: usize) { self.mac_iter = mac_iter; } @@ -188,7 +203,7 @@ mod test { let cert = gen.sign(&pkey).unwrap(); - let pkcs12_builder = Pkcs12Builder::new("mypass", subject_name, &pkey, &cert); + let pkcs12_builder = Pkcs12::builder("mypass", subject_name, &pkey, &cert); let pkcs12 = pkcs12_builder.build().unwrap(); let der = pkcs12.to_der().unwrap(); From 540387d5ee074a22a686da704a8f0bac85e02fa5 Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Sun, 22 Jan 2017 22:43:27 -0800 Subject: [PATCH 115/140] fix ptr types --- openssl-sys/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index f12e1f2d..7413be10 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1977,9 +1977,9 @@ extern { pub fn d2i_PKCS12(a: *mut *mut PKCS12, pp: *mut *const u8, length: c_long) -> *mut PKCS12; pub fn PKCS12_create(pass: *const c_char, friendly_name: *const c_char, - pkey: *const EVP_PKEY, - cert: *const X509, - ca: *const stack_st_X509, + pkey: *mut EVP_PKEY, + cert: *mut X509, + ca: *mut stack_st_X509, nid_key: c_int, nid_cert: c_int, iter: c_int, From 591022a7fa4b43d152154fd95bb67fce5ecfa28e Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Mon, 23 Jan 2017 22:12:11 -0800 Subject: [PATCH 116/140] fix multi-version compat --- openssl-sys/src/lib.rs | 11 ------- openssl-sys/src/libressl.rs | 12 +++++++ openssl-sys/src/ossl10x.rs | 12 +++++++ openssl-sys/src/ossl110.rs | 12 +++++++ openssl/src/pkcs12.rs | 62 ++++++++++++++++--------------------- 5 files changed, 63 insertions(+), 46 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 7413be10..01be1b23 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -55,7 +55,6 @@ pub enum X509_REQ {} pub enum X509_STORE {} pub enum X509_STORE_CTX {} pub enum bio_st {} -pub enum PKCS12 {} pub enum DH_METHOD {} pub enum RSA_METHOD {} pub enum BN_MONT_CTX {} @@ -1975,16 +1974,6 @@ extern { pub fn i2d_PKCS12_bio(b: *mut BIO, a: *mut PKCS12) -> c_int; pub fn i2d_PKCS12(a: *mut PKCS12, buf: *mut *mut u8) -> c_int; pub fn d2i_PKCS12(a: *mut *mut PKCS12, pp: *mut *const u8, length: c_long) -> *mut PKCS12; - pub fn PKCS12_create(pass: *const c_char, - friendly_name: *const c_char, - pkey: *mut EVP_PKEY, - cert: *mut X509, - ca: *mut stack_st_X509, - nid_key: c_int, - nid_cert: c_int, - iter: c_int, - mac_iter: c_int, - keytype: c_int) -> *mut PKCS12; pub fn PKCS12_parse(p12: *mut PKCS12, pass: *const c_char, pkey: *mut *mut EVP_PKEY, diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index c1411e60..2862a47e 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -508,6 +508,7 @@ pub struct X509_VERIFY_PARAM { } pub enum X509_VERIFY_PARAM_ID {} +pub enum PKCS12 {} pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; @@ -637,6 +638,17 @@ extern { pub fn OCSP_cert_to_id(dgst: *const ::EVP_MD, subject: *mut ::X509, issuer: *mut ::X509) -> *mut ::OCSP_CERTID; + pub fn PKCS12_create(pass: *mut c_char, + friendly_name: *mut c_char, + pkey: *mut EVP_PKEY, + cert: *mut X509, + ca: *mut stack_st_X509, + nid_key: c_int, + nid_cert: c_int, + iter: c_int, + mac_iter: c_int, + keytype: c_int) -> *mut PKCS12; + pub fn SSL_library_init() -> c_int; pub fn SSL_load_error_strings(); pub fn OPENSSL_add_all_algorithms_noconf(); diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index f721daaa..14b7c414 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -653,6 +653,7 @@ pub struct X509_VERIFY_PARAM { #[cfg(not(ossl101))] pub enum X509_VERIFY_PARAM_ID {} +pub enum PKCS12 {} pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; @@ -782,6 +783,17 @@ extern { pub fn OCSP_cert_to_id(dgst: *const ::EVP_MD, subject: *mut ::X509, issuer: *mut ::X509) -> *mut ::OCSP_CERTID; + pub fn PKCS12_create(pass: *mut c_char, + friendly_name: *mut c_char, + pkey: *mut EVP_PKEY, + cert: *mut X509, + ca: *mut stack_st_X509, + nid_key: c_int, + nid_cert: c_int, + iter: c_int, + mac_iter: c_int, + keytype: c_int) -> *mut PKCS12; + pub fn SSL_library_init() -> c_int; pub fn SSL_load_error_strings(); pub fn OPENSSL_add_all_algorithms_noconf(); diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index 75c6253e..b7fdebab 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -11,6 +11,7 @@ pub enum EVP_MD_CTX {} pub enum EVP_PKEY {} pub enum HMAC_CTX {} pub enum OPENSSL_STACK {} +pub enum PKCS12 {} pub enum RSA {} pub enum SSL {} pub enum SSL_CTX {} @@ -179,4 +180,15 @@ extern { pub fn OPENSSL_sk_free(st: *mut ::OPENSSL_STACK); pub fn OPENSSL_sk_pop_free(st: *mut ::OPENSSL_STACK, free: Option); pub fn OPENSSL_sk_pop(st: *mut ::OPENSSL_STACK) -> *mut c_void; + + pub fn PKCS12_create(pass: *const c_char, + friendly_name: *const c_char, + pkey: *mut EVP_PKEY, + cert: *mut X509, + ca: *mut stack_st_X509, + nid_key: c_int, + nid_cert: c_int, + iter: c_int, + mac_iter: c_int, + keytype: c_int) -> *mut PKCS12; } diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index fecef27a..1b847bb6 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -10,7 +10,7 @@ use pkey::{PKey, PKeyRef}; use error::ErrorStack; use x509::X509; use types::{OpenSslType, OpenSslTypeRef}; -use stack::{Stack, StackRef}; +use stack::Stack; use nid; type_!(Pkcs12, Pkcs12Ref, ffi::PKCS12, ffi::PKCS12_free); @@ -58,25 +58,10 @@ impl Pkcs12 { /// * `nid_cert` - `nid::PBE_WITHSHA1AND40BITRC2_CBC` /// * `iter` - `2048` /// * `mac_iter` - `2048` - /// - /// # Arguments - /// - /// * `password` - the password used to encrypt the key and certificate - /// * `friendly_name` - user defined name for the certificate - /// * `pkey` - key to store - /// * `cert` - certificate to store - pub fn builder<'a, 'b, 'c, 'd>(password: &'a str, - friendly_name: &'b str, - pkey: &'c PKeyRef, - cert: &'d X509) -> Pkcs12Builder<'a, 'b, 'c, 'd> { + pub fn builder() -> Pkcs12Builder { ffi::init(); Pkcs12Builder { - password: password, - friendly_name: friendly_name, - pkey: pkey, - cert: cert, - chain: None, nid_key: nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC, nid_cert: nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC, iter: ffi::PKCS12_DEFAULT_ITER as usize, // 2048 @@ -91,20 +76,15 @@ pub struct ParsedPkcs12 { pub chain: Stack, } -pub struct Pkcs12Builder<'a, 'b, 'c, 'd> { - password: &'a str, - friendly_name: &'b str, - pkey: &'c PKeyRef, - cert: &'d X509, - chain: Option>, +// TODO: add ca chain +pub struct Pkcs12Builder { nid_key: nid::Nid, nid_cert: nid::Nid, iter: usize, mac_iter: usize, } -// TODO: add chain option -impl<'a, 'b, 'c, 'd> Pkcs12Builder<'a, 'b, 'c, 'd> { +impl Pkcs12Builder { /// The encryption algorithm that should be used for the key pub fn nid_key(&mut self, nid: nid::Nid) { self.nid_key = nid; @@ -128,13 +108,25 @@ impl<'a, 'b, 'c, 'd> Pkcs12Builder<'a, 'b, 'c, 'd> { self.mac_iter = mac_iter; } - pub fn build(self) -> Result { + /// Builds the pkcs12 object + /// + /// # Arguments + /// + /// * `password` - the password used to encrypt the key and certificate + /// * `friendly_name` - user defined name for the certificate + /// * `pkey` - key to store + /// * `cert` - certificate to store + pub fn build(self, + password: &str, + friendly_name: &str, + pkey: &PKeyRef, + cert: &X509) -> Result { unsafe { - let pass = CString::new(self.password).unwrap(); - let friendly_name = CString::new(self.friendly_name).unwrap(); - let pkey = self.pkey.as_ptr(); - let cert = self.cert.as_ptr(); - let ca = self.chain.map(|ca| ca.as_ptr()).unwrap_or(ptr::null_mut()); + let pass = CString::new(password).unwrap(); + let friendly_name = CString::new(friendly_name).unwrap(); + let pkey = pkey.as_ptr(); + let cert = cert.as_ptr(); + let ca = ptr::null_mut(); // TODO: should allow for a chain to be set in the builder let nid_key = self.nid_key.as_raw(); let nid_cert = self.nid_cert.as_raw(); @@ -143,8 +135,8 @@ impl<'a, 'b, 'c, 'd> Pkcs12Builder<'a, 'b, 'c, 'd> { // https://www.openssl.org/docs/man1.0.2/crypto/PKCS12_create.html let keytype = 0; - let pkcs12_ptr = ffi::PKCS12_create(pass.as_ptr(), - friendly_name.as_ptr(), + let pkcs12_ptr = ffi::PKCS12_create(pass.as_ptr() as *const _ as *mut _, + friendly_name.as_ptr() as *const _ as *mut _, pkey, cert, ca, @@ -203,8 +195,8 @@ mod test { let cert = gen.sign(&pkey).unwrap(); - let pkcs12_builder = Pkcs12::builder("mypass", subject_name, &pkey, &cert); - let pkcs12 = pkcs12_builder.build().unwrap(); + let pkcs12_builder = Pkcs12::builder(); + let pkcs12 = pkcs12_builder.build("mypass", subject_name, &pkey, &cert).unwrap(); let der = pkcs12.to_der().unwrap(); let pkcs12 = Pkcs12::from_der(&der).unwrap(); From 01e46671756d4e729adb0bfd88f3c98638712b5d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 24 Jan 2017 21:31:41 +0100 Subject: [PATCH 117/140] Make sure to not add system dirs to linkage cc #447 --- openssl-sys/Cargo.toml | 5 +++-- openssl-sys/build.rs | 21 +++++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index fe484a79..1f1750dc 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -15,11 +15,12 @@ build = "build.rs" libc = "0.2" [build-dependencies] -metadeps = "1" +pkg-config = "0.3.9" [target.'cfg(windows)'.dependencies] user32-sys = "0.2" gdi32-sys = "0.2" +# We don't actually use metadeps for annoying reasons but this is still hear for tooling [package.metadata.pkg-config] -openssl = "1.0.0" # We actually need 1.0.1, but OpenBSD reports as 1.0.0 +openssl = "1.0.1" diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index c59a76d4..0e1cdc46 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -1,4 +1,4 @@ -extern crate metadeps; +extern crate pkg_config; use std::collections::HashSet; use std::env; @@ -172,8 +172,16 @@ fn try_pkg_config() { // cflags dirs for showing us lots of `-I`. env::set_var("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS", "1"); - let lib = match metadeps::probe() { - Ok(mut libs) => libs.remove("openssl").unwrap(), + // This is more complex than normal because we need to track down opensslconf.h. + // To do that, we need the inlude paths even if they're on the default search path, but the + // linkage directories emitted from that cause all kinds of issues if other libraries happen to + // live in them. So, we run pkg-config twice, once asking for system dirs but not emitting + // metadata, and a second time emitting metadata but not asking for system dirs. Yay. + let lib = match pkg_config::Config::new() + .cargo_metadata(false) + .print_system_libs(true) + .find("openssl") { + Ok(lib) => lib, Err(_) => return, }; @@ -196,7 +204,7 @@ specific to your distribution: sudo dnf install openssl-devel See rust-openssl README for more information: - + https://github.com/sfackler/rust-openssl#linux "); } @@ -207,6 +215,11 @@ See rust-openssl README for more information: println!("cargo:include={}", include.display()); } + pkg_config::Config::new() + .print_system_libs(false) + .find("openssl") + .unwrap(); + std::process::exit(0); } From 15b1b348b29590ec9221f1dfdb164651c2e21b29 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 25 Jan 2017 11:13:59 +0000 Subject: [PATCH 118/140] Pkcs12Builder tweaks --- openssl/src/pkcs12.rs | 61 ++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index 1b847bb6..44a67af0 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -5,7 +5,7 @@ use libc::c_int; use std::ptr; use std::ffi::CString; -use cvt; +use {cvt, cvt_p}; use pkey::{PKey, PKeyRef}; use error::ErrorStack; use x509::X509; @@ -64,8 +64,9 @@ impl Pkcs12 { Pkcs12Builder { nid_key: nid::UNDEF, //nid::PBE_WITHSHA1AND3_KEY_TRIPLEDES_CBC, nid_cert: nid::UNDEF, //nid::PBE_WITHSHA1AND40BITRC2_CBC, - iter: ffi::PKCS12_DEFAULT_ITER as usize, // 2048 - mac_iter: ffi::PKCS12_DEFAULT_ITER as usize, // 2048 + iter: ffi::PKCS12_DEFAULT_ITER, + mac_iter: ffi::PKCS12_DEFAULT_ITER, + ca: None, } } } @@ -76,39 +77,50 @@ pub struct ParsedPkcs12 { pub chain: Stack, } -// TODO: add ca chain pub struct Pkcs12Builder { nid_key: nid::Nid, nid_cert: nid::Nid, - iter: usize, - mac_iter: usize, + iter: c_int, + mac_iter: c_int, + ca: Option>, } impl Pkcs12Builder { /// The encryption algorithm that should be used for the key - pub fn nid_key(&mut self, nid: nid::Nid) { + pub fn key_algorithm(&mut self, nid: nid::Nid) -> &mut Self { self.nid_key = nid; + self } /// The encryption algorithm that should be used for the cert - pub fn nid_cert(&mut self, nid: nid::Nid) { + pub fn cert_algorithm(&mut self, nid: nid::Nid) -> &mut Self { self.nid_cert = nid; + self } /// Key iteration count, default is 2048 as of this writing - pub fn iter(&mut self, iter: usize) { - self.iter = iter; + 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 default. + /// MAC iteration count, default is the same as key_iter. /// - /// Old implementation 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: usize) { - self.mac_iter = mac_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 } - /// Builds the pkcs12 object + /// An additional set of certificates to include in the archive beyond the one provided to + /// `build`. + pub fn ca(&mut self, ca: Stack) -> &mut Self { + self.ca = Some(ca); + self + } + + /// Builds the PKCS #12 object /// /// # Arguments /// @@ -126,7 +138,7 @@ impl Pkcs12Builder { let friendly_name = CString::new(friendly_name).unwrap(); let pkey = pkey.as_ptr(); let cert = cert.as_ptr(); - let ca = ptr::null_mut(); // TODO: should allow for a chain to be set in the builder + 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(); @@ -135,22 +147,17 @@ impl Pkcs12Builder { // https://www.openssl.org/docs/man1.0.2/crypto/PKCS12_create.html let keytype = 0; - let pkcs12_ptr = ffi::PKCS12_create(pass.as_ptr() as *const _ as *mut _, + cvt_p(ffi::PKCS12_create(pass.as_ptr() as *const _ as *mut _, friendly_name.as_ptr() as *const _ as *mut _, pkey, cert, ca, nid_key, nid_cert, - self.iter as c_int, - self.mac_iter as c_int, - keytype); - - if pkcs12_ptr.is_null() { - Err(ErrorStack::get()) - } else { - Ok(Pkcs12::from_ptr(pkcs12_ptr)) - } + self.iter, + self.mac_iter, + keytype)) + .map(Pkcs12) } } } From 557b936e27177718b62d31dcf3364f481bb15c2c Mon Sep 17 00:00:00 2001 From: mredlek Date: Thu, 26 Jan 2017 20:59:32 +0100 Subject: [PATCH 119/140] Added X509ReqRef.subject_name and X509ReqRef.version --- openssl-sys/src/lib.rs | 4 +++- openssl-sys/src/libressl.rs | 17 +++++++++++++++++ openssl-sys/src/ossl10x.rs | 17 +++++++++++++++++ openssl-sys/src/ossl110.rs | 6 ++++++ openssl/src/asn1.rs | 22 ++++++++++++++++++++++ openssl/src/x509/mod.rs | 27 +++++++++++++++++++++++++++ openssl/src/x509/tests.rs | 9 +++++++-- 7 files changed, 99 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 01be1b23..e801ca98 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -51,7 +51,6 @@ pub enum X509_CRL {} pub enum X509_EXTENSION {} pub enum X509_NAME {} pub enum X509_NAME_ENTRY {} -pub enum X509_REQ {} pub enum X509_STORE {} pub enum X509_STORE_CTX {} pub enum bio_st {} @@ -1387,6 +1386,7 @@ extern { pub fn AES_set_decrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; pub fn AES_ige_encrypt(in_: *const c_uchar, out: *mut c_uchar, length: size_t, key: *const AES_KEY, ivec: *mut c_uchar, enc: c_int); + pub fn ASN1_INTEGER_get(dest: *mut ASN1_INTEGER) -> c_long; pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; @@ -1918,6 +1918,8 @@ extern { pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + pub fn ASN1_INTEGER_free(x: *mut ASN1_INTEGER); + pub fn X509_STORE_new() -> *mut X509_STORE; pub fn X509_STORE_free(store: *mut X509_STORE); pub fn X509_STORE_add_cert(store: *mut X509_STORE, x: *mut X509) -> c_int; diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index 2862a47e..0767df0d 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -298,6 +298,23 @@ pub struct X509_VAL { pub notAfter: *mut ::ASN1_TIME, } +#[repr(C)] +pub struct X509_REQ_INFO { + pub enc: ASN1_ENCODING, + pub version: *mut ::ASN1_INTEGER, + pub subject: *mut ::X509_NAME, + pub pubkey: *mut c_void, + pub attributes: *mut stack_st_X509_ATTRIBUTE +} + +#[repr(C)] +pub struct X509_REQ { + pub req_info: *mut X509_REQ_INFO, + pub sig_alg: *mut c_void, + pub signature: *mut c_void, + references: c_int +} + #[repr(C)] pub struct SSL { version: c_int, diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 14b7c414..d9729b0d 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -305,6 +305,23 @@ pub struct X509_VAL { pub notAfter: *mut ::ASN1_TIME, } +#[repr(C)] +pub struct X509_REQ_INFO { + pub enc: ASN1_ENCODING, + pub version: *mut ::ASN1_INTEGER, + pub subject: *mut ::X509_NAME, + pub pubkey: *mut c_void, + pub attributes: *mut stack_st_X509_ATTRIBUTE +} + +#[repr(C)] +pub struct X509_REQ { + pub req_info: *mut X509_REQ_INFO, + pub sig_alg: *mut c_void, + pub signature: *mut c_void, + references: c_int +} + #[repr(C)] pub struct SSL { version: c_int, diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index b7fdebab..c3c95fa4 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -27,6 +27,7 @@ pub enum stack_st_X509_EXTENSION {} pub enum stack_st_SSL_CIPHER {} pub enum X509 {} pub enum X509_VERIFY_PARAM {} +pub enum X509_REQ {} pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000000; pub const SSL_OP_NETSCAPE_CHALLENGE_BUG: c_ulong = 0x00000000; @@ -191,4 +192,9 @@ extern { iter: c_int, mac_iter: c_int, keytype: c_int) -> *mut PKCS12; + pub fn X509_REQ_get_version(req: *const X509_REQ) -> c_long; + pub fn X509_REQ_set_version(x: *mut X509_REQ, version: c_long) -> c_int; + pub fn X509_REQ_get_subject_name(req: *const X509_REQ) -> *mut ::X509_NAME; + pub fn X509_REQ_set_subject_name(req: *mut X509_REQ, name: *mut ::X509_NAME) -> c_int; + } diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index d177885e..f5d6a102 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -75,6 +75,28 @@ impl Asn1StringRef { } } +type_!(Asn1Integer, Asn1IntegerRef, ffi::ASN1_INTEGER, ffi::ASN1_INTEGER_free); + +impl Asn1IntegerRef { + pub fn get(&self) -> i64 { + unsafe { + return ::ffi::ASN1_INTEGER_get(self.as_ptr()); + } + } + + pub fn set(&self, value: i64) -> Result<(), ErrorStack> + { + unsafe { + let res = ::ffi::ASN1_INTEGER_set(self.as_ptr(), value); + if res < 0 { + return Err(ErrorStack::get()); + } + + Ok(()) + } + } +} + #[cfg(any(ossl101, ossl102))] use ffi::ASN1_STRING_data; diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index e75dcf5d..2edfa675 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -599,6 +599,21 @@ impl X509Req { impl X509ReqRef { to_pem!(ffi::PEM_write_bio_X509_REQ); to_der!(ffi::i2d_X509_REQ); + + pub fn version(&self) -> i64 + { + unsafe { + let version = compat::X509_REQ_get_version(self.as_ptr()); + version + } + } + + pub fn subject_name(&self) -> &X509NameRef { + unsafe { + let name = compat::X509_REQ_get_subject_name(self.as_ptr()); + X509NameRef::from_ptr(name) + } + } } /// A collection of X.509 extensions. @@ -779,6 +794,8 @@ mod compat { pub use ffi::X509_getm_notBefore as X509_get_notBefore; pub use ffi::X509_up_ref; pub use ffi::X509_get0_extensions; + pub use ffi::X509_REQ_get_version; + pub use ffi::X509_REQ_get_subject_name; } #[cfg(ossl10x)] @@ -812,4 +829,14 @@ mod compat { (*info).extensions } } + + pub unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long + { + ::ffi::ASN1_INTEGER_get((*(*x).req_info).version) + } + + pub unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME + { + (*(*x).req_info).subject + } } diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 01cbf2ec..14fbb173 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -6,7 +6,7 @@ use nid::X9_62_PRIME256V1; use pkey::PKey; use rsa::Rsa; use ssl::{SslMethod, SslContextBuilder}; -use x509::{X509, X509Generator}; +use x509::{X509, X509Generator, X509Req}; use x509::extension::Extension::{KeyUsage, ExtKeyUsage, SubjectAltName, OtherNid, OtherStr}; use x509::extension::AltNameOption as SAN; use x509::extension::KeyUsageOption::{DigitalSignature, KeyEncipherment}; @@ -75,7 +75,12 @@ fn test_req_gen() { let pkey = pkey(); let req = get_generator().request(&pkey).unwrap(); - req.to_pem().unwrap(); + let reqpem = req.to_pem().unwrap(); + + let req = X509Req::from_pem(&reqpem).ok().expect("Failed to load PEM"); + let cn = (*req).subject_name().entries_by_nid(nid::COMMONNAME).next().unwrap(); + assert_eq!(0, (*req).version()); + assert_eq!(cn.data().as_slice(), b"test_me"); // FIXME: check data in result to be correct, needs implementation // of X509_REQ getters From 6a8f6f425f504459a6f4c54eac273f543c53a55e Mon Sep 17 00:00:00 2001 From: mredlek Date: Fri, 27 Jan 2017 19:11:05 +0100 Subject: [PATCH 120/140] Style changes according to review --- openssl-sys/src/lib.rs | 2 +- openssl-sys/src/libressl.rs | 6 +++--- openssl-sys/src/ossl10x.rs | 6 +++--- openssl/src/asn1.rs | 11 +++-------- openssl/src/x509/mod.rs | 5 ++--- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index e801ca98..47bc314c 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1386,7 +1386,7 @@ extern { pub fn AES_set_decrypt_key(userKey: *const c_uchar, bits: c_int, key: *mut AES_KEY) -> c_int; pub fn AES_ige_encrypt(in_: *const c_uchar, out: *mut c_uchar, length: size_t, key: *const AES_KEY, ivec: *mut c_uchar, enc: c_int); - pub fn ASN1_INTEGER_get(dest: *mut ASN1_INTEGER) -> c_long; + pub fn ASN1_INTEGER_get(dest: *const ASN1_INTEGER) -> c_long; pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index 0767df0d..fd115a98 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -303,15 +303,15 @@ pub struct X509_REQ_INFO { pub enc: ASN1_ENCODING, pub version: *mut ::ASN1_INTEGER, pub subject: *mut ::X509_NAME, - pub pubkey: *mut c_void, + pubkey: *mut c_void, pub attributes: *mut stack_st_X509_ATTRIBUTE } #[repr(C)] pub struct X509_REQ { pub req_info: *mut X509_REQ_INFO, - pub sig_alg: *mut c_void, - pub signature: *mut c_void, + sig_alg: *mut c_void, + signature: *mut c_void, references: c_int } diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index d9729b0d..0b3376d0 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -310,15 +310,15 @@ pub struct X509_REQ_INFO { pub enc: ASN1_ENCODING, pub version: *mut ::ASN1_INTEGER, pub subject: *mut ::X509_NAME, - pub pubkey: *mut c_void, + pubkey: *mut c_void, pub attributes: *mut stack_st_X509_ATTRIBUTE } #[repr(C)] pub struct X509_REQ { pub req_info: *mut X509_REQ_INFO, - pub sig_alg: *mut c_void, - pub signature: *mut c_void, + sig_alg: *mut c_void, + signature: *mut c_void, references: c_int } diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index f5d6a102..dc616b59 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -80,19 +80,14 @@ type_!(Asn1Integer, Asn1IntegerRef, ffi::ASN1_INTEGER, ffi::ASN1_INTEGER_free); impl Asn1IntegerRef { pub fn get(&self) -> i64 { unsafe { - return ::ffi::ASN1_INTEGER_get(self.as_ptr()); + ::ffi::ASN1_INTEGER_get(self.as_ptr()) as i64 } } - pub fn set(&self, value: i64) -> Result<(), ErrorStack> + pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> { unsafe { - let res = ::ffi::ASN1_INTEGER_set(self.as_ptr(), value); - if res < 0 { - return Err(ErrorStack::get()); - } - - Ok(()) + cvt(::ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } } } diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 2edfa675..23d9bcaa 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -600,11 +600,10 @@ impl X509ReqRef { to_pem!(ffi::PEM_write_bio_X509_REQ); to_der!(ffi::i2d_X509_REQ); - pub fn version(&self) -> i64 + pub fn version(&self) -> i32 { unsafe { - let version = compat::X509_REQ_get_version(self.as_ptr()); - version + compat::X509_REQ_get_version(self.as_ptr()) as i32 } } From f5149eac5a5746c1cb45edab445ab0d240d33c86 Mon Sep 17 00:00:00 2001 From: mredlek Date: Fri, 27 Jan 2017 20:55:40 +0100 Subject: [PATCH 121/140] Add setters to new getter-functions in X509ReqRef --- openssl-sys/src/lib.rs | 3 +++ openssl-sys/src/ossl110.rs | 3 --- openssl/src/x509/mod.rs | 13 +++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 47bc314c..1340a63f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1935,6 +1935,9 @@ extern { pub fn X509_REQ_add_extensions(req: *mut X509_REQ, exts: *mut stack_st_X509_EXTENSION) -> c_int; pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; + pub fn X509_REQ_set_version(x: *mut X509_REQ, version: c_long) -> c_int; + pub fn X509_REQ_set_subject_name(req: *mut X509_REQ, name: *mut ::X509_NAME) -> c_int; + #[cfg(not(ossl101))] pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM); diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index c3c95fa4..84f08f29 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -193,8 +193,5 @@ extern { mac_iter: c_int, keytype: c_int) -> *mut PKCS12; pub fn X509_REQ_get_version(req: *const X509_REQ) -> c_long; - pub fn X509_REQ_set_version(x: *mut X509_REQ, version: c_long) -> c_int; pub fn X509_REQ_get_subject_name(req: *const X509_REQ) -> *mut ::X509_NAME; - pub fn X509_REQ_set_subject_name(req: *mut X509_REQ, name: *mut ::X509_NAME) -> c_int; - } diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 23d9bcaa..c08fc337 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -607,12 +607,25 @@ impl X509ReqRef { } } + pub fn set_version(&mut self, value: i32) -> Result<(), ErrorStack> + { + unsafe { + cvt(ffi::X509_REQ_set_version(self.as_ptr(), value as c_long)).map(|_| ()) + } + } + pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = compat::X509_REQ_get_subject_name(self.as_ptr()); X509NameRef::from_ptr(name) } } + + pub fn set_subject_name(&self, value: &X509NameRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::X509_REQ_set_subject_name(self.as_ptr(), value.as_ptr())).map(|_| ()) + } + } } /// A collection of X.509 extensions. From 0598561f0ec961001cb5b5a67a945ec39b7b2cd7 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 28 Jan 2017 17:49:41 -0800 Subject: [PATCH 122/140] Macro-expand OpenSSL headers for feature checks Closes #564 --- openssl-sys/Cargo.toml | 3 +- openssl-sys/build.rs | 230 +++++++++++++++++++---------------------- 2 files changed, 109 insertions(+), 124 deletions(-) diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 1f1750dc..76bd9172 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -16,11 +16,12 @@ libc = "0.2" [build-dependencies] pkg-config = "0.3.9" +gcc = "0.3.42" [target.'cfg(windows)'.dependencies] user32-sys = "0.2" gdi32-sys = "0.2" -# We don't actually use metadeps for annoying reasons but this is still hear for tooling +# We don't actually use metadeps for annoying reasons but this is still here for tooling [package.metadata.pkg-config] openssl = "1.0.1" diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index 0e1cdc46..1b717693 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -1,13 +1,37 @@ extern crate pkg_config; +extern crate gcc; use std::collections::HashSet; use std::env; use std::ffi::OsString; use std::fs::File; -use std::io::Read; +use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; use std::process::Command; +// The set of `OPENSSL_NO_`s that we care about. +const DEFINES: &'static [&'static str] = &[ + "OPENSSL_NO_BUF_FREELISTS", + "OPENSSL_NO_COMP", + "OPENSSL_NO_EC", + "OPENSSL_NO_ENGINE", + "OPENSSL_NO_KRB5", + "OPENSSL_NO_NEXTPROTONEG", + "OPENSSL_NO_PSK", + "OPENSSL_NO_RFC3779", + "OPENSSL_NO_SHA", + "OPENSSL_NO_SRP", + "OPENSSL_NO_SSL3_METHOD", + "OPENSSL_NO_TLSEXT", +]; + +enum Version { + Openssl110, + Openssl102, + Openssl101, + Libressl, +} + fn main() { let target = env::var("TARGET").unwrap(); @@ -38,17 +62,14 @@ fn main() { println!("cargo:rustc-link-search=native={}", lib_dir.to_string_lossy()); println!("cargo:include={}", include_dir.to_string_lossy()); - let version = validate_headers(&[include_dir.clone().into()], - &[lib_dir.clone().into()]); + let version = validate_headers(&[include_dir.clone().into()]); - let libs = if (version.contains("0x10001") || - version.contains("0x10002")) && - target.contains("windows") { - ["ssleay32", "libeay32"] - } else if target.contains("windows") { - ["libssl", "libcrypto"] - } else { - ["ssl", "crypto"] + let libs = match version { + Version::Openssl101 | Version::Openssl102 if target.contains("windows") => { + ["ssleay32", "libeay32"] + } + Version::Openssl110 if target.contains("windows") => ["libssl", "libcrypto"], + _ => ["ssl", "crypto"], }; let kind = determine_mode(Path::new(&lib_dir), &libs); @@ -209,7 +230,7 @@ See rust-openssl README for more information: "); } - validate_headers(&lib.include_paths, &lib.link_paths); + validate_headers(&lib.include_paths); for include in lib.include_paths.iter() { println!("cargo:include={}", include.display()); @@ -225,74 +246,11 @@ See rust-openssl README for more information: /// Validates the header files found in `include_dir` and then returns the /// version string of OpenSSL. -fn validate_headers(include_dirs: &[PathBuf], - libdirs: &[PathBuf]) -> String { +fn validate_headers(include_dirs: &[PathBuf]) -> Version { // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, and 1.1.0. To // correctly expose the right API from this crate, take a look at // `opensslv.h` to see what version OpenSSL claims to be. - let mut version_header = String::new(); - let mut include = include_dirs.iter() - .map(|p| p.join("openssl/opensslv.h")) - .filter(|p| p.exists()); - let mut f = match include.next() { - Some(f) => File::open(f).unwrap(), - None => { - panic!("failed to open header file at `openssl/opensslv.h` to learn - about OpenSSL's version number, looked inside:\n\n{:#?}\n\n", - include_dirs); - } - }; - f.read_to_string(&mut version_header).unwrap(); - - // Do a bit of string parsing to find `#define OPENSSL_VERSION_NUMBER ...` - let version_line = version_header.lines().find(|l| { - l.contains("define ") && l.contains("OPENSSL_VERSION_NUMBER") - }).and_then(|line| { - let start = match line.find("0x") { - Some(start) => start, - None => return None, - }; - Some(line[start..].trim()) - }); - let version_text = match version_line { - Some(text) => text, - None => { - panic!("header file at `{}` did not include `OPENSSL_VERSION_NUMBER` \ - that this crate recognized, failed to learn about the \ - OpenSSL version number"); - } - }; - if version_text.contains("0x10001") { - println!("cargo:rustc-cfg=ossl101"); - println!("cargo:version=101"); - } else if version_text.contains("0x10002") { - println!("cargo:rustc-cfg=ossl102"); - println!("cargo:version=102"); - } else if version_text.contains("0x10100") { - println!("cargo:rustc-cfg=ossl110"); - println!("cargo:version=110"); - } else if version_text.contains("0x20000000L") { - // Check if it is really LibreSSL - if version_header.lines().any(|l| { - l.contains("define ") && l.contains("LIBRESSL_VERSION_NUMBER") - }) { - println!("cargo:rustc-cfg=libressl"); - println!("cargo:libressl=true"); - println!("cargo:version=101"); - } - } else { - panic!(" - -This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, but a -different version of OpenSSL was found: - - {} - -The build is now aborting due to this version mismatch. - -", version_text); - } - + // // OpenSSL has a number of build-time configuration options which affect // various structs and such. Since OpenSSL 1.1.0 this isn't really a problem // as the library is much more FFI-friendly, but 1.0.{1,2} suffer this problem. @@ -301,56 +259,82 @@ The build is now aborting due to this version mismatch. // file of OpenSSL, `opensslconf.h`, and then dump out everything it defines // as our own #[cfg] directives. That way the `ossl10x.rs` bindings can // account for compile differences and such. - let mut conf_header = String::new(); - let mut include = include_dirs.iter() - .map(|p| p.join("openssl/opensslconf.h")) - .filter(|p| p.exists()); - let mut f = match include.next() { - Some(f) => File::open(f).unwrap(), - None => { - // It's been seen that on linux the include dir printed out by - // `pkg-config` doesn't actually have opensslconf.h. Instead - // it's in an architecture-specific include directory. - // - // Try to detect that case to see if it exists. - let mut libdirs = libdirs.iter().map(|p| { - p.iter() - .map(|p| if p == "lib" {"include".as_ref()} else {p}) - .collect::() - }).map(|p| { - p.join("openssl/opensslconf.h") - }).filter(|p| p.exists()); - match libdirs.next() { - Some(f) => File::open(f).unwrap(), - None => { - panic!("failed to open header file at - `openssl/opensslconf.h` to learn about \ - OpenSSL's version number, looked \ - inside:\n\n{:#?}\n\n", - include_dirs); - } - } - } - }; - f.read_to_string(&mut conf_header).unwrap(); + let mut path = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + path.push("expando.c"); + let mut file = BufWriter::new(File::create(&path).unwrap()); - // Look for `#define OPENSSL_FOO`, print out everything as our own - // #[cfg] flag. - let mut vars = vec![]; - for line in conf_header.lines() { - let i = match line.find("define ") { - Some(i) => i, - None => continue, - }; - let var = line[i + "define ".len()..].trim(); - if var.starts_with("OPENSSL") && !var.contains(" ") { - println!("cargo:rustc-cfg=osslconf=\"{}\"", var); - vars.push(var); + write!(file, "\ +#include +#include + +#ifdef LIBRESSL_VERSION_NUMBER +RUST_LIBRESSL +#elif OPENSSL_VERSION_NUMBER >= 0x10200000 +RUST_OPENSSL_NEW +#elif OPENSSL_VERSION_NUMBER >= 0x10100000 +RUST_OPENSSL_110 +#elif OPENSSL_VERSION_NUMBER >= 0x10002000 +RUST_OPENSSL_102 +#elif OPENSSL_VERSION_NUMBER >= 0x10001000 +RUST_OPENSSL_101 +#else +RUST_OPENSSL_OLD +#endif +").unwrap(); + + for define in DEFINES { + write!(file, "\ +#ifdef {define} +RUST_{define} +#endif +", define = define).unwrap(); + } + + file.flush().unwrap(); + drop(file); + + let mut gcc = gcc::Config::new(); + for include_dir in include_dirs { + gcc.include(include_dir); + } + let expanded = gcc.file(&path).expand(); + let expanded = String::from_utf8(expanded).unwrap(); + + let mut enabled = vec![]; + for &define in DEFINES { + if expanded.contains(&format!("RUST_{}", define)) { + println!("cargo:rustc-cfg=osslconf=\"{}\"", define); + enabled.push(define); } } - println!("cargo:conf={}", vars.join(",")); + println!("cargo:conf={}", enabled.join(",")); - return version_text.to_string() + if expanded.contains("RUST_LIBRESSL") { + println!("cargo:rustc-cfg=libressl"); + println!("cargo:libressl=true"); + println!("cargo:version=101"); + Version::Libressl + } else if expanded.contains("RUST_OPENSSL_110") { + println!("cargo:rustc-cfg=ossl110"); + println!("cargo:version=110"); + Version::Openssl110 + } else if expanded.contains("RUST_OPENSSL_102") { + println!("cargo:rustc-cfg=ossl102"); + println!("cargo:version=102"); + Version::Openssl102 + } else if expanded.contains("RUST_OPENSSL_101") { + println!("cargo:rustc-cfg=ossl101"); + println!("cargo:version=101"); + Version::Openssl101 + } else { + panic!(" + +This crate is only compatible with OpenSSL 1.0.1, 1.0.2, and 1.1.0, or LibreSSL, +but a different version of OpenSSL was found. The build is now aborting due to +this version mismatch. + +"); + } } /// Given a libdir for OpenSSL (where artifacts are located) as well as the name From caeade39a13697000a2fcf449ee48bfe859848bf Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 28 Jan 2017 20:04:51 -0800 Subject: [PATCH 123/140] Bump test versions --- .travis.yml | 12 ++++++------ appveyor.yml | 8 ++++---- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index e8d89347..795c9370 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,7 +19,7 @@ matrix: # ARM-bit version compat - env: > TARGET=arm-unknown-linux-gnueabihf - BUILD_OPENSSL_VERSION=1.0.2h + BUILD_OPENSSL_VERSION=1.0.2k CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf RUST_TEST_THREADS=1 @@ -32,7 +32,7 @@ matrix: - binfmt-support - env: > TARGET=arm-unknown-linux-gnueabihf - BUILD_OPENSSL_VERSION=1.1.0c + BUILD_OPENSSL_VERSION=1.1.0d CARGO_TARGET_ARM_UNKNOWN_LINUX_GNUEABIHF_LINKER=arm-linux-gnueabihf-gcc QEMU_LD_PREFIX=/usr/arm-linux-gnueabihf RUST_TEST_THREADS=1 @@ -52,8 +52,8 @@ matrix: - rust: nightly # 64-bit version compat - - env: BUILD_OPENSSL_VERSION=1.0.2h - - env: BUILD_OPENSSL_VERSION=1.1.0c + - env: BUILD_OPENSSL_VERSION=1.0.2k + - env: BUILD_OPENSSL_VERSION=1.1.0d # 32-bit version compat - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.1u @@ -61,12 +61,12 @@ matrix: apt: packages: - gcc-multilib - - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2h + - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.0.2k addons: apt: packages: - gcc-multilib - - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0c + - env: TARGET=i686-unknown-linux-gnu BUILD_OPENSSL_VERSION=1.1.0d addons: apt: packages: diff --git a/appveyor.yml b/appveyor.yml index 9b4a3f02..d396bd62 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,20 +5,20 @@ environment: - TARGET: i686-pc-windows-gnu BITS: 32 MSYS2: 1 - OPENSSL_VERSION: 1_1_0c + OPENSSL_VERSION: 1_1_0d - TARGET: x86_64-pc-windows-msvc BITS: 64 - OPENSSL_VERSION: 1_1_0c + OPENSSL_VERSION: 1_1_0d OPENSSL_DIR: C:\OpenSSL # 1.0.2, 64/32 bit - TARGET: x86_64-pc-windows-gnu BITS: 64 MSYS2: 1 - OPENSSL_VERSION: 1_0_2j + OPENSSL_VERSION: 1_0_2k - TARGET: i686-pc-windows-msvc BITS: 32 - OPENSSL_VERSION: 1_0_2j + OPENSSL_VERSION: 1_0_2k OPENSSL_DIR: C:\OpenSSL install: # install OpenSSL From ddc0066211fb9adadd658bd04547dc143dcfbc5a Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Fri, 27 Jan 2017 18:16:22 -0800 Subject: [PATCH 124/140] Add the necessary constants to access the pkey ctx stuff. --- openssl-sys/src/lib.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 01be1b23..6b61aab7 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -151,6 +151,8 @@ pub const EVP_PKEY_DSA: c_int = NID_dsa; pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey; +pub const EVP_PKEY_ALG_CTRL: c_int = 0x1000; + 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_SET_TAG: c_int = 0x11; @@ -1121,6 +1123,10 @@ pub const RSA_NO_PADDING: c_int = 3; pub const RSA_PKCS1_OAEP_PADDING: c_int = 4; pub const RSA_X931_PADDING: c_int = 5; +pub const RSA_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1; + +pub const RSA_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; + pub const SSL_CTRL_SET_TMP_DH: c_int = 3; pub const SSL_CTRL_SET_TMP_ECDH: c_int = 4; pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; @@ -1726,6 +1732,7 @@ extern { pub fn RSA_new() -> *mut RSA; pub fn RSA_free(rsa: *mut RSA); pub fn RSA_generate_key_ex(rsa: *mut RSA, bits: c_int, e: *mut BIGNUM, cb: *mut BN_GENCB) -> c_int; + pub fn RSA_pkey_ctx_ctrl(ctx: *mut EVP_PKEY_CTX, optype: c_int, cmd: c_int, p1: c_int, p2: *mut c_void) -> c_int; pub fn RSA_private_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA, pad: c_int) -> c_int; pub fn RSA_public_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA, @@ -1996,3 +2003,12 @@ extern { md: *mut c_uchar, len: *mut c_uint) -> c_int; } + +// EVP_PKEY_CTX_ctrl macros +unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { + RSA_pkey_ctx_ctrl(ctx, -1, RSA_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) +} + +unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { + RSA_pkey_ctx_ctrl(ctx, -1, RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) +} From 588fd33552f9c84e8ed67c4cff35264b671362d9 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:08:25 -0800 Subject: [PATCH 125/140] Testing first version that works with signer. --- openssl-sys/src/lib.rs | 12 +++++++----- openssl/src/pkey.rs | 6 ++++++ openssl/src/rsa.rs | 19 ++++++++++++++++++- openssl/src/sign.rs | 17 ++++++++++++----- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 6b61aab7..7ef5f7fe 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1638,6 +1638,9 @@ extern { key: *const c_uchar, keylen: c_int) -> *mut EVP_PKEY; + + pub fn EVP_PKEY_CTX_ctrl(ctx: *mut EVP_PKEY_CTX, keytype: c_int, optype: c_int, cmd: c_int, p1: c_int, p2: *mut c_void) -> c_int; + pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int; pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP; @@ -1732,7 +1735,6 @@ extern { pub fn RSA_new() -> *mut RSA; pub fn RSA_free(rsa: *mut RSA); pub fn RSA_generate_key_ex(rsa: *mut RSA, bits: c_int, e: *mut BIGNUM, cb: *mut BN_GENCB) -> c_int; - pub fn RSA_pkey_ctx_ctrl(ctx: *mut EVP_PKEY_CTX, optype: c_int, cmd: c_int, p1: c_int, p2: *mut c_void) -> c_int; pub fn RSA_private_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA, pad: c_int) -> c_int; pub fn RSA_public_decrypt(flen: c_int, from: *const u8, to: *mut u8, k: *mut RSA, @@ -2005,10 +2007,10 @@ extern { } // EVP_PKEY_CTX_ctrl macros -unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { - RSA_pkey_ctx_ctrl(ctx, -1, RSA_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) +pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, RSA_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) } -unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { - RSA_pkey_ctx_ctrl(ctx, -1, RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) +pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) } diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 7a32692b..fd963c24 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -151,6 +151,12 @@ impl PKey { } } +pub struct PKeyCtxRef(::util::Opaque); + +impl ::types::OpenSslTypeRef for PKeyCtxRef { + type CType = ffi::EVP_PKEY_CTX; +} + #[cfg(test)] mod tests { use symm::Cipher; diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 8c3507f4..75893545 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -10,9 +10,10 @@ use bio::MemBioSlice; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; use types::OpenSslTypeRef; +use pkey::PKeyCtxRef; /// Type of encryption padding to use. -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Padding(c_int); pub const NO_PADDING: Padding = Padding(ffi::RSA_NO_PADDING); @@ -343,6 +344,22 @@ mod compat { } } +impl PKeyCtxRef { + pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { + unsafe { + try!(cvt(ffi::EVP_PKEY_CTX_set_rsa_padding(self.as_ptr(), pad.0))); + } + Ok(()) + } + + pub fn get_rsa_padding(&mut self) -> Result { + let mut pad: c_int = 0; + unsafe { + try!(cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))); + }; + Ok(Padding(pad)) + } +} #[cfg(test)] mod test { diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index ec37c885..d1fcffd5 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -68,7 +68,7 @@ use std::ptr; use {cvt, cvt_p}; use hash::MessageDigest; -use pkey::PKeyRef; +use pkey::{PKeyRef, PKeyCtxRef}; use error::ErrorStack; use types::OpenSslTypeRef; @@ -77,7 +77,7 @@ use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free}; #[cfg(any(ossl101, ossl102))] use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; -pub struct Signer<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>); +pub struct Signer<'a>(*mut ffi::EVP_MD_CTX, *mut ffi::EVP_PKEY_CTX, PhantomData<&'a PKeyRef>, PhantomData<&'a PKeyCtxRef>); impl<'a> Drop for Signer<'a> { fn drop(&mut self) { @@ -93,8 +93,9 @@ impl<'a> Signer<'a> { ffi::init(); let ctx = try!(cvt_p(EVP_MD_CTX_new())); + let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut(); let r = ffi::EVP_DigestSignInit(ctx, - ptr::null_mut(), + &mut pctx, type_.as_ptr(), ptr::null_mut(), pkey.as_ptr()); @@ -102,10 +103,14 @@ impl<'a> Signer<'a> { EVP_MD_CTX_free(ctx); return Err(ErrorStack::get()); } - Ok(Signer(ctx, PhantomData)) + Ok(Signer(ctx, pctx, PhantomData, PhantomData)) } } + pub fn pkey_ctx(&mut self) -> Option<&mut PKeyCtxRef> { + unsafe { self.1.as_mut().map(|ctx| ::types::OpenSslTypeRef::from_ptr_mut(ctx)) } + } + pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ()) @@ -219,7 +224,7 @@ mod test { use sign::{Signer, Verifier}; use ec::{EcGroup, EcKey}; use nid; - use rsa::Rsa; + use rsa::{Rsa, PKCS1_PADDING}; use dsa::Dsa; use pkey::PKey; @@ -254,6 +259,8 @@ mod test { let pkey = PKey::from_rsa(private_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); + assert_eq!(signer.pkey_ctx().unwrap().get_rsa_padding().unwrap(), PKCS1_PADDING); + signer.pkey_ctx().unwrap().set_rsa_padding(PKCS1_PADDING).unwrap(); signer.update(INPUT).unwrap(); let result = signer.finish().unwrap(); From 20eed1e762f01ddac0a46b6471105dca8284ff8b Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:19:06 -0800 Subject: [PATCH 126/140] Simplify code, so that openssl-sys really doesn't contain anything aside from bindings --- openssl-sys/src/lib.rs | 9 ------- openssl/src/rsa.rs | 13 ++++++++-- openssl/src/sign.rs | 54 ++++++++++++++++++++++++++++++++---------- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 7ef5f7fe..9f89762b 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2005,12 +2005,3 @@ extern { md: *mut c_uchar, len: *mut c_uint) -> c_int; } - -// EVP_PKEY_CTX_ctrl macros -pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, RSA_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) -} - -pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) -} diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 75893545..63ed874a 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -344,10 +344,19 @@ mod compat { } } +// EVP_PKEY_CTX_ctrl macros +unsafe fn pkey_ctx_set_rsa_padding(ctx: *mut ffi::EVP_PKEY_CTX, pad: c_int) -> c_int { + ffi::EVP_PKEY_CTX_ctrl(ctx, ffi::EVP_PKEY_RSA, -1, ffi::RSA_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) +} + +unsafe fn pkey_ctx_get_rsa_padding(ctx: *mut ffi::EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { + ffi::EVP_PKEY_CTX_ctrl(ctx, ffi::EVP_PKEY_RSA, -1, ffi::RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) +} + impl PKeyCtxRef { pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { unsafe { - try!(cvt(ffi::EVP_PKEY_CTX_set_rsa_padding(self.as_ptr(), pad.0))); + try!(cvt(pkey_ctx_set_rsa_padding(self.as_ptr(), pad.0))); } Ok(()) } @@ -355,7 +364,7 @@ impl PKeyCtxRef { pub fn get_rsa_padding(&mut self) -> Result { let mut pad: c_int = 0; unsafe { - try!(cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))); + try!(cvt(pkey_ctx_get_rsa_padding(self.as_ptr(), &mut pad))); }; Ok(Padding(pad)) } diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index d1fcffd5..41314a84 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -77,12 +77,18 @@ use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free}; #[cfg(any(ossl101, ossl102))] use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; -pub struct Signer<'a>(*mut ffi::EVP_MD_CTX, *mut ffi::EVP_PKEY_CTX, PhantomData<&'a PKeyRef>, PhantomData<&'a PKeyCtxRef>); +pub struct Signer<'a> { + md_ctx: *mut ffi::EVP_MD_CTX, + pkey_ctx: *mut ffi::EVP_PKEY_CTX, + pkey_pd: PhantomData<&'a PKeyRef>, + pkey_ctx_pd: PhantomData<&'a PKeyCtxRef> +} 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. unsafe { - EVP_MD_CTX_free(self.0); + EVP_MD_CTX_free(self.md_ctx); } } } @@ -103,26 +109,31 @@ impl<'a> Signer<'a> { EVP_MD_CTX_free(ctx); return Err(ErrorStack::get()); } - Ok(Signer(ctx, pctx, PhantomData, PhantomData)) + Ok(Signer { + md_ctx: ctx, + pkey_ctx: pctx, + pkey_pd: PhantomData, + pkey_ctx_pd: PhantomData + }) } } pub fn pkey_ctx(&mut self) -> Option<&mut PKeyCtxRef> { - unsafe { self.1.as_mut().map(|ctx| ::types::OpenSslTypeRef::from_ptr_mut(ctx)) } + unsafe { self.pkey_ctx.as_mut().map(|ctx| ::types::OpenSslTypeRef::from_ptr_mut(ctx)) } } pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { - cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ()) + cvt(ffi::EVP_DigestUpdate(self.md_ctx, buf.as_ptr() as *const _, buf.len())).map(|_| ()) } } pub fn finish(&self) -> Result, ErrorStack> { unsafe { let mut len = 0; - try!(cvt(ffi::EVP_DigestSignFinal(self.0, ptr::null_mut(), &mut len))); + try!(cvt(ffi::EVP_DigestSignFinal(self.md_ctx, ptr::null_mut(), &mut len))); let mut buf = vec![0; len]; - try!(cvt(ffi::EVP_DigestSignFinal(self.0, buf.as_mut_ptr() as *mut _, &mut len))); + try!(cvt(ffi::EVP_DigestSignFinal(self.md_ctx, buf.as_mut_ptr() as *mut _, &mut len))); // The advertised length is not always equal to the real length for things like DSA buf.truncate(len); Ok(buf) @@ -141,12 +152,18 @@ impl<'a> Write for Signer<'a> { } } -pub struct Verifier<'a>(*mut ffi::EVP_MD_CTX, PhantomData<&'a PKeyRef>); +pub struct Verifier<'a> { + md_ctx: *mut ffi::EVP_MD_CTX, + pkey_ctx: *mut ffi::EVP_PKEY_CTX, + pkey_pd: PhantomData<&'a PKeyRef>, + pkey_ctx_pd: PhantomData<&'a PKeyCtxRef>, +} impl<'a> Drop for Verifier<'a> { fn drop(&mut self) { + // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. unsafe { - EVP_MD_CTX_free(self.0); + EVP_MD_CTX_free(self.md_ctx); } } } @@ -157,8 +174,9 @@ impl<'a> Verifier<'a> { ffi::init(); let ctx = try!(cvt_p(EVP_MD_CTX_new())); + let mut pctx: *mut ffi::EVP_PKEY_CTX = ptr::null_mut(); let r = ffi::EVP_DigestVerifyInit(ctx, - ptr::null_mut(), + &mut pctx, type_.as_ptr(), ptr::null_mut(), pkey.as_ptr()); @@ -167,19 +185,28 @@ impl<'a> Verifier<'a> { return Err(ErrorStack::get()); } - Ok(Verifier(ctx, PhantomData)) + Ok(Verifier { + md_ctx: ctx, + pkey_ctx: pctx, + pkey_pd: PhantomData, + pkey_ctx_pd: PhantomData, + }) } } + pub fn pkey_ctx(&mut self) -> Option<&mut PKeyCtxRef> { + unsafe { self.pkey_ctx.as_mut().map(|ctx| ::types::OpenSslTypeRef::from_ptr_mut(ctx)) } + } + pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { unsafe { - cvt(ffi::EVP_DigestUpdate(self.0, buf.as_ptr() as *const _, buf.len())).map(|_| ()) + cvt(ffi::EVP_DigestUpdate(self.md_ctx, buf.as_ptr() as *const _, buf.len())).map(|_| ()) } } pub fn finish(&self, signature: &[u8]) -> Result { unsafe { - let r = EVP_DigestVerifyFinal(self.0, signature.as_ptr() as *const _, signature.len()); + let r = EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *const _, signature.len()); match r { 1 => Ok(true), 0 => { @@ -274,6 +301,7 @@ mod test { let pkey = PKey::from_rsa(private_key).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); + assert_eq!(verifier.pkey_ctx().unwrap().get_rsa_padding().unwrap(), PKCS1_PADDING); verifier.update(INPUT).unwrap(); assert!(verifier.finish(SIGNATURE).unwrap()); } From e1fc5b2b7ea46161d83f91f4e372fd52423107b9 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:29:06 -0800 Subject: [PATCH 127/140] Simplify protocol based on the semantics defined by openssl. --- openssl/src/sign.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index 41314a84..fe38a9a8 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -109,6 +109,9 @@ impl<'a> Signer<'a> { EVP_MD_CTX_free(ctx); return Err(ErrorStack::get()); } + + assert!(!pctx.is_null()); + Ok(Signer { md_ctx: ctx, pkey_ctx: pctx, @@ -118,8 +121,8 @@ impl<'a> Signer<'a> { } } - pub fn pkey_ctx(&mut self) -> Option<&mut PKeyCtxRef> { - unsafe { self.pkey_ctx.as_mut().map(|ctx| ::types::OpenSslTypeRef::from_ptr_mut(ctx)) } + pub fn pkey_ctx(&mut self) -> &mut PKeyCtxRef { + unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) } } pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { @@ -185,6 +188,8 @@ impl<'a> Verifier<'a> { return Err(ErrorStack::get()); } + assert!(!pctx.is_null()); + Ok(Verifier { md_ctx: ctx, pkey_ctx: pctx, @@ -194,8 +199,8 @@ impl<'a> Verifier<'a> { } } - pub fn pkey_ctx(&mut self) -> Option<&mut PKeyCtxRef> { - unsafe { self.pkey_ctx.as_mut().map(|ctx| ::types::OpenSslTypeRef::from_ptr_mut(ctx)) } + pub fn pkey_ctx(&mut self) -> &mut PKeyCtxRef { + unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) } } pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { @@ -286,8 +291,8 @@ mod test { let pkey = PKey::from_rsa(private_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); - assert_eq!(signer.pkey_ctx().unwrap().get_rsa_padding().unwrap(), PKCS1_PADDING); - signer.pkey_ctx().unwrap().set_rsa_padding(PKCS1_PADDING).unwrap(); + assert_eq!(signer.pkey_ctx().get_rsa_padding().unwrap(), PKCS1_PADDING); + signer.pkey_ctx().set_rsa_padding(PKCS1_PADDING).unwrap(); signer.update(INPUT).unwrap(); let result = signer.finish().unwrap(); @@ -301,7 +306,7 @@ mod test { let pkey = PKey::from_rsa(private_key).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); - assert_eq!(verifier.pkey_ctx().unwrap().get_rsa_padding().unwrap(), PKCS1_PADDING); + assert_eq!(verifier.pkey_ctx().get_rsa_padding().unwrap(), PKCS1_PADDING); verifier.update(INPUT).unwrap(); assert!(verifier.finish(SIGNATURE).unwrap()); } From ef61b814ff51d516adbc33d522dd0d84f2344196 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:30:25 -0800 Subject: [PATCH 128/140] Small amount of docs. --- openssl/src/rsa.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 63ed874a..433efd56 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -353,6 +353,7 @@ unsafe fn pkey_ctx_get_rsa_padding(ctx: *mut ffi::EVP_PKEY_CTX, ppad: *mut c_int ffi::EVP_PKEY_CTX_ctrl(ctx, ffi::EVP_PKEY_RSA, -1, ffi::RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) } +// This is needed here, as it needs access to the privade data of Padding. impl PKeyCtxRef { pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { unsafe { From 72a10f3e65c1bed4689ba609d67865fbe766c92f Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:35:57 -0800 Subject: [PATCH 129/140] Fixing typo --- openssl/src/rsa.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 433efd56..d9e599c8 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -353,7 +353,7 @@ unsafe fn pkey_ctx_get_rsa_padding(ctx: *mut ffi::EVP_PKEY_CTX, ppad: *mut c_int ffi::EVP_PKEY_CTX_ctrl(ctx, ffi::EVP_PKEY_RSA, -1, ffi::RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) } -// This is needed here, as it needs access to the privade data of Padding. +// This is needed here, as it needs access to the private data of Padding. impl PKeyCtxRef { pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { unsafe { From 302ee77d32acb0b92fe563f29c36882e3b9b7d62 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 16:51:10 -0800 Subject: [PATCH 130/140] Adding suggestions from review. --- openssl-sys/src/lib.rs | 9 +++++++++ openssl/src/pkey.rs | 19 ++++++++++++++++++- openssl/src/rsa.rs | 38 ++++++++++---------------------------- openssl/src/sign.rs | 14 +++++--------- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 9f89762b..1859c3ba 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1310,6 +1310,15 @@ pub unsafe fn BIO_set_retry_write(b: *mut BIO) { BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY) } +// EVP_PKEY_CTX_ctrl macros +pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, RSA_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) +} + +pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) +} + 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()) } diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index fd963c24..0d8de1dd 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -8,7 +8,7 @@ use bio::MemBioSlice; use dh::Dh; use dsa::Dsa; use ec::EcKey; -use rsa::Rsa; +use rsa::{Rsa, Padding}; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; use types::{OpenSslType, OpenSslTypeRef}; @@ -153,6 +153,23 @@ impl PKey { pub struct PKeyCtxRef(::util::Opaque); +impl PKeyCtxRef { + pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { + unsafe { + try!(cvt(ffi::EVP_PKEY_CTX_set_rsa_padding(self.as_ptr(), pad.as_raw()))); + } + Ok(()) + } + + pub fn rsa_padding(&mut self) -> Result { + let mut pad: c_int = 0; + unsafe { + try!(cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))); + }; + Ok(Padding::from_raw(pad)) + } +} + impl ::types::OpenSslTypeRef for PKeyCtxRef { type CType = ffi::EVP_PKEY_CTX; } diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index d9e599c8..dc760f7a 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -10,12 +10,21 @@ use bio::MemBioSlice; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; use types::OpenSslTypeRef; -use pkey::PKeyCtxRef; /// Type of encryption padding to use. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct Padding(c_int); +impl Padding { + pub fn from_raw(value: c_int) -> Padding { + Padding(value) + } + + pub fn as_raw(&self) -> c_int { + self.0 + } +} + pub const NO_PADDING: Padding = Padding(ffi::RSA_NO_PADDING); pub const PKCS1_PADDING: Padding = Padding(ffi::RSA_PKCS1_PADDING); pub const PKCS1_OAEP_PADDING: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING); @@ -344,33 +353,6 @@ mod compat { } } -// EVP_PKEY_CTX_ctrl macros -unsafe fn pkey_ctx_set_rsa_padding(ctx: *mut ffi::EVP_PKEY_CTX, pad: c_int) -> c_int { - ffi::EVP_PKEY_CTX_ctrl(ctx, ffi::EVP_PKEY_RSA, -1, ffi::RSA_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) -} - -unsafe fn pkey_ctx_get_rsa_padding(ctx: *mut ffi::EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { - ffi::EVP_PKEY_CTX_ctrl(ctx, ffi::EVP_PKEY_RSA, -1, ffi::RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) -} - -// This is needed here, as it needs access to the private data of Padding. -impl PKeyCtxRef { - pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { - unsafe { - try!(cvt(pkey_ctx_set_rsa_padding(self.as_ptr(), pad.0))); - } - Ok(()) - } - - pub fn get_rsa_padding(&mut self) -> Result { - let mut pad: c_int = 0; - unsafe { - try!(cvt(pkey_ctx_get_rsa_padding(self.as_ptr(), &mut pad))); - }; - Ok(Padding(pad)) - } -} - #[cfg(test)] mod test { use symm::Cipher; diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index fe38a9a8..3ae8f1a2 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -81,7 +81,6 @@ pub struct Signer<'a> { md_ctx: *mut ffi::EVP_MD_CTX, pkey_ctx: *mut ffi::EVP_PKEY_CTX, pkey_pd: PhantomData<&'a PKeyRef>, - pkey_ctx_pd: PhantomData<&'a PKeyCtxRef> } impl<'a> Drop for Signer<'a> { @@ -116,12 +115,11 @@ impl<'a> Signer<'a> { md_ctx: ctx, pkey_ctx: pctx, pkey_pd: PhantomData, - pkey_ctx_pd: PhantomData }) } } - pub fn pkey_ctx(&mut self) -> &mut PKeyCtxRef { + pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef { unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) } } @@ -159,7 +157,6 @@ pub struct Verifier<'a> { md_ctx: *mut ffi::EVP_MD_CTX, pkey_ctx: *mut ffi::EVP_PKEY_CTX, pkey_pd: PhantomData<&'a PKeyRef>, - pkey_ctx_pd: PhantomData<&'a PKeyCtxRef>, } impl<'a> Drop for Verifier<'a> { @@ -194,12 +191,11 @@ impl<'a> Verifier<'a> { md_ctx: ctx, pkey_ctx: pctx, pkey_pd: PhantomData, - pkey_ctx_pd: PhantomData, }) } } - pub fn pkey_ctx(&mut self) -> &mut PKeyCtxRef { + pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef { unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) } } @@ -291,8 +287,8 @@ mod test { let pkey = PKey::from_rsa(private_key).unwrap(); let mut signer = Signer::new(MessageDigest::sha256(), &pkey).unwrap(); - assert_eq!(signer.pkey_ctx().get_rsa_padding().unwrap(), PKCS1_PADDING); - signer.pkey_ctx().set_rsa_padding(PKCS1_PADDING).unwrap(); + assert_eq!(signer.pkey_ctx_mut().rsa_padding().unwrap(), PKCS1_PADDING); + signer.pkey_ctx_mut().set_rsa_padding(PKCS1_PADDING).unwrap(); signer.update(INPUT).unwrap(); let result = signer.finish().unwrap(); @@ -306,7 +302,7 @@ mod test { let pkey = PKey::from_rsa(private_key).unwrap(); let mut verifier = Verifier::new(MessageDigest::sha256(), &pkey).unwrap(); - assert_eq!(verifier.pkey_ctx().get_rsa_padding().unwrap(), PKCS1_PADDING); + assert_eq!(verifier.pkey_ctx_mut().rsa_padding().unwrap(), PKCS1_PADDING); verifier.update(INPUT).unwrap(); assert!(verifier.finish(SIGNATURE).unwrap()); } From 4900d3fe5d8fe9f581940bd60e2d919155839fa8 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Tue, 31 Jan 2017 11:59:59 -0800 Subject: [PATCH 131/140] Fixed constant names from openssl/rsa.h Fixed PKeyCtxRef method that didn't need to be mutable. Added non-mutable accessors for PKeyCtxRef for Signer and Verifier. --- openssl-sys/src/lib.rs | 12 ++++++------ openssl/src/pkey.rs | 2 +- openssl/src/sign.rs | 8 ++++++++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 1859c3ba..d18fa5ad 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -153,6 +153,10 @@ 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_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1; + +pub const EVP_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; + 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_SET_TAG: c_int = 0x11; @@ -1123,10 +1127,6 @@ pub const RSA_NO_PADDING: c_int = 3; pub const RSA_PKCS1_OAEP_PADDING: c_int = 4; pub const RSA_X931_PADDING: c_int = 5; -pub const RSA_PKEY_CTRL_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 1; - -pub const RSA_PKEY_CTRL_GET_RSA_PADDING: c_int = EVP_PKEY_ALG_CTRL + 6; - pub const SSL_CTRL_SET_TMP_DH: c_int = 3; pub const SSL_CTRL_SET_TMP_ECDH: c_int = 4; pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14; @@ -1312,11 +1312,11 @@ pub unsafe fn BIO_set_retry_write(b: *mut BIO) { // EVP_PKEY_CTX_ctrl macros pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, RSA_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, ptr::null_mut()) } pub unsafe fn EVP_PKEY_CTX_get_rsa_padding(ctx: *mut EVP_PKEY_CTX, ppad: *mut c_int) -> c_int { - EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, RSA_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) + EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_GET_RSA_PADDING, 0, ppad as *mut c_void) } pub unsafe fn SSL_CTX_set_mode(ctx: *mut SSL_CTX, op: c_long) -> c_long { diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index 0d8de1dd..c9f5ec1b 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -161,7 +161,7 @@ impl PKeyCtxRef { Ok(()) } - pub fn rsa_padding(&mut self) -> Result { + pub fn rsa_padding(&self) -> Result { let mut pad: c_int = 0; unsafe { try!(cvt(ffi::EVP_PKEY_CTX_get_rsa_padding(self.as_ptr(), &mut pad))); diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index 3ae8f1a2..ac33bd07 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -119,6 +119,10 @@ impl<'a> Signer<'a> { } } + pub fn pkey_ctx(&self) -> &PKeyCtxRef { + unsafe { ::types::OpenSslTypeRef::from_ptr(self.pkey_ctx) } + } + pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef { unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) } } @@ -195,6 +199,10 @@ impl<'a> Verifier<'a> { } } + pub fn pkey_ctx(&self) -> &PKeyCtxRef { + unsafe { ::types::OpenSslTypeRef::from_ptr(self.pkey_ctx) } + } + pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef { unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) } } From 5e3dd07ee477fc30779b438be50dc6157b716d22 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 3 Feb 2017 01:27:11 -0800 Subject: [PATCH 132/140] Clean up pkg-config logic Now that we're letting the C compiler track down headers this is no longer necessary. --- openssl-sys/build.rs | 75 +++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/openssl-sys/build.rs b/openssl-sys/build.rs index 1b717693..fc0f4680 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build.rs @@ -7,6 +7,7 @@ use std::ffi::OsString; use std::fs::File; use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; +use std::panic::{self, AssertUnwindSafe}; use std::process::Command; // The set of `OPENSSL_NO_`s that we care about. @@ -189,46 +190,10 @@ fn try_pkg_config() { return } - // We're going to be looking at header files, so show us all the system - // cflags dirs for showing us lots of `-I`. - env::set_var("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS", "1"); - - // This is more complex than normal because we need to track down opensslconf.h. - // To do that, we need the inlude paths even if they're on the default search path, but the - // linkage directories emitted from that cause all kinds of issues if other libraries happen to - // live in them. So, we run pkg-config twice, once asking for system dirs but not emitting - // metadata, and a second time emitting metadata but not asking for system dirs. Yay. - let lib = match pkg_config::Config::new() - .cargo_metadata(false) - .print_system_libs(true) - .find("openssl") { - Ok(lib) => lib, - Err(_) => return, - }; - - if lib.include_paths.len() == 0 { - panic!(" - -Used pkg-config to discover the OpenSSL installation, but pkg-config did not -return any include paths for the installation. This crate needs to take a peek -at the header files so it cannot proceed unless they're found. - -You can try fixing this setting the `OPENSSL_DIR` environment variable -pointing to your OpenSSL installation or installing OpenSSL headers package -specific to your distribution: - - # On Ubuntu - sudo apt-get install libssl-dev - # On Arch Linux - sudo pacman -S openssl - # On Fedora - sudo dnf install openssl-devel - -See rust-openssl README for more information: - - https://github.com/sfackler/rust-openssl#linux -"); - } + let lib = pkg_config::Config::new() + .print_system_libs(false) + .find("openssl") + .unwrap(); validate_headers(&lib.include_paths); @@ -236,11 +201,6 @@ See rust-openssl README for more information: println!("cargo:include={}", include.display()); } - pkg_config::Config::new() - .print_system_libs(false) - .find("openssl") - .unwrap(); - std::process::exit(0); } @@ -297,7 +257,30 @@ RUST_{define} for include_dir in include_dirs { gcc.include(include_dir); } - let expanded = gcc.file(&path).expand(); + // https://github.com/alexcrichton/gcc-rs/issues/133 + let expanded = match panic::catch_unwind(AssertUnwindSafe(|| gcc.file(&path).expand())) { + Ok(expanded) => expanded, + Err(_) => { + panic!(" +Failed to find OpenSSL development headers. + +You can try fixing this setting the `OPENSSL_DIR` environment variable +pointing to your OpenSSL installation or installing OpenSSL headers package +specific to your distribution: + + # On Ubuntu + sudo apt-get install libssl-dev + # On Arch Linux + sudo pacman -S openssl + # On Fedora + sudo dnf install openssl-devel + +See rust-openssl README for more information: + + https://github.com/sfackler/rust-openssl#linux +"); + } + }; let expanded = String::from_utf8(expanded).unwrap(); let mut enabled = vec![]; From 12ae31ad476d373ce93b4222d3875b9663f3da17 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 3 Feb 2017 01:24:05 -0800 Subject: [PATCH 133/140] Switch to foreign_types --- openssl/Cargo.toml | 1 + openssl/src/asn1.rs | 26 +++++++++++++++--- openssl/src/bn.rs | 18 ++++++++++--- openssl/src/dh.rs | 11 ++++++-- openssl/src/dsa.rs | 14 +++++++--- openssl/src/ec.rs | 35 ++++++++++++++++++++---- openssl/src/lib.rs | 2 ++ openssl/src/macros.rs | 47 +++----------------------------- openssl/src/ocsp.rs | 42 ++++++++++++++++++++++++----- openssl/src/pkcs12.rs | 10 +++++-- openssl/src/pkey.rs | 14 +++++++--- openssl/src/rsa.rs | 10 +++++-- openssl/src/sign.rs | 10 +++---- openssl/src/ssl/mod.rs | 30 ++++++++++++++++----- openssl/src/ssl/tests/mod.rs | 2 +- openssl/src/stack.rs | 17 ++++++------ openssl/src/string.rs | 10 +++++-- openssl/src/types.rs | 43 +++-------------------------- openssl/src/verify.rs | 10 +++++-- openssl/src/x509/mod.rs | 52 ++++++++++++++++++++++++++++++------ openssl/src/x509/store.rs | 18 ++++++++++--- 21 files changed, 272 insertions(+), 150 deletions(-) diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index d1893fe8..5d9aab92 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -19,6 +19,7 @@ v110 = [] [dependencies] bitflags = "0.7" +foreign-types = "0.1" lazy_static = "0.2" libc = "0.2" openssl-sys = { version = "0.9.6", path = "../openssl-sys" } diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index d177885e..fd932723 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -1,4 +1,5 @@ use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_long, c_char}; use std::fmt; use std::ptr; @@ -8,10 +9,15 @@ use std::str; use {cvt, cvt_p}; use bio::MemBio; use error::ErrorStack; -use types::{OpenSslType, OpenSslTypeRef}; use string::OpensslString; -type_!(Asn1GeneralizedTime, Asn1GeneralizedTimeRef, ffi::ASN1_GENERALIZEDTIME, ffi::ASN1_GENERALIZEDTIME_free); +foreign_type! { + type CType = ffi::ASN1_GENERALIZEDTIME; + fn drop = ffi::ASN1_GENERALIZEDTIME_free; + + pub struct Asn1GeneralizedTime; + pub struct Asn1GeneralizedTimeRef; +} impl fmt::Display for Asn1GeneralizedTimeRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -23,7 +29,13 @@ impl fmt::Display for Asn1GeneralizedTimeRef { } } -type_!(Asn1Time, Asn1TimeRef, ffi::ASN1_TIME, ffi::ASN1_TIME_free); +foreign_type! { + type CType = ffi::ASN1_TIME; + fn drop = ffi::ASN1_TIME_free; + + pub struct Asn1Time; + pub struct Asn1TimeRef; +} impl fmt::Display for Asn1TimeRef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -51,7 +63,13 @@ impl Asn1Time { } } -type_!(Asn1String, Asn1StringRef, ffi::ASN1_STRING, ffi::ASN1_STRING_free); +foreign_type! { + type CType = ffi::ASN1_STRING; + fn drop = ffi::ASN1_STRING_free; + + pub struct Asn1String; + pub struct Asn1StringRef; +} impl Asn1StringRef { pub fn as_utf8(&self) -> Result { diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index 01c0b428..7d288eee 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -1,4 +1,5 @@ use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::cmp::Ordering; use std::ffi::CString; @@ -8,7 +9,6 @@ use std::ops::{Add, Div, Mul, Neg, Rem, Shl, Shr, Sub, Deref}; use {cvt, cvt_p, cvt_n}; use error::ErrorStack; use string::OpensslString; -use types::{OpenSslType, OpenSslTypeRef}; #[cfg(ossl10x)] use ffi::{get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, @@ -40,7 +40,13 @@ pub const MSB_ONE: MsbOption = MsbOption(0); /// of bits in the original numbers. pub const TWO_MSB_ONE: MsbOption = MsbOption(1); -type_!(BigNumContext, BigNumContextRef, ffi::BN_CTX, ffi::BN_CTX_free); +foreign_type! { + type CType = ffi::BN_CTX; + fn drop = ffi::BN_CTX_free; + + pub struct BigNumContext; + pub struct BigNumContextRef; +} impl BigNumContext { /// Returns a new `BigNumContext`. @@ -509,7 +515,13 @@ impl BigNumRef { } } -type_!(BigNum, BigNumRef, ffi::BIGNUM, ffi::BN_free); +foreign_type! { + type CType = ffi::BIGNUM; + fn drop = ffi::BN_free; + + pub struct BigNum; + pub struct BigNumRef; +} impl BigNum { /// Creates a new `BigNum` with the value 0. diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index 64494f95..a7454150 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -1,13 +1,20 @@ use error::ErrorStack; use ffi; +use foreign_types::ForeignTypeRef; use std::mem; use std::ptr; use {cvt, cvt_p, init}; use bn::BigNum; -use types::OpenSslTypeRef; -type_!(Dh, DhRef, ffi::DH, ffi::DH_free); +foreign_type! { + type CType = ffi::DH; + fn drop = ffi::DH_free; + + pub struct Dh; + + pub struct DhRef; +} impl DhRef { to_pem!(ffi::PEM_write_bio_DHparams); diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index a4a8bf30..60a1afde 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -1,16 +1,22 @@ -use error::ErrorStack; use ffi; +use foreign_types::ForeignTypeRef; use libc::{c_int, c_char, c_void}; use std::fmt; use std::ptr; +use {cvt, cvt_p}; use bio::MemBioSlice; use bn::BigNumRef; -use {cvt, cvt_p}; -use types::OpenSslTypeRef; +use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; -type_!(Dsa, DsaRef, ffi::DSA, ffi::DSA_free); +foreign_type! { + type CType = ffi::DSA; + fn drop = ffi::DSA_free; + + pub struct Dsa; + pub struct DsaRef; +} impl DsaRef { private_key_to_pem!(ffi::PEM_write_bio_DSAPrivateKey); diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index ebb631e8..37815021 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -1,4 +1,5 @@ use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; use std::ptr; use std::mem; use libc::c_int; @@ -7,7 +8,6 @@ use {cvt, cvt_n, cvt_p, init}; use bn::{BigNumRef, BigNumContextRef}; use error::ErrorStack; use nid::Nid; -use types::{OpenSslType, OpenSslTypeRef}; pub const POINT_CONVERSION_COMPRESSED: PointConversionForm = PointConversionForm(ffi::point_conversion_form_t::POINT_CONVERSION_COMPRESSED); @@ -29,7 +29,13 @@ pub struct PointConversionForm(ffi::point_conversion_form_t); #[derive(Copy, Clone)] pub struct Asn1Flag(c_int); -type_!(EcGroup, EcGroupRef, ffi::EC_GROUP, ffi::EC_GROUP_free); +foreign_type! { + type CType = ffi::EC_GROUP; + fn drop = ffi::EC_GROUP_free; + + pub struct EcGroup; + pub struct EcGroupRef; +} impl EcGroup { /// Returns the group of a standard named curve. @@ -103,7 +109,13 @@ impl EcGroupRef { } } -type_!(EcPoint, EcPointRef, ffi::EC_POINT, ffi::EC_POINT_free); +foreign_type! { + type CType = ffi::EC_POINT; + fn drop = ffi::EC_POINT_free; + + pub struct EcPoint; + pub struct EcPointRef; +} impl EcPointRef { /// Computes `a + b`, storing the result in `self`. @@ -253,7 +265,13 @@ impl EcPoint { } } -type_!(EcKey, EcKeyRef, ffi::EC_KEY, ffi::EC_KEY_free); +foreign_type! { + type CType = ffi::EC_KEY; + fn drop = ffi::EC_KEY_free; + + pub struct EcKey; + pub struct EcKeyRef; +} impl EcKeyRef { private_key_to_pem!(ffi::PEM_write_bio_ECPrivateKey); @@ -355,7 +373,14 @@ impl EcKey { private_key_from_der!(EcKey, ffi::d2i_ECPrivateKey); } -type_!(EcKeyBuilder, EcKeyBuilderRef, ffi::EC_KEY, ffi::EC_KEY_free); + +foreign_type! { + type CType = ffi::EC_KEY; + fn drop = ffi::EC_KEY_free; + + pub struct EcKeyBuilder; + pub struct EcKeyBuilderRef; +} impl EcKeyBuilder { pub fn new() -> Result { diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index ea71a269..507af1d4 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -2,6 +2,8 @@ #[macro_use] extern crate bitflags; +#[macro_use] +extern crate foreign_types; extern crate libc; #[macro_use] extern crate lazy_static; diff --git a/openssl/src/macros.rs b/openssl/src/macros.rs index b36e8319..b2fe0c18 100644 --- a/openssl/src/macros.rs +++ b/openssl/src/macros.rs @@ -1,45 +1,4 @@ -macro_rules! type_ { - ($n:ident, $r:ident, $c:path, $d:path) => { - pub struct $n(*mut $c); - - impl ::types::OpenSslType for $n { - type CType = $c; - type Ref = $r; - - unsafe fn from_ptr(ptr: *mut $c) -> $n { - $n(ptr) - } - } - - impl Drop for $n { - fn drop(&mut self) { - unsafe { $d(self.0) } - } - } - - impl ::std::ops::Deref for $n { - type Target = $r; - - fn deref(&self) -> &$r { - unsafe { ::types::OpenSslTypeRef::from_ptr(self.0) } - } - } - - impl ::std::ops::DerefMut for $n { - fn deref_mut(&mut self) -> &mut $r { - unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.0) } - } - } - - pub struct $r(::util::Opaque); - - impl ::types::OpenSslTypeRef for $r { - type CType = $c; - } - } -} - macro_rules! private_key_from_pem { ($t:ident, $f:path) => { from_pem_inner!(/// Deserializes a PEM-formatted private key. @@ -161,9 +120,11 @@ macro_rules! to_der_inner { #[$m] pub fn $n(&self) -> Result, ::error::ErrorStack> { unsafe { - let len = try!(::cvt($f(::types::OpenSslTypeRef::as_ptr(self), ptr::null_mut()))); + let len = try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), + ptr::null_mut()))); let mut buf = vec![0; len as usize]; - try!(::cvt($f(::types::OpenSslTypeRef::as_ptr(self), &mut buf.as_mut_ptr()))); + try!(::cvt($f(::foreign_types::ForeignTypeRef::as_ptr(self), + &mut buf.as_mut_ptr()))); Ok(buf) } } diff --git a/openssl/src/ocsp.rs b/openssl/src/ocsp.rs index 708c3561..67d51838 100644 --- a/openssl/src/ocsp.rs +++ b/openssl/src/ocsp.rs @@ -1,4 +1,5 @@ use ffi; +use foreign_types::ForeignTypeRef; use libc::{c_int, c_long, c_ulong}; use std::ptr; use std::mem; @@ -8,7 +9,6 @@ use asn1::Asn1GeneralizedTimeRef; use error::ErrorStack; use hash::MessageDigest; use stack::StackRef; -use types::OpenSslTypeRef; use x509::store::X509StoreRef; use x509::{X509, X509Ref}; @@ -135,7 +135,13 @@ impl<'a> Status<'a> { } } -type_!(OcspBasicResponse, OcspBasicResponseRef, ffi::OCSP_BASICRESP, ffi::OCSP_BASICRESP_free); +foreign_type! { + 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. @@ -189,7 +195,13 @@ impl OcspBasicResponseRef { } } -type_!(OcspCertId, OcspCertIdRef, ffi::OCSP_CERTID, ffi::OCSP_CERTID_free); +foreign_type! { + 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`. @@ -204,7 +216,13 @@ impl OcspCertId { } } -type_!(OcspResponse, OcspResponseRef, ffi::OCSP_RESPONSE, ffi::OCSP_RESPONSE_free); +foreign_type! { + 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. @@ -245,7 +263,13 @@ impl OcspResponseRef { } } -type_!(OcspRequest, OcspRequestRef, ffi::OCSP_REQUEST, ffi::OCSP_REQUEST_free); +foreign_type! { + type CType = ffi::OCSP_REQUEST; + fn drop = ffi::OCSP_REQUEST_free; + + pub struct OcspRequest; + pub struct OcspRequestRef; +} impl OcspRequest { pub fn new() -> Result { @@ -271,4 +295,10 @@ impl OcspRequestRef { } } -type_!(OcspOneReq, OcspOneReqRef, ffi::OCSP_ONEREQ, ffi::OCSP_ONEREQ_free); +foreign_type! { + type CType = ffi::OCSP_ONEREQ; + fn drop = ffi::OCSP_ONEREQ_free; + + pub struct OcspOneReq; + pub struct OcspOneReqRef; +} diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index 44a67af0..1e23668e 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -1,6 +1,7 @@ //! PKCS #12 archives. use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::ptr; use std::ffi::CString; @@ -9,11 +10,16 @@ use {cvt, cvt_p}; use pkey::{PKey, PKeyRef}; use error::ErrorStack; use x509::X509; -use types::{OpenSslType, OpenSslTypeRef}; use stack::Stack; use nid; -type_!(Pkcs12, Pkcs12Ref, ffi::PKCS12, ffi::PKCS12_free); +foreign_type! { + type CType = ffi::PKCS12; + fn drop = ffi::PKCS12_free; + + pub struct Pkcs12; + pub struct Pkcs12Ref; +} impl Pkcs12Ref { to_der!(ffi::i2d_PKCS12); diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index c9f5ec1b..5608dd51 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -2,6 +2,7 @@ use libc::{c_void, c_char, c_int}; use std::ptr; use std::mem; use ffi; +use foreign_types::{Opaque, ForeignType, ForeignTypeRef}; use {cvt, cvt_p}; use bio::MemBioSlice; @@ -11,9 +12,14 @@ use ec::EcKey; use rsa::{Rsa, Padding}; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; -use types::{OpenSslType, OpenSslTypeRef}; -type_!(PKey, PKeyRef, ffi::EVP_PKEY, ffi::EVP_PKEY_free); +foreign_type! { + type CType = ffi::EVP_PKEY; + fn drop = ffi::EVP_PKEY_free; + + pub struct PKey; + pub struct PKeyRef; +} impl PKeyRef { /// Returns a copy of the internal RSA key. @@ -151,7 +157,7 @@ impl PKey { } } -pub struct PKeyCtxRef(::util::Opaque); +pub struct PKeyCtxRef(Opaque); impl PKeyCtxRef { pub fn set_rsa_padding(&mut self, pad: Padding) -> Result<(), ErrorStack> { @@ -170,7 +176,7 @@ impl PKeyCtxRef { } } -impl ::types::OpenSslTypeRef for PKeyCtxRef { +impl ForeignTypeRef for PKeyCtxRef { type CType = ffi::EVP_PKEY_CTX; } diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index dc760f7a..792f7070 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -3,13 +3,13 @@ use std::fmt; use std::ptr; use std::mem; use libc::{c_int, c_void, c_char}; +use foreign_types::ForeignTypeRef; use {cvt, cvt_p, cvt_n}; use bn::{BigNum, BigNumRef}; use bio::MemBioSlice; use error::ErrorStack; use util::{CallbackState, invoke_passwd_cb_old}; -use types::OpenSslTypeRef; /// Type of encryption padding to use. #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -29,7 +29,13 @@ pub const NO_PADDING: Padding = Padding(ffi::RSA_NO_PADDING); pub const PKCS1_PADDING: Padding = Padding(ffi::RSA_PKCS1_PADDING); pub const PKCS1_OAEP_PADDING: Padding = Padding(ffi::RSA_PKCS1_OAEP_PADDING); -type_!(Rsa, RsaRef, ffi::RSA, ffi::RSA_free); +foreign_type! { + type CType = ffi::RSA; + fn drop = ffi::RSA_free; + + pub struct Rsa; + pub struct RsaRef; +} impl RsaRef { private_key_to_pem!(ffi::PEM_write_bio_RSAPrivateKey); diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index ac33bd07..279f294d 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -62,6 +62,7 @@ //! assert!(memcmp::eq(&hmac, &target)); //! ``` use ffi; +use foreign_types::ForeignTypeRef; use std::io::{self, Write}; use std::marker::PhantomData; use std::ptr; @@ -70,7 +71,6 @@ use {cvt, cvt_p}; use hash::MessageDigest; use pkey::{PKeyRef, PKeyCtxRef}; use error::ErrorStack; -use types::OpenSslTypeRef; #[cfg(ossl110)] use ffi::{EVP_MD_CTX_new, EVP_MD_CTX_free}; @@ -120,11 +120,11 @@ impl<'a> Signer<'a> { } pub fn pkey_ctx(&self) -> &PKeyCtxRef { - unsafe { ::types::OpenSslTypeRef::from_ptr(self.pkey_ctx) } + unsafe { PKeyCtxRef::from_ptr(self.pkey_ctx) } } pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef { - unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) } + unsafe { PKeyCtxRef::from_ptr_mut(self.pkey_ctx) } } pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { @@ -200,11 +200,11 @@ impl<'a> Verifier<'a> { } pub fn pkey_ctx(&self) -> &PKeyCtxRef { - unsafe { ::types::OpenSslTypeRef::from_ptr(self.pkey_ctx) } + unsafe { PKeyCtxRef::from_ptr(self.pkey_ctx) } } pub fn pkey_ctx_mut(&mut self) -> &mut PKeyCtxRef { - unsafe { ::types::OpenSslTypeRef::from_ptr_mut(self.pkey_ctx) } + unsafe { PKeyCtxRef::from_ptr_mut(self.pkey_ctx) } } pub fn update(&mut self, buf: &[u8]) -> Result<(), ErrorStack> { diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index dd7f72cc..860e2e00 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -71,6 +71,7 @@ //! } //! ``` use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_void, c_long, c_ulong}; use libc::{c_uchar, c_uint}; use std::any::Any; @@ -102,7 +103,6 @@ use x509::store::{X509StoreBuilderRef, X509StoreRef}; use verify::X509VerifyParamRef; use pkey::PKeyRef; use error::ErrorStack; -use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; use stack::{Stack, StackRef}; @@ -966,7 +966,13 @@ impl SslContextBuilder { } } -type_!(SslContext, SslContextRef, ffi::SSL_CTX, ffi::SSL_CTX_free); +foreign_type! { + type CType = ffi::SSL_CTX; + fn drop = ffi::SSL_CTX_free; + + pub struct SslContext; + pub struct SslContextRef; +} unsafe impl Send for SslContext {} unsafe impl Sync for SslContext {} @@ -1051,7 +1057,7 @@ pub struct CipherBits { pub struct SslCipher(*mut ffi::SSL_CIPHER); -impl OpenSslType for SslCipher { +impl ForeignType for SslCipher { type CType = ffi::SSL_CIPHER; type Ref = SslCipherRef; @@ -1076,7 +1082,7 @@ impl DerefMut for SslCipher { pub struct SslCipherRef(Opaque); -impl OpenSslTypeRef for SslCipherRef { +impl ForeignTypeRef for SslCipherRef { type CType = ffi::SSL_CIPHER; } @@ -1124,7 +1130,13 @@ impl SslCipherRef { } } -type_!(SslSession, SslSessionRef, ffi::SSL_SESSION, ffi::SSL_SESSION_free); +foreign_type! { + type CType = ffi::SSL_SESSION; + fn drop = ffi::SSL_SESSION_free; + + pub struct SslSession; + pub struct SslSessionRef; +} impl SslSessionRef { /// Returns the SSL session ID. @@ -1149,7 +1161,13 @@ impl SslSessionRef { } } -type_!(Ssl, SslRef, ffi::SSL, ffi::SSL_free); +foreign_type! { + type CType = ffi::SSL; + fn drop = ffi::SSL_free; + + pub struct Ssl; + pub struct SslRef; +} impl fmt::Debug for SslRef { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { diff --git a/openssl/src/ssl/tests/mod.rs b/openssl/src/ssl/tests/mod.rs index 536088ab..9c00e3ed 100644 --- a/openssl/src/ssl/tests/mod.rs +++ b/openssl/src/ssl/tests/mod.rs @@ -174,7 +174,7 @@ macro_rules! run_test( use hash::MessageDigest; use x509::X509StoreContext; use hex::FromHex; - use types::OpenSslTypeRef; + use foreign_types::ForeignTypeRef; use super::Server; #[test] diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index dae42ca8..372040aa 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -1,12 +1,12 @@ -use std::ops::{Deref, DerefMut, Index, IndexMut}; -use std::iter; +use foreign_types::{ForeignTypeRef, ForeignType}; +use libc::c_int; use std::borrow::Borrow; use std::convert::AsRef; +use std::iter; use std::marker::PhantomData; -use libc::c_int; use std::mem; +use std::ops::{Deref, DerefMut, Index, IndexMut}; -use types::{OpenSslType, OpenSslTypeRef}; use util::Opaque; #[cfg(ossl10x)] @@ -17,9 +17,8 @@ use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPE /// Trait implemented by types which can be placed in a stack. /// -/// Like `OpenSslType`, it should not be implemented for any type outside -/// of this crate. -pub trait Stackable: OpenSslType { +/// 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 @@ -72,7 +71,7 @@ impl Borrow> for Stack { } } -impl OpenSslType for Stack { +impl ForeignType for Stack { type CType = T::StackType; type Ref = StackRef; @@ -140,7 +139,7 @@ impl ExactSizeIterator for IntoIter {} pub struct StackRef(Opaque, PhantomData); -impl OpenSslTypeRef for StackRef { +impl ForeignTypeRef for StackRef { type CType = T::StackType; } diff --git a/openssl/src/string.rs b/openssl/src/string.rs index 37d44d16..4a1d3479 100644 --- a/openssl/src/string.rs +++ b/openssl/src/string.rs @@ -1,14 +1,20 @@ use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_void}; use std::fmt; use std::ffi::CStr; use std::ops::Deref; use std::str; -use types::{OpenSslType, OpenSslTypeRef}; use stack::Stackable; -type_!(OpensslString, OpensslStringRef, c_char, free); +foreign_type! { + type CType = c_char; + fn drop = free; + + pub struct OpensslString; + pub struct OpensslStringRef; +} impl OpensslString { #[deprecated(note = "use from_ptr", since = "0.9.7")] diff --git a/openssl/src/types.rs b/openssl/src/types.rs index 2fadfd42..25ffe501 100644 --- a/openssl/src/types.rs +++ b/openssl/src/types.rs @@ -1,40 +1,5 @@ -//! Items used by other types. +#[deprecated(note = "use foreign_types instead", since = "0.9.7")] +pub use foreign_types::ForeignType as OpenSslType; -/// A type implemented by wrappers over OpenSSL types. -/// -/// This should not be implemented by anything outside of this crate; new methods may be added at -/// any time. -pub trait OpenSslType: Sized { - /// The raw C type. - type CType; - - /// The type representing a reference to this type. - type Ref: OpenSslTypeRef; - - /// Constructs an instance of this type from its raw type. - unsafe fn from_ptr(ptr: *mut Self::CType) -> Self; -} - -/// A trait implemented by types which reference borrowed OpenSSL types. -/// -/// This should not be implemented by anything outside of this crate; new methods may be added at -/// any time. -pub trait OpenSslTypeRef: Sized { - /// The raw C type. - type CType; - - /// Constructs a shared instance of this type from its raw type. - unsafe fn from_ptr<'a>(ptr: *mut Self::CType) -> &'a Self { - &*(ptr as *mut _) - } - - /// Constructs a mutable reference of this type from its raw type. - unsafe fn from_ptr_mut<'a>(ptr: *mut Self::CType) -> &'a mut Self { - &mut *(ptr as *mut _) - } - - /// Returns a raw pointer to the wrapped value. - fn as_ptr(&self) -> *mut Self::CType { - self as *const _ as *mut _ - } -} +#[deprecated(note = "use foreign_types instead", since = "0.9.7")] +pub use foreign_types::ForeignTypeRef as OpenSslTypeRef; diff --git a/openssl/src/verify.rs b/openssl/src/verify.rs index 2f070fe5..f554127a 100644 --- a/openssl/src/verify.rs +++ b/openssl/src/verify.rs @@ -1,9 +1,9 @@ use libc::c_uint; use ffi; +use foreign_types::ForeignTypeRef; use cvt; use error::ErrorStack; -use types::OpenSslTypeRef; bitflags! { pub flags X509CheckFlags: c_uint { @@ -19,7 +19,13 @@ bitflags! { } } -type_!(X509VerifyParam, X509VerifyParamRef, ffi::X509_VERIFY_PARAM, ffi::X509_VERIFY_PARAM_free); +foreign_type! { + type CType = ffi::X509_VERIFY_PARAM; + fn drop = ffi::X509_VERIFY_PARAM_free; + + pub struct X509VerifyParam; + pub struct X509VerifyParamRef; +} impl X509VerifyParamRef { pub fn set_hostflags(&mut self, hostflags: X509CheckFlags) { diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index e75dcf5d..a0b76fef 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -1,3 +1,5 @@ +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_long, c_ulong}; use std::borrow::Borrow; use std::collections::HashMap; @@ -17,9 +19,7 @@ use hash::MessageDigest; use pkey::{PKey, PKeyRef}; use rand::rand_bytes; use error::ErrorStack; -use ffi; use nid::Nid; -use types::{OpenSslType, OpenSslTypeRef}; use string::OpensslString; use stack::{Stack, StackRef, Stackable}; @@ -53,7 +53,13 @@ pub const X509_FILETYPE_PEM: X509FileType = X509FileType(ffi::X509_FILETYPE_PEM) pub const X509_FILETYPE_ASN1: X509FileType = X509FileType(ffi::X509_FILETYPE_ASN1); pub const X509_FILETYPE_DEFAULT: X509FileType = X509FileType(ffi::X509_FILETYPE_DEFAULT); -type_!(X509StoreContext, X509StoreContextRef, ffi::X509_STORE_CTX, ffi::X509_STORE_CTX_free); +foreign_type! { + type CType = ffi::X509_STORE_CTX; + fn drop = ffi::X509_STORE_CTX_free; + + pub struct X509StoreContext; + pub struct X509StoreContextRef; +} impl X509StoreContextRef { pub fn error(&self) -> Option { @@ -354,7 +360,13 @@ impl X509Generator { } } -type_!(X509, X509Ref, ffi::X509, ffi::X509_free); +foreign_type! { + type CType = ffi::X509; + fn drop = ffi::X509_free; + + pub struct X509; + pub struct X509Ref; +} impl X509Ref { pub fn subject_name(&self) -> &X509NameRef { @@ -513,7 +525,13 @@ impl Stackable for X509 { type StackType = ffi::stack_st_X509; } -type_!(X509Name, X509NameRef, ffi::X509_NAME, ffi::X509_NAME_free); +foreign_type! { + type CType = ffi::X509_NAME; + fn drop = ffi::X509_NAME_free; + + pub struct X509Name; + pub struct X509NameRef; +} impl X509Name { /// Loads subject names from a file containing PEM-formatted certificates. @@ -567,7 +585,13 @@ impl<'a> Iterator for X509NameEntries<'a> { } } -type_!(X509NameEntry, X509NameEntryRef, ffi::X509_NAME_ENTRY, ffi::X509_NAME_ENTRY_free); +foreign_type! { + type CType = ffi::X509_NAME_ENTRY; + fn drop = ffi::X509_NAME_ENTRY_free; + + pub struct X509NameEntry; + pub struct X509NameEntryRef; +} impl X509NameEntryRef { pub fn data(&self) -> &Asn1StringRef { @@ -578,7 +602,13 @@ impl X509NameEntryRef { } } -type_!(X509Req, X509ReqRef, ffi::X509_REQ, ffi::X509_REQ_free); +foreign_type! { + type CType = ffi::X509_REQ; + fn drop = ffi::X509_REQ_free; + + pub struct X509Req; + pub struct X509ReqRef; +} impl X509Req { /// Reads CSR from PEM @@ -724,7 +754,13 @@ impl X509VerifyError { } } -type_!(GeneralName, GeneralNameRef, ffi::GENERAL_NAME, ffi::GENERAL_NAME_free); +foreign_type! { + type CType = ffi::GENERAL_NAME; + fn drop = ffi::GENERAL_NAME_free; + + pub struct GeneralName; + pub struct GeneralNameRef; +} impl GeneralNameRef { /// Returns the contents of this `GeneralName` if it is a `dNSName`. diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs index dd08a49b..8b7a084b 100644 --- a/openssl/src/x509/store.rs +++ b/openssl/src/x509/store.rs @@ -1,12 +1,18 @@ use ffi; +use foreign_types::ForeignTypeRef; use std::mem; use {cvt, cvt_p}; use error::ErrorStack; -use types::OpenSslTypeRef; use x509::X509; -type_!(X509StoreBuilder, X509StoreBuilderRef, ffi::X509_STORE, ffi::X509_STORE_free); +foreign_type! { + type CType = ffi::X509_STORE; + fn drop = ffi::X509_STORE_free; + + pub struct X509StoreBuilder; + pub struct X509StoreBuilderRef; +} impl X509StoreBuilder { /// Returns a builder for a certificate store. @@ -50,4 +56,10 @@ impl X509StoreBuilderRef { } } -type_!(X509Store, X509StoreRef, ffi::X509_STORE, ffi::X509_STORE_free); +foreign_type! { + type CType = ffi::X509_STORE; + fn drop = ffi::X509_STORE_free; + + pub struct X509Store; + pub struct X509StoreRef; +} From 8ae424235e1a09b5fdcd2879a960742d529c04da Mon Sep 17 00:00:00 2001 From: mredlek Date: Tue, 7 Feb 2017 21:49:07 +0100 Subject: [PATCH 134/140] Make it compile again. Make self mut in set_subject_name. Add assert to prevent a null pointer in subject_name. --- openssl/src/asn1.rs | 8 +++++++- openssl/src/x509/mod.rs | 3 ++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 8016df13..46c09740 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -93,7 +93,13 @@ impl Asn1StringRef { } } -type_!(Asn1Integer, Asn1IntegerRef, ffi::ASN1_INTEGER, ffi::ASN1_INTEGER_free); +foreign_type! { + type CType = ffi::ASN1_INTEGER; + fn drop = ffi::ASN1_INTEGER_free; + + pub struct Asn1Integer; + pub struct Asn1IntegerRef; +} impl Asn1IntegerRef { pub fn get(&self) -> i64 { diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 174635ca..d9fd36ef 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -647,11 +647,12 @@ impl X509ReqRef { pub fn subject_name(&self) -> &X509NameRef { unsafe { let name = compat::X509_REQ_get_subject_name(self.as_ptr()); + assert!(!name.is_null()); X509NameRef::from_ptr(name) } } - pub fn set_subject_name(&self, value: &X509NameRef) -> Result<(), ErrorStack> { + pub fn set_subject_name(&mut self, value: &X509NameRef) -> Result<(), ErrorStack> { unsafe { cvt(ffi::X509_REQ_set_subject_name(self.as_ptr(), value.as_ptr())).map(|_| ()) } From f1ef97beb7e0a4cc701328d03c92b0a927ee4c7f Mon Sep 17 00:00:00 2001 From: Stephan Buys Date: Wed, 8 Feb 2017 10:06:29 +0200 Subject: [PATCH 135/140] Add MacOS and XCode hint --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3a5b266b..c6d5ebda 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,12 @@ Homebrew: brew install openssl ``` +> Occasionally an update of XCode or MacOS will cause the linker to fail after complication, to rectify this you may want to try and run: + +```bash +xcode-select --install +``` + If Homebrew is installed to the default location of `/usr/local`, OpenSSL will be automatically detected. From a04594fccd7a3461be3f3402dc6b5de48ef7eadc Mon Sep 17 00:00:00 2001 From: Stephan Buys Date: Wed, 8 Feb 2017 18:58:22 +0200 Subject: [PATCH 136/140] complication -> compilation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c6d5ebda..3bc3960b 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ Homebrew: brew install openssl ``` -> Occasionally an update of XCode or MacOS will cause the linker to fail after complication, to rectify this you may want to try and run: +> Occasionally an update of XCode or MacOS will cause the linker to fail after compilation, to rectify this you may want to try and run: ```bash xcode-select --install From a1d7956f828a5208f16d49871b7c1965d21a6893 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 10 Feb 2017 19:38:51 -0800 Subject: [PATCH 137/140] Add Asn1BitString --- openssl-sys/src/lib.rs | 2 ++ openssl/src/asn1.rs | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index d18fa5ad..37921021 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -26,6 +26,7 @@ pub use libressl::*; pub enum ASN1_INTEGER {} pub enum ASN1_GENERALIZEDTIME {} pub enum ASN1_STRING {} +pub enum ASN1_BIT_STRING {} pub enum ASN1_TIME {} pub enum ASN1_TYPE {} pub enum BN_CTX {} @@ -1408,6 +1409,7 @@ extern { pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); pub fn ASN1_TIME_print(b: *mut BIO, tm: *const ASN1_TIME) -> c_int; + pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; pub fn BIO_free_all(b: *mut BIO); diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index fd932723..0ba54440 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -93,6 +93,24 @@ impl Asn1StringRef { } } +foreign_type! { + type CType = ffi::ASN1_BIT_STRING; + fn drop = ffi::ASN1_BIT_STRING_free; + + pub struct Asn1BitString; + pub struct Asn1BitStringRef; +} + +impl Asn1BitStringRef { + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr() as *mut _), self.len()) } + } + + pub fn len(&self) -> usize { + unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *mut _) as usize } + } +} + #[cfg(any(ossl101, ossl102))] use ffi::ASN1_STRING_data; From 8e5735d84c43cfc2a18c1178893eedf9b8373e8e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 10 Feb 2017 19:59:11 -0800 Subject: [PATCH 138/140] X509 signature access --- openssl-sys/src/lib.rs | 1 + openssl-sys/src/libressl.rs | 4 ++-- openssl-sys/src/ossl10x.rs | 6 ++++-- openssl-sys/src/ossl110.rs | 1 + openssl/src/x509/mod.rs | 32 +++++++++++++++++++++++++++----- openssl/src/x509/tests.rs | 15 +++++++++++++++ 6 files changed, 50 insertions(+), 9 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 37921021..817a6c88 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -48,6 +48,7 @@ pub enum OCSP_REQUEST {} pub enum OCSP_ONEREQ {} pub enum SSL_CIPHER {} pub enum SSL_METHOD {} +pub enum X509_ALGOR {} pub enum X509_CRL {} pub enum X509_EXTENSION {} pub enum X509_NAME {} diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index 2862a47e..d9a151f3 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -247,8 +247,8 @@ pub struct DH { #[repr(C)] pub struct X509 { pub cert_info: *mut X509_CINF, - sig_alg: *mut c_void, - signature: *mut c_void, + pub sig_alg: *mut ::X509_ALGOR, + pub signature: *mut ::ASN1_BIT_STRING, pub valid: c_int, pub references: c_int, pub name: *mut c_char, diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 14b7c414..061c880e 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -250,8 +250,8 @@ pub struct DH { #[repr(C)] pub struct X509 { pub cert_info: *mut X509_CINF, - sig_alg: *mut c_void, - signature: *mut c_void, + pub sig_alg: *mut ::X509_ALGOR, + pub signature: *mut ::ASN1_BIT_STRING, pub valid: c_int, pub references: c_int, pub name: *mut c_char, @@ -833,6 +833,8 @@ extern { pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; pub fn X509_set_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; pub fn X509_get_ext_d2i(x: *mut ::X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; + #[cfg(not(ossl101))] + pub fn X509_get0_signature(psig: *mut *mut ::ASN1_BIT_STRING, palg: *mut *mut ::X509_ALGOR, x: *const ::X509); pub fn X509_NAME_get_entry(n: *mut ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; pub fn X509_NAME_ENTRY_get_data(ne: *mut ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; pub fn X509_STORE_CTX_get_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index b7fdebab..7cabac50 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -127,6 +127,7 @@ extern { pub fn SSL_CTX_clear_options(ctx: *mut ::SSL_CTX, op: c_ulong) -> c_ulong; pub fn X509_getm_notAfter(x: *const ::X509) -> *mut ::ASN1_TIME; pub fn X509_getm_notBefore(x: *const ::X509) -> *mut ::ASN1_TIME; + pub fn X509_get0_signature(psig: *mut *const ::ASN1_BIT_STRING, palg: *mut *const ::X509_ALGOR, x: *const ::X509); pub fn DH_set0_pqg(dh: *mut ::DH, p: *mut ::BIGNUM, q: *mut ::BIGNUM, diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index a0b76fef..5829b8e4 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -13,7 +13,7 @@ use std::slice; use std::str; use {cvt, cvt_p}; -use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef}; +use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef, Asn1BitStringRef}; use bio::MemBioSlice; use hash::MessageDigest; use pkey::{PKey, PKeyRef}; @@ -410,8 +410,8 @@ impl X509Ref { } } - /// Returns certificate Not After validity period. - pub fn not_after<'a>(&'a self) -> &'a Asn1TimeRef { + /// Returns the certificate's Not After validity period. + pub fn not_after(&self) -> &Asn1TimeRef { unsafe { let date = compat::X509_get_notAfter(self.as_ptr()); assert!(!date.is_null()); @@ -419,8 +419,8 @@ impl X509Ref { } } - /// Returns certificate Not Before validity period. - pub fn not_before<'a>(&'a self) -> &'a Asn1TimeRef { + /// Returns the certificate's Not Before validity period. + pub fn not_before(&self) -> &Asn1TimeRef { unsafe { let date = compat::X509_get_notBefore(self.as_ptr()); assert!(!date.is_null()); @@ -428,6 +428,16 @@ impl X509Ref { } } + /// Returns the certificate's signature + pub fn signature(&self) -> &Asn1BitStringRef { + unsafe { + let mut signature = ptr::null(); + compat::X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); + assert!(!signature.is_null()); + Asn1BitStringRef::from_ptr(signature as *mut _) + } + } + /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information /// Access field. pub fn ocsp_responders(&self) -> Result, ErrorStack> { @@ -815,6 +825,7 @@ mod compat { pub use ffi::X509_getm_notBefore as X509_get_notBefore; pub use ffi::X509_up_ref; pub use ffi::X509_get0_extensions; + pub use ffi::X509_get0_signature; } #[cfg(ossl10x)] @@ -848,4 +859,15 @@ mod compat { (*info).extensions } } + + pub unsafe fn X509_get0_signature(psig: *mut *const ffi::ASN1_BIT_STRING, + palg: *mut *const ffi::X509_ALGOR, + x: *const ffi::X509) { + if !psig.is_null() { + *psig = (*x).signature; + } + if !palg.is_null() { + *palg = (*x).sig_alg; + } + } } diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 01cbf2ec..abd83ec1 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -220,3 +220,18 @@ fn ecdsa_cert() { ctx.set_private_key(&key).unwrap(); ctx.check_private_key().unwrap(); } + +#[test] +fn signature() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + let signature = cert.signature(); + assert_eq!(signature.as_slice().to_hex(), + "4af607b889790b43470442cfa551cdb8b6d0b0340d2958f76b9e3ef6ad4992230cead6842587f0ecad5\ + 78e6e11a221521e940187e3d6652de14e84e82f6671f097cc47932e022add3c0cb54a26bf27fa84c107\ + 4971caa6bee2e42d34a5b066c427f2d452038082b8073993399548088429de034fdd589dcfb0dd33be7\ + ebdfdf698a28d628a89568881d658151276bde333600969502c4e62e1d3470a683364dfb241f78d310a\ + 89c119297df093eb36b7fd7540224f488806780305d1e79ffc938fe2275441726522ab36d88348e6c51\ + f13dcc46b5e1cdac23c974fd5ef86aa41e91c9311655090a52333bc79687c748d833595d4c5f987508f\ + e121997410d37c"); +} From 03fe3015dc7f8ec321e483c3dde63766f1c365ad Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 10 Feb 2017 21:37:33 -0800 Subject: [PATCH 139/140] X509 signature algorithm access --- openssl-sys/src/lib.rs | 8 +++++- openssl-sys/src/libressl.rs | 6 +++++ openssl-sys/src/ossl10x.rs | 10 ++++++++ openssl-sys/src/ossl110.rs | 3 +++ openssl/src/asn1.rs | 34 ++++++++++++++++++++++++- openssl/src/x509/mod.rs | 49 +++++++++++++++++++++++++++++++------ openssl/src/x509/tests.rs | 3 +++ 7 files changed, 103 insertions(+), 10 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 817a6c88..68943c87 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -29,6 +29,7 @@ pub enum ASN1_STRING {} pub enum ASN1_BIT_STRING {} pub enum ASN1_TIME {} pub enum ASN1_TYPE {} +pub enum ASN1_OBJECT {} pub enum BN_CTX {} pub enum BN_GENCB {} pub enum CONF {} @@ -48,7 +49,6 @@ pub enum OCSP_REQUEST {} pub enum OCSP_ONEREQ {} pub enum SSL_CIPHER {} pub enum SSL_METHOD {} -pub enum X509_ALGOR {} pub enum X509_CRL {} pub enum X509_EXTENSION {} pub enum X509_NAME {} @@ -1411,6 +1411,7 @@ extern { pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); pub fn ASN1_TIME_print(b: *mut BIO, tm: *const ASN1_TIME) -> c_int; pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); + pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; pub fn BIO_free_all(b: *mut BIO); @@ -1655,6 +1656,9 @@ extern { pub fn HMAC_CTX_copy(dst: *mut HMAC_CTX, src: *mut HMAC_CTX) -> c_int; + pub fn OBJ_obj2nid(o: *const ASN1_OBJECT) -> c_int; + pub fn OBJ_obj2txt(buf: *mut c_char, buf_len: c_int, a: *const ASN1_OBJECT, no_name: c_int) -> c_int; + pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP; pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP); pub fn OCSP_basic_verify(bs: *mut OCSP_BASICRESP, certs: *mut stack_st_X509, st: *mut X509_STORE, flags: c_ulong) -> c_int; @@ -1928,6 +1932,8 @@ extern { 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_ALGOR_free(x: *mut X509_ALGOR); + pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); pub fn X509_NAME_free(x: *mut X509_NAME); diff --git a/openssl-sys/src/libressl.rs b/openssl-sys/src/libressl.rs index d9a151f3..1bb17849 100644 --- a/openssl-sys/src/libressl.rs +++ b/openssl-sys/src/libressl.rs @@ -285,6 +285,12 @@ pub struct X509_CINF { enc: ASN1_ENCODING, } +#[repr(C)] +pub struct X509_ALGOR { + pub algorithm: *mut ::ASN1_OBJECT, + parameter: *mut c_void, +} + #[repr(C)] pub struct ASN1_ENCODING { pub enc: *mut c_uchar, diff --git a/openssl-sys/src/ossl10x.rs b/openssl-sys/src/ossl10x.rs index 061c880e..f709c46f 100644 --- a/openssl-sys/src/ossl10x.rs +++ b/openssl-sys/src/ossl10x.rs @@ -292,6 +292,12 @@ pub struct X509_CINF { enc: ASN1_ENCODING, } +#[repr(C)] +pub struct X509_ALGOR { + pub algorithm: *mut ::ASN1_OBJECT, + parameter: *mut c_void, +} + #[repr(C)] pub struct ASN1_ENCODING { pub enc: *mut c_uchar, @@ -835,6 +841,10 @@ extern { pub fn X509_get_ext_d2i(x: *mut ::X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; #[cfg(not(ossl101))] pub fn X509_get0_signature(psig: *mut *mut ::ASN1_BIT_STRING, palg: *mut *mut ::X509_ALGOR, x: *const ::X509); + #[cfg(not(ossl101))] + pub fn X509_get_signature_nid(x: *const X509) -> c_int; + #[cfg(not(ossl101))] + pub fn X509_ALGOR_get0(paobj: *mut *mut ::ASN1_OBJECT, pptype: *mut c_int, ppval: *mut *mut c_void, alg: *mut ::X509_ALGOR); pub fn X509_NAME_get_entry(n: *mut ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; pub fn X509_NAME_ENTRY_get_data(ne: *mut ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; pub fn X509_STORE_CTX_get_chain(ctx: *mut ::X509_STORE_CTX) -> *mut stack_st_X509; diff --git a/openssl-sys/src/ossl110.rs b/openssl-sys/src/ossl110.rs index 7cabac50..68a62c6c 100644 --- a/openssl-sys/src/ossl110.rs +++ b/openssl-sys/src/ossl110.rs @@ -26,6 +26,7 @@ pub enum stack_st_X509_ATTRIBUTE {} pub enum stack_st_X509_EXTENSION {} pub enum stack_st_SSL_CIPHER {} pub enum X509 {} +pub enum X509_ALGOR {} pub enum X509_VERIFY_PARAM {} pub const SSL_OP_MICROSOFT_SESS_ID_BUG: c_ulong = 0x00000000; @@ -84,6 +85,8 @@ extern { pub fn X509_set1_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; pub fn X509_set1_notBefore(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; pub fn X509_get_ext_d2i(x: *const ::X509, nid: c_int, crit: *mut c_int, idx: *mut c_int) -> *mut c_void; + pub fn X509_get_signature_nid(x: *const X509) -> c_int; + pub fn X509_ALGOR_get0(paobj: *mut *const ::ASN1_OBJECT, pptype: *mut c_int, ppval: *mut *const c_void, alg: *const ::X509_ALGOR); pub fn X509_NAME_get_entry(n: *const ::X509_NAME, loc: c_int) -> *mut ::X509_NAME_ENTRY; pub fn X509_NAME_ENTRY_get_data(ne: *const ::X509_NAME_ENTRY) -> *mut ::ASN1_STRING; pub fn X509V3_EXT_nconf_nid(conf: *mut ::CONF, ctx: *mut ::X509V3_CTX, ext_nid: c_int, value: *const c_char) -> *mut ::X509_EXTENSION; diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 0ba54440..2c38e14d 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -1,6 +1,6 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; -use libc::{c_long, c_char}; +use libc::{c_long, c_char, c_int}; use std::fmt; use std::ptr; use std::slice; @@ -9,6 +9,7 @@ use std::str; use {cvt, cvt_p}; use bio::MemBio; use error::ErrorStack; +use nid::Nid; use string::OpensslString; foreign_type! { @@ -111,6 +112,37 @@ impl Asn1BitStringRef { } } +foreign_type! { + type CType = ffi::ASN1_OBJECT; + fn drop = ffi::ASN1_OBJECT_free; + + pub struct Asn1Object; + pub struct Asn1ObjectRef; +} + +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); + let s = try!(str::from_utf8(&buf[..len as usize]).map_err(|_| fmt::Error)); + fmt.write_str(s) + } + } +} + #[cfg(any(ossl101, ossl102))] use ffi::ASN1_STRING_data; diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 5829b8e4..de7aece7 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -13,7 +13,7 @@ use std::slice; use std::str; use {cvt, cvt_p}; -use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef, Asn1BitStringRef}; +use asn1::{Asn1StringRef, Asn1Time, Asn1TimeRef, Asn1BitStringRef, Asn1ObjectRef}; use bio::MemBioSlice; use hash::MessageDigest; use pkey::{PKey, PKeyRef}; @@ -438,6 +438,16 @@ impl X509Ref { } } + /// Returns the certificate's signature algorithm. + pub fn signature_algorithm(&self) -> &X509AlgorithmRef { + unsafe { + let mut algor = ptr::null(); + compat::X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); + assert!(!algor.is_null()); + X509AlgorithmRef::from_ptr(algor as *mut _) + } + } + /// Returns the list of OCSP responder URLs specified in the certificate's Authority Information /// Access field. pub fn ocsp_responders(&self) -> Result, ErrorStack> { @@ -810,12 +820,23 @@ impl Stackable for GeneralName { type StackType = ffi::stack_st_GENERAL_NAME; } -#[test] -fn test_negative_serial() { - // I guess that's enough to get a random negative number - for _ in 0..1000 { - assert!(X509Generator::random_serial().unwrap() > 0, - "All serials should be positive"); +foreign_type! { + type CType = ffi::X509_ALGOR; + fn drop = ffi::X509_ALGOR_free; + + pub struct X509Algorithm; + pub struct X509AlgorithmRef; +} + +impl X509AlgorithmRef { + /// Returns the ASN.1 OID of this algorithm. + pub fn object(&self) -> &Asn1ObjectRef { + unsafe { + let mut oid = ptr::null(); + compat::X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); + assert!(!oid.is_null()); + Asn1ObjectRef::from_ptr(oid as *mut _) + } } } @@ -826,12 +847,13 @@ mod compat { pub use ffi::X509_up_ref; pub use ffi::X509_get0_extensions; pub use ffi::X509_get0_signature; + pub use ffi::X509_ALGOR_get0; } #[cfg(ossl10x)] #[allow(bad_style)] mod compat { - use libc::c_int; + use libc::{c_int, c_void}; use ffi; pub unsafe fn X509_get_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { @@ -870,4 +892,15 @@ mod compat { *palg = (*x).sig_alg; } } + + pub unsafe fn X509_ALGOR_get0(paobj: *mut *const ffi::ASN1_OBJECT, + pptype: *mut c_int, + pval: *mut *mut c_void, + alg: *const ffi::X509_ALGOR) { + if !paobj.is_null() { + *paobj = (*alg).algorithm; + } + assert!(pptype.is_null()); + assert!(pval.is_null()); + } } diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index abd83ec1..d6ec7beb 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -234,4 +234,7 @@ fn signature() { 89c119297df093eb36b7fd7540224f488806780305d1e79ffc938fe2275441726522ab36d88348e6c51\ f13dcc46b5e1cdac23c974fd5ef86aa41e91c9311655090a52333bc79687c748d833595d4c5f987508f\ e121997410d37c"); + let algorithm = cert.signature_algorithm(); + assert_eq!(algorithm.object().nid(), nid::SHA256WITHRSAENCRYPTION); + assert_eq!(algorithm.object().to_string(), "sha256WithRSAEncryption"); } From 5ad4af70ae4bb2c04c1df5d4adda05c4f6b54295 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 11 Feb 2017 09:17:39 -0800 Subject: [PATCH 140/140] Re-add reexport --- openssl/src/x509/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 79f36e7c..0d329da4 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -873,6 +873,7 @@ mod compat { pub use ffi::X509_getm_notAfter as X509_get_notAfter; pub use ffi::X509_getm_notBefore as X509_get_notBefore; pub use ffi::X509_up_ref; + pub use ffi::X509_get0_extensions; pub use ffi::X509_REQ_get_version; pub use ffi::X509_REQ_get_subject_name; pub use ffi::X509_get0_signature;