aboutsummaryrefslogtreecommitdiff
path: root/openssl/src/ssl/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'openssl/src/ssl/mod.rs')
-rw-r--r--openssl/src/ssl/mod.rs145
1 files changed, 114 insertions, 31 deletions
diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs
index 88ba9af4..35180d3a 100644
--- a/openssl/src/ssl/mod.rs
+++ b/openssl/src/ssl/mod.rs
@@ -6,6 +6,7 @@ use std::fmt;
use std::io;
use std::io::prelude::*;
use std::mem;
+use std::str;
use std::net;
use std::path::Path;
use std::ptr;
@@ -30,7 +31,9 @@ mod tests;
static mut VERIFY_IDX: c_int = -1;
-fn init() {
+/// Manually initialize SSL.
+/// It is optional to call this function and safe to do so more than once.
+pub fn init() {
static mut INIT: Once = ONCE_INIT;
unsafe {
@@ -46,35 +49,52 @@ fn init() {
}
bitflags! {
- flags SslContextOptions: c_long {
- const SSL_OP_LEGACY_SERVER_CONNECT = 0x00000004,
- const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008,
- const SSL_OP_TLSEXT_PADDING = 0x00000010,
- const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020,
- const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = 0x00000040,
- const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080,
- const SSL_OP_TLS_D5_BUG = 0x00000100,
- const SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200,
- const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800,
- const SSL_OP_ALL = 0x80000BFF,
- const SSL_OP_NO_QUERY_MTU = 0x00001000,
- const SSL_OP_COOKIE_EXCHANGE = 0x00002000,
- const SSL_OP_NO_TICKET = 0x00004000,
- const SSL_OP_CISCO_ANYCONNECT = 0x00008000,
- const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000,
- const SSL_OP_NO_COMPRESSION = 0x00020000,
- const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0x00040000,
- const SSL_OP_SINGLE_ECDH_USE = 0x00080000,
- const SSL_OP_SINGLE_DH_USE = 0x00100000,
- const SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000,
- const SSL_OP_TLS_ROLLBACK_BUG = 0x00800000,
- const SSL_OP_NO_SSLV2 = 0x00000000,
- const SSL_OP_NO_SSLV3 = 0x02000000,
- const SSL_OP_NO_TLSV1 = 0x04000000,
- const SSL_OP_NO_TLSV1_2 = 0x08000000,
- const SSL_OP_NO_TLSV1_1 = 0x10000000,
- const SSL_OP_NO_DTLSV1 = 0x04000000,
- const SSL_OP_NO_DTLSV1_2 = 0x08000000
+ flags SslContextOptions: u64 {
+ const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG,
+ const SSL_OP_NETSCAPE_CHALLENGE_BUG = ffi::SSL_OP_NETSCAPE_CHALLENGE_BUG,
+ const SSL_OP_LEGACY_SERVER_CONNECT = ffi::SSL_OP_LEGACY_SERVER_CONNECT,
+ const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = ffi::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG,
+ const SSL_OP_TLSEXT_PADDING = ffi::SSL_OP_TLSEXT_PADDING,
+ const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = ffi::SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER,
+ const SSL_OP_SAFARI_ECDHE_ECDSA_BUG = ffi::SSL_OP_SAFARI_ECDHE_ECDSA_BUG,
+ const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = ffi::SSL_OP_SSLEAY_080_CLIENT_DH_BUG,
+ const SSL_OP_TLS_D5_BUG = ffi::SSL_OP_TLS_D5_BUG,
+ const SSL_OP_TLS_BLOCK_PADDING_BUG = ffi::SSL_OP_TLS_BLOCK_PADDING_BUG,
+ const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS,
+ const SSL_OP_NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU,
+ const SSL_OP_COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE,
+ const SSL_OP_NO_TICKET = ffi::SSL_OP_NO_TICKET,
+ const SSL_OP_CISCO_ANYCONNECT = ffi::SSL_OP_CISCO_ANYCONNECT,
+ const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION,
+ const SSL_OP_NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION,
+ const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION,
+ const SSL_OP_SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE,
+ const SSL_OP_SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE,
+ const SSL_OP_CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE,
+ const SSL_OP_TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG,
+ const SSL_OP_NO_SSLV2 = ffi::SSL_OP_NO_SSLv2,
+ const SSL_OP_NO_SSLV3 = ffi::SSL_OP_NO_SSLv3,
+ const SSL_OP_NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1,
+ const SSL_OP_NO_TLSV1 = ffi::SSL_OP_NO_TLSv1,
+ const SSL_OP_NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2,
+ const SSL_OP_NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2,
+ const SSL_OP_NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1,
+ const SSL_OP_NETSCAPE_CA_DN_BUG = ffi::SSL_OP_NETSCAPE_CA_DN_BUG,
+ const SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = ffi::SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG,
+ const SSL_OP_CRYPTOPRO_TLSEXT_BUG = ffi::SSL_OP_CRYPTOPRO_TLSEXT_BUG,
+ const SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = ffi::SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG,
+ const SSL_OP_MSIE_SSLV2_RSA_PADDING = ffi::SSL_OP_MSIE_SSLV2_RSA_PADDING,
+ const SSL_OP_PKCS1_CHECK_1 = ffi::SSL_OP_PKCS1_CHECK_1,
+ const SSL_OP_PKCS1_CHECK_2 = ffi::SSL_OP_PKCS1_CHECK_2,
+ const SSL_OP_EPHEMERAL_RSA = ffi::SSL_OP_EPHEMERAL_RSA,
+ const SSL_OP_ALL = SSL_OP_MICROSOFT_SESS_ID_BUG.bits|SSL_OP_NETSCAPE_CHALLENGE_BUG.bits
+ |SSL_OP_LEGACY_SERVER_CONNECT.bits|SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG.bits
+ |SSL_OP_TLSEXT_PADDING.bits|SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER.bits
+ |SSL_OP_SAFARI_ECDHE_ECDSA_BUG.bits|SSL_OP_SSLEAY_080_CLIENT_DH_BUG.bits
+ |SSL_OP_TLS_D5_BUG.bits|SSL_OP_TLS_BLOCK_PADDING_BUG.bits
+ |SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS.bits|SSL_OP_CRYPTOPRO_TLSEXT_BUG.bits,
+ const SSL_OP_NO_SSL_MASK = SSL_OP_NO_SSLV2.bits|SSL_OP_NO_SSLV3.bits|SSL_OP_NO_TLSV1.bits
+ |SSL_OP_NO_TLSV1_1.bits|SSL_OP_NO_TLSV1_2.bits,
}
}
@@ -124,6 +144,25 @@ impl SslMethod {
}
}
+ unsafe fn from_raw(method: *const ffi::SSL_METHOD) -> Option<SslMethod> {
+ match method {
+ #[cfg(feature = "sslv2")]
+ x if x == ffi::SSLv2_method() => Some(SslMethod::Sslv2),
+ x if x == ffi::SSLv3_method() => Some(SslMethod::Sslv3),
+ x if x == ffi::TLSv1_method() => Some(SslMethod::Tlsv1),
+ x if x == ffi::SSLv23_method() => Some(SslMethod::Sslv23),
+ #[cfg(feature = "tlsv1_1")]
+ x if x == ffi::TLSv1_1_method() => Some(SslMethod::Tlsv1_1),
+ #[cfg(feature = "tlsv1_2")]
+ x if x == ffi::TLSv1_2_method() => Some(SslMethod::Tlsv1_2),
+ #[cfg(feature = "dtlsv1")]
+ x if x == ffi::DTLSv1_method() => Some(SslMethod::Dtlsv1),
+ #[cfg(feature = "dtlsv1_2")]
+ x if x == ffi::DTLSv1_2_method() => Some(SslMethod::Dtlsv1_2),
+ _ => None,
+ }
+ }
+
#[cfg(feature = "dtlsv1")]
pub fn is_dtlsv1(&self) -> bool {
*self == SslMethod::Dtlsv1
@@ -652,6 +691,24 @@ impl Ssl {
Ok(ssl)
}
+ pub fn get_state_string(&self) -> &'static str {
+ let state = unsafe {
+ let ptr = ffi::SSL_state_string(self.ssl);
+ CStr::from_ptr(ptr)
+ };
+
+ str::from_utf8(state.to_bytes()).unwrap()
+ }
+
+ pub fn get_state_string_long(&self) -> &'static str {
+ let state = unsafe {
+ let ptr = ffi::SSL_state_string_long(self.ssl);
+ CStr::from_ptr(ptr)
+ };
+
+ str::from_utf8(state.to_bytes()).unwrap()
+ }
+
fn get_rbio<'a>(&'a self) -> MemBioRef<'a> {
unsafe { self.wrap_bio(ffi::SSL_get_rbio(self.ssl)) }
}
@@ -770,6 +827,13 @@ impl Ssl {
ffi::SSL_pending(self.ssl) as usize
}
}
+
+ pub fn get_ssl_method(&self) -> Option<SslMethod> {
+ unsafe {
+ let method = ffi::SSL_get_ssl_method(self.ssl);
+ SslMethod::from_raw(method)
+ }
+ }
}
macro_rules! make_LibSslError {
@@ -871,8 +935,16 @@ impl<S: Read+Write> IndirectStream<S> {
LibSslError::ErrorWantRead => {
try_ssl_stream!(self.flush());
let len = try_ssl_stream!(self.stream.read(&mut self.buf[..]));
+
+
if len == 0 {
- self.ssl.get_rbio().set_eof(true);
+ let method = self.ssl.get_ssl_method();
+
+ if method.map(|m| m.is_dtls()).unwrap_or(false) {
+ return Ok(0);
+ } else {
+ self.ssl.get_rbio().set_eof(true);
+ }
} else {
try_ssl_stream!(self.ssl.get_rbio().write_all(&self.buf[..len]));
}
@@ -993,6 +1065,9 @@ impl<S> DirectStream<S> {
err
}
}
+ LibSslError::ErrorWantWrite | LibSslError::ErrorWantRead => {
+ SslError::StreamError(io::Error::last_os_error())
+ }
err => panic!("unexpected error {:?} with ret {}", err, ret),
}
}
@@ -1260,6 +1335,14 @@ impl<S: Read+Write> SslStream<S> {
pub fn pending(&self) -> usize {
self.kind.ssl().pending()
}
+
+ pub fn get_state_string(&self) -> &'static str {
+ self.kind.ssl().get_state_string()
+ }
+
+ pub fn get_state_string_long(&self) -> &'static str {
+ self.kind.ssl().get_state_string_long()
+ }
}
impl<S: Read+Write> Read for SslStream<S> {