Loading error.rs +1 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ use std::libc::c_ulong; use super::ffi; #[deriving(ToStr)] pub enum SslError { StreamEof, SslSessionClosed, Loading ffi.rs +28 −2 Original line number Diff line number Diff line #[doc(hidden)]; use std::libc::{c_int, c_void, c_ulong, c_char}; use std::libc::{c_int, c_void, c_long, c_ulong, c_char}; // openssl/ssl.h pub type SSL_CTX = c_void; Loading @@ -9,6 +9,19 @@ 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 CRYPTO_EX_DATA = c_void; pub type CRYPTO_EX_new = Option<extern "C" fn(parent: *c_void, ptr: *c_void, ad: *CRYPTO_EX_DATA, idx: c_int, argl: c_long, argp: *c_void) -> c_int>; pub type CRYPTO_EX_dup = extern "C" fn(to: *CRYPTO_EX_DATA, from: *CRYPTO_EX_DATA, from_d: *c_void, idx: c_int, argl: c_long, argp: *c_void) -> c_int; pub type CRYPTO_EX_free = extern "C" fn(parent: *c_void, ptr: *c_void, ad: *CRYPTO_EX_DATA, idx: c_int, argl: c_long, argp: *c_void); pub static SSL_ERROR_NONE: c_int = 0; pub static SSL_ERROR_SSL: c_int = 1; Loading Loading @@ -38,9 +51,20 @@ externfn!(fn SSLv23_method() -> *SSL_METHOD) externfn!(fn SSL_CTX_new(method: *SSL_METHOD) -> *SSL_CTX) externfn!(fn SSL_CTX_free(ctx: *SSL_CTX)) externfn!(fn SSL_CTX_set_verify(ctx: *SSL_CTX, mode: c_int, verify_callback: Option<extern "C" fn(int, *X509_STORE_CTX) -> c_int>)) verify_callback: Option<extern "C" fn(c_int, *X509_STORE_CTX) -> c_int>)) externfn!(fn SSL_CTX_load_verify_locations(ctx: *SSL_CTX, CAfile: *c_char, CApath: *c_char) -> c_int) externfn!(fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *c_void, new_func: Option<CRYPTO_EX_new>, dup_func: Option<CRYPTO_EX_dup>, free_func: Option<CRYPTO_EX_free>) -> c_int) externfn!(fn SSL_CTX_set_ex_data(ctx: *SSL_CTX, idx: c_int, data: *c_void) -> c_int) externfn!(fn SSL_CTX_get_ex_data(ctx: *SSL_CTX, idx: c_int) -> *c_void) externfn!(fn X509_STORE_CTX_get_ex_data(ctx: *X509_STORE_CTX, idx: c_int) -> *c_void) externfn!(fn SSL_new(ctx: *SSL_CTX) -> *SSL) externfn!(fn SSL_free(ssl: *SSL)) Loading @@ -53,6 +77,8 @@ externfn!(fn SSL_get_error(ssl: *SSL, ret: c_int) -> c_int) externfn!(fn SSL_read(ssl: *SSL, buf: *c_void, num: c_int) -> c_int) externfn!(fn SSL_write(ssl: *SSL, buf: *c_void, num: c_int) -> c_int) externfn!(fn SSL_shutdown(ssl: *SSL) -> c_int) externfn!(fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int) externfn!(fn SSL_get_SSL_CTX(ssl: *SSL) -> *SSL_CTX) externfn!(fn BIO_s_mem() -> *BIO_METHOD) externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO) Loading lib.rs +35 −3 Original line number Diff line number Diff line use std::cast; use std::libc::{c_int, c_void}; use std::ptr; use std::task; use std::unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, Acquire, Release}; use std::unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, AtomicInt, INIT_ATOMIC_INT, Acquire, Release, SeqCst}; use std::rt::io::{Stream, Reader, Writer, Decorator}; use std::vec; Loading @@ -17,6 +19,8 @@ mod ffi; static mut STARTED_INIT: AtomicBool = INIT_ATOMIC_BOOL; static mut FINISHED_INIT: AtomicBool = INIT_ATOMIC_BOOL; static mut VERIFY_IDX: AtomicInt = INIT_ATOMIC_INT; pub fn init() { unsafe { if STARTED_INIT.swap(true, Acquire) { Loading @@ -27,6 +31,11 @@ pub fn init() { } ffi::SSL_library_init(); let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None); assert!(verify_idx >= 0); VERIFY_IDX.store(verify_idx as int, SeqCst); FINISHED_INIT.store(true, Release); } } Loading Loading @@ -54,6 +63,25 @@ pub enum SslVerifyMode { SslVerifyNone = ffi::SSL_VERIFY_NONE } extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *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 idx = VERIFY_IDX.load(SeqCst) as c_int; let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, idx); let verify: Option<VerifyCallback> = cast::transmute(verify); match verify { None => preverify_ok, Some(verify) => verify(preverify_ok != 0) as c_int } } } pub type VerifyCallback = extern "Rust" fn(preverify_ok: bool) -> bool; pub struct SslContext { priv ctx: *ffi::SSL_CTX } Loading Loading @@ -84,9 +112,13 @@ impl SslContext { } // TODO: support callback (see SSL_CTX_set_ex_data) pub fn set_verify(&mut self, mode: SslVerifyMode) { pub fn set_verify(&mut self, mode: SslVerifyMode, verify: Option<VerifyCallback>) { unsafe { ffi::SSL_CTX_set_verify(self.ctx, mode as c_int, None); let idx = VERIFY_IDX.load(SeqCst) as c_int; ffi::SSL_CTX_set_ex_data(self.ctx, idx, cast::transmute(verify)); ffi::SSL_CTX_set_verify(self.ctx, mode as c_int, Some(raw_verify)); } } Loading tests.rs +54 −2 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ fn test_new_sslstream() { fn test_verify_untrusted() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer); ctx.set_verify(SslVerifyPeer, None); match SslStream::try_new(&ctx, stream) { Ok(_) => fail!("expected failure"), Err(err) => println!("error {:?}", err) Loading @@ -31,7 +31,7 @@ fn test_verify_untrusted() { fn test_verify_trusted() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer); ctx.set_verify(SslVerifyPeer, None); assert!(ctx.set_CA_file("cert.pem").is_none()); match SslStream::try_new(&ctx, stream) { Ok(_) => (), Loading @@ -39,6 +39,58 @@ fn test_verify_trusted() { } } #[test] fn test_verify_untrusted_callback_override_ok() { fn callback(_preverify_ok: bool) -> bool { true } let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer, Some(callback)); match SslStream::try_new(&ctx, stream) { Ok(_) => (), Err(err) => fail!("Expected success, got {:?}", err) } } #[test] fn test_verify_untrusted_callback_override_bad() { fn callback(_preverify_ok: bool) -> bool { false } let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(SslStream::try_new(&ctx, stream).is_err()); } #[test] fn test_verify_trusted_callback_override_ok() { fn callback(_preverify_ok: bool) -> bool { true } let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(ctx.set_CA_file("cert.pem").is_none()); match SslStream::try_new(&ctx, stream) { Ok(_) => (), Err(err) => fail!("Expected success, got {:?}", err) } } #[test] fn test_verify_trusted_callback_override_bad() { fn callback(_preverify_ok: bool) -> bool { false } let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(ctx.set_CA_file("cert.pem").is_none()); assert!(SslStream::try_new(&ctx, stream).is_err()); } #[test] fn test_write() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); Loading Loading
error.rs +1 −0 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ use std::libc::c_ulong; use super::ffi; #[deriving(ToStr)] pub enum SslError { StreamEof, SslSessionClosed, Loading
ffi.rs +28 −2 Original line number Diff line number Diff line #[doc(hidden)]; use std::libc::{c_int, c_void, c_ulong, c_char}; use std::libc::{c_int, c_void, c_long, c_ulong, c_char}; // openssl/ssl.h pub type SSL_CTX = c_void; Loading @@ -9,6 +9,19 @@ 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 CRYPTO_EX_DATA = c_void; pub type CRYPTO_EX_new = Option<extern "C" fn(parent: *c_void, ptr: *c_void, ad: *CRYPTO_EX_DATA, idx: c_int, argl: c_long, argp: *c_void) -> c_int>; pub type CRYPTO_EX_dup = extern "C" fn(to: *CRYPTO_EX_DATA, from: *CRYPTO_EX_DATA, from_d: *c_void, idx: c_int, argl: c_long, argp: *c_void) -> c_int; pub type CRYPTO_EX_free = extern "C" fn(parent: *c_void, ptr: *c_void, ad: *CRYPTO_EX_DATA, idx: c_int, argl: c_long, argp: *c_void); pub static SSL_ERROR_NONE: c_int = 0; pub static SSL_ERROR_SSL: c_int = 1; Loading Loading @@ -38,9 +51,20 @@ externfn!(fn SSLv23_method() -> *SSL_METHOD) externfn!(fn SSL_CTX_new(method: *SSL_METHOD) -> *SSL_CTX) externfn!(fn SSL_CTX_free(ctx: *SSL_CTX)) externfn!(fn SSL_CTX_set_verify(ctx: *SSL_CTX, mode: c_int, verify_callback: Option<extern "C" fn(int, *X509_STORE_CTX) -> c_int>)) verify_callback: Option<extern "C" fn(c_int, *X509_STORE_CTX) -> c_int>)) externfn!(fn SSL_CTX_load_verify_locations(ctx: *SSL_CTX, CAfile: *c_char, CApath: *c_char) -> c_int) externfn!(fn SSL_CTX_get_ex_new_index(argl: c_long, argp: *c_void, new_func: Option<CRYPTO_EX_new>, dup_func: Option<CRYPTO_EX_dup>, free_func: Option<CRYPTO_EX_free>) -> c_int) externfn!(fn SSL_CTX_set_ex_data(ctx: *SSL_CTX, idx: c_int, data: *c_void) -> c_int) externfn!(fn SSL_CTX_get_ex_data(ctx: *SSL_CTX, idx: c_int) -> *c_void) externfn!(fn X509_STORE_CTX_get_ex_data(ctx: *X509_STORE_CTX, idx: c_int) -> *c_void) externfn!(fn SSL_new(ctx: *SSL_CTX) -> *SSL) externfn!(fn SSL_free(ssl: *SSL)) Loading @@ -53,6 +77,8 @@ externfn!(fn SSL_get_error(ssl: *SSL, ret: c_int) -> c_int) externfn!(fn SSL_read(ssl: *SSL, buf: *c_void, num: c_int) -> c_int) externfn!(fn SSL_write(ssl: *SSL, buf: *c_void, num: c_int) -> c_int) externfn!(fn SSL_shutdown(ssl: *SSL) -> c_int) externfn!(fn SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int) externfn!(fn SSL_get_SSL_CTX(ssl: *SSL) -> *SSL_CTX) externfn!(fn BIO_s_mem() -> *BIO_METHOD) externfn!(fn BIO_new(type_: *BIO_METHOD) -> *BIO) Loading
lib.rs +35 −3 Original line number Diff line number Diff line use std::cast; use std::libc::{c_int, c_void}; use std::ptr; use std::task; use std::unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, Acquire, Release}; use std::unstable::atomics::{AtomicBool, INIT_ATOMIC_BOOL, AtomicInt, INIT_ATOMIC_INT, Acquire, Release, SeqCst}; use std::rt::io::{Stream, Reader, Writer, Decorator}; use std::vec; Loading @@ -17,6 +19,8 @@ mod ffi; static mut STARTED_INIT: AtomicBool = INIT_ATOMIC_BOOL; static mut FINISHED_INIT: AtomicBool = INIT_ATOMIC_BOOL; static mut VERIFY_IDX: AtomicInt = INIT_ATOMIC_INT; pub fn init() { unsafe { if STARTED_INIT.swap(true, Acquire) { Loading @@ -27,6 +31,11 @@ pub fn init() { } ffi::SSL_library_init(); let verify_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None, None, None); assert!(verify_idx >= 0); VERIFY_IDX.store(verify_idx as int, SeqCst); FINISHED_INIT.store(true, Release); } } Loading Loading @@ -54,6 +63,25 @@ pub enum SslVerifyMode { SslVerifyNone = ffi::SSL_VERIFY_NONE } extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *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 idx = VERIFY_IDX.load(SeqCst) as c_int; let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, idx); let verify: Option<VerifyCallback> = cast::transmute(verify); match verify { None => preverify_ok, Some(verify) => verify(preverify_ok != 0) as c_int } } } pub type VerifyCallback = extern "Rust" fn(preverify_ok: bool) -> bool; pub struct SslContext { priv ctx: *ffi::SSL_CTX } Loading Loading @@ -84,9 +112,13 @@ impl SslContext { } // TODO: support callback (see SSL_CTX_set_ex_data) pub fn set_verify(&mut self, mode: SslVerifyMode) { pub fn set_verify(&mut self, mode: SslVerifyMode, verify: Option<VerifyCallback>) { unsafe { ffi::SSL_CTX_set_verify(self.ctx, mode as c_int, None); let idx = VERIFY_IDX.load(SeqCst) as c_int; ffi::SSL_CTX_set_ex_data(self.ctx, idx, cast::transmute(verify)); ffi::SSL_CTX_set_verify(self.ctx, mode as c_int, Some(raw_verify)); } } Loading
tests.rs +54 −2 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ fn test_new_sslstream() { fn test_verify_untrusted() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer); ctx.set_verify(SslVerifyPeer, None); match SslStream::try_new(&ctx, stream) { Ok(_) => fail!("expected failure"), Err(err) => println!("error {:?}", err) Loading @@ -31,7 +31,7 @@ fn test_verify_untrusted() { fn test_verify_trusted() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer); ctx.set_verify(SslVerifyPeer, None); assert!(ctx.set_CA_file("cert.pem").is_none()); match SslStream::try_new(&ctx, stream) { Ok(_) => (), Loading @@ -39,6 +39,58 @@ fn test_verify_trusted() { } } #[test] fn test_verify_untrusted_callback_override_ok() { fn callback(_preverify_ok: bool) -> bool { true } let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer, Some(callback)); match SslStream::try_new(&ctx, stream) { Ok(_) => (), Err(err) => fail!("Expected success, got {:?}", err) } } #[test] fn test_verify_untrusted_callback_override_bad() { fn callback(_preverify_ok: bool) -> bool { false } let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(SslStream::try_new(&ctx, stream).is_err()); } #[test] fn test_verify_trusted_callback_override_ok() { fn callback(_preverify_ok: bool) -> bool { true } let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(ctx.set_CA_file("cert.pem").is_none()); match SslStream::try_new(&ctx, stream) { Ok(_) => (), Err(err) => fail!("Expected success, got {:?}", err) } } #[test] fn test_verify_trusted_callback_override_bad() { fn callback(_preverify_ok: bool) -> bool { false } let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); let mut ctx = SslContext::new(Sslv23); ctx.set_verify(SslVerifyPeer, Some(callback)); assert!(ctx.set_CA_file("cert.pem").is_none()); assert!(SslStream::try_new(&ctx, stream).is_err()); } #[test] fn test_write() { let stream = TcpStream::connect(FromStr::from_str("127.0.0.1:15418").unwrap()).unwrap(); Loading