From 4fd169a1e5d465a10d5a815877479baa960a16eb Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Wed, 24 Sep 2014 19:17:17 +0300 Subject: Certificate/pkey generation & PEM export Required quite a lot of refactoring --- src/asn1/mod.rs | 23 +++ src/bio/mod.rs | 106 +++++++++++ src/crypto/pkey.rs | 29 ++- src/lib.rs | 9 +- src/macros.rs | 61 +++++++ src/ssl/ffi.rs | 91 +--------- src/ssl/mod.rs | 248 +++---------------------- src/ssl/tests.rs | 20 ++- src/x509/mod.rs | 517 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 791 insertions(+), 313 deletions(-) create mode 100644 src/asn1/mod.rs create mode 100644 src/bio/mod.rs mode change 100644 => 100755 src/lib.rs create mode 100755 src/macros.rs create mode 100755 src/x509/mod.rs (limited to 'src') diff --git a/src/asn1/mod.rs b/src/asn1/mod.rs new file mode 100644 index 00000000..d302d6b7 --- /dev/null +++ b/src/asn1/mod.rs @@ -0,0 +1,23 @@ +pub mod ffi { + #![allow(dead_code)] + #![allow(non_camel_case_types)] + use libc::{c_int, c_long, c_void}; + + pub type ASN1_INTEGER = c_void; + pub type ASN1_TIME = c_void; + pub type ASN1_STRING = c_void; + + pub static MBSTRING_FLAG: c_int = 0x1000; + pub static MBSTRING_UTF8: c_int = MBSTRING_FLAG; + pub static MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; + pub static MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; + pub static MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; + + pub static V_ASN1_UTCTIME: c_int = 23; + pub static V_ASN1_GENERALIZEDTIME: c_int = 24; + + extern "C" { + pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; + pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; + } +} diff --git a/src/bio/mod.rs b/src/bio/mod.rs new file mode 100644 index 00000000..019129ea --- /dev/null +++ b/src/bio/mod.rs @@ -0,0 +1,106 @@ +use libc::{c_void, c_int}; +use std::io::{IoResult, IoError, OtherIoError}; +use std::io::{Reader, Writer}; +use std::ptr; + +use ssl::error::{SslError}; + +pub struct MemBio { + bio: *mut ffi::BIO, + owned: bool +} + +impl Drop for MemBio { + fn drop(&mut self) { + if self.owned { + unsafe { + ffi::BIO_free_all(self.bio); + } + } + } +} + +impl MemBio { + /// Creates a new owned memory based BIO + pub fn new() -> Result { + let bio = unsafe { ffi::BIO_new(ffi::BIO_s_mem()) }; + try_ssl_null!(bio); + + Ok(MemBio { + bio: bio, + owned: true + }) + } + + /// Returns a "borrow", i.e. it has no ownership + pub fn borrowed(bio: *mut ffi::BIO) -> MemBio { + MemBio { + bio: bio, + owned: false + } + } + + /// Consumes current bio and returns wrapped value + /// Note that data ownership is lost and + /// should be handled manually + pub unsafe fn unwrap(self) -> *mut ffi::BIO { + let mut t = self; + t.owned = false; + t.bio + } + + /// Temporarily gets wrapped value + pub unsafe fn get_handle(&self) -> *mut ffi::BIO { + self.bio + } +} + +impl Reader for MemBio { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + // FIXME: merge with read + let ret = unsafe { + ffi::BIO_read(self.bio, buf.as_ptr() as *mut c_void, + buf.len() as c_int) + }; + + if ret < 0 { + // FIXME: provide details from OpenSSL + Err(IoError{kind: OtherIoError, desc: "mem bio read error", detail: None}) + } else { + Ok(ret as uint) + } + } +} + +impl Writer for MemBio { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + // FIXME: merge with write + let ret = unsafe { + ffi::BIO_write(self.bio, buf.as_ptr() as *const c_void, + buf.len() as c_int) + }; + if buf.len() != ret as uint { + // FIXME: provide details from OpenSSL + Err(IoError{kind: OtherIoError, desc: "mem bio write error", detail: None}) + } else { + Ok(()) + } + } +} + +pub mod ffi { + #![allow(non_camel_case_types)] + + use libc::{c_int, c_void}; + + pub type BIO = c_void; + pub type BIO_METHOD = c_void; + + extern "C" { + pub fn BIO_s_mem() -> *const BIO_METHOD; + pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; + pub fn BIO_free_all(a: *mut BIO); + pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; + pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; + } +} diff --git a/src/crypto/pkey.rs b/src/crypto/pkey.rs index d4a98713..5c4b108f 100644 --- a/src/crypto/pkey.rs +++ b/src/crypto/pkey.rs @@ -1,8 +1,11 @@ -use libc::{c_char, c_int, c_uint}; +use libc::{c_char, c_int, c_uint, c_void}; use libc; use std::mem; use std::ptr; +use bio::{mod, MemBio}; use crypto::hash::{HashType, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD160}; +use crypto::symm::{EVP_CIPHER}; +use ssl::error::{SslError, StreamError}; #[allow(non_camel_case_types)] pub type EVP_PKEY = *mut libc::c_void; @@ -10,6 +13,8 @@ pub type EVP_PKEY = *mut libc::c_void; #[allow(non_camel_case_types)] pub type RSA = *mut libc::c_void; +pub type PrivateKeyWriteCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; + #[link(name = "crypto")] extern { fn EVP_PKEY_new() -> *mut EVP_PKEY; @@ -34,6 +39,11 @@ extern { k: *mut RSA) -> c_int; fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint, k: *mut RSA) -> c_int; + + fn PEM_write_bio_PrivateKey(bio: *mut bio::ffi::BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER, + kstr: *mut c_char, klen: c_int, + callback: *mut c_void, + user_data: *mut c_void) -> c_int; } enum Parts { @@ -163,6 +173,19 @@ impl PKey { self.parts = Both; } + /// Stores private key as a PEM + // FIXME: also add password and encryption + pub fn write_pem(&self, writer: &mut Writer/*, password: Option*/) -> Result<(), SslError> { + let mut mem_bio = try!(MemBio::new()); + unsafe { + try_ssl!(PEM_write_bio_PrivateKey(mem_bio.get_handle(), self.evp, ptr::null(), + ptr::null_mut(), -1, ptr::null_mut(), ptr::null_mut())); + + } + let buf = try!(mem_bio.read_to_end().map_err(StreamError)); + writer.write(buf.as_slice()).map_err(StreamError) + } + /** * Returns the size of the public key modulus. */ @@ -326,6 +349,10 @@ impl PKey { rv == 1 as c_int } } + + pub unsafe fn get_handle(&self) -> *mut EVP_PKEY { + return self.evp + } } impl Drop for PKey { diff --git a/src/lib.rs b/src/lib.rs old mode 100644 new mode 100755 index 3e0f3b92..d142f865 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,11 @@ extern crate libc; extern crate serialize; extern crate sync; -pub mod ssl; -pub mod crypto; +mod macros; + +mod asn1; pub mod bn; +pub mod bio; +pub mod crypto; +pub mod ssl; +pub mod x509; diff --git a/src/macros.rs b/src/macros.rs new file mode 100755 index 00000000..b11f9dad --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,61 @@ +#![macro_escape] + +#[macro_export] +macro_rules! try_ssl_stream { + ($e:expr) => ( + match $e { + Ok(ok) => ok, + Err(err) => return Err(StreamError(err)) + } + ) +} + +/// Shortcut return with SSL error if something went wrong +#[macro_export] +macro_rules! try_ssl_if { + ($e:expr) => ( + if $e { + return Err(SslError::get()) + } + ) +} + +/// Shortcut return with SSL error if last error result is 0 +/// (default) +#[macro_export] +macro_rules! try_ssl{ + ($e:expr) => (try_ssl_if!($e == 0)) +} + +/// Shortcut return with SSL if got a null result +#[macro_export] +macro_rules! try_ssl_null{ + ($e:expr) => (try_ssl_if!($e == ptr::null_mut())) +} + + +/// Lifts current SSL error code into Result<(), Error> +/// if expression is true +/// Lifting is actually a shortcut of the following form: +/// +/// ```ignore +/// let _ = try!(something) +/// Ok(()) +/// ``` +#[macro_export] +macro_rules! lift_ssl_if{ + ($e:expr) => ( { + if $e { + Err(SslError::get()) + } else { + Ok(()) + } + }) +} + +/// Lifts current SSL error code into Result<(), Error> +/// if SSL returned 0 (default error indication) +#[macro_export] +macro_rules! lift_ssl { + ($e:expr) => (lift_ssl_if!($e == 0)) +} diff --git a/src/ssl/ffi.rs b/src/ssl/ffi.rs index a40af35e..02392f74 100755 --- a/src/ssl/ffi.rs +++ b/src/ssl/ffi.rs @@ -1,17 +1,14 @@ #![allow(non_camel_case_types)] -use libc::{c_int, c_void, c_long, c_ulong, c_char, c_uint}; -use crypto::hash::{EVP_MD}; +use libc::{c_int, c_void, c_long, c_ulong, c_char}; + +use bio; +use x509; pub type SSL_CTX = c_void; pub type SSL_METHOD = c_void; pub type COMP_METHOD = c_void; pub type SSL = c_void; -pub type BIO = c_void; -pub type BIO_METHOD = c_void; -pub type X509_STORE_CTX = c_void; -pub type X509 = c_void; -pub type X509_NAME = c_void; pub type CRYPTO_EX_DATA = c_void; pub type CRYPTO_EX_new = extern "C" fn(parent: *mut c_void, ptr: *mut c_void, @@ -44,64 +41,6 @@ pub static SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; pub static TLSEXT_NAMETYPE_host_name: c_long = 0; -pub static X509_V_OK: c_int = 0; -pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; -pub static X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; -pub static X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; -pub static X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; -pub static X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; -pub static X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; -pub static X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; -pub static X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; -pub static X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; -pub static X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; -pub static X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; -pub static X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; -pub static X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; -pub static X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; -pub static X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; -pub static X509_V_ERR_OUT_OF_MEM: c_int = 17; -pub static X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; -pub static X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; -pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; -pub static X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; -pub static X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; -pub static X509_V_ERR_CERT_REVOKED: c_int = 23; -pub static X509_V_ERR_INVALID_CA: c_int = 24; -pub static X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; -pub static X509_V_ERR_INVALID_PURPOSE: c_int = 26; -pub static X509_V_ERR_CERT_UNTRUSTED: c_int = 27; -pub static X509_V_ERR_CERT_REJECTED: c_int = 28; -pub static X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; -pub static X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; -pub static X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; -pub static X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; -pub static X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; -pub static X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; -pub static X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; -pub static X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; -pub static X509_V_ERR_INVALID_NON_CA: c_int = 37; -pub static X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; -pub static X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; -pub static X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; -pub static X509_V_ERR_INVALID_EXTENSION: c_int = 41; -pub static X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; -pub static X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; -pub static X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; -pub static X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; -pub static X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; -pub static X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; -pub static X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; -pub static X509_V_ERR_SUBTREE_MINMAX: c_int = 49; -pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; -pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; -pub static X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; -pub static X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; -pub static X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; - -pub static X509_FILETYPE_PEM: c_int = 1; -pub static X509_FILETYPE_ASN1: c_int = 2; -pub static X509_FILETYPE_DEFAULT: c_int = 3; #[cfg(target_os = "macos", feature = "tlsv1_1")] #[cfg(target_os = "macos", feature = "tlsv1_2")] @@ -139,7 +78,7 @@ extern "C" { pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; pub fn SSL_CTX_free(ctx: *mut SSL_CTX); pub fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int, - verify_callback: Option c_int>); + verify_callback: Option c_int>); pub fn SSL_CTX_load_verify_locations(ctx: *mut SSL_CTX, CAfile: *const c_char, CApath: *const c_char) -> c_int; pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *const c_void, @@ -154,19 +93,11 @@ extern "C" { pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int; pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int; - pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) - -> *mut c_void; - pub fn X509_STORE_CTX_get_current_cert(ct: *mut X509_STORE_CTX) -> *mut X509; - pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int; - - pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME; - pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; - pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL; pub fn SSL_free(ssl: *mut SSL); - pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO); - pub fn SSL_get_rbio(ssl: *mut SSL) -> *mut BIO; - pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut BIO; + pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut bio::ffi::BIO, wbio: *mut bio::ffi::BIO); + pub fn SSL_get_rbio(ssl: *mut SSL) -> *mut bio::ffi::BIO; + pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut bio::ffi::BIO; pub fn SSL_connect(ssl: *mut SSL) -> c_int; pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; @@ -177,12 +108,6 @@ extern "C" { pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX; pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; - pub fn BIO_s_mem() -> *const BIO_METHOD; - pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; - pub fn BIO_free_all(a: *mut BIO); - pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; - pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; - pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; } diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index fc775a32..d13972d2 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_uint, c_void, c_char}; +use libc::{c_int, c_void, c_char}; use std::io::{IoResult, IoError, EndOfFile, Stream, Reader, Writer}; use std::mem; use std::ptr; @@ -6,8 +6,9 @@ use std::rt::mutex::NativeMutex; use std::string; use sync::one::{Once, ONCE_INIT}; -use crypto::hash::{HashType, evpmd}; +use bio::{mod, MemBio}; use ssl::error::{SslError, SslSessionClosed, StreamError}; +use x509::{mod, X509StoreContext, X509FileType}; pub mod error; mod ffi; @@ -17,15 +18,6 @@ mod tests; static mut VERIFY_IDX: c_int = -1; static mut MUTEXES: *mut Vec = 0 as *mut Vec; -macro_rules! try_ssl( - ($e:expr) => ( - match $e { - Ok(ok) => ok, - Err(err) => return Err(StreamError(err)) - } - ) -) - fn init() { static mut INIT: Once = ONCE_INIT; @@ -103,16 +95,16 @@ extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, } } -extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) +extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut x509::ffi::X509_STORE_CTX) -> c_int { unsafe { let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); - let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); + let ssl = x509::ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX); let verify: Option = mem::transmute(verify); - let ctx = X509StoreContext { ctx: x509_ctx }; + let ctx = X509StoreContext::new(x509_ctx); match verify { None => preverify_ok, @@ -125,13 +117,6 @@ extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) pub type VerifyCallback = fn(preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool; -#[repr(i32)] -pub enum X509FileType { - PEM = ffi::X509_FILETYPE_PEM, - ASN1 = ffi::X509_FILETYPE_ASN1, - Default = ffi::X509_FILETYPE_DEFAULT -} - // FIXME: macro may be instead of inlining? #[inline] fn wrap_ssl_result(res: c_int) -> Option { @@ -207,146 +192,22 @@ impl SslContext { } } -pub struct X509StoreContext { - ctx: *mut ffi::X509_STORE_CTX -} - -impl X509StoreContext { - pub fn get_error(&self) -> Option { - let err = unsafe { ffi::X509_STORE_CTX_get_error(self.ctx) }; - X509ValidationError::from_raw(err) - } - - pub fn get_current_cert<'a>(&'a self) -> Option> { - let ptr = unsafe { ffi::X509_STORE_CTX_get_current_cert(self.ctx) }; - - if ptr.is_null() { - None - } else { - Some(X509 { ctx: self, x509: ptr }) - } - } -} - #[allow(dead_code)] -/// A public key certificate -pub struct X509<'ctx> { - ctx: &'ctx X509StoreContext, - x509: *mut ffi::X509 +struct MemBioRef<'ssl> { + ssl: &'ssl Ssl, + bio: MemBio, } -impl<'ctx> X509<'ctx> { - pub fn subject_name<'a>(&'a self) -> X509Name<'a> { - let name = unsafe { ffi::X509_get_subject_name(self.x509) }; - X509Name { x509: self, name: name } +impl<'ssl> MemBioRef<'ssl> { + fn read(&mut self, buf: &mut [u8]) -> Option { + (&mut self.bio as &mut Reader).read(buf).ok() } - /// Returns certificate fingerprint calculated using provided hash - pub fn fingerprint(&self, hash_type: HashType) -> Option> { - let (evp, len) = evpmd(hash_type); - let v: Vec = Vec::from_elem(len, 0); - let act_len: c_uint = 0; - let res = unsafe { - ffi::X509_digest(self.x509, evp, mem::transmute(v.as_ptr()), - mem::transmute(&act_len)) - }; - - match res { - 0 => None, - _ => { - let act_len = act_len as uint; - match len.cmp(&act_len) { - Greater => None, - Equal => Some(v), - Less => fail!("Fingerprint buffer was corrupted!") - } - } - } + fn write(&mut self, buf: &[u8]) { + let _ = (&mut self.bio as &mut Writer).write(buf); } } -#[allow(dead_code)] -pub struct X509Name<'x> { - x509: &'x X509<'x>, - name: *mut ffi::X509_NAME -} - -macro_rules! make_validation_error( - ($ok_val:ident, $($name:ident = $val:ident,)+) => ( - pub enum X509ValidationError { - $($name,)+ - X509UnknownError(c_int) - } - - impl X509ValidationError { - #[doc(hidden)] - pub fn from_raw(err: c_int) -> Option { - match err { - self::ffi::$ok_val => None, - $(self::ffi::$val => Some($name),)+ - err => Some(X509UnknownError(err)) - } - } - } - ) -) - -make_validation_error!(X509_V_OK, - X509UnableToGetIssuerCert = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, - X509UnableToGetCrl = X509_V_ERR_UNABLE_TO_GET_CRL, - X509UnableToDecryptCertSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, - X509UnableToDecryptCrlSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, - X509UnableToDecodeIssuerPublicKey = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, - X509CertSignatureFailure = X509_V_ERR_CERT_SIGNATURE_FAILURE, - X509CrlSignatureFailure = X509_V_ERR_CRL_SIGNATURE_FAILURE, - X509CertNotYetValid = X509_V_ERR_CERT_NOT_YET_VALID, - X509CertHasExpired = X509_V_ERR_CERT_HAS_EXPIRED, - X509CrlNotYetValid = X509_V_ERR_CRL_NOT_YET_VALID, - X509CrlHasExpired = X509_V_ERR_CRL_HAS_EXPIRED, - X509ErrorInCertNotBeforeField = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD, - X509ErrorInCertNotAfterField = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD, - X509ErrorInCrlLastUpdateField = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD, - X509ErrorInCrlNextUpdateField = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD, - X509OutOfMem = X509_V_ERR_OUT_OF_MEM, - X509DepthZeroSelfSignedCert = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, - X509SelfSignedCertInChain = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, - X509UnableToGetIssuerCertLocally = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, - X509UnableToVerifyLeafSignature = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, - X509CertChainTooLong = X509_V_ERR_CERT_CHAIN_TOO_LONG, - X509CertRevoked = X509_V_ERR_CERT_REVOKED, - X509InvalidCA = X509_V_ERR_INVALID_CA, - X509PathLengthExceeded = X509_V_ERR_PATH_LENGTH_EXCEEDED, - X509InvalidPurpose = X509_V_ERR_INVALID_PURPOSE, - X509CertUntrusted = X509_V_ERR_CERT_UNTRUSTED, - X509CertRejected = X509_V_ERR_CERT_REJECTED, - X509SubjectIssuerMismatch = X509_V_ERR_SUBJECT_ISSUER_MISMATCH, - X509AkidSkidMismatch = X509_V_ERR_AKID_SKID_MISMATCH, - X509AkidIssuerSerialMismatch = X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH, - X509KeyusageNoCertsign = X509_V_ERR_KEYUSAGE_NO_CERTSIGN, - X509UnableToGetCrlIssuer = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, - X509UnhandledCriticalExtension = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION, - X509KeyusageNoCrlSign = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN, - X509UnhandledCriticalCrlExtension = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION, - X509InvalidNonCA = X509_V_ERR_INVALID_NON_CA, - X509ProxyPathLengthExceeded = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED, - X509KeyusageNoDigitalSignature = X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, - X509ProxyCertificatesNotAllowed = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED, - X509InvalidExtension = X509_V_ERR_INVALID_EXTENSION, - X509InavlidPolicyExtension = X509_V_ERR_INVALID_POLICY_EXTENSION, - X509NoExplicitPolicy = X509_V_ERR_NO_EXPLICIT_POLICY, - X509DifferentCrlScope = X509_V_ERR_DIFFERENT_CRL_SCOPE, - X509UnsupportedExtensionFeature = X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE, - X509UnnestedResource = X509_V_ERR_UNNESTED_RESOURCE, - X509PermittedVolation = X509_V_ERR_PERMITTED_VIOLATION, - X509ExcludedViolation = X509_V_ERR_EXCLUDED_VIOLATION, - X509SubtreeMinmax = X509_V_ERR_SUBTREE_MINMAX, - X509UnsupportedConstraintType = X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, - X509UnsupportedConstraintSyntax = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX, - X509UnsupportedNameSyntax = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, - X509CrlPathValidationError= X509_V_ERR_CRL_PATH_VALIDATION_ERROR, - X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION, -) - pub struct Ssl { ssl: *mut ffi::SSL } @@ -365,18 +226,10 @@ impl Ssl { } let ssl = Ssl { ssl: ssl }; - let rbio = unsafe { ffi::BIO_new(ffi::BIO_s_mem()) }; - if rbio == ptr::null_mut() { - return Err(SslError::get()); - } - - let wbio = unsafe { ffi::BIO_new(ffi::BIO_s_mem()) }; - if wbio == ptr::null_mut() { - unsafe { ffi::BIO_free_all(rbio) } - return Err(SslError::get()); - } + let rbio = try!(MemBio::new()); + let wbio = try!(MemBio::new()); - unsafe { ffi::SSL_set_bio(ssl.ssl, rbio, wbio) } + unsafe { ffi::SSL_set_bio(ssl.ssl, rbio.unwrap(), wbio.unwrap()) } Ok(ssl) } @@ -388,14 +241,11 @@ impl Ssl { unsafe { self.wrap_bio(ffi::SSL_get_wbio(self.ssl)) } } - fn wrap_bio<'a>(&'a self, bio: *mut ffi::BIO) -> MemBioRef<'a> { + fn wrap_bio<'a>(&'a self, bio: *mut bio::ffi::BIO) -> MemBioRef<'a> { assert!(bio != ptr::mut_null()); MemBioRef { ssl: self, - bio: MemBio { - bio: bio, - owned: false - } + bio: MemBio::borrowed(bio) } } @@ -459,60 +309,6 @@ enum LibSslError { ErrorWantAccept = ffi::SSL_ERROR_WANT_ACCEPT, } -#[allow(dead_code)] -struct MemBioRef<'ssl> { - ssl: &'ssl Ssl, - bio: MemBio, -} - -impl<'ssl> MemBioRef<'ssl> { - fn read(&self, buf: &mut [u8]) -> Option { - self.bio.read(buf) - } - - fn write(&self, buf: &[u8]) { - self.bio.write(buf) - } -} - -struct MemBio { - bio: *mut ffi::BIO, - owned: bool -} - -impl Drop for MemBio { - fn drop(&mut self) { - if self.owned { - unsafe { - ffi::BIO_free_all(self.bio); - } - } - } -} - -impl MemBio { - fn read(&self, buf: &mut [u8]) -> Option { - let ret = unsafe { - ffi::BIO_read(self.bio, buf.as_ptr() as *mut c_void, - buf.len() as c_int) - }; - - if ret < 0 { - None - } else { - Some(ret as uint) - } - } - - fn write(&self, buf: &[u8]) { - let ret = unsafe { - ffi::BIO_write(self.bio, buf.as_ptr() as *const c_void, - buf.len() as c_int) - }; - assert_eq!(buf.len(), ret as uint); - } -} - /// A stream wrapper which handles SSL encryption for an underlying stream. pub struct SslStream { stream: S, @@ -556,11 +352,11 @@ impl SslStream { match self.ssl.get_error(ret) { ErrorWantRead => { - try_ssl!(self.flush()); - let len = try_ssl!(self.stream.read(self.buf.as_mut_slice())); + try_ssl_stream!(self.flush()); + let len = try_ssl_stream!(self.stream.read(self.buf.as_mut_slice())); self.ssl.get_rbio().write(self.buf.slice_to(len)); } - ErrorWantWrite => { try_ssl!(self.flush()) } + ErrorWantWrite => { try_ssl_stream!(self.flush()) } ErrorZeroReturn => return Err(SslSessionClosed), ErrorSsl => return Err(SslError::get()), _ => unreachable!() diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 99241719..82effee0 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -2,7 +2,9 @@ use std::io::Writer; use std::io::net::tcp::TcpStream; use std::str; -use ssl::{Sslv23, SslContext, SslStream, SslVerifyPeer, X509StoreContext}; +use crypto::hash::{SHA256}; +use ssl::{Sslv23, SslContext, SslStream, SslVerifyPeer}; +use x509::{X509Generator, X509, DigitalSignature, KeyEncipherment, ClientAuth, ServerAuth, X509StoreContext}; #[test] fn test_new_ctx() { @@ -158,3 +160,19 @@ 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()); + // FIXME: check data in result to be correct, needs implementation + // of X509 getters +} diff --git a/src/x509/mod.rs b/src/x509/mod.rs new file mode 100755 index 00000000..06ae4b27 --- /dev/null +++ b/src/x509/mod.rs @@ -0,0 +1,517 @@ +use libc::{c_int, c_long, c_uint}; +use std::mem; +use std::ptr; + +use asn1; +use bio::{MemBio}; +use crypto::hash::{HashType, evpmd, SHA1}; +use crypto::pkey::{PKey}; +use crypto::rand::rand_bytes; +use ssl::error::{SslError, StreamError}; + + +#[repr(i32)] +pub enum X509FileType { + PEM = ffi::X509_FILETYPE_PEM, + ASN1 = ffi::X509_FILETYPE_ASN1, + Default = ffi::X509_FILETYPE_DEFAULT +} +pub struct X509StoreContext { + ctx: *mut ffi::X509_STORE_CTX +} + +impl X509StoreContext { + pub fn new(ctx: *mut ffi::X509_STORE_CTX) -> X509StoreContext { + X509StoreContext { + ctx: ctx + } + } + + pub fn get_error(&self) -> Option { + let err = unsafe { ffi::X509_STORE_CTX_get_error(self.ctx) }; + X509ValidationError::from_raw(err) + } + + pub fn get_current_cert<'a>(&'a self) -> Option> { + let ptr = unsafe { ffi::X509_STORE_CTX_get_current_cert(self.ctx) }; + + if ptr.is_null() { + None + } else { + Some(X509 { ctx: Some(self), x509: ptr }) + } + } +} + +trait AsStr<'a> { + fn as_str(&self) -> &'a str; +} + +#[deriving(Clone)] +pub enum KeyUsage { + DigitalSignature, + NonRepudiation, + KeyEncipherment, + DataEncipherment, + KeyAgreement, + KeyCertSign, + CRLSign, + EncipherOnly, + DecipherOnly +} + +impl AsStr<'static> for KeyUsage { + fn as_str(&self) -> &'static str { + match self { + &DigitalSignature => "digitalSignature", + &NonRepudiation => "nonRepudiation", + &KeyEncipherment => "keyEncipherment", + &DataEncipherment => "dataEncipherment", + &KeyAgreement => "keyAgreement", + &KeyCertSign => "keyCertSign", + &CRLSign => "cRLSign", + &EncipherOnly => "encipherOnly", + &DecipherOnly => "decipherOnly" + } + } +} + + +#[deriving(Clone)] +pub enum ExtKeyUsage { + ServerAuth, + ClientAuth, + CodeSigning, + EmailProtection, + TimeStamping, + MsCodeInd, + MsCodeCom, + MsCtlSign, + MsSgc, + MsEfs, + NsSgc +} + +impl AsStr<'static> for ExtKeyUsage { + fn as_str(&self) -> &'static str { + match self { + &ServerAuth => "serverAuth", + &ClientAuth => "clientAuth", + &CodeSigning => "codeSigning", + &EmailProtection => "emailProtection", + &TimeStamping => "timeStamping", + &MsCodeInd => "msCodeInd", + &MsCodeCom => "msCodeCom", + &MsCtlSign => "msCTLSign", + &MsSgc => "msSGC", + &MsEfs => "msEFS", + &NsSgc =>"nsSGC" + } + } +} + + +// FIXME: a dirty hack as there is no way to +// implement ToString for Vec as both are defined +// in another crate +trait ToStr { + fn to_str(&self) -> String; +} + +impl<'a, T: AsStr<'a>> ToStr for Vec { + fn to_str(&self) -> String { + self.iter().enumerate().fold(String::new(), |mut acc, (idx, v)| { + if idx > 0 { acc.push_char(',') }; + acc.push_str(v.as_str()); + acc + }) + } +} + +#[allow(non_snake_case)] +pub struct X509Generator { + bits: uint, + days: uint, + CN: String, + key_usage: Vec, + ext_key_usage: Vec, + hash_type: HashType, +} + +impl X509Generator { + pub fn new() -> X509Generator { + X509Generator { + bits: 1024, + days: 365, + CN: "rust-openssl".to_string(), + key_usage: Vec::new(), + ext_key_usage: Vec::new(), + hash_type: SHA1 + } + } + + pub fn set_bitlength(mut self, bits: uint) -> X509Generator { + self.bits = bits; + self + } + + pub fn set_valid_period(mut self, days: uint) -> X509Generator { + self.days = days; + self + } + + #[allow(non_snake_case)] + pub fn set_CN(mut self, CN: &str) -> X509Generator { + self.CN = CN.to_string(); + self + } + + pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator { + self.key_usage = purposes.to_vec(); + self + } + + pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator { + self.ext_key_usage = purposes.to_vec(); + self + } + + pub fn set_sign_hash(mut self, hash_type: HashType) -> X509Generator { + self.hash_type = hash_type; + self + } + + fn add_extension(x509: *mut ffi::X509, extension: c_int, value: &str) -> Result<(), SslError> { + unsafe { + // FIXME: RAII + let ctx: ffi::X509V3_CTX = mem::zeroed(); + ffi::X509V3_set_ctx(mem::transmute(&ctx), x509, x509, + ptr::null_mut(), ptr::null_mut(), 0); + let ext = value.with_c_str(|value| + ffi::X509V3_EXT_conf_nid(ptr::null_mut(), mem::transmute(&ctx), extension, mem::transmute(value))); + try_ssl_null!(ext); + try_ssl!(ffi::X509_add_ext(x509, ext, -1)); + ffi::X509_EXTENSION_free(ext); + Ok(()) + } + } + + fn add_name(name: *mut ffi::X509_NAME, key: &str, value: &str) -> Result<(), SslError> { + let value_len = value.len() as c_int; + lift_ssl!(key.with_c_str(|key| { + value.with_c_str(|value| unsafe { + ffi::X509_NAME_add_entry_by_txt(name, key, asn1::ffi::MBSTRING_UTF8, + value, value_len, -1, 0) + }) + })) + } + + fn random_serial() -> c_long { + let len = mem::size_of::(); + let bytes = rand_bytes(len); + let mut res = 0; + for b in bytes.iter() { + res = res << 8; + res |= (*b as c_long) & 0xff; + } + res + } + + pub fn generate<'a>(&self) -> Result<(X509<'a>, PKey), SslError> { + let mut p_key = PKey::new(); + p_key.gen(self.bits); + + // FIXME: all allocated resources should be correctly + // dropped in case of failure + unsafe { + let x509 = ffi::X509_new(); + try_ssl_null!(x509); + try_ssl!(ffi::X509_set_version(x509, 2)); + try_ssl!(asn1::ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509), X509Generator::random_serial())); + + let not_before = ffi::X509_gmtime_adj(ptr::null_mut(), 0); + try_ssl_null!(not_before); + + let not_after = ffi::X509_gmtime_adj(ptr::null_mut(), 60*60*24*self.days as i64); + try_ssl_null!(not_after); + + try_ssl!(ffi::X509_set_notBefore(x509, mem::transmute(not_before))); + try_ssl!(ffi::X509_set_notAfter(x509, mem::transmute(not_after))); + + try_ssl!(ffi::X509_set_pubkey(x509, p_key.get_handle())); + + let name = ffi::X509_get_subject_name(x509); + try_ssl_null!(name); + + try!(X509Generator::add_name(name, "CN", self.CN.as_slice())); + ffi::X509_set_issuer_name(x509, name); + + if self.key_usage.len() > 0 { + try!(X509Generator::add_extension(x509, ffi::NID_key_usage, + self.key_usage.to_str().as_slice())); + } + + if self.ext_key_usage.len() > 0 { + try!(X509Generator::add_extension(x509, ffi::NID_ext_key_usage, + self.ext_key_usage.to_str().as_slice())); + } + + let (hash_fn, _) = evpmd(self.hash_type); + try_ssl!(ffi::X509_sign(x509, p_key.get_handle(), hash_fn)); + Ok((X509 { x509: x509, ctx: None }, p_key)) + } + } +} + +#[allow(dead_code)] +/// A public key certificate +pub struct X509<'ctx> { + ctx: Option<&'ctx X509StoreContext>, + x509: *mut ffi::X509 +} + +impl<'ctx> X509<'ctx> { + pub fn subject_name<'a>(&'a self) -> X509Name<'a> { + let name = unsafe { ffi::X509_get_subject_name(self.x509) }; + X509Name { x509: self, name: name } + } + + /// Returns certificate fingerprint calculated using provided hash + pub fn fingerprint(&self, hash_type: HashType) -> Option> { + let (evp, len) = evpmd(hash_type); + let v: Vec = Vec::from_elem(len, 0); + let act_len: c_uint = 0; + let res = unsafe { + ffi::X509_digest(self.x509, evp, mem::transmute(v.as_ptr()), + mem::transmute(&act_len)) + }; + + match res { + 0 => None, + _ => { + let act_len = act_len as uint; + match len.cmp(&act_len) { + Greater => None, + Equal => Some(v), + Less => fail!("Fingerprint buffer was corrupted!") + } + } + } + } + + /// Writes certificate as PEM + pub fn write_pem(&self, writer: &mut Writer) -> Result<(), SslError> { + let mut mem_bio = try!(MemBio::new()); + unsafe { + try_ssl!(ffi::PEM_write_bio_X509(mem_bio.get_handle(), + self.x509)); + } + let buf = try!(mem_bio.read_to_end().map_err(StreamError)); + writer.write(buf.as_slice()).map_err(StreamError) + } +} + +#[allow(dead_code)] +pub struct X509Name<'x> { + x509: &'x X509<'x>, + name: *mut ffi::X509_NAME +} + + +pub mod ffi { + #![allow(non_camel_case_types)] + use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint}; + + use asn1::ffi::{ASN1_INTEGER, ASN1_TIME}; + use bio::ffi::{BIO}; + use crypto::hash::{EVP_MD}; + use crypto::pkey::{EVP_PKEY}; + + pub type X509_STORE_CTX = c_void; + pub type X509 = c_void; + pub type X509_NAME = c_void; + pub type X509_CRL = c_void; + pub type X509_REQ = c_void; + pub type X509_EXTENSION = c_void; + + #[repr(C)] + pub struct X509V3_CTX { + flags: c_int, + issuer_cert: *mut c_void, + subject_cert: *mut c_void, + subject_req: *mut c_void, + crl: *mut c_void, + db_meth: *mut c_void, + db: *mut c_void, + // I like the last comment line, it is copied from OpenSSL sources: + // Maybe more here + } + + pub static X509_V_OK: c_int = 0; + pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; + pub static X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; + pub static X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; + pub static X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; + pub static X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; + pub static X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; + pub static X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; + pub static X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; + pub static X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; + pub static X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; + pub static X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; + pub static X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; + pub static X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; + pub static X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; + pub static X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; + pub static X509_V_ERR_OUT_OF_MEM: c_int = 17; + pub static X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; + pub static X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; + pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; + pub static X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; + pub static X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; + pub static X509_V_ERR_CERT_REVOKED: c_int = 23; + pub static X509_V_ERR_INVALID_CA: c_int = 24; + pub static X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; + pub static X509_V_ERR_INVALID_PURPOSE: c_int = 26; + pub static X509_V_ERR_CERT_UNTRUSTED: c_int = 27; + pub static X509_V_ERR_CERT_REJECTED: c_int = 28; + pub static X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; + pub static X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; + pub static X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; + pub static X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; + pub static X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; + pub static X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; + pub static X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; + pub static X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; + pub static X509_V_ERR_INVALID_NON_CA: c_int = 37; + pub static X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; + pub static X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; + pub static X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; + pub static X509_V_ERR_INVALID_EXTENSION: c_int = 41; + pub static X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; + pub static X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; + pub static X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; + pub static X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; + pub static X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; + pub static X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; + pub static X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; + pub static X509_V_ERR_SUBTREE_MINMAX: c_int = 49; + pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; + pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; + pub static X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; + pub static X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; + pub static X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; + + pub static X509_FILETYPE_PEM: c_int = 1; + pub static X509_FILETYPE_ASN1: c_int = 2; + pub static X509_FILETYPE_DEFAULT: c_int = 3; + + pub static NID_key_usage: c_int = 83; + pub static NID_ext_key_usage: c_int = 126; + + + + extern "C" { + pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; + pub fn X509_STORE_CTX_get_current_cert(ct: *mut X509_STORE_CTX) -> *mut X509; + pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int; + + pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; + pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; + pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; + pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME; + pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; + pub fn X509_new() -> *mut X509; + pub fn X509_set_issuer_name(x: *mut X509, name: *mut X509_NAME) -> c_int; + pub fn X509_set_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + pub fn X509_set_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + pub fn X509_set_version(x: *mut X509, version: c_ulong) -> c_int; + pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; + pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; + + pub fn X509_NAME_add_entry_by_txt(x: *mut X509, field: *const c_char, ty: c_int, bytes: *const c_char, len: c_int, loc: c_int, set: c_int) -> c_int; + + pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION; + pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int); + + pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); + + pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; + } +} + +macro_rules! make_validation_error( + ($ok_val:ident, $($name:ident = $val:ident,)+) => ( + pub enum X509ValidationError { + $($name,)+ + X509UnknownError(c_int) + } + + impl X509ValidationError { + #[doc(hidden)] + pub fn from_raw(err: c_int) -> Option { + match err { + self::ffi::$ok_val => None, + $(self::ffi::$val => Some($name),)+ + err => Some(X509UnknownError(err)) + } + } + } + ) +) + +make_validation_error!(X509_V_OK, + X509UnableToGetIssuerCert = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, + X509UnableToGetCrl = X509_V_ERR_UNABLE_TO_GET_CRL, + X509UnableToDecryptCertSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, + X509UnableToDecryptCrlSignature = X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, + X509UnableToDecodeIssuerPublicKey = X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, + X509CertSignatureFailure = X509_V_ERR_CERT_SIGNATURE_FAILURE, + X509CrlSignatureFailure = X509_V_ERR_CRL_SIGNATURE_FAILURE, + X509CertNotYetValid = X509_V_ERR_CERT_NOT_YET_VALID, + X509CertHasExpired = X509_V_ERR_CERT_HAS_EXPIRED, + X509CrlNotYetValid = X509_V_ERR_CRL_NOT_YET_VALID, + X509CrlHasExpired = X509_V_ERR_CRL_HAS_EXPIRED, + X509ErrorInCertNotBeforeField = X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD, + X509ErrorInCertNotAfterField = X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD, + X509ErrorInCrlLastUpdateField = X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD, + X509ErrorInCrlNextUpdateField = X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD, + X509OutOfMem = X509_V_ERR_OUT_OF_MEM, + X509DepthZeroSelfSignedCert = X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, + X509SelfSignedCertInChain = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN, + X509UnableToGetIssuerCertLocally = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, + X509UnableToVerifyLeafSignature = X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE, + X509CertChainTooLong = X509_V_ERR_CERT_CHAIN_TOO_LONG, + X509CertRevoked = X509_V_ERR_CERT_REVOKED, + X509InvalidCA = X509_V_ERR_INVALID_CA, + X509PathLengthExceeded = X509_V_ERR_PATH_LENGTH_EXCEEDED, + X509InvalidPurpose = X509_V_ERR_INVALID_PURPOSE, + X509CertUntrusted = X509_V_ERR_CERT_UNTRUSTED, + X509CertRejected = X509_V_ERR_CERT_REJECTED, + X509SubjectIssuerMismatch = X509_V_ERR_SUBJECT_ISSUER_MISMATCH, + X509AkidSkidMismatch = X509_V_ERR_AKID_SKID_MISMATCH, + X509AkidIssuerSerialMismatch = X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH, + X509KeyusageNoCertsign = X509_V_ERR_KEYUSAGE_NO_CERTSIGN, + X509UnableToGetCrlIssuer = X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER, + X509UnhandledCriticalExtension = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION, + X509KeyusageNoCrlSign = X509_V_ERR_KEYUSAGE_NO_CRL_SIGN, + X509UnhandledCriticalCrlExtension = X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION, + X509InvalidNonCA = X509_V_ERR_INVALID_NON_CA, + X509ProxyPathLengthExceeded = X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED, + X509KeyusageNoDigitalSignature = X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE, + X509ProxyCertificatesNotAllowed = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED, + X509InvalidExtension = X509_V_ERR_INVALID_EXTENSION, + X509InavlidPolicyExtension = X509_V_ERR_INVALID_POLICY_EXTENSION, + X509NoExplicitPolicy = X509_V_ERR_NO_EXPLICIT_POLICY, + X509DifferentCrlScope = X509_V_ERR_DIFFERENT_CRL_SCOPE, + X509UnsupportedExtensionFeature = X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE, + X509UnnestedResource = X509_V_ERR_UNNESTED_RESOURCE, + X509PermittedVolation = X509_V_ERR_PERMITTED_VIOLATION, + X509ExcludedViolation = X509_V_ERR_EXCLUDED_VIOLATION, + X509SubtreeMinmax = X509_V_ERR_SUBTREE_MINMAX, + X509UnsupportedConstraintType = X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE, + X509UnsupportedConstraintSyntax = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX, + X509UnsupportedNameSyntax = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX, + X509CrlPathValidationError= X509_V_ERR_CRL_PATH_VALIDATION_ERROR, + X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION, +) -- cgit v1.2.3 From 3f413e9354238919bce6dc87e3415919f301d487 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Sun, 28 Sep 2014 07:09:57 +0300 Subject: Addressed review comments - fixed invalid file permissions - removed redundand mem::transmute - removed outdated FIXME's - removed redundand temporary variable - removed macro_export for internal macros --- src/bio/mod.rs | 9 +++------ src/lib.rs | 0 src/macros.rs | 6 ------ src/x509/mod.rs | 4 ++-- 4 files changed, 5 insertions(+), 14 deletions(-) mode change 100755 => 100644 src/lib.rs mode change 100755 => 100644 src/macros.rs (limited to 'src') diff --git a/src/bio/mod.rs b/src/bio/mod.rs index 019129ea..f81114de 100644 --- a/src/bio/mod.rs +++ b/src/bio/mod.rs @@ -43,10 +43,9 @@ impl MemBio { /// Consumes current bio and returns wrapped value /// Note that data ownership is lost and /// should be handled manually - pub unsafe fn unwrap(self) -> *mut ffi::BIO { - let mut t = self; - t.owned = false; - t.bio + pub unsafe fn unwrap(mut self) -> *mut ffi::BIO { + self.owned = false; + self.bio } /// Temporarily gets wrapped value @@ -57,7 +56,6 @@ impl MemBio { impl Reader for MemBio { fn read(&mut self, buf: &mut [u8]) -> IoResult { - // FIXME: merge with read let ret = unsafe { ffi::BIO_read(self.bio, buf.as_ptr() as *mut c_void, buf.len() as c_int) @@ -74,7 +72,6 @@ impl Reader for MemBio { impl Writer for MemBio { fn write(&mut self, buf: &[u8]) -> IoResult<()> { - // FIXME: merge with write let ret = unsafe { ffi::BIO_write(self.bio, buf.as_ptr() as *const c_void, buf.len() as c_int) diff --git a/src/lib.rs b/src/lib.rs old mode 100755 new mode 100644 diff --git a/src/macros.rs b/src/macros.rs old mode 100755 new mode 100644 index b11f9dad..061381f2 --- a/src/macros.rs +++ b/src/macros.rs @@ -1,6 +1,5 @@ #![macro_escape] -#[macro_export] macro_rules! try_ssl_stream { ($e:expr) => ( match $e { @@ -11,7 +10,6 @@ macro_rules! try_ssl_stream { } /// Shortcut return with SSL error if something went wrong -#[macro_export] macro_rules! try_ssl_if { ($e:expr) => ( if $e { @@ -22,13 +20,11 @@ macro_rules! try_ssl_if { /// Shortcut return with SSL error if last error result is 0 /// (default) -#[macro_export] macro_rules! try_ssl{ ($e:expr) => (try_ssl_if!($e == 0)) } /// Shortcut return with SSL if got a null result -#[macro_export] macro_rules! try_ssl_null{ ($e:expr) => (try_ssl_if!($e == ptr::null_mut())) } @@ -42,7 +38,6 @@ macro_rules! try_ssl_null{ /// let _ = try!(something) /// Ok(()) /// ``` -#[macro_export] macro_rules! lift_ssl_if{ ($e:expr) => ( { if $e { @@ -55,7 +50,6 @@ macro_rules! lift_ssl_if{ /// Lifts current SSL error code into Result<(), Error> /// if SSL returned 0 (default error indication) -#[macro_export] macro_rules! lift_ssl { ($e:expr) => (lift_ssl_if!($e == 0)) } diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 06ae4b27..cc911afe 100755 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -184,8 +184,8 @@ impl X509Generator { fn add_extension(x509: *mut ffi::X509, extension: c_int, value: &str) -> Result<(), SslError> { unsafe { // FIXME: RAII - let ctx: ffi::X509V3_CTX = mem::zeroed(); - ffi::X509V3_set_ctx(mem::transmute(&ctx), x509, x509, + let mut ctx: ffi::X509V3_CTX = mem::zeroed(); + ffi::X509V3_set_ctx(&mut ctx, x509, x509, ptr::null_mut(), ptr::null_mut(), 0); let ext = value.with_c_str(|value| ffi::X509V3_EXT_conf_nid(ptr::null_mut(), mem::transmute(&ctx), extension, mem::transmute(value))); -- cgit v1.2.3 From 02637ec7d451c38792c42c5c2cb4d59505e13ced Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Sun, 28 Sep 2014 08:15:51 +0300 Subject: single `ffi` module --- src/asn1/mod.rs | 23 --- src/bio/mod.rs | 18 +-- src/bn/mod.rs | 191 +++++++----------------- src/crypto/hash.rs | 71 +++------ src/crypto/hmac.rs | 46 ++---- src/crypto/pkcs5.rs | 11 +- src/crypto/pkey.rs | 107 +++++--------- src/crypto/rand.rs | 8 +- src/crypto/symm.rs | 62 ++------ src/ffi.rs | 418 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/ssl/error.rs | 2 +- src/ssl/ffi.rs | 117 --------------- src/ssl/mod.rs | 12 +- src/x509/mod.rs | 133 +---------------- 15 files changed, 571 insertions(+), 649 deletions(-) create mode 100755 src/ffi.rs delete mode 100755 src/ssl/ffi.rs (limited to 'src') diff --git a/src/asn1/mod.rs b/src/asn1/mod.rs index d302d6b7..e69de29b 100644 --- a/src/asn1/mod.rs +++ b/src/asn1/mod.rs @@ -1,23 +0,0 @@ -pub mod ffi { - #![allow(dead_code)] - #![allow(non_camel_case_types)] - use libc::{c_int, c_long, c_void}; - - pub type ASN1_INTEGER = c_void; - pub type ASN1_TIME = c_void; - pub type ASN1_STRING = c_void; - - pub static MBSTRING_FLAG: c_int = 0x1000; - pub static MBSTRING_UTF8: c_int = MBSTRING_FLAG; - pub static MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; - pub static MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; - pub static MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; - - pub static V_ASN1_UTCTIME: c_int = 23; - pub static V_ASN1_GENERALIZEDTIME: c_int = 24; - - extern "C" { - pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; - pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; - } -} diff --git a/src/bio/mod.rs b/src/bio/mod.rs index f81114de..5c5e8df0 100644 --- a/src/bio/mod.rs +++ b/src/bio/mod.rs @@ -3,6 +3,7 @@ use std::io::{IoResult, IoError, OtherIoError}; use std::io::{Reader, Writer}; use std::ptr; +use ffi; use ssl::error::{SslError}; pub struct MemBio { @@ -84,20 +85,3 @@ impl Writer for MemBio { } } } - -pub mod ffi { - #![allow(non_camel_case_types)] - - use libc::{c_int, c_void}; - - pub type BIO = c_void; - pub type BIO_METHOD = c_void; - - extern "C" { - pub fn BIO_s_mem() -> *const BIO_METHOD; - pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; - pub fn BIO_free_all(a: *mut BIO); - pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; - pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; - } -} diff --git a/src/bn/mod.rs b/src/bn/mod.rs index cc64d8cd..29ffd413 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -1,88 +1,12 @@ - -use libc::{c_void, c_int, c_ulong, c_char}; +use libc::{c_int, c_ulong}; use std::{fmt, ptr}; use std::c_str::CString; use std::num::{One, Zero}; +use ffi; use ssl::error::SslError; -#[allow(dead_code)] -#[repr(C)] -struct BIGNUM { - d: *mut c_void, - top: c_int, - dmax: c_int, - neg: c_int, - flags: c_int, -} - -#[allow(non_camel_case_types)] -type BN_CTX = *mut c_void; - -#[link(name = "crypto")] -extern { - fn BN_new() -> *mut BIGNUM; - fn BN_clear_free(bn: *mut BIGNUM); - - fn BN_CTX_new() -> *mut BN_CTX; - fn BN_CTX_free(ctx: *mut BN_CTX); - - fn BN_set_word(bn: *mut BIGNUM, n: c_ulong) -> c_int; - fn BN_set_negative(bn: *mut BIGNUM, n: c_int); - fn BN_num_bits(bn: *mut BIGNUM) -> c_int; - - /* Arithmetic operations on BIGNUMs */ - fn BN_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - fn BN_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - fn BN_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_sqr(r: *mut BIGNUM, a: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_div(dv: *mut BIGNUM, rem: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_nnmod(rem: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_mod_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_mod_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_mod_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_mod_sqr(r: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_mod_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - fn BN_mod_inverse(r: *mut BIGNUM, a: *mut BIGNUM, n: *mut BIGNUM, ctx: *mut BN_CTX) -> *const BIGNUM; - fn BN_gcd(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - - /* Bit operations on BIGNUMs */ - fn BN_set_bit(a: *mut BIGNUM, n: c_int) -> c_int; - fn BN_clear_bit(a: *mut BIGNUM, n: c_int) -> c_int; - fn BN_is_bit_set(a: *mut BIGNUM, n: c_int) -> c_int; - fn BN_mask_bits(a: *mut BIGNUM, n: c_int) -> c_int; - fn BN_lshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int; - fn BN_lshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int; - fn BN_rshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int; - fn BN_rshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int; - - /* Comparisons on BIGNUMs */ - fn BN_cmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - fn BN_ucmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - fn BN_is_zero(a: *mut BIGNUM) -> c_int; - - /* Prime handling */ - fn BN_generate_prime_ex(r: *mut BIGNUM, bits: c_int, safe: c_int, add: *mut BIGNUM, rem: *mut BIGNUM, cb: *const c_void) -> c_int; - fn BN_is_prime_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, cb: *const c_void) -> c_int; - fn BN_is_prime_fasttest_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, do_trial_division: c_int, cb: *const c_void) -> c_int; - - /* Random number handling */ - fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; - fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; - fn BN_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int; - fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int; - - /* Conversion from/to binary representation */ - fn BN_bn2bin(a: *mut BIGNUM, to: *mut u8) -> c_int; - fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; - - /* Conversion from/to string representation */ - fn BN_bn2dec(a: *mut BIGNUM) -> *const c_char; - fn CRYPTO_free(buf: *const c_char); -} - -pub struct BigNum(*mut BIGNUM); +pub struct BigNum(*mut ffi::BIGNUM); #[repr(C)] pub enum RNGProperty { @@ -93,12 +17,12 @@ pub enum RNGProperty { macro_rules! with_ctx( ($name:ident, $action:block) => ({ - let $name = BN_CTX_new(); + let $name = ffi::BN_CTX_new(); if ($name).is_null() { Err(SslError::get()) } else { let r = $action; - BN_CTX_free($name); + ffi::BN_CTX_free($name); r } }); @@ -125,7 +49,7 @@ macro_rules! with_bn_in_ctx( let tmp = BigNum::new(); match tmp { Ok($name) => { - let $ctx_name = BN_CTX_new(); + let $ctx_name = ffi::BN_CTX_new(); if ($ctx_name).is_null() { Err(SslError::get()) } else { @@ -135,7 +59,7 @@ macro_rules! with_bn_in_ctx( } else { Err(SslError::get()) }; - BN_CTX_free($ctx_name); + ffi::BN_CTX_free($ctx_name); r } }, @@ -147,7 +71,7 @@ macro_rules! with_bn_in_ctx( impl BigNum { pub fn new() -> Result { unsafe { - let v = BN_new(); + let v = ffi::BN_new(); if v.is_null() { Err(SslError::get()) } else { @@ -158,8 +82,8 @@ impl BigNum { pub fn new_from(n: u64) -> Result { unsafe { - let bn = BN_new(); - if bn.is_null() || BN_set_word(bn, n as c_ulong) == 0 { + let bn = ffi::BN_new(); + if bn.is_null() || ffi::BN_set_word(bn, n as c_ulong) == 0 { Err(SslError::get()) } else { Ok(BigNum(bn)) @@ -169,8 +93,8 @@ impl BigNum { pub fn new_from_slice(n: &[u8]) -> Result { unsafe { - let bn = BN_new(); - if bn.is_null() || BN_bin2bn(n.as_ptr(), n.len() as c_int, bn).is_null() { + let bn = ffi::BN_new(); + if bn.is_null() || ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, bn).is_null() { Err(SslError::get()) } else { Ok(BigNum(bn)) @@ -180,61 +104,61 @@ impl BigNum { pub fn checked_sqr(&self) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_sqr(r.raw(), self.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_sqr(r.raw(), self.raw(), ctx) == 1 }) } } pub fn checked_nnmod(&self, n: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_nnmod(r.raw(), self.raw(), n.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_nnmod(r.raw(), self.raw(), n.raw(), ctx) == 1 }) } } pub fn checked_mod_add(&self, a: &BigNum, n: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_mod_add(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_mod_add(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 }) } } pub fn checked_mod_sub(&self, a: &BigNum, n: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_mod_sub(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_mod_sub(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 }) } } pub fn checked_mod_mul(&self, a: &BigNum, n: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_mod_mul(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_mod_mul(r.raw(), self.raw(), a.raw(), n.raw(), ctx) == 1 }) } } pub fn checked_mod_sqr(&self, n: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_mod_sqr(r.raw(), self.raw(), n.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_mod_sqr(r.raw(), self.raw(), n.raw(), ctx) == 1 }) } } pub fn checked_exp(&self, p: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_exp(r.raw(), self.raw(), p.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_exp(r.raw(), self.raw(), p.raw(), ctx) == 1 }) } } pub fn checked_mod_exp(&self, p: &BigNum, n: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_mod_exp(r.raw(), self.raw(), p.raw(), n.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_mod_exp(r.raw(), self.raw(), p.raw(), n.raw(), ctx) == 1 }) } } pub fn checked_mod_inv(&self, n: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { !BN_mod_inverse(r.raw(), self.raw(), n.raw(), ctx).is_null() }) + with_bn_in_ctx!(r, ctx, { !ffi::BN_mod_inverse(r.raw(), self.raw(), n.raw(), ctx).is_null() }) } } pub fn checked_gcd(&self, a: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_gcd(r.raw(), self.raw(), a.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_gcd(r.raw(), self.raw(), a.raw(), ctx) == 1 }) } } @@ -244,7 +168,7 @@ impl BigNum { let add_arg = add.map(|a| a.raw()).unwrap_or(ptr::mut_null()); let rem_arg = rem.map(|r| r.raw()).unwrap_or(ptr::mut_null()); - BN_generate_prime_ex(r.raw(), bits as c_int, safe as c_int, add_arg, rem_arg, ptr::null()) == 1 + ffi::BN_generate_prime_ex(r.raw(), bits as c_int, safe as c_int, add_arg, rem_arg, ptr::null()) == 1 }) } } @@ -252,7 +176,7 @@ impl BigNum { pub fn is_prime(&self, checks: i32) -> Result { unsafe { with_ctx!(ctx, { - Ok(BN_is_prime_ex(self.raw(), checks as c_int, ctx, ptr::null()) == 1) + Ok(ffi::BN_is_prime_ex(self.raw(), checks as c_int, ctx, ptr::null()) == 1) }) } } @@ -260,38 +184,38 @@ impl BigNum { pub fn is_prime_fast(&self, checks: i32, do_trial_division: bool) -> Result { unsafe { with_ctx!(ctx, { - Ok(BN_is_prime_fasttest_ex(self.raw(), checks as c_int, ctx, do_trial_division as c_int, ptr::null()) == 1) + Ok(ffi::BN_is_prime_fasttest_ex(self.raw(), checks as c_int, ctx, do_trial_division as c_int, ptr::null()) == 1) }) } } pub fn checked_new_random(bits: i32, prop: RNGProperty, odd: bool) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1 }) } } pub fn checked_new_pseudo_random(bits: i32, prop: RNGProperty, odd: bool) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_pseudo_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_pseudo_rand(r.raw(), bits as c_int, prop as c_int, odd as c_int) == 1 }) } } pub fn checked_rand_in_range(&self) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_rand_range(r.raw(), self.raw()) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_rand_range(r.raw(), self.raw()) == 1 }) } } pub fn checked_pseudo_rand_in_range(&self) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_pseudo_rand_range(r.raw(), self.raw()) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_pseudo_rand_range(r.raw(), self.raw()) == 1 }) } } pub fn set_bit(&mut self, n: i32) -> Result<(), SslError> { unsafe { - if BN_set_bit(self.raw(), n as c_int) == 1 { + if ffi::BN_set_bit(self.raw(), n as c_int) == 1 { Ok(()) } else { Err(SslError::get()) @@ -301,7 +225,7 @@ impl BigNum { pub fn clear_bit(&mut self, n: i32) -> Result<(), SslError> { unsafe { - if BN_clear_bit(self.raw(), n as c_int) == 1 { + if ffi::BN_clear_bit(self.raw(), n as c_int) == 1 { Ok(()) } else { Err(SslError::get()) @@ -311,13 +235,13 @@ impl BigNum { pub fn is_bit_set(&self, n: i32) -> bool { unsafe { - BN_is_bit_set(self.raw(), n as c_int) == 1 + ffi::BN_is_bit_set(self.raw(), n as c_int) == 1 } } pub fn mask_bits(&mut self, n: i32) -> Result<(), SslError> { unsafe { - if BN_mask_bits(self.raw(), n as c_int) == 1 { + if ffi::BN_mask_bits(self.raw(), n as c_int) == 1 { Ok(()) } else { Err(SslError::get()) @@ -327,67 +251,67 @@ impl BigNum { pub fn checked_shl1(&self) -> Result { unsafe { - with_bn!(r, { BN_lshift1(r.raw(), self.raw()) == 1 }) + with_bn!(r, { ffi::BN_lshift1(r.raw(), self.raw()) == 1 }) } } pub fn checked_shr1(&self) -> Result { unsafe { - with_bn!(r, { BN_rshift1(r.raw(), self.raw()) == 1 }) + with_bn!(r, { ffi::BN_rshift1(r.raw(), self.raw()) == 1 }) } } pub fn checked_add(&self, a: &BigNum) -> Result { unsafe { - with_bn!(r, { BN_add(r.raw(), self.raw(), a.raw()) == 1 }) + with_bn!(r, { ffi::BN_add(r.raw(), self.raw(), a.raw()) == 1 }) } } pub fn checked_sub(&self, a: &BigNum) -> Result { unsafe { - with_bn!(r, { BN_sub(r.raw(), self.raw(), a.raw()) == 1 }) + with_bn!(r, { ffi::BN_sub(r.raw(), self.raw(), a.raw()) == 1 }) } } pub fn checked_mul(&self, a: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_mul(r.raw(), self.raw(), a.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_mul(r.raw(), self.raw(), a.raw(), ctx) == 1 }) } } pub fn checked_div(&self, a: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_div(r.raw(), ptr::mut_null(), self.raw(), a.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_div(r.raw(), ptr::mut_null(), self.raw(), a.raw(), ctx) == 1 }) } } pub fn checked_mod(&self, a: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { BN_div(ptr::mut_null(), r.raw(), self.raw(), a.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_div(ptr::mut_null(), r.raw(), self.raw(), a.raw(), ctx) == 1 }) } } pub fn checked_shl(&self, a: &i32) -> Result { unsafe { - with_bn!(r, { BN_lshift(r.raw(), self.raw(), *a as c_int) == 1 }) + with_bn!(r, { ffi::BN_lshift(r.raw(), self.raw(), *a as c_int) == 1 }) } } pub fn checked_shr(&self, a: &i32) -> Result { unsafe { - with_bn!(r, { BN_rshift(r.raw(), self.raw(), *a as c_int) == 1 }) + with_bn!(r, { ffi::BN_rshift(r.raw(), self.raw(), *a as c_int) == 1 }) } } pub fn negate(&mut self) { unsafe { - BN_set_negative(self.raw(), !self.is_negative() as c_int) + ffi::BN_set_negative(self.raw(), !self.is_negative() as c_int) } } pub fn abs_cmp(&self, oth: BigNum) -> Ordering { unsafe { - let res = BN_ucmp(self.raw(), oth.raw()) as i32; + let res = ffi::BN_ucmp(self.raw(), oth.raw()) as i32; if res < 0 { Less } else if res > 0 { @@ -406,7 +330,7 @@ impl BigNum { pub fn num_bits(&self) -> i32 { unsafe { - BN_num_bits(self.raw()) as i32 + ffi::BN_num_bits(self.raw()) as i32 } } @@ -414,7 +338,7 @@ impl BigNum { (self.num_bits() + 7) / 8 } - unsafe fn raw(&self) -> *mut BIGNUM { + unsafe fn raw(&self) -> *mut ffi::BIGNUM { let BigNum(n) = *self; n } @@ -423,7 +347,7 @@ impl BigNum { let size = self.num_bytes() as uint; let mut v = Vec::with_capacity(size); unsafe { - BN_bn2bin(self.raw(), v.as_mut_ptr()); + ffi::BN_bn2bin(self.raw(), v.as_mut_ptr()); v.set_len(size); } v @@ -431,11 +355,11 @@ impl BigNum { pub fn to_dec_str(&self) -> String { unsafe { - let buf = BN_bn2dec(self.raw()); + let buf = ffi::BN_bn2dec(self.raw()); assert!(!buf.is_null()); let c_str = CString::new(buf, false); let str = c_str.as_str().unwrap().to_string(); - CRYPTO_free(buf); + ffi::CRYPTO_free(buf); str } } @@ -459,7 +383,7 @@ impl Zero for BigNum { } fn is_zero(&self) -> bool { unsafe { - BN_is_zero(self.raw()) == 1 + ffi::BN_is_zero(self.raw()) == 1 } } } @@ -468,7 +392,7 @@ impl Eq for BigNum { } impl PartialEq for BigNum { fn eq(&self, oth: &BigNum) -> bool { unsafe { - BN_cmp(self.raw(), oth.raw()) == 0 + ffi::BN_cmp(self.raw(), oth.raw()) == 0 } } } @@ -482,7 +406,7 @@ impl Ord for BigNum { impl PartialOrd for BigNum { fn partial_cmp(&self, oth: &BigNum) -> Option { unsafe { - let v = BN_cmp(self.raw(), oth.raw()); + let v = ffi::BN_cmp(self.raw(), oth.raw()); let ret = if v == 0 { Equal @@ -500,18 +424,15 @@ impl Drop for BigNum { fn drop(&mut self) { unsafe { if !self.raw().is_null() { - BN_clear_free(self.raw()); + ffi::BN_clear_free(self.raw()); } } } } pub mod unchecked { - use super::{BIGNUM, BigNum}; - - extern { - fn BN_dup(n: *mut BIGNUM) -> *mut BIGNUM; - } + use ffi; + use super::{BigNum}; impl Add for BigNum { fn add(&self, oth: &BigNum) -> BigNum { @@ -558,7 +479,7 @@ pub mod unchecked { impl Clone for BigNum { fn clone(&self) -> BigNum { unsafe { - let r = BN_dup(self.raw()); + let r = ffi::BN_dup(self.raw()); if r.is_null() { fail!("Unexpected null pointer from BN_dup(..)") } else { diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index 4a4031e2..03d0f097 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -1,7 +1,8 @@ -use libc; use libc::c_uint; use std::ptr; +use ffi; + pub enum HashType { MD5, SHA1, @@ -12,71 +13,33 @@ pub enum HashType { RIPEMD160 } -#[allow(dead_code)] -#[allow(non_camel_case_types)] -#[repr(C)] -pub struct EVP_MD_CTX { - digest: *mut EVP_MD, - engine: *mut libc::c_void, - flags: libc::c_ulong, - md_data: *mut libc::c_void, - pctx: *mut EVP_PKEY_CTX, - update: *mut libc::c_void -} - -#[allow(non_camel_case_types)] -#[repr(C)] -pub struct EVP_MD; - -#[allow(non_camel_case_types)] -#[repr(C)] -pub struct EVP_PKEY_CTX; - -#[link(name = "crypto")] -extern { - fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; - fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); - - fn EVP_md5() -> *const EVP_MD; - fn EVP_sha1() -> *const EVP_MD; - fn EVP_sha224() -> *const EVP_MD; - fn EVP_sha256() -> *const EVP_MD; - fn EVP_sha384() -> *const EVP_MD; - fn EVP_sha512() -> *const EVP_MD; - fn EVP_ripemd160() -> *const EVP_MD; - - fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD); - fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const u8, n: c_uint); - fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32); -} - -pub fn evpmd(t: HashType) -> (*const EVP_MD, uint) { +pub fn evpmd(t: HashType) -> (*const ffi::EVP_MD, uint) { unsafe { match t { - MD5 => (EVP_md5(), 16u), - SHA1 => (EVP_sha1(), 20u), - SHA224 => (EVP_sha224(), 28u), - SHA256 => (EVP_sha256(), 32u), - SHA384 => (EVP_sha384(), 48u), - SHA512 => (EVP_sha512(), 64u), - RIPEMD160 => (EVP_ripemd160(), 20u), + MD5 => (ffi::EVP_md5(), 16u), + SHA1 => (ffi::EVP_sha1(), 20u), + SHA224 => (ffi::EVP_sha224(), 28u), + SHA256 => (ffi::EVP_sha256(), 32u), + SHA384 => (ffi::EVP_sha384(), 48u), + SHA512 => (ffi::EVP_sha512(), 64u), + RIPEMD160 => (ffi::EVP_ripemd160(), 20u), } } } #[allow(dead_code)] pub struct Hasher { - evp: *const EVP_MD, - ctx: *mut EVP_MD_CTX, + evp: *const ffi::EVP_MD, + ctx: *mut ffi::EVP_MD_CTX, len: uint, } impl Hasher { pub fn new(ht: HashType) -> Hasher { - let ctx = unsafe { EVP_MD_CTX_create() }; + let ctx = unsafe { ffi::EVP_MD_CTX_create() }; let (evp, mdlen) = evpmd(ht); unsafe { - EVP_DigestInit(ctx, evp); + ffi::EVP_DigestInit(ctx, evp); } Hasher { evp: evp, ctx: ctx, len: mdlen } @@ -85,7 +48,7 @@ impl Hasher { /// Update this hasher with more input bytes pub fn update(&self, data: &[u8]) { unsafe { - EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint) + ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint) } } @@ -96,7 +59,7 @@ impl Hasher { pub fn final(&self) -> Vec { unsafe { let mut res = Vec::from_elem(self.len, 0u8); - EVP_DigestFinal(self.ctx, res.as_mut_ptr(), ptr::null_mut()); + ffi::EVP_DigestFinal(self.ctx, res.as_mut_ptr(), ptr::null_mut()); res } } @@ -105,7 +68,7 @@ impl Hasher { impl Drop for Hasher { fn drop(&mut self) { unsafe { - EVP_MD_CTX_destroy(self.ctx); + ffi::EVP_MD_CTX_destroy(self.ctx); } } } diff --git a/src/crypto/hmac.rs b/src/crypto/hmac.rs index 5bf62586..0d945200 100644 --- a/src/crypto/hmac.rs +++ b/src/crypto/hmac.rs @@ -14,35 +14,13 @@ * limitations under the License. */ -use libc::{c_uchar, c_int, c_uint}; -use crypto::hash; - -#[allow(dead_code)] -#[allow(non_camel_case_types)] -#[repr(C)] -pub struct HMAC_CTX { - md: *mut hash::EVP_MD, - md_ctx: hash::EVP_MD_CTX, - i_ctx: hash::EVP_MD_CTX, - o_ctx: hash::EVP_MD_CTX, - key_length: c_uint, - key: [c_uchar, ..128] -} +use libc::{c_int, c_uint}; -#[link(name = "crypto")] -extern { - fn HMAC_CTX_init(ctx: *mut HMAC_CTX); - fn HMAC_Init_ex(ctx: *mut HMAC_CTX, key: *const u8, keylen: c_int, md: *const hash::EVP_MD, imple: *const ENGINE); - fn HMAC_Update(ctx: *mut HMAC_CTX, input: *const u8, len: c_uint); - fn HMAC_Final(ctx: *mut HMAC_CTX, output: *mut u8, len: *mut c_uint); -} - -#[allow(non_camel_case_types)] -#[repr(C)] -struct ENGINE; +use crypto::hash; +use ffi; pub struct HMAC { - ctx: HMAC_CTX, + ctx: ffi::HMAC_CTX, len: uint, } @@ -51,13 +29,13 @@ pub fn HMAC(ht: hash::HashType, key: &[u8]) -> HMAC { unsafe { let (evp, mdlen) = hash::evpmd(ht); - let mut ctx : HMAC_CTX = ::std::mem::uninitialized(); + let mut ctx : ffi::HMAC_CTX = ::std::mem::uninitialized(); - HMAC_CTX_init(&mut ctx); - HMAC_Init_ex(&mut ctx, - key.as_ptr(), - key.len() as c_int, - evp, 0 as *const _); + ffi::HMAC_CTX_init(&mut ctx); + ffi::HMAC_Init_ex(&mut ctx, + key.as_ptr(), + key.len() as c_int, + evp, 0 as *const _); HMAC { ctx: ctx, len: mdlen } } @@ -66,7 +44,7 @@ pub fn HMAC(ht: hash::HashType, key: &[u8]) -> HMAC { impl HMAC { pub fn update(&mut self, data: &[u8]) { unsafe { - HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint) + ffi::HMAC_Update(&mut self.ctx, data.as_ptr(), data.len() as c_uint) } } @@ -74,7 +52,7 @@ impl HMAC { unsafe { let mut res = Vec::from_elem(self.len, 0u8); let mut outlen = 0; - HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut outlen); + ffi::HMAC_Final(&mut self.ctx, res.as_mut_ptr(), &mut outlen); assert!(self.len == outlen as uint) res } diff --git a/src/crypto/pkcs5.rs b/src/crypto/pkcs5.rs index b795d84a..ec6e0cef 100644 --- a/src/crypto/pkcs5.rs +++ b/src/crypto/pkcs5.rs @@ -1,12 +1,5 @@ use libc::c_int; - -#[link(name = "crypto")] -extern { - fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const u8, passlen: c_int, - salt: *const u8, saltlen: c_int, - iter: c_int, keylen: c_int, - out: *mut u8) -> c_int; -} +use ffi; /// Derives a key from a password and salt using the PBKDF2-HMAC-SHA1 algorithm. pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: uint, keylen: uint) -> Vec { @@ -16,7 +9,7 @@ pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: uint, keylen: uint) -> Ve let mut out = Vec::with_capacity(keylen); - let r = PKCS5_PBKDF2_HMAC_SHA1( + let r = ffi::PKCS5_PBKDF2_HMAC_SHA1( pass.as_ptr(), pass.len() as c_int, salt.as_ptr(), salt.len() as c_int, iter as c_int, keylen as c_int, diff --git a/src/crypto/pkey.rs b/src/crypto/pkey.rs index 5c4b108f..d95e7738 100644 --- a/src/crypto/pkey.rs +++ b/src/crypto/pkey.rs @@ -1,50 +1,11 @@ -use libc::{c_char, c_int, c_uint, c_void}; -use libc; +use libc::{c_int, c_uint}; use std::mem; use std::ptr; -use bio::{mod, MemBio}; +use bio::{MemBio}; use crypto::hash::{HashType, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD160}; -use crypto::symm::{EVP_CIPHER}; +use ffi; use ssl::error::{SslError, StreamError}; -#[allow(non_camel_case_types)] -pub type EVP_PKEY = *mut libc::c_void; - -#[allow(non_camel_case_types)] -pub type RSA = *mut libc::c_void; - -pub type PrivateKeyWriteCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; - -#[link(name = "crypto")] -extern { - fn EVP_PKEY_new() -> *mut EVP_PKEY; - fn EVP_PKEY_free(k: *mut EVP_PKEY); - fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *const c_char) -> c_int; - fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; - fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; - - fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int; - fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; - fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; - fn d2i_RSAPrivateKey(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; - - fn RSA_generate_key(modsz: c_uint, e: c_uint, cb: *const u8, cbarg: *const u8) -> *mut RSA; - fn RSA_size(k: *mut RSA) -> c_uint; - - fn RSA_public_encrypt(flen: c_uint, from: *const u8, to: *mut u8, k: *mut RSA, - pad: c_int) -> c_int; - fn RSA_private_decrypt(flen: c_uint, from: *const u8, to: *mut u8, k: *mut RSA, - pad: c_int) -> c_int; - fn RSA_sign(t: c_int, m: *const u8, mlen: c_uint, sig: *mut u8, siglen: *mut c_uint, - k: *mut RSA) -> c_int; - fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint, - k: *mut RSA) -> c_int; - - fn PEM_write_bio_PrivateKey(bio: *mut bio::ffi::BIO, pkey: *mut EVP_PKEY, cipher: *const EVP_CIPHER, - kstr: *mut c_char, klen: c_int, - callback: *mut c_void, - user_data: *mut c_void) -> c_int; -} enum Parts { Neither, @@ -86,7 +47,7 @@ fn openssl_hash_nid(hash: HashType) -> c_int { } pub struct PKey { - evp: *mut EVP_PKEY, + evp: *mut ffi::EVP_PKEY, parts: Parts, } @@ -95,15 +56,15 @@ impl PKey { pub fn new() -> PKey { unsafe { PKey { - evp: EVP_PKEY_new(), + evp: ffi::EVP_PKEY_new(), parts: Neither, } } } - fn _tostr(&self, f: unsafe extern "C" fn(*mut RSA, *const *mut u8) -> c_int) -> Vec { + fn _tostr(&self, f: unsafe extern "C" fn(*mut ffi::RSA, *const *mut u8) -> c_int) -> Vec { unsafe { - let rsa = EVP_PKEY_get1_RSA(self.evp); + let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); let len = f(rsa, ptr::null()); if len < 0 as c_int { return vec!(); } let mut s = Vec::from_elem(len as uint, 0u8); @@ -115,17 +76,17 @@ impl PKey { } } - fn _fromstr(&mut self, s: &[u8], f: unsafe extern "C" fn(*const *mut RSA, *const *const u8, c_uint) -> *mut RSA) { + fn _fromstr(&mut self, s: &[u8], f: unsafe extern "C" fn(*const *mut ffi::RSA, *const *const u8, c_uint) -> *mut ffi::RSA) { unsafe { let rsa = ptr::null_mut(); f(&rsa, &s.as_ptr(), s.len() as c_uint); - EVP_PKEY_set1_RSA(self.evp, rsa); + ffi::EVP_PKEY_set1_RSA(self.evp, rsa); } } pub fn gen(&mut self, keysz: uint) { unsafe { - let rsa = RSA_generate_key( + let rsa = ffi::RSA_generate_key( keysz as c_uint, 65537u as c_uint, ptr::null(), @@ -133,7 +94,7 @@ impl PKey { ); // XXX: 6 == NID_rsaEncryption - EVP_PKEY_assign( + ffi::EVP_PKEY_assign( self.evp, 6 as c_int, mem::transmute(rsa)); @@ -146,14 +107,14 @@ impl PKey { * Returns a serialized form of the public key, suitable for load_pub(). */ pub fn save_pub(&self) -> Vec { - self._tostr(i2d_RSA_PUBKEY) + self._tostr(ffi::i2d_RSA_PUBKEY) } /** * Loads a serialized form of the public key, as produced by save_pub(). */ pub fn load_pub(&mut self, s: &[u8]) { - self._fromstr(s, d2i_RSA_PUBKEY); + self._fromstr(s, ffi::d2i_RSA_PUBKEY); self.parts = Public; } @@ -162,14 +123,14 @@ impl PKey { * load_priv(). */ pub fn save_priv(&self) -> Vec { - self._tostr(i2d_RSAPrivateKey) + self._tostr(ffi::i2d_RSAPrivateKey) } /** * Loads a serialized form of the public and private keys, as produced by * save_priv(). */ pub fn load_priv(&mut self, s: &[u8]) { - self._fromstr(s, d2i_RSAPrivateKey); + self._fromstr(s, ffi::d2i_RSAPrivateKey); self.parts = Both; } @@ -178,8 +139,8 @@ impl PKey { pub fn write_pem(&self, writer: &mut Writer/*, password: Option*/) -> Result<(), SslError> { let mut mem_bio = try!(MemBio::new()); unsafe { - try_ssl!(PEM_write_bio_PrivateKey(mem_bio.get_handle(), self.evp, ptr::null(), - ptr::null_mut(), -1, ptr::null_mut(), ptr::null_mut())); + 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())); } let buf = try!(mem_bio.read_to_end().map_err(StreamError)); @@ -191,7 +152,7 @@ impl PKey { */ pub fn size(&self) -> uint { unsafe { - RSA_size(EVP_PKEY_get1_RSA(self.evp)) as uint + ffi::RSA_size(ffi::EVP_PKEY_get1_RSA(self.evp)) as uint } } @@ -229,8 +190,8 @@ impl PKey { */ pub fn max_data(&self) -> uint { unsafe { - let rsa = EVP_PKEY_get1_RSA(self.evp); - let len = RSA_size(rsa); + let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); + let len = ffi::RSA_size(rsa); // 41 comes from RSA_public_encrypt(3) for OAEP len as uint - 41u @@ -239,14 +200,14 @@ impl PKey { pub fn encrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec { unsafe { - let rsa = EVP_PKEY_get1_RSA(self.evp); - let len = RSA_size(rsa); + let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); + let len = ffi::RSA_size(rsa); assert!(s.len() < self.max_data()); let mut r = Vec::from_elem(len as uint + 1u, 0u8); - let rv = RSA_public_encrypt( + let rv = ffi::RSA_public_encrypt( s.len() as c_uint, s.as_ptr(), r.as_mut_ptr(), @@ -264,14 +225,14 @@ impl PKey { pub fn decrypt_with_padding(&self, s: &[u8], padding: EncryptionPadding) -> Vec { unsafe { - let rsa = EVP_PKEY_get1_RSA(self.evp); - let len = RSA_size(rsa); + let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); + let len = ffi::RSA_size(rsa); - assert_eq!(s.len() as c_uint, RSA_size(rsa)); + assert_eq!(s.len() as c_uint, ffi::RSA_size(rsa)); let mut r = Vec::from_elem(len as uint + 1u, 0u8); - let rv = RSA_private_decrypt( + let rv = ffi::RSA_private_decrypt( s.len() as c_uint, s.as_ptr(), r.as_mut_ptr(), @@ -312,11 +273,11 @@ impl PKey { pub fn sign_with_hash(&self, s: &[u8], hash: HashType) -> Vec { unsafe { - let rsa = EVP_PKEY_get1_RSA(self.evp); - let mut len = RSA_size(rsa); + let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); + let mut len = ffi::RSA_size(rsa); let mut r = Vec::from_elem(len as uint + 1u, 0u8); - let rv = RSA_sign( + let rv = ffi::RSA_sign( openssl_hash_nid(hash), s.as_ptr(), s.len() as c_uint, @@ -335,9 +296,9 @@ impl PKey { pub fn verify_with_hash(&self, m: &[u8], s: &[u8], hash: HashType) -> bool { unsafe { - let rsa = EVP_PKEY_get1_RSA(self.evp); + let rsa = ffi::EVP_PKEY_get1_RSA(self.evp); - let rv = RSA_verify( + let rv = ffi::RSA_verify( openssl_hash_nid(hash), m.as_ptr(), m.len() as c_uint, @@ -350,7 +311,7 @@ impl PKey { } } - pub unsafe fn get_handle(&self) -> *mut EVP_PKEY { + pub unsafe fn get_handle(&self) -> *mut ffi::EVP_PKEY { return self.evp } } @@ -358,7 +319,7 @@ impl PKey { impl Drop for PKey { fn drop(&mut self) { unsafe { - EVP_PKEY_free(self.evp); + ffi::EVP_PKEY_free(self.evp); } } } diff --git a/src/crypto/rand.rs b/src/crypto/rand.rs index 9db87fcd..dffddee7 100644 --- a/src/crypto/rand.rs +++ b/src/crypto/rand.rs @@ -1,15 +1,11 @@ use libc::c_int; - -#[link(name = "crypto")] -extern { - fn RAND_bytes(buf: *mut u8, num: c_int) -> c_int; -} +use ffi; pub fn rand_bytes(len: uint) -> Vec { unsafe { let mut out = Vec::with_capacity(len); - let r = RAND_bytes(out.as_mut_ptr(), len as c_int); + let r = ffi::RAND_bytes(out.as_mut_ptr(), len as c_int); if r != 1 as c_int { fail!() } out.set_len(len); diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index 6bba7267..a3664bc0 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -1,36 +1,6 @@ -use libc::{c_int, c_uint}; -use libc; +use libc::{c_int}; -#[allow(non_camel_case_types)] -pub type EVP_CIPHER_CTX = *mut libc::c_void; - -#[allow(non_camel_case_types)] -pub type EVP_CIPHER = *mut libc::c_void; - -#[link(name = "crypto")] -extern { - fn EVP_CIPHER_CTX_new() -> EVP_CIPHER_CTX; - fn EVP_CIPHER_CTX_set_padding(ctx: EVP_CIPHER_CTX, padding: c_int); - fn EVP_CIPHER_CTX_free(ctx: EVP_CIPHER_CTX); - - fn EVP_aes_128_ecb() -> EVP_CIPHER; - fn EVP_aes_128_cbc() -> EVP_CIPHER; - // fn EVP_aes_128_ctr() -> EVP_CIPHER; - // fn EVP_aes_128_gcm() -> EVP_CIPHER; - - fn EVP_aes_256_ecb() -> EVP_CIPHER; - fn EVP_aes_256_cbc() -> EVP_CIPHER; - // fn EVP_aes_256_ctr() -> EVP_CIPHER; - // fn EVP_aes_256_gcm() -> EVP_CIPHER; - - fn EVP_rc4() -> EVP_CIPHER; - - fn EVP_CipherInit(ctx: EVP_CIPHER_CTX, evp: EVP_CIPHER, - key: *const u8, iv: *const u8, mode: c_int); - fn EVP_CipherUpdate(ctx: EVP_CIPHER_CTX, outbuf: *mut u8, - outlen: &mut c_uint, inbuf: *const u8, inlen: c_int); - fn EVP_CipherFinal(ctx: EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int); -} +use ffi; pub enum Mode { Encrypt, @@ -52,35 +22,35 @@ pub enum Type { RC4_128, } -fn evpc(t: Type) -> (EVP_CIPHER, uint, uint) { +fn evpc(t: Type) -> (ffi::EVP_CIPHER, uint, uint) { unsafe { match t { - AES_128_ECB => (EVP_aes_128_ecb(), 16u, 16u), - AES_128_CBC => (EVP_aes_128_cbc(), 16u, 16u), + AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16u, 16u), + AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16u, 16u), // AES_128_CTR => (EVP_aes_128_ctr(), 16u, 0u), //AES_128_GCM => (EVP_aes_128_gcm(), 16u, 16u), - AES_256_ECB => (EVP_aes_256_ecb(), 32u, 16u), - AES_256_CBC => (EVP_aes_256_cbc(), 32u, 16u), + AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32u, 16u), + AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32u, 16u), // AES_256_CTR => (EVP_aes_256_ctr(), 32u, 0u), //AES_256_GCM => (EVP_aes_256_gcm(), 32u, 16u), - RC4_128 => (EVP_rc4(), 16u, 0u), + RC4_128 => (ffi::EVP_rc4(), 16u, 0u), } } } /// Represents a symmetric cipher context. pub struct Crypter { - evp: EVP_CIPHER, - ctx: EVP_CIPHER_CTX, + evp: ffi::EVP_CIPHER, + ctx: ffi::EVP_CIPHER_CTX, keylen: uint, blocksize: uint } impl Crypter { pub fn new(t: Type) -> Crypter { - let ctx = unsafe { EVP_CIPHER_CTX_new() }; + let ctx = unsafe { ffi::EVP_CIPHER_CTX_new() }; let (evp, keylen, blocksz) = evpc(t); Crypter { evp: evp, ctx: ctx, keylen: keylen, blocksize: blocksz } } @@ -93,7 +63,7 @@ impl Crypter { if self.blocksize > 0 { unsafe { let v = if padding { 1 as c_int } else { 0 }; - EVP_CIPHER_CTX_set_padding(self.ctx, v); + ffi::EVP_CIPHER_CTX_set_padding(self.ctx, v); } } } @@ -109,7 +79,7 @@ impl Crypter { }; assert_eq!(key.len(), self.keylen); - EVP_CipherInit( + ffi::EVP_CipherInit( self.ctx, self.evp, key.as_ptr(), @@ -128,7 +98,7 @@ impl Crypter { let mut res = Vec::from_elem(data.len() + self.blocksize, 0u8); let mut reslen = (data.len() + self.blocksize) as u32; - EVP_CipherUpdate( + ffi::EVP_CipherUpdate( self.ctx, res.as_mut_ptr(), &mut reslen, @@ -149,7 +119,7 @@ impl Crypter { let mut res = Vec::from_elem(self.blocksize, 0u8); let mut reslen = self.blocksize as c_int; - EVP_CipherFinal(self.ctx, + ffi::EVP_CipherFinal(self.ctx, res.as_mut_ptr(), &mut reslen); @@ -162,7 +132,7 @@ impl Crypter { impl Drop for Crypter { fn drop(&mut self) { unsafe { - EVP_CIPHER_CTX_free(self.ctx); + ffi::EVP_CIPHER_CTX_free(self.ctx); } } } diff --git a/src/ffi.rs b/src/ffi.rs new file mode 100755 index 00000000..020948d1 --- /dev/null +++ b/src/ffi.rs @@ -0,0 +1,418 @@ +#![allow(non_camel_case_types)] +#![allow(dead_code)] +use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar}; + +pub type ASN1_INTEGER = c_void; +pub type ASN1_STRING = c_void; +pub type ASN1_TIME = c_void; +pub type BIO = c_void; +pub type BIO_METHOD = c_void; +pub type BN_CTX = *mut c_void; +pub type COMP_METHOD = c_void; +pub type CRYPTO_EX_DATA = c_void; +pub type ENGINE = c_void; +pub type EVP_CIPHER = *mut c_void; +pub type EVP_CIPHER_CTX = *mut c_void; +pub type EVP_MD = c_void; +pub type EVP_PKEY = *mut c_void; +pub type EVP_PKEY_CTX = c_void; +pub type RSA = *mut c_void; +pub type SSL = c_void; +pub type SSL_CTX = c_void; +pub type SSL_METHOD = c_void; +pub type X509 = c_void; +pub type X509_CRL = c_void; +pub type X509_EXTENSION = c_void; +pub type X509_NAME = c_void; +pub type X509_REQ = c_void; +pub type X509_STORE_CTX = c_void; + +#[allow(dead_code)] +#[repr(C)] +pub struct BIGNUM { + d: *mut c_void, + top: c_int, + dmax: c_int, + pub neg: c_int, + flags: c_int, +} + +#[repr(C)] +pub struct EVP_MD_CTX { + digest: *mut EVP_MD, + engine: *mut c_void, + flags: c_ulong, + md_data: *mut c_void, + pctx: *mut EVP_PKEY_CTX, + update: *mut c_void +} + +#[repr(C)] +pub struct HMAC_CTX { + md: *mut EVP_MD, + md_ctx: EVP_MD_CTX, + i_ctx: EVP_MD_CTX, + o_ctx: EVP_MD_CTX, + key_length: c_uint, + key: [c_uchar, ..128] +} + +#[repr(C)] +pub struct X509V3_CTX { + flags: c_int, + issuer_cert: *mut c_void, + subject_cert: *mut c_void, + subject_req: *mut c_void, + crl: *mut c_void, + db_meth: *mut c_void, + db: *mut c_void, + // I like the last comment line, it is copied from OpenSSL sources: + // Maybe more here +} + +pub type CRYPTO_EX_new = extern "C" fn(parent: *mut c_void, ptr: *mut c_void, + ad: *const CRYPTO_EX_DATA, idx: c_int, + argl: c_long, argp: *const c_void) -> c_int; +pub type CRYPTO_EX_dup = extern "C" fn(to: *mut CRYPTO_EX_DATA, + from: *mut CRYPTO_EX_DATA, from_d: *mut c_void, + idx: c_int, argl: c_long, argp: *mut c_void) + -> c_int; +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, + rwflag: c_int, user_data: *mut c_void) + -> c_int; + + +pub static CRYPTO_LOCK: c_int = 1; + +pub static MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; +pub static MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; +pub static MBSTRING_FLAG: c_int = 0x1000; +pub static MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; +pub static MBSTRING_UTF8: c_int = MBSTRING_FLAG; + +pub static NID_ext_key_usage: c_int = 126; +pub static NID_key_usage: c_int = 83; + +pub static SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; +pub static SSL_ERROR_NONE: c_int = 0; +pub static SSL_ERROR_SSL: c_int = 1; +pub static SSL_ERROR_SYSCALL: c_int = 5; +pub static SSL_ERROR_WANT_ACCEPT: c_int = 8; +pub static SSL_ERROR_WANT_CONNECT: c_int = 7; +pub static SSL_ERROR_WANT_READ: c_int = 2; +pub static SSL_ERROR_WANT_WRITE: c_int = 3; +pub static SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; +pub static SSL_ERROR_ZERO_RETURN: c_int = 6; +pub static SSL_VERIFY_NONE: c_int = 0; +pub static SSL_VERIFY_PEER: c_int = 1; + +pub static TLSEXT_NAMETYPE_host_name: c_long = 0; + +pub static V_ASN1_GENERALIZEDTIME: c_int = 24; +pub static V_ASN1_UTCTIME: c_int = 23; + +pub static X509_FILETYPE_ASN1: c_int = 2; +pub static X509_FILETYPE_DEFAULT: c_int = 3; +pub static X509_FILETYPE_PEM: c_int = 1; +pub static X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; +pub static X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; +pub static X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; +pub static X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; +pub static X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; +pub static X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; +pub static X509_V_ERR_CERT_REJECTED: c_int = 28; +pub static X509_V_ERR_CERT_REVOKED: c_int = 23; +pub static X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; +pub static X509_V_ERR_CERT_UNTRUSTED: c_int = 27; +pub static X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; +pub static X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; +pub static X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; +pub static X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; +pub static X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; +pub static X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; +pub static X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; +pub static X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; +pub static X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; +pub static X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; +pub static X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; +pub static X509_V_ERR_INVALID_CA: c_int = 24; +pub static X509_V_ERR_INVALID_EXTENSION: c_int = 41; +pub static X509_V_ERR_INVALID_NON_CA: c_int = 37; +pub static X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; +pub static X509_V_ERR_INVALID_PURPOSE: c_int = 26; +pub static X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; +pub static X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; +pub static X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; +pub static X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; +pub static X509_V_ERR_OUT_OF_MEM: c_int = 17; +pub static X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; +pub static X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; +pub static X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; +pub static X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; +pub static X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; +pub static X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; +pub static X509_V_ERR_SUBTREE_MINMAX: c_int = 49; +pub static X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; +pub static X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; +pub static X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; +pub static X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; +pub static X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; +pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; +pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; +pub static X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; +pub static X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; +pub static X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; +pub static X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; +pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; +pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; +pub static X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; +pub static X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; +pub static X509_V_OK: c_int = 0; + +#[cfg(target_os = "macos", feature = "tlsv1_1")] +#[cfg(target_os = "macos", feature = "tlsv1_2")] +#[link(name="ssl.1.0.0")] +#[link(name="crypto.1.0.0")] +extern {} + +#[cfg(not(target_os = "macos"))] +#[cfg(target_os = "macos", not(feature = "tlsv1_1"), not(feature = "tlsv1_2"))] +#[link(name="ssl")] +#[link(name="crypto")] +extern {} + +#[cfg(target_os = "win32")] +#[link(name="gdi32")] +#[link(name="wsock32")] +extern { } + +extern "C" { + pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; + pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; + + pub fn BIO_free_all(a: *mut BIO); + pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; + pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; + pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; + pub fn BIO_s_mem() -> *const BIO_METHOD; + + pub fn BN_new() -> *mut BIGNUM; + pub fn BN_dup(n: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_clear_free(bn: *mut BIGNUM); + + pub fn BN_CTX_new() -> *mut BN_CTX; + pub fn BN_CTX_free(ctx: *mut BN_CTX); + + pub fn BN_num_bits(bn: *mut BIGNUM) -> c_int; + pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int); + pub fn BN_set_word(bn: *mut BIGNUM, n: c_ulong) -> c_int; + + /* Arithmetic operations on BIGNUMs */ + pub fn BN_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; + pub fn BN_div(dv: *mut BIGNUM, rem: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_gcd(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_inverse(r: *mut BIGNUM, a: *mut BIGNUM, n: *mut BIGNUM, ctx: *mut BN_CTX) -> *const BIGNUM; + pub fn BN_mod_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_sqr(r: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mod_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_nnmod(rem: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_sqr(r: *mut BIGNUM, a: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; + pub fn BN_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; + + /* Bit operations on BIGNUMs */ + pub fn BN_clear_bit(a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_is_bit_set(a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_lshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_lshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int; + pub fn BN_mask_bits(a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_rshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_set_bit(a: *mut BIGNUM, n: c_int) -> c_int; + pub fn BN_rshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int; + + /* Comparisons on BIGNUMs */ + pub fn BN_cmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; + pub fn BN_ucmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; + pub fn BN_is_zero(a: *mut BIGNUM) -> c_int; + + /* Prime handling */ + pub fn BN_generate_prime_ex(r: *mut BIGNUM, bits: c_int, safe: c_int, add: *mut BIGNUM, rem: *mut BIGNUM, cb: *const c_void) -> c_int; + pub fn BN_is_prime_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, cb: *const c_void) -> c_int; + pub fn BN_is_prime_fasttest_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, do_trial_division: c_int, cb: *const c_void) -> c_int; + + /* Random number handling */ + pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; + pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; + pub fn BN_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int; + pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int; + + /* Conversion from/to binary representation */ + pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; + pub fn BN_bn2bin(a: *mut BIGNUM, to: *mut u8) -> c_int; + + /* Conversion from/to string representation */ + pub fn BN_bn2dec(a: *mut BIGNUM) -> *const c_char; + + pub fn CRYPTO_num_locks() -> c_int; + pub fn CRYPTO_set_locking_callback(func: extern "C" fn(mode: c_int, + n: c_int, + file: *const c_char, + line: c_int)); + pub fn CRYPTO_free(buf: *const c_char); + + pub fn ERR_get_error() -> c_ulong; + + pub fn EVP_md5() -> *const EVP_MD; + pub fn EVP_ripemd160() -> *const EVP_MD; + pub fn EVP_sha1() -> *const EVP_MD; + pub fn EVP_sha224() -> *const EVP_MD; + pub fn EVP_sha256() -> *const EVP_MD; + pub fn EVP_sha384() -> *const EVP_MD; + pub fn EVP_sha512() -> *const EVP_MD; + + pub fn EVP_aes_128_cbc() -> EVP_CIPHER; + pub fn EVP_aes_128_ecb() -> EVP_CIPHER; + // fn EVP_aes_128_ctr() -> EVP_CIPHER; + // fn EVP_aes_128_gcm() -> EVP_CIPHER; + pub fn EVP_aes_256_cbc() -> EVP_CIPHER; + pub fn EVP_aes_256_ecb() -> EVP_CIPHER; + // fn EVP_aes_256_ctr() -> EVP_CIPHER; + // fn EVP_aes_256_gcm() -> EVP_CIPHER; + pub fn EVP_rc4() -> EVP_CIPHER; + + pub fn EVP_CIPHER_CTX_new() -> EVP_CIPHER_CTX; + pub fn EVP_CIPHER_CTX_set_padding(ctx: EVP_CIPHER_CTX, padding: c_int); + pub fn EVP_CIPHER_CTX_free(ctx: EVP_CIPHER_CTX); + + pub fn EVP_CipherInit(ctx: EVP_CIPHER_CTX, evp: EVP_CIPHER, + key: *const u8, iv: *const u8, mode: c_int); + pub fn EVP_CipherUpdate(ctx: EVP_CIPHER_CTX, outbuf: *mut u8, + outlen: &mut c_uint, inbuf: *const u8, inlen: c_int); + pub fn EVP_CipherFinal(ctx: EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int); + + pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD); + pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const u8, n: c_uint); + pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32); + + pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; + pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); + + pub fn EVP_PKEY_new() -> *mut EVP_PKEY; + pub fn EVP_PKEY_free(k: *mut EVP_PKEY); + pub fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *const c_char) -> c_int; + pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; + pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; + + pub fn HMAC_CTX_init(ctx: *mut HMAC_CTX); + pub fn HMAC_Init_ex(ctx: *mut HMAC_CTX, key: *const u8, keylen: c_int, md: *const EVP_MD, imple: *const ENGINE); + 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_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, + user_data: *mut c_void) -> c_int; + pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; + + pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const u8, passlen: c_int, + salt: *const u8, saltlen: c_int, + iter: c_int, keylen: c_int, + out: *mut u8) -> c_int; + + + pub fn RAND_bytes(buf: *mut u8, num: c_int) -> c_int; + + pub fn RSA_generate_key(modsz: c_uint, e: c_uint, cb: *const u8, cbarg: *const u8) -> *mut RSA; + pub fn RSA_private_decrypt(flen: c_uint, from: *const u8, to: *mut u8, k: *mut RSA, + pad: c_int) -> c_int; + pub fn RSA_public_encrypt(flen: c_uint, from: *const u8, to: *mut u8, k: *mut RSA, + pad: c_int) -> c_int; + pub fn RSA_sign(t: c_int, m: *const u8, mlen: c_uint, sig: *mut u8, siglen: *mut c_uint, + k: *mut RSA) -> c_int; + pub fn RSA_size(k: *mut RSA) -> c_uint; + pub fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint, + k: *mut RSA) -> c_int; + + pub fn SSL_library_init() -> c_int; + + #[cfg(feature = "sslv2")] + pub fn SSLv2_method() -> *const SSL_METHOD; + pub fn SSLv3_method() -> *const SSL_METHOD; + pub fn TLSv1_method() -> *const SSL_METHOD; + #[cfg(feature = "tlsv1_1")] + pub fn TLSv1_1_method() -> *const SSL_METHOD; + #[cfg(feature = "tlsv1_2")] + pub fn TLSv1_2_method() -> *const SSL_METHOD; + pub fn SSLv23_method() -> *const SSL_METHOD; + + pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL; + pub fn SSL_free(ssl: *mut SSL); + pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO); + pub fn SSL_get_rbio(ssl: *mut SSL) -> *mut BIO; + pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut BIO; + pub fn SSL_connect(ssl: *mut SSL) -> c_int; + pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, + parg: *mut c_void) -> c_long; + pub fn SSL_get_error(ssl: *mut SSL, ret: c_int) -> c_int; + pub fn SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; + pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; + pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; + pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX; + pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; + + pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; + + pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; + pub fn SSL_CTX_free(ctx: *mut SSL_CTX); + pub fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int, + verify_callback: Option c_int>); + pub fn SSL_CTX_load_verify_locations(ctx: *mut SSL_CTX, CAfile: *const c_char, + CApath: *const c_char) -> c_int; + pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *const c_void, + new_func: Option, + dup_func: Option, + free_func: Option) + -> c_int; + pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) + -> c_int; + pub fn SSL_CTX_get_ex_data(ctx: *mut SSL_CTX, idx: c_int) -> *mut c_void; + + pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int; + pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int; + + + pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; + pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; + pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; + pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME; + pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; + pub fn X509_new() -> *mut X509; + pub fn X509_set_issuer_name(x: *mut X509, name: *mut X509_NAME) -> c_int; + pub fn X509_set_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + pub fn X509_set_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; + pub fn X509_set_version(x: *mut X509, version: c_ulong) -> c_int; + pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; + pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; + + pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); + + pub fn X509_NAME_add_entry_by_txt(x: *mut X509, field: *const c_char, ty: c_int, bytes: *const c_char, len: c_int, loc: c_int, set: c_int) -> c_int; + + pub fn X509_STORE_CTX_get_current_cert(ct: *mut X509_STORE_CTX) -> *mut X509; + pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int; + pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; + + pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION; + pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int); + + pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int; + pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; + pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; + pub fn d2i_RSAPrivateKey(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; +} diff --git a/src/lib.rs b/src/lib.rs index d142f865..9aee977d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,5 +15,6 @@ mod asn1; pub mod bn; pub mod bio; pub mod crypto; +pub mod ffi; pub mod ssl; pub mod x509; diff --git a/src/ssl/error.rs b/src/ssl/error.rs index 9af14dd9..452f8aad 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -1,7 +1,7 @@ use libc::c_ulong; use std::io::IoError; -use ssl::ffi; +use ffi; /// An SSL error #[deriving(Show, Clone, PartialEq, Eq)] diff --git a/src/ssl/ffi.rs b/src/ssl/ffi.rs deleted file mode 100755 index 02392f74..00000000 --- a/src/ssl/ffi.rs +++ /dev/null @@ -1,117 +0,0 @@ -#![allow(non_camel_case_types)] - -use libc::{c_int, c_void, c_long, c_ulong, c_char}; - -use bio; -use x509; - -pub type SSL_CTX = c_void; -pub type SSL_METHOD = c_void; -pub type COMP_METHOD = c_void; -pub type SSL = c_void; -pub type CRYPTO_EX_DATA = c_void; - -pub type CRYPTO_EX_new = extern "C" fn(parent: *mut c_void, ptr: *mut c_void, - ad: *const CRYPTO_EX_DATA, idx: c_int, - argl: c_long, argp: *const c_void) -> c_int; -pub type CRYPTO_EX_dup = extern "C" fn(to: *mut CRYPTO_EX_DATA, - from: *mut CRYPTO_EX_DATA, from_d: *mut c_void, - idx: c_int, argl: c_long, argp: *mut c_void) - -> c_int; -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 static CRYPTO_LOCK: c_int = 1; - -pub static SSL_ERROR_NONE: c_int = 0; -pub static SSL_ERROR_SSL: c_int = 1; -pub static SSL_ERROR_WANT_READ: c_int = 2; -pub static SSL_ERROR_WANT_WRITE: c_int = 3; -pub static SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; -pub static SSL_ERROR_SYSCALL: c_int = 5; -pub static SSL_ERROR_ZERO_RETURN: c_int = 6; -pub static SSL_ERROR_WANT_CONNECT: c_int = 7; -pub static SSL_ERROR_WANT_ACCEPT: c_int = 8; - -pub static SSL_VERIFY_NONE: c_int = 0; -pub static SSL_VERIFY_PEER: c_int = 1; - -pub static SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; - -pub static TLSEXT_NAMETYPE_host_name: c_long = 0; - - -#[cfg(target_os = "macos", feature = "tlsv1_1")] -#[cfg(target_os = "macos", feature = "tlsv1_2")] -#[link(name="ssl.1.0.0")] -#[link(name="crypto.1.0.0")] -extern {} - -#[cfg(not(target_os = "macos"))] -#[cfg(target_os = "macos", not(feature = "tlsv1_1"), not(feature = "tlsv1_2"))] -#[link(name="ssl")] -#[link(name="crypto")] -extern {} - -extern "C" { - pub fn CRYPTO_num_locks() -> c_int; - pub fn CRYPTO_set_locking_callback(func: extern "C" fn(mode: c_int, - n: c_int, - file: *const c_char, - line: c_int)); - - pub fn ERR_get_error() -> c_ulong; - - pub fn SSL_library_init() -> c_int; - - #[cfg(feature = "sslv2")] - pub fn SSLv2_method() -> *const SSL_METHOD; - pub fn SSLv3_method() -> *const SSL_METHOD; - pub fn TLSv1_method() -> *const SSL_METHOD; - #[cfg(feature = "tlsv1_1")] - pub fn TLSv1_1_method() -> *const SSL_METHOD; - #[cfg(feature = "tlsv1_2")] - pub fn TLSv1_2_method() -> *const SSL_METHOD; - pub fn SSLv23_method() -> *const SSL_METHOD; - - pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; - pub fn SSL_CTX_free(ctx: *mut SSL_CTX); - pub fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int, - verify_callback: Option c_int>); - pub fn SSL_CTX_load_verify_locations(ctx: *mut SSL_CTX, CAfile: *const c_char, - CApath: *const c_char) -> c_int; - pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *const c_void, - new_func: Option, - dup_func: Option, - free_func: Option) - -> c_int; - pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) - -> c_int; - pub fn SSL_CTX_get_ex_data(ctx: *mut SSL_CTX, idx: c_int) -> *mut c_void; - - pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int; - pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int; - - pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL; - pub fn SSL_free(ssl: *mut SSL); - pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut bio::ffi::BIO, wbio: *mut bio::ffi::BIO); - pub fn SSL_get_rbio(ssl: *mut SSL) -> *mut bio::ffi::BIO; - pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut bio::ffi::BIO; - pub fn SSL_connect(ssl: *mut SSL) -> c_int; - pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, - parg: *mut c_void) -> c_long; - pub fn SSL_get_error(ssl: *mut SSL, ret: c_int) -> c_int; - pub fn SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; - pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; - pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; - pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX; - pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; - - pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; -} - -#[cfg(target_os = "win32")] -#[link(name="gdi32")] -#[link(name="wsock32")] -extern { } diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index d13972d2..1198aa4a 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -6,12 +6,12 @@ use std::rt::mutex::NativeMutex; use std::string; use sync::one::{Once, ONCE_INIT}; -use bio::{mod, MemBio}; +use bio::{MemBio}; +use ffi; use ssl::error::{SslError, SslSessionClosed, StreamError}; -use x509::{mod, X509StoreContext, X509FileType}; +use x509::{X509StoreContext, X509FileType}; pub mod error; -mod ffi; #[cfg(test)] mod tests; @@ -95,11 +95,11 @@ extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, } } -extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut x509::ffi::X509_STORE_CTX) +extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int { unsafe { let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); - let ssl = x509::ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); + let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX); let verify: Option = mem::transmute(verify); @@ -241,7 +241,7 @@ impl Ssl { unsafe { self.wrap_bio(ffi::SSL_get_wbio(self.ssl)) } } - fn wrap_bio<'a>(&'a self, bio: *mut bio::ffi::BIO) -> MemBioRef<'a> { + fn wrap_bio<'a>(&'a self, bio: *mut ffi::BIO) -> MemBioRef<'a> { assert!(bio != ptr::mut_null()); MemBioRef { ssl: self, diff --git a/src/x509/mod.rs b/src/x509/mod.rs index cc911afe..c46edc3d 100755 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -2,11 +2,11 @@ use libc::{c_int, c_long, c_uint}; use std::mem; use std::ptr; -use asn1; use bio::{MemBio}; use crypto::hash::{HashType, evpmd, SHA1}; use crypto::pkey::{PKey}; use crypto::rand::rand_bytes; +use ffi; use ssl::error::{SslError, StreamError}; @@ -200,7 +200,7 @@ impl X509Generator { let value_len = value.len() as c_int; lift_ssl!(key.with_c_str(|key| { value.with_c_str(|value| unsafe { - ffi::X509_NAME_add_entry_by_txt(name, key, asn1::ffi::MBSTRING_UTF8, + ffi::X509_NAME_add_entry_by_txt(name, key, ffi::MBSTRING_UTF8, value, value_len, -1, 0) }) })) @@ -227,7 +227,7 @@ impl X509Generator { let x509 = ffi::X509_new(); try_ssl_null!(x509); try_ssl!(ffi::X509_set_version(x509, 2)); - try_ssl!(asn1::ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509), X509Generator::random_serial())); + try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509), X509Generator::random_serial())); let not_before = ffi::X509_gmtime_adj(ptr::null_mut(), 0); try_ssl_null!(not_before); @@ -317,129 +317,6 @@ pub struct X509Name<'x> { name: *mut ffi::X509_NAME } - -pub mod ffi { - #![allow(non_camel_case_types)] - use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint}; - - use asn1::ffi::{ASN1_INTEGER, ASN1_TIME}; - use bio::ffi::{BIO}; - use crypto::hash::{EVP_MD}; - use crypto::pkey::{EVP_PKEY}; - - pub type X509_STORE_CTX = c_void; - pub type X509 = c_void; - pub type X509_NAME = c_void; - pub type X509_CRL = c_void; - pub type X509_REQ = c_void; - pub type X509_EXTENSION = c_void; - - #[repr(C)] - pub struct X509V3_CTX { - flags: c_int, - issuer_cert: *mut c_void, - subject_cert: *mut c_void, - subject_req: *mut c_void, - crl: *mut c_void, - db_meth: *mut c_void, - db: *mut c_void, - // I like the last comment line, it is copied from OpenSSL sources: - // Maybe more here - } - - pub static X509_V_OK: c_int = 0; - pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; - pub static X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; - pub static X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; - pub static X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; - pub static X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; - pub static X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; - pub static X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; - pub static X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; - pub static X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; - pub static X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; - pub static X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; - pub static X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; - pub static X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; - pub static X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; - pub static X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; - pub static X509_V_ERR_OUT_OF_MEM: c_int = 17; - pub static X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; - pub static X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; - pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; - pub static X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; - pub static X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; - pub static X509_V_ERR_CERT_REVOKED: c_int = 23; - pub static X509_V_ERR_INVALID_CA: c_int = 24; - pub static X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; - pub static X509_V_ERR_INVALID_PURPOSE: c_int = 26; - pub static X509_V_ERR_CERT_UNTRUSTED: c_int = 27; - pub static X509_V_ERR_CERT_REJECTED: c_int = 28; - pub static X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; - pub static X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; - pub static X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; - pub static X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; - pub static X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; - pub static X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; - pub static X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; - pub static X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; - pub static X509_V_ERR_INVALID_NON_CA: c_int = 37; - pub static X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; - pub static X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; - pub static X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; - pub static X509_V_ERR_INVALID_EXTENSION: c_int = 41; - pub static X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; - pub static X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; - pub static X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; - pub static X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; - pub static X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; - pub static X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; - pub static X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; - pub static X509_V_ERR_SUBTREE_MINMAX: c_int = 49; - pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; - pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; - pub static X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; - pub static X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; - pub static X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; - - pub static X509_FILETYPE_PEM: c_int = 1; - pub static X509_FILETYPE_ASN1: c_int = 2; - pub static X509_FILETYPE_DEFAULT: c_int = 3; - - pub static NID_key_usage: c_int = 83; - pub static NID_ext_key_usage: c_int = 126; - - - - extern "C" { - pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; - pub fn X509_STORE_CTX_get_current_cert(ct: *mut X509_STORE_CTX) -> *mut X509; - pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int; - - pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; - pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; - pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; - pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME; - pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; - pub fn X509_new() -> *mut X509; - pub fn X509_set_issuer_name(x: *mut X509, name: *mut X509_NAME) -> c_int; - pub fn X509_set_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; - pub fn X509_set_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; - pub fn X509_set_version(x: *mut X509, version: c_ulong) -> c_int; - pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; - pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; - - pub fn X509_NAME_add_entry_by_txt(x: *mut X509, field: *const c_char, ty: c_int, bytes: *const c_char, len: c_int, loc: c_int, set: c_int) -> c_int; - - pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION; - pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int); - - pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); - - pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; - } -} - macro_rules! make_validation_error( ($ok_val:ident, $($name:ident = $val:ident,)+) => ( pub enum X509ValidationError { @@ -451,8 +328,8 @@ macro_rules! make_validation_error( #[doc(hidden)] pub fn from_raw(err: c_int) -> Option { match err { - self::ffi::$ok_val => None, - $(self::ffi::$val => Some($name),)+ + ffi::$ok_val => None, + $(ffi::$val => Some($name),)+ err => Some(X509UnknownError(err)) } } -- cgit v1.2.3 From dec5f967c6683a47ae495fd309db15883511ef88 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 30 Sep 2014 09:37:32 +0300 Subject: Fixed mut_null deprecation warnings --- src/bn/mod.rs | 8 ++++---- src/ssl/mod.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/bn/mod.rs b/src/bn/mod.rs index 29ffd413..fb836a39 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -165,8 +165,8 @@ impl BigNum { pub fn checked_generate_prime(bits: i32, safe: bool, add: Option<&BigNum>, rem: Option<&BigNum>) -> Result { unsafe { with_bn_in_ctx!(r, ctx, { - let add_arg = add.map(|a| a.raw()).unwrap_or(ptr::mut_null()); - let rem_arg = rem.map(|r| r.raw()).unwrap_or(ptr::mut_null()); + let add_arg = add.map(|a| a.raw()).unwrap_or(ptr::null_mut()); + let rem_arg = rem.map(|r| r.raw()).unwrap_or(ptr::null_mut()); ffi::BN_generate_prime_ex(r.raw(), bits as c_int, safe as c_int, add_arg, rem_arg, ptr::null()) == 1 }) @@ -281,13 +281,13 @@ impl BigNum { pub fn checked_div(&self, a: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { ffi::BN_div(r.raw(), ptr::mut_null(), self.raw(), a.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_div(r.raw(), ptr::null_mut(), self.raw(), a.raw(), ctx) == 1 }) } } pub fn checked_mod(&self, a: &BigNum) -> Result { unsafe { - with_bn_in_ctx!(r, ctx, { ffi::BN_div(ptr::mut_null(), r.raw(), self.raw(), a.raw(), ctx) == 1 }) + with_bn_in_ctx!(r, ctx, { ffi::BN_div(ptr::null_mut(), r.raw(), self.raw(), a.raw(), ctx) == 1 }) } } diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 1198aa4a..f034ed37 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -242,7 +242,7 @@ impl Ssl { } fn wrap_bio<'a>(&'a self, bio: *mut ffi::BIO) -> MemBioRef<'a> { - assert!(bio != ptr::mut_null()); + assert!(bio != ptr::null_mut()); MemBioRef { ssl: self, bio: MemBio::borrowed(bio) -- cgit v1.2.3 From a154ceeed22777b62b006e6cd11463a35e76abca Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 30 Sep 2014 09:39:21 +0300 Subject: Unification and explicity in FFI type decls --- src/crypto/symm.rs | 6 +++--- src/ffi.rs | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) mode change 100755 => 100644 src/ffi.rs (limited to 'src') diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index a3664bc0..a92f7753 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -22,7 +22,7 @@ pub enum Type { RC4_128, } -fn evpc(t: Type) -> (ffi::EVP_CIPHER, uint, uint) { +fn evpc(t: Type) -> (*const ffi::EVP_CIPHER, uint, uint) { unsafe { match t { AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16u, 16u), @@ -42,8 +42,8 @@ fn evpc(t: Type) -> (ffi::EVP_CIPHER, uint, uint) { /// Represents a symmetric cipher context. pub struct Crypter { - evp: ffi::EVP_CIPHER, - ctx: ffi::EVP_CIPHER_CTX, + evp: *const ffi::EVP_CIPHER, + ctx: *mut ffi::EVP_CIPHER_CTX, keylen: uint, blocksize: uint } diff --git a/src/ffi.rs b/src/ffi.rs old mode 100755 new mode 100644 index 020948d1..5a8f753a --- a/src/ffi.rs +++ b/src/ffi.rs @@ -7,16 +7,16 @@ pub type ASN1_STRING = c_void; pub type ASN1_TIME = c_void; pub type BIO = c_void; pub type BIO_METHOD = c_void; -pub type BN_CTX = *mut c_void; +pub type BN_CTX = c_void; pub type COMP_METHOD = c_void; pub type CRYPTO_EX_DATA = c_void; pub type ENGINE = c_void; -pub type EVP_CIPHER = *mut c_void; -pub type EVP_CIPHER_CTX = *mut c_void; +pub type EVP_CIPHER = c_void; +pub type EVP_CIPHER_CTX = c_void; pub type EVP_MD = c_void; -pub type EVP_PKEY = *mut c_void; +pub type EVP_PKEY = c_void; pub type EVP_PKEY_CTX = c_void; -pub type RSA = *mut c_void; +pub type RSA = c_void; pub type SSL = c_void; pub type SSL_CTX = c_void; pub type SSL_METHOD = c_void; @@ -276,25 +276,25 @@ extern "C" { pub fn EVP_sha384() -> *const EVP_MD; pub fn EVP_sha512() -> *const EVP_MD; - pub fn EVP_aes_128_cbc() -> EVP_CIPHER; - pub fn EVP_aes_128_ecb() -> EVP_CIPHER; + pub fn EVP_aes_128_cbc() -> *const EVP_CIPHER; + pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER; // fn EVP_aes_128_ctr() -> EVP_CIPHER; // fn EVP_aes_128_gcm() -> EVP_CIPHER; - pub fn EVP_aes_256_cbc() -> EVP_CIPHER; - pub fn EVP_aes_256_ecb() -> EVP_CIPHER; + pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER; + pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER; // fn EVP_aes_256_ctr() -> EVP_CIPHER; // fn EVP_aes_256_gcm() -> EVP_CIPHER; - pub fn EVP_rc4() -> EVP_CIPHER; + pub fn EVP_rc4() -> *const EVP_CIPHER; - pub fn EVP_CIPHER_CTX_new() -> EVP_CIPHER_CTX; - pub fn EVP_CIPHER_CTX_set_padding(ctx: EVP_CIPHER_CTX, padding: c_int); - pub fn EVP_CIPHER_CTX_free(ctx: EVP_CIPHER_CTX); + pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; + pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int); + pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX); - pub fn EVP_CipherInit(ctx: EVP_CIPHER_CTX, evp: EVP_CIPHER, + pub fn EVP_CipherInit(ctx: *mut EVP_CIPHER_CTX, evp: *const EVP_CIPHER, key: *const u8, iv: *const u8, mode: c_int); - pub fn EVP_CipherUpdate(ctx: EVP_CIPHER_CTX, outbuf: *mut u8, + pub fn EVP_CipherUpdate(ctx: *mut EVP_CIPHER_CTX, outbuf: *mut u8, outlen: &mut c_uint, inbuf: *const u8, inlen: c_int); - pub fn EVP_CipherFinal(ctx: EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int); + pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int); pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD); pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const u8, n: c_uint); -- cgit v1.2.3 From be0e83c9788cfea1ef0a422a9b56d11ffdc48da0 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 1 Oct 2014 13:05:42 -0700 Subject: Add bindings to CRYPTO_memcmp This should help other projects use a constant-time memory comparison. --- src/crypto/memcmp.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/crypto/mod.rs | 1 + src/ffi.rs | 4 +++- 3 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 src/crypto/memcmp.rs (limited to 'src') diff --git a/src/crypto/memcmp.rs b/src/crypto/memcmp.rs new file mode 100644 index 00000000..c30281d4 --- /dev/null +++ b/src/crypto/memcmp.rs @@ -0,0 +1,39 @@ +use libc::size_t; +use ffi; + +/// Returns `true` iff `a` and `b` contain the same bytes. +/// +/// This operation takes an amount of time dependent on the length of the two +/// arrays given, but is independent of the contents of a and b. +/// +/// # Failure +/// +/// This function will fail the current task if `a` and `b` do not have the same +/// length. +pub fn eq(a: &[u8], b: &[u8]) -> bool { + assert!(a.len() == b.len()); + let ret = unsafe { + ffi::CRYPTO_memcmp(a.as_ptr() as *const _, + b.as_ptr() as *const _, + a.len() as size_t) + }; + ret == 0 +} + +#[cfg(test)] +mod tests { + use super::eq; + + #[test] + fn test_eq() { + assert!(eq([], [])); + assert!(eq([1], [1])); + assert!(!eq([1, 2, 3], [1, 2, 4])); + } + + #[test] + #[should_fail] + fn test_diff_lens() { + eq([], [1]); + } +} diff --git a/src/crypto/mod.rs b/src/crypto/mod.rs index d7c62f98..e695de33 100644 --- a/src/crypto/mod.rs +++ b/src/crypto/mod.rs @@ -21,3 +21,4 @@ pub mod pkcs5; pub mod pkey; pub mod rand; pub mod symm; +pub mod memcmp; diff --git a/src/ffi.rs b/src/ffi.rs index 5a8f753a..b31dc1bb 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,6 +1,6 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] -use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar}; +use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; pub type ASN1_INTEGER = c_void; pub type ASN1_STRING = c_void; @@ -265,6 +265,8 @@ extern "C" { file: *const c_char, line: c_int)); pub fn CRYPTO_free(buf: *const c_char); + pub fn CRYPTO_memcmp(a: *const c_void, b: *const c_void, + len: size_t) -> c_int; pub fn ERR_get_error() -> c_ulong; -- cgit v1.2.3 From fbb359720b24266938284edcd5cec46744379f1c Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 30 Sep 2014 11:06:37 +0300 Subject: User-provided data in verify --- src/ffi.rs | 1 + src/ssl/mod.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/ssl/tests.rs | 49 +++++++++++++++++++++++++++++++-- src/x509/mod.rs | 1 + 4 files changed, 131 insertions(+), 3 deletions(-) mode change 100755 => 100644 src/x509/mod.rs (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 5a8f753a..5f09fa85 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -372,6 +372,7 @@ extern "C" { pub fn SSL_CTX_free(ctx: *mut SSL_CTX); pub fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int, verify_callback: Option c_int>); + pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int); pub fn SSL_CTX_load_verify_locations(ctx: *mut SSL_CTX, CAfile: *const c_char, CApath: *const c_char) -> c_int; pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *const c_void, diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index f034ed37..e1f35724 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_void, c_char}; +use libc::{c_int, c_void, c_char, c_long}; use std::io::{IoResult, IoError, EndOfFile, Stream, Reader, Writer}; use std::mem; use std::ptr; @@ -82,6 +82,30 @@ pub enum SslVerifyMode { SslVerifyNone = ffi::SSL_VERIFY_NONE } +// Creates a static index for user data of type T +// Registers a destructor for the data which will be called +// when context is freed +fn get_verify_data_idx() -> c_int { + static mut VERIFY_DATA_IDX: c_int = -1; + static mut INIT: Once = ONCE_INIT; + + extern fn free_data_box(_parent: *mut c_void, ptr: *mut c_void, + _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int, + _argl: c_long, _argp: *mut c_void) { + let _: Box = unsafe { mem::transmute(ptr) }; + } + + unsafe { + INIT.doit(|| { + let idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, + None, Some(free_data_box::)); + assert!(idx >= 0); + VERIFY_DATA_IDX = idx; + }); + VERIFY_DATA_IDX + } +} + extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, _line: c_int) { unsafe { @@ -113,10 +137,45 @@ extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) } } +extern fn raw_verify_with_data(preverify_ok: c_int, + x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int { + unsafe { + let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx(); + let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx); + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); + + let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, VERIFY_IDX); + let verify: Option> = mem::transmute(verify); + + let data = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::()); + let data: Box = mem::transmute(data); + + let ctx = X509StoreContext::new(x509_ctx); + + let res = match verify { + None => preverify_ok, + Some(verify) => verify(preverify_ok != 0, &ctx, &*data) as c_int + }; + + // Since data might be required on the next verification + // it is time to forget about it and avoid dropping + // data will be freed once OpenSSL considers it is time + // to free all context data + mem::forget(data); + res + } +} + /// The signature of functions that can be used to manually verify certificates pub type VerifyCallback = fn(preverify_ok: bool, x509_ctx: &X509StoreContext) -> bool; +/// The signature of functions that can be used to manually verify certificates +/// when user-data should be carried for all verification process +pub type VerifyCallbackData = fn(preverify_ok: bool, + x509_ctx: &X509StoreContext, + data: &T) -> bool; + // FIXME: macro may be instead of inlining? #[inline] fn wrap_ssl_result(res: c_int) -> Option { @@ -161,6 +220,28 @@ impl SslContext { } } + /// Configures the certificate verification method for new connections also + /// carrying supplied data. + pub fn set_verify_with_data(&mut self, mode: SslVerifyMode, + verify: Option>, + data: T) { + let data = box data; + unsafe { + ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX, + mem::transmute(verify)); + ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::(), + mem::transmute(data)); + ffi::SSL_CTX_set_verify(self.ctx, mode as c_int, Some(raw_verify_with_data::)); + } + } + + /// Sets verification depth + pub fn set_verify_depth(&mut self, depth: uint) { + unsafe { + ffi::SSL_CTX_set_verify_depth(self.ctx, depth as c_int); + } + } + #[allow(non_snake_case)] /// Specifies the file that contains trusted CA certificates. pub fn set_CA_file(&mut self, file: &str) -> Option { diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 82effee0..9dd90ae7 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -1,10 +1,11 @@ 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}; -use x509::{X509Generator, X509, DigitalSignature, KeyEncipherment, ClientAuth, ServerAuth, X509StoreContext}; +use ssl::{Sslv23, SslContext, SslStream, SslVerifyPeer, SslVerifyNone}; +use x509::{X509Generator, DigitalSignature, KeyEncipherment, ClientAuth, ServerAuth, X509StoreContext}; #[test] fn test_new_ctx() { @@ -141,6 +142,50 @@ fn test_verify_trusted_get_error_err() { assert!(SslStream::new(&ctx, stream).is_err()); } +fn hash_str_to_vec(s: &str) -> Vec { + 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 = 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) -> bool { + let cert = x509_ctx.get_current_cert(); + match cert { + None => false, + Some(cert) => { + let fingerprint = cert.fingerprint(SHA256).unwrap(); + fingerprint.as_slice() == node_id.as_slice() + } + } + } + let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let mut ctx = SslContext::new(Sslv23).unwrap(); + + // Node id 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 node_hash_str = "6204f6617e1af7495394250655f43600cd483e2dfc2005e92d0fe439d0723c34"; + let node_id = hash_str_to_vec(node_hash_str); + ctx.set_verify_with_data(SslVerifyNone, Some(callback), node_id); + ctx.set_verify_depth(1); + + match SslStream::new(&ctx, stream) { + Ok(_) => (), + Err(err) => fail!("Expected success, got {}", err) + } +} + + #[test] fn test_write() { let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); diff --git a/src/x509/mod.rs b/src/x509/mod.rs old mode 100755 new mode 100644 index c46edc3d..8c20ac8f --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -16,6 +16,7 @@ pub enum X509FileType { ASN1 = ffi::X509_FILETYPE_ASN1, Default = ffi::X509_FILETYPE_DEFAULT } + pub struct X509StoreContext { ctx: *mut ffi::X509_STORE_CTX } -- cgit v1.2.3 From 4d3f9e0520ed25bb55a95f30fd07a2cb4cf74fa5 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Sat, 4 Oct 2014 06:37:48 +0300 Subject: Simpler setter for verify with data There is no need in wrapping function in option as there is no sense in providing data without function. --- src/ssl/mod.rs | 6 ++++-- src/ssl/tests.rs | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index e1f35724..ab467f7e 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -222,13 +222,15 @@ impl SslContext { /// Configures the certificate verification method for new connections also /// carrying supplied data. + // Note: no option because there is no point to set data without providing + // a function handling it pub fn set_verify_with_data(&mut self, mode: SslVerifyMode, - verify: Option>, + verify: VerifyCallbackData, data: T) { let data = box data; unsafe { ffi::SSL_CTX_set_ex_data(self.ctx, VERIFY_IDX, - mem::transmute(verify)); + mem::transmute(Some(verify))); ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::(), mem::transmute(data)); ffi::SSL_CTX_set_verify(self.ctx, mode as c_int, Some(raw_verify_with_data::)); diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 9dd90ae7..0e6edbf7 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -176,7 +176,7 @@ fn test_verify_callback_data() { // 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, Some(callback), node_id); + ctx.set_verify_with_data(SslVerifyNone, callback, node_id); ctx.set_verify_depth(1); match SslStream::new(&ctx, stream) { -- cgit v1.2.3 From c22b3c5063da942954b0b71b03317bf2da058c7e Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Sat, 4 Oct 2014 18:18:02 -0700 Subject: Add a dummy bn_is_zero C dependency to wrap BN_is_zero This is necessary because on some architectures BN_is_zero is a CPP macro, so trying to link against it in an `extern "C"` block causes a linker error. This also introduces a build command to Cargo to compile the bn_is_zero wrapper. --- src/ffi.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index b31dc1bb..afa11a4e 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -84,7 +84,6 @@ pub type PrivateKeyWriteCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; - pub static CRYPTO_LOCK: c_int = 1; pub static MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; @@ -189,6 +188,9 @@ extern {} #[link(name="wsock32")] extern { } +/* Since the openssl BN_is_zero is sometimes a macro, this wrapper is necessary. */ +pub unsafe fn BN_is_zero(a: *mut BIGNUM) -> c_int { bn_is_zero(a) } + extern "C" { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; @@ -239,7 +241,9 @@ extern "C" { /* Comparisons on BIGNUMs */ pub fn BN_cmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; pub fn BN_ucmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - pub fn BN_is_zero(a: *mut BIGNUM) -> c_int; + + /* Special import from native/bn_is_zero.c */ + pub fn bn_is_zero(a: *mut BIGNUM) -> c_int; /* Prime handling */ pub fn BN_generate_prime_ex(r: *mut BIGNUM, bits: c_int, safe: c_int, add: *mut BIGNUM, rem: *mut BIGNUM, cb: *const c_void) -> c_int; @@ -418,3 +422,4 @@ extern "C" { pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; pub fn d2i_RSAPrivateKey(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; } + -- cgit v1.2.3 From 09ecc7e521bd3003a4449fb8e234c3525ec81dee Mon Sep 17 00:00:00 2001 From: "D.K" Date: Thu, 2 Oct 2014 14:42:28 -0400 Subject: Changes made to support 0.12.0-dev ( October 2, 2014 ) --- src/ffi.rs | 6 ++---- src/ssl/mod.rs | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 7bfaf25d..63a13335 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -171,14 +171,12 @@ pub static X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; pub static X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; pub static X509_V_OK: c_int = 0; -#[cfg(target_os = "macos", feature = "tlsv1_1")] -#[cfg(target_os = "macos", feature = "tlsv1_2")] +#[cfg( any( all(target_os = "macos", feature = "tlsv1_1"),all(target_os = "macos", feature = "tlsv1_2")))] #[link(name="ssl.1.0.0")] #[link(name="crypto.1.0.0")] extern {} -#[cfg(not(target_os = "macos"))] -#[cfg(target_os = "macos", not(feature = "tlsv1_1"), not(feature = "tlsv1_2"))] +#[cfg(any( not( target_os = "macos"), all(target_os = "macos", not(feature = "tlsv1_1"), not(feature = "tlsv1_2"))))] #[link(name="ssl")] #[link(name="crypto")] extern {} diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index ab467f7e..379a98cf 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -494,7 +494,7 @@ impl Writer for SslStream { let mut start = 0; while start < buf.len() { let ret = self.in_retry_wrapper(|ssl| { - ssl.write(buf.slice_from(start)) + ssl.write(buf.split_at(start).val1()) }); match ret { Ok(len) => start += len as uint, -- cgit v1.2.3 From b8fd300f8017b6afd6ccd8934c12647f10355da9 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 4 Oct 2014 19:44:06 -0700 Subject: Clean up warnings --- src/ffi.rs | 2 +- src/x509/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 63a13335..2118391b 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,4 +1,4 @@ -#![allow(non_camel_case_types)] +#![allow(non_camel_case_types, non_uppercase_statics, non_snake_case)] #![allow(dead_code)] use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 8c20ac8f..63be93ae 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -122,7 +122,7 @@ trait ToStr { impl<'a, T: AsStr<'a>> ToStr for Vec { fn to_str(&self) -> String { self.iter().enumerate().fold(String::new(), |mut acc, (idx, v)| { - if idx > 0 { acc.push_char(',') }; + if idx > 0 { acc.push(',') }; acc.push_str(v.as_str()); acc }) -- cgit v1.2.3 From b3c80a76ddbd871c9ef64762d4e532c3a55b903f Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Tue, 30 Sep 2014 14:34:34 -0700 Subject: Make errors human readable Change error messages from numeric codes to human readable strings. This makes debugging failures much easier. --- src/ffi.rs | 6 ++++++ src/ssl/error.rs | 19 ++++++++++--------- src/ssl/mod.rs | 1 + 3 files changed, 17 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 2118391b..42d33c87 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -272,6 +272,10 @@ extern "C" { pub fn ERR_get_error() -> c_ulong; + pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; + pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; + pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char; + pub fn EVP_md5() -> *const EVP_MD; pub fn EVP_ripemd160() -> *const EVP_MD; pub fn EVP_sha1() -> *const EVP_MD; @@ -345,6 +349,8 @@ extern "C" { pub fn SSL_library_init() -> c_int; + pub fn SSL_load_error_strings(); + #[cfg(feature = "sslv2")] pub fn SSLv2_method() -> *const SSL_METHOD; pub fn SSLv3_method() -> *const SSL_METHOD; diff --git a/src/ssl/error.rs b/src/ssl/error.rs index 452f8aad..b7688595 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -1,5 +1,6 @@ use libc::c_ulong; use std::io::IoError; +use std::c_str::CString; use ffi; @@ -20,24 +21,24 @@ pub enum OpensslError { /// An unknown error UnknownError { /// The library reporting the error - library: u8, + library: CString, /// The function reporting the error - function: u16, + function: CString, /// The reason for the error - reason: u16 + reason: CString } } -fn get_lib(err: c_ulong) -> u8 { - ((err >> 24) & 0xff) as u8 +fn get_lib(err: c_ulong) -> CString { + unsafe { CString::new(ffi::ERR_lib_error_string(err), false) } } -fn get_func(err: c_ulong) -> u16 { - ((err >> 12) & 0xfff) as u16 +fn get_func(err: c_ulong) -> CString { + unsafe { CString::new(ffi::ERR_func_error_string(err), false) } } -fn get_reason(err: c_ulong) -> u16 { - (err & 0xfff) as u16 +fn get_reason(err: c_ulong) -> CString { + unsafe { CString::new(ffi::ERR_reason_error_string(err), false) } } impl SslError { diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 379a98cf..b5027e8f 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -24,6 +24,7 @@ fn init() { unsafe { INIT.doit(|| { ffi::SSL_library_init(); + ffi::SSL_load_error_strings(); // maybe add err_load_crypto_strings? let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None); assert!(verify_idx >= 0); -- cgit v1.2.3 From 02c124a1fecee45f06e08314554502fce7a8190a Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 2 Oct 2014 02:05:49 -0700 Subject: Address CR comments and add a test --- src/ssl/error.rs | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/ssl/error.rs b/src/ssl/error.rs index b7688595..a1e8eadc 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -21,24 +21,36 @@ pub enum OpensslError { /// An unknown error UnknownError { /// The library reporting the error - library: CString, + library: String, /// The function reporting the error - function: CString, + function: String, /// The reason for the error - reason: CString + reason: String } } -fn get_lib(err: c_ulong) -> CString { - unsafe { CString::new(ffi::ERR_lib_error_string(err), false) } +fn get_lib(err: c_ulong) -> String { + unsafe { CString::new(ffi::ERR_lib_error_string(err), false) }.to_string() } -fn get_func(err: c_ulong) -> CString { - unsafe { CString::new(ffi::ERR_func_error_string(err), false) } +fn get_func(err: c_ulong) -> String { + unsafe { CString::new(ffi::ERR_func_error_string(err), false).to_string() } } -fn get_reason(err: c_ulong) -> CString { - unsafe { CString::new(ffi::ERR_reason_error_string(err), false) } +fn get_reason(err: c_ulong) -> String { + unsafe { CString::new(ffi::ERR_reason_error_string(err), false).to_string() } +} + +#[test] +fn test_uknown_error_should_have_correct_messages() { + let err = 336032784; + let library = get_lib(err); + let function = get_func(err); + let reason = get_reason(err); + + assert_eq!(library.as_slice(),"20"); + assert_eq!(function.as_slice(), "119"); + assert_eq!(reason.as_slice(), "1040"); } impl SslError { -- cgit v1.2.3 From 5713c42df72da232b21dd5c55b91a527227174bb Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Thu, 2 Oct 2014 02:11:35 -0700 Subject: Fix error messages --- src/ssl/error.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ssl/error.rs b/src/ssl/error.rs index a1e8eadc..0c1af90a 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -48,9 +48,9 @@ fn test_uknown_error_should_have_correct_messages() { let function = get_func(err); let reason = get_reason(err); - assert_eq!(library.as_slice(),"20"); - assert_eq!(function.as_slice(), "119"); - assert_eq!(reason.as_slice(), "1040"); + assert_eq!(library.as_slice(),"SSL routines"); + assert_eq!(function.as_slice(), "SSL23_GET_SERVER_HELLO"); + assert_eq!(reason.as_slice(), "sslv3 alert handshake failure"); } impl SslError { -- cgit v1.2.3 From a8cadc46ac9f125e74b729fdbd1cb75897cab575 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sun, 5 Oct 2014 02:50:33 -0700 Subject: Load crypto error strings --- src/ffi.rs | 3 ++- src/ssl/mod.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 42d33c87..9ceb7f31 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -276,6 +276,8 @@ extern "C" { pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char; + pub fn ERR_load_crypto_strings(); + pub fn EVP_md5() -> *const EVP_MD; pub fn EVP_ripemd160() -> *const EVP_MD; pub fn EVP_sha1() -> *const EVP_MD; @@ -427,4 +429,3 @@ extern "C" { pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; pub fn d2i_RSAPrivateKey(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; } - diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index b5027e8f..c7c024ed 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -24,7 +24,8 @@ fn init() { unsafe { INIT.doit(|| { ffi::SSL_library_init(); - ffi::SSL_load_error_strings(); // maybe add err_load_crypto_strings? + ffi::SSL_load_error_strings(); + ffi::ERR_load_crypto_strings(); let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None); assert!(verify_idx >= 0); -- cgit v1.2.3 From 6231a39a4187ac2728038d35216aed60b9d93075 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 5 Oct 2014 13:47:20 -0700 Subject: Ignore error string text cc #65 --- src/ssl/error.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/ssl/error.rs b/src/ssl/error.rs index 0c1af90a..56105253 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -42,6 +42,7 @@ fn get_reason(err: c_ulong) -> String { } #[test] +#[ignore] // FIXME #65 fn test_uknown_error_should_have_correct_messages() { let err = 336032784; let library = get_lib(err); -- cgit v1.2.3 From 72ee42adba18adbb0e6eefd13faab5e6d610fdcd Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Wed, 1 Oct 2014 20:19:29 +0300 Subject: Better error handling in cert generation Now it should correctly free all resources in case of failure. --- src/asn1/mod.rs | 47 ++++++++++++++++++++++++++++++++++++ src/ffi.rs | 2 ++ src/lib.rs | 4 +-- src/macros.rs | 6 ++++- src/x509/mod.rs | 75 ++++++++++++++++++++++++++++++++++++--------------------- 5 files changed, 103 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/asn1/mod.rs b/src/asn1/mod.rs index e69de29b..2cd4584f 100644 --- a/src/asn1/mod.rs +++ b/src/asn1/mod.rs @@ -0,0 +1,47 @@ +use libc::{c_long}; +use std::ptr; + +use ffi; +use ssl::error::{SslError}; + + +pub struct Asn1Time { + handle: *mut ffi::ASN1_TIME, + owned: bool +} + +impl Asn1Time { + /// Wraps existing ASN1_TIME and takes ownership + pub fn new(handle: *mut ffi::ASN1_TIME) -> Asn1Time { + Asn1Time { + handle: handle, + owned: true + } + } + + fn new_with_period(period: u64) -> Result { + let handle = unsafe { + try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), + period as c_long)) + }; + Ok(Asn1Time::new(handle)) + } + + /// Creates a new time on specified interval in days from now + pub fn days_from_now(days: uint) -> Result { + Asn1Time::new_with_period(days as u64 * 60 * 60 * 24) + } + + /// Returns raw handle + pub unsafe fn get_handle(&self) -> *mut ffi::ASN1_TIME { + return self.handle + } +} + +impl Drop for Asn1Time { + fn drop(&mut self) { + if self.owned { + unsafe { ffi::ASN1_TIME_free(self.handle) }; + } + } +} diff --git a/src/ffi.rs b/src/ffi.rs index 9ceb7f31..ec53df4b 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -192,6 +192,7 @@ pub unsafe fn BN_is_zero(a: *mut BIGNUM) -> c_int { bn_is_zero(a) } extern "C" { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; + pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); pub fn BIO_free_all(a: *mut BIO); pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; @@ -402,6 +403,7 @@ extern "C" { pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; + pub fn X509_free(x: *mut X509); pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME; pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; diff --git a/src/lib.rs b/src/lib.rs index 9aee977d..edc8a2a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(struct_variant, macro_rules)] +#![feature(struct_variant, macro_rules, unsafe_destructor)] #![crate_name="openssl"] #![crate_type="rlib"] #![crate_type="dylib"] @@ -11,7 +11,7 @@ extern crate sync; mod macros; -mod asn1; +pub mod asn1; pub mod bn; pub mod bio; pub mod crypto; diff --git a/src/macros.rs b/src/macros.rs index 061381f2..2de14620 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -26,7 +26,11 @@ macro_rules! try_ssl{ /// Shortcut return with SSL if got a null result macro_rules! try_ssl_null{ - ($e:expr) => (try_ssl_if!($e == ptr::null_mut())) + ($e:expr) => ({ + let t = $e; + try_ssl_if!(t == ptr::null_mut()); + t + }) } diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 63be93ae..d12d6374 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -2,6 +2,7 @@ use libc::{c_int, c_long, c_uint}; use std::mem; use std::ptr; +use asn1::{Asn1Time}; use bio::{MemBio}; use crypto::hash::{HashType, evpmd, SHA1}; use crypto::pkey::{PKey}; @@ -39,7 +40,7 @@ impl X509StoreContext { if ptr.is_null() { None } else { - Some(X509 { ctx: Some(self), x509: ptr }) + Some(X509 { ctx: Some(self), handle: ptr, owned: false }) } } } @@ -184,16 +185,21 @@ impl X509Generator { fn add_extension(x509: *mut ffi::X509, extension: c_int, value: &str) -> Result<(), SslError> { unsafe { - // FIXME: RAII let mut ctx: ffi::X509V3_CTX = mem::zeroed(); ffi::X509V3_set_ctx(&mut ctx, x509, x509, ptr::null_mut(), ptr::null_mut(), 0); let ext = value.with_c_str(|value| - ffi::X509V3_EXT_conf_nid(ptr::null_mut(), mem::transmute(&ctx), extension, mem::transmute(value))); - try_ssl_null!(ext); - try_ssl!(ffi::X509_add_ext(x509, ext, -1)); - ffi::X509_EXTENSION_free(ext); - Ok(()) + ffi::X509V3_EXT_conf_nid(ptr::null_mut(), + mem::transmute(&ctx), + extension, + mem::transmute(value))); + + let mut success = false; + if ext != ptr::null_mut() { + success = ffi::X509_add_ext(x509, ext, -1) != 0; + ffi::X509_EXTENSION_free(ext); + } + lift_ssl_if!(!success) } } @@ -222,44 +228,47 @@ impl X509Generator { let mut p_key = PKey::new(); p_key.gen(self.bits); - // FIXME: all allocated resources should be correctly - // dropped in case of failure unsafe { let x509 = ffi::X509_new(); try_ssl_null!(x509); - try_ssl!(ffi::X509_set_version(x509, 2)); - try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509), X509Generator::random_serial())); - let not_before = ffi::X509_gmtime_adj(ptr::null_mut(), 0); - try_ssl_null!(not_before); + let x509 = X509 { handle: x509, ctx: None, owned: true}; + + try_ssl!(ffi::X509_set_version(x509.handle, 2)); + try_ssl!(ffi::ASN1_INTEGER_set(ffi::X509_get_serialNumber(x509.handle), X509Generator::random_serial())); - let not_after = ffi::X509_gmtime_adj(ptr::null_mut(), 60*60*24*self.days as i64); - try_ssl_null!(not_after); + let not_before = try!(Asn1Time::days_from_now(0)); + let not_after = try!(Asn1Time::days_from_now(self.days)); - try_ssl!(ffi::X509_set_notBefore(x509, mem::transmute(not_before))); - try_ssl!(ffi::X509_set_notAfter(x509, mem::transmute(not_after))); + try_ssl!(ffi::X509_set_notBefore(x509.handle, mem::transmute(not_before.get_handle()))); + // If prev line succeded - ownership should go to cert + mem::forget(not_before); - try_ssl!(ffi::X509_set_pubkey(x509, p_key.get_handle())); + try_ssl!(ffi::X509_set_notAfter(x509.handle, mem::transmute(not_after.get_handle()))); + // If prev line succeded - ownership should go to cert + mem::forget(not_after); - let name = ffi::X509_get_subject_name(x509); + try_ssl!(ffi::X509_set_pubkey(x509.handle, p_key.get_handle())); + + let name = ffi::X509_get_subject_name(x509.handle); try_ssl_null!(name); try!(X509Generator::add_name(name, "CN", self.CN.as_slice())); - ffi::X509_set_issuer_name(x509, name); + ffi::X509_set_issuer_name(x509.handle, name); if self.key_usage.len() > 0 { - try!(X509Generator::add_extension(x509, ffi::NID_key_usage, + try!(X509Generator::add_extension(x509.handle, ffi::NID_key_usage, self.key_usage.to_str().as_slice())); } if self.ext_key_usage.len() > 0 { - try!(X509Generator::add_extension(x509, ffi::NID_ext_key_usage, + try!(X509Generator::add_extension(x509.handle, ffi::NID_ext_key_usage, self.ext_key_usage.to_str().as_slice())); } let (hash_fn, _) = evpmd(self.hash_type); - try_ssl!(ffi::X509_sign(x509, p_key.get_handle(), hash_fn)); - Ok((X509 { x509: x509, ctx: None }, p_key)) + try_ssl!(ffi::X509_sign(x509.handle, p_key.get_handle(), hash_fn)); + Ok((x509, p_key)) } } } @@ -268,12 +277,13 @@ impl X509Generator { /// A public key certificate pub struct X509<'ctx> { ctx: Option<&'ctx X509StoreContext>, - x509: *mut ffi::X509 + handle: *mut ffi::X509, + owned: bool } impl<'ctx> X509<'ctx> { pub fn subject_name<'a>(&'a self) -> X509Name<'a> { - let name = unsafe { ffi::X509_get_subject_name(self.x509) }; + let name = unsafe { ffi::X509_get_subject_name(self.handle) }; X509Name { x509: self, name: name } } @@ -283,7 +293,7 @@ impl<'ctx> X509<'ctx> { let v: Vec = Vec::from_elem(len, 0); let act_len: c_uint = 0; let res = unsafe { - ffi::X509_digest(self.x509, evp, mem::transmute(v.as_ptr()), + ffi::X509_digest(self.handle, evp, mem::transmute(v.as_ptr()), mem::transmute(&act_len)) }; @@ -305,13 +315,22 @@ impl<'ctx> X509<'ctx> { let mut mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_X509(mem_bio.get_handle(), - self.x509)); + self.handle)); } let buf = try!(mem_bio.read_to_end().map_err(StreamError)); writer.write(buf.as_slice()).map_err(StreamError) } } +#[unsafe_destructor] +impl<'ctx> Drop for X509<'ctx> { + fn drop(&mut self) { + if self.owned { + unsafe { ffi::X509_free(self.handle) }; + } + } +} + #[allow(dead_code)] pub struct X509Name<'x> { x509: &'x X509<'x>, -- cgit v1.2.3 From 7e214fe8a885a1a0c7b16680be1e33eaa2852ceb Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Mon, 6 Oct 2014 01:53:56 -0700 Subject: Fix #65: failing test case --- src/ssl/error.rs | 2 +- src/ssl/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ssl/error.rs b/src/ssl/error.rs index 56105253..56df2747 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -42,8 +42,8 @@ fn get_reason(err: c_ulong) -> String { } #[test] -#[ignore] // FIXME #65 fn test_uknown_error_should_have_correct_messages() { + unsafe { ffi::SSL_load_error_strings(); } let err = 336032784; let library = get_lib(err); let function = get_func(err); diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index c7c024ed..9dd22766 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -25,7 +25,7 @@ fn init() { INIT.doit(|| { ffi::SSL_library_init(); ffi::SSL_load_error_strings(); - ffi::ERR_load_crypto_strings(); + ffi::ERR_load_crypto_strings(); // necessary? let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None); assert!(verify_idx >= 0); -- cgit v1.2.3 From 41287f3b146c3b5b5c2a706eac7d436dac060864 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 7 Oct 2014 14:54:35 +0300 Subject: Using `Path`s instead of plain strings Refs #45 --- src/ssl/mod.rs | 6 +++--- src/ssl/tests.rs | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index c7c024ed..b37d3142 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -248,7 +248,7 @@ impl SslContext { #[allow(non_snake_case)] /// Specifies the file that contains trusted CA certificates. - pub fn set_CA_file(&mut self, file: &str) -> Option { + pub fn set_CA_file(&mut self, file: &Path) -> Option { wrap_ssl_result(file.with_c_str(|file| { unsafe { ffi::SSL_CTX_load_verify_locations(self.ctx, file, ptr::null()) @@ -257,7 +257,7 @@ impl SslContext { } /// Specifies the file that is client certificate - pub fn set_certificate_file(&mut self, file: &str, + pub fn set_certificate_file(&mut self, file: &Path, file_type: X509FileType) -> Option { wrap_ssl_result(file.with_c_str(|file| { unsafe { @@ -267,7 +267,7 @@ impl SslContext { } /// Specifies the file that is client private key - pub fn set_private_key_file(&mut self, file: &str, + pub fn set_private_key_file(&mut self, file: &Path, file_type: X509FileType) -> Option { wrap_ssl_result(file.with_c_str(|file| { unsafe { diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 0e6edbf7..fc609bf3 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -34,7 +34,7 @@ fn test_verify_trusted() { let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, None); - match ctx.set_CA_file("test/cert.pem") { + match ctx.set_CA_file(&Path::new("test/cert.pem")) { None => {} Some(err) => fail!("Unexpected error {}", err) } @@ -77,7 +77,7 @@ fn test_verify_trusted_callback_override_ok() { let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); - match ctx.set_CA_file("test/cert.pem") { + match ctx.set_CA_file(&Path::new("test/cert.pem")) { None => {} Some(err) => fail!("Unexpected error {}", err) } @@ -95,7 +95,7 @@ fn test_verify_trusted_callback_override_bad() { let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); - match ctx.set_CA_file("test/cert.pem") { + match ctx.set_CA_file(&Path::new("test/cert.pem")) { None => {} Some(err) => fail!("Unexpected error {}", err) } @@ -123,7 +123,7 @@ fn test_verify_trusted_get_error_ok() { let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); - match ctx.set_CA_file("test/cert.pem") { + match ctx.set_CA_file(&Path::new("test/cert.pem")) { None => {} Some(err) => fail!("Unexpected error {}", err) } -- cgit v1.2.3 From 9dd8ce9270afa8c110f44b42d87b133620b1ec30 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 7 Oct 2014 14:33:53 +0300 Subject: Potential fix for #68 --- src/ffi.rs | 9 ++++++--- src/ssl/tests.rs | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index ec53df4b..fcd0d33e 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -189,6 +189,12 @@ extern { } /* Since the openssl BN_is_zero is sometimes a macro, this wrapper is necessary. */ pub unsafe fn BN_is_zero(a: *mut BIGNUM) -> c_int { bn_is_zero(a) } +/* Special import from native/bn_is_zero.c */ +#[link(name="wrapped")] +extern "C" { + pub fn bn_is_zero(a: *mut BIGNUM) -> c_int; +} + extern "C" { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; @@ -241,9 +247,6 @@ extern "C" { pub fn BN_cmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; pub fn BN_ucmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - /* Special import from native/bn_is_zero.c */ - pub fn bn_is_zero(a: *mut BIGNUM) -> c_int; - /* Prime handling */ pub fn BN_generate_prime_ex(r: *mut BIGNUM, bits: c_int, safe: c_int, add: *mut BIGNUM, rem: *mut BIGNUM, cb: *const c_void) -> c_int; pub fn BN_is_prime_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, cb: *const c_void) -> c_int; diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 0e6edbf7..50c24b94 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -221,3 +221,16 @@ fn test_cert_gen() { // FIXME: check data in result to be correct, needs implementation // of X509 getters } + +#[test] +fn test_bn_is_zero() { + use ffi; + use std::ptr; + + unsafe { + let bn = ffi::BN_new(); + assert!(bn != ptr::null_mut()); + // Just make sure it is linked and resolved correctly + ffi::BN_is_zero(bn); + } +} -- cgit v1.2.3 From 3ba768bc288031964994e39d0fa08607fccf728e Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 7 Oct 2014 15:09:20 +0300 Subject: Fixed incorrect EOF handling in MemBio, added error description Actually, EOF wasn't handled at all and it caused `mem_bio.read_to_end()` to fail. Which in turn failed all `write_pem` implementations. --- src/bio/mod.rs | 28 ++++++++++++++++++++++------ src/ffi.rs | 12 +++++++++++- src/ssl/tests.rs | 18 +++++++++++++++++- 3 files changed, 50 insertions(+), 8 deletions(-) mode change 100644 => 100755 src/ffi.rs (limited to 'src') diff --git a/src/bio/mod.rs b/src/bio/mod.rs index 5c5e8df0..a6dc9dc2 100644 --- a/src/bio/mod.rs +++ b/src/bio/mod.rs @@ -1,5 +1,5 @@ use libc::{c_void, c_int}; -use std::io::{IoResult, IoError, OtherIoError}; +use std::io::{EndOfFile, IoResult, IoError, OtherIoError}; use std::io::{Reader, Writer}; use std::ptr; @@ -62,9 +62,22 @@ impl Reader for MemBio { buf.len() as c_int) }; - if ret < 0 { - // FIXME: provide details from OpenSSL - Err(IoError{kind: OtherIoError, desc: "mem bio read error", detail: None}) + if ret <= 0 { + let is_eof = unsafe { ffi::BIO_eof(self.bio) }; + let err = if is_eof { + IoError { + kind: EndOfFile, + desc: "MemBio EOF", + detail: None + } + } else { + IoError { + kind: OtherIoError, + desc: "MemBio read error", + detail: Some(format!("{}", SslError::get())) + } + }; + Err(err) } else { Ok(ret as uint) } @@ -78,8 +91,11 @@ impl Writer for MemBio { buf.len() as c_int) }; if buf.len() != ret as uint { - // FIXME: provide details from OpenSSL - Err(IoError{kind: OtherIoError, desc: "mem bio write error", detail: None}) + Err(IoError { + kind: OtherIoError, + desc: "MemBio write error", + detail: Some(format!("{}", SslError::get())) + }) } else { Ok(()) } diff --git a/src/ffi.rs b/src/ffi.rs old mode 100644 new mode 100755 index fcd0d33e..40291869 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,6 +1,7 @@ #![allow(non_camel_case_types, non_uppercase_statics, non_snake_case)] #![allow(dead_code)] use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; +use std::ptr; pub type ASN1_INTEGER = c_void; pub type ASN1_STRING = c_void; @@ -84,6 +85,8 @@ pub type PrivateKeyWriteCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; +pub static BIO_CTRL_EOF: c_int = 2; + pub static CRYPTO_LOCK: c_int = 1; pub static MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; @@ -195,12 +198,19 @@ extern "C" { pub fn bn_is_zero(a: *mut BIGNUM) -> c_int; } +// Functions converted from macros +pub unsafe fn BIO_eof(b: *mut BIO) -> bool { + BIO_ctrl(b, BIO_CTRL_EOF, 0, ptr::null_mut()) == 1 +} + +// True functions extern "C" { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); - pub fn BIO_free_all(a: *mut BIO); + pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn BIO_free_all(b: *mut BIO); pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 50c24b94..1113b2df 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -1,4 +1,4 @@ -use std::io::Writer; +use std::io::{File, Open, Write, Writer}; use std::io::net::tcp::TcpStream; use std::num::FromStrRadix; use std::str; @@ -218,6 +218,22 @@ fn test_cert_gen() { 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 } -- cgit v1.2.3 From fec1c43a4a348ba6356ab7c80961cc2652a2602e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 7 Oct 2014 23:18:20 -0400 Subject: Revert "Fix #65: failing test case" --- src/ssl/error.rs | 2 +- src/ssl/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ssl/error.rs b/src/ssl/error.rs index 56df2747..56105253 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -42,8 +42,8 @@ fn get_reason(err: c_ulong) -> String { } #[test] +#[ignore] // FIXME #65 fn test_uknown_error_should_have_correct_messages() { - unsafe { ffi::SSL_load_error_strings(); } let err = 336032784; let library = get_lib(err); let function = get_func(err); diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 67437b52..b37d3142 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -25,7 +25,7 @@ fn init() { INIT.doit(|| { ffi::SSL_library_init(); ffi::SSL_load_error_strings(); - ffi::ERR_load_crypto_strings(); // necessary? + ffi::ERR_load_crypto_strings(); let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None); assert!(verify_idx >= 0); -- cgit v1.2.3 From 6f399239d8cddf12b169679c340f0f24d70a794b Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Wed, 8 Oct 2014 09:06:16 +0300 Subject: Minor doc fixes and feature mentions --- src/bio/mod.rs | 2 +- src/ssl/mod.rs | 12 +++++++----- src/x509/mod.rs | 19 ++++++++++++++++++- 3 files changed, 26 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/bio/mod.rs b/src/bio/mod.rs index a6dc9dc2..2ae66516 100644 --- a/src/bio/mod.rs +++ b/src/bio/mod.rs @@ -43,7 +43,7 @@ impl MemBio { /// Consumes current bio and returns wrapped value /// Note that data ownership is lost and - /// should be handled manually + /// should be managed manually pub unsafe fn unwrap(mut self) -> *mut ffi::BIO { self.owned = false; self.bio diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index b37d3142..31307a03 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -45,17 +45,19 @@ fn init() { #[allow(non_camel_case_types)] pub enum SslMethod { #[cfg(feature = "sslv2")] - /// Only support the SSLv2 protocol + /// Only support the SSLv2 protocol, requires `feature="sslv2"` Sslv2, + /// Support the SSLv2, SSLv3 and TLSv1 protocols + Sslv23, /// Only support the SSLv3 protocol Sslv3, /// Only support the TLSv1 protocol Tlsv1, - /// Support the SSLv2, SSLv3 and TLSv1 protocols - Sslv23, #[cfg(feature = "tlsv1_1")] + /// Support TLSv1.1 protocol, requires `feature="tlsv1_1"` Tlsv1_1, #[cfg(feature = "tlsv1_2")] + /// Support TLSv1.2 protocol, requires `feature="tlsv1_2"` Tlsv1_2, } @@ -256,7 +258,7 @@ impl SslContext { })) } - /// Specifies the file that is client certificate + /// Specifies the file that contains certificate pub fn set_certificate_file(&mut self, file: &Path, file_type: X509FileType) -> Option { wrap_ssl_result(file.with_c_str(|file| { @@ -266,7 +268,7 @@ impl SslContext { })) } - /// Specifies the file that is client private key + /// Specifies the file that contains private key pub fn set_private_key_file(&mut self, file: &Path, file_type: X509FileType) -> Option { wrap_ssl_result(file.with_c_str(|file| { diff --git a/src/x509/mod.rs b/src/x509/mod.rs index d12d6374..f04f6ff1 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -45,6 +45,7 @@ impl X509StoreContext { } } +#[doc(hidden)] trait AsStr<'a> { fn as_str(&self) -> &'a str; } @@ -116,6 +117,7 @@ impl AsStr<'static> for ExtKeyUsage { // FIXME: a dirty hack as there is no way to // implement ToString for Vec as both are defined // in another crate +#[doc(hidden)] trait ToStr { fn to_str(&self) -> String; } @@ -141,6 +143,15 @@ pub struct X509Generator { } impl X509Generator { + /// Creates a new generator with the following defaults: + /// + /// bit length: 1024 + /// + /// validity period: 365 days + /// + /// CN: "rust-openssl" + /// + /// hash: SHA1 pub fn new() -> X509Generator { X509Generator { bits: 1024, @@ -152,27 +163,32 @@ impl X509Generator { } } + /// Sets desired bit length pub fn set_bitlength(mut self, bits: uint) -> X509Generator { self.bits = bits; self } + /// Sets certificate validity period in days since today pub fn set_valid_period(mut self, days: uint) -> X509Generator { self.days = days; self } #[allow(non_snake_case)] + /// Sets Common Name of certificate pub fn set_CN(mut self, CN: &str) -> X509Generator { self.CN = CN.to_string(); self } + /// Sets what for certificate could be used pub fn set_usage(mut self, purposes: &[KeyUsage]) -> X509Generator { self.key_usage = purposes.to_vec(); self } + /// Sets allowed extended usage of certificate pub fn set_ext_usage(mut self, purposes: &[ExtKeyUsage]) -> X509Generator { self.ext_key_usage = purposes.to_vec(); self @@ -224,6 +240,7 @@ impl X509Generator { res } + /// Generates a private key and a signed certificate and returns them pub fn generate<'a>(&self) -> Result<(X509<'a>, PKey), SslError> { let mut p_key = PKey::new(); p_key.gen(self.bits); @@ -315,7 +332,7 @@ impl<'ctx> X509<'ctx> { let mut mem_bio = try!(MemBio::new()); unsafe { try_ssl!(ffi::PEM_write_bio_X509(mem_bio.get_handle(), - self.handle)); + self.handle)); } let buf = try!(mem_bio.read_to_end().map_err(StreamError)); writer.write(buf.as_slice()).map_err(StreamError) -- cgit v1.2.3 From fe21d4bb666ac3fbea3101d9d5ad8afe972d0e9b Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Wed, 8 Oct 2014 09:07:10 +0300 Subject: X509 Generator sample Forcing static linking for lib wrapped as in other case doc tests fail to locate the static library --- src/ffi.rs | 2 +- src/x509/mod.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 40291869..93a25274 100755 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -193,7 +193,7 @@ extern { } pub unsafe fn BN_is_zero(a: *mut BIGNUM) -> c_int { bn_is_zero(a) } /* Special import from native/bn_is_zero.c */ -#[link(name="wrapped")] +#[link(name = "wrapped", kind = "static")] extern "C" { pub fn bn_is_zero(a: *mut BIGNUM) -> c_int; } diff --git a/src/x509/mod.rs b/src/x509/mod.rs index f04f6ff1..88b81d7e 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -133,6 +133,36 @@ impl<'a, T: AsStr<'a>> ToStr for Vec { } #[allow(non_snake_case)] +/// Generator of private key/certificate pairs +/// +/// # Example +/// +/// ``` +/// use std::io::{File, Open, Write}; +/// # use std::io::fs; +/// +/// use openssl::crypto::hash::SHA256; +/// use openssl::x509::{DigitalSignature, X509Generator}; +/// +/// let gen = X509Generator::new() +/// .set_bitlength(2048) +/// .set_valid_period(365*2) +/// .set_CN("SuperMegaCorp Inc.") +/// .set_sign_hash(SHA256) +/// .set_usage([DigitalSignature]); +/// +/// let (cert, pkey) = gen.generate().unwrap(); +/// +/// let cert_path = Path::new("doc_cert.pem"); +/// let mut file = File::open_mode(&cert_path, Open, Write).unwrap(); +/// assert!(cert.write_pem(&mut file).is_ok()); +/// # let _ = fs::unlink(&cert_path); +/// +/// let pkey_path = Path::new("doc_key.pem"); +/// let mut file = File::open_mode(&pkey_path, Open, Write).unwrap(); +/// assert!(pkey.write_pem(&mut file).is_ok()); +/// # let _ = fs::unlink(&pkey_path); +/// ``` pub struct X509Generator { bits: uint, days: uint, -- cgit v1.2.3 From 95b9cf39c93d73e977b682e2287f275690180f3a Mon Sep 17 00:00:00 2001 From: Samuel Fredrickson Date: Thu, 9 Oct 2014 00:34:51 -0700 Subject: "final" is now a reserved word, so change occurrences to "finalize". --- src/crypto/hash.rs | 4 ++-- src/crypto/hmac.rs | 8 ++++---- src/crypto/symm.rs | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index 03d0f097..61221cb5 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -56,7 +56,7 @@ impl Hasher { * Return the digest of all bytes added to this hasher since its last * initialization */ - pub fn final(&self) -> Vec { + pub fn finalize(&self) -> Vec { unsafe { let mut res = Vec::from_elem(self.len, 0u8); ffi::EVP_DigestFinal(self.ctx, res.as_mut_ptr(), ptr::null_mut()); @@ -80,7 +80,7 @@ impl Drop for Hasher { pub fn hash(t: HashType, data: &[u8]) -> Vec { let h = Hasher::new(t); h.update(data); - h.final() + h.finalize() } #[cfg(test)] diff --git a/src/crypto/hmac.rs b/src/crypto/hmac.rs index 0d945200..4c8617ca 100644 --- a/src/crypto/hmac.rs +++ b/src/crypto/hmac.rs @@ -48,7 +48,7 @@ impl HMAC { } } - pub fn final(&mut self) -> Vec { + pub fn finalize(&mut self) -> Vec { unsafe { let mut res = Vec::from_elem(self.len, 0u8); let mut outlen = 0; @@ -94,7 +94,7 @@ mod tests { for &(ref key, ref data, ref res) in tests.iter() { let mut hmac = HMAC(MD5, key.as_slice()); hmac.update(data.as_slice()); - assert_eq!(hmac.final(), *res); + assert_eq!(hmac.finalize(), *res); } } @@ -127,7 +127,7 @@ mod tests { for &(ref key, ref data, ref res) in tests.iter() { let mut hmac = HMAC(SHA1, key.as_slice()); hmac.update(data.as_slice()); - assert_eq!(hmac.final(), *res); + assert_eq!(hmac.finalize(), *res); } } @@ -151,7 +151,7 @@ mod tests { for (&(ref key, ref data), res) in tests.iter().zip(results.iter()) { let mut hmac = HMAC(ty, key.as_slice()); hmac.update(data.as_slice()); - assert_eq!(hmac.final(), *res); + assert_eq!(hmac.finalize(), *res); } } diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index a92f7753..9953ac7b 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -114,7 +114,7 @@ impl Crypter { /** * Finish crypting. Returns the remaining partial block of output, if any. */ - pub fn final(&self) -> Vec { + pub fn finalize(&self) -> Vec { unsafe { let mut res = Vec::from_elem(self.blocksize, 0u8); let mut reslen = self.blocksize as c_int; @@ -145,7 +145,7 @@ pub fn encrypt(t: Type, key: &[u8], iv: Vec, data: &[u8]) -> Vec { let c = Crypter::new(t); c.init(Encrypt, key, iv); let mut r = c.update(data); - let rest = c.final(); + let rest = c.finalize(); r.extend(rest.into_iter()); r } @@ -158,7 +158,7 @@ pub fn decrypt(t: Type, key: &[u8], iv: Vec, data: &[u8]) -> Vec { let c = Crypter::new(t); c.init(Decrypt, key, iv); let mut r = c.update(data); - let rest = c.final(); + let rest = c.finalize(); r.extend(rest.into_iter()); r } @@ -186,12 +186,12 @@ mod tests { c.init(super::Encrypt, k0.as_slice(), vec![]); c.pad(false); let mut r0 = c.update(p0.as_slice()); - r0.extend(c.final().into_iter()); + r0.extend(c.finalize().into_iter()); assert!(r0 == c0); c.init(super::Decrypt, k0.as_slice(), vec![]); c.pad(false); let mut p1 = c.update(r0.as_slice()); - p1.extend(c.final().into_iter()); + p1.extend(c.finalize().into_iter()); assert!(p1 == p0); } @@ -203,7 +203,7 @@ mod tests { let expected = ct.from_hex().unwrap().as_slice().to_vec(); let mut computed = cipher.update(pt.from_hex().unwrap().as_slice()); - computed.extend(cipher.final().into_iter()); + computed.extend(cipher.finalize().into_iter()); if computed != expected { println!("Computed: {}", computed.as_slice().to_hex()); -- cgit v1.2.3 From 59b843517df8d35b339eaee95ba4e533b190f9d6 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Thu, 9 Oct 2014 12:33:29 +0300 Subject: BN_is_zero as a Rust function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although wrapping was relatively easy it basically meant that we depend on C compilation which becomes nightmare as soon as multiple platforms are used. I’ve got a huge pain once iOS was involved with 3 device archs and 2 simulator arches to support, not mentioning different set of include and lib flags. So there are 2 different approaches: - continue this way, maintaining all compilation issues like like managing correct flags, providing correct paths and so on. This way our Makefile will grow extremely fast and will actually take more efforts to maintain. - doing it pure Rust way. In this case we provide all the macros expansions inside our wrappers and there should be no other way to access raw data other than through those wrappers. It might be fragile if OpenSSL internal data structures will ever change, but I think (or hope) it is pretty stable and wouldn’t change anytime soon. This PR eliminates `BN_is_zero` at all from public API. It’s functionality is implemented in `BigNum.is_zero` and should be enough. Additional notes: 1. I’ve moved BIGNUM into `bn` so it could access fields directly and keep it as an opaque structure for everyone else 2. I’ve kept empty Makefile as I hope to land `feature-matrix` branch soon and I don’t like merging deleted/added file conflicts. --- src/bn/mod.rs | 16 ++++++++++++++-- src/ffi.rs | 21 ++------------------- src/ssl/tests.rs | 13 ------------- 3 files changed, 16 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/bn/mod.rs b/src/bn/mod.rs index fb836a39..129f6b90 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_ulong}; +use libc::{c_int, c_ulong, c_void}; use std::{fmt, ptr}; use std::c_str::CString; use std::num::{One, Zero}; @@ -6,6 +6,16 @@ use std::num::{One, Zero}; use ffi; use ssl::error::SslError; +#[allow(dead_code)] +#[repr(C)] +pub struct BIGNUM { + d: *mut c_void, + top: c_int, + dmax: c_int, + neg: c_int, + flags: c_int, +} + pub struct BigNum(*mut ffi::BIGNUM); #[repr(C)] @@ -381,9 +391,11 @@ impl Zero for BigNum { fn zero() -> BigNum { BigNum::new_from(0).unwrap() } + fn is_zero(&self) -> bool { unsafe { - ffi::BN_is_zero(self.raw()) == 1 + // It is raw contents of BN_is_zero macro + (*self.raw()).top == 0 } } } diff --git a/src/ffi.rs b/src/ffi.rs index 93a25274..0801577e 100755 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -3,6 +3,8 @@ use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; use std::ptr; +pub use bn::BIGNUM; + pub type ASN1_INTEGER = c_void; pub type ASN1_STRING = c_void; pub type ASN1_TIME = c_void; @@ -28,16 +30,6 @@ pub type X509_NAME = c_void; pub type X509_REQ = c_void; pub type X509_STORE_CTX = c_void; -#[allow(dead_code)] -#[repr(C)] -pub struct BIGNUM { - d: *mut c_void, - top: c_int, - dmax: c_int, - pub neg: c_int, - flags: c_int, -} - #[repr(C)] pub struct EVP_MD_CTX { digest: *mut EVP_MD, @@ -189,15 +181,6 @@ extern {} #[link(name="wsock32")] extern { } -/* Since the openssl BN_is_zero is sometimes a macro, this wrapper is necessary. */ -pub unsafe fn BN_is_zero(a: *mut BIGNUM) -> c_int { bn_is_zero(a) } - -/* Special import from native/bn_is_zero.c */ -#[link(name = "wrapped", kind = "static")] -extern "C" { - pub fn bn_is_zero(a: *mut BIGNUM) -> c_int; -} - // Functions converted from macros pub unsafe fn BIO_eof(b: *mut BIO) -> bool { BIO_ctrl(b, BIO_CTRL_EOF, 0, ptr::null_mut()) == 1 diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index f98352be..a68d4967 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -237,16 +237,3 @@ fn test_cert_gen() { // FIXME: check data in result to be correct, needs implementation // of X509 getters } - -#[test] -fn test_bn_is_zero() { - use ffi; - use std::ptr; - - unsafe { - let bn = ffi::BN_new(); - assert!(bn != ptr::null_mut()); - // Just make sure it is linked and resolved correctly - ffi::BN_is_zero(bn); - } -} -- cgit v1.2.3 From f1b8ad7df93ca79404b221fd97f640a62586e174 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 9 Oct 2014 18:33:59 -0700 Subject: Prepare for s/static/const/ --- src/ffi.rs | 176 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 88 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 0801577e..0bdae5b6 100755 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -77,94 +77,94 @@ pub type PrivateKeyWriteCallback = extern "C" fn(buf: *mut c_char, size: c_int, rwflag: c_int, user_data: *mut c_void) -> c_int; -pub static BIO_CTRL_EOF: c_int = 2; - -pub static CRYPTO_LOCK: c_int = 1; - -pub static MBSTRING_ASC: c_int = MBSTRING_FLAG | 1; -pub static MBSTRING_BMP: c_int = MBSTRING_FLAG | 2; -pub static MBSTRING_FLAG: c_int = 0x1000; -pub static MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; -pub static MBSTRING_UTF8: c_int = MBSTRING_FLAG; - -pub static NID_ext_key_usage: c_int = 126; -pub static NID_key_usage: c_int = 83; - -pub static SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; -pub static SSL_ERROR_NONE: c_int = 0; -pub static SSL_ERROR_SSL: c_int = 1; -pub static SSL_ERROR_SYSCALL: c_int = 5; -pub static SSL_ERROR_WANT_ACCEPT: c_int = 8; -pub static SSL_ERROR_WANT_CONNECT: c_int = 7; -pub static SSL_ERROR_WANT_READ: c_int = 2; -pub static SSL_ERROR_WANT_WRITE: c_int = 3; -pub static SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; -pub static SSL_ERROR_ZERO_RETURN: c_int = 6; -pub static SSL_VERIFY_NONE: c_int = 0; -pub static SSL_VERIFY_PEER: c_int = 1; - -pub static TLSEXT_NAMETYPE_host_name: c_long = 0; - -pub static V_ASN1_GENERALIZEDTIME: c_int = 24; -pub static V_ASN1_UTCTIME: c_int = 23; - -pub static X509_FILETYPE_ASN1: c_int = 2; -pub static X509_FILETYPE_DEFAULT: c_int = 3; -pub static X509_FILETYPE_PEM: c_int = 1; -pub static X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; -pub static X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; -pub static X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; -pub static X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; -pub static X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; -pub static X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; -pub static X509_V_ERR_CERT_REJECTED: c_int = 28; -pub static X509_V_ERR_CERT_REVOKED: c_int = 23; -pub static X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; -pub static X509_V_ERR_CERT_UNTRUSTED: c_int = 27; -pub static X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; -pub static X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; -pub static X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; -pub static X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; -pub static X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; -pub static X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; -pub static X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; -pub static X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; -pub static X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; -pub static X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; -pub static X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; -pub static X509_V_ERR_INVALID_CA: c_int = 24; -pub static X509_V_ERR_INVALID_EXTENSION: c_int = 41; -pub static X509_V_ERR_INVALID_NON_CA: c_int = 37; -pub static X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; -pub static X509_V_ERR_INVALID_PURPOSE: c_int = 26; -pub static X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; -pub static X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; -pub static X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; -pub static X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; -pub static X509_V_ERR_OUT_OF_MEM: c_int = 17; -pub static X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; -pub static X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; -pub static X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; -pub static X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; -pub static X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; -pub static X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; -pub static X509_V_ERR_SUBTREE_MINMAX: c_int = 49; -pub static X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; -pub static X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; -pub static X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; -pub static X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; -pub static X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; -pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; -pub static X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; -pub static X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; -pub static X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; -pub static X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; -pub static X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; -pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; -pub static X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; -pub static X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; -pub static X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; -pub static X509_V_OK: c_int = 0; +pub const BIO_CTRL_EOF: c_int = 2; + +pub const CRYPTO_LOCK: c_int = 1; + +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; +pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; +pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG; + +pub const NID_ext_key_usage: c_int = 126; +pub const NID_key_usage: c_int = 83; + +pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; +pub const SSL_ERROR_NONE: c_int = 0; +pub const SSL_ERROR_SSL: c_int = 1; +pub const SSL_ERROR_SYSCALL: c_int = 5; +pub const SSL_ERROR_WANT_ACCEPT: c_int = 8; +pub const SSL_ERROR_WANT_CONNECT: c_int = 7; +pub const SSL_ERROR_WANT_READ: c_int = 2; +pub const SSL_ERROR_WANT_WRITE: c_int = 3; +pub const SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; +pub const SSL_ERROR_ZERO_RETURN: c_int = 6; +pub const SSL_VERIFY_NONE: c_int = 0; +pub const SSL_VERIFY_PEER: c_int = 1; + +pub const TLSEXT_NAMETYPE_host_name: c_long = 0; + +pub const V_ASN1_GENERALIZEDTIME: c_int = 24; +pub const V_ASN1_UTCTIME: c_int = 23; + +pub const X509_FILETYPE_ASN1: c_int = 2; +pub const X509_FILETYPE_DEFAULT: c_int = 3; +pub const X509_FILETYPE_PEM: c_int = 1; +pub const X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; +pub const X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; +pub const X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; +pub const X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; +pub const X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; +pub const X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; +pub const X509_V_ERR_CERT_REJECTED: c_int = 28; +pub const X509_V_ERR_CERT_REVOKED: c_int = 23; +pub const X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; +pub const X509_V_ERR_CERT_UNTRUSTED: c_int = 27; +pub const X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; +pub const X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; +pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; +pub const X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; +pub const X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; +pub const X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; +pub const X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; +pub const X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; +pub const X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; +pub const X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; +pub const X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; +pub const X509_V_ERR_INVALID_CA: c_int = 24; +pub const X509_V_ERR_INVALID_EXTENSION: c_int = 41; +pub const X509_V_ERR_INVALID_NON_CA: c_int = 37; +pub const X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; +pub const X509_V_ERR_INVALID_PURPOSE: c_int = 26; +pub const X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; +pub const X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; +pub const X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; +pub const X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; +pub const X509_V_ERR_OUT_OF_MEM: c_int = 17; +pub const X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; +pub const X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; +pub const X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; +pub const X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; +pub const X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; +pub const X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; +pub const X509_V_ERR_SUBTREE_MINMAX: c_int = 49; +pub const X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; +pub const X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; +pub const X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; +pub const X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; +pub const X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; +pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; +pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; +pub const X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; +pub const X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; +pub const X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; +pub const X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; +pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; +pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; +pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; +pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; +pub const X509_V_OK: c_int = 0; #[cfg( any( all(target_os = "macos", feature = "tlsv1_1"),all(target_os = "macos", feature = "tlsv1_2")))] #[link(name="ssl.1.0.0")] -- cgit v1.2.3 From 5f017cd549b4c76849bfd5c33e6f6962acd89535 Mon Sep 17 00:00:00 2001 From: Jared Roesch Date: Sat, 11 Oct 2014 01:50:34 -0700 Subject: Refactor init and error handling code Move common ffi initialization code to 'ffi::init()' and the initialization of error handling to a a shared location. --- src/ffi.rs | 12 ++++++++++++ src/ssl/error.rs | 47 +++++++++++++++++++++++++++++------------------ src/ssl/mod.rs | 5 ++--- 3 files changed, 43 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 0bdae5b6..46466d39 100755 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -2,6 +2,7 @@ #![allow(dead_code)] use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; use std::ptr; +use sync::one::{Once, ONCE_INIT}; pub use bn::BIGNUM; @@ -181,6 +182,17 @@ extern {} #[link(name="wsock32")] extern { } +pub fn init() { + static mut INIT: Once = ONCE_INIT; + + unsafe { + INIT.doit(|| { + SSL_library_init(); + SSL_load_error_strings() + }) + } +} + // Functions converted from macros pub unsafe fn BIO_eof(b: *mut BIO) -> bool { BIO_ctrl(b, BIO_CTRL_EOF, 0, ptr::null_mut()) == 1 diff --git a/src/ssl/error.rs b/src/ssl/error.rs index 56105253..5af6c866 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -41,19 +41,6 @@ fn get_reason(err: c_ulong) -> String { unsafe { CString::new(ffi::ERR_reason_error_string(err), false).to_string() } } -#[test] -#[ignore] // FIXME #65 -fn test_uknown_error_should_have_correct_messages() { - let err = 336032784; - let library = get_lib(err); - let function = get_func(err); - let reason = get_reason(err); - - assert_eq!(library.as_slice(),"SSL routines"); - assert_eq!(function.as_slice(), "SSL23_GET_SERVER_HELLO"); - assert_eq!(reason.as_slice(), "sslv3 alert handshake failure"); -} - impl SslError { /// Creates a new `OpenSslErrors` with the current contents of the error /// stack. @@ -62,13 +49,37 @@ impl SslError { loop { match unsafe { ffi::ERR_get_error() } { 0 => break, - err => errs.push(UnknownError { - library: get_lib(err), - function: get_func(err), - reason: get_reason(err) - }) + err => errs.push(SslError::from_error_code(err)) } } OpenSslErrors(errs) } + + /// Creates an `SslError` from the raw numeric error code. + pub fn from_error(err: c_ulong) -> SslError { + OpenSslErrors(vec![SslError::from_error_code(err)]) + } + + fn from_error_code(err: c_ulong) -> OpensslError { + ffi::init(); + UnknownError { + library: get_lib(err), + function: get_func(err), + reason: get_reason(err) + } + } +} + +#[test] +fn test_uknown_error_should_have_correct_messages() { + let errs = match SslError::from_error(336032784) { + OpenSslErrors(errs) => errs, + _ => fail!("This should always be an `OpenSslErrors` variant.") + }; + + let UnknownError { ref library, ref function, ref reason } = errs[0]; + + assert_eq!(library.as_slice(),"SSL routines"); + assert_eq!(function.as_slice(), "SSL23_GET_SERVER_HELLO"); + assert_eq!(reason.as_slice(), "sslv3 alert handshake failure"); } diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 31307a03..33112f7a 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -23,9 +23,8 @@ fn init() { unsafe { INIT.doit(|| { - ffi::SSL_library_init(); - ffi::SSL_load_error_strings(); - ffi::ERR_load_crypto_strings(); + ffi::init(); + let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None); assert!(verify_idx >= 0); -- cgit v1.2.3 From a6af89c67bf3c0ea562e960ba3e51c772b9e1be0 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Tue, 23 Sep 2014 16:59:24 -0400 Subject: ssl: allow setting cipher list --- src/ffi.rs | 1 + src/ssl/mod.rs | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index 46466d39..4dc7b0cc 100755 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -408,6 +408,7 @@ extern "C" { pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int; pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int; + pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 33112f7a..86b3ec83 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -276,6 +276,14 @@ impl SslContext { } })) } + + pub fn set_cipher_list(&mut self, cipher_list: &str) -> Option { + wrap_ssl_result(cipher_list.with_c_str(|cipher_list| { + unsafe { + ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list) + } + })) + } } #[allow(dead_code)] -- cgit v1.2.3 From dd46d1922e4706cf4c15c8cd915c1254363def8c Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Mon, 13 Oct 2014 17:41:03 +0300 Subject: Correct init mutexes and locking function `libcrypto` uses locks quite intensively even without SSL. So they should be initialized before everything else to function properly in multi-threaded apps in which SSL operations are absent or delayed. Finishes #79 --- src/asn1/mod.rs | 2 ++ src/bio/mod.rs | 2 ++ src/bn/mod.rs | 4 ++++ src/crypto/hash.rs | 2 ++ src/crypto/hmac.rs | 2 ++ src/crypto/pkcs5.rs | 2 ++ src/crypto/pkey.rs | 2 ++ src/crypto/rand.rs | 1 + src/crypto/symm.rs | 2 ++ src/ffi.rs | 25 ++++++++++++++++++++++++- src/ssl/mod.rs | 23 +---------------------- src/x509/mod.rs | 2 ++ 12 files changed, 46 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/asn1/mod.rs b/src/asn1/mod.rs index 2cd4584f..89c79f74 100644 --- a/src/asn1/mod.rs +++ b/src/asn1/mod.rs @@ -20,6 +20,8 @@ impl Asn1Time { } fn new_with_period(period: u64) -> Result { + ffi::init(); + let handle = unsafe { try_ssl_null!(ffi::X509_gmtime_adj(ptr::null_mut(), period as c_long)) diff --git a/src/bio/mod.rs b/src/bio/mod.rs index 2ae66516..afc55849 100644 --- a/src/bio/mod.rs +++ b/src/bio/mod.rs @@ -24,6 +24,8 @@ impl Drop for MemBio { impl MemBio { /// Creates a new owned memory based BIO pub fn new() -> Result { + ffi::init(); + let bio = unsafe { ffi::BIO_new(ffi::BIO_s_mem()) }; try_ssl_null!(bio); diff --git a/src/bn/mod.rs b/src/bn/mod.rs index 129f6b90..510c9269 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -79,8 +79,10 @@ macro_rules! with_bn_in_ctx( ) impl BigNum { + // FIXME: squash 3 constructors into one pub fn new() -> Result { unsafe { + ffi::init(); let v = ffi::BN_new(); if v.is_null() { Err(SslError::get()) @@ -92,6 +94,7 @@ impl BigNum { pub fn new_from(n: u64) -> Result { unsafe { + ffi::init(); let bn = ffi::BN_new(); if bn.is_null() || ffi::BN_set_word(bn, n as c_ulong) == 0 { Err(SslError::get()) @@ -103,6 +106,7 @@ impl BigNum { pub fn new_from_slice(n: &[u8]) -> Result { unsafe { + ffi::init(); let bn = ffi::BN_new(); if bn.is_null() || ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, bn).is_null() { Err(SslError::get()) diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index 61221cb5..a72b8d9f 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -36,6 +36,8 @@ pub struct Hasher { impl Hasher { pub fn new(ht: HashType) -> Hasher { + ffi::init(); + let ctx = unsafe { ffi::EVP_MD_CTX_create() }; let (evp, mdlen) = evpmd(ht); unsafe { diff --git a/src/crypto/hmac.rs b/src/crypto/hmac.rs index 4c8617ca..ef2a0414 100644 --- a/src/crypto/hmac.rs +++ b/src/crypto/hmac.rs @@ -27,6 +27,8 @@ pub struct HMAC { #[allow(non_snake_case)] pub fn HMAC(ht: hash::HashType, key: &[u8]) -> HMAC { unsafe { + ffi::init(); + let (evp, mdlen) = hash::evpmd(ht); let mut ctx : ffi::HMAC_CTX = ::std::mem::uninitialized(); diff --git a/src/crypto/pkcs5.rs b/src/crypto/pkcs5.rs index ec6e0cef..feaff9c8 100644 --- a/src/crypto/pkcs5.rs +++ b/src/crypto/pkcs5.rs @@ -9,6 +9,8 @@ pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: uint, keylen: uint) -> Ve let mut out = Vec::with_capacity(keylen); + ffi::init(); + let r = ffi::PKCS5_PBKDF2_HMAC_SHA1( pass.as_ptr(), pass.len() as c_int, salt.as_ptr(), salt.len() as c_int, diff --git a/src/crypto/pkey.rs b/src/crypto/pkey.rs index d95e7738..ac16f478 100644 --- a/src/crypto/pkey.rs +++ b/src/crypto/pkey.rs @@ -55,6 +55,8 @@ pub struct PKey { impl PKey { pub fn new() -> PKey { unsafe { + ffi::init(); + PKey { evp: ffi::EVP_PKEY_new(), parts: Neither, diff --git a/src/crypto/rand.rs b/src/crypto/rand.rs index dffddee7..5f94c93c 100644 --- a/src/crypto/rand.rs +++ b/src/crypto/rand.rs @@ -5,6 +5,7 @@ pub fn rand_bytes(len: uint) -> Vec { unsafe { let mut out = Vec::with_capacity(len); + ffi::init(); let r = ffi::RAND_bytes(out.as_mut_ptr(), len as c_int); if r != 1 as c_int { fail!() } diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index 9953ac7b..171c1b05 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -50,6 +50,8 @@ pub struct Crypter { impl Crypter { pub fn new(t: Type) -> Crypter { + ffi::init(); + let ctx = unsafe { ffi::EVP_CIPHER_CTX_new() }; let (evp, keylen, blocksz) = evpc(t); Crypter { evp: evp, ctx: ctx, keylen: keylen, blocksize: blocksz } diff --git a/src/ffi.rs b/src/ffi.rs index 4dc7b0cc..8b2cd467 100755 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,7 +1,9 @@ #![allow(non_camel_case_types, non_uppercase_statics, non_snake_case)] #![allow(dead_code)] use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; +use std::mem; use std::ptr; +use std::rt::mutex::NativeMutex; use sync::one::{Once, ONCE_INIT}; pub use bn::BIGNUM; @@ -182,13 +184,34 @@ extern {} #[link(name="wsock32")] extern { } +static mut MUTEXES: *mut Vec = 0 as *mut Vec; + +extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, + _line: c_int) { + unsafe { + let mutex = (*MUTEXES).get_mut(n as uint); + + if mode & CRYPTO_LOCK != 0 { + mutex.lock_noguard(); + } else { + mutex.unlock_noguard(); + } + } +} + pub fn init() { static mut INIT: Once = ONCE_INIT; unsafe { INIT.doit(|| { SSL_library_init(); - SSL_load_error_strings() + SSL_load_error_strings(); + + let num_locks = CRYPTO_num_locks(); + let mutexes = box Vec::from_fn(num_locks as uint, |_| NativeMutex::new()); + MUTEXES = mem::transmute(mutexes); + + CRYPTO_set_locking_callback(locking_function); }) } } diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 86b3ec83..0ed3c2e8 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -1,8 +1,7 @@ -use libc::{c_int, c_void, c_char, c_long}; +use libc::{c_int, c_void, c_long}; use std::io::{IoResult, IoError, EndOfFile, Stream, Reader, Writer}; use std::mem; use std::ptr; -use std::rt::mutex::NativeMutex; use std::string; use sync::one::{Once, ONCE_INIT}; @@ -16,7 +15,6 @@ pub mod error; mod tests; static mut VERIFY_IDX: c_int = -1; -static mut MUTEXES: *mut Vec = 0 as *mut Vec; fn init() { static mut INIT: Once = ONCE_INIT; @@ -29,12 +27,6 @@ fn init() { None, None); assert!(verify_idx >= 0); VERIFY_IDX = verify_idx; - - let num_locks = ffi::CRYPTO_num_locks(); - let mutexes = box Vec::from_fn(num_locks as uint, |_| NativeMutex::new()); - MUTEXES = mem::transmute(mutexes); - - ffi::CRYPTO_set_locking_callback(locking_function); }); } } @@ -109,19 +101,6 @@ fn get_verify_data_idx() -> c_int { } } -extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, - _line: c_int) { - unsafe { - let mutex = (*MUTEXES).get_mut(n as uint); - - if mode & ffi::CRYPTO_LOCK != 0 { - mutex.lock_noguard(); - } else { - mutex.unlock_noguard(); - } - } -} - extern fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int { unsafe { diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 88b81d7e..e3ececcc 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -272,6 +272,8 @@ impl X509Generator { /// Generates a private key and a signed certificate and returns them pub fn generate<'a>(&self) -> Result<(X509<'a>, PKey), SslError> { + ffi::init(); + let mut p_key = PKey::new(); p_key.gen(self.bits); -- cgit v1.2.3 From 3164ac0214c991b993f7b8e0b1410024eb7a7986 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 14 Oct 2014 22:39:07 +0300 Subject: Cleaned up BigNum constructors --- src/bn/mod.rs | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/bn/mod.rs b/src/bn/mod.rs index 510c9269..6311e89c 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -79,41 +79,27 @@ macro_rules! with_bn_in_ctx( ) impl BigNum { - // FIXME: squash 3 constructors into one pub fn new() -> Result { unsafe { ffi::init(); - let v = ffi::BN_new(); - if v.is_null() { - Err(SslError::get()) - } else { - Ok(BigNum(v)) - } + + let v = try_ssl_null!(ffi::BN_new()); + Ok(BigNum(v)) } } pub fn new_from(n: u64) -> Result { - unsafe { - ffi::init(); - let bn = ffi::BN_new(); - if bn.is_null() || ffi::BN_set_word(bn, n as c_ulong) == 0 { - Err(SslError::get()) - } else { - Ok(BigNum(bn)) - } - } + BigNum::new().and_then(|v| unsafe { + try_ssl!(ffi::BN_set_word(v.raw(), n as c_ulong)); + Ok(v) + }) } pub fn new_from_slice(n: &[u8]) -> Result { - unsafe { - ffi::init(); - let bn = ffi::BN_new(); - if bn.is_null() || ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, bn).is_null() { - Err(SslError::get()) - } else { - Ok(BigNum(bn)) - } - } + BigNum::new().and_then(|v| unsafe { + try_ssl_null!(ffi::BN_bin2bn(n.as_ptr(), n.len() as c_int, v.raw())); + Ok(v) + }) } pub fn checked_sqr(&self) -> Result { -- cgit v1.2.3 From e47a3cf7e2241175da9a8a9a7857dd3e02c76e53 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 14 Oct 2014 17:51:20 +0300 Subject: Cert loading from PEM & restructuring - Added cert loading - Extracted X509 tests --- src/crypto/pkey.rs | 2 +- src/ffi.rs | 11 +++++++---- src/ssl/tests.rs | 57 ++++++------------------------------------------------ src/x509/mod.rs | 37 +++++++++++++++++++++++++++++++++++ src/x509/tests.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 56 deletions(-) create mode 100644 src/x509/tests.rs (limited to 'src') diff --git a/src/crypto/pkey.rs b/src/crypto/pkey.rs index ac16f478..a04937b3 100644 --- a/src/crypto/pkey.rs +++ b/src/crypto/pkey.rs @@ -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)); diff --git a/src/ffi.rs b/src/ffi.rs index 8b2cd467..aa5758f3 100755 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -76,9 +76,9 @@ 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, - rwflag: c_int, user_data: *mut c_void) - -> 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; pub const BIO_CTRL_EOF: c_int = 2; @@ -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, + 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, user_data: *mut c_void) -> c_int; pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index a68d4967..5a47aa5f 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -1,11 +1,11 @@ -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() { @@ -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 { - 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 = 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) -> bool { @@ -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) { @@ -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 -} diff --git a/src/x509/mod.rs b/src/x509/mod.rs index e3ececcc..94934b25 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -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, @@ -322,6 +325,7 @@ impl X509Generator { } } + #[allow(dead_code)] /// A public key certificate pub struct X509<'ctx> { @@ -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, 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 } diff --git a/src/x509/tests.rs b/src/x509/tests.rs new file mode 100644 index 00000000..e4f7b142 --- /dev/null +++ b/src/x509/tests.rs @@ -0,0 +1,49 @@ +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()); +} -- cgit v1.2.3 From ebbc44bb3fda11a907fa7de3d02bebc584fb550f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 26 Oct 2014 13:10:57 -0700 Subject: Update doc location --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index edc8a2a5..14b23d60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ #![crate_name="openssl"] #![crate_type="rlib"] #![crate_type="dylib"] -#![doc(html_root_url="http://www.rust-ci.org/sfackler/rust-openssl/doc")] +#![doc(html_root_url="https://sfackler.github.io/doc/openssl")] extern crate libc; #[cfg(test)] -- cgit v1.2.3 From b41201c3c9fddf42d02f71d11b5d4718eb9e88c4 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 26 Oct 2014 21:05:27 -0700 Subject: Clean up some BN stuff --- src/bn/mod.rs | 12 +----------- src/ffi.rs | 11 +++++++++-- src/lib.rs | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) mode change 100755 => 100644 src/ffi.rs (limited to 'src') diff --git a/src/bn/mod.rs b/src/bn/mod.rs index 6311e89c..0900f478 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_ulong, c_void}; +use libc::{c_int, c_ulong}; use std::{fmt, ptr}; use std::c_str::CString; use std::num::{One, Zero}; @@ -6,16 +6,6 @@ use std::num::{One, Zero}; use ffi; use ssl::error::SslError; -#[allow(dead_code)] -#[repr(C)] -pub struct BIGNUM { - d: *mut c_void, - top: c_int, - dmax: c_int, - neg: c_int, - flags: c_int, -} - pub struct BigNum(*mut ffi::BIGNUM); #[repr(C)] diff --git a/src/ffi.rs b/src/ffi.rs old mode 100755 new mode 100644 index aa5758f3..dedff22c --- a/src/ffi.rs +++ b/src/ffi.rs @@ -6,8 +6,6 @@ use std::ptr; use std::rt::mutex::NativeMutex; use sync::one::{Once, ONCE_INIT}; -pub use bn::BIGNUM; - pub type ASN1_INTEGER = c_void; pub type ASN1_STRING = c_void; pub type ASN1_TIME = c_void; @@ -66,6 +64,15 @@ pub struct X509V3_CTX { // Maybe more here } +#[repr(C)] +pub struct BIGNUM { + pub d: *mut c_void, + pub top: c_int, + pub dmax: c_int, + pub neg: c_int, + pub flags: c_int, +} + pub type CRYPTO_EX_new = extern "C" fn(parent: *mut c_void, ptr: *mut c_void, ad: *const CRYPTO_EX_DATA, idx: c_int, argl: c_long, argp: *const c_void) -> c_int; diff --git a/src/lib.rs b/src/lib.rs index 14b23d60..8d81b70c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,6 @@ pub mod asn1; pub mod bn; pub mod bio; pub mod crypto; -pub mod ffi; +mod ffi; pub mod ssl; pub mod x509; -- cgit v1.2.3 From d10c552af6699988d685db8ec77e41276d1c8e15 Mon Sep 17 00:00:00 2001 From: pyrho Date: Tue, 28 Oct 2014 02:15:31 +0100 Subject: AES 256 CBC unit test --- src/crypto/symm.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src') diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index 171c1b05..bacee55d 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -197,6 +197,45 @@ mod tests { assert!(p1 == p0); } + #[test] + fn test_aes_256_cbc_decrypt() { + let cr = super::Crypter::new(super::AES_256_CBC); + let iv = vec![ + 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, + 69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, 0_u8, 0_u8, + 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, 0_u8, + 0_u8, 0_u8, 0_u8 + ]; + let data = [ + 143_u8, 210_u8, 75_u8, 63_u8, 214_u8, 179_u8, 155_u8, + 241_u8, 242_u8, 31_u8, 154_u8, 56_u8, 198_u8, 145_u8, 192_u8, 64_u8, + 2_u8, 245_u8, 167_u8, 220_u8, 55_u8, 119_u8, 233_u8, 136_u8, 139_u8, + 27_u8, 71_u8, 242_u8, 119_u8, 175_u8, 65_u8, 207_u8 + ]; + let ciphered_data = [ + 0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, 0xd7_u8, + 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0x65_u8, 0x6f_u8 + ]; + cr.init(super::Decrypt, data, iv); + cr.pad(false); + let unciphered_data_1 = cr.update(ciphered_data); + let unciphered_data_2 = cr.finalize(); + + // A string translating to "I love turtles." with a trailing + // 0x1 as last byte. + let expected_unciphered_data = vec![ + 0x49_u8, 0x20_u8, 0x6c_u8, 0x6f_u8, 0x76_u8, 0x65_u8, 0x20_u8, 0x74_u8, + 0x75_u8, 0x72_u8, 0x74_u8, 0x6c_u8, 0x65_u8, 0x73_u8, 0x2e_u8, 0x1_u8 + ]; + + assert!(unciphered_data_2.len() == 0); + + assert_eq!( + unciphered_data_1, + expected_unciphered_data + ); + } + fn cipher_test(ciphertype: super::Type, pt: &str, ct: &str, key: &str, iv: &str) { use serialize::hex::ToHex; -- cgit v1.2.3 From 42e9438e4ffd0d73cc3a72a08093ecfe728838b5 Mon Sep 17 00:00:00 2001 From: pyrho Date: Tue, 28 Oct 2014 14:15:13 +0100 Subject: Replaced vector of bytes with bytes string literal for expected output of AES_256_CBC deciphering unit test --- src/crypto/symm.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index bacee55d..6a823c4a 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -221,17 +221,12 @@ mod tests { let unciphered_data_1 = cr.update(ciphered_data); let unciphered_data_2 = cr.finalize(); - // A string translating to "I love turtles." with a trailing - // 0x1 as last byte. - let expected_unciphered_data = vec![ - 0x49_u8, 0x20_u8, 0x6c_u8, 0x6f_u8, 0x76_u8, 0x65_u8, 0x20_u8, 0x74_u8, - 0x75_u8, 0x72_u8, 0x74_u8, 0x6c_u8, 0x65_u8, 0x73_u8, 0x2e_u8, 0x1_u8 - ]; + let expected_unciphered_data = b"I love turtles.\x01"; assert!(unciphered_data_2.len() == 0); assert_eq!( - unciphered_data_1, + unciphered_data_1.as_slice(), expected_unciphered_data ); } -- cgit v1.2.3 From 1eb79df25abf3eede1f9d799992927986ce8c7a0 Mon Sep 17 00:00:00 2001 From: Michael Gehring Date: Thu, 30 Oct 2014 09:58:22 +0100 Subject: fail! -> panic! --- src/bn/mod.rs | 2 +- src/crypto/memcmp.rs | 2 +- src/crypto/pkcs5.rs | 2 +- src/crypto/rand.rs | 2 +- src/crypto/symm.rs | 2 +- src/ssl/error.rs | 2 +- src/ssl/tests.rs | 18 +++++++++--------- src/x509/mod.rs | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/bn/mod.rs b/src/bn/mod.rs index 6311e89c..5a1b9b65 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -483,7 +483,7 @@ pub mod unchecked { unsafe { let r = ffi::BN_dup(self.raw()); if r.is_null() { - fail!("Unexpected null pointer from BN_dup(..)") + panic!("Unexpected null pointer from BN_dup(..)") } else { BigNum(r) } diff --git a/src/crypto/memcmp.rs b/src/crypto/memcmp.rs index c30281d4..7473fcab 100644 --- a/src/crypto/memcmp.rs +++ b/src/crypto/memcmp.rs @@ -8,7 +8,7 @@ use ffi; /// /// # Failure /// -/// This function will fail the current task if `a` and `b` do not have the same +/// This function will panic the current task if `a` and `b` do not have the same /// length. pub fn eq(a: &[u8], b: &[u8]) -> bool { assert!(a.len() == b.len()); diff --git a/src/crypto/pkcs5.rs b/src/crypto/pkcs5.rs index feaff9c8..6efd23ff 100644 --- a/src/crypto/pkcs5.rs +++ b/src/crypto/pkcs5.rs @@ -17,7 +17,7 @@ pub fn pbkdf2_hmac_sha1(pass: &str, salt: &[u8], iter: uint, keylen: uint) -> Ve iter as c_int, keylen as c_int, out.as_mut_ptr()); - if r != 1 { fail!(); } + if r != 1 { panic!(); } out.set_len(keylen); diff --git a/src/crypto/rand.rs b/src/crypto/rand.rs index 5f94c93c..92d38f2c 100644 --- a/src/crypto/rand.rs +++ b/src/crypto/rand.rs @@ -7,7 +7,7 @@ pub fn rand_bytes(len: uint) -> Vec { ffi::init(); let r = ffi::RAND_bytes(out.as_mut_ptr(), len as c_int); - if r != 1 as c_int { fail!() } + if r != 1 as c_int { panic!() } out.set_len(len); diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index 171c1b05..954fa298 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -214,7 +214,7 @@ mod tests { println!("Lengths differ: {} in computed vs {} expected", computed.len(), expected.len()); } - fail!("test failure"); + panic!("test failure"); } } diff --git a/src/ssl/error.rs b/src/ssl/error.rs index 5af6c866..7066299f 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -74,7 +74,7 @@ impl SslError { fn test_uknown_error_should_have_correct_messages() { let errs = match SslError::from_error(336032784) { OpenSslErrors(errs) => errs, - _ => fail!("This should always be an `OpenSslErrors` variant.") + _ => panic!("This should always be an `OpenSslErrors` variant.") }; let UnknownError { ref library, ref function, ref reason } = errs[0]; diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 5a47aa5f..c5abdd52 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -24,7 +24,7 @@ fn test_verify_untrusted() { let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, None); match SslStream::new(&ctx, stream) { - Ok(_) => fail!("expected failure"), + Ok(_) => panic!("expected failure"), Err(err) => println!("error {}", err) } } @@ -36,11 +36,11 @@ fn test_verify_trusted() { ctx.set_verify(SslVerifyPeer, None); match ctx.set_CA_file(&Path::new("test/cert.pem")) { None => {} - Some(err) => fail!("Unexpected error {}", err) + Some(err) => panic!("Unexpected error {}", err) } match SslStream::new(&ctx, stream) { Ok(_) => (), - Err(err) => fail!("Expected success, got {}", err) + Err(err) => panic!("Expected success, got {}", err) } } @@ -54,7 +54,7 @@ fn test_verify_untrusted_callback_override_ok() { ctx.set_verify(SslVerifyPeer, Some(callback)); match SslStream::new(&ctx, stream) { Ok(_) => (), - Err(err) => fail!("Expected success, got {}", err) + Err(err) => panic!("Expected success, got {}", err) } } @@ -79,11 +79,11 @@ fn test_verify_trusted_callback_override_ok() { ctx.set_verify(SslVerifyPeer, Some(callback)); match ctx.set_CA_file(&Path::new("test/cert.pem")) { None => {} - Some(err) => fail!("Unexpected error {}", err) + Some(err) => panic!("Unexpected error {}", err) } match SslStream::new(&ctx, stream) { Ok(_) => (), - Err(err) => fail!("Expected success, got {}", err) + Err(err) => panic!("Expected success, got {}", err) } } @@ -97,7 +97,7 @@ fn test_verify_trusted_callback_override_bad() { ctx.set_verify(SslVerifyPeer, Some(callback)); match ctx.set_CA_file(&Path::new("test/cert.pem")) { None => {} - Some(err) => fail!("Unexpected error {}", err) + Some(err) => panic!("Unexpected error {}", err) } assert!(SslStream::new(&ctx, stream).is_err()); } @@ -125,7 +125,7 @@ fn test_verify_trusted_get_error_ok() { ctx.set_verify(SslVerifyPeer, Some(callback)); match ctx.set_CA_file(&Path::new("test/cert.pem")) { None => {} - Some(err) => fail!("Unexpected error {}", err) + Some(err) => panic!("Unexpected error {}", err) } assert!(SslStream::new(&ctx, stream).is_ok()); } @@ -168,7 +168,7 @@ fn test_verify_callback_data() { match SslStream::new(&ctx, stream) { Ok(_) => (), - Err(err) => fail!("Expected success, got {}", err) + Err(err) => panic!("Expected success, got {}", err) } } diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 94934b25..48b5d455 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -390,7 +390,7 @@ impl<'ctx> X509<'ctx> { match len.cmp(&act_len) { Greater => None, Equal => Some(v), - Less => fail!("Fingerprint buffer was corrupted!") + Less => panic!("Fingerprint buffer was corrupted!") } } } -- cgit v1.2.3 From 1e706b8ef4d4344b5297b90bcd430cc96f40fb39 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 31 Oct 2014 19:14:30 -0700 Subject: Clean up some warnings --- src/ffi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index dedff22c..e661d205 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -1,4 +1,4 @@ -#![allow(non_camel_case_types, non_uppercase_statics, non_snake_case)] +#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] #![allow(dead_code)] use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; use std::mem; @@ -196,7 +196,7 @@ static mut MUTEXES: *mut Vec = 0 as *mut Vec; extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, _line: c_int) { unsafe { - let mutex = (*MUTEXES).get_mut(n as uint); + let mutex = &(*MUTEXES)[n as uint]; if mode & CRYPTO_LOCK != 0 { mutex.lock_noguard(); -- cgit v1.2.3 From 89fb825e78ecfc22b2c4186fd9ab97beab18efb0 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Fri, 7 Nov 2014 13:46:53 -0500 Subject: Update to work with change in TcpStream api --- src/ssl/tests.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index c5abdd52..f9f941a9 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -14,13 +14,13 @@ fn test_new_ctx() { #[test] fn test_new_sslstream() { - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); SslStream::new(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); } #[test] fn test_verify_untrusted() { - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, None); match SslStream::new(&ctx, stream) { @@ -31,7 +31,7 @@ fn test_verify_untrusted() { #[test] fn test_verify_trusted() { - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, None); match ctx.set_CA_file(&Path::new("test/cert.pem")) { @@ -49,7 +49,7 @@ fn test_verify_untrusted_callback_override_ok() { fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool { true } - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); match SslStream::new(&ctx, stream) { @@ -63,7 +63,7 @@ fn test_verify_untrusted_callback_override_bad() { fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool { false } - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(SslStream::new(&ctx, stream).is_err()); @@ -74,7 +74,7 @@ fn test_verify_trusted_callback_override_ok() { fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool { true } - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); match ctx.set_CA_file(&Path::new("test/cert.pem")) { @@ -92,7 +92,7 @@ fn test_verify_trusted_callback_override_bad() { fn callback(_preverify_ok: bool, _x509_ctx: &X509StoreContext) -> bool { false } - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); match ctx.set_CA_file(&Path::new("test/cert.pem")) { @@ -108,7 +108,7 @@ fn test_verify_callback_load_certs() { assert!(x509_ctx.get_current_cert().is_some()); true } - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(SslStream::new(&ctx, stream).is_ok()); @@ -120,7 +120,7 @@ fn test_verify_trusted_get_error_ok() { assert!(x509_ctx.get_error().is_none()); true } - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); match ctx.set_CA_file(&Path::new("test/cert.pem")) { @@ -136,7 +136,7 @@ fn test_verify_trusted_get_error_err() { assert!(x509_ctx.get_error().is_some()); false } - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(SslStream::new(&ctx, stream).is_err()); @@ -154,7 +154,7 @@ fn test_verify_callback_data() { } } } - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap(); // Node id was generated as SHA256 hash of certificate "test/cert.pem" @@ -175,7 +175,7 @@ fn test_verify_callback_data() { #[test] fn test_write() { - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut stream = SslStream::new(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); stream.write("hello".as_bytes()).unwrap(); stream.flush().unwrap(); @@ -185,7 +185,7 @@ fn test_write() { #[test] fn test_read() { - let stream = TcpStream::connect("127.0.0.1", 15418).unwrap(); + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); let mut stream = SslStream::new(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); stream.write("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); -- cgit v1.2.3 From b9f95b4ce4887c481ac4934e02a7a3aca4a316a6 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Fri, 7 Nov 2014 12:19:01 -0500 Subject: crypto/hash: impl Writer for Hasher to allow use of Reader-Writer convenience functions --- src/crypto/hash.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index a72b8d9f..60517adf 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -1,5 +1,6 @@ use libc::c_uint; use std::ptr; +use std::io; use ffi; @@ -34,6 +35,13 @@ pub struct Hasher { len: uint, } +impl io::Writer for Hasher { + fn write(&mut self, buf: &[u8]) -> io::IoResult<()> { + self.update(buf); + Ok(()) + } +} + impl Hasher { pub fn new(ht: HashType) -> Hasher { ffi::init(); -- cgit v1.2.3 From 3cbc5182496297abab0918430a9d5e72295c0b24 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Fri, 7 Nov 2014 16:56:00 -0500 Subject: Hasher::write(): add basic test --- src/crypto/hash.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index 60517adf..b00dfba8 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -120,6 +120,12 @@ mod tests { assert!(calced == hashtest.expected_output); } + pub fn hash_writer(t: super::HashType, data: &[u8]) -> Vec { + let mut h = super::Hasher::new(t); + h.write(data); + h.finalize() + } + // Test vectors from http://www.nsrl.nist.gov/testdata/ #[test] fn test_md5() { @@ -175,4 +181,11 @@ mod tests { hash_test(super::RIPEMD160, test); } } + + #[test] + fn test_writer() { + let tv = "rust-openssl".as_bytes(); + let ht = super::RIPEMD160; + assert!(hash_writer(ht, tv) == super::hash(ht, tv)); + } } -- cgit v1.2.3 From 019e47020a52c0e4409739837ef653f7837f2e1c Mon Sep 17 00:00:00 2001 From: Richard Diamond Date: Sun, 9 Nov 2014 23:07:59 -0600 Subject: Support PNaCl/NaCl. --- src/ffi.rs | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs index e661d205..e67f444d 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -176,20 +176,26 @@ pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; pub const X509_V_OK: c_int = 0; -#[cfg( any( all(target_os = "macos", feature = "tlsv1_1"),all(target_os = "macos", feature = "tlsv1_2")))] -#[link(name="ssl.1.0.0")] -#[link(name="crypto.1.0.0")] -extern {} - -#[cfg(any( not( target_os = "macos"), all(target_os = "macos", not(feature = "tlsv1_1"), not(feature = "tlsv1_2"))))] -#[link(name="ssl")] -#[link(name="crypto")] -extern {} - -#[cfg(target_os = "win32")] -#[link(name="gdi32")] -#[link(name="wsock32")] -extern { } +#[cfg(not(target_os = "nacl"))] +mod link { + #[cfg( any( all(target_os = "macos", feature = "tlsv1_1"), + all(target_os = "macos", feature = "tlsv1_2")))] + #[link(name="ssl.1.0.0")] + #[link(name="crypto.1.0.0")] + extern {} + + #[cfg(any( not( target_os = "macos"), + all(target_os = "macos", not(feature = "tlsv1_1"), + not(feature = "tlsv1_2"))))] + #[link(name="ssl")] + #[link(name="crypto")] + extern {} + + #[cfg(target_os = "win32")] + #[link(name="gdi32")] + #[link(name="wsock32")] + extern { } +} static mut MUTEXES: *mut Vec = 0 as *mut Vec; -- cgit v1.2.3 From c2717cd98c88c80e165b44d6ce1fdd7d2fad155e Mon Sep 17 00:00:00 2001 From: Richard Diamond Date: Sun, 9 Nov 2014 23:40:46 -0600 Subject: Force linkage of LibreSSL when targeting NaCl OSs. --- src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 8d81b70c..456c8c7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,9 @@ extern crate libc; extern crate serialize; extern crate sync; +#[cfg(target_os = "nacl")] +extern crate "openssl-sys" as _unused; + mod macros; pub mod asn1; -- cgit v1.2.3 From b60d140d3d18c1e8b226036bd8e39e8a87264fb7 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Tue, 11 Nov 2014 16:54:17 +0200 Subject: New build system --- src/ffi.rs | 481 ------------------------------------------------------------- src/lib.rs | 4 +- 2 files changed, 1 insertion(+), 484 deletions(-) delete mode 100644 src/ffi.rs (limited to 'src') diff --git a/src/ffi.rs b/src/ffi.rs deleted file mode 100644 index e67f444d..00000000 --- a/src/ffi.rs +++ /dev/null @@ -1,481 +0,0 @@ -#![allow(non_camel_case_types, non_upper_case_globals, non_snake_case)] -#![allow(dead_code)] -use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t}; -use std::mem; -use std::ptr; -use std::rt::mutex::NativeMutex; -use sync::one::{Once, ONCE_INIT}; - -pub type ASN1_INTEGER = c_void; -pub type ASN1_STRING = c_void; -pub type ASN1_TIME = c_void; -pub type BIO = c_void; -pub type BIO_METHOD = c_void; -pub type BN_CTX = c_void; -pub type COMP_METHOD = c_void; -pub type CRYPTO_EX_DATA = c_void; -pub type ENGINE = c_void; -pub type EVP_CIPHER = c_void; -pub type EVP_CIPHER_CTX = c_void; -pub type EVP_MD = c_void; -pub type EVP_PKEY = c_void; -pub type EVP_PKEY_CTX = c_void; -pub type RSA = c_void; -pub type SSL = c_void; -pub type SSL_CTX = c_void; -pub type SSL_METHOD = c_void; -pub type X509 = c_void; -pub type X509_CRL = c_void; -pub type X509_EXTENSION = c_void; -pub type X509_NAME = c_void; -pub type X509_REQ = c_void; -pub type X509_STORE_CTX = c_void; - -#[repr(C)] -pub struct EVP_MD_CTX { - digest: *mut EVP_MD, - engine: *mut c_void, - flags: c_ulong, - md_data: *mut c_void, - pctx: *mut EVP_PKEY_CTX, - update: *mut c_void -} - -#[repr(C)] -pub struct HMAC_CTX { - md: *mut EVP_MD, - md_ctx: EVP_MD_CTX, - i_ctx: EVP_MD_CTX, - o_ctx: EVP_MD_CTX, - key_length: c_uint, - key: [c_uchar, ..128] -} - -#[repr(C)] -pub struct X509V3_CTX { - flags: c_int, - issuer_cert: *mut c_void, - subject_cert: *mut c_void, - subject_req: *mut c_void, - crl: *mut c_void, - db_meth: *mut c_void, - db: *mut c_void, - // I like the last comment line, it is copied from OpenSSL sources: - // Maybe more here -} - -#[repr(C)] -pub struct BIGNUM { - pub d: *mut c_void, - pub top: c_int, - pub dmax: c_int, - pub neg: c_int, - pub flags: c_int, -} - -pub type CRYPTO_EX_new = extern "C" fn(parent: *mut c_void, ptr: *mut c_void, - ad: *const CRYPTO_EX_DATA, idx: c_int, - argl: c_long, argp: *const c_void) -> c_int; -pub type CRYPTO_EX_dup = extern "C" fn(to: *mut CRYPTO_EX_DATA, - from: *mut CRYPTO_EX_DATA, from_d: *mut c_void, - idx: c_int, argl: c_long, argp: *mut c_void) - -> c_int; -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 PasswordCallback = extern "C" fn(buf: *mut c_char, size: c_int, - rwflag: c_int, user_data: *mut c_void) - -> c_int; - -pub const BIO_CTRL_EOF: c_int = 2; - -pub const CRYPTO_LOCK: c_int = 1; - -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; -pub const MBSTRING_UNIV: c_int = MBSTRING_FLAG | 4; -pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG; - -pub const NID_ext_key_usage: c_int = 126; -pub const NID_key_usage: c_int = 83; - -pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; -pub const SSL_ERROR_NONE: c_int = 0; -pub const SSL_ERROR_SSL: c_int = 1; -pub const SSL_ERROR_SYSCALL: c_int = 5; -pub const SSL_ERROR_WANT_ACCEPT: c_int = 8; -pub const SSL_ERROR_WANT_CONNECT: c_int = 7; -pub const SSL_ERROR_WANT_READ: c_int = 2; -pub const SSL_ERROR_WANT_WRITE: c_int = 3; -pub const SSL_ERROR_WANT_X509_LOOKUP: c_int = 4; -pub const SSL_ERROR_ZERO_RETURN: c_int = 6; -pub const SSL_VERIFY_NONE: c_int = 0; -pub const SSL_VERIFY_PEER: c_int = 1; - -pub const TLSEXT_NAMETYPE_host_name: c_long = 0; - -pub const V_ASN1_GENERALIZEDTIME: c_int = 24; -pub const V_ASN1_UTCTIME: c_int = 23; - -pub const X509_FILETYPE_ASN1: c_int = 2; -pub const X509_FILETYPE_DEFAULT: c_int = 3; -pub const X509_FILETYPE_PEM: c_int = 1; -pub const X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: c_int = 31; -pub const X509_V_ERR_AKID_SKID_MISMATCH: c_int = 30; -pub const X509_V_ERR_APPLICATION_VERIFICATION: c_int = 50; -pub const X509_V_ERR_CERT_CHAIN_TOO_LONG: c_int = 22; -pub const X509_V_ERR_CERT_HAS_EXPIRED: c_int = 10; -pub const X509_V_ERR_CERT_NOT_YET_VALID: c_int = 9; -pub const X509_V_ERR_CERT_REJECTED: c_int = 28; -pub const X509_V_ERR_CERT_REVOKED: c_int = 23; -pub const X509_V_ERR_CERT_SIGNATURE_FAILURE: c_int = 7; -pub const X509_V_ERR_CERT_UNTRUSTED: c_int = 27; -pub const X509_V_ERR_CRL_HAS_EXPIRED: c_int = 12; -pub const X509_V_ERR_CRL_NOT_YET_VALID: c_int = 11; -pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; -pub const X509_V_ERR_CRL_SIGNATURE_FAILURE: c_int = 8; -pub const X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: c_int = 18; -pub const X509_V_ERR_DIFFERENT_CRL_SCOPE: c_int = 44; -pub const X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: c_int = 14; -pub const X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: c_int = 13; -pub const X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: c_int = 15; -pub const X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: c_int = 16; -pub const X509_V_ERR_EXCLUDED_VIOLATION: c_int = 48; -pub const X509_V_ERR_INVALID_CA: c_int = 24; -pub const X509_V_ERR_INVALID_EXTENSION: c_int = 41; -pub const X509_V_ERR_INVALID_NON_CA: c_int = 37; -pub const X509_V_ERR_INVALID_POLICY_EXTENSION: c_int = 42; -pub const X509_V_ERR_INVALID_PURPOSE: c_int = 26; -pub const X509_V_ERR_KEYUSAGE_NO_CERTSIGN: c_int = 32; -pub const X509_V_ERR_KEYUSAGE_NO_CRL_SIGN: c_int = 35; -pub const X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE: c_int = 39; -pub const X509_V_ERR_NO_EXPLICIT_POLICY: c_int = 43; -pub const X509_V_ERR_OUT_OF_MEM: c_int = 17; -pub const X509_V_ERR_PATH_LENGTH_EXCEEDED: c_int = 25; -pub const X509_V_ERR_PERMITTED_VIOLATION: c_int = 47; -pub const X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED: c_int = 40; -pub const X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED: c_int = 38; -pub const X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: c_int = 19; -pub const X509_V_ERR_SUBJECT_ISSUER_MISMATCH: c_int = 29; -pub const X509_V_ERR_SUBTREE_MINMAX: c_int = 49; -pub const X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: c_int = 6; -pub const X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: c_int = 4; -pub const X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: c_int = 5; -pub const X509_V_ERR_UNABLE_TO_GET_CRL: c_int = 3; -pub const X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: c_int = 33; -pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: c_int = 2; -pub const X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: c_int = 20; -pub const X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: c_int = 21; -pub const X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION: c_int = 36; -pub const X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: c_int = 34; -pub const X509_V_ERR_UNNESTED_RESOURCE: c_int = 46; -pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; -pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE: c_int = 51; -pub const X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE: c_int = 45; -pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; -pub const X509_V_OK: c_int = 0; - -#[cfg(not(target_os = "nacl"))] -mod link { - #[cfg( any( all(target_os = "macos", feature = "tlsv1_1"), - all(target_os = "macos", feature = "tlsv1_2")))] - #[link(name="ssl.1.0.0")] - #[link(name="crypto.1.0.0")] - extern {} - - #[cfg(any( not( target_os = "macos"), - all(target_os = "macos", not(feature = "tlsv1_1"), - not(feature = "tlsv1_2"))))] - #[link(name="ssl")] - #[link(name="crypto")] - extern {} - - #[cfg(target_os = "win32")] - #[link(name="gdi32")] - #[link(name="wsock32")] - extern { } -} - -static mut MUTEXES: *mut Vec = 0 as *mut Vec; - -extern fn locking_function(mode: c_int, n: c_int, _file: *const c_char, - _line: c_int) { - unsafe { - let mutex = &(*MUTEXES)[n as uint]; - - if mode & CRYPTO_LOCK != 0 { - mutex.lock_noguard(); - } else { - mutex.unlock_noguard(); - } - } -} - -pub fn init() { - static mut INIT: Once = ONCE_INIT; - - unsafe { - INIT.doit(|| { - SSL_library_init(); - SSL_load_error_strings(); - - let num_locks = CRYPTO_num_locks(); - let mutexes = box Vec::from_fn(num_locks as uint, |_| NativeMutex::new()); - MUTEXES = mem::transmute(mutexes); - - CRYPTO_set_locking_callback(locking_function); - }) - } -} - -// Functions converted from macros -pub unsafe fn BIO_eof(b: *mut BIO) -> bool { - BIO_ctrl(b, BIO_CTRL_EOF, 0, ptr::null_mut()) == 1 -} - -// True functions -extern "C" { - pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; - pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; - pub fn ASN1_TIME_free(tm: *mut ASN1_TIME); - - pub fn BIO_ctrl(b: *mut BIO, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; - pub fn BIO_free_all(b: *mut BIO); - pub fn BIO_new(type_: *const BIO_METHOD) -> *mut BIO; - pub fn BIO_read(b: *mut BIO, buf: *mut c_void, len: c_int) -> c_int; - pub fn BIO_write(b: *mut BIO, buf: *const c_void, len: c_int) -> c_int; - pub fn BIO_s_mem() -> *const BIO_METHOD; - - pub fn BN_new() -> *mut BIGNUM; - pub fn BN_dup(n: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_clear_free(bn: *mut BIGNUM); - - pub fn BN_CTX_new() -> *mut BN_CTX; - pub fn BN_CTX_free(ctx: *mut BN_CTX); - - pub fn BN_num_bits(bn: *mut BIGNUM) -> c_int; - pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int); - pub fn BN_set_word(bn: *mut BIGNUM, n: c_ulong) -> c_int; - - /* Arithmetic operations on BIGNUMs */ - pub fn BN_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - pub fn BN_div(dv: *mut BIGNUM, rem: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_gcd(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_add(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_exp(r: *mut BIGNUM, a: *mut BIGNUM, p: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_inverse(r: *mut BIGNUM, a: *mut BIGNUM, n: *mut BIGNUM, ctx: *mut BN_CTX) -> *const BIGNUM; - pub fn BN_mod_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_sqr(r: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mod_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_mul(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_nnmod(rem: *mut BIGNUM, a: *mut BIGNUM, m: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_sqr(r: *mut BIGNUM, a: *mut BIGNUM, ctx: *mut BN_CTX) -> c_int; - pub fn BN_sub(r: *mut BIGNUM, a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - - /* Bit operations on BIGNUMs */ - pub fn BN_clear_bit(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_is_bit_set(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_lshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_lshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int; - pub fn BN_mask_bits(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_rshift(r: *mut BIGNUM, a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_set_bit(a: *mut BIGNUM, n: c_int) -> c_int; - pub fn BN_rshift1(r: *mut BIGNUM, a: *mut BIGNUM) -> c_int; - - /* Comparisons on BIGNUMs */ - pub fn BN_cmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - pub fn BN_ucmp(a: *mut BIGNUM, b: *mut BIGNUM) -> c_int; - - /* Prime handling */ - pub fn BN_generate_prime_ex(r: *mut BIGNUM, bits: c_int, safe: c_int, add: *mut BIGNUM, rem: *mut BIGNUM, cb: *const c_void) -> c_int; - pub fn BN_is_prime_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, cb: *const c_void) -> c_int; - pub fn BN_is_prime_fasttest_ex(p: *mut BIGNUM, checks: c_int, ctx: *mut BN_CTX, do_trial_division: c_int, cb: *const c_void) -> c_int; - - /* Random number handling */ - pub fn BN_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; - pub fn BN_pseudo_rand(r: *mut BIGNUM, bits: c_int, top: c_int, bottom: c_int) -> c_int; - pub fn BN_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int; - pub fn BN_pseudo_rand_range(r: *mut BIGNUM, range: *mut BIGNUM) -> c_int; - - /* Conversion from/to binary representation */ - pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; - pub fn BN_bn2bin(a: *mut BIGNUM, to: *mut u8) -> c_int; - - /* Conversion from/to string representation */ - pub fn BN_bn2dec(a: *mut BIGNUM) -> *const c_char; - - pub fn CRYPTO_num_locks() -> c_int; - pub fn CRYPTO_set_locking_callback(func: extern "C" fn(mode: c_int, - n: c_int, - file: *const c_char, - line: c_int)); - pub fn CRYPTO_free(buf: *const c_char); - pub fn CRYPTO_memcmp(a: *const c_void, b: *const c_void, - len: size_t) -> c_int; - - pub fn ERR_get_error() -> c_ulong; - - pub fn ERR_lib_error_string(err: c_ulong) -> *const c_char; - pub fn ERR_func_error_string(err: c_ulong) -> *const c_char; - pub fn ERR_reason_error_string(err: c_ulong) -> *const c_char; - - pub fn ERR_load_crypto_strings(); - - pub fn EVP_md5() -> *const EVP_MD; - pub fn EVP_ripemd160() -> *const EVP_MD; - pub fn EVP_sha1() -> *const EVP_MD; - pub fn EVP_sha224() -> *const EVP_MD; - pub fn EVP_sha256() -> *const EVP_MD; - pub fn EVP_sha384() -> *const EVP_MD; - pub fn EVP_sha512() -> *const EVP_MD; - - pub fn EVP_aes_128_cbc() -> *const EVP_CIPHER; - pub fn EVP_aes_128_ecb() -> *const EVP_CIPHER; - // fn EVP_aes_128_ctr() -> EVP_CIPHER; - // fn EVP_aes_128_gcm() -> EVP_CIPHER; - pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER; - pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER; - // fn EVP_aes_256_ctr() -> EVP_CIPHER; - // fn EVP_aes_256_gcm() -> EVP_CIPHER; - pub fn EVP_rc4() -> *const EVP_CIPHER; - - pub fn EVP_CIPHER_CTX_new() -> *mut EVP_CIPHER_CTX; - pub fn EVP_CIPHER_CTX_set_padding(ctx: *mut EVP_CIPHER_CTX, padding: c_int); - pub fn EVP_CIPHER_CTX_free(ctx: *mut EVP_CIPHER_CTX); - - pub fn EVP_CipherInit(ctx: *mut EVP_CIPHER_CTX, evp: *const EVP_CIPHER, - key: *const u8, iv: *const u8, mode: c_int); - pub fn EVP_CipherUpdate(ctx: *mut EVP_CIPHER_CTX, outbuf: *mut u8, - outlen: &mut c_uint, inbuf: *const u8, inlen: c_int); - pub fn EVP_CipherFinal(ctx: *mut EVP_CIPHER_CTX, res: *mut u8, len: &mut c_int); - - pub fn EVP_DigestInit(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD); - pub fn EVP_DigestUpdate(ctx: *mut EVP_MD_CTX, data: *const u8, n: c_uint); - pub fn EVP_DigestFinal(ctx: *mut EVP_MD_CTX, res: *mut u8, n: *mut u32); - - pub fn EVP_MD_CTX_create() -> *mut EVP_MD_CTX; - pub fn EVP_MD_CTX_destroy(ctx: *mut EVP_MD_CTX); - - pub fn EVP_PKEY_new() -> *mut EVP_PKEY; - pub fn EVP_PKEY_free(k: *mut EVP_PKEY); - pub fn EVP_PKEY_assign(pkey: *mut EVP_PKEY, typ: c_int, key: *const c_char) -> c_int; - pub fn EVP_PKEY_get1_RSA(k: *mut EVP_PKEY) -> *mut RSA; - pub fn EVP_PKEY_set1_RSA(k: *mut EVP_PKEY, r: *mut RSA) -> c_int; - - pub fn HMAC_CTX_init(ctx: *mut HMAC_CTX); - pub fn HMAC_Init_ex(ctx: *mut HMAC_CTX, key: *const u8, keylen: c_int, md: *const EVP_MD, imple: *const ENGINE); - 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, - 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: Option, - user_data: *mut c_void) -> c_int; - pub fn PEM_write_bio_X509(bio: *mut BIO, x509: *mut X509) -> c_int; - - pub fn PKCS5_PBKDF2_HMAC_SHA1(pass: *const u8, passlen: c_int, - salt: *const u8, saltlen: c_int, - iter: c_int, keylen: c_int, - out: *mut u8) -> c_int; - - - pub fn RAND_bytes(buf: *mut u8, num: c_int) -> c_int; - - pub fn RSA_generate_key(modsz: c_uint, e: c_uint, cb: *const u8, cbarg: *const u8) -> *mut RSA; - pub fn RSA_private_decrypt(flen: c_uint, from: *const u8, to: *mut u8, k: *mut RSA, - pad: c_int) -> c_int; - pub fn RSA_public_encrypt(flen: c_uint, from: *const u8, to: *mut u8, k: *mut RSA, - pad: c_int) -> c_int; - pub fn RSA_sign(t: c_int, m: *const u8, mlen: c_uint, sig: *mut u8, siglen: *mut c_uint, - k: *mut RSA) -> c_int; - pub fn RSA_size(k: *mut RSA) -> c_uint; - pub fn RSA_verify(t: c_int, m: *const u8, mlen: c_uint, sig: *const u8, siglen: c_uint, - k: *mut RSA) -> c_int; - - pub fn SSL_library_init() -> c_int; - - pub fn SSL_load_error_strings(); - - #[cfg(feature = "sslv2")] - pub fn SSLv2_method() -> *const SSL_METHOD; - pub fn SSLv3_method() -> *const SSL_METHOD; - pub fn TLSv1_method() -> *const SSL_METHOD; - #[cfg(feature = "tlsv1_1")] - pub fn TLSv1_1_method() -> *const SSL_METHOD; - #[cfg(feature = "tlsv1_2")] - pub fn TLSv1_2_method() -> *const SSL_METHOD; - pub fn SSLv23_method() -> *const SSL_METHOD; - - pub fn SSL_new(ctx: *mut SSL_CTX) -> *mut SSL; - pub fn SSL_free(ssl: *mut SSL); - pub fn SSL_set_bio(ssl: *mut SSL, rbio: *mut BIO, wbio: *mut BIO); - pub fn SSL_get_rbio(ssl: *mut SSL) -> *mut BIO; - pub fn SSL_get_wbio(ssl: *mut SSL) -> *mut BIO; - pub fn SSL_connect(ssl: *mut SSL) -> c_int; - pub fn SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, - parg: *mut c_void) -> c_long; - pub fn SSL_get_error(ssl: *mut SSL, ret: c_int) -> c_int; - pub fn SSL_read(ssl: *mut SSL, buf: *mut c_void, num: c_int) -> c_int; - pub fn SSL_write(ssl: *mut SSL, buf: *const c_void, num: c_int) -> c_int; - pub fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int; - pub fn SSL_get_SSL_CTX(ssl: *mut SSL) -> *mut SSL_CTX; - pub fn SSL_get_current_compression(ssl: *mut SSL) -> *const COMP_METHOD; - - pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char; - - pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX; - pub fn SSL_CTX_free(ctx: *mut SSL_CTX); - pub fn SSL_CTX_set_verify(ctx: *mut SSL_CTX, mode: c_int, - verify_callback: Option c_int>); - pub fn SSL_CTX_set_verify_depth(ctx: *mut SSL_CTX, depth: c_int); - pub fn SSL_CTX_load_verify_locations(ctx: *mut SSL_CTX, CAfile: *const c_char, - CApath: *const c_char) -> c_int; - pub fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *const c_void, - new_func: Option, - dup_func: Option, - free_func: Option) - -> c_int; - pub fn SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) - -> c_int; - pub fn SSL_CTX_get_ex_data(ctx: *mut SSL_CTX, idx: c_int) -> *mut c_void; - - pub fn SSL_CTX_use_certificate_file(ctx: *mut SSL_CTX, cert_file: *const c_char, file_type: c_int) -> c_int; - pub fn SSL_CTX_use_PrivateKey_file(ctx: *mut SSL_CTX, key_file: *const c_char, file_type: c_int) -> c_int; - - pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; - - pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; - pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; - pub fn X509_free(x: *mut X509); - pub fn X509_get_serialNumber(x: *mut X509) -> *mut ASN1_INTEGER; - pub fn X509_get_subject_name(x: *mut X509) -> *mut X509_NAME; - pub fn X509_gmtime_adj(time: *mut ASN1_TIME, adj: c_long) -> *mut ASN1_TIME; - pub fn X509_new() -> *mut X509; - pub fn X509_set_issuer_name(x: *mut X509, name: *mut X509_NAME) -> c_int; - pub fn X509_set_notAfter(x: *mut X509, tm: *const ASN1_TIME) -> c_int; - pub fn X509_set_notBefore(x: *mut X509, tm: *const ASN1_TIME) -> c_int; - pub fn X509_set_version(x: *mut X509, version: c_ulong) -> c_int; - pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; - pub fn X509_sign(x: *mut X509, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; - - pub fn X509_EXTENSION_free(ext: *mut X509_EXTENSION); - - pub fn X509_NAME_add_entry_by_txt(x: *mut X509, field: *const c_char, ty: c_int, bytes: *const c_char, len: c_int, loc: c_int, set: c_int) -> c_int; - - pub fn X509_STORE_CTX_get_current_cert(ct: *mut X509_STORE_CTX) -> *mut X509; - pub fn X509_STORE_CTX_get_error(ctx: *mut X509_STORE_CTX) -> c_int; - pub fn X509_STORE_CTX_get_ex_data(ctx: *mut X509_STORE_CTX, idx: c_int) -> *mut c_void; - - pub fn X509V3_EXT_conf_nid(conf: *mut c_void, ctx: *mut X509V3_CTX, ext_nid: c_int, value: *mut c_char) -> *mut X509_EXTENSION; - pub fn X509V3_set_ctx(ctx: *mut X509V3_CTX, issuer: *mut X509, subject: *mut X509, req: *mut X509_REQ, crl: *mut X509_CRL, flags: c_int); - - pub fn i2d_RSA_PUBKEY(k: *mut RSA, buf: *const *mut u8) -> c_int; - pub fn d2i_RSA_PUBKEY(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; - pub fn i2d_RSAPrivateKey(k: *mut RSA, buf: *const *mut u8) -> c_int; - pub fn d2i_RSAPrivateKey(k: *const *mut RSA, buf: *const *const u8, len: c_uint) -> *mut RSA; -} diff --git a/src/lib.rs b/src/lib.rs index 456c8c7d..a974e399 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,8 +9,7 @@ extern crate libc; extern crate serialize; extern crate sync; -#[cfg(target_os = "nacl")] -extern crate "openssl-sys" as _unused; +extern crate "openssl-sys" as ffi; mod macros; @@ -18,6 +17,5 @@ pub mod asn1; pub mod bn; pub mod bio; pub mod crypto; -mod ffi; pub mod ssl; pub mod x509; -- cgit v1.2.3 From 287d4020424262d290bf0db678e32fd83a8dfb50 Mon Sep 17 00:00:00 2001 From: Corey Ford Date: Wed, 5 Nov 2014 23:00:39 -0800 Subject: Add XTS-AES mode --- src/crypto/symm.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index c389ee99..6ad39933 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -11,11 +11,13 @@ pub enum Mode { pub enum Type { AES_128_ECB, AES_128_CBC, + AES_128_XTS, // AES_128_CTR, //AES_128_GCM, AES_256_ECB, AES_256_CBC, + AES_256_XTS, // AES_256_CTR, //AES_256_GCM, @@ -27,11 +29,13 @@ fn evpc(t: Type) -> (*const ffi::EVP_CIPHER, uint, uint) { match t { AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16u, 16u), AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16u, 16u), + AES_128_XTS => (ffi::EVP_aes_128_xts(), 32u, 16u), // AES_128_CTR => (EVP_aes_128_ctr(), 16u, 0u), //AES_128_GCM => (EVP_aes_128_gcm(), 16u, 16u), AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32u, 16u), AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32u, 16u), + AES_256_XTS => (ffi::EVP_aes_256_xts(), 64u, 16u), // AES_256_CTR => (EVP_aes_256_ctr(), 32u, 0u), //AES_256_GCM => (EVP_aes_256_gcm(), 32u, 16u), @@ -263,6 +267,18 @@ mod tests { cipher_test(super::RC4_128, pt, ct, key, iv); } + #[test] + fn test_aes256_xts() { + // Test case 174 from + // http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip + let pt = "77f4ef63d734ebd028508da66c22cdebdd52ecd6ee2ab0a50bc8ad0cfd692ca5fcd4e6dedc45df7f6503f462611dc542"; + let ct = "ce7d905a7776ac72f240d22aafed5e4eb7566cdc7211220e970da634ce015f131a5ecb8d400bc9e84f0b81d8725dbbc7"; + let key = "b6bfef891f83b5ff073f2231267be51eb084b791fa19a154399c0684c8b2dfcb37de77d28bbda3b4180026ad640b74243b3133e7b9fae629403f6733423dae28"; + let iv = "db200efb7eaaa737dbdf40babb68953f"; + + cipher_test(super::AES_256_XTS, pt, ct, key, iv); + } + /*#[test] fn test_aes128_ctr() { -- cgit v1.2.3 From 5258ce6ece505c6c9b40310bcff0ef55a3073300 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Nov 2014 13:57:05 -0800 Subject: Move AES XTS support to a feature --- src/crypto/hash.rs | 2 +- src/crypto/symm.rs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index b00dfba8..14dd34b5 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -122,7 +122,7 @@ mod tests { pub fn hash_writer(t: super::HashType, data: &[u8]) -> Vec { let mut h = super::Hasher::new(t); - h.write(data); + h.write(data).unwrap(); h.finalize() } diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index 6ad39933..6af4be6c 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -11,12 +11,16 @@ pub enum Mode { pub enum Type { AES_128_ECB, AES_128_CBC, + /// Requires the `aes_xts` feature + #[cfg(feature = "aes_xts")] AES_128_XTS, // AES_128_CTR, //AES_128_GCM, AES_256_ECB, AES_256_CBC, + /// Requires the `aes_xts` feature + #[cfg(feature = "aes_xts")] AES_256_XTS, // AES_256_CTR, //AES_256_GCM, @@ -29,12 +33,14 @@ fn evpc(t: Type) -> (*const ffi::EVP_CIPHER, uint, uint) { match t { AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16u, 16u), AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16u, 16u), + #[cfg(feature = "aes_xts")] AES_128_XTS => (ffi::EVP_aes_128_xts(), 32u, 16u), // AES_128_CTR => (EVP_aes_128_ctr(), 16u, 0u), //AES_128_GCM => (EVP_aes_128_gcm(), 16u, 16u), AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32u, 16u), AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32u, 16u), + #[cfg(feature = "aes_xts")] AES_256_XTS => (ffi::EVP_aes_256_xts(), 64u, 16u), // AES_256_CTR => (EVP_aes_256_ctr(), 32u, 0u), //AES_256_GCM => (EVP_aes_256_gcm(), 32u, 16u), @@ -268,6 +274,7 @@ mod tests { } #[test] + #[cfg(feature = "aes_xts")] fn test_aes256_xts() { // Test case 174 from // http://csrc.nist.gov/groups/STM/cavp/documents/aes/XTSTestVectors.zip -- cgit v1.2.3 From 2569b398556dcec70ba2dc4369327172bedef375 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sun, 16 Nov 2014 22:21:45 -0800 Subject: Impl Error for SslError --- src/lib.rs | 2 +- src/ssl/error.rs | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index a974e399..f2d8a30d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(struct_variant, macro_rules, unsafe_destructor)] +#![feature(struct_variant, macro_rules, unsafe_destructor, globs)] #![crate_name="openssl"] #![crate_type="rlib"] #![crate_type="dylib"] diff --git a/src/ssl/error.rs b/src/ssl/error.rs index 7066299f..7e8daef1 100644 --- a/src/ssl/error.rs +++ b/src/ssl/error.rs @@ -1,4 +1,8 @@ +pub use self::SslError::*; +pub use self::OpensslError::*; + use libc::c_ulong; +use std::error; use std::io::IoError; use std::c_str::CString; @@ -7,7 +11,7 @@ use ffi; /// An SSL error #[deriving(Show, Clone, PartialEq, Eq)] pub enum SslError { - /// The underlying stream has reported an error + /// The underlying stream reported an error StreamError(IoError), /// The SSL session has been closed by the other end SslSessionClosed, @@ -15,6 +19,23 @@ pub enum SslError { OpenSslErrors(Vec) } +impl error::Error for SslError { + fn description(&self) -> &str { + match *self { + StreamError(_) => "The underlying stream reported an error", + SslSessionClosed => "The SSL session has been closed by the other end", + OpenSslErrors(_) => "An error in the OpenSSL library", + } + } + + fn cause(&self) -> Option<&error::Error> { + match *self { + StreamError(ref err) => Some(err as &error::Error), + _ => None + } + } +} + /// An error from the OpenSSL library #[deriving(Show, Clone, PartialEq, Eq)] pub enum OpensslError { -- cgit v1.2.3 From f02d8c22ecf0138535ce93731c8b4653e4d09e86 Mon Sep 17 00:00:00 2001 From: James Hurst Date: Mon, 17 Nov 2014 19:16:51 -0500 Subject: Fixed compilation errors related to namedspaced enums --- src/crypto/hash.rs | 24 +++++++-------- src/crypto/hmac.rs | 2 +- src/crypto/pkey.rs | 90 +++++++++++++++++++++++++++--------------------------- src/crypto/symm.rs | 38 +++++++++++------------ src/lib.rs | 2 +- src/ssl/mod.rs | 20 ++++++------ src/ssl/tests.rs | 6 ++-- src/x509/mod.rs | 48 ++++++++++++++--------------- src/x509/tests.rs | 6 ++-- 9 files changed, 120 insertions(+), 116 deletions(-) (limited to 'src') diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index 14dd34b5..1587e55d 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -17,13 +17,13 @@ pub enum HashType { pub fn evpmd(t: HashType) -> (*const ffi::EVP_MD, uint) { unsafe { match t { - MD5 => (ffi::EVP_md5(), 16u), - SHA1 => (ffi::EVP_sha1(), 20u), - SHA224 => (ffi::EVP_sha224(), 28u), - SHA256 => (ffi::EVP_sha256(), 32u), - SHA384 => (ffi::EVP_sha384(), 48u), - SHA512 => (ffi::EVP_sha512(), 64u), - RIPEMD160 => (ffi::EVP_ripemd160(), 20u), + HashType::MD5 => (ffi::EVP_md5(), 16u), + HashType::SHA1 => (ffi::EVP_sha1(), 20u), + HashType::SHA224 => (ffi::EVP_sha224(), 28u), + HashType::SHA256 => (ffi::EVP_sha256(), 32u), + HashType::SHA384 => (ffi::EVP_sha384(), 48u), + HashType::SHA512 => (ffi::EVP_sha512(), 64u), + HashType::RIPEMD160 => (ffi::EVP_ripemd160(), 20u), } } } @@ -145,7 +145,7 @@ mod tests { HashTest("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1")]; for test in tests.iter() { - hash_test(super::MD5, test); + hash_test(super::HashType::MD5, test); } } @@ -156,7 +156,7 @@ mod tests { ]; for test in tests.iter() { - hash_test(super::SHA1, test); + hash_test(super::HashType::SHA1, test); } } @@ -167,7 +167,7 @@ mod tests { ]; for test in tests.iter() { - hash_test(super::SHA256, test); + hash_test(super::HashType::SHA256, test); } } @@ -178,14 +178,14 @@ mod tests { ]; for test in tests.iter() { - hash_test(super::RIPEMD160, test); + hash_test(super::HashType::RIPEMD160, test); } } #[test] fn test_writer() { let tv = "rust-openssl".as_bytes(); - let ht = super::RIPEMD160; + let ht = super::HashType::RIPEMD160; assert!(hash_writer(ht, tv) == super::hash(ht, tv)); } } diff --git a/src/crypto/hmac.rs b/src/crypto/hmac.rs index ef2a0414..a3d92236 100644 --- a/src/crypto/hmac.rs +++ b/src/crypto/hmac.rs @@ -64,7 +64,7 @@ impl HMAC { #[cfg(test)] mod tests { use serialize::hex::FromHex; - use crypto::hash::{HashType, MD5, SHA1, SHA224, SHA256, SHA384, SHA512}; + use crypto::hash::HashType::{mod, MD5, SHA1, SHA224, SHA256, SHA384, SHA512}; use super::HMAC; #[test] diff --git a/src/crypto/pkey.rs b/src/crypto/pkey.rs index a04937b3..146d2aa3 100644 --- a/src/crypto/pkey.rs +++ b/src/crypto/pkey.rs @@ -2,7 +2,7 @@ use libc::{c_int, c_uint}; use std::mem; use std::ptr; use bio::{MemBio}; -use crypto::hash::{HashType, MD5, SHA1, SHA224, SHA256, SHA384, SHA512, RIPEMD160}; +use crypto::hash::HashType; use ffi; use ssl::error::{SslError, StreamError}; @@ -29,20 +29,20 @@ pub enum EncryptionPadding { fn openssl_padding_code(padding: EncryptionPadding) -> c_int { match padding { - OAEP => 4, - PKCS1v15 => 1 + EncryptionPadding::OAEP => 4, + EncryptionPadding::PKCS1v15 => 1 } } 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 - RIPEMD160 => 117, // NID_ripemd160 + HashType::MD5 => 4, // NID_md5, + HashType::SHA1 => 64, // NID_sha1 + HashType::SHA224 => 675, // NID_sha224 + HashType::SHA256 => 672, // NID_sha256 + HashType::SHA384 => 673, // NID_sha384 + HashType::SHA512 => 674, // NID_sha512 + HashType::RIPEMD160 => 117, // NID_ripemd160 } } @@ -59,7 +59,7 @@ impl PKey { PKey { evp: ffi::EVP_PKEY_new(), - parts: Neither, + parts: Parts::Neither, } } } @@ -101,7 +101,7 @@ impl PKey { 6 as c_int, mem::transmute(rsa)); - self.parts = Both; + self.parts = Parts::Both; } } @@ -117,7 +117,7 @@ impl PKey { */ pub fn load_pub(&mut self, s: &[u8]) { self._fromstr(s, ffi::d2i_RSA_PUBKEY); - self.parts = Public; + self.parts = Parts::Public; } /** @@ -133,7 +133,7 @@ impl PKey { */ pub fn load_priv(&mut self, s: &[u8]) { self._fromstr(s, ffi::d2i_RSAPrivateKey); - self.parts = Both; + self.parts = Parts::Both; } /// Stores private key as a PEM @@ -163,24 +163,24 @@ impl PKey { */ pub fn can(&self, r: Role) -> bool { match r { - Encrypt => + Role::Encrypt => match self.parts { - Neither => false, + Parts::Neither => false, _ => true, }, - Verify => + Role::Verify => match self.parts { - Neither => false, + Parts::Neither => false, _ => true, }, - Decrypt => + Role::Decrypt => match self.parts { - Both => true, + Parts::Both => true, _ => false, }, - Sign => + Role::Sign => match self.parts { - Both => true, + Parts::Both => true, _ => false, }, } @@ -254,24 +254,24 @@ impl PKey { * Encrypts data using OAEP padding, returning the encrypted data. The * supplied data must not be larger than max_data(). */ - pub fn encrypt(&self, s: &[u8]) -> Vec { self.encrypt_with_padding(s, OAEP) } + pub fn encrypt(&self, s: &[u8]) -> Vec { self.encrypt_with_padding(s, EncryptionPadding::OAEP) } /** * Decrypts data, expecting OAEP padding, returning the decrypted data. */ - pub fn decrypt(&self, s: &[u8]) -> Vec { self.decrypt_with_padding(s, OAEP) } + pub fn decrypt(&self, s: &[u8]) -> Vec { self.decrypt_with_padding(s, EncryptionPadding::OAEP) } /** * Signs data, using OpenSSL's default scheme and sha256. Unlike encrypt(), * can process an arbitrary amount of data; returns the signature. */ - pub fn sign(&self, s: &[u8]) -> Vec { self.sign_with_hash(s, SHA256) } + pub fn sign(&self, s: &[u8]) -> Vec { self.sign_with_hash(s, HashType::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. */ - pub fn verify(&self, m: &[u8], s: &[u8]) -> bool { self.verify_with_hash(m, s, SHA256) } + pub fn verify(&self, m: &[u8], s: &[u8]) -> bool { self.verify_with_hash(m, s, HashType::SHA256) } pub fn sign_with_hash(&self, s: &[u8], hash: HashType) -> Vec { unsafe { @@ -328,7 +328,7 @@ impl Drop for PKey { #[cfg(test)] mod tests { - use crypto::hash::{MD5, SHA1}; + use crypto::hash::HashType::{MD5, SHA1}; #[test] fn test_gen_pub() { @@ -338,14 +338,14 @@ mod tests { k1.load_pub(k0.save_pub().as_slice()); assert_eq!(k0.save_pub(), k1.save_pub()); assert_eq!(k0.size(), k1.size()); - assert!(k0.can(super::Encrypt)); - assert!(k0.can(super::Decrypt)); - assert!(k0.can(super::Verify)); - assert!(k0.can(super::Sign)); - assert!(k1.can(super::Encrypt)); - assert!(!k1.can(super::Decrypt)); - assert!(k1.can(super::Verify)); - assert!(!k1.can(super::Sign)); + assert!(k0.can(super::Role::Encrypt)); + assert!(k0.can(super::Role::Decrypt)); + assert!(k0.can(super::Role::Verify)); + assert!(k0.can(super::Role::Sign)); + assert!(k1.can(super::Role::Encrypt)); + assert!(!k1.can(super::Role::Decrypt)); + assert!(k1.can(super::Role::Verify)); + assert!(!k1.can(super::Role::Sign)); } #[test] @@ -356,14 +356,14 @@ mod tests { k1.load_priv(k0.save_priv().as_slice()); assert_eq!(k0.save_priv(), k1.save_priv()); assert_eq!(k0.size(), k1.size()); - assert!(k0.can(super::Encrypt)); - assert!(k0.can(super::Decrypt)); - assert!(k0.can(super::Verify)); - assert!(k0.can(super::Sign)); - assert!(k1.can(super::Encrypt)); - assert!(k1.can(super::Decrypt)); - assert!(k1.can(super::Verify)); - assert!(k1.can(super::Sign)); + assert!(k0.can(super::Role::Encrypt)); + assert!(k0.can(super::Role::Decrypt)); + assert!(k0.can(super::Role::Verify)); + assert!(k0.can(super::Role::Sign)); + assert!(k1.can(super::Role::Encrypt)); + assert!(k1.can(super::Role::Decrypt)); + assert!(k1.can(super::Role::Verify)); + assert!(k1.can(super::Role::Sign)); } #[test] @@ -385,8 +385,8 @@ mod tests { let msg = vec!(0xdeu8, 0xadu8, 0xd0u8, 0x0du8); k0.gen(512u); k1.load_pub(k0.save_pub().as_slice()); - let emsg = k1.encrypt_with_padding(msg.as_slice(), super::PKCS1v15); - let dmsg = k0.decrypt_with_padding(emsg.as_slice(), super::PKCS1v15); + let emsg = k1.encrypt_with_padding(msg.as_slice(), super::EncryptionPadding::PKCS1v15); + let dmsg = k0.decrypt_with_padding(emsg.as_slice(), super::EncryptionPadding::PKCS1v15); assert!(msg == dmsg); } diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index 6af4be6c..c6211784 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -31,21 +31,21 @@ pub enum Type { fn evpc(t: Type) -> (*const ffi::EVP_CIPHER, uint, uint) { unsafe { match t { - AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16u, 16u), - AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16u, 16u), + Type::AES_128_ECB => (ffi::EVP_aes_128_ecb(), 16u, 16u), + Type::AES_128_CBC => (ffi::EVP_aes_128_cbc(), 16u, 16u), #[cfg(feature = "aes_xts")] - AES_128_XTS => (ffi::EVP_aes_128_xts(), 32u, 16u), + Type::AES_128_XTS => (ffi::EVP_aes_128_xts(), 32u, 16u), // AES_128_CTR => (EVP_aes_128_ctr(), 16u, 0u), //AES_128_GCM => (EVP_aes_128_gcm(), 16u, 16u), - AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32u, 16u), - AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32u, 16u), + Type::AES_256_ECB => (ffi::EVP_aes_256_ecb(), 32u, 16u), + Type::AES_256_CBC => (ffi::EVP_aes_256_cbc(), 32u, 16u), #[cfg(feature = "aes_xts")] - AES_256_XTS => (ffi::EVP_aes_256_xts(), 64u, 16u), + Type::AES_256_XTS => (ffi::EVP_aes_256_xts(), 64u, 16u), // AES_256_CTR => (EVP_aes_256_ctr(), 32u, 0u), //AES_256_GCM => (EVP_aes_256_gcm(), 32u, 16u), - RC4_128 => (ffi::EVP_rc4(), 16u, 0u), + Type::RC4_128 => (ffi::EVP_rc4(), 16u, 0u), } } } @@ -86,8 +86,8 @@ impl Crypter { pub fn init(&self, mode: Mode, key: &[u8], iv: Vec) { unsafe { let mode = match mode { - Encrypt => 1 as c_int, - Decrypt => 0 as c_int, + Mode::Encrypt => 1 as c_int, + Mode::Decrypt => 0 as c_int, }; assert_eq!(key.len(), self.keylen); @@ -155,7 +155,7 @@ impl Drop for Crypter { */ pub fn encrypt(t: Type, key: &[u8], iv: Vec, data: &[u8]) -> Vec { let c = Crypter::new(t); - c.init(Encrypt, key, iv); + c.init(Mode::Encrypt, key, iv); let mut r = c.update(data); let rest = c.finalize(); r.extend(rest.into_iter()); @@ -168,7 +168,7 @@ pub fn encrypt(t: Type, key: &[u8], iv: Vec, data: &[u8]) -> Vec { */ pub fn decrypt(t: Type, key: &[u8], iv: Vec, data: &[u8]) -> Vec { let c = Crypter::new(t); - c.init(Decrypt, key, iv); + c.init(Mode::Decrypt, key, iv); let mut r = c.update(data); let rest = c.finalize(); r.extend(rest.into_iter()); @@ -194,13 +194,13 @@ mod tests { let c0 = vec!(0x8eu8, 0xa2u8, 0xb7u8, 0xcau8, 0x51u8, 0x67u8, 0x45u8, 0xbfu8, 0xeau8, 0xfcu8, 0x49u8, 0x90u8, 0x4bu8, 0x49u8, 0x60u8, 0x89u8); - let c = super::Crypter::new(super::AES_256_ECB); - c.init(super::Encrypt, k0.as_slice(), vec![]); + let c = super::Crypter::new(super::Type::AES_256_ECB); + c.init(super::Mode::Encrypt, k0.as_slice(), vec![]); c.pad(false); let mut r0 = c.update(p0.as_slice()); r0.extend(c.finalize().into_iter()); assert!(r0 == c0); - c.init(super::Decrypt, k0.as_slice(), vec![]); + c.init(super::Mode::Decrypt, k0.as_slice(), vec![]); c.pad(false); let mut p1 = c.update(r0.as_slice()); p1.extend(c.finalize().into_iter()); @@ -209,7 +209,7 @@ mod tests { #[test] fn test_aes_256_cbc_decrypt() { - let cr = super::Crypter::new(super::AES_256_CBC); + let cr = super::Crypter::new(super::Type::AES_256_CBC); let iv = vec![ 4_u8, 223_u8, 153_u8, 219_u8, 28_u8, 142_u8, 234_u8, 68_u8, 227_u8, 69_u8, 98_u8, 107_u8, 208_u8, 14_u8, 236_u8, 60_u8, 0_u8, 0_u8, @@ -226,7 +226,7 @@ mod tests { 0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, 0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0x65_u8, 0x6f_u8 ]; - cr.init(super::Decrypt, data, iv); + cr.init(super::Mode::Decrypt, data, iv); cr.pad(false); let unciphered_data_1 = cr.update(ciphered_data); let unciphered_data_2 = cr.finalize(); @@ -245,7 +245,7 @@ mod tests { use serialize::hex::ToHex; let cipher = super::Crypter::new(ciphertype); - cipher.init(super::Encrypt, key.from_hex().unwrap().as_slice(), iv.from_hex().unwrap()); + cipher.init(super::Mode::Encrypt, key.from_hex().unwrap().as_slice(), iv.from_hex().unwrap()); let expected = ct.from_hex().unwrap().as_slice().to_vec(); let mut computed = cipher.update(pt.from_hex().unwrap().as_slice()); @@ -270,7 +270,7 @@ mod tests { let key = "97CD440324DA5FD1F7955C1C13B6B466"; let iv = ""; - cipher_test(super::RC4_128, pt, ct, key, iv); + cipher_test(super::Type::RC4_128, pt, ct, key, iv); } #[test] @@ -283,7 +283,7 @@ mod tests { let key = "b6bfef891f83b5ff073f2231267be51eb084b791fa19a154399c0684c8b2dfcb37de77d28bbda3b4180026ad640b74243b3133e7b9fae629403f6733423dae28"; let iv = "db200efb7eaaa737dbdf40babb68953f"; - cipher_test(super::AES_256_XTS, pt, ct, key, iv); + cipher_test(super::Type::AES_256_XTS, pt, ct, key, iv); } /*#[test] diff --git a/src/lib.rs b/src/lib.rs index f2d8a30d..4f5e3e75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(struct_variant, macro_rules, unsafe_destructor, globs)] +#![feature(macro_rules, unsafe_destructor, globs)] #![crate_name="openssl"] #![crate_type="rlib"] #![crate_type="dylib"] diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 0ed3c2e8..a3eb5c14 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -56,14 +56,14 @@ impl SslMethod { unsafe fn to_raw(&self) -> *const ffi::SSL_METHOD { match *self { #[cfg(feature = "sslv2")] - Sslv2 => ffi::SSLv2_method(), - Sslv3 => ffi::SSLv3_method(), - Tlsv1 => ffi::TLSv1_method(), - Sslv23 => ffi::SSLv23_method(), + SslMethod::Sslv2 => ffi::SSLv2_method(), + SslMethod::Sslv3 => ffi::SSLv3_method(), + SslMethod::Tlsv1 => ffi::TLSv1_method(), + SslMethod::Sslv23 => ffi::SSLv23_method(), #[cfg(feature = "tlsv1_1")] - Tlsv1_1 => ffi::TLSv1_1_method(), + SslMethod::Tlsv1_1 => ffi::TLSv1_1_method(), #[cfg(feature = "tlsv1_2")] - Tlsv1_2 => ffi::TLSv1_2_method() + SslMethod::Tlsv1_2 => ffi::TLSv1_2_method() } } } @@ -424,14 +424,14 @@ impl SslStream { } match self.ssl.get_error(ret) { - ErrorWantRead => { + LibSslError::ErrorWantRead => { try_ssl_stream!(self.flush()); let len = try_ssl_stream!(self.stream.read(self.buf.as_mut_slice())); self.ssl.get_rbio().write(self.buf.slice_to(len)); } - ErrorWantWrite => { try_ssl_stream!(self.flush()) } - ErrorZeroReturn => return Err(SslSessionClosed), - ErrorSsl => return Err(SslError::get()), + LibSslError::ErrorWantWrite => { try_ssl_stream!(self.flush()) } + LibSslError::ErrorZeroReturn => return Err(SslSessionClosed), + LibSslError::ErrorSsl => return Err(SslError::get()), _ => unreachable!() } } diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index f9f941a9..5aa9834f 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -3,8 +3,10 @@ use std::io::{Writer}; use std::io::net::tcp::TcpStream; use std::str; -use crypto::hash::{SHA256}; -use ssl::{Sslv23, SslContext, SslStream, SslVerifyPeer}; +use crypto::hash::HashType::{SHA256}; +use ssl::SslMethod::Sslv23; +use ssl::{SslContext, SslStream}; +use ssl::SslVerifyMode::SslVerifyPeer; use x509::{X509StoreContext}; #[test] diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 48b5d455..21c3a9d6 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -4,7 +4,7 @@ use std::ptr; use asn1::{Asn1Time}; use bio::{MemBio}; -use crypto::hash::{HashType, evpmd, SHA1}; +use crypto::hash::{HashType, evpmd}; use crypto::pkey::{PKey}; use crypto::rand::rand_bytes; use ffi; @@ -69,15 +69,15 @@ pub enum KeyUsage { impl AsStr<'static> for KeyUsage { fn as_str(&self) -> &'static str { match self { - &DigitalSignature => "digitalSignature", - &NonRepudiation => "nonRepudiation", - &KeyEncipherment => "keyEncipherment", - &DataEncipherment => "dataEncipherment", - &KeyAgreement => "keyAgreement", - &KeyCertSign => "keyCertSign", - &CRLSign => "cRLSign", - &EncipherOnly => "encipherOnly", - &DecipherOnly => "decipherOnly" + &KeyUsage::DigitalSignature => "digitalSignature", + &KeyUsage::NonRepudiation => "nonRepudiation", + &KeyUsage::KeyEncipherment => "keyEncipherment", + &KeyUsage::DataEncipherment => "dataEncipherment", + &KeyUsage::KeyAgreement => "keyAgreement", + &KeyUsage::KeyCertSign => "keyCertSign", + &KeyUsage::CRLSign => "cRLSign", + &KeyUsage::EncipherOnly => "encipherOnly", + &KeyUsage::DecipherOnly => "decipherOnly" } } } @@ -101,17 +101,17 @@ pub enum ExtKeyUsage { impl AsStr<'static> for ExtKeyUsage { fn as_str(&self) -> &'static str { match self { - &ServerAuth => "serverAuth", - &ClientAuth => "clientAuth", - &CodeSigning => "codeSigning", - &EmailProtection => "emailProtection", - &TimeStamping => "timeStamping", - &MsCodeInd => "msCodeInd", - &MsCodeCom => "msCodeCom", - &MsCtlSign => "msCTLSign", - &MsSgc => "msSGC", - &MsEfs => "msEFS", - &NsSgc =>"nsSGC" + &ExtKeyUsage::ServerAuth => "serverAuth", + &ExtKeyUsage::ClientAuth => "clientAuth", + &ExtKeyUsage::CodeSigning => "codeSigning", + &ExtKeyUsage::EmailProtection => "emailProtection", + &ExtKeyUsage::TimeStamping => "timeStamping", + &ExtKeyUsage::MsCodeInd => "msCodeInd", + &ExtKeyUsage::MsCodeCom => "msCodeCom", + &ExtKeyUsage::MsCtlSign => "msCTLSign", + &ExtKeyUsage::MsSgc => "msSGC", + &ExtKeyUsage::MsEfs => "msEFS", + &ExtKeyUsage::NsSgc =>"nsSGC" } } } @@ -192,7 +192,7 @@ impl X509Generator { CN: "rust-openssl".to_string(), key_usage: Vec::new(), ext_key_usage: Vec::new(), - hash_type: SHA1 + hash_type: HashType::SHA1 } } @@ -435,8 +435,8 @@ macro_rules! make_validation_error( pub fn from_raw(err: c_int) -> Option { match err { ffi::$ok_val => None, - $(ffi::$val => Some($name),)+ - err => Some(X509UnknownError(err)) + $(ffi::$val => Some(X509ValidationError::$name),)+ + err => Some(X509ValidationError::X509UnknownError(err)) } } } diff --git a/src/x509/tests.rs b/src/x509/tests.rs index e4f7b142..49e399d9 100644 --- a/src/x509/tests.rs +++ b/src/x509/tests.rs @@ -2,8 +2,10 @@ 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}; +use crypto::hash::HashType::{SHA256}; +use x509::{X509, X509Generator}; +use x509::KeyUsage::{DigitalSignature, KeyEncipherment}; +use x509::ExtKeyUsage::{ClientAuth, ServerAuth}; #[test] fn test_cert_gen() { -- cgit v1.2.3 From af5533d936558a77c2de8c5d2d572bb1f89dfada Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 17 Nov 2014 16:29:12 -0800 Subject: Remove Zero and One impls --- src/bn/mod.rs | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'src') diff --git a/src/bn/mod.rs b/src/bn/mod.rs index a3ac8ffd..b33f94ce 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -1,7 +1,6 @@ use libc::{c_int, c_ulong}; use std::{fmt, ptr}; use std::c_str::CString; -use std::num::{One, Zero}; use ffi; use ssl::error::SslError; @@ -361,25 +360,6 @@ impl fmt::Show for BigNum { } } -impl One for BigNum { - fn one() -> BigNum { - BigNum::new_from(1).unwrap() - } -} - -impl Zero for BigNum { - fn zero() -> BigNum { - BigNum::new_from(0).unwrap() - } - - fn is_zero(&self) -> bool { - unsafe { - // It is raw contents of BN_is_zero macro - (*self.raw()).top == 0 - } - } -} - impl Eq for BigNum { } impl PartialEq for BigNum { fn eq(&self, oth: &BigNum) -> bool { -- cgit v1.2.3 From b9e3ed50ad22e72e67c61f69bd3805b43e519122 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Tue, 23 Sep 2014 16:11:34 -0400 Subject: Baseline server support Allows calling SSL_accept() instead of SSL_connect() when creating an SslStream. --- src/ssl/mod.rs | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index a3eb5c14..1f0599b4 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -326,6 +326,10 @@ impl Ssl { unsafe { ffi::SSL_connect(self.ssl) } } + fn accept(&self) -> c_int { + unsafe { ffi::SSL_accept(self.ssl) } + } + fn read(&self, buf: &mut [u8]) -> c_int { unsafe { ffi::SSL_read(self.ssl, buf.as_ptr() as *mut c_void, buf.len() as c_int) } @@ -390,31 +394,38 @@ pub struct SslStream { } impl SslStream { - /// Attempts to create a new SSL stream from a given `Ssl` instance. - pub fn new_from(ssl: Ssl, stream: S) -> Result, SslError> { - let mut ssl = SslStream { + fn new_base(ssl:Ssl, stream: S) -> SslStream { + SslStream { stream: stream, ssl: ssl, // Maximum TLS record size is 16k buf: Vec::from_elem(16 * 1024, 0u8) - }; - - match ssl.in_retry_wrapper(|ssl| { ssl.connect() }) { - Ok(_) => Ok(ssl), - Err(err) => Err(err) } } + pub fn new_server_from(ssl: Ssl, stream: S) -> Result, SslError> { + let mut ssl = SslStream::new_base(ssl, stream); + ssl.in_retry_wrapper(|ssl| { ssl.accept() }).and(Ok(ssl)) + } + + /// Attempts to create a new SSL stream from a given `Ssl` instance. + pub fn new_from(ssl: Ssl, stream: S) -> Result, SslError> { + let mut ssl = SslStream::new_base(ssl, stream); + ssl.in_retry_wrapper(|ssl| { ssl.connect() }).and(Ok(ssl)) + } + /// Creates a new SSL stream pub fn new(ctx: &SslContext, stream: S) -> Result, SslError> { - let ssl = match Ssl::new(ctx) { - Ok(ssl) => ssl, - Err(err) => return Err(err) - }; - + let ssl = try!(Ssl::new(ctx)); SslStream::new_from(ssl, stream) } + /// Creates a new SSL server stream + pub fn new_server(ctx: &SslContext, stream: S) -> Result, SslError> { + let ssl = try!(Ssl::new(ctx)); + SslStream::new_server_from(ssl, stream) + } + fn in_retry_wrapper(&mut self, blk: |&Ssl| -> c_int) -> Result { loop { -- cgit v1.2.3 From 9996f5874e4f62f66d9e837a91310f1a9a946a7f Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 19 Nov 2014 12:36:32 -0800 Subject: Fix test build --- src/crypto/hmac.rs | 8 ++++---- src/crypto/memcmp.rs | 8 ++++---- src/crypto/symm.rs | 4 ++-- src/x509/tests.rs | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/crypto/hmac.rs b/src/crypto/hmac.rs index a3d92236..a7a854b7 100644 --- a/src/crypto/hmac.rs +++ b/src/crypto/hmac.rs @@ -167,7 +167,7 @@ mod tests { "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e".from_hex().unwrap(), "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1".from_hex().unwrap() ]; - test_sha2(SHA224, results); + test_sha2(SHA224, &results); } #[test] @@ -180,7 +180,7 @@ mod tests { "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54".from_hex().unwrap(), "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2".from_hex().unwrap() ]; - test_sha2(SHA256, results); + test_sha2(SHA256, &results); } #[test] @@ -205,7 +205,7 @@ mod tests { 602420feb0b8fb9adccebb82461e99c5\ a678cc31e799176d3860e6110c46523e".from_hex().unwrap() ]; - test_sha2(SHA384, results); + test_sha2(SHA384, &results); } #[test] @@ -236,6 +236,6 @@ mod tests { b6022cac3c4982b10d5eeb55c3e4de15\ 134676fb6de0446065c97440fa8c6a58".from_hex().unwrap() ]; - test_sha2(SHA512, results); + test_sha2(SHA512, &results); } } diff --git a/src/crypto/memcmp.rs b/src/crypto/memcmp.rs index 7473fcab..299effa9 100644 --- a/src/crypto/memcmp.rs +++ b/src/crypto/memcmp.rs @@ -26,14 +26,14 @@ mod tests { #[test] fn test_eq() { - assert!(eq([], [])); - assert!(eq([1], [1])); - assert!(!eq([1, 2, 3], [1, 2, 4])); + assert!(eq(&[], &[])); + assert!(eq(&[1], &[1])); + assert!(!eq(&[1, 2, 3], &[1, 2, 4])); } #[test] #[should_fail] fn test_diff_lens() { - eq([], [1]); + eq(&[], &[1]); } } diff --git a/src/crypto/symm.rs b/src/crypto/symm.rs index c6211784..998d351c 100644 --- a/src/crypto/symm.rs +++ b/src/crypto/symm.rs @@ -226,9 +226,9 @@ mod tests { 0x4a_u8, 0x2e_u8, 0xe5_u8, 0x6_u8, 0xbf_u8, 0xcf_u8, 0xf2_u8, 0xd7_u8, 0xea_u8, 0x2d_u8, 0xb1_u8, 0x85_u8, 0x6c_u8, 0x93_u8, 0x65_u8, 0x6f_u8 ]; - cr.init(super::Mode::Decrypt, data, iv); + cr.init(super::Mode::Decrypt, &data, iv); cr.pad(false); - let unciphered_data_1 = cr.update(ciphered_data); + let unciphered_data_1 = cr.update(&ciphered_data); let unciphered_data_2 = cr.finalize(); let expected_unciphered_data = b"I love turtles.\x01"; diff --git a/src/x509/tests.rs b/src/x509/tests.rs index 49e399d9..259fc851 100644 --- a/src/x509/tests.rs +++ b/src/x509/tests.rs @@ -14,8 +14,8 @@ fn test_cert_gen() { .set_valid_period(365*2) .set_CN("test_me") .set_sign_hash(SHA256) - .set_usage([DigitalSignature, KeyEncipherment]) - .set_ext_usage([ClientAuth, ServerAuth]); + .set_usage(&[DigitalSignature, KeyEncipherment]) + .set_ext_usage(&[ClientAuth, ServerAuth]); let res = gen.generate(); assert!(res.is_ok()); -- cgit v1.2.3 From 50f11e533cd3e1fb3f893423ee15c685999670cf Mon Sep 17 00:00:00 2001 From: Gleb Kozyrev Date: Thu, 20 Nov 2014 07:53:56 +0200 Subject: Replace an expired cert with a new one to make tests happy --- src/ssl/tests.rs | 2 +- src/x509/tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 5aa9834f..99ef2386 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -163,7 +163,7 @@ fn test_verify_callback_data() { // 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 node_hash_str = "6204f6617e1af7495394250655f43600cd483e2dfc2005e92d0fe439d0723c34"; + let node_hash_str = "46e3f1a6d17a41ce70d0c66ef51cee2ab4ba67cac8940e23f10c1f944b49fb5c"; let node_id = node_hash_str.from_hex().unwrap(); ctx.set_verify_with_data(SslVerifyPeer, callback, node_id); ctx.set_verify_depth(1); diff --git a/src/x509/tests.rs b/src/x509/tests.rs index 259fc851..4e7fc925 100644 --- a/src/x509/tests.rs +++ b/src/x509/tests.rs @@ -44,7 +44,7 @@ fn test_cert_loading() { // 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_str = "46e3f1a6d17a41ce70d0c66ef51cee2ab4ba67cac8940e23f10c1f944b49fb5c"; let hash_vec = hash_str.from_hex().unwrap(); assert_eq!(fingerprint.as_slice(), hash_vec.as_slice()); -- cgit v1.2.3 From ef9e0b00bdbd688368c5ae3818b59bd7dcc651d7 Mon Sep 17 00:00:00 2001 From: Gleb Kozyrev Date: Thu, 20 Nov 2014 08:06:22 +0200 Subject: Slice syntax fix --- src/x509/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/x509/mod.rs b/src/x509/mod.rs index 21c3a9d6..f35eb7c2 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -152,7 +152,7 @@ impl<'a, T: AsStr<'a>> ToStr for Vec { /// .set_valid_period(365*2) /// .set_CN("SuperMegaCorp Inc.") /// .set_sign_hash(SHA256) -/// .set_usage([DigitalSignature]); +/// .set_usage(&[DigitalSignature]); /// /// let (cert, pkey) = gen.generate().unwrap(); /// -- cgit v1.2.3 From e9e60fe3f36a9dbaf8dd922c70ab6bdcee701175 Mon Sep 17 00:00:00 2001 From: Valerii Hiora Date: Fri, 21 Nov 2014 17:23:30 +0200 Subject: Fix negative serials on generated certs required for compatibility with Go crypto --- src/x509/mod.rs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/x509/mod.rs b/src/x509/mod.rs index f35eb7c2..86152ac4 100644 --- a/src/x509/mod.rs +++ b/src/x509/mod.rs @@ -1,5 +1,6 @@ use libc::{c_int, c_long, c_uint}; use std::mem; +use std::num::SignedInt; use std::ptr; use asn1::{Asn1Time}; @@ -270,7 +271,11 @@ impl X509Generator { res = res << 8; res |= (*b as c_long) & 0xff; } - res + + // While OpenSSL is actually OK to have negative serials + // other libraries (for example, Go crypto) can drop + // such certificates as invalid + res.abs() } /// Generates a private key and a signed certificate and returns them @@ -498,3 +503,12 @@ make_validation_error!(X509_V_OK, X509CrlPathValidationError= X509_V_ERR_CRL_PATH_VALIDATION_ERROR, X509ApplicationVerification = X509_V_ERR_APPLICATION_VERIFICATION, ) + + +#[test] +fn test_negative_serial() { + // I guess that's enough to get a random negative number + for _ in range(0u, 1000) { + assert!(X509Generator::random_serial() > 0, "All serials should be positive"); + } +} -- cgit v1.2.3 From 381a9b6e511099b71891ebcec48b131cf80f2c51 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Mon, 13 Oct 2014 15:14:58 -0400 Subject: sys (and bn): make CRYPTO_free() take a *mut c_void insead of a *const c_char CRYPTO_free() ends up being used for a variety of types of data, not just c_char. And it essentially takes full ownership of the type, making *mut appropriate. With this change it also more closely (exactly) matches the C defintion: void CRYPTO_free(void *ptr); --- src/bn/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/bn/mod.rs b/src/bn/mod.rs index b33f94ce..2536f8a5 100644 --- a/src/bn/mod.rs +++ b/src/bn/mod.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_ulong}; +use libc::{c_int, c_ulong, c_void}; use std::{fmt, ptr}; use std::c_str::CString; @@ -348,7 +348,7 @@ impl BigNum { assert!(!buf.is_null()); let c_str = CString::new(buf, false); let str = c_str.as_str().unwrap().to_string(); - ffi::CRYPTO_free(buf); + ffi::CRYPTO_free(buf as *mut c_void); str } } -- cgit v1.2.3 From fd14cc77f37f4bec78d313106191fbebf72a9284 Mon Sep 17 00:00:00 2001 From: Cody P Schafer Date: Mon, 24 Nov 2014 15:48:08 -0500 Subject: ssl: add get_peer_certificate() --- src/ssl/mod.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 1f0599b4..8e035466 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -8,7 +8,7 @@ use sync::one::{Once, ONCE_INIT}; use bio::{MemBio}; use ffi; use ssl::error::{SslError, SslSessionClosed, StreamError}; -use x509::{X509StoreContext, X509FileType}; +use x509::{X509StoreContext, X509FileType, X509}; pub mod error; #[cfg(test)] @@ -370,6 +370,17 @@ impl Ssl { } } + pub fn get_peer_certificate(&self) -> Option { + unsafe { + let ptr = ffi::SSL_get_peer_certificate(self.ssl); + if ptr.is_null() { + None + } else { + Some(X509::new(ptr, true)) + } + } + } + } #[deriving(FromPrimitive)] -- cgit v1.2.3 From f71555e8207fef6ba6f6090078309ca9bbe3a51d Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Mon, 24 Nov 2014 13:09:16 -0800 Subject: Fix deprecation warning --- src/ssl/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 8e035466..245e401e 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -2,7 +2,6 @@ use libc::{c_int, c_void, c_long}; use std::io::{IoResult, IoError, EndOfFile, Stream, Reader, Writer}; use std::mem; use std::ptr; -use std::string; use sync::one::{Once, ONCE_INIT}; use bio::{MemBio}; @@ -479,7 +478,7 @@ impl SslStream { } let meth = unsafe { ffi::SSL_COMP_get_name(ptr) }; - let s = unsafe { string::raw::from_buf(meth as *const u8) }; + let s = unsafe { String::from_raw_buf(meth as *const u8) }; Some(s) } -- cgit v1.2.3 From a7a9ef7eaa508a8437e5e23c16638d8b05877e6e Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Tue, 25 Nov 2014 16:44:42 -0800 Subject: Allow access to the underlying stream The use case here is to allow methods like `set_read_timeout` to be called. --- src/ssl/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 245e401e..1985dcd0 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -436,6 +436,15 @@ impl SslStream { SslStream::new_server_from(ssl, stream) } + /// Returns a mutable reference to the underlying stream + /// + /// ## Warning + /// `read`ing or `write`ing directly to the underlying stream will most + /// likely desynchronize the SSL session. + pub fn get_inner(&mut self) -> &mut S { + &mut self.stream + } + fn in_retry_wrapper(&mut self, blk: |&Ssl| -> c_int) -> Result { loop { -- cgit v1.2.3 From 762331eb2b8d464bab3b7c27940ce9c1ed233800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andor=20Uhl=C3=A1r?= Date: Wed, 26 Nov 2014 16:04:10 +0100 Subject: Sync is now part of the standard library --- src/lib.rs | 1 - src/ssl/mod.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 4f5e3e75..c89010ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ extern crate libc; #[cfg(test)] extern crate serialize; -extern crate sync; extern crate "openssl-sys" as ffi; diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 1985dcd0..c9e33e8e 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -2,7 +2,7 @@ use libc::{c_int, c_void, c_long}; use std::io::{IoResult, IoError, EndOfFile, Stream, Reader, Writer}; use std::mem; use std::ptr; -use sync::one::{Once, ONCE_INIT}; +use std::sync::{Once, ONCE_INIT}; use bio::{MemBio}; use ffi; -- cgit v1.2.3 From 5fafe4fc60848d525e3edb37266bc0f762cb7963 Mon Sep 17 00:00:00 2001 From: Gleb Kozyrev Date: Thu, 20 Nov 2014 07:06:59 +0200 Subject: Hasher: static contract checking, context reuse - Store EVP_MD_CTX in a separate struct. - Add with_context() constructor that uses an existing context. - Switch to EVP_Digest(Init|Final)_ex for efficient context reuse. - Make update() borrow &mut self. - Make finalize() consume self. Add finalize_reuse() that also returns the context which can be passed to from_context() constructor for reuse. These changes let the type system prevent illegal calls to update() and finalize(). --- src/crypto/hash.rs | 85 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/crypto/hash.rs b/src/crypto/hash.rs index 1587e55d..b5d0eab5 100644 --- a/src/crypto/hash.rs +++ b/src/crypto/hash.rs @@ -28,10 +28,32 @@ pub fn evpmd(t: HashType) -> (*const ffi::EVP_MD, uint) { } } +pub struct HasherContext { + ptr: *mut ffi::EVP_MD_CTX +} + +impl HasherContext { + pub fn new() -> HasherContext { + ffi::init(); + + unsafe { + HasherContext { ptr: ffi::EVP_MD_CTX_create() } + } + } +} + +impl Drop for HasherContext { + fn drop(&mut self) { + unsafe { + ffi::EVP_MD_CTX_destroy(self.ptr); + } + } +} + #[allow(dead_code)] pub struct Hasher { evp: *const ffi::EVP_MD, - ctx: *mut ffi::EVP_MD_CTX, + ctx: HasherContext, len: uint, } @@ -44,21 +66,23 @@ impl io::Writer for Hasher { impl Hasher { pub fn new(ht: HashType) -> Hasher { - ffi::init(); + let ctx = HasherContext::new(); + Hasher::with_context(ctx, ht) + } - let ctx = unsafe { ffi::EVP_MD_CTX_create() }; + pub fn with_context(ctx: HasherContext, ht: HashType) -> Hasher { let (evp, mdlen) = evpmd(ht); unsafe { - ffi::EVP_DigestInit(ctx, evp); + ffi::EVP_DigestInit_ex(ctx.ptr, evp, 0 as *const _); } Hasher { evp: evp, ctx: ctx, len: mdlen } } /// Update this hasher with more input bytes - pub fn update(&self, data: &[u8]) { + pub fn update(&mut self, data: &[u8]) { unsafe { - ffi::EVP_DigestUpdate(self.ctx, data.as_ptr(), data.len() as c_uint) + ffi::EVP_DigestUpdate(self.ctx.ptr, data.as_ptr(), data.len() as c_uint) } } @@ -66,20 +90,21 @@ impl Hasher { * Return the digest of all bytes added to this hasher since its last * initialization */ - pub fn finalize(&self) -> Vec { - unsafe { - let mut res = Vec::from_elem(self.len, 0u8); - ffi::EVP_DigestFinal(self.ctx, res.as_mut_ptr(), ptr::null_mut()); - res - } + pub fn finalize(self) -> Vec { + let (res, _) = self.finalize_reuse(); + res } -} -impl Drop for Hasher { - fn drop(&mut self) { + /** + * Return the digest of all bytes added to this hasher since its last + * initialization and its context for reuse + */ + pub fn finalize_reuse(self) -> (Vec, HasherContext) { + let mut res = Vec::from_elem(self.len, 0u8); unsafe { - ffi::EVP_MD_CTX_destroy(self.ctx); - } + ffi::EVP_DigestFinal_ex(self.ctx.ptr, res.as_mut_ptr(), ptr::null_mut()) + }; + (res, self.ctx) } } @@ -88,7 +113,7 @@ impl Drop for Hasher { * value */ pub fn hash(t: HashType, data: &[u8]) -> Vec { - let h = Hasher::new(t); + let mut h = Hasher::new(t); h.update(data); h.finalize() } @@ -108,9 +133,7 @@ mod tests { expected_output: output.to_string() } } - fn hash_test(hashtype: super::HashType, hashtest: &HashTest) { - let calced_raw = super::hash(hashtype, hashtest.input.as_slice()); - + fn compare(calced_raw: Vec, hashtest: &HashTest) { let calced = calced_raw.as_slice().to_hex().into_string(); if calced != hashtest.expected_output { @@ -120,6 +143,22 @@ mod tests { assert!(calced == hashtest.expected_output); } + fn hash_test(hashtype: super::HashType, hashtest: &HashTest) { + let calced_raw = super::hash(hashtype, hashtest.input.as_slice()); + compare(calced_raw, hashtest); + } + + fn hash_reuse_test(ctx: super::HasherContext, hashtype: super::HashType, + hashtest: &HashTest) -> super::HasherContext { + let mut h = super::Hasher::with_context(ctx, hashtype); + h.update(hashtest.input.as_slice()); + let (calced_raw, ctx) = h.finalize_reuse(); + + compare(calced_raw, hashtest); + + ctx + } + pub fn hash_writer(t: super::HashType, data: &[u8]) -> Vec { let mut h = super::Hasher::new(t); h.write(data).unwrap(); @@ -144,8 +183,10 @@ mod tests { HashTest("A510CD18F7A56852EB0319", "577e216843dd11573574d3fb209b97d8"), HashTest("AAED18DBE8938C19ED734A8D", "6f80fb775f27e0a4ce5c2f42fc72c5f1")]; + let mut ctx = super::HasherContext::new(); + for test in tests.iter() { - hash_test(super::HashType::MD5, test); + ctx = hash_reuse_test(ctx, super::HashType::MD5, test); } } -- cgit v1.2.3 From 72ca8433f574f8d70fc66aa6856affdf773a5867 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 28 Nov 2014 15:43:58 -0800 Subject: Add MaybeSslStream --- src/ssl/mod.rs | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index c9e33e8e..778b50c7 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -436,12 +436,29 @@ impl SslStream { SslStream::new_server_from(ssl, stream) } - /// Returns a mutable reference to the underlying stream + /// Returns a mutable reference to the underlying stream. /// /// ## Warning + /// /// `read`ing or `write`ing directly to the underlying stream will most /// likely desynchronize the SSL session. + #[deprecated="use get_mut instead"] pub fn get_inner(&mut self) -> &mut S { + self.get_mut() + } + + /// Returns a reference to the underlying stream. + pub fn get_ref(&self) -> &S { + &self.stream + } + + /// Returns a mutable reference to the underlying stream. + /// + /// ## Warning + /// + /// It is inadvisable to read from or write to the underlying stream as it + /// will most likely desynchronize the SSL session. + pub fn get_mut(&mut self) -> &mut S { &mut self.stream } @@ -530,3 +547,58 @@ impl Writer for SslStream { self.stream.flush() } } + +/// A utility type to help in cases where the use of SSL is decided at runtime. +pub enum MaybeSslStream where S: Stream { + /// A connection using SSL + Ssl(SslStream), + /// A connection not using SSL + Normal(S), +} + +impl Reader for MaybeSslStream where S: Stream { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + match *self { + MaybeSslStream::Ssl(ref mut s) => s.read(buf), + MaybeSslStream::Normal(ref mut s) => s.read(buf), + } + } +} + +impl Writer for MaybeSslStream where S: Stream{ + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + match *self { + MaybeSslStream::Ssl(ref mut s) => s.write(buf), + MaybeSslStream::Normal(ref mut s) => s.write(buf), + } + } + + fn flush(&mut self) -> IoResult<()> { + match *self { + MaybeSslStream::Ssl(ref mut s) => s.flush(), + MaybeSslStream::Normal(ref mut s) => s.flush(), + } + } +} + +impl MaybeSslStream where S: Stream { + /// Returns a reference to the underlying stream. + pub fn get_ref(&self) -> &S { + match *self { + MaybeSslStream::Ssl(ref s) => s.get_ref(), + MaybeSslStream::Normal(ref s) => s, + } + } + + /// Returns a mutable reference to the underlying stream. + /// + /// ## Warning + /// + /// It is inadvisable to read from or write to the underlying stream. + pub fn get_mut(&mut self) -> &mut S { + match *self { + MaybeSslStream::Ssl(ref mut s) => s.get_mut(), + MaybeSslStream::Normal(ref mut s) => s, + } + } +} -- cgit v1.2.3 From c3603b0db00d044c8332d39dd9d49e3c76a2a978 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Sat, 29 Nov 2014 11:06:16 -0800 Subject: Make SslStream Cloneable Closes #6 --- src/ssl/mod.rs | 9 +++++---- src/ssl/tests.rs | 16 +++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/ssl/mod.rs b/src/ssl/mod.rs index 778b50c7..d29d633e 100644 --- a/src/ssl/mod.rs +++ b/src/ssl/mod.rs @@ -2,7 +2,7 @@ use libc::{c_int, c_void, c_long}; use std::io::{IoResult, IoError, EndOfFile, Stream, Reader, Writer}; use std::mem; use std::ptr; -use std::sync::{Once, ONCE_INIT}; +use std::sync::{Once, ONCE_INIT, Arc}; use bio::{MemBio}; use ffi; @@ -397,9 +397,10 @@ enum LibSslError { } /// A stream wrapper which handles SSL encryption for an underlying stream. +#[deriving(Clone)] pub struct SslStream { stream: S, - ssl: Ssl, + ssl: Arc, buf: Vec } @@ -407,7 +408,7 @@ impl SslStream { fn new_base(ssl:Ssl, stream: S) -> SslStream { SslStream { stream: stream, - ssl: ssl, + ssl: Arc::new(ssl), // Maximum TLS record size is 16k buf: Vec::from_elem(16 * 1024, 0u8) } @@ -465,7 +466,7 @@ impl SslStream { fn in_retry_wrapper(&mut self, blk: |&Ssl| -> c_int) -> Result { loop { - let ret = blk(&self.ssl); + let ret = blk(&*self.ssl); if ret > 0 { return Ok(ret); } diff --git a/src/ssl/tests.rs b/src/ssl/tests.rs index 99ef2386..e4414f84 100644 --- a/src/ssl/tests.rs +++ b/src/ssl/tests.rs @@ -1,7 +1,6 @@ use serialize::hex::FromHex; use std::io::{Writer}; use std::io::net::tcp::TcpStream; -use std::str; use crypto::hash::HashType::{SHA256}; use ssl::SslMethod::Sslv23; @@ -191,6 +190,17 @@ fn test_read() { let mut stream = SslStream::new(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); stream.write("GET /\r\n\r\n".as_bytes()).unwrap(); stream.flush().unwrap(); - let buf = stream.read_to_end().ok().expect("read error"); - print!("{}", str::from_utf8(buf.as_slice())); + stream.read_to_end().ok().expect("read error"); +} + +#[test] +fn test_clone() { + let stream = TcpStream::connect("127.0.0.1:15418").unwrap(); + let mut stream = SslStream::new(&SslContext::new(Sslv23).unwrap(), stream).unwrap(); + let mut stream2 = stream.clone(); + spawn(proc() { + stream2.write("GET /\r\n\r\n".as_bytes()).unwrap(); + stream2.flush().unwrap(); + }); + stream.read_to_end().ok().expect("read error"); } -- cgit v1.2.3