Decouple C SSL Option bit flags from Rust version

The OpenSSL "SSL_OP_*" flags are in constant flux between different OpenSSL
versions. To avoid having to change the Rust definitions, we implement our
own numbering system in Rust, and use an automatically-generated C shim to
convert the bitflags at runtime.
This commit is contained in:
Jethro Beekman 2015-07-01 21:49:11 -07:00
parent 2a4d7165f4
commit aeefa364b7
4 changed files with 182 additions and 35 deletions

View File

@ -2,7 +2,10 @@ extern crate pkg_config;
extern crate gcc;
use std::env;
use std::fmt::Write as FmtWrite;
use std::path::PathBuf;
use std::fs::File;
use std::io::Write;
fn main() {
let target = env::var("TARGET").unwrap();
@ -65,7 +68,67 @@ fn main() {
build_openssl_shim(&include_dirs);
}
macro_rules! import_options {
( $( $name:ident $val:expr )* ) => {
&[ $( (stringify!($name),$val), )* ]
};
}
fn generate_options_shim() -> PathBuf {
let options: &[(&'static str,u64)]=include!("src/ssl_options.rs");
let mut shim = String::new();
writeln!(shim,"#include <stdint.h>").unwrap();
writeln!(shim,"#include <openssl/ssl.h>").unwrap();
for &(name,value) in options {
writeln!(shim,"#define RUST_{} UINT64_C({})",name,value).unwrap();
writeln!(shim,"#ifndef {}",name).unwrap();
writeln!(shim,"# define {} 0",name).unwrap();
writeln!(shim,"#endif").unwrap();
}
writeln!(shim,"#define COPY_MASK ( \\").unwrap();
let mut it=options.iter().peekable();
while let Some(&(name,_))=it.next() {
let eol=match it.peek() {
Some(_) => " | \\",
None => " )"
};
writeln!(shim," ((RUST_{0}==(uint64_t)(uint32_t){0})?RUST_{0}:UINT64_C(0)){1}",name,eol).unwrap();
}
writeln!(shim,"long rust_openssl_ssl_ctx_options_rust_to_c(uint64_t rustval) {{").unwrap();
writeln!(shim," long cval=rustval&COPY_MASK;").unwrap();
for &(name,_) in options {
writeln!(shim,"#if RUST_{0}!={0}",name).unwrap();
writeln!(shim," if (rustval&RUST_{0}) cval|={0};",name).unwrap();
writeln!(shim,"#endif").unwrap();
}
writeln!(shim," return cval;").unwrap();
writeln!(shim,"}}").unwrap();
writeln!(shim,"uint64_t rust_openssl_ssl_ctx_options_c_to_rust(long cval) {{").unwrap();
writeln!(shim," uint64_t rustval=cval&COPY_MASK;").unwrap();
for &(name,_) in options {
writeln!(shim,"#if RUST_{0}!={0}",name).unwrap();
writeln!(shim," if (cval&{0}) rustval|=RUST_{0};",name).unwrap();
writeln!(shim,"#endif").unwrap();
}
writeln!(shim," return rustval;").unwrap();
writeln!(shim,"}}").unwrap();
let out_dir = env::var("OUT_DIR").unwrap();
let dest_file = PathBuf::from(&out_dir).join("ssl_ctx_options_shim.c");
let mut f = File::create(&dest_file).unwrap();
f.write_all(shim.as_bytes()).unwrap();
dest_file
}
fn build_openssl_shim(include_paths: &[PathBuf]) {
let options_shim_file = generate_options_shim();
let mut config = gcc::Config::new();
for path in include_paths {
@ -73,6 +136,7 @@ fn build_openssl_shim(include_paths: &[PathBuf]) {
}
config.file("src/openssl_shim.c")
.file(options_shim_file)
.compile("libopenssl_shim.a");
}

View File

@ -155,6 +155,14 @@ pub const SSL_TLSEXT_ERR_ALERT_WARNING: c_int = 1;
pub const SSL_TLSEXT_ERR_ALERT_FATAL: c_int = 2;
pub const SSL_TLSEXT_ERR_NOACK: c_int = 3;
macro_rules! import_options {
( $( $name:ident $val:expr )* ) => {
$( pub const $name: u64 = $val; )*
};
}
include!("ssl_options.rs");
#[cfg(feature = "npn")]
pub const OPENSSL_NPN_UNSUPPORTED: c_int = 0;
#[cfg(feature = "npn")]
@ -262,8 +270,23 @@ pub fn init() {
}
}
pub unsafe fn SSL_CTX_set_options(ssl: *mut SSL_CTX, op: u64) -> u64 {
rust_openssl_ssl_ctx_options_c_to_rust(SSL_CTX_set_options_shim(ssl, rust_openssl_ssl_ctx_options_rust_to_c(op)))
}
pub unsafe fn SSL_CTX_get_options(ssl: *mut SSL_CTX) -> u64 {
rust_openssl_ssl_ctx_options_c_to_rust(SSL_CTX_get_options_shim(ssl))
}
pub unsafe fn SSL_CTX_clear_options(ssl: *mut SSL_CTX, op: u64) -> u64 {
rust_openssl_ssl_ctx_options_c_to_rust(SSL_CTX_clear_options_shim(ssl, rust_openssl_ssl_ctx_options_rust_to_c(op)))
}
// True functions
extern "C" {
fn rust_openssl_ssl_ctx_options_rust_to_c(rustval: u64) -> c_long;
fn rust_openssl_ssl_ctx_options_c_to_rust(cval: c_long) -> u64;
pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int;
pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING;
pub fn ASN1_TIME_free(tm: *mut ASN1_TIME);
@ -615,12 +638,9 @@ extern "C" {
pub fn BIO_eof(b: *mut BIO) -> c_int;
#[link_name = "BIO_set_mem_eof_return_shim"]
pub fn BIO_set_mem_eof_return(b: *mut BIO, v: c_int);
#[link_name = "SSL_CTX_set_options_shim"]
pub fn SSL_CTX_set_options(ctx: *mut SSL_CTX, options: c_long) -> c_long;
#[link_name = "SSL_CTX_get_options_shim"]
pub fn SSL_CTX_get_options(ctx: *mut SSL_CTX) -> c_long;
#[link_name = "SSL_CTX_clear_options_shim"]
pub fn SSL_CTX_clear_options(ctx: *mut SSL_CTX, options: c_long) -> c_long;
pub fn SSL_CTX_set_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long;
pub fn SSL_CTX_get_options_shim(ctx: *mut SSL_CTX) -> c_long;
pub fn SSL_CTX_clear_options_shim(ctx: *mut SSL_CTX, options: c_long) -> c_long;
#[link_name = "SSL_CTX_add_extra_chain_cert_shim"]
pub fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) -> c_long;
#[link_name = "SSL_CTX_set_read_ahead_shim"]

View File

@ -0,0 +1,46 @@
import_options!{
// The following values are directly from recent OpenSSL
SSL_OP_MICROSOFT_SESS_ID_BUG 0x00000001
SSL_OP_NETSCAPE_CHALLENGE_BUG 0x00000002
SSL_OP_LEGACY_SERVER_CONNECT 0x00000004
SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG 0x00000008
SSL_OP_TLSEXT_PADDING 0x00000010
SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER 0x00000020
SSL_OP_SAFARI_ECDHE_ECDSA_BUG 0x00000040
SSL_OP_SSLEAY_080_CLIENT_DH_BUG 0x00000080
SSL_OP_TLS_D5_BUG 0x00000100
SSL_OP_TLS_BLOCK_PADDING_BUG 0x00000200
// unused: 0x00000400
SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS 0x00000800
SSL_OP_NO_QUERY_MTU 0x00001000
SSL_OP_COOKIE_EXCHANGE 0x00002000
SSL_OP_NO_TICKET 0x00004000
SSL_OP_CISCO_ANYCONNECT 0x00008000
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION 0x00010000
SSL_OP_NO_COMPRESSION 0x00020000
SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION 0x00040000
SSL_OP_SINGLE_ECDH_USE 0x00080000
SSL_OP_SINGLE_DH_USE 0x00100000
// unused: 0x00200000
SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000
SSL_OP_TLS_ROLLBACK_BUG 0x00800000
SSL_OP_NO_SSLv2 0x01000000
SSL_OP_NO_SSLv3 0x02000000
SSL_OP_NO_DTLSv1 0x04000000
SSL_OP_NO_TLSv1 0x04000000
SSL_OP_NO_DTLSv1_2 0x08000000
SSL_OP_NO_TLSv1_2 0x08000000
SSL_OP_NO_TLSv1_1 0x10000000
SSL_OP_NETSCAPE_CA_DN_BUG 0x20000000
SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG 0x40000000
SSL_OP_CRYPTOPRO_TLSEXT_BUG 0x80000000
// The following values were in 32-bit range in old OpenSSL
SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG 0x100000000
SSL_OP_MSIE_SSLV2_RSA_PADDING 0x200000000
SSL_OP_PKCS1_CHECK_1 0x400000000
SSL_OP_PKCS1_CHECK_2 0x800000000
// The following values were redefined to 0 for security reasons
SSL_OP_EPHEMERAL_RSA 0x0
}

View File

@ -46,35 +46,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,
}
}