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/ssl/ffi.rs | 91 ++------------------ src/ssl/mod.rs | 248 +++++-------------------------------------------------- src/ssl/tests.rs | 20 ++++- 3 files changed, 49 insertions(+), 310 deletions(-) (limited to 'src/ssl') 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 +} -- 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/ssl/error.rs | 2 +- src/ssl/ffi.rs | 117 ------------------------------------------------------- src/ssl/mod.rs | 12 +++--- 3 files changed, 7 insertions(+), 124 deletions(-) delete mode 100755 src/ssl/ffi.rs (limited to 'src/ssl') 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, -- 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/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ssl') 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 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/ssl/mod.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/ssl/tests.rs | 49 +++++++++++++++++++++++++++++++-- 2 files changed, 129 insertions(+), 3 deletions(-) (limited to 'src/ssl') 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(); -- 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/ssl') 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 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/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ssl') 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 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/ssl/error.rs | 19 ++++++++++--------- src/ssl/mod.rs | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'src/ssl') 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/ssl') 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/ssl') 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/ssl/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/ssl') 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/ssl') 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 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/ssl') 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/ssl') 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/ssl/tests.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src/ssl') 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/ssl/tests.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src/ssl') 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/ssl') 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/ssl/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/ssl') 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| { -- 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/ssl/tests.rs | 13 ------------- 1 file changed, 13 deletions(-) (limited to 'src/ssl') 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 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/ssl/error.rs | 47 +++++++++++++++++++++++++++++------------------ src/ssl/mod.rs | 5 ++--- 2 files changed, 31 insertions(+), 21 deletions(-) (limited to 'src/ssl') 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/ssl/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/ssl') 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/ssl/mod.rs | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) (limited to 'src/ssl') 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 { -- 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/ssl/tests.rs | 57 ++++++-------------------------------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) (limited to 'src/ssl') 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 -} -- 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/ssl/error.rs | 2 +- src/ssl/tests.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src/ssl') 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) } } -- 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/ssl') 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 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/ssl/error.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'src/ssl') 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/ssl/mod.rs | 20 ++++++++++---------- src/ssl/tests.rs | 6 ++++-- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'src/ssl') 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] -- 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/ssl') 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 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 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ssl') 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); -- 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/ssl') 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/ssl') 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/ssl') 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/ssl/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ssl') 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 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/ssl') 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/ssl') 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