Hash reform

Closes #430
This commit is contained in:
Steven Fackler 2016-08-07 16:28:29 -07:00
parent 05089bacb3
commit 7ca5ccf064
10 changed files with 200 additions and 238 deletions

View File

@ -282,6 +282,8 @@ pub const BIO_FLAGS_SHOULD_RETRY: c_int = 0x08;
pub const CRYPTO_LOCK: c_int = 1;
pub const EVP_MAX_MD_SIZE: c_uint = 64;
pub const MBSTRING_ASC: c_int = MBSTRING_FLAG | 1;
pub const MBSTRING_BMP: c_int = MBSTRING_FLAG | 2;
pub const MBSTRING_FLAG: c_int = 0x1000;

View File

@ -7,7 +7,7 @@ use libc::{c_uint, c_int, c_char, c_void};
use bn::BigNumRef;
use bio::{MemBio, MemBioSlice};
use crypto::hash;
use crypto::HashTypeInternals;
use HashTypeInternals;
use crypto::util::{CallbackState, invoke_passwd_cb};
@ -249,9 +249,9 @@ mod test {
let input: Vec<u8> = (0..25).cycle().take(1024).collect();
let digest = {
let mut sha = Hasher::new(Type::SHA1);
let mut sha = Hasher::new(Type::SHA1).unwrap();
sha.write_all(&input).unwrap();
sha.finish()
sha.finish().unwrap()
};
let sig = key.sign(Type::SHA1, &digest).unwrap();
@ -274,9 +274,9 @@ mod test {
};
let digest = {
let mut sha = Hasher::new(Type::SHA1);
let mut sha = Hasher::new(Type::SHA1).unwrap();
sha.write_all(&input).unwrap();
sha.finish()
sha.finish().unwrap()
};
let sig = private_key.sign(Type::SHA1, &digest).unwrap();
@ -298,9 +298,9 @@ mod test {
};
let digest = {
let mut sha = Hasher::new(Type::SHA1);
let mut sha = Hasher::new(Type::SHA1).unwrap();
sha.write_all(&input).unwrap();
sha.finish()
sha.finish().unwrap()
};
let mut sig = private_key.sign(Type::SHA1, &digest).unwrap();

View File

@ -1,10 +1,12 @@
use libc::c_uint;
use std::iter::repeat;
use std::io::prelude::*;
use std::io;
use std::ptr;
use std::cmp;
use ffi;
use crypto::HashTypeInternals;
use HashTypeInternals;
use error::ErrorStack;
use nid::Nid;
/// Message digest (hash) type.
@ -31,26 +33,8 @@ impl HashTypeInternals for Type {
Type::RIPEMD160 => Nid::RIPEMD160,
}
}
}
impl Type {
/// Returns the length of the message digest.
#[inline]
pub fn md_len(&self) -> usize {
match *self {
Type::MD5 => 16,
Type::SHA1 => 20,
Type::SHA224 => 28,
Type::SHA256 => 32,
Type::SHA384 => 48,
Type::SHA512 => 64,
Type::RIPEMD160 => 20,
}
}
/// Internal interface subject to removal.
#[inline]
pub fn evp_md(&self) -> *const ffi::EVP_MD {
fn evp_md(&self) -> *const ffi::EVP_MD {
unsafe {
match *self {
Type::MD5 => ffi::EVP_md5(),
@ -84,21 +68,20 @@ use self::State::*;
/// use openssl::crypto::hash::{hash, Type};
/// let data = b"\x42\xF4\x97\xE0";
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let res = hash(Type::MD5, data);
/// let res = hash(Type::MD5, data).unwrap();
/// assert_eq!(res, spec);
/// ```
///
/// Use the `Write` trait to supply the input in chunks.
///
/// ```
/// use std::io::prelude::*;
/// use openssl::crypto::hash::{Hasher, Type};
/// let data = [b"\x42\xF4", b"\x97\xE0"];
/// let spec = b"\x7c\x43\x0f\x17\x8a\xef\xdf\x14\x87\xfe\xe7\x14\x4e\x96\x41\xe2";
/// let mut h = Hasher::new(Type::MD5);
/// h.write_all(data[0]);
/// h.write_all(data[1]);
/// let res = h.finish();
/// let mut h = Hasher::new(Type::MD5).unwrap();
/// h.update(data[0]).unwrap();
/// h.update(data[1]).unwrap();
/// let res = h.finish().unwrap();
/// assert_eq!(res, spec);
/// ```
///
@ -116,14 +99,10 @@ pub struct Hasher {
impl Hasher {
/// Creates a new `Hasher` with the specified hash type.
pub fn new(ty: Type) -> Hasher {
pub fn new(ty: Type) -> Result<Hasher, ErrorStack> {
ffi::init();
let ctx = unsafe {
let r = ffi::EVP_MD_CTX_create();
assert!(!r.is_null());
r
};
let ctx = unsafe { try_ssl_null!(ffi::EVP_MD_CTX_create()) };
let md = ty.evp_md();
let mut h = Hasher {
@ -132,67 +111,60 @@ impl Hasher {
type_: ty,
state: Finalized,
};
h.init();
h
try!(h.init());
Ok(h)
}
#[inline]
fn init(&mut self) {
fn init(&mut self) -> Result<(), ErrorStack> {
match self.state {
Reset => return,
Reset => return Ok(()),
Updated => {
self.finalize();
try!(self.finish());
}
Finalized => (),
}
unsafe {
let r = ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _);
assert_eq!(r, 1);
}
unsafe { try_ssl!(ffi::EVP_DigestInit_ex(self.ctx, self.md, 0 as *const _)); }
self.state = Reset;
Ok(())
}
#[inline]
fn update(&mut self, data: &[u8]) {
/// Feeds data into the hasher.
pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
if self.state == Finalized {
self.init();
try!(self.init());
}
while !data.is_empty() {
let len = cmp::min(data.len(), c_uint::max_value() as usize);
unsafe {
let r = ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint);
assert_eq!(r, 1);
try_ssl!(ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), len as c_uint));
}
data = &data[len..];
}
self.state = Updated;
}
#[inline]
fn finalize(&mut self) -> Vec<u8> {
if self.state == Finalized {
self.init();
}
let md_len = self.type_.md_len();
let mut res: Vec<u8> = repeat(0).take(md_len).collect();
unsafe {
let mut len = 0;
let r = ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len);
self.state = Finalized;
assert_eq!(len as usize, md_len);
assert_eq!(r, 1);
}
res
Ok(())
}
/// Returns the hash of the data written since creation or
/// the last `finish` and resets the hasher.
#[inline]
pub fn finish(&mut self) -> Vec<u8> {
self.finalize()
pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
if self.state == Finalized {
try!(self.init());
}
unsafe {
let mut len = ffi::EVP_MAX_MD_SIZE;
let mut res = vec![0; len as usize];
try_ssl!(ffi::EVP_DigestFinal_ex(self.ctx, res.as_mut_ptr(), &mut len));
res.truncate(len as usize);
self.state = Finalized;
Ok(res)
}
}
}
impl Write for Hasher {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.update(buf);
try!(self.update(buf));
Ok(buf.len())
}
@ -223,9 +195,7 @@ impl Drop for Hasher {
fn drop(&mut self) {
unsafe {
if self.state != Finalized {
let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect();
let mut len = 0;
ffi::EVP_DigestFinal_ex(self.ctx, buf.as_mut_ptr(), &mut len);
drop(self.finish());
}
ffi::EVP_MD_CTX_destroy(self.ctx);
}
@ -233,9 +203,9 @@ impl Drop for Hasher {
}
/// Computes the hash of the `data` with the hash `t`.
pub fn hash(t: Type, data: &[u8]) -> Vec<u8> {
let mut h = Hasher::new(t);
let _ = h.write_all(data);
pub fn hash(t: Type, data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let mut h = try!(Hasher::new(t));
try!(h.update(data));
h.finish()
}
@ -246,13 +216,13 @@ mod tests {
use std::io::prelude::*;
fn hash_test(hashtype: Type, hashtest: &(&str, &str)) {
let res = hash(hashtype, &*hashtest.0.from_hex().unwrap());
let res = hash(hashtype, &*hashtest.0.from_hex().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());
let res = h.finish();
let _ = h.write_all(&*hashtest.0.from_hex().unwrap()).unwrap();
let res = h.finish().unwrap();
assert_eq!(res.to_hex(), hashtest.1);
}
@ -294,7 +264,7 @@ mod tests {
#[test]
fn test_md5_recycle() {
let mut h = Hasher::new(Type::MD5);
let mut h = Hasher::new(Type::MD5).unwrap();
for test in md5_tests.iter() {
hash_recycle_test(&mut h, test);
}
@ -302,11 +272,11 @@ mod tests {
#[test]
fn test_finish_twice() {
let mut h = Hasher::new(Type::MD5);
let _ = h.write_all(&*md5_tests[6].0.from_hex().unwrap());
let _ = h.finish();
let res = h.finish();
let null = hash(Type::MD5, &[]);
let mut h = Hasher::new(Type::MD5).unwrap();
h.write_all(&*md5_tests[6].0.from_hex().unwrap()).unwrap();
h.finish().unwrap();
let res = h.finish().unwrap();
let null = hash(Type::MD5, &[]).unwrap();
assert_eq!(res, null);
}
@ -316,26 +286,26 @@ mod tests {
let inp = md5_tests[i].0.from_hex().unwrap();
assert!(inp.len() > 2);
let p = inp.len() / 2;
let h0 = Hasher::new(Type::MD5);
let h0 = Hasher::new(Type::MD5).unwrap();
println!("Clone a new hasher");
let mut h1 = h0.clone();
let _ = h1.write_all(&inp[..p]);
h1.write_all(&inp[..p]).unwrap();
{
println!("Clone an updated hasher");
let mut h2 = h1.clone();
let _ = h2.write_all(&inp[p..]);
let res = h2.finish();
h2.write_all(&inp[p..]).unwrap();
let res = h2.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i].1);
}
let _ = h1.write_all(&inp[p..]);
let res = h1.finish();
h1.write_all(&inp[p..]).unwrap();
let res = h1.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i].1);
println!("Clone a finished hasher");
let mut h3 = h1.clone();
let _ = h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap());
let res = h3.finish();
h3.write_all(&*md5_tests[i + 1].0.from_hex().unwrap()).unwrap();
let res = h3.finish().unwrap();
assert_eq!(res.to_hex(), md5_tests[i + 1].1);
}

View File

@ -14,14 +14,16 @@
//
use libc::{c_int, c_uint};
use std::iter::repeat;
use std::io;
use std::io::prelude::*;
use crypto::hash::Type;
use std::cmp;
use ffi;
use ffi_extras;
use HashTypeInternals;
use crypto::hash::Type;
use error::ErrorStack;
#[derive(PartialEq, Copy, Clone)]
enum State {
Reset,
@ -43,23 +45,22 @@ use self::State::*;
/// let key = b"Jefe";
/// let data = b"what do ya want for nothing?";
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
/// let res = hmac(Type::MD5, key, data);
/// let res = hmac(Type::MD5, key, data).unwrap();
/// assert_eq!(res, spec);
/// ```
///
/// Use the `Write` trait to supply the input in chunks.
///
/// ```
/// use std::io::prelude::*;
/// use openssl::crypto::hash::Type;
/// use openssl::crypto::hmac::HMAC;
/// let key = b"Jefe";
/// let data: &[&[u8]] = &[b"what do ya ", b"want for nothing?"];
/// let spec = b"\x75\x0c\x78\x3e\x6a\xb0\xb5\x03\xea\xa8\x6e\x31\x0a\x5d\xb7\x38";
/// let mut h = HMAC::new(Type::MD5, &*key);
/// h.write_all(data[0]);
/// h.write_all(data[1]);
/// let res = h.finish();
/// let mut h = HMAC::new(Type::MD5, &*key).unwrap();
/// h.update(data[0]).unwrap();
/// h.update(data[1]).unwrap();
/// let res = h.finish().unwrap();
/// assert_eq!(res, spec);
/// ```
pub struct HMAC {
@ -70,7 +71,7 @@ pub struct HMAC {
impl HMAC {
/// Creates a new `HMAC` with the specified hash type using the `key`.
pub fn new(ty: Type, key: &[u8]) -> HMAC {
pub fn new(ty: Type, key: &[u8]) -> Result<HMAC, ErrorStack> {
ffi::init();
let ctx = unsafe {
@ -85,86 +86,79 @@ impl HMAC {
type_: ty,
state: Finalized,
};
h.init_once(md, key);
h
try!(h.init_once(md, key));
Ok(h)
}
#[inline]
fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) {
fn init_once(&mut self, md: *const ffi::EVP_MD, key: &[u8]) -> Result<(), ErrorStack> {
unsafe {
let r = ffi_extras::HMAC_Init_ex(&mut self.ctx,
try_ssl!(ffi_extras::HMAC_Init_ex(&mut self.ctx,
key.as_ptr(),
key.len() as c_int,
md,
0 as *const _);
assert_eq!(r, 1);
0 as *const _));
}
self.state = Reset;
Ok(())
}
#[inline]
fn init(&mut self) {
fn init(&mut self) -> Result<(), ErrorStack> {
match self.state {
Reset => return,
Reset => return Ok(()),
Updated => {
self.finalize();
try!(self.finish());
}
Finalized => (),
}
// If the key and/or md is not supplied it's reused from the last time
// avoiding redundant initializations
unsafe {
let r = ffi_extras::HMAC_Init_ex(&mut self.ctx,
try_ssl!(ffi_extras::HMAC_Init_ex(&mut self.ctx,
0 as *const _,
0,
0 as *const _,
0 as *const _);
assert_eq!(r, 1);
0 as *const _));
}
self.state = Reset;
Ok(())
}
#[inline]
fn update(&mut self, data: &[u8]) {
pub fn update(&mut self, mut data: &[u8]) -> Result<(), ErrorStack> {
if self.state == Finalized {
self.init();
try!(self.init());
}
while !data.is_empty() {
let len = cmp::min(data.len(), c_uint::max_value() as usize);
unsafe {
let r = ffi_extras::HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint);
assert_eq!(r, 1);
try_ssl!(ffi_extras::HMAC_Update(&mut self.ctx, data.as_ptr(), len as c_uint));
}
data = &data[len..];
}
self.state = Updated;
}
#[inline]
fn finalize(&mut self) -> Vec<u8> {
if self.state == Finalized {
self.init();
}
let md_len = self.type_.md_len();
let mut res: Vec<u8> = repeat(0).take(md_len).collect();
unsafe {
let mut len = 0;
let r = ffi_extras::HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len);
self.state = Finalized;
assert_eq!(len as usize, md_len);
assert_eq!(r, 1);
}
res
Ok(())
}
/// Returns the hash of the data written since creation or
/// the last `finish` and resets the hasher.
#[inline]
pub fn finish(&mut self) -> Vec<u8> {
self.finalize()
pub fn finish(&mut self) -> Result<Vec<u8>, ErrorStack> {
if self.state == Finalized {
try!(self.init());
}
unsafe {
let mut len = ffi::EVP_MAX_MD_SIZE;
let mut res = vec![0; len as usize];
try_ssl!(ffi_extras::HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut len));
res.truncate(len as usize);
self.state = Finalized;
Ok(res)
}
}
}
impl Write for HMAC {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.update(buf);
try!(self.update(buf));
Ok(buf.len())
}
@ -193,9 +187,7 @@ impl Drop for HMAC {
fn drop(&mut self) {
unsafe {
if self.state != Finalized {
let mut buf: Vec<u8> = repeat(0).take(self.type_.md_len()).collect();
let mut len = 0;
ffi_extras::HMAC_Final(&mut self.ctx, buf.as_mut_ptr(), &mut len);
drop(self.finish());
}
ffi::HMAC_CTX_cleanup(&mut self.ctx);
}
@ -203,9 +195,9 @@ impl Drop for HMAC {
}
/// Computes the HMAC of the `data` with the hash `t` and `key`.
pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Vec<u8> {
let mut h = HMAC::new(t, key);
let _ = h.write_all(data);
pub fn hmac(t: Type, key: &[u8], data: &[u8]) -> Result<Vec<u8>, ErrorStack> {
let mut h = try!(HMAC::new(t, key));
try!(h.update(data));
h.finish()
}
@ -220,14 +212,14 @@ mod tests {
fn test_hmac(ty: Type, tests: &[(Vec<u8>, Vec<u8>, Vec<u8>)]) {
for &(ref key, ref data, ref res) in tests.iter() {
assert_eq!(hmac(ty, &**key, &**data), *res);
assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
}
}
fn test_hmac_recycle(h: &mut HMAC, test: &(Vec<u8>, Vec<u8>, Vec<u8>)) {
let &(_, ref data, ref res) = test;
let _ = h.write_all(&**data);
assert_eq!(h.finish(), *res);
h.write_all(&**data).unwrap();
assert_eq!(h.finish().unwrap(), *res);
}
#[test]
@ -273,7 +265,7 @@ mod tests {
.to_vec(),
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
let mut h = HMAC::new(MD5, &*tests[0].0);
let mut h = HMAC::new(MD5, &*tests[0].0).unwrap();
for i in 0..100usize {
let test = &tests[i % 2];
test_hmac_recycle(&mut h, test);
@ -287,11 +279,11 @@ mod tests {
b"Test Using Larger Than Block-Size Key - Hash Key First".to_vec(),
"6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd".from_hex().unwrap());
let mut h = HMAC::new(Type::MD5, &*test.0);
let _ = h.write_all(&*test.1);
let _ = h.finish();
let res = h.finish();
let null = hmac(Type::MD5, &*test.0, &[]);
let mut h = HMAC::new(Type::MD5, &*test.0).unwrap();
h.write_all(&*test.1).unwrap();
h.finish().unwrap();
let res = h.finish().unwrap();
let null = hmac(Type::MD5, &*test.0, &[]).unwrap();
assert_eq!(res, null);
}
@ -307,26 +299,26 @@ mod tests {
.to_vec(),
"6f630fad67cda0ee1fb1f562db3aa53e".from_hex().unwrap())];
let p = tests[0].0.len() / 2;
let h0 = HMAC::new(Type::MD5, &*tests[0].0);
let h0 = HMAC::new(Type::MD5, &*tests[0].0).unwrap();
println!("Clone a new hmac");
let mut h1 = h0.clone();
let _ = h1.write_all(&tests[0].1[..p]);
h1.write_all(&tests[0].1[..p]).unwrap();
{
println!("Clone an updated hmac");
let mut h2 = h1.clone();
let _ = h2.write_all(&tests[0].1[p..]);
let res = h2.finish();
h2.write_all(&tests[0].1[p..]).unwrap();
let res = h2.finish().unwrap();
assert_eq!(res, tests[0].2);
}
let _ = h1.write_all(&tests[0].1[p..]);
let res = h1.finish();
h1.write_all(&tests[0].1[p..]).unwrap();
let res = h1.finish().unwrap();
assert_eq!(res, tests[0].2);
println!("Clone a finished hmac");
let mut h3 = h1.clone();
let _ = h3.write_all(&*tests[1].1);
let res = h3.finish();
h3.write_all(&*tests[1].1).unwrap();
let res = h3.finish().unwrap();
assert_eq!(res, tests[1].2);
}
@ -373,7 +365,7 @@ mod tests {
.to_vec(),
"e8e99d0f45237d786d6bbaa7965c7808bbff1a91".from_hex().unwrap())];
let mut h = HMAC::new(SHA1, &*tests[0].0);
let mut h = HMAC::new(SHA1, &*tests[0].0).unwrap();
for i in 0..100usize {
let test = &tests[i % 2];
test_hmac_recycle(&mut h, test);
@ -399,11 +391,11 @@ mod tests {
.to_vec())];
for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) {
assert_eq!(hmac(ty, &**key, &**data), *res);
assert_eq!(hmac(ty, &**key, &**data).unwrap(), *res);
}
// recycle test
let mut h = HMAC::new(ty, &*tests[5].0);
let mut h = HMAC::new(ty, &*tests[5].0).unwrap();
for i in 0..100usize {
let test = &tests[4 + i % 2];
let tup = (test.0.clone(), test.1.clone(), results[4 + i % 2].clone());

View File

@ -14,8 +14,6 @@
// limitations under the License.
//
use nid::Nid;
pub mod hash;
pub mod hmac;
pub mod pkcs5;
@ -28,7 +26,3 @@ pub mod dsa;
mod util;
mod symm_internal;
trait HashTypeInternals {
fn as_nid(&self) -> Nid;
}

View File

@ -1,10 +1,12 @@
use libc::c_int;
use std::ptr::null;
use std::ptr;
use ffi;
use HashTypeInternals;
use crypto::symm_internal::evpc;
use crypto::hash;
use crypto::symm;
use ffi;
use error::ErrorStack;
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct KeyIvPair {
@ -27,7 +29,7 @@ pub fn evp_bytes_to_key_pbkdf1_compatible(typ: symm::Type,
data: &[u8],
salt: Option<&[u8]>,
count: u32)
-> KeyIvPair {
-> Result<KeyIvPair, ErrorStack> {
unsafe {
@ -36,30 +38,40 @@ pub fn evp_bytes_to_key_pbkdf1_compatible(typ: symm::Type,
assert_eq!(salt.len(), ffi::PKCS5_SALT_LEN as usize);
salt.as_ptr()
}
None => null(),
None => ptr::null(),
};
ffi::init();
let (evp, keylen, _) = evpc(typ);
let (evp, _, _) = evpc(typ);
let message_digest = message_digest_type.evp_md();
let mut key = vec![0; keylen as usize];
let mut iv = vec![0; keylen as usize];
let len = ffi::EVP_BytesToKey(evp,
message_digest,
salt_ptr,
data.as_ptr(),
data.len() as c_int,
count as c_int,
ptr::null_mut(),
ptr::null_mut());
if len == 0 {
return Err(ErrorStack::get());
}
let mut key = vec![0; len as usize];
let mut iv = vec![0; len as usize];
let ret: c_int = ffi::EVP_BytesToKey(evp,
try_ssl!(ffi::EVP_BytesToKey(evp,
message_digest,
salt_ptr,
data.as_ptr(),
data.len() as c_int,
count as c_int,
key.as_mut_ptr(),
iv.as_mut_ptr());
assert!(ret == keylen as c_int);
iv.as_mut_ptr()));
KeyIvPair { key: key, iv: iv }
Ok(KeyIvPair { key: key, iv: iv })
}
}
@ -257,7 +269,7 @@ mod tests {
hash::Type::SHA1,
&data,
Some(&salt),
1),
1).unwrap(),
super::KeyIvPair {
key: expected_key,
iv: expected_iv,

View File

@ -4,7 +4,7 @@ use std::mem;
use std::ptr;
use bio::{MemBio, MemBioSlice};
use crypto::HashTypeInternals;
use HashTypeInternals;
use crypto::hash;
use crypto::hash::Type as HashType;
use ffi;

View File

@ -6,7 +6,7 @@ use libc::{c_int, c_void, c_char};
use bn::{BigNum, BigNumRef};
use bio::{MemBio, MemBioSlice};
use error::ErrorStack;
use crypto::HashTypeInternals;
use HashTypeInternals;
use crypto::hash;
use crypto::util::{CallbackState, invoke_passwd_cb};
@ -262,9 +262,9 @@ mod test {
let key = include_bytes!("../../test/rsa.pem");
let private_key = RSA::private_key_from_pem(key).unwrap();
let mut sha = Hasher::new(Type::SHA256);
let mut sha = Hasher::new(Type::SHA256).unwrap();
sha.write_all(&signing_input_rs256()).unwrap();
let digest = sha.finish();
let digest = sha.finish().unwrap();
let result = private_key.sign(Type::SHA256, &digest).unwrap();
@ -276,9 +276,9 @@ mod test {
let key = include_bytes!("../../test/rsa.pem.pub");
let public_key = RSA::public_key_from_pem(key).unwrap();
let mut sha = Hasher::new(Type::SHA256);
let mut sha = Hasher::new(Type::SHA256).unwrap();
sha.write_all(&signing_input_rs256()).unwrap();
let digest = sha.finish();
let digest = sha.finish().unwrap();
let result = public_key.verify(Type::SHA256, &digest, &signature_rs256()).unwrap();

View File

@ -14,6 +14,8 @@ extern crate rustc_serialize as serialize;
#[cfg(test)]
extern crate net2;
use nid::Nid;
mod macros;
pub mod asn1;
@ -26,3 +28,8 @@ pub mod nid;
pub mod ssl;
pub mod version;
pub mod x509;
trait HashTypeInternals {
fn as_nid(&self) -> Nid;
fn evp_md(&self) -> *const ffi::EVP_MD;
}

View File

@ -1,7 +1,5 @@
use libc::{c_char, c_int, c_long, c_ulong, c_uint, c_void};
use std::cmp::Ordering;
use libc::{c_char, c_int, c_long, c_ulong, c_void};
use std::ffi::CString;
use std::iter::repeat;
use std::mem;
use std::ptr;
use std::ops::Deref;
@ -11,6 +9,7 @@ use std::slice;
use std::collections::HashMap;
use std::marker::PhantomData;
use HashTypeInternals;
use asn1::Asn1Time;
use bio::{MemBio, MemBioSlice};
use crypto::hash;
@ -434,28 +433,14 @@ impl<'a> X509Ref<'a> {
}
/// Returns certificate fingerprint calculated using provided hash
pub fn fingerprint(&self, hash_type: hash::Type) -> Option<Vec<u8>> {
pub fn fingerprint(&self, hash_type: hash::Type) -> Result<Vec<u8>, ErrorStack> {
unsafe {
let evp = hash_type.evp_md();
let len = hash_type.md_len();
let v: Vec<u8> = repeat(0).take(len as usize).collect();
let act_len: c_uint = 0;
let res = unsafe {
ffi::X509_digest(self.0,
evp,
mem::transmute(v.as_ptr()),
mem::transmute(&act_len))
};
match res {
0 => None,
_ => {
let act_len = act_len as usize;
match len.cmp(&act_len) {
Ordering::Greater => None,
Ordering::Equal => Some(v),
Ordering::Less => panic!("Fingerprint buffer was corrupted!"),
}
}
let mut len = ffi::EVP_MAX_MD_SIZE;
let mut buf = vec![0u8; len as usize];
try_ssl!(ffi::X509_digest(self.0, evp, buf.as_mut_ptr() as *mut _, &mut len));
buf.truncate(len as usize);
Ok(buf)
}
}