Commit 6609a816 authored by Steven Fackler's avatar Steven Fackler
Browse files

Migrate DSA sign/verify to EVP APIs

parent 228b8fbc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
+3 −107
Original line number Diff line number Diff line
@@ -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]
+12 −0
Original line number Diff line number Diff line
@@ -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 {
+56 −3
Original line number Diff line number Diff line
@@ -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();