Migrate DSA sign/verify to EVP APIs

This commit is contained in:
Steven Fackler 2016-10-15 15:02:02 -07:00
parent 228b8fbc5b
commit 6609a81685
4 changed files with 73 additions and 110 deletions

View File

@ -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;

View File

@ -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<Vec<u8>, 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<bool, ErrorStack> {
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<u8> = (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<u8> = (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<u8> = (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]

View File

@ -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<PKey, ErrorStack> {
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<PKey, ErrorStack> {
unsafe {

View File

@ -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<u8> = (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<u8> = (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<u8>, Vec<u8>, Vec<u8>)]) {
for &(ref key, ref data, ref res) in tests.iter() {
let pkey = PKey::hmac(key).unwrap();