Loading src/crypto/pkey.rs +1 −1 Original line number Diff line number Diff line Loading @@ -142,7 +142,7 @@ impl PKey { let mut mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(), self.evp, ptr::null(), ptr::null_mut(), -1, ptr::null_mut(), ptr::null_mut())); ptr::null_mut(), -1, None, ptr::null_mut())); } let buf = try!(mem_bio.read_to_end().map_err(StreamError)); Loading src/ffi.rs +7 −4 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ pub type CRYPTO_EX_dup = extern "C" fn(to: *mut CRYPTO_EX_DATA, pub type CRYPTO_EX_free = extern "C" fn(parent: *mut c_void, ptr: *mut c_void, ad: *mut CRYPTO_EX_DATA, idx: c_int, argl: c_long, argp: *mut c_void); pub type PrivateKeyWriteCallback = extern "C" fn(buf: *mut c_char, size: c_int, pub type PasswordCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; Loading Loading @@ -356,9 +356,12 @@ extern "C" { pub fn HMAC_Final(ctx: *mut HMAC_CTX, output: *mut u8, len: *mut c_uint); pub fn HMAC_Update(ctx: *mut HMAC_CTX, input: *const u8, len: c_uint); pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option<PasswordCallback>, user_data: *mut c_void) -> *mut X509; pub fn PEM_write_bio_PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER, kstr: *mut c_char, klen: c_int, callback: *mut c_void, callback: Option<PasswordCallback>, user_data: *mut c_void) -> c_int; pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; Loading src/ssl/tests.rs +6 −51 Original line number Diff line number Diff line use std::io::{File, Open, Write, Writer}; use serialize::hex::FromHex; use std::io::{Writer}; use std::io::net::tcp::TcpStream; use std::num::FromStrRadix; use std::str; use crypto::hash::{SHA256}; use ssl::{Sslv23, SslContext, SslStream, SslVerifyPeer, SslVerifyNone}; use x509::{X509Generator, DigitalSignature, KeyEncipherment, ClientAuth, ServerAuth, X509StoreContext}; use ssl::{Sslv23, SslContext, SslStream, SslVerifyPeer}; use x509::{X509StoreContext}; #[test] fn test_new_ctx() { Loading Loading @@ -142,19 +142,6 @@ fn test_verify_trusted_get_error_err() { assert!(SslStream::new(&ctx, stream).is_err()); } fn hash_str_to_vec(s: &str) -> Vec<u8> { let mut res = Vec::new(); assert!(s.len() % 2 == 0, "Hash str should have len = 2 * n"); for i in range(0, s.len() / 2) { let substr = s.slice(i, i + 2); let t: Option<u8> = FromStrRadix::from_str_radix(substr, 16); assert!(t.is_some(), "Hash str must contain only hex digits, i.e. [0-9a-f]"); res.push(t.unwrap()); } res } #[test] fn test_verify_callback_data() { fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext, node_id: &Vec<u8>) -> bool { Loading @@ -175,8 +162,8 @@ fn test_verify_callback_data() { // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 // Please update if "test/cert.pem" will ever change let node_hash_str = "6204f6617e1af7495394250655f43600cd483e2dfc2005e92d0fe439d0723c34"; let node_id = hash_str_to_vec(node_hash_str); ctx.set_verify_with_data(SslVerifyNone, callback, node_id); let node_id = node_hash_str.from_hex().unwrap(); ctx.set_verify_with_data(SslVerifyPeer, callback, node_id); ctx.set_verify_depth(1); match SslStream::new(&ctx, stream) { Loading Loading @@ -205,35 +192,3 @@ fn test_read() { let buf = stream.read_to_end().ok().expect("read error"); print!("{}", str::from_utf8(buf.as_slice())); } #[test] fn test_cert_gen() { let gen = X509Generator::new() .set_bitlength(2048) .set_valid_period(365*2) .set_CN("test_me") .set_sign_hash(SHA256) .set_usage([DigitalSignature, KeyEncipherment]) .set_ext_usage([ClientAuth, ServerAuth]); let res = gen.generate(); assert!(res.is_ok()); let (cert, pkey) = res.unwrap(); #[cfg(unix)] static NULL_PATH: &'static str = "/dev/null"; #[cfg(windows)] static NULL_PATH: &'static str = "nul"; let cert_path = Path::new(NULL_PATH); let mut file = File::open_mode(&cert_path, Open, Write).unwrap(); assert!(cert.write_pem(&mut file).is_ok()); let key_path = Path::new(NULL_PATH); let mut file = File::open_mode(&key_path, Open, Write).unwrap(); assert!(pkey.write_pem(&mut file).is_ok()); // FIXME: check data in result to be correct, needs implementation // of X509 getters } src/x509/mod.rs +37 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,9 @@ use ffi; use ssl::error::{SslError, StreamError}; #[cfg(test)] mod tests; #[repr(i32)] pub enum X509FileType { PEM = ffi::X509_FILETYPE_PEM, Loading Loading @@ -322,6 +325,7 @@ impl X509Generator { } } #[allow(dead_code)] /// A public key certificate pub struct X509<'ctx> { Loading @@ -331,6 +335,39 @@ pub struct X509<'ctx> { } impl<'ctx> X509<'ctx> { /// Creates new from handle with desired ownership. pub fn new(handle: *mut ffi::X509, owned: bool) -> X509<'ctx> { X509 { ctx: None, handle: handle, owned: owned, } } /// Creates a new certificate from context. Doesn't take ownership /// of handle. pub fn new_in_ctx(handle: *mut ffi::X509, ctx: &'ctx X509StoreContext) -> X509<'ctx> { X509 { ctx: Some(ctx), handle: handle, owned: false } } /// Reads certificate from PEM, takes ownership of handle pub fn from_pem(reader: &mut Reader) -> Result<X509<'ctx>, SslError> { let mut mem_bio = try!(MemBio::new()); let buf = try!(reader.read_to_end().map_err(StreamError)); try!(mem_bio.write(buf.as_slice()).map_err(StreamError)); unsafe { let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.get_handle(), ptr::null_mut(), None, ptr::null_mut())); Ok(X509::new(handle, true)) } } pub fn subject_name<'a>(&'a self) -> X509Name<'a> { let name = unsafe { ffi::X509_get_subject_name(self.handle) }; X509Name { x509: self, name: name } Loading src/x509/tests.rs 0 → 100644 +49 −0 Original line number Diff line number Diff line use serialize::hex::FromHex; use std::io::{File, Open, Read}; use std::io::util::NullWriter; use crypto::hash::{SHA256}; use x509::{X509, X509Generator, DigitalSignature, KeyEncipherment, ClientAuth, ServerAuth}; #[test] fn test_cert_gen() { let gen = X509Generator::new() .set_bitlength(2048) .set_valid_period(365*2) .set_CN("test_me") .set_sign_hash(SHA256) .set_usage([DigitalSignature, KeyEncipherment]) .set_ext_usage([ClientAuth, ServerAuth]); let res = gen.generate(); assert!(res.is_ok()); let (cert, pkey) = res.unwrap(); let mut writer = NullWriter; assert!(cert.write_pem(&mut writer).is_ok()); assert!(pkey.write_pem(&mut writer).is_ok()); // FIXME: check data in result to be correct, needs implementation // of X509 getters } #[test] fn test_cert_loading() { let cert_path = Path::new("test/cert.pem"); let mut file = File::open_mode(&cert_path, Open, Read) .ok() .expect("Failed to open `test/cert.pem`"); let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); let fingerprint = cert.fingerprint(SHA256).unwrap(); // Hash was generated as SHA256 hash of certificate "test/cert.pem" // in DER format. // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 // Please update if "test/cert.pem" will ever change let hash_str = "6204f6617e1af7495394250655f43600cd483e2dfc2005e92d0fe439d0723c34"; let hash_vec = hash_str.from_hex().unwrap(); assert_eq!(fingerprint.as_slice(), hash_vec.as_slice()); } Loading
src/crypto/pkey.rs +1 −1 Original line number Diff line number Diff line Loading @@ -142,7 +142,7 @@ impl PKey { let mut mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_PrivateKey(mem_bio.get_handle(), self.evp, ptr::null(), ptr::null_mut(), -1, ptr::null_mut(), ptr::null_mut())); ptr::null_mut(), -1, None, ptr::null_mut())); } let buf = try!(mem_bio.read_to_end().map_err(StreamError)); Loading
src/ffi.rs +7 −4 Original line number Diff line number Diff line Loading @@ -76,7 +76,7 @@ pub type CRYPTO_EX_dup = extern "C" fn(to: *mut CRYPTO_EX_DATA, pub type CRYPTO_EX_free = extern "C" fn(parent: *mut c_void, ptr: *mut c_void, ad: *mut CRYPTO_EX_DATA, idx: c_int, argl: c_long, argp: *mut c_void); pub type PrivateKeyWriteCallback = extern "C" fn(buf: *mut c_char, size: c_int, pub type PasswordCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; Loading Loading @@ -356,9 +356,12 @@ extern "C" { pub fn HMAC_Final(ctx: *mut HMAC_CTX, output: *mut u8, len: *mut c_uint); pub fn HMAC_Update(ctx: *mut HMAC_CTX, input: *const u8, len: c_uint); pub fn PEM_read_bio_X509(bio: *mut BIO, out: *mut *mut X509, callback: Option<PasswordCallback>, user_data: *mut c_void) -> *mut X509; pub fn PEM_write_bio_PrivateKey(bio: *mut BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER, kstr: *mut c_char, klen: c_int, callback: *mut c_void, callback: Option<PasswordCallback>, user_data: *mut c_void) -> c_int; pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; Loading
src/ssl/tests.rs +6 −51 Original line number Diff line number Diff line use std::io::{File, Open, Write, Writer}; use serialize::hex::FromHex; use std::io::{Writer}; use std::io::net::tcp::TcpStream; use std::num::FromStrRadix; use std::str; use crypto::hash::{SHA256}; use ssl::{Sslv23, SslContext, SslStream, SslVerifyPeer, SslVerifyNone}; use x509::{X509Generator, DigitalSignature, KeyEncipherment, ClientAuth, ServerAuth, X509StoreContext}; use ssl::{Sslv23, SslContext, SslStream, SslVerifyPeer}; use x509::{X509StoreContext}; #[test] fn test_new_ctx() { Loading Loading @@ -142,19 +142,6 @@ fn test_verify_trusted_get_error_err() { assert!(SslStream::new(&ctx, stream).is_err()); } fn hash_str_to_vec(s: &str) -> Vec<u8> { let mut res = Vec::new(); assert!(s.len() % 2 == 0, "Hash str should have len = 2 * n"); for i in range(0, s.len() / 2) { let substr = s.slice(i, i + 2); let t: Option<u8> = FromStrRadix::from_str_radix(substr, 16); assert!(t.is_some(), "Hash str must contain only hex digits, i.e. [0-9a-f]"); res.push(t.unwrap()); } res } #[test] fn test_verify_callback_data() { fn callback(_preverify_ok: bool, x509_ctx: &X509StoreContext, node_id: &Vec<u8>) -> bool { Loading @@ -175,8 +162,8 @@ fn test_verify_callback_data() { // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 // Please update if "test/cert.pem" will ever change let node_hash_str = "6204f6617e1af7495394250655f43600cd483e2dfc2005e92d0fe439d0723c34"; let node_id = hash_str_to_vec(node_hash_str); ctx.set_verify_with_data(SslVerifyNone, callback, node_id); let node_id = node_hash_str.from_hex().unwrap(); ctx.set_verify_with_data(SslVerifyPeer, callback, node_id); ctx.set_verify_depth(1); match SslStream::new(&ctx, stream) { Loading Loading @@ -205,35 +192,3 @@ fn test_read() { let buf = stream.read_to_end().ok().expect("read error"); print!("{}", str::from_utf8(buf.as_slice())); } #[test] fn test_cert_gen() { let gen = X509Generator::new() .set_bitlength(2048) .set_valid_period(365*2) .set_CN("test_me") .set_sign_hash(SHA256) .set_usage([DigitalSignature, KeyEncipherment]) .set_ext_usage([ClientAuth, ServerAuth]); let res = gen.generate(); assert!(res.is_ok()); let (cert, pkey) = res.unwrap(); #[cfg(unix)] static NULL_PATH: &'static str = "/dev/null"; #[cfg(windows)] static NULL_PATH: &'static str = "nul"; let cert_path = Path::new(NULL_PATH); let mut file = File::open_mode(&cert_path, Open, Write).unwrap(); assert!(cert.write_pem(&mut file).is_ok()); let key_path = Path::new(NULL_PATH); let mut file = File::open_mode(&key_path, Open, Write).unwrap(); assert!(pkey.write_pem(&mut file).is_ok()); // FIXME: check data in result to be correct, needs implementation // of X509 getters }
src/x509/mod.rs +37 −0 Original line number Diff line number Diff line Loading @@ -11,6 +11,9 @@ use ffi; use ssl::error::{SslError, StreamError}; #[cfg(test)] mod tests; #[repr(i32)] pub enum X509FileType { PEM = ffi::X509_FILETYPE_PEM, Loading Loading @@ -322,6 +325,7 @@ impl X509Generator { } } #[allow(dead_code)] /// A public key certificate pub struct X509<'ctx> { Loading @@ -331,6 +335,39 @@ pub struct X509<'ctx> { } impl<'ctx> X509<'ctx> { /// Creates new from handle with desired ownership. pub fn new(handle: *mut ffi::X509, owned: bool) -> X509<'ctx> { X509 { ctx: None, handle: handle, owned: owned, } } /// Creates a new certificate from context. Doesn't take ownership /// of handle. pub fn new_in_ctx(handle: *mut ffi::X509, ctx: &'ctx X509StoreContext) -> X509<'ctx> { X509 { ctx: Some(ctx), handle: handle, owned: false } } /// Reads certificate from PEM, takes ownership of handle pub fn from_pem(reader: &mut Reader) -> Result<X509<'ctx>, SslError> { let mut mem_bio = try!(MemBio::new()); let buf = try!(reader.read_to_end().map_err(StreamError)); try!(mem_bio.write(buf.as_slice()).map_err(StreamError)); unsafe { let handle = try_ssl_null!(ffi::PEM_read_bio_X509(mem_bio.get_handle(), ptr::null_mut(), None, ptr::null_mut())); Ok(X509::new(handle, true)) } } pub fn subject_name<'a>(&'a self) -> X509Name<'a> { let name = unsafe { ffi::X509_get_subject_name(self.handle) }; X509Name { x509: self, name: name } Loading
src/x509/tests.rs 0 → 100644 +49 −0 Original line number Diff line number Diff line use serialize::hex::FromHex; use std::io::{File, Open, Read}; use std::io::util::NullWriter; use crypto::hash::{SHA256}; use x509::{X509, X509Generator, DigitalSignature, KeyEncipherment, ClientAuth, ServerAuth}; #[test] fn test_cert_gen() { let gen = X509Generator::new() .set_bitlength(2048) .set_valid_period(365*2) .set_CN("test_me") .set_sign_hash(SHA256) .set_usage([DigitalSignature, KeyEncipherment]) .set_ext_usage([ClientAuth, ServerAuth]); let res = gen.generate(); assert!(res.is_ok()); let (cert, pkey) = res.unwrap(); let mut writer = NullWriter; assert!(cert.write_pem(&mut writer).is_ok()); assert!(pkey.write_pem(&mut writer).is_ok()); // FIXME: check data in result to be correct, needs implementation // of X509 getters } #[test] fn test_cert_loading() { let cert_path = Path::new("test/cert.pem"); let mut file = File::open_mode(&cert_path, Open, Read) .ok() .expect("Failed to open `test/cert.pem`"); let cert = X509::from_pem(&mut file).ok().expect("Failed to load PEM"); let fingerprint = cert.fingerprint(SHA256).unwrap(); // Hash was generated as SHA256 hash of certificate "test/cert.pem" // in DER format. // Command: openssl x509 -in test/cert.pem -outform DER | openssl dgst -sha256 // Please update if "test/cert.pem" will ever change let hash_str = "6204f6617e1af7495394250655f43600cd483e2dfc2005e92d0fe439d0723c34"; let hash_vec = hash_str.from_hex().unwrap(); assert_eq!(fingerprint.as_slice(), hash_vec.as_slice()); }