Commit 3ef8dc77 authored by lloyd's avatar lloyd
Browse files

Add support for RSA signing with alternate hashes (MD5, SHA-512, etc)

parent b0fd9567
Loading
Loading
Loading
Loading
+39 −10
Original line number Diff line number Diff line
use libc::{c_int, c_uint};
use hash::{HashType, MD5, SHA1, SHA224, SHA256, SHA384, SHA512};

#[allow(non_camel_case_types)]
type EVP_PKEY = *libc::c_void;
@@ -62,6 +63,17 @@ fn openssl_padding_code(padding: EncryptionPadding) -> c_int {
    }
}

fn openssl_hash_nid(hash: HashType) -> c_int {
    match hash {
        MD5    => 4,   // NID_md5,
        SHA1   => 64,  // NID_sha1
        SHA224 => 675, // NID_sha224
        SHA256 => 672, // NID_sha256
        SHA384 => 673, // NID_sha384
        SHA512 => 674, // NID_sha512
    }
}

fn rsa_to_any(rsa: *RSA) -> *ANYKEY unsafe {
    cast::reinterpret_cast(&rsa)
}
@@ -268,7 +280,15 @@ pub impl PKey {
     * Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(),
     * can process an arbitrary amount of data; returns the signature.
     */
    fn sign(s: &[u8]) -> ~[u8] unsafe {
    fn sign(s: &[u8]) -> ~[u8] unsafe { self.sign_with_hash(s, SHA256) }

    /**
     * Verifies a signature s (using OpenSSL's default scheme and sha256) on a
     * message m. Returns true if the signature is valid, and false otherwise.
     */
    fn verify(m: &[u8], s: &[u8]) -> bool unsafe { self.verify_with_hash(m, s, SHA256) }

    fn sign_with_hash(s: &[u8], hash: HashType) -> ~[u8] unsafe {
        let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);
        let len = libcrypto::RSA_size(rsa);
        let mut r = vec::from_elem(len as uint + 1u, 0u8);
@@ -277,9 +297,8 @@ pub impl PKey {
            do vec::as_imm_buf(s) |ps, s_len| {
                let plen = ptr::addr_of(&len);

                // XXX: 672 == NID_sha256
                let rv = libcrypto::RSA_sign(
                    672 as c_int,
                    openssl_hash_nid(hash),
                    ps,
                    s_len as c_uint,
                    pr,
@@ -295,18 +314,13 @@ pub impl PKey {
        }
    }

    /**
     * Verifies a signature s (using OpenSSL's default scheme and sha256) on a
     * message m. Returns true if the signature is valid, and false otherwise.
     */
    fn verify(m: &[u8], s: &[u8]) -> bool unsafe {
    fn verify_with_hash(m: &[u8], s: &[u8], hash: HashType) -> bool unsafe {
        let rsa = libcrypto::EVP_PKEY_get1_RSA(self.evp);

        do vec::as_imm_buf(m) |pm, m_len| {
            do vec::as_imm_buf(s) |ps, s_len| {
                // XXX: 672 == NID_sha256
                let rv = libcrypto::RSA_verify(
                    672 as c_int,
                    openssl_hash_nid(hash),
                    pm,
                    m_len as c_uint,
                    ps,
@@ -393,4 +407,19 @@ mod tests {
        let rv = k1.verify(msg, sig);
        assert(rv == true);
    }

    #[test]
    fn test_sign_hashes() {
        let k0 = PKey();
        let k1 = PKey();
        let msg = ~[0xdeu8, 0xadu8, 0xd0u8, 0x0du8];
        k0.gen(512u);
        k1.load_pub(k0.save_pub());

        let sig = k0.sign_with_hash(msg, MD5);

        assert k1.verify_with_hash(msg, sig, MD5);
        assert !k1.verify_with_hash(msg, sig, SHA1);
    }

}