From 203a02c3e6472330160bb1746d46202d5e8c78fe Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Nov 2016 20:25:57 +0000 Subject: 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/src/symm.rs | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 3 deletions(-) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From 913723997bc12281d2851c91f402871391810553 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Nov 2016 22:35:16 +0000 Subject: Add convenience functions for AEAD encryption/decryption --- openssl/src/symm.rs | 71 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 57 insertions(+), 14 deletions(-) (limited to 'openssl/src') 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()); } } -- cgit v1.2.3 From aa7c27536ad56def21afad4043d6d658f517ecc4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 8 Nov 2016 22:38:48 +0000 Subject: 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(-) (limited to 'openssl/src') 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) -- cgit v1.2.3 From 7c8ae5f664ee9d36cc42527208362c9bfe5b25ab Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Nov 2016 18:54:29 +0000 Subject: Better docs for AEAD tag --- openssl/src/symm.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'openssl/src') 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(), -- cgit v1.2.3 From a42c6e8713702175001686c6f146bb4b99023613 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 9 Nov 2016 20:35:23 +0000 Subject: Drop rustc-serialize dependency --- 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 ++-- 7 files changed, 45 insertions(+), 49 deletions(-) (limited to 'openssl/src') 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); } -- cgit v1.2.3 From 898e7f02df5ca722f4b4b42a8e116f96f72b9452 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 15:10:30 +0000 Subject: 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(-) (limited to 'openssl/src') 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. -- cgit v1.2.3 From 0d2d4865e5d98dcc19968b8428a7aee2a747091a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 16:44:19 +0000 Subject: Release v0.9.1 --- openssl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 609a09ebb90cf44524ce299b968ce19173583ce8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 18:52:27 +0000 Subject: Add PKey::dsa Closes #501 --- openssl/src/pkey.rs | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From 32cbed0782d47b036938316805f63ed6cc2ea759 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 19:04:54 +0000 Subject: PKey <-> DH conversions Closes #498 --- openssl/src/pkey.rs | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From 15490a43e399ce0f6e3838c96c609abf08b1c5db Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 19:17:26 +0000 Subject: Add EcKey <-> PKey conversions Closes #499 --- openssl/src/ec_key.rs | 7 +++++-- openssl/src/pkey.rs | 32 +++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From 6b7279eb5224a422860d0adb38becd5bca19763f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 11 Nov 2016 19:49:00 +0000 Subject: Consistently support both PEM and DER encodings Closes #500 --- openssl/src/dh.rs | 48 +++++++++++++++++++++++++++++++++++++++--------- openssl/src/dsa.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++---- openssl/src/pkey.rs | 19 ++++++++++++++----- openssl/src/rsa.rs | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 144 insertions(+), 19 deletions(-) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 26a3358a2b70b46bf06403b2810c379f5299a551 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 00:24:12 +0000 Subject: Add basic X509_STORE access There's more to do here, but this enabled addition of trusted CAs from X509 objects. Closes #394 --- 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 ++++++++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 openssl/src/x509/store.rs (limited to 'openssl/src') 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(|_| ()) + } + } +} -- cgit v1.2.3 From 9b5c62b053fb84dc233c69ba1700bee9b8a4387f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 11:00:15 +0000 Subject: Add PKey::bits --- openssl/src/pkey.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'openssl/src') 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 } } -- cgit v1.2.3 From b14d68f715b3ba02e671d9c3e158abcf89237ef9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 11:14:05 +0000 Subject: Drop bits to u32 --- openssl/src/pkey.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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. -- cgit v1.2.3 From 563754fb0892ebf8021bb6043f4540c98f3b86a6 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 12:43:44 +0000 Subject: Add SslContextBuilder::set_tmp_{ec,}dh_callback --- openssl/src/dsa.rs | 1 + openssl/src/rsa.rs | 1 + openssl/src/ssl/mod.rs | 91 +++++++++++++++++++++++++++++++++++++++++--- openssl/src/ssl/tests/mod.rs | 65 +++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 6 deletions(-) (limited to 'openssl/src') 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() {} -- cgit v1.2.3 From 780c46e0e722f683ba6a8b7a8b2a7924e49695c3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 12:56:58 +0000 Subject: 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(-) (limited to 'openssl/src') 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() {} -- cgit v1.2.3 From 93253ba5991414a86fe10db4e74c4a7bfeae19fc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:09:12 +0000 Subject: Adjust cipher lists to work on older versions --- openssl/src/ssl/tests/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 2a1d7b2bcb229283c85a991dd97aa83f59b02ed2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:35:51 +0000 Subject: 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(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 96d24c89575c4d2e193f31de67e1ba273f15d6b0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 13:45:54 +0000 Subject: Add SslRef::set_{tmp_dh,tmp_ecdh,ecdh_auto} --- openssl/src/ssl/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'openssl/src') 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()); -- cgit v1.2.3 From 796d7b4deb547f1cd0bce0d54dea2dc5cdf650bb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 14:14:56 +0000 Subject: Add constructors for various standard primes --- openssl/src/bn.rs | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'openssl/src') 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. /// /// ``` -- cgit v1.2.3 From 157034d995f9bcb930b186acb2dbcddb5efada8b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 14:30:53 +0000 Subject: Add a missing init --- openssl/src/bn.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'openssl/src') 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)) -- cgit v1.2.3 From 7cdb58bc47fdc8060593b48d5624e7d14b5ac285 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 14:42:48 +0000 Subject: Simplify test logic a bit --- openssl/src/ssl/tests/mod.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 6b3599d319977ac3c60677638d29783a9e9f4f60 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 16:45:18 +0000 Subject: 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(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 2f8301fc63114120b930fbb5779e383f1b100635 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 16:51:26 +0000 Subject: 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(-) (limited to 'openssl/src') 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] -- cgit v1.2.3 From 64e9932ac92bdb63896b49922146c602769e066d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 12 Nov 2016 17:52:58 +0000 Subject: Use ffdhe2048 in mozilla_intermediate --- openssl/src/ssl/connector.rs | 50 +++++++------------------------------------- 1 file changed, 8 insertions(+), 42 deletions(-) (limited to 'openssl/src') 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()); - } -} -- cgit v1.2.3 From 85c1474ce68932d4fad0e53144cf43428b5e12c7 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 12:19:31 +0000 Subject: No need to use a raw string anymore --- openssl/src/ssl/connector.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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)); -- cgit v1.2.3 From 08e0c4ca9061c3dc0c951db0c08909689b04a310 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 15:02:38 +0000 Subject: Some serialization support for EcKey --- 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 +++++++++++++++++---- 7 files changed, 148 insertions(+), 118 deletions(-) create mode 100644 openssl/src/macros.rs (limited to 'openssl/src') 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)); - - 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)) - } - } + private_key_from_pem!(Dsa, ffi::PEM_read_bio_DSAPrivateKey); - /// 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) })); -- cgit v1.2.3 From 2a8923c05073d533175ed94d2931a3a79273a684 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 15:12:50 +0000 Subject: 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(-) (limited to 'openssl/src') 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> { -- cgit v1.2.3 From 7d411c7975cf578205f81c2e1440c1b482a8a1a8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 15:27:39 +0000 Subject: 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(-) (limited to 'openssl/src') 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| { -- cgit v1.2.3 From 387e78257b578fef5933142085aefa1c76722b49 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 16:09:52 +0000 Subject: Support serialization of encrypted private keys Switch to PEM_write_bio_PKCS8PrivateKey since the other function outputs nonstandard PEM when encrypting. --- openssl/src/dsa.rs | 10 ++++++++++ openssl/src/macros.rs | 20 ++++++++++++++++++++ openssl/src/pkey.rs | 12 +++++++++++- openssl/src/rsa.rs | 16 +++++++++++++--- 4 files changed, 54 insertions(+), 4 deletions(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From ed9f600e2889906bb928150d7e892370062f6ca1 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 16:18:52 +0000 Subject: 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(-) (limited to 'openssl/src') 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 -- cgit v1.2.3 From b0415f466c4b62f949b1e47e6b1e703d1b24122b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 16:52:19 +0000 Subject: Macroise to_der --- 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 ++---------------- 7 files changed, 47 insertions(+), 91 deletions(-) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 48c0009418cbbf7c69c24b35d56e80edb0c80d45 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 17:06:50 +0000 Subject: Macroise from_der --- 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 +++---------- 7 files changed, 52 insertions(+), 92 deletions(-) (limited to 'openssl/src') 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. -- cgit v1.2.3 From df9666c334f29d4d0887919c2b35c45092960d3a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 17:42:45 +0000 Subject: 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(-) (limited to 'openssl/src') 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 -- cgit v1.2.3 From ccef9e339dc3717761fc9e70c34f1df86b608579 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 17:56:48 +0000 Subject: 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(-) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 7dbef567e6cec78adb1d7ec55735935ca7de20fd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 18:00:42 +0000 Subject: 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(-) (limited to 'openssl/src') 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); -- cgit v1.2.3 From b2de36049a7687da00870e714c2e299ac5a903cd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:19:38 +0000 Subject: Add Some more elliptic curve functionality --- openssl/src/ec_key.rs | 114 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) (limited to 'openssl/src') 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(); + } } -- cgit v1.2.3 From 0d0b5080e25fb0a2f9ada042810b98d28f5e0414 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:21:44 +0000 Subject: 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(-) (limited to 'openssl/src') 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) } -- cgit v1.2.3 From 3d31539ba9f0c1f57869d7e50e433a0ef5850138 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:31:44 +0000 Subject: Public keys are not always present --- openssl/src/ec_key.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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()); -- cgit v1.2.3 From 1a52649516e5b3924917314ee503523d59ed528b Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 20:46:01 +0000 Subject: More functionality --- openssl/src/ec_key.rs | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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(); + } } -- cgit v1.2.3 From 35f11d555eefd4a122b7d4688d589dcc1e918fcf Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 22:06:18 +0000 Subject: More functionality --- openssl/src/ec_key.rs | 157 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From 82eb3c4f516e1457ec2fec56a4233aa4542957cc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 13 Nov 2016 22:10:52 +0000 Subject: Add EcKey::check_key --- openssl/src/ec_key.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 4c60aa005d1bcce1a0cb41df82422d9ac7c55815 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 19:20:08 +0100 Subject: Fix non-static EcGroup method locations --- openssl/src/ec_key.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openssl/src') 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, -- cgit v1.2.3 From e929e092169dba0dfda26a957a38c61fa3e33eb2 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 19:44:20 +0100 Subject: Add EcPoint::invert --- openssl/src/ec_key.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'openssl/src') 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, -- cgit v1.2.3 From 90acfaea513ad079119e7b3485a9a2e35702ad33 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 22:08:04 +0100 Subject: Split EcKey::mul --- openssl/src/ec_key.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) (limited to 'openssl/src') 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())) -- cgit v1.2.3 From 6794a45d602def6812a70841f8b012445f62c7ac Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 14 Nov 2016 22:37:01 +0100 Subject: 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 (limited to 'openssl/src') 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; -- cgit v1.2.3 From b914f779e83647df0cfeb9444de0a2eed18a1eb5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Nov 2016 21:20:06 +0100 Subject: Turns out yet another variant of EC_POINT_mul is allowed! --- openssl/src/ec.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'openssl/src') 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(), -- cgit v1.2.3 From ec0fa36714a082ac7529dac7e0a8928f95a5bef0 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Nov 2016 21:24:34 +0100 Subject: Add a test for mul_generator --- openssl/src/ec.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From 7515510125396db580d3aaa4efd28c51b02aa708 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 15 Nov 2016 22:06:20 +0100 Subject: Test elliptic curve signatures --- openssl/src/sign.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From e58dda89900dd30c14811b981b43f24352c683bd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 16 Nov 2016 13:53:03 +0100 Subject: 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(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 8b60d4a3c2822ab20988439c46f973ae86367d48 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 16 Nov 2016 15:45:15 -0800 Subject: Return Option from group --- openssl/src/ec.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'openssl/src') 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 _)) + } } } -- cgit v1.2.3 From 234f126d7d9718bd95655aca5fa6f57dc2c4270a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 19 Nov 2016 10:19:52 -0800 Subject: 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(-) (limited to 'openssl/src') 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) } } -- cgit v1.2.3 From 146512099b484928e9b9396d4b8a476b1c47ee54 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 27 Nov 2016 21:35:35 -0800 Subject: Implement Clone for SslConnector and SslAcceptor --- openssl/src/ssl/connector.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 0602712bf4e4e0451fcd527edc4e50a768e9b8d3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 27 Nov 2016 22:23:32 -0800 Subject: Release v0.9.2 --- openssl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 00816653399ceb3a06a35c3b7c3fb161891f5763 Mon Sep 17 00:00:00 2001 From: 0xa Date: Fri, 9 Dec 2016 17:06:15 +0000 Subject: Add Blowfish support --- openssl/src/symm.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'openssl/src') 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()) } } -- cgit v1.2.3 From 0850f605b1fcb686bae341a4763d072af4c67e50 Mon Sep 17 00:00:00 2001 From: 0xa Date: Fri, 9 Dec 2016 18:42:10 +0000 Subject: Use EVP_bf_cfb64 instead of EVP_bf_cfb --- openssl/src/symm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 5340895249164e0761996b5adbdb4587122880dc Mon Sep 17 00:00:00 2001 From: 0xa Date: Fri, 9 Dec 2016 21:26:58 +0000 Subject: Add Blowfish tests --- openssl/src/symm.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'openssl/src') 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() { -- cgit v1.2.3 From 152d7889981f2f25a8134c9f8082e5024ba9073e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 9 Dec 2016 21:32:28 -0800 Subject: Fix ErrorStack display --- openssl/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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(()) } -- cgit v1.2.3 From 26cefe7d97595db76be9a5b76ac12834096454cd Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 9 Dec 2016 21:52:43 -0800 Subject: Switch to docs.rs for docs --- openssl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 791f2c8f4d70f49f2face6ea56ef924a784c12fb Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 9 Dec 2016 21:54:06 -0800 Subject: Release v0.9.3 --- openssl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 8e01f8d2502098497e642ee477d926a99ee619a8 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 20 Dec 2016 14:04:10 -0800 Subject: 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(+) (limited to 'openssl/src') 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(); -- cgit v1.2.3 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: Add LibreSSL 2.5.0 support --- openssl/src/ssl/mod.rs | 3 +++ openssl/src/ssl/tests/mod.rs | 8 ++++---- openssl/src/version.rs | 7 ++++++- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'openssl/src') 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:")); -- cgit v1.2.3 From 762510a5faf8c38d0aab6b86d19bc0c7c24e8e78 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 23 Dec 2016 13:38:00 -0500 Subject: Release v0.9.4 --- openssl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 5c49b58a88e5e30c695b0f5a5fc6bb267efe8a84 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 31 Dec 2016 09:44:57 -0800 Subject: Indicate that memcmp::eq should be used for HMACs --- openssl/src/sign.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'openssl/src') 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}; -- cgit v1.2.3 From 444c00955a5622ff694eaefd75f047e7eabbad2a Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Sat, 31 Dec 2016 10:40:56 -0800 Subject: add EcKey creation from EcPoint, public_key --- openssl/src/ec.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From 85a6e8acca7af3a86ad609de8347af6ef7e17b48 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 09:53:08 -0800 Subject: Fix doc reference --- openssl/src/pkcs5.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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], -- cgit v1.2.3 From cdabc1b3e3fb57874df1a31e01cf6019433fea9c Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 10:07:32 -0800 Subject: Fix docs --- openssl/src/hash.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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}; -- cgit v1.2.3 From 7e75c76bb4c1bbf7b21181aeb7aab919dcee2576 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 10:13:34 -0800 Subject: Stick tag description on the right function --- openssl/src/symm.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'openssl/src') 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]>, -- cgit v1.2.3 From 0e0bee50a59ab65c310122dc6300416eadfea851 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 10:18:43 -0800 Subject: Clean up bio --- openssl/src/ssl/bio.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'openssl/src') 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; } -- cgit v1.2.3 From 0483ea767cf51615e22f7730df31aeca55bca455 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 1 Jan 2017 11:05:54 -0800 Subject: Little cleanup --- openssl/src/version.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'openssl/src') 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: /// -- cgit v1.2.3 From cfb2539ed45fd11cec1af850256078ec494d8987 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 2 Jan 2017 09:37:31 -0800 Subject: Typo --- openssl/src/ssl/connector.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 1767cd5464c18c37730eddeba6f74dc5721c7bf1 Mon Sep 17 00:00:00 2001 From: Philipp Keck Date: Tue, 3 Jan 2017 14:48:46 +0100 Subject: 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(+) (limited to 'openssl/src') 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); -- cgit v1.2.3 From e2f1569500b8d66f6a1f69923676df816430a27d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Jan 2017 12:35:52 -0800 Subject: Tweak layout a little bit --- openssl/src/pkey.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'openssl/src') 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); -- cgit v1.2.3 From 6291407b177dfb8bee0b50974cad57c98da110f8 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Jan 2017 14:56:00 -0800 Subject: Add X509::stack_from_pem Implementation is a clone of SSL_CTX_use_certificate_chain_file --- openssl/src/x509/mod.rs | 30 ++++++++++++++++++++++++++++++ openssl/src/x509/tests.rs | 14 +++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) (limited to 'openssl/src') 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"); +} -- cgit v1.2.3 From dbd6134fd66ef5947013c185f3fa44d8ee8e288e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Jan 2017 15:33:45 -0800 Subject: Clean up EcKey example a bit --- openssl/src/ec.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From cdf388e3f44b49a5ea4255b9674d8e1ded2ba472 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 3 Jan 2017 16:09:24 -0800 Subject: Release v0.9.5 --- openssl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 88a7032f4b78895eaeeb72d3837dd698e571e882 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 20:59:46 -0800 Subject: Types and accessor for SslSession --- openssl/src/ssl/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 5d53405597f2e8dc3a6543e8c4a56705b0ecd47a Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:07:51 -0800 Subject: Provide access to the session ID --- openssl/src/ssl/mod.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 0b1bfee46d6c986d6cb073c922045ae98b598900 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:15:09 -0800 Subject: session is nullable --- openssl/src/ssl/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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)) + } + } } } -- cgit v1.2.3 From a2c118bf82ac4fbb13d5dd32b931490862ccd930 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:18:13 -0800 Subject: Add basic session tests --- openssl/src/ssl/tests/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'openssl/src') 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() {} -- cgit v1.2.3 From 404e0341d82d5aab58daaa48b864eaf1a281d101 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 4 Jan 2017 21:33:47 -0800 Subject: Provide master key access --- openssl/src/ssl/mod.rs | 28 +++++++++++++++++++++++++++- openssl/src/ssl/tests/mod.rs | 10 +++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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() { -- cgit v1.2.3 From 0978f870956ff06dee2e7dcbb6a30c6cbfce6e1e Mon Sep 17 00:00:00 2001 From: Marc-Antoine Perennou Date: Thu, 5 Jan 2017 16:15:53 +0100 Subject: 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(-) (limited to 'openssl/src') 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(|_| ()) } } -- cgit v1.2.3 From 1942977408a6483770332f316fc012e06ad757b9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 8 Jan 2017 10:57:04 -0800 Subject: 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(-) (limited to 'openssl/src') 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))] -- cgit v1.2.3 From 1fbe8f8d71b2559d901c6cc1f5a1a754634a966d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 8 Jan 2017 11:04:47 -0800 Subject: Fix typo --- openssl/src/ssl/connector.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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)); -- cgit v1.2.3 From 9942643ab6fbdecb0561fcdc08565d4f154865b3 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 9 Jan 2017 20:50:26 -0800 Subject: Release v0.9.6 --- openssl/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 920ab0d6fb60c17077f43d7f08ad3ff391201689 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 13 Jan 2017 19:38:12 -0800 Subject: OCSP functionality --- 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 +- 11 files changed, 627 insertions(+), 78 deletions(-) create mode 100644 openssl/src/ocsp.rs create mode 100644 openssl/src/string.rs (limited to 'openssl/src') 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(); +} -- cgit v1.2.3 From d353b366811023049eb77189234abc8196f9372f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 20 Jan 2017 22:34:30 +0000 Subject: Support AES IGE This is a special snowflake used only by Telegram apparently. Closes #523 --- openssl/src/aes.rs | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++ openssl/src/lib.rs | 1 + 2 files changed, 116 insertions(+) create mode 100644 openssl/src/aes.rs (limited to 'openssl/src') 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; -- cgit v1.2.3 From 26e159a5f07a36be24fc35221154fdaebcabdf02 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 21 Jan 2017 11:11:24 +0000 Subject: Support chacha20 and chacha20_poly1305 --- openssl/src/crypto.rs | 1 - openssl/src/ocsp.rs | 2 +- openssl/src/symm.rs | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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()); + } } -- cgit v1.2.3 From 1ffdf8a1ab75f49b95bae96d4dac31ab6cd3f526 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 21 Jan 2017 14:43:43 +0000 Subject: Fix test warnings --- openssl/src/ssl/tests/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 54900976bb76d3cef4a78df48a3645b0ac49bb46 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 22 Jan 2017 10:44:59 +0000 Subject: Support EC_GROUP_set_asn1_flag Closes #561 --- openssl/src/ec.rs | 84 +++++++++++++++++++++++++++++++++++++++-------- openssl/src/x509/tests.rs | 23 +++++++++++++ 2 files changed, 94 insertions(+), 13 deletions(-) (limited to 'openssl/src') 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(); +} -- cgit v1.2.3 From 52c7868bb615b04feb01be88cd1f47af866f12ad Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Sun, 22 Jan 2017 21:27:31 -0800 Subject: add pkcs12_create and to_der funcs --- openssl/src/pkcs12.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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)); + } } -- cgit v1.2.3 From fbfecd63aeb0cd1ee24d017df2d89078a53bf0fe Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Sun, 22 Jan 2017 22:23:21 -0800 Subject: add some documentation --- openssl/src/pkcs12.rs | 67 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 26 deletions(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 591022a7fa4b43d152154fd95bb67fce5ecfa28e Mon Sep 17 00:00:00 2001 From: Benjamin Fry Date: Mon, 23 Jan 2017 22:12:11 -0800 Subject: fix multi-version compat --- openssl/src/pkcs12.rs | 62 ++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 35 deletions(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 15b1b348b29590ec9221f1dfdb164651c2e21b29 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 25 Jan 2017 11:13:59 +0000 Subject: Pkcs12Builder tweaks --- openssl/src/pkcs12.rs | 61 ++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'openssl/src') 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) } } } -- cgit v1.2.3 From 557b936e27177718b62d31dcf3364f481bb15c2c Mon Sep 17 00:00:00 2001 From: mredlek Date: Thu, 26 Jan 2017 20:59:32 +0100 Subject: Added X509ReqRef.subject_name and X509ReqRef.version --- openssl/src/asn1.rs | 22 ++++++++++++++++++++++ openssl/src/x509/mod.rs | 27 +++++++++++++++++++++++++++ openssl/src/x509/tests.rs | 9 +++++++-- 3 files changed, 56 insertions(+), 2 deletions(-) (limited to 'openssl/src') 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 -- cgit v1.2.3 From 6a8f6f425f504459a6f4c54eac273f543c53a55e Mon Sep 17 00:00:00 2001 From: mredlek Date: Fri, 27 Jan 2017 19:11:05 +0100 Subject: Style changes according to review --- openssl/src/asn1.rs | 11 +++-------- openssl/src/x509/mod.rs | 5 ++--- 2 files changed, 5 insertions(+), 11 deletions(-) (limited to 'openssl/src') 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 } } -- cgit v1.2.3 From f5149eac5a5746c1cb45edab445ab0d240d33c86 Mon Sep 17 00:00:00 2001 From: mredlek Date: Fri, 27 Jan 2017 20:55:40 +0100 Subject: Add setters to new getter-functions in X509ReqRef --- openssl/src/x509/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'openssl/src') 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. -- cgit v1.2.3 From 588fd33552f9c84e8ed67c4cff35264b671362d9 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:08:25 -0800 Subject: Testing first version that works with signer. --- openssl/src/pkey.rs | 6 ++++++ openssl/src/rsa.rs | 19 ++++++++++++++++++- openssl/src/sign.rs | 17 ++++++++++++----- 3 files changed, 36 insertions(+), 6 deletions(-) (limited to 'openssl/src') 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(); -- cgit v1.2.3 From 20eed1e762f01ddac0a46b6471105dca8284ff8b Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:19:06 -0800 Subject: Simplify code, so that openssl-sys really doesn't contain anything aside from bindings --- openssl/src/rsa.rs | 13 +++++++++++-- openssl/src/sign.rs | 54 ++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 52 insertions(+), 15 deletions(-) (limited to 'openssl/src') 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()); } -- cgit v1.2.3 From e1fc5b2b7ea46161d83f91f4e372fd52423107b9 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:29:06 -0800 Subject: Simplify protocol based on the semantics defined by openssl. --- openssl/src/sign.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'openssl/src') 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()); } -- cgit v1.2.3 From ef61b814ff51d516adbc33d522dd0d84f2344196 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:30:25 -0800 Subject: Small amount of docs. --- openssl/src/rsa.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 72a10f3e65c1bed4689ba609d67865fbe766c92f Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 10:35:57 -0800 Subject: Fixing typo --- openssl/src/rsa.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'openssl/src') 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 { -- cgit v1.2.3 From 302ee77d32acb0b92fe563f29c36882e3b9b7d62 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Mon, 30 Jan 2017 16:51:10 -0800 Subject: Adding suggestions from review. --- openssl/src/pkey.rs | 19 ++++++++++++++++++- openssl/src/rsa.rs | 38 ++++++++++---------------------------- openssl/src/sign.rs | 14 +++++--------- 3 files changed, 33 insertions(+), 38 deletions(-) (limited to 'openssl/src') 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()); } -- cgit v1.2.3 From 4900d3fe5d8fe9f581940bd60e2d919155839fa8 Mon Sep 17 00:00:00 2001 From: Brian Chin Date: Tue, 31 Jan 2017 11:59:59 -0800 Subject: 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/src/pkey.rs | 2 +- openssl/src/sign.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'openssl/src') 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) } } -- cgit v1.2.3 From 12ae31ad476d373ce93b4222d3875b9663f3da17 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 3 Feb 2017 01:24:05 -0800 Subject: Switch to foreign_types --- 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 ++++++++++++--- 20 files changed, 271 insertions(+), 150 deletions(-) (limited to 'openssl/src') 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; +} -- cgit v1.2.3 From 8ae424235e1a09b5fdcd2879a960742d529c04da Mon Sep 17 00:00:00 2001 From: mredlek Date: Tue, 7 Feb 2017 21:49:07 +0100 Subject: 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(-) (limited to 'openssl/src') 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(|_| ()) } -- cgit v1.2.3 From a1d7956f828a5208f16d49871b7c1965d21a6893 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 10 Feb 2017 19:38:51 -0800 Subject: Add Asn1BitString --- openssl/src/asn1.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'openssl/src') 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; -- cgit v1.2.3 From 8e5735d84c43cfc2a18c1178893eedf9b8373e8e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 10 Feb 2017 19:59:11 -0800 Subject: X509 signature access --- openssl/src/x509/mod.rs | 32 +++++++++++++++++++++++++++----- openssl/src/x509/tests.rs | 15 +++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) (limited to 'openssl/src') 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"); +} -- cgit v1.2.3 From 03fe3015dc7f8ec321e483c3dde63766f1c365ad Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 10 Feb 2017 21:37:33 -0800 Subject: X509 signature algorithm access --- openssl/src/asn1.rs | 34 +++++++++++++++++++++++++++++++- openssl/src/x509/mod.rs | 49 +++++++++++++++++++++++++++++++++++++++-------- openssl/src/x509/tests.rs | 3 +++ 3 files changed, 77 insertions(+), 9 deletions(-) (limited to 'openssl/src') 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"); } -- cgit v1.2.3 From 5ad4af70ae4bb2c04c1df5d4adda05c4f6b54295 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 11 Feb 2017 09:17:39 -0800 Subject: Re-add reexport --- openssl/src/x509/mod.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'openssl/src') 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; -- cgit v1.2.3