diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 67b93f25..ae38d1b3 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -110,6 +110,7 @@ pub const CRYPTO_LOCK: c_int = 1; pub const EVP_MAX_MD_SIZE: c_uint = 64; pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; pub const EVP_PKEY_HMAC: c_int = NID_hmac; +pub const EVP_PKEY_DSA: c_int = NID_dsa; pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; @@ -120,6 +121,7 @@ pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG; pub const NID_rsaEncryption: c_int = 6; pub const NID_ext_key_usage: c_int = 126; pub const NID_key_usage: c_int = 83; +pub const NID_dsa: c_int = 116; pub const NID_hmac: c_int = 855; pub const PKCS5_SALT_LEN: c_int = 8; diff --git a/openssl/src/crypto/dsa.rs b/openssl/src/crypto/dsa.rs index bb4fe474..addaae2f 100644 --- a/openssl/src/crypto/dsa.rs +++ b/openssl/src/crypto/dsa.rs @@ -2,16 +2,14 @@ use ffi; use std::fmt; use error::ErrorStack; use std::ptr; -use libc::{c_uint, c_int, c_char, c_void}; +use libc::{c_int, c_char, c_void}; use bn::BigNumRef; use bio::{MemBio, MemBioSlice}; -use crypto::hash; -use HashTypeInternals; use crypto::util::{CallbackState, invoke_passwd_cb}; -/// Builder for upfront DSA parameter generateration +/// Builder for upfront DSA parameter generation pub struct DSAParams(*mut ffi::DSA); impl DSAParams { @@ -156,39 +154,6 @@ impl DSA { } } - pub fn sign(&self, hash: hash::Type, message: &[u8]) -> Result, ErrorStack> { - let k_len = self.size().expect("DSA missing a q") as c_uint; - let mut sig = vec![0; k_len as usize]; - let mut sig_len = k_len; - assert!(self.has_private_key()); - - unsafe { - try_ssl!(ffi::DSA_sign(hash.as_nid() as c_int, - message.as_ptr(), - message.len() as c_int, - sig.as_mut_ptr(), - &mut sig_len, - self.0)); - sig.set_len(sig_len as usize); - sig.shrink_to_fit(); - Ok(sig) - } - } - - pub fn verify(&self, hash: hash::Type, message: &[u8], sig: &[u8]) -> Result { - unsafe { - let result = ffi::DSA_verify(hash.as_nid() as c_int, - message.as_ptr(), - message.len() as c_int, - sig.as_ptr(), - sig.len() as c_int, - self.0); - - try_ssl_if!(result == -1); - Ok(result == 1) - } - } - pub fn as_ptr(&self) -> *mut ffi::DSA { self.0 } @@ -282,76 +247,7 @@ mod test { #[test] pub fn test_generate() { - let key = DSA::generate(1024).unwrap(); - - key.public_key_to_pem().unwrap(); - key.private_key_to_pem().unwrap(); - - let input: Vec = (0..25).cycle().take(1024).collect(); - - let digest = { - let mut sha = Hasher::new(Type::SHA1).unwrap(); - sha.write_all(&input).unwrap(); - sha.finish().unwrap() - }; - - let sig = key.sign(Type::SHA1, &digest).unwrap(); - let verified = key.verify(Type::SHA1, &digest, &sig).unwrap(); - assert!(verified); - } - - #[test] - pub fn test_sign_verify() { - let input: Vec = (0..25).cycle().take(1024).collect(); - - let private_key = { - let key = include_bytes!("../../test/dsa.pem"); - DSA::private_key_from_pem(key).unwrap() - }; - - let public_key = { - let key = include_bytes!("../../test/dsa.pem.pub"); - DSA::public_key_from_pem(key).unwrap() - }; - - let digest = { - let mut sha = Hasher::new(Type::SHA1).unwrap(); - sha.write_all(&input).unwrap(); - sha.finish().unwrap() - }; - - let sig = private_key.sign(Type::SHA1, &digest).unwrap(); - let verified = public_key.verify(Type::SHA1, &digest, &sig).unwrap(); - assert!(verified); - } - - #[test] - pub fn test_sign_verify_fail() { - let input: Vec = (0..25).cycle().take(128).collect(); - let private_key = { - let key = include_bytes!("../../test/dsa.pem"); - DSA::private_key_from_pem(key).unwrap() - }; - - let public_key = { - let key = include_bytes!("../../test/dsa.pem.pub"); - DSA::public_key_from_pem(key).unwrap() - }; - - let digest = { - let mut sha = Hasher::new(Type::SHA1).unwrap(); - sha.write_all(&input).unwrap(); - sha.finish().unwrap() - }; - - let mut sig = private_key.sign(Type::SHA1, &digest).unwrap(); - // tamper with the sig this should cause a failure - let len = sig.len(); - sig[len / 2] = 0; - sig[len - 1] = 0; - if let Ok(true) = public_key.verify(Type::SHA1, &digest, &sig) { - panic!("Tampered with signatures should not verify!"); - } + DSA::generate(1024).unwrap(); } #[test] diff --git a/openssl/src/crypto/pkey.rs b/openssl/src/crypto/pkey.rs index 8b408d29..67ff7520 100644 --- a/openssl/src/crypto/pkey.rs +++ b/openssl/src/crypto/pkey.rs @@ -4,6 +4,7 @@ use std::mem; use ffi; use bio::{MemBio, MemBioSlice}; +use crypto::dsa::DSA; use crypto::rsa::RSA; use error::ErrorStack; use crypto::util::{CallbackState, invoke_passwd_cb}; @@ -26,6 +27,17 @@ impl PKey { } } + /// Create a new `PKey` containing a DSA key. + pub fn from_dsa(dsa: DSA) -> Result { + unsafe { + let evp = try_ssl_null!(ffi::EVP_PKEY_new()); + let pkey = PKey(evp); + try_ssl!(ffi::EVP_PKEY_assign(pkey.0, ffi::EVP_PKEY_DSA, dsa.as_ptr() as *mut _)); + mem::forget(dsa); + Ok(pkey) + } + } + /// Create a new `PKey` containing an HMAC key. pub fn hmac(key: &[u8]) -> Result { unsafe { diff --git a/openssl/src/crypto/sign.rs b/openssl/src/crypto/sign.rs index c5d54597..24078fdc 100644 --- a/openssl/src/crypto/sign.rs +++ b/openssl/src/crypto/sign.rs @@ -113,6 +113,8 @@ impl<'a> Signer<'a> { let mut buf = vec![0; len]; try_ssl_if!(ffi::EVP_DigestSignFinal(self.0, buf.as_mut_ptr() as *mut _, &mut len) != 1); + // The advertised length is not always equal to the real length for things like DSA + buf.truncate(len); Ok(buf) } } @@ -213,6 +215,7 @@ mod test { use crypto::hash::Type; use crypto::sign::{Signer, Verifier}; use crypto::rsa::RSA; + use crypto::dsa::DSA; use crypto::pkey::PKey; static INPUT: &'static [u8] = @@ -240,7 +243,7 @@ mod test { 112, 223, 200, 163, 42, 70, 149, 67, 208, 25, 238, 251, 71]; #[test] - fn test_sign() { + fn rsa_sign() { let key = include_bytes!("../../test/rsa.pem"); let private_key = RSA::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); @@ -253,7 +256,7 @@ mod test { } #[test] - fn test_verify_ok() { + fn rsa_verify_ok() { let key = include_bytes!("../../test/rsa.pem"); let private_key = RSA::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); @@ -264,7 +267,7 @@ mod test { } #[test] - fn test_verify_invalid() { + fn rsa_verify_invalid() { let key = include_bytes!("../../test/rsa.pem"); let private_key = RSA::private_key_from_pem(key).unwrap(); let pkey = PKey::from_rsa(private_key).unwrap(); @@ -275,6 +278,56 @@ mod test { assert!(!verifier.finish(SIGNATURE).unwrap()); } + #[test] + pub fn dsa_sign_verify() { + let input: Vec = (0..25).cycle().take(1024).collect(); + + let private_key = { + let key = include_bytes!("../../test/dsa.pem"); + PKey::from_dsa(DSA::private_key_from_pem(key).unwrap()).unwrap() + }; + + let public_key = { + let key = include_bytes!("../../test/dsa.pem.pub"); + PKey::from_dsa(DSA::public_key_from_pem(key).unwrap()).unwrap() + }; + + let mut signer = Signer::new(Type::SHA1, &private_key).unwrap(); + signer.update(&input).unwrap(); + let sig = signer.finish().unwrap(); + + let mut verifier = Verifier::new(Type::SHA1, &public_key).unwrap(); + verifier.update(&input).unwrap(); + assert!(verifier.finish(&sig).unwrap()); + } + + #[test] + pub fn dsa_sign_verify_fail() { + let input: Vec = (0..25).cycle().take(1024).collect(); + + let private_key = { + let key = include_bytes!("../../test/dsa.pem"); + PKey::from_dsa(DSA::private_key_from_pem(key).unwrap()).unwrap() + }; + + let public_key = { + let key = include_bytes!("../../test/dsa.pem.pub"); + PKey::from_dsa(DSA::public_key_from_pem(key).unwrap()).unwrap() + }; + + let mut signer = Signer::new(Type::SHA1, &private_key).unwrap(); + signer.update(&input).unwrap(); + let mut sig = signer.finish().unwrap(); + sig[0] -= 1; + + let mut verifier = Verifier::new(Type::SHA1, &public_key).unwrap(); + verifier.update(&input).unwrap(); + match verifier.finish(&sig) { + Ok(true) => panic!("unexpected success"), + Ok(false) | Err(_) => {}, + } + } + fn test_hmac(ty: Type, tests: &[(Vec, Vec, Vec)]) { for &(ref key, ref data, ref res) in tests.iter() { let pkey = PKey::hmac(key).unwrap();