diff --git a/CHANGELOG.md b/CHANGELOG.md index c0734265..3091a4fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,50 @@ ## [Unreleased] +## [v0.10.9] - 2018-06-01 + +### Fixed + +* Fixed a use-after-free in `CmsContentInfo::sign`. +* `SslRef::servername` now returns `None` rather than panicking on a non-UTF8 name. + +### Added + +* Added `MessageDigest::from_nid`. +* Added `Nid::signature_algorithms`, `Nid::long_name`, and `Nid::short_name`. +* Added early data and early keying material export support for TLS 1.3. +* Added `SslRef::verified_chain`. +* Added `SslRef::servername_raw` which returns a `&[u8]` rather than `&str`. +* Added `SslRef::finished` and `SslRef::peer_finished`. +* Added `X509Ref::digest` to replace `X509Ref::fingerprint`. +* `X509StoreBuilder` and `X509Store` now implement `Sync` and `Send`. + +### Deprecated + +* `X509Ref::fingerprint` has been deprecated in favor of `X509Ref::digest`. + +## [v0.10.8] - 2018-05-20 + +### Fixed + +* `openssl-sys` will now detect Homebrew-installed OpenSSL when installed to a non-default + directory. +* The `X509_V_ERR_INVALID_CALL`, `X509_V_ERR_STORE_LOOKUP`, and + `X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION` constants in `openssl-sys` are now only present when + building against 1.1.0g and up rather than 1.1.0. +* `SslContextBuilder::max_proto_version` and `SslContextBuilder::min_proto_version` are only present + when building against 1.1.0g and up rather than 1.1.0. + +### Added + +* Added `CmsContentInfo::sign`. +* Added `Clone` and `ToOwned` implementations to `Rsa` and `RsaRef` respectively. +* The `min_proto_version` and `max_proto_version` methods are available when linking against + LibreSSL 2.6.1 and up in addition to OpenSSL. +* `X509VerifyParam` is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* ALPN support is available when linking against LibreSSL 2.6.1 and up in addition to OpenSSL. +* `Stack` and `StackRef` are now `Sync` and `Send`. + ## [v0.10.7] - 2018-04-30 ### Added @@ -183,7 +227,9 @@ Look at the [release tags] for information about older releases. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.7...master +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.9...master +[v0.10.9]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.8...openssl-v0.10.9 +[v0.10.8]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.7...openssl-v0.10.8 [v0.10.7]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.6...openssl-v0.10.7 [v0.10.6]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.5...openssl-v0.10.6 [v0.10.5]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.4...openssl-v0.10.5 diff --git a/README.md b/README.md index 33727d0d..16155fbd 100644 --- a/README.md +++ b/README.md @@ -48,25 +48,25 @@ make -j$(nproc) make install ``` -### OSX +### macOS -Although OpenSSL 0.9.8 is preinstalled on OSX this library is being phased out -of OSX and this crate also does not support that version of OpenSSL. To use this -crate on OSX you'll need to install OpenSSL via some alternate means, typically +Although OpenSSL 0.9.8 is preinstalled on macOS this library is being phased out +of macOS and this crate also does not support that version of OpenSSL. To use this +crate on macOS you'll need to install OpenSSL via some alternate means, typically Homebrew: ```bash brew install openssl ``` -Occasionally an update of XCode or MacOS will cause the linker to fail after compilation, to rectify this you may want to try and run: +Occasionally an update of XCode or macOS will cause the linker to fail after compilation, to rectify this you may want to try and run: ```bash xcode-select --install ``` -If Homebrew is installed to the default location of `/usr/local`, OpenSSL will be -automatically detected. +If you're using latest version of Homebrew which supports `--prefix` command, +OpenSSL will be automatically detected. ### Windows MSVC diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 1153dd5a..9e53ce64 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-sys" -version = "0.9.30" +version = "0.9.32" authors = ["Alex Crichton ", "Steven Fackler "] license = "MIT" @@ -9,6 +9,7 @@ repository = "https://github.com/sfackler/rust-openssl" readme = "README.md" categories = ["cryptography", "external-ffi-bindings"] links = "openssl" +build = "build/main.rs" [dependencies] libc = "0.2" diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs new file mode 100644 index 00000000..4648f6f5 --- /dev/null +++ b/openssl-sys/build/cfgs.rs @@ -0,0 +1,43 @@ +pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<&'static str> { + let mut cfgs = vec![]; + + if let Some(libressl_version) = libressl_version { + cfgs.push("libressl"); + + if libressl_version >= 0x2_05_01_00_0 { + cfgs.push("libressl251"); + } + if libressl_version >= 0x2_06_01_00_0 { + cfgs.push("libressl261"); + } + if libressl_version >= 0x2_07_00_00_0 { + cfgs.push("libressl270"); + } + } else { + let openssl_version = openssl_version.unwrap(); + + if openssl_version >= 0x1_00_01_00_0 { + cfgs.push("ossl101"); + } + if openssl_version >= 0x1_00_02_00_0 { + cfgs.push("ossl102"); + } + if openssl_version >= 0x1_00_02_08_0 { + cfgs.push("ossl102h"); + } + if openssl_version >= 0x1_01_00_00_0 { + cfgs.push("ossl110"); + } + if openssl_version >= 0x1_01_00_06_0 { + cfgs.push("ossl110f"); + } + if openssl_version >= 0x1_01_00_07_0 { + cfgs.push("ossl110g"); + } + if openssl_version >= 0x1_01_01_00_0 { + cfgs.push("ossl111"); + } + } + + cfgs +} diff --git a/openssl-sys/build.rs b/openssl-sys/build/main.rs similarity index 91% rename from openssl-sys/build.rs rename to openssl-sys/build/main.rs index 0b8341fa..e2b3108c 100644 --- a/openssl-sys/build.rs +++ b/openssl-sys/build/main.rs @@ -11,6 +11,8 @@ use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; use std::process::Command; +mod cfgs; + // The set of `OPENSSL_NO_`s that we care about. const DEFINES: &'static [&'static str] = &[ "OPENSSL_NO_BUF_FREELISTS", @@ -104,6 +106,8 @@ fn find_openssl_dir(target: &str) -> OsString { let host = env::var("HOST").unwrap(); if host == target && target.contains("apple-darwin") { + // Check up default Homebrew installation location first + // for quick resolution if possible. let homebrew = Path::new("/usr/local/opt/openssl@1.1"); if homebrew.exists() { return homebrew.to_path_buf().into(); @@ -112,6 +116,22 @@ fn find_openssl_dir(target: &str) -> OsString { if homebrew.exists() { return homebrew.to_path_buf().into(); } + // Calling `brew --prefix ` command usually slow and + // takes seconds, and will be used only as a last resort. + let output = execute_command_and_get_output("brew", &["--prefix", "openssl@1.1"]); + if let Some(ref output) = output { + let homebrew = Path::new(&output); + if homebrew.exists() { + return homebrew.to_path_buf().into(); + } + } + let output = execute_command_and_get_output("brew", &["--prefix", "openssl"]); + if let Some(ref output) = output { + let homebrew = Path::new(&output); + if homebrew.exists() { + return homebrew.to_path_buf().into(); + } + } } try_pkg_config(); @@ -409,6 +429,10 @@ See rust-openssl README for more information: } println!("cargo:conf={}", enabled.join(",")); + for cfg in cfgs::get(openssl_version, libressl_version) { + println!("cargo:rustc-cfg={}", cfg); + } + if let Some(libressl_version) = libressl_version { println!("cargo:libressl_version_number={:x}", libressl_version); @@ -427,8 +451,6 @@ See rust-openssl README for more information: _ => version_error(), }; - println!("cargo:rustc-cfg=libressl"); - println!("cargo:rustc-cfg=libressl2{}{}", minor, fix); println!("cargo:libressl=true"); println!("cargo:libressl_version=2{}{}", minor, fix); println!("cargo:version=101"); @@ -437,37 +459,22 @@ See rust-openssl README for more information: let openssl_version = openssl_version.unwrap(); println!("cargo:version_number={:x}", openssl_version); - if openssl_version >= 0x1_00_02_08_0 { - println!("cargo:rustc-cfg=ossl102h"); - } - - if openssl_version >= 0x1_01_00_07_0 { - println!("cargo:rustc-cfg=ossl110g"); - } - if openssl_version >= 0x1_01_02_00_0 { version_error() } else if openssl_version >= 0x1_01_01_00_0 { - println!("cargo:rustc-cfg=ossl111"); - println!("cargo:rustc-cfg=ossl110"); println!("cargo:version=111"); Version::Openssl11x } else if openssl_version >= 0x1_01_00_06_0 { - println!("cargo:rustc-cfg=ossl110"); - println!("cargo:rustc-cfg=ossl110f"); println!("cargo:version=110"); println!("cargo:patch=f"); Version::Openssl11x } else if openssl_version >= 0x1_01_00_00_0 { - println!("cargo:rustc-cfg=ossl110"); println!("cargo:version=110"); Version::Openssl11x } else if openssl_version >= 0x1_00_02_00_0 { - println!("cargo:rustc-cfg=ossl102"); println!("cargo:version=102"); Version::Openssl10x } else if openssl_version >= 0x1_00_01_00_0 { - println!("cargo:rustc-cfg=ossl101"); println!("cargo:version=101"); Version::Openssl10x } else { @@ -524,10 +531,12 @@ fn determine_mode(libdir: &Path, libs: &[&str]) -> &'static str { .map(|e| e.file_name()) .filter_map(|e| e.into_string().ok()) .collect::>(); - let can_static = libs.iter() + let can_static = libs + .iter() .all(|l| files.contains(&format!("lib{}.a", l)) || files.contains(&format!("{}.lib", l))); let can_dylib = libs.iter().all(|l| { - files.contains(&format!("lib{}.so", l)) || files.contains(&format!("{}.dll", l)) + files.contains(&format!("lib{}.so", l)) + || files.contains(&format!("{}.dll", l)) || files.contains(&format!("lib{}.dylib", l)) }); match (can_static, can_dylib) { @@ -548,3 +557,16 @@ fn determine_mode(libdir: &Path, libs: &[&str]) -> &'static str { // practices with security libs", let's link dynamically. "dylib" } + +fn execute_command_and_get_output(cmd: &str, args: &[&str]) -> Option { + let out = Command::new(cmd).args(args).output(); + if let Ok(ref r1) = out { + if r1.status.success() { + let r2 = String::from_utf8(r1.stdout.clone()); + if let Ok(r3) = r2 { + return Some(r3.trim().to_string()); + } + } + } + return None; +} diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 9f970701..30889a7f 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -236,8 +236,10 @@ pub const EVP_PKEY_OP_VERIFYCTX: c_int = 1 << 7; pub const EVP_PKEY_OP_ENCRYPT: c_int = 1 << 8; pub const EVP_PKEY_OP_DECRYPT: c_int = 1 << 9; -pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN | EVP_PKEY_OP_VERIFY - | EVP_PKEY_OP_VERIFYRECOVER | EVP_PKEY_OP_SIGNCTX +pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN + | EVP_PKEY_OP_VERIFY + | EVP_PKEY_OP_VERIFYRECOVER + | EVP_PKEY_OP_SIGNCTX | EVP_PKEY_OP_VERIFYCTX; pub const EVP_PKEY_OP_TYPE_CRYPT: c_int = EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT; @@ -1259,21 +1261,23 @@ pub const SSL_VERIFY_NONE: c_int = 0; pub const SSL_VERIFY_PEER: c_int = 1; pub const SSL_VERIFY_FAIL_IF_NO_PEER_CERT: c_int = 2; -#[cfg(not(any(libressl261, libressl262, libressl26x, libressl27x, ossl101)))] +#[cfg(any(ossl102, all(libressl, not(libressl261))))] pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x00000010; -#[cfg(any(libressl261, libressl262, libressl26x, libressl27x))] +#[cfg(libressl261)] pub const SSL_OP_TLSEXT_PADDING: c_ulong = 0x0; pub const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: c_ulong = 0x00000800; -#[cfg(not(any(libressl261, libressl262, libressl26x, libressl27x)))] +#[cfg(not(libressl261))] pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x80000000; -#[cfg(any(libressl261, libressl262, libressl26x, libressl27x))] +#[cfg(libressl261)] pub const SSL_OP_CRYPTOPRO_TLSEXT_BUG: c_ulong = 0x0; pub const SSL_OP_LEGACY_SERVER_CONNECT: c_ulong = 0x00000004; -#[cfg(not(any(libressl, ossl110f, ossl111)))] +#[cfg(not(any(libressl, ossl110f)))] pub const SSL_OP_ALL: c_ulong = 0x80000BFF; -#[cfg(any(ossl110f, ossl111))] -pub const SSL_OP_ALL: c_ulong = SSL_OP_CRYPTOPRO_TLSEXT_BUG | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS - | SSL_OP_LEGACY_SERVER_CONNECT | SSL_OP_TLSEXT_PADDING +#[cfg(ossl110f)] +pub const SSL_OP_ALL: c_ulong = SSL_OP_CRYPTOPRO_TLSEXT_BUG + | SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS + | SSL_OP_LEGACY_SERVER_CONNECT + | SSL_OP_TLSEXT_PADDING | SSL_OP_SAFARI_ECDHE_ECDSA_BUG; pub const SSL_OP_NO_QUERY_MTU: c_ulong = 0x00001000; pub const SSL_OP_COOKIE_EXCHANGE: c_ulong = 0x00002000; @@ -1285,12 +1289,15 @@ pub const SSL_OP_NO_TLSv1: c_ulong = 0x04000000; pub const SSL_OP_NO_TLSv1_1: c_ulong = 0x10000000; pub const SSL_OP_NO_TLSv1_2: c_ulong = 0x08000000; -#[cfg(not(any(ossl101, libressl, ossl111)))] +#[cfg(all(ossl102, not(ossl111)))] pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2; #[cfg(ossl111)] -pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 - | SSL_OP_NO_TLSv1_1 | SSL_OP_NO_TLSv1_2 +pub const SSL_OP_NO_SSL_MASK: c_ulong = SSL_OP_NO_SSLv2 + | SSL_OP_NO_SSLv3 + | SSL_OP_NO_TLSv1 + | SSL_OP_NO_TLSv1_1 + | SSL_OP_NO_TLSv1_2 | SSL_OP_NO_TLSv1_3; pub const SSL_FILETYPE_PEM: c_int = X509_FILETYPE_PEM; @@ -1386,35 +1393,35 @@ pub const X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX: c_int = 52; pub const X509_V_ERR_UNSUPPORTED_NAME_SYNTAX: c_int = 53; pub const X509_V_ERR_CRL_PATH_VALIDATION_ERROR: c_int = 54; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_INVALID_VERSION: c_int = 56; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_INVALID_ALGORITHM: c_int = 57; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_INVALID_CURVE: c_int = 58; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM: c_int = 59; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED: c_int = 60; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256: c_int = 61; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_HOSTNAME_MISMATCH: c_int = 62; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_EMAIL_MISMATCH: c_int = 63; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub const X509_V_ERR_IP_ADDRESS_MISMATCH: c_int = 64; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT: c_uint = 0x1; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_NO_WILDCARDS: c_uint = 0x2; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS: c_uint = 0x4; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS: c_uint = 0x8; -#[cfg(not(any(ossl101, libressl)))] +#[cfg(any(ossl102, libressl261))] pub const X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS: c_uint = 0x10; pub const GEN_OTHERNAME: c_int = 0; @@ -1446,6 +1453,10 @@ pub unsafe fn BIO_set_retry_write(b: *mut BIO) { BIO_set_flags(b, BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY) } +pub unsafe fn EVP_get_digestbynid(type_: c_int) -> *const EVP_MD { + EVP_get_digestbyname(OBJ_nid2sn(type_)) +} + // EVP_PKEY_CTX_ctrl macros pub unsafe fn EVP_PKEY_CTX_set_rsa_padding(ctx: *mut EVP_PKEY_CTX, pad: c_int) -> c_int { EVP_PKEY_CTX_ctrl( @@ -1519,7 +1530,7 @@ pub unsafe fn SSL_CTX_add_extra_chain_cert(ctx: *mut SSL_CTX, x509: *mut X509) - SSL_CTX_ctrl(ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, x509 as *mut c_void) } -#[cfg(not(any(ossl101, libressl)))] +#[cfg(ossl102)] pub unsafe fn SSL_CTX_set0_verify_cert_store(ctx: *mut SSL_CTX, st: *mut X509_STORE) -> c_long { SSL_CTX_ctrl(ctx, SSL_CTRL_SET_VERIFY_CERT_STORE, 0, st as *mut c_void) } @@ -1634,9 +1645,9 @@ extern "C" { pub fn BIO_new_socket(sock: c_int, close_flag: c_int) -> *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; - #[cfg(any(ossl101, libressl))] + #[cfg(not(ossl102))] pub fn BIO_new_mem_buf(buf: *mut c_void, len: c_int) -> *mut BIO; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn BIO_new_mem_buf(buf: *const c_void, len: c_int) -> *mut BIO; pub fn BIO_set_flags(b: *mut BIO, flags: c_int); pub fn BIO_clear_flags(b: *mut BIO, flags: c_int); @@ -1767,11 +1778,11 @@ extern "C" { pub fn DH_new() -> *mut DH; pub fn DH_free(dh: *mut DH); - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn DH_get_1024_160() -> *mut DH; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn DH_get_2048_224() -> *mut DH; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn DH_get_2048_256() -> *mut DH; pub fn EC_KEY_new() -> *mut EC_KEY; @@ -2029,13 +2040,13 @@ extern "C" { e: *mut ENGINE, pkey: *mut EVP_PKEY, ) -> c_int; - #[cfg(any(ossl101, libressl))] + #[cfg(not(ossl102))] pub fn EVP_DigestVerifyFinal( ctx: *mut EVP_MD_CTX, sigret: *mut c_uchar, siglen: size_t, ) -> c_int; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn EVP_DigestVerifyFinal( ctx: *mut EVP_MD_CTX, sigret: *const c_uchar, @@ -2095,7 +2106,10 @@ extern "C" { a: *const ASN1_OBJECT, no_name: c_int, ) -> c_int; + pub fn OBJ_nid2ln(nid: c_int) -> *const c_char; pub fn OBJ_nid2sn(nid: c_int) -> *const c_char; + pub fn OBJ_find_sigid_algs(signid: c_int, pdig_nid: *mut c_int, ppkey_nid: *mut c_int) + -> c_int; pub fn OCSP_BASICRESP_new() -> *mut OCSP_BASICRESP; pub fn OCSP_BASICRESP_free(r: *mut OCSP_BASICRESP); @@ -2351,6 +2365,14 @@ extern "C" { k: *mut RSA, ) -> c_int; + pub fn RSA_padding_check_PKCS1_type_2( + to: *mut c_uchar, + tlen: c_int, + f: *const c_uchar, + fl: c_int, + rsa_len: c_int, + ) -> c_int; + pub fn DSA_new() -> *mut DSA; pub fn DSA_free(dsa: *mut DSA); pub fn DSA_size(dsa: *const DSA) -> c_int; @@ -2439,14 +2461,14 @@ extern "C" { pub fn SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void; pub fn SSL_get_servername(ssl: *const SSL, name_type: c_int) -> *const c_char; pub fn SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(any(ossl102, libressl261))] pub fn SSL_get0_param(ssl: *mut SSL) -> *mut X509_VERIFY_PARAM; pub fn SSL_get_verify_result(ssl: *const SSL) -> c_long; pub fn SSL_shutdown(ssl: *mut SSL) -> c_int; pub fn SSL_get_certificate(ssl: *const SSL) -> *mut X509; - #[cfg(any(ossl101, libressl))] + #[cfg(not(ossl102))] pub fn SSL_get_privatekey(ssl: *mut SSL) -> *mut EVP_PKEY; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn SSL_get_privatekey(ssl: *const SSL) -> *mut EVP_PKEY; pub fn SSL_load_client_CA_file(file: *const c_char) -> *mut stack_st_X509_NAME; pub fn SSL_set_tmp_dh_callback( @@ -2539,9 +2561,9 @@ extern "C" { remove_session_cb: Option, ); - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn SSL_CTX_get0_certificate(ctx: *const SSL_CTX) -> *mut X509; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(ossl102)] pub fn SSL_CTX_get0_privatekey(ctx: *const SSL_CTX) -> *mut EVP_PKEY; pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int; @@ -2600,10 +2622,12 @@ extern "C" { ); pub fn SSL_get_session(s: *const SSL) -> *mut SSL_SESSION; pub fn SSL_set_session(ssl: *mut SSL, session: *mut SSL_SESSION) -> c_int; - #[cfg(not(any(ossl101, libressl, ossl110f, ossl111)))] + #[cfg(all(ossl102, not(ossl110f)))] pub fn SSL_is_server(s: *mut SSL) -> c_int; - #[cfg(any(ossl110f, ossl111))] + #[cfg(ossl110f)] pub fn SSL_is_server(s: *const SSL) -> c_int; + pub fn SSL_get_finished(s: *const SSL, buf: *mut c_void, count: size_t) -> size_t; + pub fn SSL_get_peer_finished(s: *const SSL, buf: *mut c_void, count: size_t) -> size_t; pub fn SSL_SESSION_free(s: *mut SSL_SESSION); pub fn SSL_SESSION_get_id(s: *const SSL_SESSION, len: *mut c_uint) -> *const c_uchar; @@ -2615,14 +2639,14 @@ extern "C" { ) -> *mut SSL_SESSION; pub fn i2d_SSL_SESSION(s: *mut SSL_SESSION, pp: *mut *mut c_uchar) -> c_int; - #[cfg(not(ossl101))] + #[cfg(any(ossl102, libressl261))] pub fn SSL_CTX_set_alpn_protos(s: *mut SSL_CTX, data: *const c_uchar, len: c_uint) -> c_int; - #[cfg(not(ossl101))] + #[cfg(any(ossl102, libressl261))] pub fn SSL_set_alpn_protos(s: *mut SSL, data: *const c_uchar, len: c_uint) -> c_int; // FIXME should take an Option - #[cfg(not(ossl101))] + #[cfg(any(ossl102, libressl261))] pub fn SSL_CTX_set_alpn_select_cb( ssl: *mut SSL_CTX, cb: extern "C" fn( @@ -2635,7 +2659,7 @@ extern "C" { ) -> c_int, arg: *mut c_void, ); - #[cfg(not(ossl101))] + #[cfg(any(ossl102, libressl261))] pub fn SSL_get0_alpn_selected(s: *const SSL, data: *mut *const c_uchar, len: *mut c_uint); pub fn X509_add_ext(x: *mut X509, ext: *mut X509_EXTENSION, loc: c_int) -> c_int; @@ -2727,17 +2751,17 @@ extern "C" { pub fn X509_REQ_get_extensions(req: *mut X509_REQ) -> *mut stack_st_X509_EXTENSION; pub fn X509_REQ_sign(x: *mut X509_REQ, pkey: *mut EVP_PKEY, md: *const EVP_MD) -> c_int; - #[cfg(not(ossl101))] + #[cfg(any(ossl102, libressl261))] pub fn X509_VERIFY_PARAM_free(param: *mut X509_VERIFY_PARAM); - #[cfg(not(any(ossl101, libressl)))] + #[cfg(any(ossl102, libressl261))] pub fn X509_VERIFY_PARAM_set_hostflags(param: *mut X509_VERIFY_PARAM, flags: c_uint); - #[cfg(not(any(ossl101, libressl)))] + #[cfg(any(ossl102, libressl261))] pub fn X509_VERIFY_PARAM_set1_host( param: *mut X509_VERIFY_PARAM, name: *const c_char, namelen: size_t, ) -> c_int; - #[cfg(not(any(ossl101, libressl)))] + #[cfg(any(ossl102, libressl261))] pub fn X509_VERIFY_PARAM_set1_ip( param: *mut X509_VERIFY_PARAM, ip: *const c_uchar, @@ -2839,5 +2863,9 @@ extern "C" { ); pub fn EVP_MD_size(md: *const EVP_MD) -> c_int; + pub fn EVP_get_digestbyname(name: *const c_char) -> *const EVP_MD; pub fn EVP_get_cipherbyname(name: *const c_char) -> *const EVP_CIPHER; + + pub fn SSL_set_connect_state(s: *mut SSL); + pub fn SSL_set_accept_state(s: *mut SSL); } diff --git a/openssl-sys/src/libressl/mod.rs b/openssl-sys/src/libressl/mod.rs index 366d9502..0080fc7d 100644 --- a/openssl-sys/src/libressl/mod.rs +++ b/openssl-sys/src/libressl/mod.rs @@ -1,19 +1,18 @@ +use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t}; use std::mem; use std::ptr; use std::sync::{Mutex, MutexGuard}; use std::sync::{Once, ONCE_INIT}; -#[cfg(libressl250)] +#[cfg(not(libressl251))] pub use libressl::v250::*; -#[cfg(not(libressl250))] -pub use libressl::v25x::*; +#[cfg(libressl251)] +pub use libressl::v251::*; -use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t}; - -#[cfg(libressl250)] +#[cfg(not(libressl251))] mod v250; -#[cfg(not(libressl250))] -mod v25x; +#[cfg(libressl251)] +mod v251; #[repr(C)] pub struct stack_st_ASN1_OBJECT { @@ -337,9 +336,9 @@ pub const SSL_CTRL_OPTIONS: c_int = 32; pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77; pub const SSL_CTRL_SET_ECDH_AUTO: c_int = 94; -#[cfg(any(libressl261, libressl262, libressl26x, libressl27x))] +#[cfg(libressl261)] pub const SSL_OP_ALL: c_ulong = 0x4; -#[cfg(not(any(libressl261, libressl262, libressl26x, libressl27x)))] +#[cfg(not(libressl261))] pub const SSL_OP_ALL: c_ulong = 0x80000014; pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x0; pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x0; @@ -352,9 +351,9 @@ pub const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: c_ulong = 0x0; pub const SSL_OP_SSLEAY_080_CLIENT_DH_BUG: c_ulong = 0x0; pub const SSL_OP_TLS_D5_BUG: c_ulong = 0x0; pub const SSL_OP_TLS_BLOCK_PADDING_BUG: c_ulong = 0x0; -#[cfg(any(libressl261, libressl262, libressl26x, libressl27x))] +#[cfg(libressl261)] pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x0; -#[cfg(not(any(libressl261, libressl262, libressl26x, libressl27x)))] +#[cfg(not(libressl261))] pub const SSL_OP_SINGLE_ECDH_USE: c_ulong = 0x00080000; pub const SSL_OP_SINGLE_DH_USE: c_ulong = 0x00100000; pub const SSL_OP_NO_SSLv2: c_ulong = 0x0; @@ -448,6 +447,28 @@ pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int { ::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int } +pub unsafe fn SSL_CTX_get_options(ctx: *const ::SSL_CTX) -> c_ulong { + ::SSL_CTX_ctrl(ctx as *mut _, ::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong +} + +pub unsafe fn SSL_CTX_set_options(ctx: *const ::SSL_CTX, op: c_ulong) -> c_ulong { + ::SSL_CTX_ctrl( + ctx as *mut _, + ::SSL_CTRL_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong +} + +pub unsafe fn SSL_CTX_clear_options(ctx: *const ::SSL_CTX, op: c_ulong) -> c_ulong { + ::SSL_CTX_ctrl( + ctx as *mut _, + ::SSL_CTRL_CLEAR_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong +} + extern "C" { pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; pub fn BIO_s_file() -> *mut BIO_METHOD; @@ -540,6 +561,15 @@ extern "C" { unsafe extern "C" fn(*mut ::SSL, *mut c_uchar, c_int, *mut c_int) -> *mut SSL_SESSION, >, ); + #[cfg(libressl261)] + pub fn SSL_CTX_set_min_proto_version(ctx: *mut ::SSL_CTX, version: u16) -> c_int; + #[cfg(libressl261)] + pub fn SSL_CTX_set_max_proto_version(ctx: *mut ::SSL_CTX, version: u16) -> c_int; + #[cfg(libressl270)] + pub fn SSL_CTX_get_min_proto_version(ctx: *mut ::SSL_CTX) -> c_int; + #[cfg(libressl270)] + pub fn SSL_CTX_get_max_proto_version(ctx: *mut ::SSL_CTX) -> c_int; + pub fn X509_get_subject_name(x: *mut ::X509) -> *mut ::X509_NAME; pub fn X509_get_issuer_name(x: *mut ::X509) -> *mut ::X509_NAME; pub fn X509_set_notAfter(x: *mut ::X509, tm: *const ::ASN1_TIME) -> c_int; diff --git a/openssl-sys/src/libressl/v25x.rs b/openssl-sys/src/libressl/v251.rs similarity index 94% rename from openssl-sys/src/libressl/v25x.rs rename to openssl-sys/src/libressl/v251.rs index 7e7023ec..541b61db 100644 --- a/openssl-sys/src/libressl/v25x.rs +++ b/openssl-sys/src/libressl/v251.rs @@ -1,4 +1,4 @@ -use libc::{c_int, c_char, c_void, c_long, c_uchar, size_t, c_uint, c_ulong, time_t}; +use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t, time_t}; use super::*; @@ -84,6 +84,6 @@ pub struct X509_VERIFY_PARAM { pub purpose: c_int, pub trust: c_int, pub depth: c_int, - policies: *mut stack_st_ASN1_OBJECT, + pub policies: *mut stack_st_ASN1_OBJECT, id: *mut c_void, } diff --git a/openssl-sys/src/openssl/mod.rs b/openssl-sys/src/openssl/mod.rs index a1e4a345..b65b6129 100644 --- a/openssl-sys/src/openssl/mod.rs +++ b/openssl-sys/src/openssl/mod.rs @@ -1,8 +1,8 @@ use libc::{c_int, c_long, c_uchar, c_uint, c_ulong}; -#[cfg(any(ossl101, ossl102))] +#[cfg(not(ossl110))] mod v10x; -#[cfg(any(ossl101, ossl102))] +#[cfg(not(ossl110))] pub use openssl::v10x::*; #[cfg(ossl110)] @@ -15,7 +15,7 @@ mod v111; #[cfg(ossl111)] pub use openssl::v111::*; -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub const SSL_CTRL_SET_VERIFY_CERT_STORE: c_int = 106; pub const SSL_MODE_SEND_CLIENTHELLO_TIME: c_long = 0x20; @@ -28,9 +28,9 @@ pub const SSL_OP_CISCO_ANYCONNECT: c_ulong = 0x00008000; pub const SSL_OP_NO_COMPRESSION: c_ulong = 0x00020000; pub const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: c_ulong = 0x00040000; pub const SSL_OP_NO_SSLv3: c_ulong = 0x02000000; -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub const SSL_OP_NO_DTLSv1: c_ulong = 0x04000000; -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub const SSL_OP_NO_DTLSv1_2: c_ulong = 0x08000000; pub const X509_V_ERR_UNSPECIFIED: c_int = 1; @@ -55,7 +55,7 @@ pub const CMS_PARTIAL: c_uint = 0x4000; pub const CMS_REUSE_DIGEST: c_uint = 0x8000; pub const CMS_USE_KEYID: c_uint = 0x10000; pub const CMS_DEBUG_DECRYPT: c_uint = 0x20000; -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub const CMS_KEY_PARAM: c_uint = 0x40000; extern "C" { diff --git a/openssl-sys/src/openssl/v10x.rs b/openssl-sys/src/openssl/v10x.rs index 6a4d4346..c22bb7fc 100644 --- a/openssl-sys/src/openssl/v10x.rs +++ b/openssl-sys/src/openssl/v10x.rs @@ -5,7 +5,7 @@ use std::ptr; use std::sync::{Mutex, MutexGuard}; use std::sync::{Once, ONCE_INIT}; -#[cfg(not(ossl101))] +#[cfg(ossl102)] use libc::time_t; use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_ulong, c_void, size_t}; @@ -573,9 +573,6 @@ pub struct SSL_CTX { #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl101))] srtp_profiles: *mut c_void, - - #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] - srtp_profiles: *mut c_void, #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] alpn_select_cb: *mut c_void, #[cfg(all(not(osslconf = "OPENSSL_NO_TLSEXT"), ossl102))] @@ -669,7 +666,7 @@ pub struct SRP_CTX { } #[repr(C)] -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub struct X509_VERIFY_PARAM { pub name: *mut c_char, pub check_time: time_t, @@ -682,7 +679,7 @@ pub struct X509_VERIFY_PARAM { pub id: *mut X509_VERIFY_PARAM_ID, } -#[cfg(not(ossl101))] +#[cfg(ossl102)] pub enum X509_VERIFY_PARAM_ID {} pub enum PKCS12 {} @@ -810,6 +807,28 @@ pub unsafe fn SSL_session_reused(ssl: *mut ::SSL) -> c_int { ::SSL_ctrl(ssl, SSL_CTRL_GET_SESSION_REUSED, 0, ptr::null_mut()) as c_int } +pub unsafe fn SSL_CTX_get_options(ctx: *const ::SSL_CTX) -> c_ulong { + ::SSL_CTX_ctrl(ctx as *mut _, ::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong +} + +pub unsafe fn SSL_CTX_set_options(ctx: *const ::SSL_CTX, op: c_ulong) -> c_ulong { + ::SSL_CTX_ctrl( + ctx as *mut _, + ::SSL_CTRL_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong +} + +pub unsafe fn SSL_CTX_clear_options(ctx: *const ::SSL_CTX, op: c_ulong) -> c_ulong { + ::SSL_CTX_ctrl( + ctx as *mut _, + ::SSL_CTRL_CLEAR_OPTIONS, + op as c_long, + ptr::null_mut(), + ) as c_ulong +} + extern "C" { pub fn BIO_new(type_: *mut BIO_METHOD) -> *mut BIO; pub fn BIO_s_file() -> *mut BIO_METHOD; @@ -925,15 +944,15 @@ extern "C" { loc: c_int, set: c_int, ) -> c_int; - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn X509_get0_signature( psig: *mut *mut ::ASN1_BIT_STRING, palg: *mut *mut ::X509_ALGOR, x: *const ::X509, ); - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn X509_get_signature_nid(x: *const X509) -> c_int; - #[cfg(not(ossl101))] + #[cfg(ossl102)] pub fn X509_ALGOR_get0( paobj: *mut *mut ::ASN1_OBJECT, pptype: *mut c_int, diff --git a/openssl-sys/src/openssl/v110.rs b/openssl-sys/src/openssl/v110.rs index 4f1aa1c1..47d2bee4 100644 --- a/openssl-sys/src/openssl/v110.rs +++ b/openssl-sys/src/openssl/v110.rs @@ -280,6 +280,7 @@ extern "C" { ); pub fn SSL_get_client_random(ssl: *const SSL, out: *mut c_uchar, len: size_t) -> size_t; pub fn SSL_get_server_random(ssl: *const SSL, out: *mut c_uchar, len: size_t) -> size_t; + pub fn SSL_get0_verified_chain(ssl: *const SSL) -> *mut stack_st_X509; pub fn X509_getm_notAfter(x: *const ::X509) -> *mut ::ASN1_TIME; pub fn X509_getm_notBefore(x: *const ::X509) -> *mut ::ASN1_TIME; pub fn X509_get0_signature( diff --git a/openssl-sys/src/openssl/v111.rs b/openssl-sys/src/openssl/v111.rs index 8574efc8..36682663 100644 --- a/openssl-sys/src/openssl/v111.rs +++ b/openssl-sys/src/openssl/v111.rs @@ -55,6 +55,9 @@ pub const SSL_EXT_TLS1_3_CERTIFICATE: c_uint = 0x1000; pub const SSL_EXT_TLS1_3_NEW_SESSION_TICKET: c_uint = 0x2000; pub const SSL_EXT_TLS1_3_CERTIFICATE_REQUEST: c_uint = 0x4000; +pub const SSL_READ_EARLY_DATA_ERROR: c_int = 0; +pub const SSL_READ_EARLY_DATA_SUCCESS: c_int = 1; +pub const SSL_READ_EARLY_DATA_FINISH: c_int = 2; extern "C" { pub fn SSL_CTX_set_keylog_callback(ctx: *mut ::SSL_CTX, cb: SSL_CTX_keylog_cb_func); @@ -82,4 +85,24 @@ extern "C" { cookie_len: size_t ) -> c_int> ); + + pub fn SSL_CTX_set_max_early_data(ctx: *mut ::SSL_CTX, max_early_data: u32) -> c_int; + pub fn SSL_CTX_get_max_early_data(ctx: *const ::SSL_CTX) -> u32; + pub fn SSL_set_max_early_data(ctx: *mut ::SSL, max_early_data: u32) -> c_int; + pub fn SSL_get_max_early_data(ctx: *const ::SSL) -> u32; + pub fn SSL_SESSION_set_max_early_data(ctx: *mut ::SSL_SESSION, max_early_data: u32) -> c_int; + pub fn SSL_SESSION_get_max_early_data(ctx: *const ::SSL_SESSION) -> u32; + + pub fn SSL_export_keying_material_early( + s: *mut ::SSL, + out: *mut c_uchar, + olen: size_t, + label: *const c_char, + llen: size_t, + context: *const c_uchar, + contextlen: size_t, + ) -> c_int; + + pub fn SSL_write_early_data(s: *mut ::SSL, buf: *const c_void, num: size_t, written: *mut size_t) -> c_int; + pub fn SSL_read_early_data(s: *mut ::SSL, buf: *mut c_void, num: size_t, readbytes: *mut size_t) -> c_int; } diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 25aab11d..81568472 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.10.7" +version = "0.10.9" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" @@ -18,10 +18,12 @@ v111 = [] [dependencies] bitflags = "1.0" +cfg-if = "0.1" foreign-types = "0.3.1" lazy_static = "1" libc = "0.2" -openssl-sys = { version = "0.9.30", path = "../openssl-sys" } + +openssl-sys = { version = "0.9.32", path = "../openssl-sys" } [dev-dependencies] tempdir = "0.3" diff --git a/openssl/build.rs b/openssl/build.rs index 612322fe..5a5b86f2 100644 --- a/openssl/build.rs +++ b/openssl/build.rs @@ -1,25 +1,6 @@ use std::env; fn main() { - match env::var("DEP_OPENSSL_VERSION") { - Ok(ref v) if v == "101" => { - println!("cargo:rustc-cfg=ossl101"); - println!("cargo:rustc-cfg=ossl10x"); - } - Ok(ref v) if v == "102" => { - println!("cargo:rustc-cfg=ossl102"); - println!("cargo:rustc-cfg=ossl10x"); - } - Ok(ref v) if v == "110" => { - println!("cargo:rustc-cfg=ossl110"); - } - Ok(ref v) if v == "111" => { - println!("cargo:rustc-cfg=ossl110"); - println!("cargo:rustc-cfg=ossl111"); - } - _ => panic!("Unable to detect OpenSSL version"), - } - if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { println!("cargo:rustc-cfg=libressl"); } @@ -37,8 +18,32 @@ fn main() { if let Ok(version) = env::var("DEP_OPENSSL_VERSION_NUMBER") { let version = u64::from_str_radix(&version, 16).unwrap(); + if version >= 0x1_00_01_00_0 { + println!("cargo:rustc-cfg=ossl101"); + } + if version >= 0x1_00_02_00_0 { + println!("cargo:rustc-cfg=ossl102"); + } + if version >= 0x1_01_00_00_0 { + println!("cargo:rustc-cfg=ossl110"); + } if version >= 0x1_01_00_07_0 { println!("cargo:rustc-cfg=ossl110g"); } + if version >= 0x1_01_01_00_0 { + println!("cargo:rustc-cfg=ossl111"); + } + } + + if let Ok(version) = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&version, 16).unwrap(); + + if version >= 0x2_06_01_00_0 { + println!("cargo:rustc-cfg=libressl261"); + } + + if version >= 0x2_07_00_00_0 { + println!("cargo:rustc-cfg=libressl270"); + } } } diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index f6917aae..03546a4d 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -32,12 +32,12 @@ use std::ptr; use std::slice; use std::str; -use {cvt, cvt_p}; use bio::MemBio; use bn::BigNum; use error::ErrorStack; use nid::Nid; use string::OpensslString; +use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_GENERALIZEDTIME; @@ -162,7 +162,7 @@ impl Asn1StringRef { /// /// [`as_utf8`]: struct.Asn1String.html#method.as_utf8 pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr()), self.len()) } + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) } } /// Return the length of the Asn1String (number of bytes) @@ -241,11 +241,11 @@ foreign_type_and_impl_send_sync! { impl Asn1BitStringRef { /// Returns the Asn1BitString as a slice pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_data(self.as_ptr() as *mut _), self.len()) } + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } } /// Length of Asn1BitString in number of bytes. pub fn len(&self) -> usize { - unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *mut _) as usize } + unsafe { ffi::ASN1_STRING_length(self.as_ptr() as *const _) as usize } } } @@ -296,11 +296,13 @@ impl fmt::Display for Asn1ObjectRef { } } -#[cfg(any(ossl101, ossl102))] -use ffi::ASN1_STRING_data; - -#[cfg(ossl110)] -#[allow(bad_style)] -unsafe fn ASN1_STRING_data(s: *mut ffi::ASN1_STRING) -> *mut ::libc::c_uchar { - ffi::ASN1_STRING_get0_data(s) as *mut _ +cfg_if! { + if #[cfg(ossl110)] { + use ffi::ASN1_STRING_get0_data; + } else { + #[allow(bad_style)] + unsafe fn ASN1_STRING_get0_data(s: *mut ffi::ASN1_STRING) -> *const ::libc::c_uchar { + ffi::ASN1_STRING_data(s) + } + } } diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index 56ba1f3d..51724e3f 100644 --- a/openssl/src/bio.rs +++ b/openssl/src/bio.rs @@ -1,8 +1,8 @@ +use ffi; +use libc::c_int; use std::marker::PhantomData; use std::ptr; use std::slice; -use libc::c_int; -use ffi; use cvt_p; use error::ErrorStack; @@ -68,11 +68,13 @@ impl MemBio { } } -#[cfg(not(ossl101))] -use ffi::BIO_new_mem_buf; - -#[cfg(ossl101)] -#[allow(bad_style)] -unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO { - ffi::BIO_new_mem_buf(buf as *mut _, len) +cfg_if! { + if #[cfg(ossl102)] { + use ffi::BIO_new_mem_buf; + } else { + #[allow(bad_style)] + unsafe fn BIO_new_mem_buf(buf: *const ::libc::c_void, len: ::libc::c_int) -> *mut ffi::BIO { + ffi::BIO_new_mem_buf(buf as *mut _, len) + } + } } diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index fe662e85..15dd7368 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -30,28 +30,39 @@ use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::cmp::Ordering; use std::ffi::CString; -use std::{fmt, ptr}; use std::ops::{Add, Deref, Div, Mul, Neg, Rem, Shl, Shr, Sub}; +use std::{fmt, ptr}; -use {cvt, cvt_n, cvt_p}; use asn1::Asn1Integer; use error::ErrorStack; use string::OpensslString; +use {cvt, cvt_n, cvt_p}; -#[cfg(ossl10x)] -use ffi::{get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, - get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, - get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, - get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, - get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, - get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, - get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, - get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + BN_get_rfc2409_prime_1024, BN_get_rfc2409_prime_768, BN_get_rfc3526_prime_1536, + BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096, + BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192, BN_is_negative, + }; + } else { + use ffi::{ + get_rfc2409_prime_1024 as BN_get_rfc2409_prime_1024, + get_rfc2409_prime_768 as BN_get_rfc2409_prime_768, + get_rfc3526_prime_1536 as BN_get_rfc3526_prime_1536, + get_rfc3526_prime_2048 as BN_get_rfc3526_prime_2048, + get_rfc3526_prime_3072 as BN_get_rfc3526_prime_3072, + get_rfc3526_prime_4096 as BN_get_rfc3526_prime_4096, + get_rfc3526_prime_6144 as BN_get_rfc3526_prime_6144, + get_rfc3526_prime_8192 as BN_get_rfc3526_prime_8192, + }; -#[cfg(ossl110)] -use ffi::{BN_get_rfc2409_prime_1024, BN_get_rfc2409_prime_768, BN_get_rfc3526_prime_1536, - BN_get_rfc3526_prime_2048, BN_get_rfc3526_prime_3072, BN_get_rfc3526_prime_4096, - BN_get_rfc3526_prime_6144, BN_get_rfc3526_prime_8192}; + #[allow(bad_style)] + unsafe fn BN_is_negative(bn: *const ffi::BIGNUM) -> c_int { + (*bn).neg + } + } +} /// Options for the most significant bits of a randomly generated `BigNum`. pub struct MsbOption(c_int); @@ -361,17 +372,7 @@ impl BigNumRef { /// Returns `true` if `self` is negative. pub fn is_negative(&self) -> bool { - self._is_negative() - } - - #[cfg(ossl10x)] - fn _is_negative(&self) -> bool { - unsafe { (*self.as_ptr()).neg == 1 } - } - - #[cfg(ossl110)] - fn _is_negative(&self) -> bool { - unsafe { ffi::BN_is_negative(self.as_ptr()) == 1 } + unsafe { BN_is_negative(self.as_ptr()) == 1 } } /// Returns the number of significant bits in `self`. @@ -1218,7 +1219,7 @@ macro_rules! delegate { $t::$m(self.deref(), oth.deref()) } } - } + }; } impl<'a, 'b> Add<&'b BigNumRef> for &'a BigNumRef { diff --git a/openssl/src/cms.rs b/openssl/src/cms.rs index 6ee62fd0..d8d64c00 100644 --- a/openssl/src/cms.rs +++ b/openssl/src/cms.rs @@ -13,8 +13,8 @@ use bio::{MemBio, MemBioSlice}; use error::ErrorStack; use libc::c_uint; use pkey::{HasPrivate, PKeyRef}; -use stack::Stack; -use x509::X509; +use stack::StackRef; +use x509::{X509, X509Ref}; use {cvt, cvt_p}; bitflags! { @@ -130,30 +130,25 @@ impl CmsContentInfo { /// OpenSSL documentation at [`CMS_sign`] /// /// [`CMS_sign`]: https://www.openssl.org/docs/manmaster/man3/CMS_sign.html - pub fn sign( - signcert: Option<&X509>, + pub fn sign( + signcert: Option<&X509Ref>, pkey: Option<&PKeyRef>, - certs: Option<&Stack>, + certs: Option<&StackRef>, data: Option<&[u8]>, flags: CMSOptions, - ) -> Result { + ) -> Result + where + T: HasPrivate, + { unsafe { - let signcert = match signcert { - Some(cert) => cert.as_ptr(), - None => ptr::null_mut(), - }; - let pkey = match pkey { - Some(pkey) => pkey.as_ptr(), - None => ptr::null_mut(), - }; - let data_bio_ptr = match data { - Some(data) => MemBioSlice::new(data)?.as_ptr(), - None => ptr::null_mut(), - }; - let certs = match certs { - Some(certs) => certs.as_ptr(), - None => ptr::null_mut(), + let signcert = signcert.map_or(ptr::null_mut(), |p| p.as_ptr()); + let pkey = pkey.map_or(ptr::null_mut(), |p| p.as_ptr()); + let data_bio = match data { + Some(data) => Some(MemBioSlice::new(data)?), + None => None, }; + let data_bio_ptr = data_bio.as_ref().map_or(ptr::null_mut(), |p| p.as_ptr()); + let certs = certs.map_or(ptr::null_mut(), |p| p.as_ptr()); let cms = cvt_p(ffi::CMS_sign( signcert, diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index a90b10b8..730a5180 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -4,9 +4,9 @@ use foreign_types::{ForeignType, ForeignTypeRef}; use std::mem; use std::ptr; -use {cvt, cvt_p}; use bn::BigNum; use pkey::{HasParams, Params}; +use {cvt, cvt_p}; generic_foreign_type_and_impl_send_sync! { type CType = ffi::DH; @@ -48,12 +48,7 @@ impl Dh { pub fn from_params(p: BigNum, g: BigNum, q: BigNum) -> Result, ErrorStack> { unsafe { let dh = Dh::from_ptr(cvt_p(ffi::DH_new())?); - cvt(compat::DH_set0_pqg( - dh.0, - p.as_ptr(), - q.as_ptr(), - g.as_ptr(), - ))?; + cvt(DH_set0_pqg(dh.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; mem::forget((p, g, q)); Ok(dh) } @@ -111,34 +106,29 @@ impl Dh { } } -#[cfg(ossl110)] -mod compat { - pub use ffi::DH_set0_pqg; -} - -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use ffi; - use libc::c_int; - - pub unsafe fn DH_set0_pqg( - dh: *mut ffi::DH, - p: *mut ffi::BIGNUM, - q: *mut ffi::BIGNUM, - g: *mut ffi::BIGNUM, - ) -> c_int { - (*dh).p = p; - (*dh).q = q; - (*dh).g = g; - 1 +cfg_if! { + if #[cfg(ossl110)] { + use ffi::DH_set0_pqg; + } else { + #[allow(bad_style)] + unsafe fn DH_set0_pqg( + dh: *mut ffi::DH, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + g: *mut ffi::BIGNUM, + ) -> ::libc::c_int { + (*dh).p = p; + (*dh).q = q; + (*dh).g = g; + 1 + } } } #[cfg(test)] mod tests { - use dh::Dh; use bn::BigNum; + use dh::Dh; use ssl::{SslContext, SslMethod}; #[test] diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index 0a14ccc3..abc2e297 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -11,10 +11,10 @@ use libc::c_int; use std::fmt; use std::ptr; -use {cvt, cvt_p}; use bn::BigNumRef; use error::ErrorStack; use pkey::{HasParams, HasPublic, Private, Public}; +use {cvt, cvt_p}; generic_foreign_type_and_impl_send_sync! { type CType = ffi::DSA; @@ -101,7 +101,8 @@ where /// Returns the DSA prime parameter of `self`. pub fn p(&self) -> &BigNumRef { unsafe { - let p = compat::pqg(self.as_ptr())[0]; + let mut p = ptr::null(); + DSA_get0_pqg(self.as_ptr(), &mut p, ptr::null_mut(), ptr::null_mut()); BigNumRef::from_ptr(p as *mut _) } } @@ -109,7 +110,8 @@ where /// Returns the DSA sub-prime parameter of `self`. pub fn q(&self) -> &BigNumRef { unsafe { - let q = compat::pqg(self.as_ptr())[1]; + let mut q = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), &mut q, ptr::null_mut()); BigNumRef::from_ptr(q as *mut _) } } @@ -117,7 +119,8 @@ where /// Returns the DSA base parameter of `self`. pub fn g(&self) -> &BigNumRef { unsafe { - let g = compat::pqg(self.as_ptr())[2]; + let mut g = ptr::null(); + DSA_get0_pqg(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut g); BigNumRef::from_ptr(g as *mut _) } } @@ -184,24 +187,27 @@ impl fmt::Debug for Dsa { } } -#[cfg(ossl110)] -mod compat { - use std::ptr; - use ffi::{self, BIGNUM, DSA}; - - pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] { - let (mut p, mut q, mut g) = (ptr::null(), ptr::null(), ptr::null()); - ffi::DSA_get0_pqg(d, &mut p, &mut q, &mut g); - [p, q, g] - } -} - -#[cfg(ossl10x)] -mod compat { - use ffi::{BIGNUM, DSA}; - - pub unsafe fn pqg(d: *const DSA) -> [*const BIGNUM; 3] { - [(*d).p, (*d).q, (*d).g] +cfg_if! { + if #[cfg(ossl110)] { + use ffi::DSA_get0_pqg; + } else { + #[allow(bad_style)] + unsafe fn DSA_get0_pqg( + d: *mut ffi::DSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + g: *mut *const ffi::BIGNUM) + { + if !p.is_null() { + *p = (*d).p; + } + if !q.is_null() { + *q = (*d).q; + } + if !g.is_null() { + *g = (*d).g; + } + } } } diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index c4800c73..573d0c00 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -33,14 +33,14 @@ //! ``` use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; -use std::ptr; use libc::c_int; +use std::ptr; -use {cvt, cvt_n, cvt_p, init}; use bn::{BigNumContextRef, BigNumRef}; use error::ErrorStack; use nid::Nid; use pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; +use {cvt, cvt_n, cvt_p, init}; /// Compressed or Uncompressed conversion /// @@ -803,10 +803,10 @@ impl Clone for EcKey { #[cfg(test)] mod test { - use bn::{BigNum, BigNumContext}; - use nid::Nid; - use data_encoding::BASE64URL_NOPAD; use super::*; + use bn::{BigNum, BigNumContext}; + use data_encoding::BASE64URL_NOPAD; + use nid::Nid; #[test] fn key_new_by_curve_name() { @@ -823,7 +823,7 @@ mod test { fn dup() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); - key.clone(); + drop(key.clone()); } #[test] @@ -862,7 +862,8 @@ mod test { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); let mut ctx = BigNumContext::new().unwrap(); - let bytes = key.public_key() + let bytes = key + .public_key() .to_bytes(&group, PointConversionForm::COMPRESSED, &mut ctx) .unwrap(); @@ -877,7 +878,8 @@ mod test { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); let key = EcKey::generate(&group).unwrap(); - let dup_key = EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); + let dup_key = + EcKey::from_private_components(&group, key.private_key(), key.public_key()).unwrap(); let res = dup_key.check_key().unwrap(); assert!(res == ()); diff --git a/openssl/src/ecdsa.rs b/openssl/src/ecdsa.rs index 120f6531..d07dfda4 100644 --- a/openssl/src/ecdsa.rs +++ b/openssl/src/ecdsa.rs @@ -3,12 +3,13 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::mem; +use std::ptr; use bn::{BigNum, BigNumRef}; -use {cvt, cvt_n, cvt_p}; use ec::EcKeyRef; use error::ErrorStack; use pkey::{Private, Public}; +use {cvt_n, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::ECDSA_SIG; @@ -53,7 +54,7 @@ impl EcdsaSig { pub fn from_private_components(r: BigNum, s: BigNum) -> Result { unsafe { let sig = cvt_p(ffi::ECDSA_SIG_new())?; - cvt(compat::set_numbers(sig, r.as_ptr(), s.as_ptr()))?; + ECDSA_SIG_set0(sig, r.as_ptr(), s.as_ptr()); mem::forget((r, s)); Ok(EcdsaSig::from_ptr(sig as *mut _)) } @@ -83,8 +84,9 @@ impl EcdsaSig { /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html pub fn r(&self) -> &BigNumRef { unsafe { - let xs = compat::get_numbers(self.as_ptr()); - BigNumRef::from_ptr(xs[0] as *mut _) + let mut r = ptr::null(); + ECDSA_SIG_get0(self.as_ptr(), &mut r, ptr::null_mut()); + BigNumRef::from_ptr(r as *mut _) } } @@ -95,53 +97,50 @@ impl EcdsaSig { /// [`ECDSA_SIG_get0`]: https://www.openssl.org/docs/man1.1.0/crypto/ECDSA_SIG_get0.html pub fn s(&self) -> &BigNumRef { unsafe { - let xs = compat::get_numbers(self.as_ptr()); - BigNumRef::from_ptr(xs[1] as *mut _) + let mut s = ptr::null(); + ECDSA_SIG_get0(self.as_ptr(), ptr::null_mut(), &mut s); + BigNumRef::from_ptr(s as *mut _) } } } -#[cfg(ossl110)] -mod compat { - use std::ptr; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; + } else { + #[allow(bad_style)] + unsafe fn ECDSA_SIG_set0( + sig: *mut ffi::ECDSA_SIG, + r: *mut ffi::BIGNUM, + s: *mut ffi::BIGNUM, + ) -> c_int { + (*sig).r = r; + (*sig).s = s; + 1 + } - use libc::c_int; - use ffi::{self, BIGNUM, ECDSA_SIG}; - - pub unsafe fn set_numbers(sig: *mut ECDSA_SIG, r: *mut BIGNUM, s: *mut BIGNUM) -> c_int { - ffi::ECDSA_SIG_set0(sig, r, s) + #[allow(bad_style)] + unsafe fn ECDSA_SIG_get0( + sig: *const ffi::ECDSA_SIG, + pr: *mut *const ffi::BIGNUM, + ps: *mut *const ffi::BIGNUM) + { + if !pr.is_null() { + (*pr) = (*sig).r; + } + if !ps.is_null() { + (*ps) = (*sig).s; + } + } } - - pub unsafe fn get_numbers(sig: *mut ECDSA_SIG) -> [*const BIGNUM; 2] { - let (mut r, mut s) = (ptr::null(), ptr::null()); - ffi::ECDSA_SIG_get0(sig, &mut r, &mut s); - [r, s] - } -} - -#[cfg(ossl10x)] -mod compat { - use libc::c_int; - use ffi::{BIGNUM, ECDSA_SIG}; - - pub unsafe fn set_numbers(sig: *mut ECDSA_SIG, r: *mut BIGNUM, s: *mut BIGNUM) -> c_int { - (*sig).r = r; - (*sig).s = s; - 1 - } - - pub unsafe fn get_numbers(sig: *mut ECDSA_SIG) -> [*const BIGNUM; 2] { - [(*sig).r, (*sig).s] - } - } #[cfg(test)] mod test { - use nid::Nid; + use super::*; use ec::EcGroup; use ec::EcKey; - use super::*; + use nid::Nid; #[cfg(not(osslconf = "OPENSSL_NO_EC2M"))] static CURVE_IDENTIFER: Nid = Nid::X9_62_PRIME192V1; @@ -171,7 +170,8 @@ mod test { assert!(verification); // Signature will not be verified using the incorrect data but the correct public key - let verification2 = res.verify(String::from("hello2").as_bytes(), &public_key) + let verification2 = res + .verify(String::from("hello2").as_bytes(), &public_key) .unwrap(); assert!(verification2 == false); diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index 726ebe9c..dd4d136c 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -1,22 +1,44 @@ -use std::io::prelude::*; -use std::io; -use std::ops::{Deref, DerefMut}; -use std::fmt; use ffi; +use std::fmt; +use std::io; +use std::io::prelude::*; +use std::ops::{Deref, DerefMut}; -#[cfg(ossl110)] -use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; -#[cfg(any(ossl101, ossl102))] -use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; - -use {cvt, cvt_p}; use error::ErrorStack; +use nid::Nid; +use {cvt, cvt_p}; + +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} #[derive(Copy, Clone)] pub struct MessageDigest(*const ffi::EVP_MD); impl MessageDigest { - pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self { MessageDigest(x) } + pub unsafe fn from_ptr(x: *const ffi::EVP_MD) -> Self { + MessageDigest(x) + } + + /// Returns the `MessageDigest` corresponding to an `Nid`. + /// + /// This corresponds to [`EVP_get_digestbynid`]. + /// + /// [`EVP_get_digestbynid`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_DigestInit.html + pub fn from_nid(type_: Nid) -> Option { + unsafe { + let ptr = ffi::EVP_get_digestbynid(type_.as_raw()); + if ptr.is_null() { + None + } else { + Some(MessageDigest(ptr)) + } + } + } pub fn md5() -> MessageDigest { unsafe { MessageDigest(ffi::EVP_md5()) } @@ -229,8 +251,8 @@ impl Drop for Hasher { /// store the digest data. #[derive(Copy)] pub struct DigestBytes { - buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], - len: usize, + pub(crate) buf: [u8; ffi::EVP_MAX_MD_SIZE as usize], + pub(crate) len: usize, } impl Clone for DigestBytes { @@ -382,12 +404,10 @@ mod tests { #[test] fn test_sha256() { - let tests = [ - ( - "616263", - "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", - ), - ]; + let tests = [( + "616263", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + )]; for test in tests.iter() { hash_test(MessageDigest::sha256(), test); @@ -402,4 +422,12 @@ mod tests { hash_test(MessageDigest::ripemd160(), test); } } + + #[test] + fn from_nid() { + assert_eq!( + MessageDigest::from_nid(Nid::SHA256).unwrap().as_ptr(), + MessageDigest::sha256().as_ptr() + ); + } } diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index a66a7743..d74ce65f 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -3,6 +3,8 @@ #[macro_use] extern crate bitflags; #[macro_use] +extern crate cfg_if; +#[macro_use] extern crate foreign_types; #[macro_use] extern crate lazy_static; @@ -53,8 +55,8 @@ pub mod pkcs5; pub mod pkey; pub mod rand; pub mod rsa; -pub mod sign; pub mod sha; +pub mod sign; pub mod ssl; pub mod stack; pub mod string; diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index 7c041236..6f480254 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -1,6 +1,23 @@ //! A collection of numerical identifiers for OpenSSL objects. use ffi; -use libc::c_int; +use libc::{c_char, c_int}; + +use std::ffi::CStr; +use std::str; + +use cvt_p; +use error::ErrorStack; + +/// The digest and public-key algorithms associated with a signature. +pub struct SignatureAlgorithms { + /// The signature's digest. + /// + /// If the signature does not specify a digest, this will be `NID::UNDEF`. + pub digest: Nid, + + /// The signature's public-key. + pub pkey: Nid, +} /// A numerical identifier for an OpenSSL object. /// @@ -42,6 +59,46 @@ impl Nid { self.0 } + /// Returns the `Nid`s of the digest and public key algorithms associated with a signature ID. + /// + /// This corresponds to `OBJ_find_sigid_algs`. + pub fn signature_algorithms(&self) -> Option { + unsafe { + let mut digest = 0; + let mut pkey = 0; + if ffi::OBJ_find_sigid_algs(self.0, &mut digest, &mut pkey) == 1 { + Some(SignatureAlgorithms { + digest: Nid(digest), + pkey: Nid(pkey), + }) + } else { + None + } + } + } + + /// Return the string representation of a `Nid` (long) + /// This corresponds to [`OBJ_nid2ln`] + /// + /// [`OBJ_nid2ln`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2ln.html + pub fn long_name(&self) -> Result<&'static str, ErrorStack> { + unsafe { + cvt_p(ffi::OBJ_nid2ln(self.0) as *mut c_char) + .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) + } + } + + /// Return the string representation of a `Nid` (short) + /// This corresponds to [`OBJ_nid2sn`] + /// + /// [`OBJ_nid2sn`]: https://www.openssl.org/docs/man1.1.0/crypto/OBJ_nid2sn.html + pub fn short_name(&self) -> Result<&'static str, ErrorStack> { + unsafe { + cvt_p(ffi::OBJ_nid2sn(self.0) as *mut c_char) + .map(|nameptr| str::from_utf8(CStr::from_ptr(nameptr).to_bytes()).unwrap()) + } + } + pub const UNDEF: Nid = Nid(ffi::NID_undef); pub const ITU_T: Nid = Nid(ffi::NID_itu_t); pub const CCITT: Nid = Nid(ffi::NID_ccitt); @@ -991,3 +1048,73 @@ impl Nid { pub const AES_192_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_192_cbc_hmac_sha1); pub const AES_256_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_256_cbc_hmac_sha1); } + +#[cfg(test)] +mod test { + use super::Nid; + + #[test] + fn signature_digest() { + let algs = Nid::SHA256WITHRSAENCRYPTION.signature_algorithms().unwrap(); + assert_eq!(algs.digest, Nid::SHA256); + assert_eq!(algs.pkey, Nid::RSAENCRYPTION); + } + + #[test] + fn test_long_name_conversion() { + let common_name = Nid::COMMONNAME; + let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; + let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; + let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; + let ms_ctl_sign = Nid::MS_CTL_SIGN; + let undefined_nid = Nid::from_raw(118); + + assert_eq!(common_name.long_name().unwrap(), "commonName"); + assert_eq!( + organizational_unit_name.long_name().unwrap(), + "organizationalUnitName" + ); + assert_eq!( + aes256_cbc_hmac_sha1.long_name().unwrap(), + "aes-256-cbc-hmac-sha1" + ); + assert_eq!( + id_cmc_lrapopwitness.long_name().unwrap(), + "id-cmc-lraPOPWitness" + ); + assert_eq!( + ms_ctl_sign.long_name().unwrap(), + "Microsoft Trust List Signing" + ); + assert!( + undefined_nid.long_name().is_err(), + "undefined_nid should not return a valid value" + ); + } + + #[test] + fn test_short_name_conversion() { + let common_name = Nid::COMMONNAME; + let organizational_unit_name = Nid::ORGANIZATIONALUNITNAME; + let aes256_cbc_hmac_sha1 = Nid::AES_256_CBC_HMAC_SHA1; + let id_cmc_lrapopwitness = Nid::ID_CMC_LRAPOPWITNESS; + let ms_ctl_sign = Nid::MS_CTL_SIGN; + let undefined_nid = Nid::from_raw(118); + + assert_eq!(common_name.short_name().unwrap(), "CN"); + assert_eq!(organizational_unit_name.short_name().unwrap(), "OU"); + assert_eq!( + aes256_cbc_hmac_sha1.short_name().unwrap(), + "AES-256-CBC-HMAC-SHA1" + ); + assert_eq!( + id_cmc_lrapopwitness.short_name().unwrap(), + "id-cmc-lraPOPWitness" + ); + assert_eq!(ms_ctl_sign.short_name().unwrap(), "msCTLSign"); + assert!( + undefined_nid.short_name().is_err(), + "undefined_nid should not return a valid value" + ); + } +} diff --git a/openssl/src/pkcs12.rs b/openssl/src/pkcs12.rs index d71a1d82..b98848c8 100644 --- a/openssl/src/pkcs12.rs +++ b/openssl/src/pkcs12.rs @@ -3,15 +3,15 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; -use std::ptr; use std::ffi::CString; +use std::ptr; -use {cvt, cvt_p}; -use pkey::{HasPrivate, PKey, PKeyRef, Private}; use error::ErrorStack; -use x509::{X509, X509Ref}; -use stack::Stack; use nid::Nid; +use pkey::{HasPrivate, PKey, PKeyRef, Private}; +use stack::Stack; +use x509::{X509, X509Ref}; +use {cvt, cvt_p}; foreign_type_and_impl_send_sync! { type CType = ffi::PKCS12; @@ -172,7 +172,8 @@ impl Pkcs12Builder { let friendly_name = CString::new(friendly_name).unwrap(); let pkey = pkey.as_ptr(); let cert = cert.as_ptr(); - let ca = self.ca + let ca = self + .ca .as_ref() .map(|ca| ca.as_ptr()) .unwrap_or(ptr::null_mut()); @@ -206,11 +207,11 @@ mod test { use hex; use asn1::Asn1Time; - use rsa::Rsa; - use pkey::PKey; use nid::Nid; - use x509::{X509, X509Name}; + use pkey::PKey; + use rsa::Rsa; use x509::extension::KeyUsage; + use x509::{X509, X509Name}; use super::*; @@ -221,14 +222,14 @@ mod test { let parsed = pkcs12.parse("mypass").unwrap(); assert_eq!( - hex::encode(parsed.cert.fingerprint(MessageDigest::sha1()).unwrap()), + hex::encode(parsed.cert.digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); let chain = parsed.chain.unwrap(); assert_eq!(chain.len(), 1); assert_eq!( - hex::encode(chain[0].fingerprint(MessageDigest::sha1()).unwrap()), + hex::encode(chain[0].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } @@ -279,8 +280,8 @@ mod test { let parsed = pkcs12.parse("mypass").unwrap(); assert_eq!( - parsed.cert.fingerprint(MessageDigest::sha1()).unwrap(), - cert.fingerprint(MessageDigest::sha1()).unwrap() + &*parsed.cert.digest(MessageDigest::sha1()).unwrap(), + &*cert.digest(MessageDigest::sha1()).unwrap() ); assert!(parsed.pkey.public_eq(&pkey)); } diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 0ad55b96..92a5799e 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -189,7 +189,8 @@ where /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn d(&self) -> &BigNumRef { unsafe { - let d = compat::key(self.as_ptr())[2]; + let mut d = ptr::null(); + RSA_get0_key(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut d); BigNumRef::from_ptr(d as *mut _) } } @@ -201,7 +202,8 @@ where /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn p(&self) -> Option<&BigNumRef> { unsafe { - let p = compat::factors(self.as_ptr())[0]; + let mut p = ptr::null(); + RSA_get0_factors(self.as_ptr(), &mut p, ptr::null_mut()); if p.is_null() { None } else { @@ -217,7 +219,8 @@ where /// [`RSA_get0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn q(&self) -> Option<&BigNumRef> { unsafe { - let q = compat::factors(self.as_ptr())[1]; + let mut q = ptr::null(); + RSA_get0_factors(self.as_ptr(), ptr::null_mut(), &mut q); if q.is_null() { None } else { @@ -233,7 +236,8 @@ where /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn dmp1(&self) -> Option<&BigNumRef> { unsafe { - let dp = compat::crt_params(self.as_ptr())[0]; + let mut dp = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), &mut dp, ptr::null_mut(), ptr::null_mut()); if dp.is_null() { None } else { @@ -249,7 +253,8 @@ where /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn dmq1(&self) -> Option<&BigNumRef> { unsafe { - let dq = compat::crt_params(self.as_ptr())[1]; + let mut dq = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), &mut dq, ptr::null_mut()); if dq.is_null() { None } else { @@ -265,7 +270,8 @@ where /// [`RSA_get0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn iqmp(&self) -> Option<&BigNumRef> { unsafe { - let qi = compat::crt_params(self.as_ptr())[2]; + let mut qi = ptr::null(); + RSA_get0_crt_params(self.as_ptr(), ptr::null_mut(), ptr::null_mut(), &mut qi); if qi.is_null() { None } else { @@ -391,7 +397,8 @@ where /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn n(&self) -> &BigNumRef { unsafe { - let n = compat::key(self.as_ptr())[0]; + let mut n = ptr::null(); + RSA_get0_key(self.as_ptr(), &mut n, ptr::null_mut(), ptr::null_mut()); BigNumRef::from_ptr(n as *mut _) } } @@ -403,7 +410,8 @@ where /// [`RSA_get0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html pub fn e(&self) -> &BigNumRef { unsafe { - let e = compat::key(self.as_ptr())[1]; + let mut e = ptr::null(); + RSA_get0_key(self.as_ptr(), ptr::null_mut(), &mut e, ptr::null_mut()); BigNumRef::from_ptr(e as *mut _) } } @@ -421,15 +429,10 @@ impl Rsa { /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html pub fn from_public_components(n: BigNum, e: BigNum) -> Result, ErrorStack> { unsafe { - let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?); - cvt(compat::set_key( - rsa.0, - n.as_ptr(), - e.as_ptr(), - ptr::null_mut(), - ))?; + let rsa = cvt_p(ffi::RSA_new())?; + RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), ptr::null_mut()); mem::forget((n, e)); - Ok(rsa) + Ok(Rsa::from_ptr(rsa)) } } @@ -498,10 +501,12 @@ impl RsaPrivateKeyBuilder { /// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result { unsafe { - let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?); - cvt(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr()))?; + let rsa = cvt_p(ffi::RSA_new())?; + RSA_set0_key(rsa, n.as_ptr(), e.as_ptr(), d.as_ptr()); mem::forget((n, e, d)); - Ok(RsaPrivateKeyBuilder { rsa }) + Ok(RsaPrivateKeyBuilder { + rsa: Rsa::from_ptr(rsa), + }) } } @@ -512,9 +517,10 @@ impl RsaPrivateKeyBuilder { /// This correspond to [`RSA_set0_factors`]. /// /// [`RSA_set0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_factors.html + // FIXME should be infallible pub fn set_factors(self, p: BigNum, q: BigNum) -> Result { unsafe { - cvt(compat::set_factors(self.rsa.0, p.as_ptr(), q.as_ptr()))?; + RSA_set0_factors(self.rsa.as_ptr(), p.as_ptr(), q.as_ptr()); mem::forget((p, q)); } Ok(self) @@ -528,6 +534,7 @@ impl RsaPrivateKeyBuilder { /// This correspond to [`RSA_set0_crt_params`]. /// /// [`RSA_set0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_crt_params.html + // FIXME should be infallible pub fn set_crt_params( self, dmp1: BigNum, @@ -535,12 +542,12 @@ impl RsaPrivateKeyBuilder { iqmp: BigNum, ) -> Result { unsafe { - cvt(compat::set_crt_params( - self.rsa.0, + RSA_set0_crt_params( + self.rsa.as_ptr(), dmp1.as_ptr(), dmq1.as_ptr(), iqmp.as_ptr(), - ))?; + ); mem::forget((dmp1, dmq1, iqmp)); } Ok(self) @@ -637,89 +644,99 @@ impl fmt::Debug for Rsa { } } -#[cfg(ossl110)] -mod compat { - use std::ptr; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + RSA_get0_key, RSA_get0_factors, RSA_get0_crt_params, RSA_set0_key, RSA_set0_factors, + RSA_set0_crt_params, + }; + } else { + #[allow(bad_style)] + unsafe fn RSA_get0_key( + r: *const ffi::RSA, + n: *mut *const ffi::BIGNUM, + e: *mut *const ffi::BIGNUM, + d: *mut *const ffi::BIGNUM, + ) { + if !n.is_null() { + *n = (*r).n; + } + if !e.is_null() { + *e = (*r).e; + } + if !d.is_null() { + *d = (*r).d; + } + } - use ffi::{self, BIGNUM, RSA}; - use libc::c_int; + #[allow(bad_style)] + unsafe fn RSA_get0_factors( + r: *const ffi::RSA, + p: *mut *const ffi::BIGNUM, + q: *mut *const ffi::BIGNUM, + ) { + if !p.is_null() { + *p = (*r).p; + } + if !q.is_null() { + *q = (*r).q; + } + } - pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] { - let (mut n, mut e, mut d) = (ptr::null(), ptr::null(), ptr::null()); - ffi::RSA_get0_key(r, &mut n, &mut e, &mut d); - [n, e, d] - } + #[allow(bad_style)] + unsafe fn RSA_get0_crt_params( + r: *const ffi::RSA, + dmp1: *mut *const ffi::BIGNUM, + dmq1: *mut *const ffi::BIGNUM, + iqmp: *mut *const ffi::BIGNUM, + ) { + if !dmp1.is_null() { + *dmp1 = (*r).dmp1; + } + if !dmq1.is_null() { + *dmq1 = (*r).dmq1; + } + if !iqmp.is_null() { + *iqmp = (*r).iqmp; + } + } - pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] { - let (mut p, mut q) = (ptr::null(), ptr::null()); - ffi::RSA_get0_factors(r, &mut p, &mut q); - [p, q] - } + #[allow(bad_style)] + unsafe fn RSA_set0_key( + r: *mut ffi::RSA, + n: *mut ffi::BIGNUM, + e: *mut ffi::BIGNUM, + d: *mut ffi::BIGNUM, + ) -> c_int { + (*r).n = n; + (*r).e = e; + (*r).d = d; + 1 + } - pub unsafe fn crt_params(r: *const RSA) -> [*const BIGNUM; 3] { - let (mut dp, mut dq, mut qi) = (ptr::null(), ptr::null(), ptr::null()); - ffi::RSA_get0_crt_params(r, &mut dp, &mut dq, &mut qi); - [dp, dq, qi] - } + #[allow(bad_style)] + unsafe fn RSA_set0_factors( + r: *mut ffi::RSA, + p: *mut ffi::BIGNUM, + q: *mut ffi::BIGNUM, + ) -> c_int { + (*r).p = p; + (*r).q = q; + 1 + } - pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int { - ffi::RSA_set0_key(r, n, e, d) - } - - pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int { - ffi::RSA_set0_factors(r, p, q) - } - - pub unsafe fn set_crt_params( - r: *mut RSA, - dmp1: *mut BIGNUM, - dmq1: *mut BIGNUM, - iqmp: *mut BIGNUM, - ) -> c_int { - ffi::RSA_set0_crt_params(r, dmp1, dmq1, iqmp) - } -} - -#[cfg(ossl10x)] -mod compat { - use ffi::{BIGNUM, RSA}; - use libc::c_int; - - pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] { - [(*r).n, (*r).e, (*r).d] - } - - pub unsafe fn factors(r: *const RSA) -> [*const BIGNUM; 2] { - [(*r).p, (*r).q] - } - - pub unsafe fn crt_params(r: *const RSA) -> [*const BIGNUM; 3] { - [(*r).dmp1, (*r).dmq1, (*r).iqmp] - } - - pub unsafe fn set_key(r: *mut RSA, n: *mut BIGNUM, e: *mut BIGNUM, d: *mut BIGNUM) -> c_int { - (*r).n = n; - (*r).e = e; - (*r).d = d; - 1 // TODO: is this right? should it be 0? what's success? - } - - pub unsafe fn set_factors(r: *mut RSA, p: *mut BIGNUM, q: *mut BIGNUM) -> c_int { - (*r).p = p; - (*r).q = q; - 1 // TODO: is this right? should it be 0? what's success? - } - - pub unsafe fn set_crt_params( - r: *mut RSA, - dmp1: *mut BIGNUM, - dmq1: *mut BIGNUM, - iqmp: *mut BIGNUM, - ) -> c_int { - (*r).dmp1 = dmp1; - (*r).dmq1 = dmq1; - (*r).iqmp = iqmp; - 1 // TODO: is this right? should it be 0? what's success? + #[allow(bad_style)] + unsafe fn RSA_set0_crt_params( + r: *mut ffi::RSA, + dmp1: *mut ffi::BIGNUM, + dmq1: *mut ffi::BIGNUM, + iqmp: *mut ffi::BIGNUM, + ) -> c_int { + (*r).dmp1 = dmp1; + (*r).dmq1 = dmq1; + (*r).iqmp = iqmp; + 1 + } } } @@ -751,7 +768,8 @@ mod test { #[test] fn test_to_password() { let key = Rsa::generate(2048).unwrap(); - let pem = key.private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") + let pem = key + .private_key_to_pem_passphrase(Cipher::aes_128_cbc(), b"foobar") .unwrap(); Rsa::private_key_from_pem_passphrase(&pem, b"foobar").unwrap(); assert!(Rsa::private_key_from_pem_passphrase(&pem, b"fizzbuzz").is_err()); @@ -791,7 +809,8 @@ mod test { k0.private_encrypt(&msg, &mut emesg, Padding::PKCS1) .unwrap(); let mut dmesg = vec![0; k1.size() as usize]; - let len = k1.public_decrypt(&emesg, &mut dmesg, Padding::PKCS1) + let len = k1 + .public_decrypt(&emesg, &mut dmesg, Padding::PKCS1) .unwrap(); assert_eq!(msg, &dmesg[..len]); } @@ -807,7 +826,8 @@ mod test { let mut emesg = vec![0; k0.size() as usize]; k0.public_encrypt(&msg, &mut emesg, Padding::PKCS1).unwrap(); let mut dmesg = vec![0; k1.size() as usize]; - let len = k1.private_decrypt(&emesg, &mut dmesg, Padding::PKCS1) + let len = k1 + .private_decrypt(&emesg, &mut dmesg, Padding::PKCS1) .unwrap(); assert_eq!(msg, &dmesg[..len]); } @@ -883,6 +903,6 @@ mod test { #[test] fn clone() { let key = Rsa::generate(2048).unwrap(); - key.clone(); + drop(key.clone()); } } diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index c8032686..849831ed 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -63,21 +63,24 @@ //! ``` use ffi; use foreign_types::ForeignTypeRef; +use libc::c_int; use std::io::{self, Write}; use std::marker::PhantomData; use std::ptr; -use libc::c_int; -use {cvt, cvt_p}; +use error::ErrorStack; use hash::MessageDigest; use pkey::{HasPrivate, HasPublic, PKeyRef}; -use error::ErrorStack; use rsa::Padding; +use {cvt, cvt_p}; -#[cfg(ossl110)] -use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; -#[cfg(any(ossl101, ossl102))] -use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_MD_CTX_free, EVP_MD_CTX_new}; + } else { + use ffi::{EVP_MD_CTX_create as EVP_MD_CTX_new, EVP_MD_CTX_destroy as EVP_MD_CTX_free}; + } +} /// Salt lengths that must be used with `set_rsa_pss_saltlen`. pub struct RsaPssSaltlen(c_int); @@ -459,7 +462,7 @@ impl<'a> Verifier<'a> { pub fn verify(&self, signature: &[u8]) -> Result { unsafe { let r = - EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *const _, signature.len()); + EVP_DigestVerifyFinal(self.md_ctx, signature.as_ptr() as *mut _, signature.len()); match r { 1 => Ok(true), 0 => { @@ -501,12 +504,12 @@ mod test { use hex::{self, FromHex}; use std::iter; - use hash::MessageDigest; - use sign::{RsaPssSaltlen, Signer, Verifier}; use ec::{EcGroup, EcKey}; + use hash::MessageDigest; use nid::Nid; - use rsa::{Padding, Rsa}; use pkey::PKey; + use rsa::{Padding, Rsa}; + use sign::{RsaPssSaltlen, Signer, Verifier}; const INPUT: &'static str = "65794a68624763694f694a53557a49314e694a392e65794a7063334d694f694a71623255694c41304b49434a6c\ @@ -673,7 +676,7 @@ mod test { signer.update(data as &[u8]).unwrap(); let expected = vec![ - 136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19 + 136, 101, 61, 167, 61, 30, 248, 234, 124, 166, 196, 157, 203, 52, 171, 19, ]; assert_eq!(signer.sign_to_vec().unwrap(), expected); } diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index 4b792a75..1a149b6d 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -1,11 +1,13 @@ +use ffi::{ + self, BIO_clear_retry_flags, BIO_new, BIO_set_retry_read, BIO_set_retry_write, BIO, + BIO_CTRL_FLUSH, +}; use libc::{c_char, c_int, c_long, c_void, strlen}; -use ffi::{BIO, BIO_CTRL_FLUSH, BIO_new, BIO_clear_retry_flags, BIO_set_retry_read, - BIO_set_retry_write}; use std::any::Any; use std::io; use std::io::prelude::*; use std::mem; -use std::panic::{AssertUnwindSafe, catch_unwind}; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::ptr; use std::slice; @@ -19,11 +21,11 @@ pub struct StreamState { } /// Safe wrapper for BIO_METHOD -pub struct BioMethod(compat::BIO_METHOD); +pub struct BioMethod(BIO_METHOD); impl BioMethod { fn new() -> BioMethod { - BioMethod(compat::BIO_METHOD::new::()) + BioMethod(BIO_METHOD::new::()) } } @@ -41,8 +43,8 @@ pub fn new(stream: S) -> Result<(*mut BIO, BioMethod), ErrorSta unsafe { let bio = cvt_p(BIO_new(method.0.get()))?; - compat::BIO_set_data(bio, Box::into_raw(state) as *mut _); - compat::BIO_set_init(bio, 1); + BIO_set_data(bio, Box::into_raw(state) as *mut _); + BIO_set_init(bio, 1); return Ok((bio, method)); } @@ -59,7 +61,7 @@ pub unsafe fn take_panic(bio: *mut BIO) -> Option> { } pub unsafe fn get_ref<'a, S: 'a>(bio: *mut BIO) -> &'a S { - let state: &'a StreamState = mem::transmute(compat::BIO_get_data(bio)); + let state: &'a StreamState = mem::transmute(BIO_get_data(bio)); &state.stream } @@ -68,7 +70,7 @@ pub unsafe fn get_mut<'a, S: 'a>(bio: *mut BIO) -> &'a mut S { } unsafe fn state<'a, S: 'a>(bio: *mut BIO) -> &'a mut StreamState { - &mut *(compat::BIO_get_data(bio) as *mut _) + &mut *(BIO_get_data(bio) as *mut _) } unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_int) -> c_int { @@ -117,8 +119,7 @@ unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) fn retriable_error(err: &io::Error) -> bool { match err.kind() { - io::ErrorKind::WouldBlock | - io::ErrorKind::NotConnected => true, + io::ErrorKind::WouldBlock | io::ErrorKind::NotConnected => true, _ => false, } } @@ -153,10 +154,10 @@ unsafe extern "C" fn ctrl( } unsafe extern "C" fn create(bio: *mut BIO) -> c_int { - compat::BIO_set_init(bio, 0); - compat::BIO_set_num(bio, 0); - compat::BIO_set_data(bio, ptr::null_mut()); - compat::BIO_set_flags(bio, 0); + BIO_set_init(bio, 0); + BIO_set_num(bio, 0); + BIO_set_data(bio, ptr::null_mut()); + BIO_set_flags(bio, 0); 1 } @@ -165,115 +166,110 @@ unsafe extern "C" fn destroy(bio: *mut BIO) -> c_int { return 0; } - let data = compat::BIO_get_data(bio); + let data = BIO_get_data(bio); assert!(!data.is_null()); Box::>::from_raw(data as *mut _); - compat::BIO_set_data(bio, ptr::null_mut()); - compat::BIO_set_init(bio, 0); + BIO_set_data(bio, ptr::null_mut()); + BIO_set_init(bio, 0); 1 } -#[cfg(ossl110)] -#[allow(bad_style)] -mod compat { - use std::io::{Read, Write}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{BIO_get_data, BIO_set_data, BIO_set_flags, BIO_set_init}; - use libc::c_int; - use ffi; - pub use ffi::{BIO_set_init, BIO_set_flags, BIO_set_data, BIO_get_data}; + #[allow(bad_style)] + unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} - pub unsafe fn BIO_set_num(_bio: *mut ffi::BIO, _num: c_int) {} + #[allow(bad_style)] + struct BIO_METHOD(*mut ffi::BIO_METHOD); - pub struct BIO_METHOD(*mut ffi::BIO_METHOD); + impl BIO_METHOD { + fn new() -> BIO_METHOD { + unsafe { + let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _); + assert!(!ptr.is_null()); + let ret = BIO_METHOD(ptr); + assert!(ffi::BIO_meth_set_write(ptr, bwrite::) != 0); + assert!(ffi::BIO_meth_set_read(ptr, bread::) != 0); + assert!(ffi::BIO_meth_set_puts(ptr, bputs::) != 0); + assert!(ffi::BIO_meth_set_ctrl(ptr, ctrl::) != 0); + assert!(ffi::BIO_meth_set_create(ptr, create) != 0); + assert!(ffi::BIO_meth_set_destroy(ptr, destroy::) != 0); + return ret; + } + } - impl BIO_METHOD { - pub fn new() -> BIO_METHOD { - unsafe { - let ptr = ffi::BIO_meth_new(ffi::BIO_TYPE_NONE, b"rust\0".as_ptr() as *const _); - assert!(!ptr.is_null()); - let ret = BIO_METHOD(ptr); - assert!(ffi::BIO_meth_set_write(ptr, super::bwrite::) != 0); - assert!(ffi::BIO_meth_set_read(ptr, super::bread::) != 0); - assert!(ffi::BIO_meth_set_puts(ptr, super::bputs::) != 0); - assert!(ffi::BIO_meth_set_ctrl(ptr, super::ctrl::) != 0); - assert!(ffi::BIO_meth_set_create(ptr, super::create) != 0); - assert!(ffi::BIO_meth_set_destroy(ptr, super::destroy::) != 0); - return ret; + fn get(&self) -> *mut ffi::BIO_METHOD { + self.0 } } - pub fn get(&self) -> *mut ffi::BIO_METHOD { - self.0 - } - } - - impl Drop for BIO_METHOD { - fn drop(&mut self) { - unsafe { - ffi::BIO_meth_free(self.0); + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + ffi::BIO_meth_free(self.0); + } } } + } else { + #[allow(bad_style)] + struct BIO_METHOD(*mut ffi::BIO_METHOD); + + impl BIO_METHOD { + fn new() -> BIO_METHOD { + let ptr = Box::new(ffi::BIO_METHOD { + type_: ffi::BIO_TYPE_NONE, + name: b"rust\0".as_ptr() as *const _, + bwrite: Some(bwrite::), + bread: Some(bread::), + bputs: Some(bputs::), + bgets: None, + ctrl: Some(ctrl::), + create: Some(create), + destroy: Some(destroy::), + callback_ctrl: None, + }); + + BIO_METHOD(Box::into_raw(ptr)) + } + + fn get(&self) -> *mut ffi::BIO_METHOD { + self.0 + } + } + + impl Drop for BIO_METHOD { + fn drop(&mut self) { + unsafe { + Box::::from_raw(self.0); + } + } + } + + #[allow(bad_style)] + unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) { + (*bio).init = init; + } + + #[allow(bad_style)] + unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) { + (*bio).flags = flags; + } + + #[allow(bad_style)] + unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void { + (*bio).ptr + } + + #[allow(bad_style)] + unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) { + (*bio).ptr = data; + } + + #[allow(bad_style)] + unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) { + (*bio).num = num; + } } } - -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use std::io::{Read, Write}; - - use ffi; - use libc::{c_int, c_void}; - - pub struct BIO_METHOD(*mut ffi::BIO_METHOD); - - impl BIO_METHOD { - pub fn new() -> BIO_METHOD { - let ptr = Box::new(ffi::BIO_METHOD { - type_: ffi::BIO_TYPE_NONE, - name: b"rust\0".as_ptr() as *const _, - bwrite: Some(super::bwrite::), - bread: Some(super::bread::), - bputs: Some(super::bputs::), - bgets: None, - ctrl: Some(super::ctrl::), - create: Some(super::create), - destroy: Some(super::destroy::), - callback_ctrl: None, - }); - - BIO_METHOD(Box::into_raw(ptr)) - } - - pub fn get(&self) -> *mut ffi::BIO_METHOD { - self.0 - } - } - - impl Drop for BIO_METHOD { - fn drop(&mut self) { - unsafe { - Box::::from_raw(self.0); - } - } - } - - pub unsafe fn BIO_set_init(bio: *mut ffi::BIO, init: c_int) { - (*bio).init = init; - } - - pub unsafe fn BIO_set_flags(bio: *mut ffi::BIO, flags: c_int) { - (*bio).flags = flags; - } - - pub unsafe fn BIO_get_data(bio: *mut ffi::BIO) -> *mut c_void { - (*bio).ptr - } - - pub unsafe fn BIO_set_data(bio: *mut ffi::BIO, data: *mut c_void) { - (*bio).ptr = data; - } - - pub unsafe fn BIO_set_num(bio: *mut ffi::BIO, num: c_int) { - (*bio).num = num; - } -} diff --git a/openssl/src/ssl/callbacks.rs b/openssl/src/ssl/callbacks.rs index 887d450c..883befb8 100644 --- a/openssl/src/ssl/callbacks.rs +++ b/openssl/src/ssl/callbacks.rs @@ -1,9 +1,12 @@ use ffi; use foreign_types::ForeignType; use foreign_types::ForeignTypeRef; +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] +use libc::c_char; #[cfg(ossl111)] use libc::size_t; -use libc::{c_char, c_int, c_uchar, c_uint, c_void}; +use libc::{c_int, c_uchar, c_uint, c_void}; +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] use std::ffi::CStr; use std::mem; use std::ptr; @@ -13,11 +16,11 @@ use std::str; use std::sync::Arc; use dh::Dh; -#[cfg(any(ossl101, ossl102))] +#[cfg(all(ossl101, not(ossl110)))] use ec::EcKey; use error::ErrorStack; use pkey::Params; -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] use ssl::AlpnError; #[cfg(ossl111)] use ssl::ExtensionContext; @@ -37,7 +40,8 @@ where // raw pointer shenanigans to break the borrow of ctx // the callback can't mess with its own ex_data slot so this is safe - let verify = ctx.ex_data(ssl_idx) + let verify = ctx + .ex_data(ssl_idx) .expect("BUG: store context missing ssl") .ssl_context() .ex_data(verify_idx) @@ -66,7 +70,8 @@ where let ssl = SslRef::from_ptr_mut(ssl); let callback_idx = SslContext::cached_ex_index::(); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(callback_idx) .expect("BUG: psk callback missing") as *const F; let hint = if hint != ptr::null() { @@ -130,7 +135,8 @@ where let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing"); let callback_idx = Ssl::cached_ex_index::>(); - let callback = ctx.ex_data(ssl_idx) + let callback = ctx + .ex_data(ssl_idx) .expect("BUG: store context missing ssl") .ex_data(callback_idx) .expect("BUG: ssl verify callback missing") @@ -146,7 +152,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: sni callback missing") as *const F; let mut alert = SslAlert(*al); @@ -160,7 +167,7 @@ where } } -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] pub extern "C" fn raw_alpn_select( ssl: *mut ffi::SSL, out: *mut *const c_uchar, @@ -174,7 +181,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: alpn callback missing") as *const F; let protos = slice::from_raw_parts(inbuf as *const u8, inlen as usize); @@ -199,7 +207,8 @@ where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: tmp dh callback missing") as *const F; @@ -216,7 +225,7 @@ where } } -#[cfg(any(ossl101, ossl102))] +#[cfg(all(ossl101, not(ossl110)))] pub unsafe extern "C" fn raw_tmp_ecdh( ssl: *mut ffi::SSL, is_export: c_int, @@ -226,7 +235,8 @@ where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: tmp ecdh callback missing") as *const F; @@ -252,7 +262,8 @@ where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ex_data(Ssl::cached_ex_index::>()) + let callback = ssl + .ex_data(Ssl::cached_ex_index::>()) .expect("BUG: ssl tmp dh callback missing") .clone(); @@ -269,7 +280,7 @@ where } } -#[cfg(any(ossl101, ossl102))] +#[cfg(all(ossl101, not(ossl110)))] pub unsafe extern "C" fn raw_tmp_ecdh_ssl( ssl: *mut ffi::SSL, is_export: c_int, @@ -279,7 +290,8 @@ where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ex_data(Ssl::cached_ex_index::>()) + let callback = ssl + .ex_data(Ssl::cached_ex_index::>()) .expect("BUG: ssl tmp ecdh callback missing") .clone(); @@ -301,7 +313,8 @@ where F: Fn(&mut SslRef) -> Result + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: ocsp callback missing") as *const F; let ret = (*callback)(ssl); @@ -335,7 +348,8 @@ where F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: new session callback missing") as *const F; let session = SslSession::from_ptr(session); @@ -353,7 +367,8 @@ pub unsafe extern "C" fn raw_remove_session( F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send, { let ctx = SslContextRef::from_ptr(ctx); - let callback = ctx.ex_data(SslContext::cached_ex_index::()) + let callback = ctx + .ex_data(SslContext::cached_ex_index::()) .expect("BUG: remove session callback missing"); let session = SslSessionRef::from_ptr(session); @@ -375,7 +390,8 @@ where F: Fn(&mut SslRef, &[u8]) -> Option + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: get session callback missing") as *const F; let data = slice::from_raw_parts(data as *const u8, len as usize); @@ -397,7 +413,8 @@ where F: Fn(&SslRef, &str) + 'static + Sync + Send, { let ssl = SslRef::from_ptr(ssl as *mut _); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: get session callback missing"); let line = CStr::from_ptr(line).to_bytes(); @@ -416,7 +433,8 @@ where F: Fn(&mut SslRef, &mut [u8]) -> Result + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie generate callback missing") as *const F; let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize); @@ -442,7 +460,8 @@ where F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send, { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie verify callback missing") as *const F; let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); @@ -459,7 +478,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: cookie generate callback missing") as *const F; // We subtract 1 from DTLS1_COOKIE_LENGTH as the ostensible value, 256, is erroneous but retained for @@ -495,7 +515,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: cookie verify callback missing") as *const F; let slice = @@ -528,7 +549,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: custom ext add callback missing") as *const F; let ectx = ExtensionContext::from_bits_truncate(context); @@ -604,7 +626,8 @@ where { unsafe { let ssl = SslRef::from_ptr_mut(ssl); - let callback = ssl.ssl_context() + let callback = ssl + .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: custom ext parse callback missing") as *const F; let ectx = ExtensionContext::from_bits_truncate(context); diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 9966a5a0..f10a0e23 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -3,16 +3,22 @@ use std::ops::{Deref, DerefMut}; use dh::Dh; use error::ErrorStack; -use ssl::{HandshakeError, Ssl, SslContext, SslContextBuilder, SslMethod, SslMode, SslOptions, - SslRef, SslStream, SslVerifyMode}; +use ssl::{ + HandshakeError, Ssl, SslContext, SslContextBuilder, SslMethod, SslMode, SslOptions, SslRef, + SslStream, SslVerifyMode, +}; use version; fn ctx(method: SslMethod) -> Result { let mut ctx = SslContextBuilder::new(method)?; - let mut opts = SslOptions::ALL | SslOptions::NO_COMPRESSION | SslOptions::NO_SSLV2 - | SslOptions::NO_SSLV3 | SslOptions::SINGLE_DH_USE - | SslOptions::SINGLE_ECDH_USE | SslOptions::CIPHER_SERVER_PREFERENCE; + let mut opts = SslOptions::ALL + | SslOptions::NO_COMPRESSION + | SslOptions::NO_SSLV2 + | SslOptions::NO_SSLV3 + | SslOptions::SINGLE_DH_USE + | SslOptions::SINGLE_ECDH_USE + | SslOptions::CIPHER_SERVER_PREFERENCE; opts &= !SslOptions::DONT_INSERT_EMPTY_FRAGMENTS; ctx.set_options(opts); @@ -23,7 +29,7 @@ fn ctx(method: SslMethod) -> Result { // This is quite a useful optimization for saving memory, but historically // caused CVEs in OpenSSL pre-1.0.1h, according to // https://bugs.python.org/issue25672 - if version::number() >= 0x1000108f { + if version::number() >= 0x1_00_01_08_0 { mode |= SslMode::RELEASE_BUFFERS; } @@ -277,226 +283,228 @@ impl DerefMut for SslAcceptorBuilder { } } -#[cfg(ossl101)] -fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - use ec::EcKey; - use nid::Nid; - - let curve = EcKey::from_curve_name(Nid::X9_62_PRIME256V1)?; - ctx.set_tmp_ecdh(&curve) -} - -#[cfg(ossl102)] -fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { - ctx.set_ecdh_auto(true) -} - -#[cfg(ossl110)] -fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { - Ok(()) -} - -#[cfg(any(ossl102, ossl110))] -fn setup_verify(ctx: &mut SslContextBuilder) { - ctx.set_verify(SslVerifyMode::PEER); -} - -#[cfg(ossl101)] -fn setup_verify(ctx: &mut SslContextBuilder) { - ctx.set_verify_callback(SslVerifyMode::PEER, verify::verify_callback); -} - -#[cfg(any(ossl102, ossl110))] -fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { - use x509::verify::X509CheckFlags; - - let param = ssl.param_mut(); - param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); - match domain.parse() { - Ok(ip) => param.set_ip(ip), - Err(_) => param.set_host(domain), - } -} - -#[cfg(ossl101)] -fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { - let domain = domain.to_string(); - ssl.set_ex_data(*verify::HOSTNAME_IDX, domain); - Ok(()) -} - -#[cfg(ossl101)] -mod verify { - use std::net::IpAddr; - use std::str; - - use ex_data::Index; - use nid::Nid; - use x509::{GeneralName, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, - X509VerifyResult}; - use stack::Stack; - use ssl::Ssl; - - lazy_static! { - pub static ref HOSTNAME_IDX: Index = Ssl::new_ex_index().unwrap(); - } - - pub fn verify_callback(preverify_ok: bool, x509_ctx: &mut X509StoreContextRef) -> bool { - if !preverify_ok || x509_ctx.error_depth() != 0 { - return preverify_ok; +cfg_if! { + if #[cfg(ossl110)] { + fn setup_curves(_: &mut SslContextBuilder) -> Result<(), ErrorStack> { + Ok(()) } - - let ok = match ( - x509_ctx.current_cert(), - X509StoreContext::ssl_idx() - .ok() - .and_then(|idx| x509_ctx.ex_data(idx)) - .and_then(|ssl| ssl.ex_data(*HOSTNAME_IDX)), - ) { - (Some(x509), Some(domain)) => verify_hostname(domain, &x509), - _ => true, - }; - - if !ok { - x509_ctx.set_error(X509VerifyResult::APPLICATION_VERIFICATION); + } else if #[cfg(any(ossl102, libressl))] { + fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { + ctx.set_ecdh_auto(true) } + } else { + fn setup_curves(ctx: &mut SslContextBuilder) -> Result<(), ErrorStack> { + use ec::EcKey; + use nid::Nid; - ok - } - - fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { - match cert.subject_alt_names() { - Some(names) => verify_subject_alt_names(domain, names), - None => verify_subject_name(domain, &cert.subject_name()), + let curve = EcKey::from_curve_name(Nid::X9_62_PRIME256V1)?; + ctx.set_tmp_ecdh(&curve) } } +} - fn verify_subject_alt_names(domain: &str, names: Stack) -> bool { - let ip = domain.parse(); +cfg_if! { + if #[cfg(any(ossl102, libressl261))] { + fn setup_verify(ctx: &mut SslContextBuilder) { + ctx.set_verify(SslVerifyMode::PEER); + } - for name in &names { - match ip { - Ok(ip) => { - if let Some(actual) = name.ipaddress() { - if matches_ip(&ip, actual) { - return true; - } - } - } - Err(_) => { - if let Some(pattern) = name.dnsname() { - if matches_dns(pattern, domain) { - return true; - } - } - } + fn setup_verify_hostname(ssl: &mut SslRef, domain: &str) -> Result<(), ErrorStack> { + use x509::verify::X509CheckFlags; + + let param = ssl.param_mut(); + param.set_hostflags(X509CheckFlags::NO_PARTIAL_WILDCARDS); + match domain.parse() { + Ok(ip) => param.set_ip(ip), + Err(_) => param.set_host(domain), } } + } else { + fn setup_verify(ctx: &mut SslContextBuilder) { + ctx.set_verify_callback(SslVerifyMode::PEER, verify::verify_callback); + } - false - } + fn setup_verify_hostname(ssl: &mut Ssl, domain: &str) -> Result<(), ErrorStack> { + let domain = domain.to_string(); + ssl.set_ex_data(*verify::HOSTNAME_IDX, domain); + Ok(()) + } - fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { - match subject_name.entries_by_nid(Nid::COMMONNAME).next() { - Some(pattern) => { - let pattern = match str::from_utf8(pattern.data().as_slice()) { - Ok(pattern) => pattern, - Err(_) => return false, + mod verify { + use std::net::IpAddr; + use std::str; + + use ex_data::Index; + use nid::Nid; + use ssl::Ssl; + use stack::Stack; + use x509::{ + GeneralName, X509NameRef, X509Ref, X509StoreContext, X509StoreContextRef, + X509VerifyResult, + }; + + lazy_static! { + pub static ref HOSTNAME_IDX: Index = Ssl::new_ex_index().unwrap(); + } + + pub fn verify_callback(preverify_ok: bool, x509_ctx: &mut X509StoreContextRef) -> bool { + if !preverify_ok || x509_ctx.error_depth() != 0 { + return preverify_ok; + } + + let ok = match ( + x509_ctx.current_cert(), + X509StoreContext::ssl_idx() + .ok() + .and_then(|idx| x509_ctx.ex_data(idx)) + .and_then(|ssl| ssl.ex_data(*HOSTNAME_IDX)), + ) { + (Some(x509), Some(domain)) => verify_hostname(domain, &x509), + _ => true, }; - // Unlike SANs, IP addresses in the subject name don't have a - // different encoding. - match domain.parse::() { - Ok(ip) => pattern - .parse::() - .ok() - .map_or(false, |pattern| pattern == ip), - Err(_) => matches_dns(pattern, domain), + if !ok { + x509_ctx.set_error(X509VerifyResult::APPLICATION_VERIFICATION); + } + + ok + } + + fn verify_hostname(domain: &str, cert: &X509Ref) -> bool { + match cert.subject_alt_names() { + Some(names) => verify_subject_alt_names(domain, names), + None => verify_subject_name(domain, &cert.subject_name()), } } - None => false, - } - } - fn matches_dns(mut pattern: &str, mut hostname: &str) -> bool { - // first strip trailing . off of pattern and hostname to normalize - if pattern.ends_with('.') { - pattern = &pattern[..pattern.len() - 1]; - } - if hostname.ends_with('.') { - hostname = &hostname[..hostname.len() - 1]; - } + fn verify_subject_alt_names(domain: &str, names: Stack) -> bool { + let ip = domain.parse(); - matches_wildcard(pattern, hostname).unwrap_or_else(|| pattern == hostname) - } + for name in &names { + match ip { + Ok(ip) => { + if let Some(actual) = name.ipaddress() { + if matches_ip(&ip, actual) { + return true; + } + } + } + Err(_) => { + if let Some(pattern) = name.dnsname() { + if matches_dns(pattern, domain) { + return true; + } + } + } + } + } - fn matches_wildcard(pattern: &str, hostname: &str) -> Option { - // internationalized domains can't involved in wildcards - if pattern.starts_with("xn--") { - return None; - } + false + } - let wildcard_location = match pattern.find('*') { - Some(l) => l, - None => return None, - }; + fn verify_subject_name(domain: &str, subject_name: &X509NameRef) -> bool { + match subject_name.entries_by_nid(Nid::COMMONNAME).next() { + Some(pattern) => { + let pattern = match str::from_utf8(pattern.data().as_slice()) { + Ok(pattern) => pattern, + Err(_) => return false, + }; - let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); - let wildcard_end = match dot_idxs.next() { - Some(l) => l, - None => return None, - }; + // Unlike SANs, IP addresses in the subject name don't have a + // different encoding. + match domain.parse::() { + Ok(ip) => pattern + .parse::() + .ok() + .map_or(false, |pattern| pattern == ip), + Err(_) => matches_dns(pattern, domain), + } + } + None => false, + } + } - // Never match wildcards if the pattern has less than 2 '.'s (no *.com) - // - // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. - // Chrome has a black- and white-list for this, but Firefox (via NSS) does - // the same thing we do here. - // - // The Public Suffix (https://www.publicsuffix.org/) list could - // potentially be used here, but it's both huge and updated frequently - // enough that management would be a PITA. - if dot_idxs.next().is_none() { - return None; - } + fn matches_dns(mut pattern: &str, mut hostname: &str) -> bool { + // first strip trailing . off of pattern and hostname to normalize + if pattern.ends_with('.') { + pattern = &pattern[..pattern.len() - 1]; + } + if hostname.ends_with('.') { + hostname = &hostname[..hostname.len() - 1]; + } - // Wildcards can only be in the first component - if wildcard_location > wildcard_end { - return None; - } + matches_wildcard(pattern, hostname).unwrap_or_else(|| pattern == hostname) + } - let hostname_label_end = match hostname.find('.') { - Some(l) => l, - None => return None, - }; + fn matches_wildcard(pattern: &str, hostname: &str) -> Option { + // internationalized domains can't involved in wildcards + if pattern.starts_with("xn--") { + return None; + } - // check that the non-wildcard parts are identical - if pattern[wildcard_end..] != hostname[hostname_label_end..] { - return Some(false); - } + let wildcard_location = match pattern.find('*') { + Some(l) => l, + None => return None, + }; - let wildcard_prefix = &pattern[..wildcard_location]; - let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; + let mut dot_idxs = pattern.match_indices('.').map(|(l, _)| l); + let wildcard_end = match dot_idxs.next() { + Some(l) => l, + None => return None, + }; - let hostname_label = &hostname[..hostname_label_end]; + // Never match wildcards if the pattern has less than 2 '.'s (no *.com) + // + // This is a bit dubious, as it doesn't disallow other TLDs like *.co.uk. + // Chrome has a black- and white-list for this, but Firefox (via NSS) does + // the same thing we do here. + // + // The Public Suffix (https://www.publicsuffix.org/) list could + // potentially be used here, but it's both huge and updated frequently + // enough that management would be a PITA. + if dot_idxs.next().is_none() { + return None; + } - // check the prefix of the first label - if !hostname_label.starts_with(wildcard_prefix) { - return Some(false); - } + // Wildcards can only be in the first component + if wildcard_location > wildcard_end { + return None; + } - // and the suffix - if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { - return Some(false); - } + let hostname_label_end = match hostname.find('.') { + Some(l) => l, + None => return None, + }; - Some(true) - } + // check that the non-wildcard parts are identical + if pattern[wildcard_end..] != hostname[hostname_label_end..] { + return Some(false); + } - fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { - match *expected { - IpAddr::V4(ref addr) => actual == addr.octets(), - IpAddr::V6(ref addr) => actual == addr.octets(), + let wildcard_prefix = &pattern[..wildcard_location]; + let wildcard_suffix = &pattern[wildcard_location + 1..wildcard_end]; + + let hostname_label = &hostname[..hostname_label_end]; + + // check the prefix of the first label + if !hostname_label.starts_with(wildcard_prefix) { + return Some(false); + } + + // and the suffix + if !hostname_label[wildcard_prefix.len()..].ends_with(wildcard_suffix) { + return Some(false); + } + + Some(true) + } + + fn matches_ip(expected: &IpAddr, actual: &[u8]) -> bool { + match *expected { + IpAddr::V4(ref addr) => actual == addr.octets(), + IpAddr::V6(ref addr) => actual == addr.octets(), + } + } } } } diff --git a/openssl/src/ssl/error.rs b/openssl/src/ssl/error.rs index 18e44cd6..b7e29c15 100644 --- a/openssl/src/ssl/error.rs +++ b/openssl/src/ssl/error.rs @@ -99,17 +99,18 @@ impl fmt::Display for Error { Some(_) => fmt.write_str("a nonblocking read call would have blocked"), None => fmt.write_str("the operation should be retried"), }, + ErrorCode::WANT_WRITE => match self.io_error() { + Some(_) => fmt.write_str("a nonblocking write call would have blocked"), + None => fmt.write_str("the operation should be retried"), + }, ErrorCode::SYSCALL => match self.io_error() { - Some(err) => write!(fmt, "the inner stream returned an error: {}", err), + Some(err) => write!(fmt, "{}", err), None => fmt.write_str("unexpected EOF"), }, - ErrorCode::SSL => { - fmt.write_str("OpenSSL error")?; - if let Some(ref err) = self.ssl_error() { - write!(fmt, ": {}", err)? - } - Ok(()) - } + ErrorCode::SSL => match self.ssl_error() { + Some(e) => write!(fmt, "{}", e), + None => fmt.write_str("OpenSSL error"), + }, ErrorCode(code) => write!(fmt, "unknown error code {}", code), } } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 37f5086c..b69247db 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -78,23 +78,24 @@ use std::str; use std::sync::{Arc, Mutex}; use dh::{Dh, DhRef}; -#[cfg(any(ossl101, ossl102))] +#[cfg(all(ossl101, not(ossl110)))] use ec::EcKey; use ec::EcKeyRef; use error::ErrorStack; use ex_data::Index; #[cfg(ossl111)] use hash::MessageDigest; +#[cfg(ossl110)] use nid::Nid; use pkey::{HasPrivate, PKeyRef, Params, Private}; use ssl::bio::BioMethod; use ssl::callbacks::*; use ssl::error::InnerError; use stack::{Stack, StackRef}; -#[cfg(any(ossl102, ossl110))] +#[cfg(ossl102)] use x509::store::X509Store; use x509::store::{X509StoreBuilderRef, X509StoreRef}; -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] use x509::verify::X509VerifyParamRef; use x509::{X509, X509Name, X509Ref, X509StoreContextRef, X509VerifyResult}; use {cvt, cvt_n, cvt_p, init}; @@ -284,7 +285,7 @@ impl SslMethod { /// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method` /// on OpenSSL 1.0.x. pub fn tls() -> SslMethod { - SslMethod(compat::tls_method()) + unsafe { SslMethod(TLS_method()) } } /// Support all versions of the DTLS protocol. @@ -292,7 +293,7 @@ impl SslMethod { /// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method` /// on OpenSSL 1.0.x. pub fn dtls() -> SslMethod { - SslMethod(compat::dtls_method()) + unsafe { SslMethod(DTLS_method()) } } /// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value. @@ -506,12 +507,12 @@ impl SslAlert { /// An error returned from an ALPN selection callback. /// -/// Requires OpenSSL 1.0.2 or newer. -#[cfg(any(ossl102, ossl110))] +/// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. +#[cfg(any(ossl102, libressl261))] #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub struct AlpnError(c_int); -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] impl AlpnError { /// Terminate the handshake with a fatal alert. /// @@ -767,7 +768,7 @@ impl SslContextBuilder { /// Requires OpenSSL 1.0.1 or 1.0.2. /// /// This corresponds to `SSL_CTX_set_tmp_ecdh_callback`. - #[cfg(any(ossl101, ossl102))] + #[cfg(all(ossl101, not(ossl110)))] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, @@ -976,7 +977,7 @@ impl SslContextBuilder { /// This corresponds to [`SSL_CTX_set_ecdh_auto`]. /// /// [`SSL_CTX_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_ecdh_auto.html - #[cfg(any(ossl102, libressl))] + #[cfg(any(libressl, all(ossl102, not(ossl110))))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } } @@ -992,7 +993,7 @@ impl SslContextBuilder { /// /// [`SSL_CTX_set_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn set_options(&mut self, option: SslOptions) -> SslOptions { - let bits = unsafe { compat::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; + let bits = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) }; SslOptions { bits } } @@ -1002,7 +1003,7 @@ impl SslContextBuilder { /// /// [`SSL_CTX_get_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn options(&self) -> SslOptions { - let bits = unsafe { compat::SSL_CTX_get_options(self.as_ptr()) }; + let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) }; SslOptions { bits } } @@ -1012,7 +1013,7 @@ impl SslContextBuilder { /// /// [`SSL_CTX_clear_options`]: https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set_options.html pub fn clear_options(&mut self, option: SslOptions) -> SslOptions { - let bits = unsafe { compat::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; + let bits = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) }; SslOptions { bits } } @@ -1023,15 +1024,15 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_set_min_proto_version`]. /// - /// Requires OpenSSL 1.1.0 or newer. + /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110))] + #[cfg(any(ossl110, libressl261))] pub fn set_min_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_min_proto_version( self.as_ptr(), - version.map_or(0, |v| v.0), + version.map_or(0, |v| v.0 as _), )).map(|_| ()) } } @@ -1043,15 +1044,15 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_set_max_proto_version`]. /// - /// Requires OpenSSL 1.1.0 or newer. + /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110))] + #[cfg(any(ossl110, libressl261))] pub fn set_max_proto_version(&mut self, version: Option) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_CTX_set_max_proto_version( self.as_ptr(), - version.map_or(0, |v| v.0), + version.map_or(0, |v| v.0 as _), )).map(|_| ()) } } @@ -1063,10 +1064,10 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_get_min_proto_version`]. /// - /// Requires OpenSSL 1.1.0g or newer. + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. /// /// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110g))] + #[cfg(any(ossl110g, libressl270))] pub fn min_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr()); @@ -1085,10 +1086,10 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_get_max_proto_version`]. /// - /// Requires OpenSSL 1.1.0g or newer. + /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. /// /// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html - #[cfg(any(ossl110g))] + #[cfg(any(ossl110g, libressl270))] pub fn max_proto_version(&mut self) -> Option { unsafe { let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr()); @@ -1109,10 +1110,10 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_set_alpn_protos`]. /// - /// Requires OpenSSL 1.0.2 or newer. + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// [`SSL_CTX_set_alpn_protos`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html - #[cfg(any(ossl102, ossl110))] + #[cfg(any(ossl102, libressl261))] pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> { unsafe { assert!(protocols.len() <= c_uint::max_value() as usize); @@ -1140,12 +1141,12 @@ impl SslContextBuilder { /// /// This corresponds to [`SSL_CTX_set_alpn_select_cb`]. /// - /// Requires OpenSSL 1.0.2 or newer. + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos /// [`select_next_proto`]: fn.select_next_proto.html /// [`SSL_CTX_set_alpn_select_cb`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_alpn_protos.html - #[cfg(any(ossl102, ossl110))] + #[cfg(any(ossl102, libressl261))] pub fn set_alpn_select_callback(&mut self, callback: F) where F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send, @@ -1512,6 +1513,24 @@ impl SslContextBuilder { } } + /// Sets the maximum amount of early data that will be accepted on incoming connections. + /// + /// Defaults to 0. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_set_max_early_data`]. + /// + /// [`SSL_CTX_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_max_early_data.html + #[cfg(ossl111)] + pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> { + if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + /// Consumes the builder, returning a new `SslContext`. pub fn build(self) -> SslContext { self.0 @@ -1537,7 +1556,7 @@ foreign_type_and_impl_send_sync! { impl Clone for SslContext { fn clone(&self) -> Self { unsafe { - compat::SSL_CTX_up_ref(self.as_ptr()); + SSL_CTX_up_ref(self.as_ptr()); SslContext::from_ptr(self.as_ptr()) } } @@ -1570,7 +1589,7 @@ impl SslContext { { unsafe { ffi::init(); - let idx = cvt_n(compat::get_new_idx(free_data_box::))?; + let idx = cvt_n(get_new_idx(free_data_box::))?; Ok(Index::from_raw(idx)) } } @@ -1666,6 +1685,18 @@ impl SslContextRef { } } } + + /// Gets the maximum amount of early data that will be accepted on incoming connections. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_CTX_get_max_early_data`]. + /// + /// [`SSL_CTX_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) } + } } /// Information about the state of a cipher. @@ -1814,7 +1845,7 @@ impl SslCipherRef { } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::SSL_SESSION; fn drop = ffi::SSL_SESSION_free; @@ -1829,9 +1860,6 @@ foreign_type! { pub struct SslSessionRef; } -unsafe impl Sync for SslSession {} -unsafe impl Send for SslSession {} - impl Clone for SslSession { fn clone(&self) -> SslSession { SslSessionRef::to_owned(self) @@ -1856,7 +1884,7 @@ impl ToOwned for SslSessionRef { fn to_owned(&self) -> SslSession { unsafe { - compat::SSL_SESSION_up_ref(self.as_ptr()); + SSL_SESSION_up_ref(self.as_ptr()); SslSession(self.as_ptr()) } } @@ -1882,7 +1910,7 @@ impl SslSessionRef { /// /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html pub fn master_key_len(&self) -> usize { - unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } + unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) } } /// Copies the master key into the provided buffer. @@ -1893,7 +1921,19 @@ impl SslSessionRef { /// /// [`SSL_SESSION_get_master_key`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_SESSION_get_master_key.html pub fn master_key(&self, buf: &mut [u8]) -> usize { - unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } + unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) } + } + + /// Gets the maximum amount of early data that can be sent on this session. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_SESSION_get_max_early_data`]. + /// + /// [`SSL_SESSION_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_SESSION_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) } } to_der! { @@ -1907,7 +1947,7 @@ impl SslSessionRef { } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::SSL; fn drop = ffi::SSL_free; @@ -1925,9 +1965,6 @@ foreign_type! { pub struct SslRef; } -unsafe impl Sync for Ssl {} -unsafe impl Send for Ssl {} - impl fmt::Debug for Ssl { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, fmt) @@ -1949,7 +1986,7 @@ impl Ssl { { unsafe { ffi::init(); - let idx = cvt_n(compat::get_new_ssl_idx(free_data_box::))?; + let idx = cvt_n(get_new_ssl_idx(free_data_box::))?; Ok(Index::from_raw(idx)) } } @@ -2114,7 +2151,7 @@ impl SslRef { /// This corresponds to `SSL_set_tmp_ecdh_callback`. /// /// [`SslContextBuilder::set_tmp_ecdh_callback`]: struct.SslContextBuilder.html#method.set_tmp_ecdh_callback - #[cfg(any(ossl101, ossl102))] + #[cfg(any(all(ossl101, not(ossl110))))] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result, ErrorStack> + 'static + Sync + Send, @@ -2134,7 +2171,7 @@ impl SslRef { /// /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh /// [`SSL_set_ecdh_auto`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_ecdh_auto.html - #[cfg(ossl102)] + #[cfg(all(ossl102, not(ossl110)))] pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) } } @@ -2234,6 +2271,30 @@ impl SslRef { } } + /// Returns the verified certificate chani of the peer, including the leaf certificate. + /// + /// If verification was not successful (i.e. [`verify_result`] does not return + /// [`X509VerifyResult::OK`]), this chain may be incomplete or invalid. + /// + /// Requires OpenSSL 1.1.0 or newer. + /// + /// This corresponds to [`SSL_get0_verified_chain`]. + /// + /// [`verify_result`]: #method.verify_result + /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK + /// [`SSL_get0_verified_chain`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_get0_verified_chain.html + #[cfg(ossl110)] + pub fn verified_chain(&self) -> Option<&StackRef> { + unsafe { + let ptr = ffi::SSL_get0_verified_chain(self.as_ptr()); + if ptr.is_null() { + None + } else { + Some(StackRef::from_ptr(ptr)) + } + } + } + /// Like [`SslContext::certificate`]. /// /// This corresponds to `SSL_get_certificate`. @@ -2306,12 +2367,12 @@ impl SslRef { /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client /// to interpret it. /// - /// Requires OpenSSL 1.0.2 or newer. + /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer. /// /// This corresponds to [`SSL_get0_alpn_selected`]. /// /// [`SSL_get0_alpn_selected`]: https://www.openssl.org/docs/manmaster/man3/SSL_get0_next_proto_negotiated.html - #[cfg(any(ossl102, ossl110))] + #[cfg(any(ossl102, libressl261))] pub fn selected_alpn_protocol(&self) -> Option<&[u8]> { unsafe { let mut data: *const c_uchar = ptr::null(); @@ -2346,14 +2407,38 @@ impl SslRef { /// /// This corresponds to [`SSL_get_servername`]. /// + /// # Note + /// + /// While the SNI specification requires that servernames be valid domain names (and therefore + /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client + /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns + /// the raw bytes and does not have this restriction. + /// /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html + // FIXME maybe rethink in 0.11? pub fn servername(&self, type_: NameType) -> Option<&str> { + self.servername_raw(type_) + .and_then(|b| str::from_utf8(b).ok()) + } + + /// Returns the servername sent by the client via Server Name Indication (SNI). + /// + /// It is only useful on the server side. + /// + /// This corresponds to [`SSL_get_servername`]. + /// + /// # Note + /// + /// Unlike `servername`, this method does not require the name be valid UTF-8. + /// + /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html + pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> { unsafe { let name = ffi::SSL_get_servername(self.as_ptr(), type_.0); if name == ptr::null() { None } else { - Some(str::from_utf8(CStr::from_ptr(name as *const _).to_bytes()).unwrap()) + Some(CStr::from_ptr(name as *const _).to_bytes()) } } } @@ -2386,7 +2471,7 @@ impl SslRef { /// This corresponds to [`SSL_get0_param`]. /// /// [`SSL_get0_param`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_get0_param.html - #[cfg(any(ossl102, ossl110))] + #[cfg(any(ossl102, libressl261))] pub fn param_mut(&mut self) -> &mut X509VerifyParamRef { unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) } } @@ -2479,6 +2564,36 @@ impl SslRef { } } + /// Derives keying material for application use in accordance to RFC 5705. + /// + /// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no + /// context. Therefore, unlike `export_keying_material`, `context` must always be supplied. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_export_keying_material_early`]. + /// + /// [`SSL_export_keying_material_early`]: https://www.openssl.org/docs/manmaster/man3/SSL_export_keying_material_early.html + #[cfg(ossl111)] + pub fn export_keying_material_early( + &self, + out: &mut [u8], + label: &str, + context: &[u8], + ) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::SSL_export_keying_material_early( + self.as_ptr(), + out.as_mut_ptr() as *mut c_uchar, + out.len(), + label.as_ptr() as *const c_char, + label.len(), + context.as_ptr() as *const c_uchar, + context.len(), + )).map(|_| ()) + } + } + /// Sets the session to be used. /// /// This should be called before the handshake to attempt to reuse a previously established @@ -2564,7 +2679,7 @@ impl SslRef { /// /// [`SSL_is_server`]: https://www.openssl.org/docs/manmaster/man3/SSL_is_server.html pub fn is_server(&self) -> bool { - unsafe { compat::SSL_is_server(self.as_ptr()) != 0 } + unsafe { SSL_is_server(self.as_ptr()) != 0 } } /// Sets the extra data at the specified index. @@ -2617,6 +2732,57 @@ impl SslRef { } } } + + /// Sets the maximum amount of early data that will be accepted on this connection. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_set_max_early_data`]. + /// + /// [`SSL_set_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_set_max_early_data.html + #[cfg(ossl111)] + pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> { + if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 { + Ok(()) + } else { + Err(ErrorStack::get()) + } + } + + /// Gets the maximum amount of early data that can be sent on this connection. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_get_max_early_data`]. + /// + /// [`SSL_get_max_early_data`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_get_max_early_data.html + #[cfg(ossl111)] + pub fn max_early_data(&self) -> u32 { + unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) } + } + + /// Copies the contents of the last Finished message sent to the peer into the provided buffer. + /// + /// The total size of the message is returned, so this can be used to determine the size of the + /// buffer required. + /// + /// This corresponds to `SSL_get_finished`. + pub fn finished(&self, buf: &mut [u8]) -> usize { + unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) } + } + + /// Copies the contents of the last Finished message received from the peer into the provided + /// buffer. + /// + /// The total size of the message is returned, so this can be used to determine the size of the + /// buffer required. + /// + /// This corresponds to `SSL_get_finished`. + pub fn peer_finished(&self, buf: &mut [u8]) -> usize { + unsafe { + ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) + } + } } /// An SSL stream midway through the handshake process. @@ -2860,7 +3026,8 @@ impl Read for SslStream { } Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} Err(e) => { - return Err(e.into_io_error() + return Err(e + .into_io_error() .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))) } } @@ -2875,7 +3042,8 @@ impl Write for SslStream { Ok(n) => return Ok(n), Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {} Err(e) => { - return Err(e.into_io_error() + return Err(e + .into_io_error() .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e))) } } @@ -2927,6 +3095,24 @@ where } } + /// Configure as an outgoing stream from a client. + /// + /// This corresponds to [`SSL_set_connect_state`]. + /// + /// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html + pub fn set_connect_state(&mut self) { + unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) } + } + + /// Configure as an incoming stream to a server. + /// + /// This corresponds to [`SSL_set_accept_state`]. + /// + /// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html + pub fn set_accept_state(&mut self) { + unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) } + } + /// See `Ssl::connect` pub fn connect(self) -> Result, HandshakeError> { let mut stream = self.inner; @@ -2967,7 +3153,91 @@ where } } - // Future work: early IO methods + /// Initiates the handshake. + /// + /// This will fail if `set_accept_state` or `set_connect_state` was not called first. + /// + /// This corresponds to [`SSL_do_handshake`]. + /// + /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html + pub fn handshake(self) -> Result, HandshakeError> { + let mut stream = self.inner; + let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) }; + if ret > 0 { + Ok(stream) + } else { + let error = stream.make_error(ret); + match error.code() { + ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => Err(HandshakeError::WouldBlock( + MidHandshakeSslStream { stream, error }, + )), + _ => Err(HandshakeError::Failure(MidHandshakeSslStream { + stream, + error, + })), + } + } + } + + /// Read application data transmitted by a client before handshake + /// completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// `set_accept_state` first. + /// + /// Returns `Ok(0)` if all early data has been read. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_read_early_data`]. + /// + /// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html + #[cfg(ossl111)] + pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result { + let mut read = 0; + let ret = unsafe { + ffi::SSL_read_early_data( + self.inner.ssl.as_ptr(), + buf.as_ptr() as *mut c_void, + buf.len(), + &mut read, + ) + }; + match ret { + ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.inner.make_error(ret)), + ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read), + ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0), + _ => unreachable!(), + } + } + + /// Send data to the server without blocking on handshake completion. + /// + /// Useful for reducing latency, but vulnerable to replay attacks. Call + /// `set_connect_state` first. + /// + /// Requires OpenSSL 1.1.1 or newer. + /// + /// This corresponds to [`SSL_write_early_data`]. + /// + /// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html + #[cfg(ossl111)] + pub fn write_early_data(&mut self, buf: &[u8]) -> Result { + let mut written = 0; + let ret = unsafe { + ffi::SSL_write_early_data( + self.inner.ssl.as_ptr(), + buf.as_ptr() as *const c_void, + buf.len(), + &mut written, + ) + }; + if ret > 0 { + Ok(written as usize) + } else { + Err(self.inner.make_error(ret)) + } + } } impl SslStreamBuilder { @@ -3008,133 +3278,88 @@ pub enum ShutdownResult { Received, } -#[cfg(ossl110)] -mod compat { - use std::ptr; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + SSL_CTX_up_ref, + SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server, TLS_method, DTLS_method, + }; - use ffi; - use libc::c_int; + pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::CRYPTO_get_ex_new_index( + ffi::CRYPTO_EX_INDEX_SSL_CTX, + 0, + ptr::null_mut(), + None, + None, + Some(f), + ) + } - pub use ffi::{ - SSL_CTX_clear_options, SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_up_ref, - SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server, - }; + pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::CRYPTO_get_ex_new_index( + ffi::CRYPTO_EX_INDEX_SSL, + 0, + ptr::null_mut(), + None, + None, + Some(f), + ) + } + } else { + use ffi::{SSLv23_method as TLS_method, DTLSv1_method as DTLS_method}; - pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::CRYPTO_get_ex_new_index( - ffi::CRYPTO_EX_INDEX_SSL_CTX, - 0, - ptr::null_mut(), - None, - None, - Some(f), - ) - } + pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + } - pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::CRYPTO_get_ex_new_index( - ffi::CRYPTO_EX_INDEX_SSL, - 0, - ptr::null_mut(), - None, - None, - Some(f), - ) - } + pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { + ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) + } - pub fn tls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::TLS_method() } - } + #[allow(bad_style)] + pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> c_int { + ffi::CRYPTO_add_lock( + &mut (*ssl).references, + 1, + ffi::CRYPTO_LOCK_SSL_CTX, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + 0 + } - pub fn dtls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::DTLS_method() } - } -} - -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use std::ptr; - - use ffi; - use libc::{self, c_int, c_long, c_uchar, c_ulong, size_t}; - - pub unsafe fn SSL_CTX_get_options(ctx: *const ffi::SSL_CTX) -> c_ulong { - ffi::SSL_CTX_ctrl(ctx as *mut _, ffi::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong - } - - pub unsafe fn SSL_CTX_set_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong { - ffi::SSL_CTX_ctrl( - ctx as *mut _, - ffi::SSL_CTRL_OPTIONS, - op as c_long, - ptr::null_mut(), - ) as c_ulong - } - - pub unsafe fn SSL_CTX_clear_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong { - ffi::SSL_CTX_ctrl( - ctx as *mut _, - ffi::SSL_CTRL_CLEAR_OPTIONS, - op as c_long, - ptr::null_mut(), - ) as c_ulong - } - - pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) - } - - pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int { - ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f)) - } - - pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> libc::c_int { - ffi::CRYPTO_add_lock( - &mut (*ssl).references, - 1, - ffi::CRYPTO_LOCK_SSL_CTX, - "mod.rs\0".as_ptr() as *const _, - line!() as libc::c_int, - ); - 0 - } - - pub unsafe fn SSL_SESSION_get_master_key( - session: *const ffi::SSL_SESSION, - out: *mut c_uchar, - mut outlen: size_t, - ) -> size_t { - if outlen == 0 { - return (*session).master_key_length as size_t; - } - if outlen > (*session).master_key_length as size_t { - outlen = (*session).master_key_length as size_t; - } - ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); - outlen - } - - pub fn tls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::SSLv23_method() } - } - - pub fn dtls_method() -> *const ffi::SSL_METHOD { - unsafe { ffi::DTLSv1_method() } - } - - pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { - (*s).server - } - - pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int { - ffi::CRYPTO_add_lock( - &mut (*ses).references, - 1, - ffi::CRYPTO_LOCK_SSL_CTX, - "mod.rs\0".as_ptr() as *const _, - line!() as libc::c_int, - ); - 0 + #[allow(bad_style)] + pub unsafe fn SSL_SESSION_get_master_key( + session: *const ffi::SSL_SESSION, + out: *mut c_uchar, + mut outlen: usize, + ) -> usize { + if outlen == 0 { + return (*session).master_key_length as usize; + } + if outlen > (*session).master_key_length as usize { + outlen = (*session).master_key_length as usize; + } + ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen); + outlen + } + + #[allow(bad_style)] + pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int { + (*s).server + } + + #[allow(bad_style)] + pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int { + ffi::CRYPTO_add_lock( + &mut (*ses).references, + 1, + ffi::CRYPTO_LOCK_SSL_CTX, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + 0 + } } } diff --git a/openssl/src/ssl/test.rs b/openssl/src/ssl/test.rs index 2e906728..f5ec7b29 100644 --- a/openssl/src/ssl/test.rs +++ b/openssl/src/ssl/test.rs @@ -19,7 +19,7 @@ use hash::MessageDigest; use ocsp::{OcspResponse, OcspResponseStatus}; use pkey::PKey; use ssl; -#[cfg(any(ossl110, ossl111))] +#[cfg(any(ossl110, ossl111, libressl261))] use ssl::SslVersion; use ssl::{ Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, Ssl, SslAcceptor, SslConnector, @@ -295,8 +295,8 @@ run_test!(verify_callback_data, |method, stream| { match cert { None => false, Some(cert) => { - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); - fingerprint == node_id + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); + node_id == &*fingerprint } } }); @@ -323,8 +323,8 @@ run_test!(ssl_verify_callback, |method, stream| { match x509.current_cert() { None => false, Some(cert) => { - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); - fingerprint == node_id + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); + node_id == &*fingerprint } } }); @@ -424,10 +424,10 @@ run_test!(get_peer_certificate, |method, stream| { let ctx = SslContext::builder(method).unwrap(); let stream = Ssl::new(&ctx.build()).unwrap().connect(stream).unwrap(); let cert = stream.ssl().peer_certificate().unwrap(); - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); let node_hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; let node_id = Vec::from_hex(node_hash_str).unwrap(); - assert_eq!(node_id, fingerprint) + assert_eq!(node_id, &*fingerprint) }); #[test] @@ -481,7 +481,7 @@ fn test_state() { /// Tests that connecting with the client using ALPN, but the server not does not /// break the existing connection behavior. #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_connect_with_unilateral_alpn() { let (_s, stream) = Server::new(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -503,7 +503,7 @@ fn test_connect_with_unilateral_alpn() { /// Tests that when both the client as well as the server use ALPN and their /// lists of supported protocols have an overlap, the correct protocol is chosen. #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_connect_with_alpn_successful_multiple_matching() { let (_s, stream) = Server::new_alpn(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -526,7 +526,7 @@ fn test_connect_with_alpn_successful_multiple_matching() { /// lists of supported protocols have an overlap -- with only ONE protocol /// being valid for both. #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_connect_with_alpn_successful_single_match() { let (_s, stream) = Server::new_alpn(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -548,7 +548,7 @@ fn test_connect_with_alpn_successful_single_match() { /// Tests that when the `SslStream` is created as a server stream, the protocols /// are correctly advertised to the client. #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_alpn_server_advertise_multiple() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); @@ -624,7 +624,7 @@ fn test_alpn_server_select_none_fatal() { } #[test] -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] fn test_alpn_server_select_none() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let localhost = listener.local_addr().unwrap(); @@ -1063,7 +1063,7 @@ fn tmp_dh_callback() { } #[test] -#[cfg(any(all(ossl101, not(libressl)), ossl102))] +#[cfg(all(ossl101, not(ossl110)))] fn tmp_ecdh_callback() { use ec::EcKey; use nid::Nid; @@ -1137,7 +1137,7 @@ fn tmp_dh_callback_ssl() { } #[test] -#[cfg(any(all(ossl101, not(libressl)), ossl102))] +#[cfg(all(ossl101, not(ossl110)))] fn tmp_ecdh_callback_ssl() { use ec::EcKey; use nid::Nid; @@ -1315,7 +1315,7 @@ fn keying_export() { } #[test] -#[cfg(any(ossl110))] +#[cfg(any(ossl110, libressl261))] fn no_version_overlap() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let addr = listener.local_addr().unwrap(); @@ -1330,7 +1330,7 @@ fn no_version_overlap() { ctx.set_max_proto_version(Some(SslVersion::TLS1_1)).unwrap(); #[cfg(ossl110g)] assert_eq!(ctx.min_proto_version(), None); - #[cfg(ossl110g)] + #[cfg(any(ossl110g, libressl270))] assert_eq!(ctx.max_proto_version(), Some(SslVersion::TLS1_1)); let ssl = Ssl::new(&ctx.build()).unwrap(); ssl.accept(stream).unwrap_err(); @@ -1339,7 +1339,7 @@ fn no_version_overlap() { let stream = TcpStream::connect(addr).unwrap(); let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); ctx.set_min_proto_version(Some(SslVersion::TLS1_2)).unwrap(); - #[cfg(ossl110g)] + #[cfg(any(ossl110g, libressl270))] assert_eq!(ctx.min_proto_version(), Some(SslVersion::TLS1_2)); #[cfg(ossl110g)] assert_eq!(ctx.max_proto_version(), None); diff --git a/openssl/src/stack.rs b/openssl/src/stack.rs index d8589352..ac1e2a13 100644 --- a/openssl/src/stack.rs +++ b/openssl/src/stack.rs @@ -1,23 +1,30 @@ -use foreign_types::{ForeignTypeRef, ForeignType, Opaque}; +use ffi; +use foreign_types::{ForeignType, ForeignTypeRef, Opaque}; use libc::c_int; use std::borrow::Borrow; use std::convert::AsRef; use std::iter; use std::marker::PhantomData; use std::mem; -use ffi; -use {cvt, cvt_p}; use error::ErrorStack; use std::ops::{Deref, DerefMut, Index, IndexMut}; +use {cvt, cvt_p}; -#[cfg(ossl10x)] -use ffi::{sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, - sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK, - sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push}; -#[cfg(ossl110)] -use ffi::{OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK, - OPENSSL_sk_new_null, OPENSSL_sk_push}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + OPENSSL_sk_pop, OPENSSL_sk_free, OPENSSL_sk_num, OPENSSL_sk_value, OPENSSL_STACK, + OPENSSL_sk_new_null, OPENSSL_sk_push, + }; + } else { + use ffi::{ + sk_pop as OPENSSL_sk_pop, sk_free as OPENSSL_sk_free, sk_num as OPENSSL_sk_num, + sk_value as OPENSSL_sk_value, _STACK as OPENSSL_STACK, + sk_new_null as OPENSSL_sk_new_null, sk_push as OPENSSL_sk_push, + }; + } +} /// Trait implemented by types which can be placed in a stack. /// @@ -33,15 +40,8 @@ pub trait Stackable: ForeignType { /// An owned stack of `T`. pub struct Stack(*mut T::StackType); -impl Stack { - pub fn new() -> Result, ErrorStack> { - unsafe { - ffi::init(); - let ptr = cvt_p(OPENSSL_sk_new_null())?; - Ok(Stack(ptr as *mut _)) - } - } -} +unsafe impl Send for Stack {} +unsafe impl Sync for Stack {} impl Drop for Stack { fn drop(&mut self) { @@ -52,6 +52,16 @@ impl Drop for Stack { } } +impl Stack { + pub fn new() -> Result, ErrorStack> { + unsafe { + ffi::init(); + let ptr = cvt_p(OPENSSL_sk_new_null())?; + Ok(Stack(ptr as *mut _)) + } + } +} + impl iter::IntoIterator for Stack { type IntoIter = IntoIter; type Item = T; @@ -87,7 +97,7 @@ impl ForeignType for Stack { assert!( !ptr.is_null(), "Must not instantiate a Stack from a null-ptr - use Stack::new() in \ - that case" + that case" ); Stack(ptr) } @@ -157,6 +167,9 @@ impl ExactSizeIterator for IntoIter {} pub struct StackRef(Opaque, PhantomData); +unsafe impl Send for StackRef {} +unsafe impl Sync for StackRef {} + impl ForeignTypeRef for StackRef { type CType = T::StackType; } @@ -218,9 +231,7 @@ impl StackRef { /// Pushes a value onto the top of the stack. pub fn push(&mut self, data: T) -> Result<(), ErrorStack> { unsafe { - cvt( - OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _), - )?; + cvt(OPENSSL_sk_push(self.as_stack(), data.as_ptr() as *mut _))?; mem::forget(data); Ok(()) } diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 904fb8de..33655874 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -52,14 +52,14 @@ //! println!("Decrypted: '{}'", output_string); //! ``` +use ffi; +use libc::c_int; use std::cmp; use std::ptr; -use libc::c_int; -use ffi; -use {cvt, cvt_p}; use error::ErrorStack; use nid::Nid; +use {cvt, cvt_p}; #[derive(Copy, Clone)] pub enum Mode { @@ -718,34 +718,31 @@ pub fn decrypt_aead( Ok(out) } -#[cfg(ossl110)] -use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{EVP_CIPHER_block_size, EVP_CIPHER_iv_length, EVP_CIPHER_key_length}; + } else { + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_iv_length(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).iv_len + } -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use libc::c_int; - use ffi::EVP_CIPHER; + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_block_size(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).block_size + } - pub unsafe fn EVP_CIPHER_iv_length(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).iv_len - } - - pub unsafe fn EVP_CIPHER_block_size(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).block_size - } - - pub unsafe fn EVP_CIPHER_key_length(ptr: *const EVP_CIPHER) -> c_int { - (*ptr).key_len + #[allow(bad_style)] + pub unsafe fn EVP_CIPHER_key_length(ptr: *const ffi::EVP_CIPHER) -> c_int { + (*ptr).key_len + } } } -#[cfg(ossl10x)] -use self::compat::*; #[cfg(test)] mod tests { - use hex::{self, FromHex}; use super::*; + use hex::{self, FromHex}; // Test vectors from FIPS-197: // http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf diff --git a/openssl/src/version.rs b/openssl/src/version.rs index 7254d7ba..dc8508d1 100644 --- a/openssl/src/version.rs +++ b/openssl/src/version.rs @@ -13,15 +13,21 @@ use std::ffi::CStr; -#[cfg(ossl10x)] -use ffi::{SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, - SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM, - SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num, - SSLeay_version as OpenSSL_version}; - -#[cfg(ossl110)] -use ffi::{OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, - OpenSSL_version_num, OpenSSL_version}; +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + OPENSSL_VERSION, OPENSSL_CFLAGS, OPENSSL_BUILT_ON, OPENSSL_PLATFORM, OPENSSL_DIR, + OpenSSL_version_num, OpenSSL_version, + }; + } else { + use ffi::{ + SSLEAY_VERSION as OPENSSL_VERSION, SSLEAY_CFLAGS as OPENSSL_CFLAGS, + SSLEAY_BUILT_ON as OPENSSL_BUILT_ON, SSLEAY_PLATFORM as OPENSSL_PLATFORM, + SSLEAY_DIR as OPENSSL_DIR, SSLeay as OpenSSL_version_num, + SSLeay_version as OpenSSL_version, + }; + } +} /// OPENSSL_VERSION_NUMBER is a numeric release version identifier: /// @@ -51,7 +57,6 @@ pub fn number() -> i64 { unsafe { OpenSSL_version_num() as i64 } } - /// The text variant of the version number and the release date. For example, "OpenSSL 0.9.5a 1 Apr 2000". pub fn version() -> &'static str { unsafe { diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index c1ae3b16..5c1bb23f 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -7,9 +7,9 @@ //! Internet protocols, including SSL/TLS, which is the basis for HTTPS, //! the secure protocol for browsing the web. -use libc::{c_int, c_long}; use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; +use libc::{c_int, c_long}; use std::error::Error; use std::ffi::{CStr, CString}; use std::fmt; @@ -20,27 +20,20 @@ use std::ptr; use std::slice; use std::str; -use {cvt, cvt_n, cvt_p}; use asn1::{Asn1BitStringRef, Asn1IntegerRef, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef}; use bio::MemBioSlice; use conf::ConfRef; use error::ErrorStack; use ex_data::Index; -use hash::MessageDigest; +use hash::{DigestBytes, MessageDigest}; use nid::Nid; use pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; +use ssl::SslRef; use stack::{Stack, StackRef, Stackable}; use string::OpensslString; -use ssl::SslRef; +use {cvt, cvt_n, cvt_p}; -#[cfg(ossl10x)] -use ffi::{ASN1_STRING_data, X509_STORE_CTX_get_chain, X509_set_notAfter, X509_set_notBefore}; -#[cfg(ossl110)] -use ffi::{ASN1_STRING_get0_data as ASN1_STRING_data, - X509_STORE_CTX_get0_chain as X509_STORE_CTX_get_chain, - X509_set1_notAfter as X509_set_notAfter, X509_set1_notBefore as X509_set_notBefore}; - -#[cfg(any(ossl102, ossl110))] +#[cfg(any(ossl102, libressl261))] pub mod verify; pub mod extension; @@ -215,7 +208,7 @@ impl X509StoreContextRef { /// [`X509_STORE_CTX_get0_chain`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_STORE_CTX_get0_chain.html pub fn chain(&self) -> Option<&StackRef> { unsafe { - let chain = X509_STORE_CTX_get_chain(self.as_ptr()); + let chain = X509_STORE_CTX_get0_chain(self.as_ptr()); if chain.is_null() { None @@ -240,12 +233,12 @@ impl X509Builder { /// Sets the notAfter constraint on the certificate. pub fn set_not_after(&mut self, not_after: &Asn1TimeRef) -> Result<(), ErrorStack> { - unsafe { cvt(X509_set_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } + unsafe { cvt(X509_set1_notAfter(self.0.as_ptr(), not_after.as_ptr())).map(|_| ()) } } /// Sets the notBefore constraint on the certificate. pub fn set_not_before(&mut self, not_before: &Asn1TimeRef) -> Result<(), ErrorStack> { - unsafe { cvt(X509_set_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } + unsafe { cvt(X509_set1_notBefore(self.0.as_ptr(), not_before.as_ptr())).map(|_| ()) } } /// Sets the version of the certificate. @@ -454,27 +447,39 @@ impl X509Ref { } } - /// Returns certificate fingerprint calculated using provided hash - pub fn fingerprint(&self, hash_type: MessageDigest) -> Result, ErrorStack> { + /// Returns a digest of the DER representation of the certificate. + /// + /// This corresponds to [`X509_digest`]. + /// + /// [`X509_digest`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_digest.html + pub fn digest(&self, hash_type: MessageDigest) -> Result { unsafe { - let evp = hash_type.as_ptr(); + let mut digest = DigestBytes { + buf: [0; ffi::EVP_MAX_MD_SIZE as usize], + len: ffi::EVP_MAX_MD_SIZE as usize, + }; let mut len = ffi::EVP_MAX_MD_SIZE; - let mut buf = vec![0u8; len as usize]; cvt(ffi::X509_digest( self.as_ptr(), - evp, - buf.as_mut_ptr() as *mut _, + hash_type.as_ptr(), + digest.buf.as_mut_ptr() as *mut _, &mut len, ))?; - buf.truncate(len as usize); - Ok(buf) + digest.len = len as usize; + + Ok(digest) } } + #[deprecated(since = "0.10.9", note = "renamed to digest")] + pub fn fingerprint(&self, hash_type: MessageDigest) -> Result, ErrorStack> { + self.digest(hash_type).map(|b| b.to_vec()) + } + /// Returns the certificate's Not After validity period. pub fn not_after(&self) -> &Asn1TimeRef { unsafe { - let date = compat::X509_get_notAfter(self.as_ptr()); + let date = X509_getm_notAfter(self.as_ptr()); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date) } @@ -483,7 +488,7 @@ impl X509Ref { /// Returns the certificate's Not Before validity period. pub fn not_before(&self) -> &Asn1TimeRef { unsafe { - let date = compat::X509_get_notBefore(self.as_ptr()); + let date = X509_getm_notBefore(self.as_ptr()); assert!(!date.is_null()); Asn1TimeRef::from_ptr(date) } @@ -493,7 +498,7 @@ impl X509Ref { pub fn signature(&self) -> &Asn1BitStringRef { unsafe { let mut signature = ptr::null(); - compat::X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); + X509_get0_signature(&mut signature, ptr::null_mut(), self.as_ptr()); assert!(!signature.is_null()); Asn1BitStringRef::from_ptr(signature as *mut _) } @@ -503,7 +508,7 @@ impl X509Ref { pub fn signature_algorithm(&self) -> &X509AlgorithmRef { unsafe { let mut algor = ptr::null(); - compat::X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); + X509_get0_signature(ptr::null_mut(), &mut algor, self.as_ptr()); assert!(!algor.is_null()); X509AlgorithmRef::from_ptr(algor as *mut _) } @@ -564,7 +569,7 @@ impl ToOwned for X509Ref { fn to_owned(&self) -> X509 { unsafe { - compat::X509_up_ref(self.as_ptr()); + X509_up_ref(self.as_ptr()); X509::from_ptr(self.as_ptr()) } } @@ -1054,7 +1059,7 @@ impl X509ReqRef { /// /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_version.html pub fn version(&self) -> i32 { - unsafe { compat::X509_REQ_get_version(self.as_ptr()) as i32 } + unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } } /// Returns the subject name of the certificate request. @@ -1064,7 +1069,7 @@ impl X509ReqRef { /// [`X509_REQ_get_subject_name`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_subject_name.html pub fn subject_name(&self) -> &X509NameRef { unsafe { - let name = compat::X509_REQ_get_subject_name(self.as_ptr()); + let name = X509_REQ_get_subject_name(self.as_ptr()); assert!(!name.is_null()); X509NameRef::from_ptr(name) } @@ -1172,7 +1177,7 @@ impl GeneralNameRef { return None; } - let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _); + let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); let slice = slice::from_raw_parts(ptr as *const u8, len as usize); @@ -1205,7 +1210,7 @@ impl GeneralNameRef { return None; } - let ptr = ASN1_STRING_data((*self.as_ptr()).d as *mut _); + let ptr = ASN1_STRING_get0_data((*self.as_ptr()).d as *mut _); let len = ffi::ASN1_STRING_length((*self.as_ptr()).d as *mut _); Some(slice::from_raw_parts(ptr as *const u8, len as usize)) @@ -1232,79 +1237,86 @@ impl X509AlgorithmRef { pub fn object(&self) -> &Asn1ObjectRef { unsafe { let mut oid = ptr::null(); - compat::X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); + X509_ALGOR_get0(&mut oid, ptr::null_mut(), ptr::null_mut(), self.as_ptr()); assert!(!oid.is_null()); Asn1ObjectRef::from_ptr(oid as *mut _) } } } -#[cfg(ossl110)] -mod compat { - pub use ffi::X509_getm_notAfter as X509_get_notAfter; - pub use ffi::X509_getm_notBefore as X509_get_notBefore; - pub use ffi::X509_up_ref; - pub use ffi::X509_REQ_get_version; - pub use ffi::X509_REQ_get_subject_name; - pub use ffi::X509_get0_signature; - pub use ffi::X509_ALGOR_get0; -} +cfg_if! { + if #[cfg(ossl110)] { + use ffi::{ + X509_ALGOR_get0, X509_REQ_get_subject_name, X509_REQ_get_version, + X509_get0_signature, X509_getm_notAfter, X509_getm_notBefore, X509_up_ref, + ASN1_STRING_get0_data, X509_STORE_CTX_get0_chain, X509_set1_notAfter, + X509_set1_notBefore, + }; + } else { + use ffi::{ + ASN1_STRING_data as ASN1_STRING_get0_data, + X509_STORE_CTX_get_chain as X509_STORE_CTX_get0_chain, + X509_set_notAfter as X509_set1_notAfter, + X509_set_notBefore as X509_set1_notBefore, + }; -#[cfg(ossl10x)] -#[allow(bad_style)] -mod compat { - use libc::{c_int, c_void}; - use ffi; - - pub unsafe fn X509_get_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { - (*(*(*x).cert_info).validity).notAfter - } - - pub unsafe fn X509_get_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { - (*(*(*x).cert_info).validity).notBefore - } - - pub unsafe fn X509_up_ref(x: *mut ffi::X509) { - ffi::CRYPTO_add_lock( - &mut (*x).references, - 1, - ffi::CRYPTO_LOCK_X509, - "mod.rs\0".as_ptr() as *const _, - line!() as c_int, - ); - } - - pub unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { - ::ffi::ASN1_INTEGER_get((*(*x).req_info).version) - } - - pub unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { - (*(*x).req_info).subject - } - - pub unsafe fn X509_get0_signature( - psig: *mut *const ffi::ASN1_BIT_STRING, - palg: *mut *const ffi::X509_ALGOR, - x: *const ffi::X509, - ) { - if !psig.is_null() { - *psig = (*x).signature; + #[allow(bad_style)] + unsafe fn X509_getm_notAfter(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { + (*(*(*x).cert_info).validity).notAfter } - if !palg.is_null() { - *palg = (*x).sig_alg; - } - } - pub unsafe fn X509_ALGOR_get0( - paobj: *mut *const ffi::ASN1_OBJECT, - pptype: *mut c_int, - pval: *mut *mut c_void, - alg: *const ffi::X509_ALGOR, - ) { - if !paobj.is_null() { - *paobj = (*alg).algorithm; + #[allow(bad_style)] + unsafe fn X509_getm_notBefore(x: *mut ffi::X509) -> *mut ffi::ASN1_TIME { + (*(*(*x).cert_info).validity).notBefore + } + + #[allow(bad_style)] + unsafe fn X509_up_ref(x: *mut ffi::X509) { + ffi::CRYPTO_add_lock( + &mut (*x).references, + 1, + ffi::CRYPTO_LOCK_X509, + "mod.rs\0".as_ptr() as *const _, + line!() as c_int, + ); + } + + #[allow(bad_style)] + unsafe fn X509_REQ_get_version(x: *mut ffi::X509_REQ) -> ::libc::c_long { + ffi::ASN1_INTEGER_get((*(*x).req_info).version) + } + + #[allow(bad_style)] + unsafe fn X509_REQ_get_subject_name(x: *mut ffi::X509_REQ) -> *mut ::ffi::X509_NAME { + (*(*x).req_info).subject + } + + #[allow(bad_style)] + unsafe fn X509_get0_signature( + psig: *mut *const ffi::ASN1_BIT_STRING, + palg: *mut *const ffi::X509_ALGOR, + x: *const ffi::X509, + ) { + if !psig.is_null() { + *psig = (*x).signature; + } + if !palg.is_null() { + *palg = (*x).sig_alg; + } + } + + #[allow(bad_style)] + unsafe fn X509_ALGOR_get0( + paobj: *mut *const ffi::ASN1_OBJECT, + pptype: *mut c_int, + pval: *mut *mut ::libc::c_void, + alg: *const ffi::X509_ALGOR, + ) { + if !paobj.is_null() { + *paobj = (*alg).algorithm; + } + assert!(pptype.is_null()); + assert!(pval.is_null()); } - assert!(pptype.is_null()); - assert!(pval.is_null()); } } diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs index 4d6bc9ab..f533d9c7 100644 --- a/openssl/src/x509/store.rs +++ b/openssl/src/x509/store.rs @@ -44,11 +44,11 @@ use ffi; use foreign_types::ForeignTypeRef; use std::mem; -use {cvt, cvt_p}; use error::ErrorStack; use x509::X509; +use {cvt, cvt_p}; -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; fn drop = ffi::X509_STORE_free; @@ -82,9 +82,7 @@ impl X509StoreBuilderRef { /// Adds a certificate to the certificate store. // FIXME should take an &X509Ref pub fn add_cert(&mut self, cert: X509) -> Result<(), ErrorStack> { - unsafe { - cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) - } + unsafe { cvt(ffi::X509_STORE_add_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) } } /// Load certificates from their default locations. @@ -97,7 +95,7 @@ impl X509StoreBuilderRef { } } -foreign_type! { +foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE; fn drop = ffi::X509_STORE_free; diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 7ef4d160..42859c97 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -7,10 +7,12 @@ use nid::Nid; use pkey::{PKey, Private}; use rsa::Rsa; use stack::Stack; -use x509::{X509, X509Name, X509Req, X509StoreContext, X509VerifyResult}; -use x509::extension::{AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, - SubjectAlternativeName, SubjectKeyIdentifier}; +use x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, ExtendedKeyUsage, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; use x509::store::X509StoreBuilder; +use x509::{X509, X509Name, X509Req, X509StoreContext, X509VerifyResult}; fn pkey() -> PKey { let rsa = Rsa::generate(2048).unwrap(); @@ -21,12 +23,12 @@ fn pkey() -> PKey { fn test_cert_loading() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).ok().expect("Failed to load PEM"); - let fingerprint = cert.fingerprint(MessageDigest::sha1()).unwrap(); + let fingerprint = cert.digest(MessageDigest::sha1()).unwrap(); let hash_str = "59172d9313e84459bcff27f967e79e6e9217e584"; let hash_vec = Vec::from_hex(hash_str).unwrap(); - assert_eq!(fingerprint, hash_vec); + assert_eq!(hash_vec, &*fingerprint); } #[test] @@ -197,7 +199,8 @@ fn x509_builder() { assert!(pkey.public_eq(&x509.public_key().unwrap())); - let cn = x509.subject_name() + let cn = x509 + .subject_name() .entries_by_nid(Nid::COMMONNAME) .next() .unwrap(); @@ -247,11 +250,11 @@ fn test_stack_from_pem() { assert_eq!(certs.len(), 2); assert_eq!( - hex::encode(certs[0].fingerprint(MessageDigest::sha1()).unwrap()), + hex::encode(certs[0].digest(MessageDigest::sha1()).unwrap()), "59172d9313e84459bcff27f967e79e6e9217e584" ); assert_eq!( - hex::encode(certs[1].fingerprint(MessageDigest::sha1()).unwrap()), + hex::encode(certs[1].digest(MessageDigest::sha1()).unwrap()), "c0cbdf7cdd03c9773e5468e1f6d2da7d5cbb1875" ); } @@ -291,7 +294,7 @@ fn signature() { fn clone_x509() { let cert = include_bytes!("../../test/cert.pem"); let cert = X509::from_pem(cert).unwrap(); - cert.clone(); + drop(cert.clone()); } #[test] diff --git a/openssl/src/x509/verify.rs b/openssl/src/x509/verify.rs index b90c8f58..2eabe38c 100644 --- a/openssl/src/x509/verify.rs +++ b/openssl/src/x509/verify.rs @@ -1,6 +1,6 @@ -use libc::c_uint; use ffi; use foreign_types::ForeignTypeRef; +use libc::c_uint; use std::net::IpAddr; use cvt; diff --git a/systest/build.rs b/systest/build.rs index 98e9ffb3..84c0a1ae 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -2,10 +2,12 @@ extern crate ctest; use std::env; +#[path = "../openssl-sys/build/cfgs.rs"] +mod cfgs; + fn main() { let mut cfg = ctest::TestGenerator::new(); let target = env::var("TARGET").unwrap(); - let mut is_libressl = false; if let Ok(out) = env::var("DEP_OPENSSL_INCLUDE") { cfg.include(&out); @@ -26,21 +28,17 @@ fn main() { cfg.define("WIN32_LEAN_AND_MEAN", None); } - if let Ok(_) = env::var("DEP_OPENSSL_LIBRESSL") { - cfg.cfg("libressl", None); - is_libressl = true; - } else if let Ok(version) = env::var("DEP_OPENSSL_VERSION") { - cfg.cfg(&format!("ossl{}", version), None); - if version == "111" { - cfg.cfg("ossl110", None); - } - } - if let (Ok(version), Ok(patch)) = ( - env::var("DEP_OPENSSL_VERSION"), - env::var("DEP_OPENSSL_PATCH"), - ) { - cfg.cfg(&format!("ossl{}{}", version, patch), None); + let openssl_version = env::var("DEP_OPENSSL_VERSION_NUMBER") + .ok() + .map(|v| u64::from_str_radix(&v, 16).unwrap()); + let libressl_version = env::var("DEP_OPENSSL_LIBRESSL_VERSION_NUMBER") + .ok() + .map(|v| u64::from_str_radix(&v, 16).unwrap()); + + for c in cfgs::get(openssl_version, libressl_version) { + cfg.cfg(c, None); } + if let Ok(vars) = env::var("DEP_OPENSSL_CONF") { for var in vars.split(",") { cfg.cfg("osslconf", Some(var)); @@ -65,7 +63,7 @@ fn main() { .header("openssl/ocsp.h") .header("openssl/evp.h"); - if !is_libressl { + if openssl_version.is_some() { cfg.header("openssl/cms.h"); } @@ -79,7 +77,8 @@ fn main() { } else if s == "_STACK" { format!("struct stack_st") // This logic should really be cleaned up - } else if is_struct && s != "point_conversion_form_t" + } else if is_struct + && s != "point_conversion_form_t" && s.chars().next().unwrap().is_lowercase() { format!("struct {}", s) @@ -111,9 +110,13 @@ fn main() { (s == "GENERAL_NAME" && field == "d") // union }); cfg.skip_signededness(|s| { - s.ends_with("_cb") || s.ends_with("_CB") || s.ends_with("_cb_fn") - || s.starts_with("CRYPTO_") || s == "PasswordCallback" - || s.ends_with("_cb_func") || s.ends_with("_cb_ex") + s.ends_with("_cb") + || s.ends_with("_CB") + || s.ends_with("_cb_fn") + || s.starts_with("CRYPTO_") + || s == "PasswordCallback" + || s.ends_with("_cb_func") + || s.ends_with("_cb_ex") }); cfg.field_name(|_s, field| { if field == "type_" {