diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 6d9ffb39..5c937d29 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -117,6 +117,9 @@ pub const MBSTRING_UTF8: c_int = MBSTRING_FLAG; pub const NID_ext_key_usage: c_int = 126; pub const NID_key_usage: c_int = 83; +pub const SSL_CTRL_OPTIONS: c_int = 32; +pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; + pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55; pub const SSL_ERROR_NONE: c_int = 0; pub const SSL_ERROR_SSL: c_int = 1; @@ -237,6 +240,18 @@ pub unsafe fn BIO_eof(b: *mut BIO) -> bool { BIO_ctrl(b, BIO_CTRL_EOF, 0, ptr::null_mut()) == 1 } +pub unsafe fn SSL_CTX_set_options(ssl: *mut SSL_CTX, op: c_long) -> c_long { + SSL_CTX_ctrl(ssl, SSL_CTRL_OPTIONS, op, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_get_options(ssl: *mut SSL_CTX) -> c_long { + SSL_CTX_ctrl(ssl, SSL_CTRL_OPTIONS, 0, ptr::null_mut()) +} + +pub unsafe fn SSL_CTX_clear_options(ssl: *mut SSL_CTX, op: c_long) -> c_long { + SSL_CTX_ctrl(ssl, SSL_CTRL_CLEAR_OPTIONS, (op), ptr::null_mut()) +} + // True functions extern "C" { pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; @@ -475,6 +490,8 @@ extern "C" { pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; + pub fn SSL_CTX_ctrl(ssl: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long; + pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; pub fn X509_digest(x: *mut X509, digest: *const EVP_MD, buf: *mut c_char, len: *mut c_uint) -> c_int; pub fn X509_free(x: *mut X509); diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 8c7074b1..140e8ce8 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -24,3 +24,6 @@ libc = "0.1" [dev-dependencies] rustc-serialize = "0.2" + +[dependencies] +bitflags = "0.1.1" diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index df998ff0..bfebc2f8 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -2,6 +2,9 @@ #![cfg_attr(test, feature(net, fs))] #![doc(html_root_url="https://sfackler.github.io/rust-openssl/doc/openssl")] +#[macro_use] +extern crate bitflags; + extern crate libc; #[cfg(test)] extern crate "rustc-serialize" as serialize; diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 06e37aac..a26c0578 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -40,6 +40,39 @@ 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 + } +} + /// Determines the SSL method supported #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -286,6 +319,29 @@ impl SslContext { ffi::SSL_CTX_set_cipher_list(*self.ctx, cipher_list.as_ptr()) }) } + + pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions { + let raw_bits = option.bits(); + let ret = unsafe { + ffi::SSL_CTX_set_options(*self.ctx, raw_bits) + }; + SslContextOptions::from_bits(ret).unwrap() + } + + pub fn get_options(&mut self) -> SslContextOptions { + let ret = unsafe { + ffi::SSL_CTX_get_options(*self.ctx) + }; + SslContextOptions::from_bits(ret).unwrap() + } + + pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions { + let raw_bits = option.bits(); + let ret = unsafe { + ffi::SSL_CTX_clear_options(*self.ctx, raw_bits) + }; + SslContextOptions::from_bits(ret).unwrap() + } } #[allow(dead_code)] diff --git a/openssl/src/ssl/tests.rs b/openssl/src/ssl/tests.rs index 41e54baa..5196b870 100644 --- a/openssl/src/ssl/tests.rs +++ b/openssl/src/ssl/tests.rs @@ -5,6 +5,7 @@ use std::io::prelude::*; use std::path::Path; use crypto::hash::Type::{SHA256}; +use ssl; use ssl::SslMethod::Sslv23; use ssl::{SslContext, SslStream, VerifyCallback}; use ssl::SslVerifyMode::SslVerifyPeer; @@ -175,6 +176,30 @@ fn test_verify_callback_data() { } } +#[test] +fn test_get_ctx_options() { + let mut ctx = SslContext::new(Sslv23).unwrap(); + ctx.get_options(); +} + +#[test] +fn test_set_ctx_options() { + let mut ctx = SslContext::new(Sslv23).unwrap(); + let opts = ctx.set_options(ssl::SSL_OP_NO_TICKET); + assert!(opts.contains(ssl::SSL_OP_NO_TICKET)); + assert!(!opts.contains(ssl::SSL_OP_CISCO_ANYCONNECT)); + let more_opts = ctx.set_options(ssl::SSL_OP_CISCO_ANYCONNECT); + assert!(more_opts.contains(ssl::SSL_OP_NO_TICKET)); + assert!(more_opts.contains(ssl::SSL_OP_CISCO_ANYCONNECT)); +} + +#[test] +fn test_clear_ctx_options() { + let mut ctx = SslContext::new(Sslv23).unwrap(); + ctx.set_options(ssl::SSL_OP_ALL); + let opts = ctx.clear_options(ssl::SSL_OP_ALL); + assert!(!opts.contains(ssl::SSL_OP_ALL)); +} #[test] fn test_write() {