diff --git a/README.OpenSource b/README.OpenSource index 518d65aa12076b5ed0cfc0002da8f6138c84b751..d159af9c6c5bac9292603c90dfd2889d8ee23063 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,7 +3,7 @@ "Name": "openssl", "License": "Apache License V2.0", "License File": "THIRD_PARTY", - "Version Number": "0.10.48", + "Version Number": "0.10.56", "Owner": "xuelei3@huawei.com", "Upstream URL": "https://github.com/sfackler/rust-openssl", "Description": "OpenSSL bindings." diff --git a/openssl-errors/Cargo.toml b/openssl-errors/Cargo.toml index 1f60f0ee087896776f3c107e6ba9d61d6138456c..5285b266e1abbc4343ef1c6680853b2a587b7b19 100644 --- a/openssl-errors/Cargo.toml +++ b/openssl-errors/Cargo.toml @@ -3,7 +3,7 @@ name = "openssl-errors" version = "0.2.0" authors = ["Steven Fackler "] edition = "2018" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" description = "Custom error library support for the openssl crate." repository = "https://github.com/sfackler/rust-openssl" readme = "README.md" diff --git a/openssl-macros/BUILD.gn b/openssl-macros/BUILD.gn index ec50550c8a26b8eabf64bbaa84fc41f9f711bca5..cc4d3298f20abcc54c135f4b00b2daf2e37c73b0 100644 --- a/openssl-macros/BUILD.gn +++ b/openssl-macros/BUILD.gn @@ -20,7 +20,7 @@ ohos_cargo_crate("lib") { sources = [ "src/lib.rs" ] edition = "2018" - cargo_pkg_version = "0.1.0" + cargo_pkg_version = "0.1.1" cargo_pkg_name = "openssl-macros" cargo_pkg_description = "Internal macros used by the openssl crate." deps = [ diff --git a/openssl-macros/Cargo.toml b/openssl-macros/Cargo.toml index d55f2267d852809f3cf6ad1492ff310076c788f1..7f0c1c7e4493133cf495e7c42312fa18db3475b8 100644 --- a/openssl-macros/Cargo.toml +++ b/openssl-macros/Cargo.toml @@ -1,8 +1,8 @@ [package] name = "openssl-macros" -version = "0.1.0" +version = "0.1.1" edition = "2018" -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" description = "Internal macros used by the openssl crate." [lib] @@ -11,4 +11,4 @@ proc-macro = true [dependencies] proc-macro2 = "1" quote = "1" -syn = { version = "1", features = ["full"] } +syn = { version = "2", features = ["full"] } diff --git a/openssl-sys/BUILD.gn b/openssl-sys/BUILD.gn index 7451f280dfef05eec183f5f1a9d24681850a4e87..5d243d3167484851de319e87d460c04e09d3e8d9 100644 --- a/openssl-sys/BUILD.gn +++ b/openssl-sys/BUILD.gn @@ -20,7 +20,7 @@ ohos_cargo_crate("lib") { sources = [ "src/lib.rs" ] edition = "2018" - cargo_pkg_version = "0.9.82" + cargo_pkg_version = "0.9.91" cargo_pkg_authors = "Alex Crichton , Steven Fackler " cargo_pkg_name = "openssl-sys" cargo_pkg_description = "FFI bindings to OpenSSL" diff --git a/openssl-sys/CHANGELOG.md b/openssl-sys/CHANGELOG.md index 8587ad22622b0cf0afeed1ba24a51d693533a406..3a1a1f18658e5aca87b27d718c9447bbd04160f2 100644 --- a/openssl-sys/CHANGELOG.md +++ b/openssl-sys/CHANGELOG.md @@ -2,6 +2,86 @@ ## [Unreleased] +## [v0.9.91] - 2023-08-06 + +### Added + +* Expose `poly1305_state`, `CRYPTO_poly1305_init`, `CRYPTO_poly1305_update`, and `CRYPTO_poly1305_finish` on BoringSSL and LibreSSL. +* Fix detection of libraries on OpenBSD. +* Added `EC_POINT_point2hex` and `EC_POINT_hex2point`. +* Added `EVP_PKEY_verify_recover_init`, `EVP_PKEY_verify_recover`, and `EVP_PKEY_CTX_set_signature_md`. +* Added `EVP_CIPHER_CTX_FLAG_WRAP_ALLOW` and `EVP_CTX_set_flags`. +* Added `BN_mod_sqrt`. + +## [v0.9.90] - 2023-06-20 + +### Fixed + +* Fixed compilation with BoringSSL when building with the bindgen CLI. + +## [v0.9.89] - 2023-06-20 + +### Fixed + +* Fixed compilation with recent versions of BoringSSL. + +### Added + +* Added support for detecting OpenSSL compiled with `OPENSSL_NO_OCB`. +* Added `EVP_PKEY_SM2` and `NID_sm2`. +* Added `EVP_PKEY_assign_RSA`, `EVP_PKEY_assign_DSA`, `EVP_PKEY_assign_DH`, and `EVP_PKEY_assign_EC_KEY`. +* Added `EC_GROUP_get_asn1_flag`. +* Expose `EC_POINT_get_affine_coordinates` on BoringSSL and LibreSSL. +* Added `EVP_PKEY_derive_set_peer_ex`. + +## [v0.9.88] - 2023-05-30 + +### Added + +* Added support for the LibreSSL 3.8.0. +* Added support for detecting `OPENSSL_NO_RC4`. +* Added `OBJ_dup`. +* Added `ASN1_TYPE_new`, `ASN1_TYPE_set`, `d2i_ASN1_TYPE`, and `i2d_ASN1_TYPE`. +* Added `SSL_bytes_to_cipher_list`, `SSL_CTX_get_num_tickets`, and `SSL_get_num_tickets`. +* Added `GENERAL_NAME_set0_othername`. +* Added `X509_get_pathlen`. + +## [v0.9.87] - 2023-04-24 + +### Added + +* Added `DH_CHECK`. +* Added `CMAC_CTX_new`, `CMAC_CTX_free`, `CMAC_Init`, `CMAC_Update`, `CMAC_Final`, and `CMAC_CTX_copy`. +* Added `EVP_default_properties_is_fips_enabled`. +* Added `X509_get0_subject_key_id`, `X509_get0_authority_key_id`, `X509_get0_authority_issuer`, and `X509_get0_authority_serial`. +* Added `NID_poly1305`. + + +## [v0.9.86] - 2023-04-20 + +### Fixed + +* Fixed BoringSSL support with the latest bindgen release. + +### Added + +* Added bindings for PKCS#7 functions and more X.509 functions. + + +## [v0.9.85] - 2023-04-09 + +### Added + +* Added support for LibreSSL 3.7.x. + +## [v0.9.84] - 2023-04-01 + +### Added + +* Added `ASN1_INTEGER_dup` and `ASN1_INTEGER_cmp`. +* Added `stack_st_X509_NAME_ENTRY`. +* Added `DIST_POINT_NAME`, `DIST_POINT`, `stack_st_DIST_POINT`, `DIST_POINT_free`, and `DIST_POINT_NAME_free`. + ## [v0.9.83] - 2023-03-23 ### Fixed @@ -410,7 +490,15 @@ Fixed builds against OpenSSL built with `no-cast`. * Added `X509_verify` and `X509_REQ_verify`. * Added `EVP_MD_type` and `EVP_GROUP_get_curve_name`. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.83..master +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.91..master +[v0.9.91]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.90...openssl-sys-v0.9.91 +[v0.9.90]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.89...openssl-sys-v0.9.90 +[v0.9.89]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.88...openssl-sys-v0.9.89 +[v0.9.88]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.87...openssl-sys-v0.9.88 +[v0.9.87]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.86...openssl-sys-v0.9.87 +[v0.9.86]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.85...openssl-sys-v0.9.86 +[v0.9.85]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.84...openssl-sys-v0.9.85 +[v0.9.84]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.83...openssl-sys-v0.9.84 [v0.9.83]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.82...openssl-sys-v0.9.83 [v0.9.82]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.81...openssl-sys-v0.9.82 [v0.9.81]: https://github.com/sfackler/rust-openssl/compare/openssl-sys-v0.9.80...openssl-sys-v0.9.81 diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index ad7582ad056f69d33233677b0dff4bdb38e37ab1..3caa72fa79bbd1e34900f19520456d3138d7e3fd 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-sys" -version = "0.9.83" +version = "0.9.91" authors = [ "Alex Crichton ", "Steven Fackler ", @@ -24,12 +24,9 @@ bssl-sys = { version = "0.1.0", optional = true } [build-dependencies] bindgen = { version = "0.64.0", optional = true, features = ["experimental"] } -cc = "1.0" +cc = "1.0.61" openssl-src = { version = "111", optional = true } pkg-config = "0.3.9" -autocfg = "1.0" - -[target.'cfg(target_env = "msvc")'.build-dependencies] vcpkg = "0.2.8" # We don't actually use metadeps for annoying reasons but this is still here for tooling diff --git a/openssl-sys/build/cfgs.rs b/openssl-sys/build/cfgs.rs index 960515f00f0b36a2b37b5d5e36352e99fccbb0c0..2f3ff3eafd66af92c1b3e3f1b1c105939b7535aa 100644 --- a/openssl-sys/build/cfgs.rs +++ b/openssl-sys/build/cfgs.rs @@ -1,3 +1,4 @@ +#[allow(clippy::unusual_byte_groupings)] pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<&'static str> { let mut cfgs = vec![]; @@ -91,6 +92,9 @@ pub fn get(openssl_version: Option, libressl_version: Option) -> Vec<& if openssl_version >= 0x1_01_01_03_0 { cfgs.push("ossl111c"); } + if openssl_version >= 0x1_01_01_04_0 { + cfgs.push("ossl111d"); + } } cfgs diff --git a/openssl-sys/build/expando.c b/openssl-sys/build/expando.c index 11fb04db0c7c6806749a98d4dd4d60c14c07e537..cd7456b4f04458066a53854bef0c45a8d51262bd 100644 --- a/openssl-sys/build/expando.c +++ b/openssl-sys/build/expando.c @@ -75,10 +75,18 @@ RUST_CONF_OPENSSL_NO_NEXTPROTONEG RUST_CONF_OPENSSL_NO_OCSP #endif +#ifdef OPENSSL_NO_OCB +RUST_CONF_OPENSSL_NO_OCB +#endif + #ifdef OPENSSL_NO_PSK RUST_CONF_OPENSSL_NO_PSK #endif +#ifdef OPENSSL_NO_RC4 +RUST_CONF_OPENSSL_NO_RC4 +#endif + #ifdef OPENSSL_NO_RFC3779 RUST_CONF_OPENSSL_NO_RFC3779 #endif @@ -103,6 +111,10 @@ RUST_CONF_OPENSSL_NO_SSL3_METHOD RUST_CONF_OPENSSL_NO_TLSEXT #endif +#ifdef OPENSSL_NO_SOCK +RUST_CONF_OPENSSL_NO_SOCK +#endif + #ifdef OPENSSL_NO_STDIO RUST_CONF_OPENSSL_NO_STDIO #endif diff --git a/openssl-sys/build/find_normal.rs b/openssl-sys/build/find_normal.rs index 791fc33985b337ecd7a816efa085f36f94d96461..4d461039c2883fcaf8bb7ca68addb9c3ea0d1d82 100644 --- a/openssl-sys/build/find_normal.rs +++ b/openssl-sys/build/find_normal.rs @@ -92,8 +92,8 @@ fn find_openssl_dir(target: &str) -> OsString { try_pkg_config(); try_vcpkg(); - // FreeBSD ships with OpenSSL but doesn't include a pkg-config file :( - if host == target && target.contains("freebsd") { + // FreeBSD and OpenBSD ship with Libre|OpenSSL but don't include a pkg-config file + if host == target && (target.contains("freebsd") || target.contains("openbsd")) { return OsString::from("/usr"); } @@ -198,13 +198,11 @@ fn try_pkg_config() { let target = env::var("TARGET").unwrap(); let host = env::var("HOST").unwrap(); - // If we're going to windows-gnu we can use pkg-config, but only so long as - // we're coming from a windows host. - // - // Otherwise if we're going to windows we probably can't use pkg-config. + // FIXME we really shouldn't be automatically enabling this if target.contains("windows-gnu") && host.contains("windows") { env::set_var("PKG_CONFIG_ALLOW_CROSS", "1"); - } else if target.contains("windows") { + } else if target.contains("windows-msvc") { + // MSVC targets use vcpkg instead. return; } @@ -232,8 +230,12 @@ fn try_pkg_config() { /// /// Note that if this succeeds then the function does not return as vcpkg /// should emit all of the cargo metadata that we need. -#[cfg(target_env = "msvc")] fn try_vcpkg() { + let target = env::var("TARGET").unwrap(); + if !target.contains("windows") { + return; + } + // vcpkg will not emit any metadata if it can not find libraries // appropriate for the target triple with the desired linkage. @@ -257,9 +259,6 @@ fn try_vcpkg() { process::exit(0); } -#[cfg(not(target_env = "msvc"))] -fn try_vcpkg() {} - 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 { diff --git a/openssl-sys/build/main.rs b/openssl-sys/build/main.rs index 3357518f55587255b9755632eda1562ef10e79be..21ccf3d0377e0dfaf61c51c71ba722e8c38db78a 100644 --- a/openssl-sys/build/main.rs +++ b/openssl-sys/build/main.rs @@ -1,17 +1,9 @@ -#![allow( - clippy::inconsistent_digit_grouping, - clippy::uninlined_format_args, - clippy::unusual_byte_groupings -)] - -extern crate autocfg; #[cfg(feature = "bindgen")] extern crate bindgen; extern crate cc; #[cfg(feature = "vendored")] extern crate openssl_src; extern crate pkg_config; -#[cfg(target_env = "msvc")] extern crate vcpkg; use std::collections::HashSet; @@ -74,8 +66,6 @@ fn check_ssl_kind() { } fn main() { - check_rustc_versions(); - check_ssl_kind(); let target = env::var("TARGET").unwrap(); @@ -134,15 +124,6 @@ fn main() { } } -fn check_rustc_versions() { - let cfg = autocfg::new(); - - if cfg.probe_rustc_version(1, 31) { - println!("cargo:rustc-cfg=const_fn"); - } -} - -#[allow(clippy::let_and_return)] fn postprocess(include_dirs: &[PathBuf]) -> Version { let version = validate_headers(include_dirs); @@ -157,7 +138,7 @@ fn postprocess(include_dirs: &[PathBuf]) -> Version { /// Validates the header files found in `include_dir` and then returns the /// version string of OpenSSL. -#[allow(clippy::manual_strip)] // we need to support pre-1.45.0 +#[allow(clippy::unusual_byte_groupings)] fn validate_headers(include_dirs: &[PathBuf]) -> Version { // This `*-sys` crate only works with OpenSSL 1.0.1, 1.0.2, 1.1.0, 1.1.1 and 3.0.0. // To correctly expose the right API from this crate, take a look at @@ -173,9 +154,7 @@ fn validate_headers(include_dirs: &[PathBuf]) -> Version { // account for compile differences and such. println!("cargo:rerun-if-changed=build/expando.c"); let mut gcc = cc::Build::new(); - for include_dir in include_dirs { - gcc.include(include_dir); - } + gcc.includes(include_dirs); let expanded = match gcc.file("build/expando.c").try_expand() { Ok(expanded) => expanded, Err(e) => { @@ -221,17 +200,14 @@ See rust-openssl documentation for more information: let libressl_prefix = "RUST_VERSION_LIBRESSL_"; let boringsl_prefix = "RUST_OPENSSL_IS_BORINGSSL"; let conf_prefix = "RUST_CONF_"; - if line.starts_with(openssl_prefix) { - let version = &line[openssl_prefix.len()..]; + if let Some(version) = line.strip_prefix(openssl_prefix) { openssl_version = Some(parse_version(version)); - } else if line.starts_with(new_openssl_prefix) { - let version = &line[new_openssl_prefix.len()..]; + } else if let Some(version) = line.strip_prefix(new_openssl_prefix) { openssl_version = Some(parse_new_version(version)); - } else if line.starts_with(libressl_prefix) { - let version = &line[libressl_prefix.len()..]; + } else if let Some(version) = line.strip_prefix(libressl_prefix) { libressl_version = Some(parse_version(version)); - } else if line.starts_with(conf_prefix) { - enabled.push(&line[conf_prefix.len()..]); + } else if let Some(conf) = line.strip_prefix(conf_prefix) { + enabled.push(conf); } else if line.starts_with(boringsl_prefix) { is_boringssl = true; } @@ -295,6 +271,8 @@ See rust-openssl documentation for more information: (3, 6, _) => ('3', '6', 'x'), (3, 7, 0) => ('3', '7', '0'), (3, 7, 1) => ('3', '7', '1'), + (3, 7, _) => ('3', '7', 'x'), + (3, 8, 0) => ('3', '8', '0'), _ => version_error(), }; @@ -337,7 +315,7 @@ fn version_error() -> ! { " This crate is only compatible with OpenSSL (version 1.0.1 through 1.1.1, or 3.0.0), or LibreSSL 2.5 -through 3.7.1, but a different version of OpenSSL was found. The build is now aborting +through 3.8.0, but a different version of OpenSSL was found. The build is now aborting due to this version mismatch. " @@ -345,18 +323,13 @@ due to this version mismatch. } // parses a string that looks like "0x100020cfL" -#[allow(deprecated)] // trim_right_matches is now trim_end_matches -#[allow(clippy::match_like_matches_macro)] // matches macro requires rust 1.42.0 fn parse_version(version: &str) -> u64 { // cut off the 0x prefix assert!(version.starts_with("0x")); let version = &version[2..]; // and the type specifier suffix - let version = version.trim_right_matches(|c: char| match c { - '0'..='9' | 'a'..='f' | 'A'..='F' => false, - _ => true, - }); + let version = version.trim_end_matches(|c: char| !c.is_ascii_hexdigit()); u64::from_str_radix(version, 16).unwrap() } diff --git a/openssl-sys/build/run_bindgen.rs b/openssl-sys/build/run_bindgen.rs index 0c127ae5c602a8f86aeefc40726b48382f081667..1eeaad225d83e88005c4efed4b9365ea62c6a36e 100644 --- a/openssl-sys/build/run_bindgen.rs +++ b/openssl-sys/build/run_bindgen.rs @@ -12,6 +12,7 @@ const INCLUDES: &str = " #include #include #include +#include #include #include #include @@ -54,6 +55,10 @@ const INCLUDES: &str = " #if OPENSSL_VERSION_NUMBER >= 0x30000000 #include #endif + +#if defined(LIBRESSL_VERSION_NUMBER) || defined(OPENSSL_IS_BORINGSSL) +#include +#endif "; #[cfg(feature = "bindgen")] @@ -109,12 +114,15 @@ pub fn run_boringssl(include_dirs: &[PathBuf]) { let mut builder = bindgen::builder() .rust_target(RustTarget::Stable_1_47) .ctypes_prefix("::libc") + .raw_line("use libc::*;") .derive_default(false) .enable_function_attribute_detection() - .size_t_is_usize(true) .default_macro_constant_type(MacroTypeVariation::Signed) .rustified_enum("point_conversion_form_t") .allowlist_file(".*/openssl/[^/]+\\.h") + .allowlist_recursively(false) + .blocklist_function("BIO_vsnprintf") + .blocklist_function("OPENSSL_vasprintf") .wrap_static_fns(true) .wrap_static_fns_path(out_dir.join("boring_static_wrapper").display().to_string()) .layout_tests(false) @@ -163,14 +171,19 @@ pub fn run_boringssl(include_dirs: &[PathBuf]) { bindgen_cmd .arg("-o") .arg(out_dir.join("bindgen.rs")) + // Must be a valid version from + // https://docs.rs/bindgen/latest/bindgen/enum.RustTarget.html .arg("--rust-target=1.47") .arg("--ctypes-prefix=::libc") + .arg("--raw-line=use libc::*;") .arg("--no-derive-default") .arg("--enable-function-attribute-detection") - .arg("--size_t-is-usize") .arg("--default-macro-constant-type=signed") .arg("--rustified-enum=point_conversion_form_t") .arg("--allowlist-file=.*/openssl/[^/]+\\.h") + .arg("--no-recursive-allowlist") + .arg("--blocklist-function=BIO_vsnprintf") + .arg("--blocklist-function=OPENSSL_vasprintf") .arg("--experimental") .arg("--wrap-static-fns") .arg("--wrap-static-fns-path") diff --git a/openssl-sys/src/err.rs b/openssl-sys/src/err.rs index 5e84e6208ad8e429b2cd2f6fa3398308a3c31464..4a6a2775e4b562973cc241bb9087fa9096a4b345 100644 --- a/openssl-sys/src/err.rs +++ b/openssl-sys/src/err.rs @@ -20,51 +20,47 @@ cfg_if! { pub const ERR_RFLAG_FATAL: c_ulong = 0x1 << ERR_RFLAGS_OFFSET; - const_fn! { - pub const fn ERR_SYSTEM_ERROR(errcode: c_ulong) -> bool { - errcode & ERR_SYSTEM_FLAG != 0 - } + pub const fn ERR_SYSTEM_ERROR(errcode: c_ulong) -> bool { + errcode & ERR_SYSTEM_FLAG != 0 + } - pub const fn ERR_GET_LIB(errcode: c_ulong) -> c_int { - // hacks since `if` isn't yet stable in const functions :( - ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | - (((errcode >> ERR_LIB_OFFSET) & ERR_LIB_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int - } + pub const fn ERR_GET_LIB(errcode: c_ulong) -> c_int { + // hacks since `if` isn't yet stable in const functions :( + ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | + (((errcode >> ERR_LIB_OFFSET) & ERR_LIB_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int + } - pub const fn ERR_GET_FUNC(_errcode: c_ulong) -> c_int { - 0 - } + pub const fn ERR_GET_FUNC(_errcode: c_ulong) -> c_int { + 0 + } - pub const fn ERR_GET_REASON(errcode: c_ulong) -> c_int { - // hacks since `if` isn't yet stable in const functions :( - ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | - ((errcode & ERR_REASON_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int - } + pub const fn ERR_GET_REASON(errcode: c_ulong) -> c_int { + // hacks since `if` isn't yet stable in const functions :( + ((ERR_LIB_SYS as c_ulong * (ERR_SYSTEM_ERROR(errcode) as c_ulong)) | + ((errcode & ERR_REASON_MASK) * (!ERR_SYSTEM_ERROR(errcode) as c_ulong))) as c_int + } - pub const fn ERR_PACK(lib: c_int, _func: c_int, reason: c_int) -> c_ulong { - ((lib as c_ulong & ERR_LIB_MASK) << ERR_LIB_OFFSET) | - (reason as c_ulong & ERR_REASON_MASK) - } + pub const fn ERR_PACK(lib: c_int, _func: c_int, reason: c_int) -> c_ulong { + ((lib as c_ulong & ERR_LIB_MASK) << ERR_LIB_OFFSET) | + (reason as c_ulong & ERR_REASON_MASK) } } else { - const_fn! { - pub const fn ERR_PACK(l: c_int, f: c_int, r: c_int) -> c_ulong { - ((l as c_ulong & 0x0FF) << 24) | - ((f as c_ulong & 0xFFF) << 12) | - (r as c_ulong & 0xFFF) - } + pub const fn ERR_PACK(l: c_int, f: c_int, r: c_int) -> c_ulong { + ((l as c_ulong & 0x0FF) << 24) | + ((f as c_ulong & 0xFFF) << 12) | + (r as c_ulong & 0xFFF) + } - pub const fn ERR_GET_LIB(l: c_ulong) -> c_int { - ((l >> 24) & 0x0FF) as c_int - } + pub const fn ERR_GET_LIB(l: c_ulong) -> c_int { + ((l >> 24) & 0x0FF) as c_int + } - pub const fn ERR_GET_FUNC(l: c_ulong) -> c_int { - ((l >> 12) & 0xFFF) as c_int - } + pub const fn ERR_GET_FUNC(l: c_ulong) -> c_int { + ((l >> 12) & 0xFFF) as c_int + } - pub const fn ERR_GET_REASON(l: c_ulong) -> c_int { - (l & 0xFFF) as c_int - } + pub const fn ERR_GET_REASON(l: c_ulong) -> c_int { + (l & 0xFFF) as c_int } } } diff --git a/openssl-sys/src/evp.rs b/openssl-sys/src/evp.rs index 69b49fbb0b7b359b5da31941b0b4520e4aa98075..d2ca215407f4923ba7c96bd173229b8f06894427 100644 --- a/openssl-sys/src/evp.rs +++ b/openssl-sys/src/evp.rs @@ -10,6 +10,8 @@ pub const EVP_PKEY_RSA: c_int = NID_rsaEncryption; pub const EVP_PKEY_DSA: c_int = NID_dsa; pub const EVP_PKEY_DH: c_int = NID_dhKeyAgreement; pub const EVP_PKEY_EC: c_int = NID_X9_62_id_ecPublicKey; +#[cfg(ossl111)] +pub const EVP_PKEY_SM2: c_int = NID_sm2; #[cfg(any(ossl111, libressl370))] pub const EVP_PKEY_X25519: c_int = NID_X25519; #[cfg(any(ossl111, libressl370))] @@ -20,9 +22,14 @@ pub const EVP_PKEY_X448: c_int = NID_X448; pub const EVP_PKEY_ED448: c_int = NID_ED448; pub const EVP_PKEY_HMAC: c_int = NID_hmac; pub const EVP_PKEY_CMAC: c_int = NID_cmac; +#[cfg(ossl111)] +pub const EVP_PKEY_POLY1305: c_int = NID_poly1305; #[cfg(ossl110)] pub const EVP_PKEY_HKDF: c_int = NID_hkdf; +#[cfg(ossl102)] +pub const EVP_CIPHER_CTX_FLAG_WRAP_ALLOW: c_int = 0x1; + pub const EVP_CTRL_GCM_SET_IVLEN: c_int = 0x9; pub const EVP_CTRL_GCM_GET_TAG: c_int = 0x10; pub const EVP_CTRL_GCM_SET_TAG: c_int = 0x11; @@ -182,6 +189,8 @@ pub const EVP_PKEY_OP_TYPE_SIG: c_int = EVP_PKEY_OP_SIGN pub const EVP_PKEY_OP_TYPE_CRYPT: c_int = EVP_PKEY_OP_ENCRYPT | EVP_PKEY_OP_DECRYPT; +pub const EVP_PKEY_CTRL_MD: c_int = 1; + pub const EVP_PKEY_CTRL_SET_MAC_KEY: c_int = 6; pub const EVP_PKEY_CTRL_CIPHER: c_int = 12; @@ -283,3 +292,31 @@ pub unsafe fn EVP_PKEY_CTX_add1_hkdf_info( info as *mut c_void, ) } + +#[cfg(all(not(ossl300), not(boringssl)))] +pub unsafe fn EVP_PKEY_CTX_set_signature_md(cxt: *mut EVP_PKEY_CTX, md: *mut EVP_MD) -> c_int { + EVP_PKEY_CTX_ctrl( + cxt, + -1, + EVP_PKEY_OP_TYPE_SIG, + EVP_PKEY_CTRL_MD, + 0, + md as *mut c_void, + ) +} + +pub unsafe fn EVP_PKEY_assign_RSA(pkey: *mut EVP_PKEY, rsa: *mut RSA) -> c_int { + EVP_PKEY_assign(pkey, EVP_PKEY_RSA, rsa as *mut c_void) +} + +pub unsafe fn EVP_PKEY_assign_DSA(pkey: *mut EVP_PKEY, dsa: *mut DSA) -> c_int { + EVP_PKEY_assign(pkey, EVP_PKEY_DSA, dsa as *mut c_void) +} + +pub unsafe fn EVP_PKEY_assign_DH(pkey: *mut EVP_PKEY, dh: *mut DH) -> c_int { + EVP_PKEY_assign(pkey, EVP_PKEY_DH, dh as *mut c_void) +} + +pub unsafe fn EVP_PKEY_assign_EC_KEY(pkey: *mut EVP_PKEY, ec_key: *mut EC_KEY) -> c_int { + EVP_PKEY_assign(pkey, EVP_PKEY_EC, ec_key as *mut c_void) +} diff --git a/openssl-sys/src/handwritten/asn1.rs b/openssl-sys/src/handwritten/asn1.rs index 7163a69d5e04b0795d8e678e5b745638ada8fa18..16ffcccfe7b23c15d335daef4f1e6a98b3ac9441 100644 --- a/openssl-sys/src/handwritten/asn1.rs +++ b/openssl-sys/src/handwritten/asn1.rs @@ -10,23 +10,60 @@ pub struct ASN1_ENCODING { extern "C" { pub fn ASN1_OBJECT_free(x: *mut ASN1_OBJECT); + pub fn OBJ_dup(x: *const ASN1_OBJECT) -> *mut ASN1_OBJECT; } stack!(stack_st_ASN1_OBJECT); +#[repr(C)] +pub struct ASN1_TYPE { + pub type_: c_int, + pub value: ASN1_TYPE_value, +} +#[repr(C)] +pub union ASN1_TYPE_value { + pub ptr: *mut c_char, + pub boolean: ASN1_BOOLEAN, + pub asn1_string: *mut ASN1_STRING, + pub object: *mut ASN1_OBJECT, + pub integer: *mut ASN1_INTEGER, + pub enumerated: *mut ASN1_ENUMERATED, + pub bit_string: *mut ASN1_BIT_STRING, + pub octet_string: *mut ASN1_OCTET_STRING, + pub printablestring: *mut ASN1_PRINTABLESTRING, + pub t61string: *mut ASN1_T61STRING, + pub ia5string: *mut ASN1_IA5STRING, + pub generalstring: *mut ASN1_GENERALSTRING, + pub bmpstring: *mut ASN1_BMPSTRING, + pub universalstring: *mut ASN1_UNIVERSALSTRING, + pub utctime: *mut ASN1_UTCTIME, + pub generalizedtime: *mut ASN1_GENERALIZEDTIME, + pub visiblestring: *mut ASN1_VISIBLESTRING, + pub utf8string: *mut ASN1_UTF8STRING, + pub set: *mut ASN1_STRING, + pub sequence: *mut ASN1_STRING, + pub asn1_value: *mut ASN1_VALUE, +} + extern "C" { pub fn ASN1_STRING_type_new(ty: c_int) -> *mut ASN1_STRING; #[cfg(any(ossl110, libressl273))] pub fn ASN1_STRING_get0_data(x: *const ASN1_STRING) -> *const c_uchar; #[cfg(any(all(ossl101, not(ossl110)), libressl))] pub fn ASN1_STRING_data(x: *mut ASN1_STRING) -> *mut c_uchar; - - pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); - + pub fn ASN1_STRING_new() -> *mut ASN1_STRING; + pub fn ASN1_OCTET_STRING_new() -> *mut ASN1_OCTET_STRING; pub fn ASN1_STRING_free(x: *mut ASN1_STRING); pub fn ASN1_STRING_length(x: *const ASN1_STRING) -> c_int; + pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len_in: c_int) -> c_int; + pub fn ASN1_OCTET_STRING_set( + x: *mut ASN1_OCTET_STRING, + data: *const c_uchar, + len_in: c_int, + ) -> c_int; - pub fn ASN1_STRING_set(x: *mut ASN1_STRING, data: *const c_void, len: c_int) -> c_int; + pub fn ASN1_BIT_STRING_free(x: *mut ASN1_BIT_STRING); + pub fn ASN1_OCTET_STRING_free(x: *mut ASN1_OCTET_STRING); pub fn ASN1_GENERALIZEDTIME_free(tm: *mut ASN1_GENERALIZEDTIME); pub fn ASN1_GENERALIZEDTIME_print(b: *mut BIO, tm: *const ASN1_GENERALIZEDTIME) -> c_int; @@ -43,18 +80,36 @@ extern "C" { pub fn ASN1_TIME_set(from: *mut ASN1_TIME, to: time_t) -> *mut ASN1_TIME; pub fn ASN1_INTEGER_free(x: *mut ASN1_INTEGER); + pub fn ASN1_INTEGER_dup(a: *const ASN1_INTEGER) -> *mut ASN1_INTEGER; pub fn ASN1_INTEGER_get(dest: *const ASN1_INTEGER) -> c_long; pub fn ASN1_INTEGER_set(dest: *mut ASN1_INTEGER, value: c_long) -> c_int; + pub fn ASN1_INTEGER_cmp(a: *const ASN1_INTEGER, b: *const ASN1_INTEGER) -> c_int; pub fn BN_to_ASN1_INTEGER(bn: *const BIGNUM, ai: *mut ASN1_INTEGER) -> *mut ASN1_INTEGER; pub fn ASN1_INTEGER_to_BN(ai: *const ASN1_INTEGER, bn: *mut BIGNUM) -> *mut BIGNUM; pub fn ASN1_TIME_set_string(s: *mut ASN1_TIME, str: *const c_char) -> c_int; #[cfg(ossl111)] pub fn ASN1_TIME_set_string_X509(s: *mut ASN1_TIME, str: *const c_char) -> c_int; + + pub fn ASN1_ENUMERATED_free(a: *mut ASN1_ENUMERATED); + #[cfg(ossl110)] + pub fn ASN1_ENUMERATED_get_int64(pr: *mut i64, a: *const ASN1_ENUMERATED) -> c_int; + + pub fn ASN1_TYPE_new() -> *mut ASN1_TYPE; + pub fn ASN1_TYPE_set(a: *mut ASN1_TYPE, type_: c_int, value: *mut c_void); + pub fn ASN1_TYPE_free(x: *mut ASN1_TYPE); + pub fn d2i_ASN1_TYPE( + k: *mut *mut ASN1_TYPE, + buf: *mut *const u8, + len: c_long, + ) -> *mut ASN1_TYPE; } const_ptr_api! { extern "C" { pub fn ASN1_STRING_to_UTF8(out: *mut *mut c_uchar, s: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + pub fn ASN1_STRING_type(x: #[const_ptr_if(any(ossl110, libressl280))] ASN1_STRING) -> c_int; + pub fn ASN1_generate_v3(str: #[const_ptr_if(any(ossl110, libressl280))] c_char, cnf: *mut X509V3_CTX) -> *mut ASN1_TYPE; + pub fn i2d_ASN1_TYPE(a: #[const_ptr_if(ossl300)] ASN1_TYPE, pp: *mut *mut c_uchar) -> c_int; } } diff --git a/openssl-sys/src/handwritten/bio.rs b/openssl-sys/src/handwritten/bio.rs index 7d975222510d465fb1e95ec6b5dc3dcae2432301..5f65ec5e5cf31f5a78ec8453a84ff64790b60cbd 100644 --- a/openssl-sys/src/handwritten/bio.rs +++ b/openssl-sys/src/handwritten/bio.rs @@ -58,6 +58,7 @@ const_ptr_api! { } extern "C" { + #[cfg(not(osslconf = "OPENSSL_NO_SOCK"))] pub fn BIO_new_socket(sock: c_int, close_flag: c_int) -> *mut BIO; #[cfg(any(ossl110, libressl273))] diff --git a/openssl-sys/src/handwritten/bn.rs b/openssl-sys/src/handwritten/bn.rs index 81348f692a0f1f8eb310a45178ae825c1ebe93de..fc42c139463bc4cd62c2b15f8c99c4e950591cc4 100644 --- a/openssl-sys/src/handwritten/bn.rs +++ b/openssl-sys/src/handwritten/bn.rs @@ -23,7 +23,7 @@ extern "C" { pub fn BN_clear_free(bn: *mut BIGNUM); pub fn BN_bin2bn(s: *const u8, size: c_int, ret: *mut BIGNUM) -> *mut BIGNUM; pub fn BN_bn2bin(a: *const BIGNUM, to: *mut u8) -> c_int; - #[cfg(ossl110)] + #[cfg(any(ossl110, libressl340))] pub fn BN_bn2binpad(a: *const BIGNUM, to: *mut u8, tolen: c_int) -> c_int; pub fn BN_sub(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; pub fn BN_add(r: *mut BIGNUM, a: *const BIGNUM, b: *const BIGNUM) -> c_int; @@ -32,6 +32,8 @@ extern "C" { pub fn BN_set_negative(bn: *mut BIGNUM, n: c_int); #[cfg(any(ossl110, libressl350))] pub fn BN_is_negative(b: *const BIGNUM) -> c_int; + #[cfg(any(ossl110, libressl350))] + pub fn BN_is_odd(b: *const BIGNUM) -> c_int; pub fn BN_div( dv: *mut BIGNUM, @@ -73,6 +75,13 @@ extern "C" { m: *const BIGNUM, ctx: *mut BN_CTX, ) -> c_int; + #[cfg(ossl110)] + pub fn BN_mod_sqrt( + ret: *mut BIGNUM, + a: *const BIGNUM, + p: *const BIGNUM, + ctx: *mut BN_CTX, + ) -> *mut BIGNUM; pub fn BN_mod_word(r: *const BIGNUM, w: BN_ULONG) -> BN_ULONG; pub fn BN_div_word(r: *mut BIGNUM, w: BN_ULONG) -> BN_ULONG; diff --git a/openssl-sys/src/handwritten/cmac.rs b/openssl-sys/src/handwritten/cmac.rs new file mode 100644 index 0000000000000000000000000000000000000000..e44094d21a6966f399e6d49d695afb322db8c08c --- /dev/null +++ b/openssl-sys/src/handwritten/cmac.rs @@ -0,0 +1,18 @@ +use libc::*; + +use super::super::*; + +extern "C" { + pub fn CMAC_CTX_new() -> *mut CMAC_CTX; + pub fn CMAC_CTX_free(ctx: *mut CMAC_CTX); + pub fn CMAC_Init( + ctx: *mut CMAC_CTX, + key: *const c_void, + len: size_t, + cipher: *const EVP_CIPHER, + impl_: *mut ENGINE, + ) -> c_int; + pub fn CMAC_Update(ctx: *mut CMAC_CTX, data: *const c_void, len: size_t) -> c_int; + pub fn CMAC_Final(ctx: *mut CMAC_CTX, out: *mut c_uchar, len: *mut size_t) -> c_int; + pub fn CMAC_CTX_copy(dst: *mut CMAC_CTX, src: *const CMAC_CTX) -> c_int; +} diff --git a/openssl-sys/src/handwritten/dh.rs b/openssl-sys/src/handwritten/dh.rs index a4de122eac78f127861927f9d97a0d4569a874dd..87a0817ce5ddea836b50d0057045aa5c02cee6b8 100644 --- a/openssl-sys/src/handwritten/dh.rs +++ b/openssl-sys/src/handwritten/dh.rs @@ -3,6 +3,7 @@ use super::super::*; extern "C" { pub fn DH_new() -> *mut DH; pub fn DH_free(dh: *mut DH); + pub fn DH_check(dh: *const DH, codes: *mut c_int) -> c_int; pub fn DH_generate_parameters( prime_len: c_int, diff --git a/openssl-sys/src/handwritten/ec.rs b/openssl-sys/src/handwritten/ec.rs index 6ee475f3277e2afc096227a2b1dececa268a0ba2..f199bc891cbb7da3cb370482a7dbeb597696131c 100644 --- a/openssl-sys/src/handwritten/ec.rs +++ b/openssl-sys/src/handwritten/ec.rs @@ -46,6 +46,8 @@ extern "C" { pub fn EC_GROUP_set_asn1_flag(key: *mut EC_GROUP, flag: c_int); + pub fn EC_GROUP_get_asn1_flag(group: *const EC_GROUP) -> c_int; + pub fn EC_GROUP_get_curve_GFp( group: *const EC_GROUP, p: *mut BIGNUM, @@ -99,7 +101,7 @@ extern "C" { pub fn EC_POINT_dup(p: *const EC_POINT, group: *const EC_GROUP) -> *mut EC_POINT; - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl350))] pub fn EC_POINT_get_affine_coordinates( group: *const EC_GROUP, p: *const EC_POINT, @@ -150,6 +152,20 @@ extern "C" { ctx: *mut BN_CTX, ) -> c_int; + pub fn EC_POINT_point2hex( + group: *const EC_GROUP, + p: *const EC_POINT, + form: point_conversion_form_t, + ctx: *mut BN_CTX, + ) -> *mut c_char; + + pub fn EC_POINT_hex2point( + group: *const EC_GROUP, + s: *const c_char, + p: *mut EC_POINT, + ctx: *mut BN_CTX, + ) -> *mut EC_POINT; + pub fn EC_POINT_add( group: *const EC_GROUP, r: *mut EC_POINT, diff --git a/openssl-sys/src/handwritten/evp.rs b/openssl-sys/src/handwritten/evp.rs index 1a05b7eae3f71eb238be76f917b0897a85bde799..7da92eeeb880ae81d5c0af88ce11e05eff5e7135 100644 --- a/openssl-sys/src/handwritten/evp.rs +++ b/openssl-sys/src/handwritten/evp.rs @@ -65,6 +65,14 @@ cfg_if! { } } +cfg_if! { + if #[cfg(ossl300)] { + extern "C" { + pub fn EVP_default_properties_is_fips_enabled(libctx: *mut OSSL_LIB_CTX) -> c_int; + } + } +} + extern "C" { pub fn EVP_DigestInit_ex(ctx: *mut EVP_MD_CTX, typ: *const EVP_MD, imple: *mut ENGINE) -> c_int; @@ -275,6 +283,7 @@ extern "C" { ptr: *mut c_void, ) -> c_int; pub fn EVP_CIPHER_CTX_rand_key(ctx: *mut EVP_CIPHER_CTX, key: *mut c_uchar) -> c_int; + pub fn EVP_CIPHER_CTX_set_flags(ctx: *mut EVP_CIPHER_CTX, flags: c_int); pub fn EVP_md_null() -> *const EVP_MD; pub fn EVP_md5() -> *const EVP_MD; @@ -303,6 +312,7 @@ extern "C" { pub fn EVP_des_ede3_cbc() -> *const EVP_CIPHER; pub fn EVP_des_ede3_cfb64() -> *const EVP_CIPHER; pub fn EVP_des_cbc() -> *const EVP_CIPHER; + #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn EVP_rc4() -> *const EVP_CIPHER; pub fn EVP_bf_ecb() -> *const EVP_CIPHER; pub fn EVP_bf_cbc() -> *const EVP_CIPHER; @@ -320,6 +330,10 @@ extern "C" { pub fn EVP_aes_128_ofb() -> *const EVP_CIPHER; #[cfg(ossl110)] pub fn EVP_aes_128_ocb() -> *const EVP_CIPHER; + #[cfg(ossl102)] + pub fn EVP_aes_128_wrap() -> *const EVP_CIPHER; + #[cfg(ossl110)] + pub fn EVP_aes_128_wrap_pad() -> *const EVP_CIPHER; pub fn EVP_aes_192_ecb() -> *const EVP_CIPHER; pub fn EVP_aes_192_cbc() -> *const EVP_CIPHER; pub fn EVP_aes_192_cfb1() -> *const EVP_CIPHER; @@ -331,6 +345,10 @@ extern "C" { pub fn EVP_aes_192_ofb() -> *const EVP_CIPHER; #[cfg(ossl110)] pub fn EVP_aes_192_ocb() -> *const EVP_CIPHER; + #[cfg(ossl102)] + pub fn EVP_aes_192_wrap() -> *const EVP_CIPHER; + #[cfg(ossl110)] + pub fn EVP_aes_192_wrap_pad() -> *const EVP_CIPHER; pub fn EVP_aes_256_ecb() -> *const EVP_CIPHER; pub fn EVP_aes_256_cbc() -> *const EVP_CIPHER; pub fn EVP_aes_256_cfb1() -> *const EVP_CIPHER; @@ -343,6 +361,10 @@ extern "C" { pub fn EVP_aes_256_ofb() -> *const EVP_CIPHER; #[cfg(ossl110)] pub fn EVP_aes_256_ocb() -> *const EVP_CIPHER; + #[cfg(ossl102)] + pub fn EVP_aes_256_wrap() -> *const EVP_CIPHER; + #[cfg(ossl110)] + pub fn EVP_aes_256_wrap_pad() -> *const EVP_CIPHER; #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] pub fn EVP_chacha20() -> *const EVP_CIPHER; #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_CHACHA")))] @@ -404,22 +426,6 @@ cfg_if! { pub fn EVP_PKEY_get_bits(key: *const EVP_PKEY) -> c_int; pub fn EVP_PKEY_get_security_bits(key: *const EVP_PKEY) -> c_int; } - - #[inline] - pub unsafe fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int { - EVP_PKEY_get_id(pkey) - } - - #[inline] - pub unsafe fn EVP_PKEY_bits(pkey: *const EVP_PKEY) -> c_int { - EVP_PKEY_get_bits(pkey) - } - - #[inline] - pub unsafe fn EVP_PKEY_security_bits(pkey: *const EVP_PKEY) -> c_int { - EVP_PKEY_get_security_bits(pkey) - } - } else { extern "C" { pub fn EVP_PKEY_id(pkey: *const EVP_PKEY) -> c_int; @@ -504,6 +510,9 @@ extern "C" { p2: *mut c_void, ) -> c_int; + #[cfg(ossl300)] + pub fn EVP_PKEY_CTX_set_signature_md(ctx: *mut EVP_PKEY_CTX, md: *const EVP_MD) -> c_int; + pub fn EVP_PKEY_new_mac_key( type_: c_int, e: *mut ENGINE, @@ -513,6 +522,12 @@ extern "C" { pub fn EVP_PKEY_derive_init(ctx: *mut EVP_PKEY_CTX) -> c_int; pub fn EVP_PKEY_derive_set_peer(ctx: *mut EVP_PKEY_CTX, peer: *mut EVP_PKEY) -> c_int; + #[cfg(ossl300)] + pub fn EVP_PKEY_derive_set_peer_ex( + ctx: *mut EVP_PKEY_CTX, + peer: *mut EVP_PKEY, + validate_peer: c_int, + ) -> c_int; pub fn EVP_PKEY_derive(ctx: *mut EVP_PKEY_CTX, key: *mut c_uchar, size: *mut size_t) -> c_int; #[cfg(ossl300)] @@ -557,6 +572,14 @@ extern "C" { pin: *const c_uchar, pinlen: size_t, ) -> c_int; + pub fn EVP_PKEY_verify_recover_init(ctx: *mut EVP_PKEY_CTX) -> c_int; + pub fn EVP_PKEY_verify_recover( + ctx: *mut EVP_PKEY_CTX, + rout: *mut c_uchar, + routlen: *mut size_t, + sig: *const c_uchar, + siglen: size_t, + ) -> c_int; } const_ptr_api! { diff --git a/openssl-sys/src/handwritten/mod.rs b/openssl-sys/src/handwritten/mod.rs index 28aa4aecd08661ae1a325de4f1f1952abf8f5c13..d3adfa5a13df601cea526e3be3fe8fb5766a6636 100644 --- a/openssl-sys/src/handwritten/mod.rs +++ b/openssl-sys/src/handwritten/mod.rs @@ -2,6 +2,7 @@ pub use self::aes::*; pub use self::asn1::*; pub use self::bio::*; pub use self::bn::*; +pub use self::cmac::*; pub use self::cms::*; pub use self::conf::*; pub use self::crypto::*; @@ -17,6 +18,8 @@ pub use self::ocsp::*; pub use self::pem::*; pub use self::pkcs12::*; pub use self::pkcs7::*; +#[cfg(libressl)] +pub use self::poly1305::*; pub use self::provider::*; pub use self::rand::*; pub use self::rsa::*; @@ -35,6 +38,7 @@ mod aes; mod asn1; mod bio; mod bn; +mod cmac; mod cms; mod conf; mod crypto; @@ -50,6 +54,8 @@ mod ocsp; mod pem; mod pkcs12; mod pkcs7; +#[cfg(libressl)] +mod poly1305; mod provider; mod rand; mod rsa; diff --git a/openssl-sys/src/handwritten/object.rs b/openssl-sys/src/handwritten/object.rs index 06e6553433ed602c18e750ec760152f2e88f1296..6160fad5b3a16c1705220d92991056ff1e498b97 100644 --- a/openssl-sys/src/handwritten/object.rs +++ b/openssl-sys/src/handwritten/object.rs @@ -27,4 +27,5 @@ extern "C" { pub fn OBJ_length(obj: *const ASN1_OBJECT) -> libc::size_t; #[cfg(ossl111)] pub fn OBJ_get0_data(obj: *const ASN1_OBJECT) -> *const c_uchar; + pub fn OBJ_cmp(a: *const ASN1_OBJECT, b: *const ASN1_OBJECT) -> c_int; } diff --git a/openssl-sys/src/handwritten/pkcs7.rs b/openssl-sys/src/handwritten/pkcs7.rs index 78f96ec3e30ef1dfdea0efbe1627b47cc23d0e24..f46922df335beeec69cbbd765f4318436da02c99 100644 --- a/openssl-sys/src/handwritten/pkcs7.rs +++ b/openssl-sys/src/handwritten/pkcs7.rs @@ -1,12 +1,149 @@ use super::super::*; use libc::*; -pub enum PKCS7_SIGNED {} -pub enum PKCS7_ENVELOPE {} -pub enum PKCS7_SIGN_ENVELOPE {} -pub enum PKCS7_DIGEST {} -pub enum PKCS7_ENCRYPT {} -pub enum PKCS7 {} +#[cfg(ossl300)] +#[repr(C)] +pub struct PKCS7_CTX { + libctx: *mut OSSL_LIB_CTX, + propq: *mut c_char, +} + +#[repr(C)] +pub struct PKCS7_SIGNED { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub contents: *mut PKCS7, +} +#[repr(C)] +pub struct PKCS7_ENC_CONTENT { + pub content_type: *mut ASN1_OBJECT, + pub algorithm: *mut X509_ALGOR, + pub enc_data: *mut ASN1_OCTET_STRING, /* [ 0 ] */ + pub cipher: *const EVP_CIPHER, + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, +} +#[repr(C)] +pub struct PKCS7_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, +} +#[repr(C)] +pub struct PKCS7_SIGN_ENVELOPE { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub md_algs: *mut stack_st_X509_ALGOR, /* md used */ + pub cert: *mut stack_st_X509, /* [ 0 ] */ + pub crl: *mut stack_st_X509_CRL, /* [ 1 ] */ + pub signer_info: *mut stack_st_PKCS7_SIGNER_INFO, + pub enc_data: *mut PKCS7_ENC_CONTENT, + pub recipientinfo: *mut stack_st_PKCS7_RECIP_INFO, +} +#[repr(C)] +pub struct PKCS7_DIGEST { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub md: *mut X509_ALGOR, /* md used */ + pub contents: *mut PKCS7, + pub digest: *mut ASN1_OCTET_STRING, +} +#[repr(C)] +pub struct PKCS7_ENCRYPT { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub enc_data: *mut PKCS7_ENC_CONTENT, +} + +extern "C" { + pub fn PKCS7_SIGNED_free(info: *mut PKCS7_SIGNED); + pub fn PKCS7_ENC_CONTENT_free(info: *mut PKCS7_ENC_CONTENT); + pub fn PKCS7_ENVELOPE_free(info: *mut PKCS7_ENVELOPE); + pub fn PKCS7_SIGN_ENVELOPE_free(info: *mut PKCS7_SIGN_ENVELOPE); + pub fn PKCS7_DIGEST_free(info: *mut PKCS7_DIGEST); + pub fn PKCS7_SIGNER_INFO_free(info: *mut PKCS7_SIGNER_INFO); + pub fn PKCS7_ENCRYPT_free(enc: *mut PKCS7_ENCRYPT); + pub fn PKCS7_ISSUER_AND_SERIAL_free(ias: *mut PKCS7_ISSUER_AND_SERIAL); + pub fn PKCS7_RECIP_INFO_free(info: *mut PKCS7_RECIP_INFO); +} + +#[repr(C)] +pub struct PKCS7 { + /* + * The following is non NULL if it contains ASN1 encoding of this + * structure + */ + pub asn1: *mut c_uchar, + pub length: c_long, + // # define PKCS7_S_HEADER 0 + // # define PKCS7_S_BODY 1 + // # define PKCS7_S_TAIL 2 + pub state: c_int, /* used during processing */ + pub detached: c_int, + pub type_: *mut ASN1_OBJECT, + /* content as defined by the type */ + /* + * all encryption/message digests are applied to the 'contents', leaving + * out the 'type' field. + */ + pub d: PKCS7_data, + #[cfg(ossl300)] + pub ctx: PKCS7_CTX, +} + +#[repr(C)] +pub union PKCS7_data { + pub ptr: *mut c_char, + /* NID_pkcs7_data */ + pub data: *mut ASN1_OCTET_STRING, + /* NID_pkcs7_signed */ + pub sign: *mut PKCS7_SIGNED, + /* NID_pkcs7_enveloped */ + pub enveloped: *mut PKCS7_ENVELOPE, + /* NID_pkcs7_signedAndEnveloped */ + pub signed_and_enveloped: *mut PKCS7_SIGN_ENVELOPE, + /* NID_pkcs7_digest */ + pub digest: *mut PKCS7_DIGEST, + /* NID_pkcs7_encrypted */ + pub encrypted: *mut PKCS7_ENCRYPT, + /* Anything else */ + pub other: *mut ASN1_TYPE, +} + +#[repr(C)] +pub struct PKCS7_ISSUER_AND_SERIAL { + pub issuer: *mut X509_NAME, + pub serial: *mut ASN1_INTEGER, +} + +#[repr(C)] +pub struct PKCS7_SIGNER_INFO { + pub version: *mut ASN1_INTEGER, /* version 1 */ + pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, + pub digest_alg: *mut X509_ALGOR, + pub auth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 0 ] */ + pub digest_enc_alg: *mut X509_ALGOR, + pub enc_digest: *mut ASN1_OCTET_STRING, + pub unauth_attr: *mut stack_st_X509_ATTRIBUTE, /* [ 1 ] */ + pub pkey: *mut EVP_PKEY, /* The private key to sign with */ + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, +} + +stack!(stack_st_PKCS7_SIGNER_INFO); + +#[repr(C)] +pub struct PKCS7_RECIP_INFO { + pub version: *mut ASN1_INTEGER, /* version 0 */ + pub issuer_and_serial: *mut PKCS7_ISSUER_AND_SERIAL, + pub key_enc_algor: *mut X509_ALGOR, + pub enc_key: *mut ASN1_OCTET_STRING, + pub cert: *mut X509, /* get the pub-key from this */ + #[cfg(ossl300)] + pub ctx: *const PKCS7_CTX, +} + +stack!(stack_st_PKCS7_RECIP_INFO); extern "C" { pub fn d2i_PKCS7(a: *mut *mut PKCS7, pp: *mut *const c_uchar, length: c_long) -> *mut PKCS7; @@ -15,6 +152,7 @@ extern "C" { const_ptr_api! { extern "C" { pub fn i2d_PKCS7(a: #[const_ptr_if(ossl300)] PKCS7, buf: *mut *mut u8) -> c_int; + pub fn i2d_PKCS7_bio(bio: *mut BIO, p7: #[const_ptr_if(ossl300)] PKCS7) -> c_int; } } @@ -67,4 +205,53 @@ extern "C" { ) -> c_int; pub fn SMIME_read_PKCS7(bio: *mut BIO, bcont: *mut *mut BIO) -> *mut PKCS7; + + pub fn PKCS7_new() -> *mut PKCS7; + + pub fn PKCS7_set_type(p7: *mut PKCS7, nid_pkcs7: c_int) -> c_int; + + pub fn PKCS7_add_certificate(p7: *mut PKCS7, x509: *mut X509) -> c_int; + + pub fn PKCS7_add_signature( + p7: *mut PKCS7, + x509: *mut X509, + pkey: *mut EVP_PKEY, + digest: *const EVP_MD, + ) -> *mut PKCS7_SIGNER_INFO; + + pub fn PKCS7_set_signed_attributes( + p7si: *mut PKCS7_SIGNER_INFO, + attributes: *mut stack_st_X509_ATTRIBUTE, + ) -> c_int; + + pub fn PKCS7_add_signed_attribute( + p7si: *mut PKCS7_SIGNER_INFO, + nid: c_int, + attrtype: c_int, + data: *mut c_void, + ) -> c_int; + + pub fn PKCS7_content_new(p7: *mut PKCS7, nid_pkcs7: c_int) -> c_int; + + pub fn PKCS7_dataInit(p7: *mut PKCS7, bio: *mut BIO) -> *mut BIO; + + pub fn PKCS7_dataFinal(p7: *mut PKCS7, bio: *mut BIO) -> c_int; + + pub fn PKCS7_get_signer_info(p7: *mut PKCS7) -> *mut stack_st_PKCS7_SIGNER_INFO; + + pub fn PKCS7_SIGNER_INFO_get0_algs( + si: *mut PKCS7_SIGNER_INFO, + pk: *mut *mut EVP_PKEY, + pdig: *mut *mut X509_ALGOR, + psig: *mut *mut X509_ALGOR, + ); +} + +const_ptr_api! { + extern "C" { + pub fn PKCS7_get_signed_attribute( + si: #[const_ptr_if(ossl300)] PKCS7_SIGNER_INFO, + nid: c_int + ) -> *mut ASN1_TYPE; + } } diff --git a/openssl-sys/src/handwritten/poly1305.rs b/openssl-sys/src/handwritten/poly1305.rs new file mode 100644 index 0000000000000000000000000000000000000000..8ff22f3580d39733361af133b21cf1a7c80fae31 --- /dev/null +++ b/openssl-sys/src/handwritten/poly1305.rs @@ -0,0 +1,23 @@ +use super::super::*; +use libc::*; + +cfg_if! { + if #[cfg(libressl)] { + #[repr(C)] + #[derive(Debug, Copy, Clone)] + pub struct poly1305_context { + pub aligner: usize, + pub opaque: [::libc::c_uchar; 136usize], + } + pub type poly1305_state = poly1305_context; + extern "C" { + pub fn CRYPTO_poly1305_init(ctx: *mut poly1305_context, key: *const ::libc::c_uchar); + pub fn CRYPTO_poly1305_update( + ctx: *mut poly1305_context, + in_: *const ::libc::c_uchar, + len: usize, + ); + pub fn CRYPTO_poly1305_finish(ctx: *mut poly1305_context, mac: *mut ::libc::c_uchar); + } + } +} diff --git a/openssl-sys/src/handwritten/ssl.rs b/openssl-sys/src/handwritten/ssl.rs index f179a04ab11535c4e636406b813511e785e411c4..d4f4b619f4747241ce178f7a1278aa97c75dbddd 100644 --- a/openssl-sys/src/handwritten/ssl.rs +++ b/openssl-sys/src/handwritten/ssl.rs @@ -648,6 +648,15 @@ extern "C" { num: size_t, readbytes: *mut size_t, ) -> c_int; + #[cfg(ossl111)] + pub fn SSL_bytes_to_cipher_list( + s: *mut SSL, + bytes: *const c_uchar, + len: size_t, + isv2format: c_int, + sk: *mut *mut stack_st_SSL_CIPHER, + scsvs: *mut *mut stack_st_SSL_CIPHER, + ) -> c_int; } extern "C" { @@ -905,9 +914,13 @@ extern "C" { #[cfg(ossl111)] pub fn SSL_set_num_tickets(s: *mut SSL, num_tickets: size_t) -> c_int; - #[cfg(ossl111)] + #[cfg(ossl111b)] pub fn SSL_CTX_get_num_tickets(ctx: *const SSL_CTX) -> size_t; + #[cfg(all(ossl111, not(ossl111b)))] + pub fn SSL_CTX_get_num_tickets(ctx: *mut SSL_CTX) -> size_t; - #[cfg(ossl111)] + #[cfg(ossl111b)] pub fn SSL_get_num_tickets(s: *const SSL) -> size_t; + #[cfg(all(ossl111, not(ossl111b)))] + pub fn SSL_get_num_tickets(s: *mut SSL) -> size_t; } diff --git a/openssl-sys/src/handwritten/types.rs b/openssl-sys/src/handwritten/types.rs index b229a37597704a43937cb07e4a142afe16908071..06354728f2228c65667f7c33f1e53356cd8a7e79 100644 --- a/openssl-sys/src/handwritten/types.rs +++ b/openssl-sys/src/handwritten/types.rs @@ -3,14 +3,27 @@ use libc::*; #[allow(unused_imports)] use super::super::*; +pub enum ASN1_OBJECT {} +pub enum ASN1_VALUE {} + +pub type ASN1_BOOLEAN = c_int; pub enum ASN1_INTEGER {} +pub enum ASN1_ENUMERATED {} pub enum ASN1_GENERALIZEDTIME {} pub enum ASN1_STRING {} pub enum ASN1_BIT_STRING {} pub enum ASN1_TIME {} -pub enum ASN1_TYPE {} -pub enum ASN1_OBJECT {} pub enum ASN1_OCTET_STRING {} +pub enum ASN1_NULL {} +pub enum ASN1_PRINTABLESTRING {} +pub enum ASN1_T61STRING {} +pub enum ASN1_IA5STRING {} +pub enum ASN1_GENERALSTRING {} +pub enum ASN1_BMPSTRING {} +pub enum ASN1_UNIVERSALSTRING {} +pub enum ASN1_UTCTIME {} +pub enum ASN1_VISIBLESTRING {} +pub enum ASN1_UTF8STRING {} pub enum bio_st {} // FIXME remove cfg_if! { @@ -112,6 +125,8 @@ pub enum EVP_PKEY_ASN1_METHOD {} pub enum EVP_PKEY_CTX {} +pub enum CMAC_CTX {} + cfg_if! { if #[cfg(any(ossl110, libressl280))] { pub enum HMAC_CTX {} @@ -325,6 +340,8 @@ cfg_if! { } } +stack!(stack_st_X509_ALGOR); + pub enum X509_LOOKUP_METHOD {} pub enum X509_NAME {} diff --git a/openssl-sys/src/handwritten/x509.rs b/openssl-sys/src/handwritten/x509.rs index 9e6e861dadd2139c7e9904fa08e07f1ad6f3f793..f5e3c2428920d698ed329ee5afb75b608e49e10c 100644 --- a/openssl-sys/src/handwritten/x509.rs +++ b/openssl-sys/src/handwritten/x509.rs @@ -9,12 +9,16 @@ pub struct X509_VAL { pub enum X509_NAME_ENTRY {} +stack!(stack_st_X509_NAME_ENTRY); + stack!(stack_st_X509_NAME); pub enum X509_EXTENSION {} stack!(stack_st_X509_EXTENSION); +pub enum X509_ATTRIBUTE {} + stack!(stack_st_X509_ATTRIBUTE); cfg_if! { @@ -274,6 +278,7 @@ extern "C" { pub fn X509_NAME_ENTRY_free(x: *mut X509_NAME_ENTRY); pub fn X509_NAME_new() -> *mut X509_NAME; + pub fn X509_NAME_cmp(x: *const X509_NAME, y: *const X509_NAME) -> c_int; pub fn X509_NAME_free(x: *mut X509_NAME); pub fn X509_new() -> *mut X509; @@ -359,6 +364,33 @@ const_ptr_api! { -> c_int; } } +extern "C" { + pub fn X509_REQ_get_attr_count(req: *const X509_REQ) -> c_int; + pub fn X509_REQ_get_attr_by_NID(req: *const X509_REQ, nid: c_int, lastpos: c_int) -> c_int; + pub fn X509_REQ_get_attr(req: *const X509_REQ, loc: c_int) -> *mut X509_ATTRIBUTE; + pub fn X509_REQ_delete_attr(req: *mut X509_REQ, loc: c_int) -> *mut X509_ATTRIBUTE; + pub fn X509_REQ_add1_attr_by_txt( + req: *mut X509_REQ, + attrname: *const c_char, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; + pub fn X509_REQ_add1_attr_by_NID( + req: *mut X509_REQ, + nid: c_int, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; + pub fn X509_REQ_add1_attr_by_OBJ( + req: *mut X509_REQ, + obj: *const ASN1_OBJECT, + chtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> c_int; +} extern "C" { pub fn X509_set_pubkey(x: *mut X509, pkey: *mut EVP_PKEY) -> c_int; pub fn X509_REQ_verify(req: *mut X509_REQ, pkey: *mut EVP_PKEY) -> c_int; @@ -612,10 +644,9 @@ const_ptr_api! { extern "C" { #[cfg(any(ossl110, libressl270))] pub fn X509_STORE_get0_objects(ctx: #[const_ptr_if(ossl300)] X509_STORE) -> *mut stack_st_X509_OBJECT; - #[cfg(ossl300)] - pub fn X509_STORE_get1_all_certs(ctx: *mut X509_STORE) -> *mut stack_st_X509; } } + #[cfg(any(ossl110, libressl270))] extern "C" { pub fn X509_OBJECT_get0_X509(x: *const X509_OBJECT) -> *mut X509; @@ -642,7 +673,6 @@ extern "C" { extern "C" { pub fn X509_cmp(a: *const X509, b: *const X509) -> c_int; - pub fn X509_NAME_cmp(a: *const X509_NAME, b: *const X509_NAME) -> c_int; pub fn X509_issuer_and_serial_cmp(a: *const X509, b: *const X509) -> c_int; pub fn X509_issuer_name_cmp(a: *const X509, b: *const X509) -> c_int; pub fn X509_subject_name_cmp(a: *const X509, b: *const X509) -> c_int; @@ -670,6 +700,68 @@ pub struct X509_PURPOSE { const_ptr_api! { extern "C" { pub fn X509_PURPOSE_get_by_sname(sname: #[const_ptr_if(any(ossl110, libressl280))] c_char) -> c_int; - pub fn X509_PURPOSE_get0(idx: c_int) -> *mut X509_PURPOSE; + } +} +extern "C" { + pub fn X509_PURPOSE_get0(idx: c_int) -> *mut X509_PURPOSE; +} + +extern "C" { + pub fn X509_ATTRIBUTE_new() -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_free(attr: *mut X509_ATTRIBUTE); + pub fn X509_ATTRIBUTE_create( + nid: c_int, + atrtype: c_int, + value: *mut c_void, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_NID( + attr: *mut *mut X509_ATTRIBUTE, + nid: c_int, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_OBJ( + attr: *mut *mut X509_ATTRIBUTE, + obj: *const ASN1_OBJECT, + atrtype: c_int, + data: *const c_void, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_create_by_txt( + attr: *mut *mut X509_ATTRIBUTE, + atrname: *const c_char, + atrtype: c_int, + bytes: *const c_uchar, + len: c_int, + ) -> *mut X509_ATTRIBUTE; + pub fn X509_ATTRIBUTE_set1_object(attr: *mut X509_ATTRIBUTE, obj: *const ASN1_OBJECT) -> c_int; + pub fn X509_ATTRIBUTE_set1_data( + attr: *mut X509_ATTRIBUTE, + attrtype: c_int, + data: *const c_void, + len: c_int, + ) -> c_int; + pub fn X509_ATTRIBUTE_get0_data( + attr: *mut X509_ATTRIBUTE, + idx: c_int, + atrtype: c_int, + data: *mut c_void, + ) -> *mut c_void; + pub fn X509_ATTRIBUTE_get0_object(attr: *mut X509_ATTRIBUTE) -> *mut ASN1_OBJECT; + pub fn X509_ATTRIBUTE_get0_type(attr: *mut X509_ATTRIBUTE, idx: c_int) -> *mut ASN1_TYPE; + pub fn d2i_X509_ATTRIBUTE( + a: *mut *mut X509_ATTRIBUTE, + pp: *mut *const c_uchar, + length: c_long, + ) -> *mut X509_ATTRIBUTE; +} +const_ptr_api! { + extern "C" { + pub fn X509_ATTRIBUTE_count( + attr: #[const_ptr_if(any(ossl110, libressl280))] X509_ATTRIBUTE // const since OpenSSL v1.1.0 + ) -> c_int; + pub fn i2d_X509_ATTRIBUTE(x: #[const_ptr_if(ossl300)] X509_ATTRIBUTE, buf: *mut *mut u8) -> c_int; + pub fn X509_ATTRIBUTE_dup(x: #[const_ptr_if(ossl300)] X509_ATTRIBUTE) -> *mut X509_ATTRIBUTE; } } diff --git a/openssl-sys/src/handwritten/x509v3.rs b/openssl-sys/src/handwritten/x509v3.rs index 4f661ca5ec053e10f428ddad881da9cfe325d1ab..2ee0452597d26f6f2183ab530ee490430c84ffb0 100644 --- a/openssl-sys/src/handwritten/x509v3.rs +++ b/openssl-sys/src/handwritten/x509v3.rs @@ -6,6 +6,11 @@ pub enum CONF_METHOD {} extern "C" { pub fn GENERAL_NAME_new() -> *mut GENERAL_NAME; pub fn GENERAL_NAME_free(name: *mut GENERAL_NAME); + pub fn GENERAL_NAME_set0_othername( + gen: *mut GENERAL_NAME, + oid: *mut ASN1_OBJECT, + value: *mut ASN1_TYPE, + ) -> c_int; } #[repr(C)] @@ -96,10 +101,47 @@ extern "C" { indent: c_int, ) -> c_int; + #[cfg(ossl110)] + pub fn X509_get_pathlen(x: *mut X509) -> c_long; #[cfg(ossl110)] pub fn X509_get_extension_flags(x: *mut X509) -> u32; #[cfg(ossl110)] pub fn X509_get_key_usage(x: *mut X509) -> u32; #[cfg(ossl110)] pub fn X509_get_extended_key_usage(x: *mut X509) -> u32; + #[cfg(ossl110)] + pub fn X509_get0_subject_key_id(x: *mut X509) -> *const ASN1_OCTET_STRING; + #[cfg(ossl110)] + pub fn X509_get0_authority_key_id(x: *mut X509) -> *const ASN1_OCTET_STRING; + #[cfg(ossl111d)] + pub fn X509_get0_authority_issuer(x: *mut X509) -> *const stack_st_GENERAL_NAME; + #[cfg(ossl111d)] + pub fn X509_get0_authority_serial(x: *mut X509) -> *const ASN1_INTEGER; +} + +#[repr(C)] +pub struct DIST_POINT_NAME { + pub type_: c_int, + pub name: DIST_POINT_NAME_st_anon_union, + pub dpname: *mut X509_NAME, +} + +#[repr(C)] +pub union DIST_POINT_NAME_st_anon_union { + pub fullname: *mut stack_st_GENERAL_NAME, + pub relativename: *mut stack_st_X509_NAME_ENTRY, +} + +#[repr(C)] +pub struct DIST_POINT { + pub distpoint: *mut DIST_POINT_NAME, + pub reasons: *mut ASN1_BIT_STRING, + pub CRLissuer: *mut stack_st_GENERAL_NAME, + pub dp_reasons: c_int, +} +stack!(stack_st_DIST_POINT); + +extern "C" { + pub fn DIST_POINT_free(dist_point: *mut DIST_POINT); + pub fn DIST_POINT_NAME_free(dist_point: *mut DIST_POINT_NAME); } diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index c3084755cce60dd737377c4d2f756478e0a9e45c..784b7637e1368abe2745eff2b3c4fc52951ae213 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -1,15 +1,12 @@ #![allow( clippy::missing_safety_doc, - clippy::unreadable_literal, - clippy::uninlined_format_args, - clippy::upper_case_acronyms, dead_code, non_camel_case_types, non_snake_case, non_upper_case_globals, - overflowing_literals, unused_imports )] +#![cfg_attr(feature = "unstable_boringssl", allow(ambiguous_glob_reexports))] #![doc(html_root_url = "https://docs.rs/openssl-sys/0.9")] #![recursion_limit = "128"] // configure fixed limit across all rust versions diff --git a/openssl-sys/src/macros.rs b/openssl-sys/src/macros.rs index e1b08c467adf22f82e159bd6600c14d9b6c7ae77..96523db8f4b5cec3d206dcb18821929c41456a58 100644 --- a/openssl-sys/src/macros.rs +++ b/openssl-sys/src/macros.rs @@ -70,24 +70,6 @@ macro_rules! stack { }; } -#[cfg(const_fn)] -macro_rules! const_fn { - ($(pub const fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty $b:block)*) => { - $( - pub const fn $name($($arg: $t),*) -> $ret $b - )* - } -} - -#[cfg(not(const_fn))] -macro_rules! const_fn { - ($(pub const fn $name:ident($($arg:ident: $t:ty),*) -> $ret:ty $b:block)*) => { - $( - pub fn $name($($arg: $t),*) -> $ret $b - )* - } -} - // openssl changes `*mut` to `*const` in certain parameters in certain versions; // in C this is ABI and (mostly) API compatible. // diff --git a/openssl-sys/src/obj_mac.rs b/openssl-sys/src/obj_mac.rs index 1f8e10003ab0225e276fe9505cbd82fab3b1bb60..6ae48834b5194addb59bcace200aa6aaf8a6620b 100644 --- a/openssl-sys/src/obj_mac.rs +++ b/openssl-sys/src/obj_mac.rs @@ -927,12 +927,16 @@ pub const NID_X448: c_int = 1035; #[cfg(ossl110)] pub const NID_hkdf: c_int = 1036; #[cfg(ossl111)] +pub const NID_poly1305: c_int = 1061; +#[cfg(ossl111)] pub const NID_ED25519: c_int = 1087; #[cfg(libressl370)] pub const NID_ED25519: c_int = 952; #[cfg(ossl111)] pub const NID_ED448: c_int = 1088; #[cfg(ossl111)] +pub const NID_sm2: c_int = 1172; +#[cfg(ossl111)] pub const NID_sm3: c_int = 1143; #[cfg(libressl291)] pub const NID_sm3: c_int = 968; diff --git a/openssl-sys/src/tls1.rs b/openssl-sys/src/tls1.rs index f7ae302046b0f9a8fa72169ea185e9e6f4ac1108..2cb08a91f352868b9de2284b27b77333ce300a8d 100644 --- a/openssl-sys/src/tls1.rs +++ b/openssl-sys/src/tls1.rs @@ -10,6 +10,10 @@ pub const TLS1_2_VERSION: c_int = 0x303; #[cfg(any(ossl111, libressl340))] pub const TLS1_3_VERSION: c_int = 0x304; +pub const DTLS1_VERSION: c_int = 0xFEFF; +#[cfg(any(ossl102, libressl332))] +pub const DTLS1_2_VERSION: c_int = 0xFEFD; + pub const TLS1_AD_DECODE_ERROR: c_int = 50; pub const TLS1_AD_UNRECOGNIZED_NAME: c_int = 112; diff --git a/openssl-sys/src/x509v3.rs b/openssl-sys/src/x509v3.rs index 5ae44390838ce0ceec83c520a9615390c1aa94c7..d2ff53489e9a282b7c43ab03f117add988496715 100644 --- a/openssl-sys/src/x509v3.rs +++ b/openssl-sys/src/x509v3.rs @@ -91,3 +91,14 @@ pub const X509_PURPOSE_OCSP_HELPER: c_int = 8; pub const X509_PURPOSE_TIMESTAMP_SIGN: c_int = 9; pub const X509_PURPOSE_MIN: c_int = 1; pub const X509_PURPOSE_MAX: c_int = 9; + +pub const CRL_REASON_UNSPECIFIED: c_int = 0; +pub const CRL_REASON_KEY_COMPROMISE: c_int = 1; +pub const CRL_REASON_CA_COMPROMISE: c_int = 2; +pub const CRL_REASON_AFFILIATION_CHANGED: c_int = 3; +pub const CRL_REASON_SUPERSEDED: c_int = 4; +pub const CRL_REASON_CESSATION_OF_OPERATION: c_int = 5; +pub const CRL_REASON_CERTIFICATE_HOLD: c_int = 6; +pub const CRL_REASON_REMOVE_FROM_CRL: c_int = 8; +pub const CRL_REASON_PRIVILEGE_WITHDRAWN: c_int = 9; +pub const CRL_REASON_AA_COMPROMISE: c_int = 10; diff --git a/openssl/BUILD.gn b/openssl/BUILD.gn index 684ee8683aafde8f260ce4ea8e8be0d7c6465f9c..ec6f6487c5cae30b893427b222d48f4ba5fdbf19 100644 --- a/openssl/BUILD.gn +++ b/openssl/BUILD.gn @@ -20,7 +20,7 @@ ohos_cargo_crate("lib") { sources = [ "src/lib.rs" ] edition = "2018" - cargo_pkg_version = "0.10.47" + cargo_pkg_version = "0.10.56" cargo_pkg_authors = "Steven Fackler " cargo_pkg_name = "openssl" cargo_pkg_description = "OpenSSL bindings" diff --git a/openssl/CHANGELOG.md b/openssl/CHANGELOG.md index c6d9b303cd3b134f2aca008d4c0eb8b13a486208..b6bbbb9ce77d9659bdcb0b25134134597793ba41 100644 --- a/openssl/CHANGELOG.md +++ b/openssl/CHANGELOG.md @@ -2,6 +2,86 @@ ## [Unreleased] +## [v0.10.56] - 2023-08-06 + +## Added + +* Added `BigNumRef::mod_sqrt`. +* Added `PkeyCtxRef::set_signature_md` and `PkeyCtxRef::set_rsa_pss_saltlen`. +* Added `PkeyCtxRef::verify_recover_init` and `PkeyCtxRef::verify_recover`. +* Added `BigNumRef::is_even` and `BigNumRef::is_odd`. +* Added `EcPointRef::to_hex_str` and `EcPoint::from_hex_str`. +* Added support for AES key wrap and wrap pad. + +## [v0.10.55] - 2023-06-20 + +### Fixed + +* Fixed compilation with the latest version of BoringSSL. +* Fixed compilation when OpenSSL is compiled with `OPENSSL_NO_OCB`. +* Fixed a segfault in `X509VerifyParamRef::set_host` when called with an empty string. + +### Added + +* Added `Deriver::set_peer_ex`. +* Added `EcGroupRef::asn1_flag`. +* Exposed `EcPointRef::affine_coordinates` on BoringSSL and LibreSSL. +* Added `Nid::SM2` and `Id::SM2` + +## [v0.10.54] - 2023-05-31 + +### Fixed + +* `PKey::private_key_to_pkcs8_passphrase` no longer panics if a `passphrase` contains a NUL byte. + +## [v0.10.53] - 2023-05-30 + +### Added + +* Added `Dsa::from_pqg`, `Dsa::generate_key`, and `Dsa::generate_params`. +* Added `SslRef::bytes_to_cipher_list`. +* Added `SubjectAlternativeName::other_name2` + +## [v0.10.52] - 2023-04-24 + +### Added + +* Added `DhRef::check_key`. +* Added `Id::POLY1305`. +* Added `X509Ref::subject_key_id`, `X509Ref::authority_key_id`, `X509Ref::authority_issuer`, and `X509Ref::authority_serial`. + + +## [v0.10.51] - 2023-04-20 + +### Added + +* Added `X509RevokedRef::issuer_name` and `X509RevokedRef::reason_code`. +* Added `Dh::set_key` and `Dh::set_public_key` +* Added `Asn1OctetString` and `Asn1OctetStringRef1` +* Added `X509Extension::new_from_der` + +### Deprecated + +* Deprecated `X509Extension::new` and `X509Extension::new_nid` in favor of `X509Extension::new_from_der` and the `extensions` module. +* Deprecated `X509Extension::add_alias`, it is not required with `new_from_der` or the `extensions` module. + +## [v0.10.50] - 2023-04-09 + +### Added + +* Added `CipherCtxRef::cipher_update_inplace`. + +## [v0.10.49] - 2023-04-01 + +### Fixed + +* `SslConnector` no longer sets the SNI extension when connecting to an IP address. + +### Added + +* Implemented `Ord`, `PartialOrd`, `Eq`, and `PartialEq` for `Asn1Integer` and `Asn1IntegerRef`. +* Added `X509Ref::crl_distribution_points`, and `DistPoint`. + ## [v0.10.48] - 2023-03-23 ### Fixed @@ -707,7 +787,15 @@ Look at the [release tags] for information about older releases. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...master +[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.56...master +[v0.10.56]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.55...openssl-v0.10.56 +[v0.10.55]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.54...openssl-v0.10.55 +[v0.10.54]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.53...openssl-v0.10.54 +[v0.10.53]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.52...openssl-v0.10.53 +[v0.10.52]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.51...openssl-v0.10.52 +[v0.10.51]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.50...openssl-v0.10.51 +[v0.10.50]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.49...openssl-v0.10.50 +[v0.10.49]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...openssl-v0.10.49 [v0.10.48]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.47...openssl-v0.10.48 [v0.10.47]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.46...openssl-v0.10.47 [v0.10.46]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.45...openssl-v0.10.46 diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index e49bd9163e17c2fdf2cbedd697cabce148b21a90..17f82ca843ed77c8c238a9cad77747aef5d3d566 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.10.48" +version = "0.10.56" authors = ["Steven Fackler "] license = "Apache-2.0" description = "OpenSSL bindings" @@ -30,7 +30,7 @@ libc = "0.2" once_cell = "1.5.2" openssl-macros = { version = "0.1.0", path = "../openssl-macros" } -ffi = { package = "openssl-sys", version = "0.9.83", path = "../openssl-sys" } +ffi = { package = "openssl-sys", version = "0.9.91", path = "../openssl-sys" } [dev-dependencies] hex = "0.3" diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index c0178c7e65c39daf90be277b6dc9a6c700df81b6..801310d4117f12c5fc293f4053178d0cd4b91639 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -27,8 +27,8 @@ use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_long, time_t}; -#[cfg(ossl102)] use std::cmp::Ordering; +use std::convert::TryInto; use std::ffi::CString; use std::fmt; use std::ptr; @@ -512,6 +512,23 @@ impl Asn1Integer { } } +impl Ord for Asn1Integer { + fn cmp(&self, other: &Self) -> Ordering { + Asn1IntegerRef::cmp(self, other) + } +} +impl PartialOrd for Asn1Integer { + fn partial_cmp(&self, other: &Asn1Integer) -> Option { + Some(self.cmp(other)) + } +} +impl Eq for Asn1Integer {} +impl PartialEq for Asn1Integer { + fn eq(&self, other: &Asn1Integer) -> bool { + Asn1IntegerRef::eq(self, other) + } +} + impl Asn1IntegerRef { #[allow(missing_docs, clippy::unnecessary_cast)] #[deprecated(since = "0.10.6", note = "use to_bn instead")] @@ -536,6 +553,30 @@ impl Asn1IntegerRef { pub fn set(&mut self, value: i32) -> Result<(), ErrorStack> { unsafe { cvt(ffi::ASN1_INTEGER_set(self.as_ptr(), value as c_long)).map(|_| ()) } } + + /// Creates a new Asn1Integer with the same value. + #[corresponds(ASN1_INTEGER_dup)] + pub fn to_owned(&self) -> Result { + unsafe { cvt_p(ffi::ASN1_INTEGER_dup(self.as_ptr())).map(|p| Asn1Integer::from_ptr(p)) } + } +} + +impl Ord for Asn1IntegerRef { + fn cmp(&self, other: &Self) -> Ordering { + let res = unsafe { ffi::ASN1_INTEGER_cmp(self.as_ptr(), other.as_ptr()) }; + res.cmp(&0) + } +} +impl PartialOrd for Asn1IntegerRef { + fn partial_cmp(&self, other: &Asn1IntegerRef) -> Option { + Some(self.cmp(other)) + } +} +impl Eq for Asn1IntegerRef {} +impl PartialEq for Asn1IntegerRef { + fn eq(&self, other: &Asn1IntegerRef) -> bool { + self.cmp(other) == Ordering::Equal + } } foreign_type_and_impl_send_sync! { @@ -571,9 +612,50 @@ impl Asn1BitStringRef { } } +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_OCTET_STRING; + fn drop = ffi::ASN1_OCTET_STRING_free; + /// ASN.1 OCTET STRING type + pub struct Asn1OctetString; + /// A reference to an [`Asn1OctetString`]. + pub struct Asn1OctetStringRef; +} + +impl Asn1OctetString { + /// Creates an Asn1OctetString from bytes + pub fn new_from_bytes(value: &[u8]) -> Result { + ffi::init(); + unsafe { + let s = cvt_p(ffi::ASN1_OCTET_STRING_new())?; + ffi::ASN1_OCTET_STRING_set(s, value.as_ptr(), value.len().try_into().unwrap()); + Ok(Self::from_ptr(s)) + } + } +} + +impl Asn1OctetStringRef { + /// Returns the octet string as an array of bytes. + #[corresponds(ASN1_STRING_get0_data)] + pub fn as_slice(&self) -> &[u8] { + unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) } + } + + /// Returns the number of bytes in the octet string. + #[corresponds(ASN1_STRING_length)] + pub fn len(&self) -> usize { + unsafe { ffi::ASN1_STRING_length(self.as_ptr().cast()) as usize } + } + + /// Determines if the string is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::ASN1_OBJECT; fn drop = ffi::ASN1_OBJECT_free; + fn clone = ffi::OBJ_dup; /// Object Identifier /// @@ -656,7 +738,7 @@ impl fmt::Debug for Asn1ObjectRef { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::ASN1_STRING_get0_data; } else { #[allow(bad_style)] @@ -666,6 +748,32 @@ cfg_if! { } } +foreign_type_and_impl_send_sync! { + type CType = ffi::ASN1_ENUMERATED; + fn drop = ffi::ASN1_ENUMERATED_free; + + /// An ASN.1 enumerated. + pub struct Asn1Enumerated; + /// A reference to an [`Asn1Enumerated`]. + pub struct Asn1EnumeratedRef; +} + +impl Asn1EnumeratedRef { + /// Get the value, if it fits in the required bounds. + #[corresponds(ASN1_ENUMERATED_get_int64)] + #[cfg(ossl110)] + pub fn get_i64(&self) -> Result { + let mut crl_reason = 0; + unsafe { + cvt(ffi::ASN1_ENUMERATED_get_int64( + &mut crl_reason, + self.as_ptr(), + ))?; + } + Ok(crl_reason) + } +} + #[cfg(test)] mod tests { use super::*; @@ -749,6 +857,28 @@ mod tests { assert!(c_ref < a_ref); } + #[test] + fn integer_to_owned() { + let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); + let b = a.to_owned().unwrap(); + assert_eq!( + a.to_bn().unwrap().to_dec_str().unwrap().to_string(), + b.to_bn().unwrap().to_dec_str().unwrap().to_string(), + ); + assert_ne!(a.as_ptr(), b.as_ptr()); + } + + #[test] + fn integer_cmp() { + let a = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); + let b = Asn1Integer::from_bn(&BigNum::from_dec_str("42").unwrap()).unwrap(); + let c = Asn1Integer::from_bn(&BigNum::from_dec_str("43").unwrap()).unwrap(); + assert!(a == b); + assert!(a != c); + assert!(a < c); + assert!(c > b); + } + #[test] fn object_from_str() { let object = Asn1Object::from_str("2.16.840.1.101.3.4.2.1").unwrap(); @@ -771,4 +901,11 @@ mod tests { &[0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01], ); } + + #[test] + fn asn1_octet_string() { + let octet_string = Asn1OctetString::new_from_bytes(b"hello world").unwrap(); + assert_eq!(octet_string.as_slice(), b"hello world"); + assert_eq!(octet_string.len(), 11); + } } diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index 0328730a2334b194a9048245cf4bd4c0ee555b1f..c75fac1d7096e1e3fd3d1288e5e2900f6b48e729 100644 --- a/openssl/src/bn.rs +++ b/openssl/src/bn.rs @@ -335,6 +335,20 @@ impl BigNumRef { unsafe { BN_is_negative(self.as_ptr()) == 1 } } + /// Returns `true` is `self` is even. + #[corresponds(BN_is_even)] + #[cfg(any(ossl110, boringssl, libressl350))] + pub fn is_even(&self) -> bool { + !self.is_odd() + } + + /// Returns `true` is `self` is odd. + #[corresponds(BN_is_odd)] + #[cfg(any(ossl110, boringssl, libressl350))] + pub fn is_odd(&self) -> bool { + unsafe { ffi::BN_is_odd(self.as_ptr()) == 1 } + } + /// Returns the number of significant bits in `self`. #[corresponds(BN_num_bits)] #[allow(clippy::unnecessary_cast)] @@ -639,6 +653,26 @@ impl BigNumRef { } } + /// Places into `self` the modular square root of `a` such that `self^2 = a (mod p)` + #[corresponds(BN_mod_sqrt)] + #[cfg(ossl110)] + pub fn mod_sqrt( + &mut self, + a: &BigNumRef, + p: &BigNumRef, + ctx: &mut BigNumContextRef, + ) -> Result<(), ErrorStack> { + unsafe { + cvt_p(ffi::BN_mod_sqrt( + self.as_ptr(), + a.as_ptr(), + p.as_ptr(), + ctx.as_ptr(), + )) + .map(|_| ()) + } + } + /// Places the result of `a^p` in `self`. #[corresponds(BN_exp)] pub fn exp( @@ -814,7 +848,7 @@ impl BigNumRef { /// assert_eq!(&bn_vec, &[0, 0, 0x45, 0x43]); /// ``` #[corresponds(BN_bn2binpad)] - #[cfg(ossl110)] + #[cfg(any(ossl110, libressl340, boringssl))] pub fn to_vec_padded(&self, pad_to: i32) -> Result, ErrorStack> { let mut v = Vec::with_capacity(pad_to as usize); unsafe { @@ -1455,4 +1489,30 @@ mod tests { b.set_const_time(); assert!(b.is_const_time()) } + + #[cfg(ossl110)] + #[test] + fn test_mod_sqrt() { + let mut ctx = BigNumContext::new().unwrap(); + + let s = BigNum::from_hex_str("47A8DD7626B9908C80ACD7E0D3344D69").unwrap(); + let p = BigNum::from_hex_str("81EF47265B58BCE5").unwrap(); + let mut out = BigNum::new().unwrap(); + + out.mod_sqrt(&s, &p, &mut ctx).unwrap(); + assert_eq!(out, BigNum::from_hex_str("7C6D179E19B97BDD").unwrap()); + } + + #[test] + #[cfg(any(ossl110, boringssl, libressl350))] + fn test_odd_even() { + let a = BigNum::from_u32(17).unwrap(); + let b = BigNum::from_u32(18).unwrap(); + + assert!(a.is_odd()); + assert!(!b.is_odd()); + + assert!(!a.is_even()); + assert!(b.is_even()); + } } diff --git a/openssl/src/cipher.rs b/openssl/src/cipher.rs index aeedf459aaaf08abf1e109ab4610c995b9be5635..f81895e51350f2f887bcb6774a61167c7dfed113 100644 --- a/openssl/src/cipher.rs +++ b/openssl/src/cipher.rs @@ -12,6 +12,7 @@ use foreign_types::{ForeignTypeRef, Opaque}; use openssl_macros::corresponds; #[cfg(ossl300)] use std::ffi::CString; +use std::ops::{Deref, DerefMut}; #[cfg(ossl300)] use std::ptr; @@ -41,7 +42,6 @@ cfg_if! { cfg_if! { if #[cfg(ossl300)] { use foreign_types::ForeignType; - use std::ops::{Deref, DerefMut}; type Inner = *mut ffi::EVP_CIPHER; @@ -90,6 +90,22 @@ cfg_if! { } } else { enum Inner {} + + impl Deref for Cipher { + type Target = CipherRef; + + #[inline] + fn deref(&self) -> &Self::Target { + match self.0 {} + } + } + + impl DerefMut for Cipher { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + match self.0 {} + } + } } } @@ -170,7 +186,6 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_cfb8() as *mut _) } } - #[cfg(not(boringssl))] pub fn aes_128_gcm() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_gcm() as *mut _) } } @@ -191,6 +206,18 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_ocb() as *mut _) } } + /// Requires OpenSSL 1.0.2 or newer. + #[cfg(ossl102)] + pub fn aes_128_wrap() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_wrap() as *mut _) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_128_wrap_pad() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_128_wrap_pad() as *mut _) } + } + pub fn aes_192_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ecb() as *mut _) } } @@ -236,6 +263,18 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_ocb() as *mut _) } } + /// Requires OpenSSL 1.0.2 or newer. + #[cfg(ossl102)] + pub fn aes_192_wrap() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_wrap() as *mut _) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_192_wrap_pad() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_192_wrap_pad() as *mut _) } + } + pub fn aes_256_ecb() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ecb() as *mut _) } } @@ -281,6 +320,18 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_ocb() as *mut _) } } + /// Requires OpenSSL 1.0.2 or newer. + #[cfg(ossl102)] + pub fn aes_256_wrap() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_wrap() as *mut _) } + } + + /// Requires OpenSSL 1.1.0 or newer. + #[cfg(ossl110)] + pub fn aes_256_wrap_pad() -> &'static CipherRef { + unsafe { CipherRef::from_ptr(ffi::EVP_aes_256_wrap_pad() as *mut _) } + } + #[cfg(not(osslconf = "OPENSSL_NO_BF"))] pub fn bf_cbc() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_bf_cbc() as *mut _) } @@ -324,6 +375,7 @@ impl Cipher { unsafe { CipherRef::from_ptr(ffi::EVP_des_ede3_cfb64() as *mut _) } } + #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn rc4() -> &'static CipherRef { unsafe { CipherRef::from_ptr(ffi::EVP_rc4() as *mut _) } } diff --git a/openssl/src/cipher_ctx.rs b/openssl/src/cipher_ctx.rs index 8cb942dbbde32c36066cea425128f9b320012e11..56d0d26700d5903e592ca8d75f9dd51f98310c97 100644 --- a/openssl/src/cipher_ctx.rs +++ b/openssl/src/cipher_ctx.rs @@ -55,6 +55,8 @@ use crate::error::ErrorStack; #[cfg(not(boringssl))] use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef}; use crate::{cvt, cvt_p}; +#[cfg(ossl102)] +use bitflags::bitflags; use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_uchar}; @@ -80,6 +82,15 @@ foreign_type_and_impl_send_sync! { pub struct CipherCtxRef; } +#[cfg(ossl102)] +bitflags! { + /// Flags for `EVP_CIPHER_CTX`. + pub struct CipherCtxFlags : c_int { + /// The flag used to opt into AES key wrap ciphers. + const FLAG_WRAP_ALLOW = ffi::EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; + } +} + impl CipherCtx { /// Creates a new context. #[corresponds(EVP_CIPHER_CTX_new)] @@ -509,6 +520,17 @@ impl CipherCtxRef { Ok(()) } + /// Set ctx flags. + /// + /// This function is currently used to enable AES key wrap feature supported by OpenSSL 1.0.2 or newer. + #[corresponds(EVP_CIPHER_CTX_set_flags)] + #[cfg(ossl102)] + pub fn set_flags(&mut self, flags: CipherCtxFlags) { + unsafe { + ffi::EVP_CIPHER_CTX_set_flags(self.as_ptr(), flags.bits()); + } + } + /// Writes data into the context. /// /// Providing no output buffer will cause the input to be considered additional authenticated data (AAD). @@ -551,8 +573,7 @@ impl CipherCtxRef { /// output size check removed. It can be used when the exact /// buffer size control is maintained by the caller. /// - /// # Safety - /// The caller is expected to provide `output` buffer + /// SAFETY: The caller is expected to provide `output` buffer /// large enough to contain correct number of bytes. For streaming /// ciphers the output buffer size should be at least as big as /// the input buffer. For block ciphers the size of the output @@ -592,6 +613,50 @@ impl CipherCtxRef { Ok(len) } + /// Like [`Self::cipher_update`] except that it writes output into the + /// `data` buffer. The `inlen` parameter specifies the number of bytes in + /// `data` that are considered the input. For streaming ciphers, the size of + /// `data` must be at least the input size. Otherwise, it must be at least + /// an additional block size larger. + /// + /// Note: Use [`Self::cipher_update`] with no output argument to write AAD. + /// + /// # Panics + /// + /// This function panics if the input size cannot be represented as `int` or + /// exceeds the buffer size, or if the output buffer does not contain enough + /// additional space. + #[corresponds(EVP_CipherUpdate)] + pub fn cipher_update_inplace( + &mut self, + data: &mut [u8], + inlen: usize, + ) -> Result { + assert!(inlen <= data.len(), "Input size may not exceed buffer size"); + let block_size = self.block_size(); + if block_size != 1 { + assert!( + data.len() >= inlen + block_size, + "Output buffer size must be at least {} bytes.", + inlen + block_size + ); + } + + let inlen = c_int::try_from(inlen).unwrap(); + let mut outlen = 0; + unsafe { + cvt(ffi::EVP_CipherUpdate( + self.as_ptr(), + data.as_mut_ptr(), + &mut outlen, + data.as_ptr(), + inlen, + )) + }?; + + Ok(outlen as usize) + } + /// Finalizes the encryption or decryption process. /// /// Any remaining data will be written to the output buffer. @@ -620,8 +685,7 @@ impl CipherCtxRef { /// This function is the same as [`Self::cipher_final`] but with /// the output buffer size check removed. /// - /// # Safety - /// The caller is expected to provide `output` buffer + /// SAFETY: The caller is expected to provide `output` buffer /// large enough to contain correct number of bytes. For streaming /// ciphers the output buffer can be empty, for block ciphers the /// output buffer should be at least as big as the block. @@ -780,6 +844,26 @@ mod test { ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); + // encrypt again, but use in-place encryption this time + // First reset the IV + ctx.encrypt_init(None, None, Some(&iv)).unwrap(); + ctx.set_padding(false); + let mut data_inplace: [u8; 32] = [1; 32]; + let outlen = ctx + .cipher_update_inplace(&mut data_inplace[0..15], 15) + .unwrap(); + assert_eq!(15, outlen); + + let outlen = ctx + .cipher_update_inplace(&mut data_inplace[15..32], 17) + .unwrap(); + assert_eq!(17, outlen); + + ctx.cipher_final(&mut [0u8; 0]).unwrap(); + + // Check that the resulting data is encrypted in the same manner + assert_eq!(data_inplace.as_slice(), output.as_slice()); + // try to decrypt ctx.decrypt_init(Some(cipher), Some(&key), Some(&iv)) .unwrap(); @@ -802,6 +886,19 @@ mod test { ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); // check if the decrypted blocks are the same as input (all ones) assert_eq!(output_decrypted, vec![1; 32]); + + // decrypt again, but now the output in-place + ctx.decrypt_init(None, None, Some(&iv)).unwrap(); + ctx.set_padding(false); + + let outlen = ctx.cipher_update_inplace(&mut output[0..15], 15).unwrap(); + assert_eq!(15, outlen); + + let outlen = ctx.cipher_update_inplace(&mut output[15..], 17).unwrap(); + assert_eq!(17, outlen); + + ctx.cipher_final_vec(&mut vec![0; 0]).unwrap(); + assert_eq!(output_decrypted, output); } #[test] @@ -840,4 +937,162 @@ mod test { ctx.cipher_update(&vec![0; block_size + 1], Some(&mut vec![0; block_size - 1])) .unwrap(); } + + #[cfg(ossl102)] + fn cipher_wrap_test(cipher: &CipherRef, pt: &str, ct: &str, key: &str, iv: Option<&str>) { + let pt = hex::decode(pt).unwrap(); + let key = hex::decode(key).unwrap(); + let expected = hex::decode(ct).unwrap(); + let iv = iv.map(|v| hex::decode(v).unwrap()); + let padding = 8 - pt.len() % 8; + let mut computed = vec![0; pt.len() + padding + cipher.block_size() * 2]; + let mut ctx = CipherCtx::new().unwrap(); + + ctx.set_flags(CipherCtxFlags::FLAG_WRAP_ALLOW); + ctx.encrypt_init(Some(cipher), Some(&key), iv.as_deref()) + .unwrap(); + + let count = ctx.cipher_update(&pt, Some(&mut computed)).unwrap(); + let rest = ctx.cipher_final(&mut computed[count..]).unwrap(); + computed.truncate(count + rest); + + if computed != expected { + println!("Computed: {}", hex::encode(&computed)); + println!("Expected: {}", hex::encode(&expected)); + if computed.len() != expected.len() { + println!( + "Lengths differ: {} in computed vs {} expected", + computed.len(), + expected.len() + ); + } + panic!("test failure"); + } + } + + #[test] + #[cfg(ossl102)] + fn test_aes128_wrap() { + let pt = "00112233445566778899aabbccddeeff"; + let ct = "7940ff694448b5bb5139c959a4896832e55d69aa04daa27e"; + let key = "2b7e151628aed2a6abf7158809cf4f3c"; + let iv = "0001020304050607"; + + cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, Some(iv)); + } + + #[test] + #[cfg(ossl102)] + fn test_aes128_wrap_default_iv() { + let pt = "00112233445566778899aabbccddeeff"; + let ct = "38f1215f0212526f8a70b51955b9fbdc9fe3041d9832306e"; + let key = "2b7e151628aed2a6abf7158809cf4f3c"; + + cipher_wrap_test(Cipher::aes_128_wrap(), pt, ct, key, None); + } + + #[test] + #[cfg(ossl110)] + fn test_aes128_wrap_pad() { + let pt = "00112233445566778899aabbccddee"; + let ct = "f13998f5ab32ef82a1bdbcbe585e1d837385b529572a1e1b"; + let key = "2b7e151628aed2a6abf7158809cf4f3c"; + let iv = "00010203"; + + cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, Some(iv)); + } + + #[test] + #[cfg(ossl110)] + fn test_aes128_wrap_pad_default_iv() { + let pt = "00112233445566778899aabbccddee"; + let ct = "3a501085fb8cf66f4186b7df851914d471ed823411598add"; + let key = "2b7e151628aed2a6abf7158809cf4f3c"; + + cipher_wrap_test(Cipher::aes_128_wrap_pad(), pt, ct, key, None); + } + + #[test] + #[cfg(ossl102)] + fn test_aes192_wrap() { + let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b"; + let ct = "83b89142dfeeb4871e078bfb81134d33e23fedc19b03a1cf689973d3831b6813"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + let iv = "0001020304050607"; + + cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, Some(iv)); + } + + #[test] + #[cfg(ossl102)] + fn test_aes192_wrap_default_iv() { + let pt = "9f6dee187d35302116aecbfd059657efd9f7589c4b5e7f5b"; + let ct = "c02c2cf11505d3e4851030d5534cbf5a1d7eca7ba8839adbf239756daf1b43e6"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + + cipher_wrap_test(Cipher::aes_192_wrap(), pt, ct, key, None); + } + + #[test] + #[cfg(ossl110)] + fn test_aes192_wrap_pad() { + let pt = "00112233445566778899aabbccddee"; + let ct = "b4f6bb167ef7caf061a74da82b36ad038ca057ab51e98d3a"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + let iv = "00010203"; + + cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, Some(iv)); + } + + #[test] + #[cfg(ossl110)] + fn test_aes192_wrap_pad_default_iv() { + let pt = "00112233445566778899aabbccddee"; + let ct = "b2c37a28cc602753a7c944a4c2555a2df9c98b2eded5312e"; + let key = "8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"; + + cipher_wrap_test(Cipher::aes_192_wrap_pad(), pt, ct, key, None); + } + + #[test] + #[cfg(ossl102)] + fn test_aes256_wrap() { + let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"; + let ct = "cc05da2a7f56f7dd0c144231f90bce58648fa20a8278f5a6b7d13bba6aa57a33229d4333866b7fd6"; + let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + let iv = "0001020304050607"; + + cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, Some(iv)); + } + + #[test] + #[cfg(ossl102)] + fn test_aes256_wrap_default_iv() { + let pt = "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e51"; + let ct = "0b24f068b50e52bc6987868411c36e1b03900866ed12af81eb87cef70a8d1911731c1d7abf789d88"; + let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + + cipher_wrap_test(Cipher::aes_256_wrap(), pt, ct, key, None); + } + + #[test] + #[cfg(ossl110)] + fn test_aes256_wrap_pad() { + let pt = "00112233445566778899aabbccddee"; + let ct = "91594e044ccc06130d60e6c84a996aa4f96a9faff8c5f6e7"; + let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + let iv = "00010203"; + + cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, Some(iv)); + } + + #[test] + #[cfg(ossl110)] + fn test_aes256_wrap_pad_default_iv() { + let pt = "00112233445566778899aabbccddee"; + let ct = "dc3c166a854afd68aea624a4272693554bf2e4fcbae602cd"; + let key = "603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"; + + cipher_wrap_test(Cipher::aes_256_wrap_pad(), pt, ct, key, None); + } } diff --git a/openssl/src/derive.rs b/openssl/src/derive.rs index 5d422f69761a00100c9986930166189710db8827..424c5f92d783129ef0ff6a0d4bb2f91b6508e9ef 100644 --- a/openssl/src/derive.rs +++ b/openssl/src/derive.rs @@ -56,6 +56,7 @@ use std::ptr; use crate::error::ErrorStack; use crate::pkey::{HasPrivate, HasPublic, PKeyRef}; use crate::{cvt, cvt_p}; +use openssl_macros::corresponds; /// A type used to derive a shared secret between two keys. pub struct Deriver<'a>(*mut ffi::EVP_PKEY_CTX, PhantomData<&'a ()>); @@ -82,10 +83,7 @@ impl<'a> Deriver<'a> { } /// Sets the peer key used for secret derivation. - /// - /// This corresponds to [`EVP_PKEY_derive_set_peer`]: - /// - /// [`EVP_PKEY_derive_set_peer`]: https://www.openssl.org/docs/manmaster/crypto/EVP_PKEY_derive_init.html + #[corresponds(EVP_PKEY_derive_set_peer)] pub fn set_peer(&mut self, key: &'a PKeyRef) -> Result<(), ErrorStack> where T: HasPublic, @@ -93,6 +91,29 @@ impl<'a> Deriver<'a> { unsafe { cvt(ffi::EVP_PKEY_derive_set_peer(self.0, key.as_ptr())).map(|_| ()) } } + /// Sets the peer key used for secret derivation along with optionally validating the peer public key. + /// + /// Requires OpenSSL 3.0.0 or newer. + #[corresponds(EVP_PKEY_derive_set_peer_ex)] + #[cfg(ossl300)] + pub fn set_peer_ex( + &mut self, + key: &'a PKeyRef, + validate_peer: bool, + ) -> Result<(), ErrorStack> + where + T: HasPublic, + { + unsafe { + cvt(ffi::EVP_PKEY_derive_set_peer_ex( + self.0, + key.as_ptr(), + validate_peer as i32, + )) + .map(|_| ()) + } + } + /// Returns the size of the shared secret. /// /// It can be used to size the buffer passed to [`Deriver::derive`]. @@ -179,4 +200,18 @@ mod test { let shared = deriver.derive_to_vec().unwrap(); assert!(!shared.is_empty()); } + + #[test] + #[cfg(ossl300)] + fn test_ec_key_derive_ex() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let ec_key2 = EcKey::generate(&group).unwrap(); + let pkey = PKey::from_ec_key(ec_key).unwrap(); + let pkey2 = PKey::from_ec_key(ec_key2).unwrap(); + let mut deriver = Deriver::new(&pkey).unwrap(); + deriver.set_peer_ex(&pkey2, true).unwrap(); + let shared = deriver.derive_to_vec().unwrap(); + assert!(!shared.is_empty()); + } } diff --git a/openssl/src/dh.rs b/openssl/src/dh.rs index e781543e2732c0b75cef3f9a53de7e5d915e5303..7445e3408c37f2155726229ac6057b9f8769c73a 100644 --- a/openssl/src/dh.rs +++ b/openssl/src/dh.rs @@ -7,7 +7,7 @@ use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; -use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private}; +use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; @@ -39,6 +39,16 @@ where params_to_der, ffi::i2d_DHparams } + + /// Validates DH parameters for correctness + #[corresponds(DH_check_key)] + pub fn check_key(&self) -> Result { + unsafe { + let mut codes = 0; + cvt(ffi::DH_check(self.as_ptr(), &mut codes))?; + Ok(codes == 0) + } + } } impl Dh { @@ -66,6 +76,16 @@ impl Dh { } } + /// Sets the public key on the DH object. + pub fn set_public_key(self, pub_key: BigNum) -> Result, ErrorStack> { + unsafe { + let dh_ptr = self.0; + cvt(DH_set0_key(dh_ptr, pub_key.as_ptr(), ptr::null_mut()))?; + mem::forget((self, pub_key)); + Ok(Dh::from_ptr(dh_ptr)) + } + } + /// Sets the private key on the DH object and recomputes the public key. pub fn set_private_key(self, priv_key: BigNum) -> Result, ErrorStack> { unsafe { @@ -79,6 +99,16 @@ impl Dh { } } + /// Sets the public and private keys on the DH object. + pub fn set_key(self, pub_key: BigNum, priv_key: BigNum) -> Result, ErrorStack> { + unsafe { + let dh_ptr = self.0; + cvt(DH_set0_key(dh_ptr, pub_key.as_ptr(), priv_key.as_ptr()))?; + mem::forget((self, pub_key, priv_key)); + Ok(Dh::from_ptr(dh_ptr)) + } + } + /// Generates DH params based on the given `prime_len` and a fixed `generator` value. #[corresponds(DH_generate_parameters_ex)] pub fn generate_params(prime_len: u32, generator: u32) -> Result, ErrorStack> { @@ -367,6 +397,30 @@ mod tests { assert_eq!(key1.private_key(), key2.private_key()); } + #[test] + #[cfg(ossl102)] + fn test_set_keys() { + let dh1 = Dh::get_2048_256().unwrap(); + let key1 = dh1.generate_key().unwrap(); + + let dh2 = Dh::get_2048_256().unwrap(); + let key2 = dh2 + .set_public_key(key1.public_key().to_owned().unwrap()) + .unwrap(); + + assert_eq!(key1.public_key(), key2.public_key()); + + let dh3 = Dh::get_2048_256().unwrap(); + let key3 = dh3 + .set_key( + key1.public_key().to_owned().unwrap(), + key1.private_key().to_owned().unwrap(), + ) + .unwrap(); + assert_eq!(key1.public_key(), key3.public_key()); + assert_eq!(key1.private_key(), key3.private_key()); + } + #[test] fn test_dh_from_pem() { let mut ctx = SslContext::builder(SslMethod::tls()).unwrap(); @@ -413,4 +467,14 @@ mod tests { assert_eq!(shared_a, shared_b); } + + #[test] + fn test_dh_check_key() { + let dh1 = Dh::generate_params(512, 2).unwrap(); + let p = BigNum::from_hex_str("04").unwrap(); + let g = BigNum::from_hex_str("02").unwrap(); + let dh2 = Dh::from_pqg(p, None, g).unwrap(); + assert!(dh1.check_key().unwrap()); + assert!(!dh2.check_key().unwrap()); + } } diff --git a/openssl/src/dsa.rs b/openssl/src/dsa.rs index c550f6548b9744d7d31f0a0cd5c3351426f95e50..1a63e8ad8f976c9260c65cb5dad5bb3f5b21b3d7 100644 --- a/openssl/src/dsa.rs +++ b/openssl/src/dsa.rs @@ -7,6 +7,7 @@ use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; +#[cfg(not(boringssl))] use libc::c_int; use std::fmt; use std::mem; @@ -14,7 +15,7 @@ use std::ptr; use crate::bn::{BigNum, BigNumRef}; use crate::error::ErrorStack; -use crate::pkey::{HasParams, HasPrivate, HasPublic, Private, Public}; +use crate::pkey::{HasParams, HasPrivate, HasPublic, Params, Private, Public}; use crate::util::ForeignTypeRefExt; use crate::{cvt, cvt_p}; use openssl_macros::corresponds; @@ -127,6 +128,13 @@ where ffi::PEM_write_bio_DSAPrivateKey } + to_der! { + /// Serializes the private_key to a DER-encoded `DSAPrivateKey` structure. + #[corresponds(i2d_DSAPrivateKey)] + private_key_to_der, + ffi::i2d_DSAPrivateKey + } + /// Returns a reference to the private key component of `self`. #[corresponds(DSA_get0_key)] pub fn priv_key(&self) -> &BigNumRef { @@ -183,17 +191,21 @@ type BitType = libc::c_uint; #[cfg(not(boringssl))] type BitType = c_int; -impl Dsa { - /// Generate a DSA key pair. - /// - /// Calls [`DSA_generate_parameters_ex`] to populate the `p`, `g`, and `q` values. - /// These values are used to generate the key pair with [`DSA_generate_key`]. - /// - /// The `bits` parameter corresponds to the length of the prime `p`. - /// - /// [`DSA_generate_parameters_ex`]: https://www.openssl.org/docs/manmaster/crypto/DSA_generate_parameters_ex.html - /// [`DSA_generate_key`]: https://www.openssl.org/docs/manmaster/crypto/DSA_generate_key.html - pub fn generate(bits: u32) -> Result, ErrorStack> { +impl Dsa { + /// Creates a DSA params based upon the given parameters. + #[corresponds(DSA_set0_pqg)] + pub fn from_pqg(p: BigNum, q: BigNum, g: BigNum) -> Result, ErrorStack> { + unsafe { + let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); + cvt(DSA_set0_pqg(dsa.0, p.as_ptr(), q.as_ptr(), g.as_ptr()))?; + mem::forget((p, q, g)); + Ok(dsa) + } + } + + /// Generates DSA params based on the given number of bits. + #[corresponds(DSA_generate_parameters_ex)] + pub fn generate_params(bits: u32) -> Result, ErrorStack> { ffi::init(); unsafe { let dsa = Dsa::from_ptr(cvt_p(ffi::DSA_new())?); @@ -206,11 +218,31 @@ impl Dsa { ptr::null_mut(), ptr::null_mut(), ))?; - cvt(ffi::DSA_generate_key(dsa.0))?; Ok(dsa) } } + /// Generates a private key based on the DSA params. + #[corresponds(DSA_generate_key)] + pub fn generate_key(self) -> Result, ErrorStack> { + unsafe { + let dsa_ptr = self.0; + cvt(ffi::DSA_generate_key(dsa_ptr))?; + mem::forget(self); + Ok(Dsa::from_ptr(dsa_ptr)) + } + } +} + +impl Dsa { + /// Generate a DSA key pair. + /// + /// The `bits` parameter corresponds to the length of the prime `p`. + pub fn generate(bits: u32) -> Result, ErrorStack> { + let params = Dsa::generate_params(bits)?; + params.generate_key() + } + /// Create a DSA key pair with the given parameters /// /// `p`, `q` and `g` are the common parameters. @@ -283,7 +315,7 @@ impl fmt::Debug for Dsa { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{DSA_get0_key, DSA_get0_pqg, DSA_set0_key, DSA_set0_pqg}; } else { #[allow(bad_style)] @@ -462,7 +494,7 @@ impl DsaSigRef { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{DSA_SIG_set0, DSA_SIG_get0}; } else { #[allow(bad_style)] @@ -556,6 +588,24 @@ mod test { assert_eq!(dsa.g(), &BigNum::from_u32(60).unwrap()); } + #[test] + fn test_params() { + let params = Dsa::generate_params(1024).unwrap(); + let p = params.p().to_owned().unwrap(); + let q = params.q().to_owned().unwrap(); + let g = params.g().to_owned().unwrap(); + let key = params.generate_key().unwrap(); + let params2 = Dsa::from_pqg( + key.p().to_owned().unwrap(), + key.q().to_owned().unwrap(), + key.g().to_owned().unwrap(), + ) + .unwrap(); + assert_eq!(p, *params2.p()); + assert_eq!(q, *params2.q()); + assert_eq!(g, *params2.g()); + } + #[test] #[cfg(not(boringssl))] fn test_signature() { diff --git a/openssl/src/ec.rs b/openssl/src/ec.rs index 248ced3e41757320fc5b96ea10fe07e67d7f9b2a..d541ddfc23bec8a1664cb02cd3634e6178af814b 100644 --- a/openssl/src/ec.rs +++ b/openssl/src/ec.rs @@ -15,6 +15,7 @@ //! [`EcGroup`]: struct.EcGroup.html //! [`Nid`]: ../nid/struct.Nid.html //! [Elliptic Curve Cryptography]: https://wiki.openssl.org/index.php/Elliptic_Curve_Cryptography +use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::c_int; use std::fmt; @@ -28,6 +29,13 @@ use crate::util::ForeignTypeRefExt; use crate::{cvt, cvt_n, cvt_p, init}; use openssl_macros::corresponds; +cfg_if! { + if #[cfg(not(boringssl))] { + use std::ffi::CString; + use crate::string::OpensslString; + } +} + /// Compressed or Uncompressed conversion /// /// Conversion from the binary value of the point on the curve is performed in one of @@ -57,7 +65,7 @@ impl PointConversionForm { /// Named Curve or Explicit /// /// This type acts as a boolean as to whether the `EcGroup` is named or explicit. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug, PartialEq)] pub struct Asn1Flag(c_int); impl Asn1Flag { @@ -294,6 +302,12 @@ impl EcGroupRef { } } + /// Gets the flag determining if the group corresponds to a named curve. + #[corresponds(EC_GROUP_get_asn1_flag)] + pub fn asn1_flag(&self) -> Asn1Flag { + unsafe { Asn1Flag(ffi::EC_GROUP_get_asn1_flag(self.as_ptr())) } + } + /// Returns the name of the curve, if a name is associated. #[corresponds(EC_GROUP_get_curve_name)] pub fn curve_name(&self) -> Option { @@ -457,6 +471,26 @@ impl EcPointRef { } } + /// Serializes the point to a hexadecimal string representation. + #[corresponds(EC_POINT_point2hex)] + #[cfg(not(boringssl))] + pub fn to_hex_str( + &self, + group: &EcGroupRef, + form: PointConversionForm, + ctx: &mut BigNumContextRef, + ) -> Result { + unsafe { + let buf = cvt_p(ffi::EC_POINT_point2hex( + group.as_ptr(), + self.as_ptr(), + form.0, + ctx.as_ptr(), + ))?; + Ok(OpensslString::from_ptr(buf)) + } + } + /// Creates a new point on the specified curve with the same value. #[corresponds(EC_POINT_dup)] pub fn to_owned(&self, group: &EcGroupRef) -> Result { @@ -485,7 +519,7 @@ impl EcPointRef { /// Places affine coordinates of a curve over a prime field in the provided /// `x` and `y` `BigNum`s. #[corresponds(EC_POINT_get_affine_coordinates)] - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl350))] pub fn affine_coordinates( &self, group: &EcGroupRef, @@ -625,6 +659,27 @@ impl EcPoint { } Ok(point) } + + /// Creates point from a hexadecimal string representation + #[corresponds(EC_POINT_hex2point)] + #[cfg(not(boringssl))] + pub fn from_hex_str( + group: &EcGroupRef, + s: &str, + ctx: &mut BigNumContextRef, + ) -> Result { + let point = EcPoint::new(group)?; + unsafe { + let c_str = CString::new(s.as_bytes()).unwrap(); + cvt_p(ffi::EC_POINT_hex2point( + group.as_ptr(), + c_str.as_ptr() as *const _, + point.as_ptr(), + ctx.as_ptr(), + ))?; + } + Ok(point) + } } generic_foreign_type_and_impl_send_sync! { @@ -1115,6 +1170,20 @@ mod test { assert!(point.eq(&group, &point2, &mut ctx).unwrap()); } + #[test] + #[cfg(not(boringssl))] + fn point_hex_str() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let key = EcKey::generate(&group).unwrap(); + let point = key.public_key(); + let mut ctx = BigNumContext::new().unwrap(); + let hex = point + .to_hex_str(&group, PointConversionForm::COMPRESSED, &mut ctx) + .unwrap(); + let point2 = EcPoint::from_hex_str(&group, &hex, &mut ctx).unwrap(); + assert!(point.eq(&group, &point2, &mut ctx).unwrap()); + } + #[test] fn point_owned() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); @@ -1191,7 +1260,7 @@ mod test { assert!(ec_key.check_key().is_ok()); } - #[cfg(ossl111)] + #[cfg(any(ossl111, boringssl, libressl350))] #[test] fn get_affine_coordinates() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); @@ -1265,4 +1334,12 @@ mod test { let group2 = EcGroup::from_curve_name(Nid::X9_62_PRIME239V3).unwrap(); assert!(!g.is_on_curve(&group2, &mut ctx).unwrap()); } + + #[test] + #[cfg(any(boringssl, ossl111, libressl350))] + fn asn1_flag() { + let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let flag = group.asn1_flag(); + assert_eq!(flag, Asn1Flag::NAMED_CURVE); + } } diff --git a/openssl/src/ecdsa.rs b/openssl/src/ecdsa.rs index 0a960e7b9e06c675fd8457175db4ffd4ca611b74..f3b27b39531a7695d0f7a381c05751935b97e50d 100644 --- a/openssl/src/ecdsa.rs +++ b/openssl/src/ecdsa.rs @@ -110,7 +110,7 @@ impl EcdsaSigRef { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{ECDSA_SIG_set0, ECDSA_SIG_get0}; } else { #[allow(bad_style)] diff --git a/openssl/src/hash.rs b/openssl/src/hash.rs index 37442fb274c1529860fb341e68d94852f6241a89..52d73deed446075721ae2c89919d3be542daf89a 100644 --- a/openssl/src/hash.rs +++ b/openssl/src/hash.rs @@ -43,7 +43,7 @@ use crate::nid::Nid; use crate::{cvt, cvt_p}; cfg_if! { - if #[cfg(ossl110)] { + if #[cfg(any(ossl110, boringssl))] { 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}; diff --git a/openssl/src/lib.rs b/openssl/src/lib.rs index eef740e2440849c0bf0a0937462d6381097b3560..73be1454b4dcd8e150a35622f3285e2c047e072c 100644 --- a/openssl/src/lib.rs +++ b/openssl/src/lib.rs @@ -1,7 +1,7 @@ //! Bindings to OpenSSL //! //! This crate provides a safe interface to the popular OpenSSL cryptography library. OpenSSL versions 1.0.1 through -//! 3.x.x and LibreSSL versions 2.5 through 3.4.1 are supported. +//! 3.x.x and LibreSSL versions 2.5 through 3.7.x are supported. //! //! # Building //! @@ -119,7 +119,7 @@ //! ``` #![doc(html_root_url = "https://docs.rs/openssl/0.10")] #![warn(rust_2018_idioms)] -#![allow(clippy::uninlined_format_args, clippy::needless_doctest_main)] +#![allow(clippy::uninlined_format_args)] #[doc(inline)] pub use ffi::init; @@ -166,7 +166,6 @@ pub mod nid; #[cfg(not(any(boringssl, osslconf = "OPENSSL_NO_OCSP")))] pub mod ocsp; pub mod pkcs12; -#[cfg(not(boringssl))] pub mod pkcs5; #[cfg(not(boringssl))] pub mod pkcs7; diff --git a/openssl/src/md_ctx.rs b/openssl/src/md_ctx.rs index c4d3f06b94d58ef91fa85c44212950bd76c6ab54..156f3c2fc968f97290cb57d7a1752c220b4f9149 100644 --- a/openssl/src/md_ctx.rs +++ b/openssl/src/md_ctx.rs @@ -93,7 +93,7 @@ use std::convert::TryFrom; use std::ptr; cfg_if! { - if #[cfg(ossl110)] { + if #[cfg(any(ossl110, boringssl))] { 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}; diff --git a/openssl/src/nid.rs b/openssl/src/nid.rs index e4562a1c277fb8de76e4f2b5388240e18fc376b0..91fcdeca9da068a6b202b1f224bd2a8cbc3ce3e8 100644 --- a/openssl/src/nid.rs +++ b/openssl/src/nid.rs @@ -51,13 +51,13 @@ pub struct Nid(c_int); #[allow(non_snake_case)] impl Nid { /// Create a `Nid` from an integer representation. - pub fn from_raw(raw: c_int) -> Nid { + pub const fn from_raw(raw: c_int) -> Nid { Nid(raw) } /// Return the integer representation of a `Nid`. #[allow(clippy::trivially_copy_pass_by_ref)] - pub fn as_raw(&self) -> c_int { + pub const fn as_raw(&self) -> c_int { self.0 } @@ -1074,6 +1074,8 @@ impl Nid { pub const AES_128_CBC_HMAC_SHA1: Nid = Nid(ffi::NID_aes_128_cbc_hmac_sha1); 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(ossl111)] + pub const SM2: Nid = Nid(ffi::NID_sm2); #[cfg(any(ossl111, libressl291))] pub const SM3: Nid = Nid(ffi::NID_sm3); #[cfg(ossl111)] @@ -1165,10 +1167,13 @@ mod test { assert_eq!(nid.short_name().unwrap(), "foo"); assert_eq!(nid.long_name().unwrap(), "foobar"); - let invalid_oid = Nid::create("invalid_oid", "invalid", "invalid"); - assert!( - invalid_oid.is_err(), - "invalid_oid should not return a valid value" - ); + // Due to a bug in OpenSSL 3.1.0, this test crashes on Windows + if !cfg!(ossl310) { + let invalid_oid = Nid::create("invalid_oid", "invalid", "invalid"); + assert!( + invalid_oid.is_err(), + "invalid_oid should not return a valid value" + ); + } } } diff --git a/openssl/src/pkcs5.rs b/openssl/src/pkcs5.rs index c15ce477613e41d2fcd4bb5f1302644e1e543056..cd704e8256c2d509955e811c888789c19a8a180b 100644 --- a/openssl/src/pkcs5.rs +++ b/openssl/src/pkcs5.rs @@ -1,9 +1,13 @@ +#[cfg(not(boringssl))] use libc::c_int; +use std::convert::TryInto; +#[cfg(not(boringssl))] use std::ptr; use crate::cvt; use crate::error::ErrorStack; use crate::hash::MessageDigest; +#[cfg(not(boringssl))] use crate::symm::Cipher; use openssl_macros::corresponds; @@ -25,6 +29,7 @@ pub struct KeyIvPair { /// `pbkdf2_hmac` or another more modern key derivation algorithm. #[corresponds(EVP_BytesToKey)] #[allow(clippy::useless_conversion)] +#[cfg(not(boringssl))] pub fn bytes_to_key( cipher: Cipher, digest: MessageDigest, @@ -91,19 +96,15 @@ pub fn pbkdf2_hmac( key: &mut [u8], ) -> Result<(), ErrorStack> { unsafe { - assert!(pass.len() <= c_int::max_value() as usize); - assert!(salt.len() <= c_int::max_value() as usize); - assert!(key.len() <= c_int::max_value() as usize); - ffi::init(); cvt(ffi::PKCS5_PBKDF2_HMAC( pass.as_ptr() as *const _, - pass.len() as c_int, + pass.len().try_into().unwrap(), salt.as_ptr(), - salt.len() as c_int, - iter as c_int, + salt.len().try_into().unwrap(), + iter.try_into().unwrap(), hash.as_ptr(), - key.len() as c_int, + key.len().try_into().unwrap(), key.as_mut_ptr(), )) .map(|_| ()) @@ -114,7 +115,8 @@ pub fn pbkdf2_hmac( /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PBE_scrypt)] -#[cfg(any(ossl110))] +#[cfg(any(ossl110, boringssl))] +#[allow(clippy::useless_conversion)] pub fn scrypt( pass: &[u8], salt: &[u8], @@ -134,7 +136,7 @@ pub fn scrypt( n, r, p, - maxmem, + maxmem.try_into().unwrap(), key.as_mut_ptr() as *mut _, key.len(), )) @@ -145,6 +147,7 @@ pub fn scrypt( #[cfg(test)] mod tests { use crate::hash::MessageDigest; + #[cfg(not(boringssl))] use crate::symm::Cipher; // Test vectors from @@ -246,6 +249,7 @@ mod tests { } #[test] + #[cfg(not(boringssl))] fn bytes_to_key() { let salt = [16_u8, 34_u8, 19_u8, 23_u8, 141_u8, 4_u8, 207_u8, 221_u8]; @@ -282,7 +286,7 @@ mod tests { } #[test] - #[cfg(any(ossl110))] + #[cfg(any(ossl110, boringssl))] fn scrypt() { let pass = "pleaseletmein"; let salt = "SodiumChloride"; diff --git a/openssl/src/pkey.rs b/openssl/src/pkey.rs index bec4bfdafc26d69f3a64ebdeda2f4bc69dd91ff4..453aeed72fd4f6a79afbdc80f2da5a52a6f03c24 100644 --- a/openssl/src/pkey.rs +++ b/openssl/src/pkey.rs @@ -57,7 +57,7 @@ use cfg_if::cfg_if; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_long}; use openssl_macros::corresponds; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::ffi::CString; use std::fmt; use std::mem; @@ -85,8 +85,10 @@ impl Id { pub const DSA: Id = Id(ffi::EVP_PKEY_DSA); pub const DH: Id = Id(ffi::EVP_PKEY_DH); pub const EC: Id = Id(ffi::EVP_PKEY_EC); + #[cfg(ossl111)] + pub const SM2: Id = Id(ffi::EVP_PKEY_SM2); - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] pub const HKDF: Id = Id(ffi::EVP_PKEY_HKDF); #[cfg(any(ossl111, boringssl, libressl370))] @@ -97,6 +99,8 @@ impl Id { pub const X25519: Id = Id(ffi::EVP_PKEY_X25519); #[cfg(ossl111)] pub const X448: Id = Id(ffi::EVP_PKEY_X448); + #[cfg(ossl111)] + pub const POLY1305: Id = Id(ffi::EVP_PKEY_POLY1305); /// Creates a `Id` from an integer representation. pub fn from_raw(value: c_int) -> Id { @@ -244,7 +248,11 @@ where where U: HasPublic, { - unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 } + let res = unsafe { ffi::EVP_PKEY_cmp(self.as_ptr(), other.as_ptr()) == 1 }; + // Clear the stack. OpenSSL will put an error on the stack when the + // keys are different types in some situations. + let _ = ErrorStack::get(); + res } /// Raw byte representation of a public key. @@ -344,10 +352,6 @@ where /// Serializes a private key into a DER-formatted PKCS#8, using the supplied password to /// encrypt the key. - /// - /// # Panics - /// - /// Panics if `passphrase` contains an embedded null. #[corresponds(i2d_PKCS8PrivateKey_bio)] pub fn private_key_to_pkcs8_passphrase( &self, @@ -356,14 +360,12 @@ where ) -> Result, ErrorStack> { unsafe { let bio = MemBio::new()?; - let len = passphrase.len(); - let passphrase = CString::new(passphrase).unwrap(); cvt(ffi::i2d_PKCS8PrivateKey_bio( bio.as_ptr(), self.as_ptr(), cipher.as_ptr(), passphrase.as_ptr() as *const _ as *mut _, - len as ::libc::c_int, + passphrase.len().try_into().unwrap(), None, ptr::null_mut(), ))?; @@ -406,11 +408,7 @@ impl PKey { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); - cvt(ffi::EVP_PKEY_assign( - pkey.0, - ffi::EVP_PKEY_RSA, - rsa.as_ptr() as *mut _, - ))?; + cvt(ffi::EVP_PKEY_assign_RSA(pkey.0, rsa.as_ptr()))?; mem::forget(rsa); Ok(pkey) } @@ -422,11 +420,7 @@ impl PKey { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); - cvt(ffi::EVP_PKEY_assign( - pkey.0, - ffi::EVP_PKEY_DSA, - dsa.as_ptr() as *mut _, - ))?; + cvt(ffi::EVP_PKEY_assign_DSA(pkey.0, dsa.as_ptr()))?; mem::forget(dsa); Ok(pkey) } @@ -434,15 +428,12 @@ impl PKey { /// Creates a new `PKey` containing a Diffie-Hellman key. #[corresponds(EVP_PKEY_assign_DH)] + #[cfg(not(boringssl))] pub fn from_dh(dh: Dh) -> Result, ErrorStack> { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); - cvt(ffi::EVP_PKEY_assign( - pkey.0, - ffi::EVP_PKEY_DH, - dh.as_ptr() as *mut _, - ))?; + cvt(ffi::EVP_PKEY_assign_DH(pkey.0, dh.as_ptr()))?; mem::forget(dh); Ok(pkey) } @@ -454,11 +445,7 @@ impl PKey { unsafe { let evp = cvt_p(ffi::EVP_PKEY_new())?; let pkey = PKey::from_ptr(evp); - cvt(ffi::EVP_PKEY_assign( - pkey.0, - ffi::EVP_PKEY_EC, - ec_key.as_ptr() as *mut _, - ))?; + cvt(ffi::EVP_PKEY_assign_EC_KEY(pkey.0, ec_key.as_ptr()))?; mem::forget(ec_key); Ok(pkey) } @@ -861,6 +848,7 @@ impl TryFrom> for Dsa { } } +#[cfg(not(boringssl))] impl TryFrom> for PKey { type Error = ErrorStack; @@ -885,6 +873,7 @@ mod tests { use crate::dh::Dh; use crate::dsa::Dsa; use crate::ec::EcKey; + use crate::error::Error; use crate::nid::Nid; use crate::rsa::Rsa; use crate::symm::Cipher; @@ -1168,4 +1157,17 @@ mod tests { let key = PKey::ec_gen("prime256v1").unwrap(); assert!(key.ec_key().is_ok()); } + + #[test] + fn test_public_eq() { + let rsa = Rsa::generate(2048).unwrap(); + let pkey1 = PKey::from_rsa(rsa).unwrap(); + + let group = crate::ec::EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); + let ec_key = EcKey::generate(&group).unwrap(); + let pkey2 = PKey::from_ec_key(ec_key).unwrap(); + + assert!(!pkey1.public_eq(&pkey2)); + assert!(Error::get().is_none()); + } } diff --git a/openssl/src/pkey_ctx.rs b/openssl/src/pkey_ctx.rs index 42289b9f481b78fa585b94224e9eda7acd4cb5de..4ac32a8517e8b67cd2747a9078fd6d06cca46e63 100644 --- a/openssl/src/pkey_ctx.rs +++ b/openssl/src/pkey_ctx.rs @@ -70,7 +70,8 @@ use crate::error::ErrorStack; use crate::md::MdRef; use crate::pkey::{HasPrivate, HasPublic, Id, PKey, PKeyRef, Private}; use crate::rsa::Padding; -use crate::{cvt, cvt_n, cvt_p}; +use crate::sign::RsaPssSaltlen; +use crate::{cvt, cvt_p}; use foreign_types::{ForeignType, ForeignTypeRef}; #[cfg(not(boringssl))] use libc::c_int; @@ -164,6 +165,17 @@ where Ok(()) } + /// Prepares the context for signature recovery using the public key. + #[corresponds(EVP_PKEY_verify_recover_init)] + #[inline] + pub fn verify_recover_init(&mut self) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_verify_recover_init(self.as_ptr()))?; + } + + Ok(()) + } + /// Encrypts data using the public key. /// /// If `to` is set to `None`, an upper bound on the number of bytes required for the output buffer will be @@ -209,16 +221,54 @@ where #[inline] pub fn verify(&mut self, data: &[u8], sig: &[u8]) -> Result { unsafe { - let r = cvt_n(ffi::EVP_PKEY_verify( + let r = ffi::EVP_PKEY_verify( self.as_ptr(), sig.as_ptr(), sig.len(), data.as_ptr(), data.len(), - ))?; + ); + // `EVP_PKEY_verify` is not terribly consistent about how it, + // reports errors. It does not clearly distinguish between 0 and + // -1, and may put errors on the stack in both cases. If there's + // errors on the stack, we return `Err()`, else we return + // `Ok(false)`. + if r <= 0 { + let errors = ErrorStack::get(); + if !errors.errors().is_empty() { + return Err(errors); + } + } + Ok(r == 1) } } + + /// Recovers the original data signed by the private key. You almost + /// always want `verify` instead. + /// + /// Returns the number of bytes written to `to`, or the number of bytes + /// that would be written, if `to` is `None. + #[corresponds(EVP_PKEY_verify_recover)] + #[inline] + pub fn verify_recover( + &mut self, + sig: &[u8], + to: Option<&mut [u8]>, + ) -> Result { + let mut written = to.as_ref().map_or(0, |b| b.len()); + unsafe { + cvt(ffi::EVP_PKEY_verify_recover( + self.as_ptr(), + to.map_or(ptr::null_mut(), |b| b.as_mut_ptr()), + &mut written, + sig.as_ptr(), + sig.len(), + ))?; + } + + Ok(written) + } } impl PkeyCtxRef @@ -351,6 +401,22 @@ impl PkeyCtxRef { Ok(()) } + /// Sets which algorithm was used to compute the digest used in a + /// signature. With RSA signatures this causes the signature to be wrapped + /// in a `DigestInfo` structure. This is almost always what you want with + /// RSA signatures. + #[corresponds(EVP_PKEY_CTX_set_signature_md)] + #[inline] + pub fn set_signature_md(&self, md: &MdRef) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_signature_md( + self.as_ptr(), + md.as_ptr(), + ))?; + } + Ok(()) + } + /// Returns the RSA padding mode in use. /// /// This is only useful for RSA keys. @@ -381,6 +447,21 @@ impl PkeyCtxRef { Ok(()) } + /// Sets the RSA PSS salt length. + /// + /// This is only useful for RSA keys. + #[corresponds(EVP_PKEY_CTX_set_rsa_pss_saltlen)] + #[inline] + pub fn set_rsa_pss_saltlen(&mut self, len: RsaPssSaltlen) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::EVP_PKEY_CTX_set_rsa_pss_saltlen( + self.as_ptr(), + len.as_raw(), + )) + .map(|_| ()) + } + } + /// Sets the RSA MGF1 algorithm. /// /// This is only useful for RSA keys. @@ -401,7 +482,7 @@ impl PkeyCtxRef { /// /// This is only useful for RSA keys. #[corresponds(EVP_PKEY_CTX_set_rsa_oaep_md)] - #[cfg(any(ossl102, libressl310))] + #[cfg(any(ossl102, libressl310, boringssl))] #[inline] pub fn set_rsa_oaep_md(&mut self, md: &MdRef) -> Result<(), ErrorStack> { unsafe { @@ -485,7 +566,7 @@ impl PkeyCtxRef { /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set_hkdf_md)] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] #[inline] pub fn set_hkdf_md(&mut self, digest: &MdRef) -> Result<(), ErrorStack> { unsafe { @@ -527,10 +608,13 @@ impl PkeyCtxRef { /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set1_hkdf_key)] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] #[inline] pub fn set_hkdf_key(&mut self, key: &[u8]) -> Result<(), ErrorStack> { + #[cfg(not(boringssl))] let len = c_int::try_from(key.len()).unwrap(); + #[cfg(boringssl)] + let len = key.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_set1_hkdf_key( @@ -549,10 +633,13 @@ impl PkeyCtxRef { /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_set1_hkdf_salt)] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] #[inline] pub fn set_hkdf_salt(&mut self, salt: &[u8]) -> Result<(), ErrorStack> { + #[cfg(not(boringssl))] let len = c_int::try_from(salt.len()).unwrap(); + #[cfg(boringssl)] + let len = salt.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_set1_hkdf_salt( @@ -571,10 +658,13 @@ impl PkeyCtxRef { /// /// Requires OpenSSL 1.1.0 or newer. #[corresponds(EVP_PKEY_CTX_add1_hkdf_info)] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] #[inline] pub fn add_hkdf_info(&mut self, info: &[u8]) -> Result<(), ErrorStack> { + #[cfg(not(boringssl))] let len = c_int::try_from(info.len()).unwrap(); + #[cfg(boringssl)] + let len = info.len(); unsafe { cvt(ffi::EVP_PKEY_CTX_add1_hkdf_info( @@ -632,11 +722,12 @@ mod test { #[cfg(not(boringssl))] use crate::cipher::Cipher; use crate::ec::{EcGroup, EcKey}; - #[cfg(any(ossl102, libressl310))] + use crate::hash::{hash, MessageDigest}; use crate::md::Md; use crate::nid::Nid; use crate::pkey::PKey; use crate::rsa::Rsa; + use crate::sign::Verifier; #[test] fn rsa() { @@ -662,7 +753,7 @@ mod test { } #[test] - #[cfg(any(ossl102, libressl310))] + #[cfg(any(ossl102, libressl310, boringssl))] fn rsa_oaep() { let key = include_bytes!("../test/rsa.pem"); let rsa = Rsa::private_key_from_pem(key).unwrap(); @@ -689,6 +780,53 @@ mod test { assert_eq!(pt, out); } + #[test] + fn rsa_sign() { + let key = include_bytes!("../test/rsa.pem"); + let rsa = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + + let mut ctx = PkeyCtx::new(&pkey).unwrap(); + ctx.sign_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1).unwrap(); + ctx.set_signature_md(Md::sha384()).unwrap(); + + let msg = b"hello world"; + let digest = hash(MessageDigest::sha384(), msg).unwrap(); + let mut signature = vec![]; + ctx.sign_to_vec(&digest, &mut signature).unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap(); + verifier.update(msg).unwrap(); + assert!(matches!(verifier.verify(&signature), Ok(true))); + } + + #[test] + fn rsa_sign_pss() { + let key = include_bytes!("../test/rsa.pem"); + let rsa = Rsa::private_key_from_pem(key).unwrap(); + let pkey = PKey::from_rsa(rsa).unwrap(); + + let mut ctx = PkeyCtx::new(&pkey).unwrap(); + ctx.sign_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); + ctx.set_signature_md(Md::sha384()).unwrap(); + ctx.set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)).unwrap(); + + let msg = b"hello world"; + let digest = hash(MessageDigest::sha384(), msg).unwrap(); + let mut signature = vec![]; + ctx.sign_to_vec(&digest, &mut signature).unwrap(); + + let mut verifier = Verifier::new(MessageDigest::sha384(), &pkey).unwrap(); + verifier.set_rsa_padding(Padding::PKCS1_PSS).unwrap(); + verifier + .set_rsa_pss_saltlen(RsaPssSaltlen::custom(14)) + .unwrap(); + verifier.update(msg).unwrap(); + assert!(matches!(verifier.verify(&signature), Ok(true))); + } + #[test] fn derive() { let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap(); @@ -717,7 +855,7 @@ mod test { } #[test] - #[cfg(ossl110)] + #[cfg(any(ossl110, boringssl))] fn hkdf() { let mut ctx = PkeyCtx::new_id(Id::HKDF).unwrap(); ctx.derive_init().unwrap(); @@ -798,7 +936,67 @@ mod test { let bad_data = b"Some Crypto text"; ctx.verify_init().unwrap(); - let valid = ctx.verify(bad_data, &signature).unwrap(); - assert!(!valid); + let valid = ctx.verify(bad_data, &signature); + assert!(matches!(valid, Ok(false) | Err(_))); + assert!(ErrorStack::get().errors().is_empty()); + } + + #[test] + fn verify_fail_ec() { + let key1 = + EcKey::generate(&EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap()).unwrap(); + let key1 = PKey::from_ec_key(key1).unwrap(); + + let data = b"Some Crypto Text"; + let mut ctx = PkeyCtx::new(&key1).unwrap(); + ctx.verify_init().unwrap(); + assert!(matches!(ctx.verify(data, &[0; 64]), Ok(false) | Err(_))); + assert!(ErrorStack::get().errors().is_empty()); + } + + #[test] + fn test_verify_recover() { + let key = Rsa::generate(2048).unwrap(); + let key = PKey::from_rsa(key).unwrap(); + + let digest = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + ]; + + let mut ctx = PkeyCtx::new(&key).unwrap(); + ctx.sign_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1).unwrap(); + ctx.set_signature_md(Md::sha256()).unwrap(); + let mut signature = vec![]; + ctx.sign_to_vec(&digest, &mut signature).unwrap(); + + // Attempt recovery of just the digest. + let mut ctx = PkeyCtx::new(&key).unwrap(); + ctx.verify_recover_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1).unwrap(); + ctx.set_signature_md(Md::sha256()).unwrap(); + let length = ctx.verify_recover(&signature, None).unwrap(); + let mut result_buf = vec![0; length]; + let length = ctx + .verify_recover(&signature, Some(&mut result_buf)) + .unwrap(); + assert_eq!(length, digest.len()); + // result_buf contains the digest + assert_eq!(result_buf[..length], digest); + + // Attempt recovery of teh entire DigestInfo + let mut ctx = PkeyCtx::new(&key).unwrap(); + ctx.verify_recover_init().unwrap(); + ctx.set_rsa_padding(Padding::PKCS1).unwrap(); + let length = ctx.verify_recover(&signature, None).unwrap(); + let mut result_buf = vec![0; length]; + let length = ctx + .verify_recover(&signature, Some(&mut result_buf)) + .unwrap(); + // 32-bytes of SHA256 digest + the ASN.1 DigestInfo structure == 51 bytes + assert_eq!(length, 51); + // The digest is the end of the DigestInfo structure. + assert_eq!(result_buf[length - digest.len()..length], digest); } } diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs index 68cf64b036a714db57cb670d23dced04e69eafb9..f155b12dfe651ffa6ede21ca1dfb1e3b7c75686c 100644 --- a/openssl/src/rsa.rs +++ b/openssl/src/rsa.rs @@ -581,7 +581,7 @@ impl fmt::Debug for Rsa { } cfg_if! { - if #[cfg(any(ossl110, libressl273))] { + if #[cfg(any(ossl110, libressl273, boringssl))] { use ffi::{ RSA_get0_key, RSA_get0_factors, RSA_get0_crt_params, RSA_set0_key, RSA_set0_factors, RSA_set0_crt_params, diff --git a/openssl/src/sign.rs b/openssl/src/sign.rs index 406bb42e8f44e91b6330f9993bee35b0bd6dd46f..1c770d18b79d2a4dd240d91a212c77a8f0e0273a 100644 --- a/openssl/src/sign.rs +++ b/openssl/src/sign.rs @@ -93,7 +93,7 @@ pub struct RsaPssSaltlen(c_int); impl RsaPssSaltlen { /// Returns the integer representation of `RsaPssSaltlen`. - fn as_raw(&self) -> c_int { + pub(crate) fn as_raw(&self) -> c_int { self.0 } @@ -117,10 +117,10 @@ pub struct Signer<'a> { _p: PhantomData<&'a ()>, } -unsafe impl<'a> Sync for Signer<'a> {} -unsafe impl<'a> Send for Signer<'a> {} +unsafe impl Sync for Signer<'_> {} +unsafe impl Send for Signer<'_> {} -impl<'a> Drop for Signer<'a> { +impl Drop for Signer<'_> { fn drop(&mut self) { // pkey_ctx is owned by the md_ctx, so no need to explicitly free it. unsafe { @@ -130,7 +130,7 @@ impl<'a> Drop for Signer<'a> { } #[allow(clippy::len_without_is_empty)] -impl<'a> Signer<'a> { +impl Signer<'_> { /// Creates a new `Signer`. /// /// This cannot be used with Ed25519 or Ed448 keys. Please refer to @@ -139,7 +139,7 @@ impl<'a> Signer<'a> { /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html - pub fn new(type_: MessageDigest, pkey: &'a PKeyRef) -> Result, ErrorStack> + pub fn new<'a, T>(type_: MessageDigest, pkey: &PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { @@ -154,16 +154,16 @@ impl<'a> Signer<'a> { /// OpenSSL documentation at [`EVP_DigestSignInit`]. /// /// [`EVP_DigestSignInit`]: https://www.openssl.org/docs/manmaster/man3/EVP_DigestSignInit.html - pub fn new_without_digest(pkey: &'a PKeyRef) -> Result, ErrorStack> + pub fn new_without_digest<'a, T>(pkey: &PKeyRef) -> Result, ErrorStack> where T: HasPrivate, { Self::new_intern(None, pkey) } - fn new_intern( + fn new_intern<'a, T>( type_: Option, - pkey: &'a PKeyRef, + pkey: &PKeyRef, ) -> Result, ErrorStack> where T: HasPrivate, diff --git a/openssl/src/ssl/connector.rs b/openssl/src/ssl/connector.rs index 39f729df905cb061ff23d9727be663849f50ea65..66d1bd8939f154a1163d4211316f7710e15c1b59 100644 --- a/openssl/src/ssl/connector.rs +++ b/openssl/src/ssl/connector.rs @@ -11,6 +11,7 @@ use crate::ssl::{ SslOptions, SslRef, SslStream, SslVerifyMode, }; use crate::version; +use std::net::IpAddr; const FFDHE_2048: &str = " -----BEGIN DH PARAMETERS----- @@ -177,9 +178,9 @@ impl ConnectConfiguration { /// Returns an `Ssl` configured to connect to the provided domain. /// - /// The domain is used for SNI and hostname verification if enabled. + /// The domain is used for SNI (if it is not an IP address) and hostname verification if enabled. pub fn into_ssl(mut self, domain: &str) -> Result { - if self.sni { + if self.sni && domain.parse::().is_err() { self.ssl.set_hostname(domain)?; } diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index c8648c4bcdbc13836106bc120f6deee86e80ddbc..27e817f30705358c7c5c629ef30bce33347fc387 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -72,7 +72,7 @@ use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef}; use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; use crate::ssl::error::InnerError; -use crate::stack::{Stack, StackRef}; +use crate::stack::{Stack, StackRef, Stackable}; use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; #[cfg(any(ossl102, libressl261))] @@ -599,7 +599,7 @@ impl AlpnError { /// Terminate the handshake with a fatal alert. /// /// Requires OpenSSL 1.1.0 or newer. - #[cfg(any(ossl110))] + #[cfg(ossl110)] pub const ALERT_FATAL: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL); /// Do not select a protocol, but continue the handshake. @@ -644,6 +644,17 @@ impl SslVersion { /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer. #[cfg(any(ossl111, libressl340))] pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION); + + /// DTLSv1.0 + /// + /// DTLS 1.0 corresponds to TLS 1.1. + pub const DTLS1: SslVersion = SslVersion(ffi::DTLS1_VERSION); + + /// DTLSv1.2 + /// + /// DTLS 1.2 corresponds to TLS 1.2 to harmonize versions. There was never a DTLS 1.1. + #[cfg(any(ossl102, libressl332))] + pub const DTLS1_2: SslVersion = SslVersion(ffi::DTLS1_2_VERSION); } cfg_if! { @@ -1120,7 +1131,7 @@ impl SslContextBuilder { /// Sets the minimum supported protocol version. /// - /// A value of `None` will enable protocol versions down the the lowest version supported by + /// A value of `None` will enable protocol versions down to the lowest version supported by /// OpenSSL. /// /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. @@ -1138,7 +1149,7 @@ impl SslContextBuilder { /// Sets the maximum supported protocol version. /// - /// A value of `None` will enable protocol versions down the the highest version supported by + /// A value of `None` will enable protocol versions up to the highest version supported by /// OpenSSL. /// /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. @@ -1156,7 +1167,7 @@ impl SslContextBuilder { /// Gets the minimum supported protocol version. /// - /// A value of `None` indicates that all versions down the the lowest version supported by + /// A value of `None` indicates that all versions down to the lowest version supported by /// OpenSSL are enabled. /// /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. @@ -1175,7 +1186,7 @@ impl SslContextBuilder { /// Gets the maximum supported protocol version. /// - /// A value of `None` indicates that all versions down the the highest version supported by + /// A value of `None` indicates that all versions up to the highest version supported by /// OpenSSL are enabled. /// /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer. @@ -1929,6 +1940,10 @@ impl ForeignType for SslCipher { } } +impl Stackable for SslCipher { + type StackType = ffi::stack_st_SSL_CIPHER; +} + impl Deref for SslCipher { type Target = SslCipherRef; @@ -2045,6 +2060,19 @@ impl SslCipherRef { } } +impl fmt::Debug for SslCipherRef { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "{}", self.name()) + } +} + +/// A stack of selected ciphers, and a stack of selected signalling cipher suites +#[derive(Debug)] +pub struct CipherLists { + pub suites: Stack, + pub signalling_suites: Stack, +} + foreign_type_and_impl_send_sync! { type CType = ffi::SSL_SESSION; fn drop = ffi::SSL_SESSION_free; @@ -2385,7 +2413,7 @@ impl SslRef { /// /// Requires OpenSSL 1.0.1 or 1.0.2. #[corresponds(SSL_set_tmp_ecdh_callback)] - #[cfg(any(all(ossl101, not(ossl110))))] + #[cfg(all(ossl101, not(ossl110)))] #[deprecated(note = "this function leaks memory and does not exist on newer OpenSSL versions")] pub fn set_tmp_ecdh_callback(&mut self, callback: F) where @@ -3072,6 +3100,41 @@ impl SslRef { } } + /// Decodes a slice of wire-format cipher suite specification bytes. Unsupported cipher suites + /// are ignored. + /// + /// Requires OpenSSL 1.1.1 or newer. + #[corresponds(SSL_bytes_to_cipher_list)] + #[cfg(ossl111)] + pub fn bytes_to_cipher_list( + &self, + bytes: &[u8], + isv2format: bool, + ) -> Result { + unsafe { + let ptr = bytes.as_ptr(); + let len = bytes.len(); + let mut sk = ptr::null_mut(); + let mut scsvs = ptr::null_mut(); + let res = ffi::SSL_bytes_to_cipher_list( + self.as_ptr(), + ptr, + len, + isv2format as c_int, + &mut sk, + &mut scsvs, + ); + if res == 1 { + Ok(CipherLists { + suites: Stack::from_ptr(sk), + signalling_suites: Stack::from_ptr(scsvs), + }) + } else { + Err(ErrorStack::get()) + } + } + } + /// Returns the compression methods field of the client's hello message. /// /// This can only be used inside of the client hello callback. Otherwise, `None` is returned. @@ -3223,7 +3286,7 @@ impl SslRef { /// Sets the minimum supported protocol version. /// - /// A value of `None` will enable protocol versions down the the lowest version supported by + /// A value of `None` will enable protocol versions down to the lowest version supported by /// OpenSSL. /// /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer. @@ -3241,7 +3304,7 @@ impl SslRef { /// Sets the maximum supported protocol version. /// - /// A value of `None` will enable protocol versions down the the highest version supported by + /// A value of `None` will enable protocol versions up to the highest version supported by /// OpenSSL. /// /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer. diff --git a/openssl/src/ssl/test/mod.rs b/openssl/src/ssl/test/mod.rs index 03dc89e5c36db17ae66be6a1792b69b395957849..7707af238fed1b8ff844594140e07bc6d375f9f7 100644 --- a/openssl/src/ssl/test/mod.rs +++ b/openssl/src/ssl/test/mod.rs @@ -21,10 +21,10 @@ use crate::hash::MessageDigest; use crate::ocsp::{OcspResponse, OcspResponseStatus}; use crate::pkey::PKey; use crate::srtp::SrtpProfileId; -use crate::ssl; use crate::ssl::test::server::Server; #[cfg(any(ossl110, ossl111, libressl261))] use crate::ssl::SslVersion; +use crate::ssl::{self, NameType, SslConnectorBuilder}; #[cfg(ossl111)] use crate::ssl::{ClientHelloResponse, ExtensionContext}; use crate::ssl::{ @@ -467,7 +467,7 @@ fn test_alpn_server_advertise_multiple() { } #[test] -#[cfg(any(ossl110))] +#[cfg(ossl110)] fn test_alpn_server_select_none_fatal() { let mut server = Server::builder(); server.ctx().set_alpn_select_callback(|_, client| { @@ -767,6 +767,61 @@ fn connector_can_disable_verify() { s.read_exact(&mut [0]).unwrap(); } +#[test] +fn connector_does_use_sni_with_dnsnames() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut builder = Server::builder(); + builder.ctx().set_servername_callback(|ssl, _| { + assert_eq!(ssl.servername(NameType::HOST_NAME), Some("foobar.com")); + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(()) + }); + let server = builder.build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + connector.set_ca_file("test/root-ca.pem").unwrap(); + + let s = server.connect_tcp(); + let mut s = connector + .build() + .configure() + .unwrap() + .connect("foobar.com", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + +#[test] +fn connector_doesnt_use_sni_with_ips() { + static CALLED_BACK: AtomicBool = AtomicBool::new(false); + + let mut builder = Server::builder(); + builder.ctx().set_servername_callback(|ssl, _| { + assert_eq!(ssl.servername(NameType::HOST_NAME), None); + CALLED_BACK.store(true, Ordering::SeqCst); + Ok(()) + }); + let server = builder.build(); + + let mut connector = SslConnector::builder(SslMethod::tls()).unwrap(); + // The server's cert isn't issued for 127.0.0.1 but we don't care for this test. + connector.set_verify(SslVerifyMode::NONE); + + let s = server.connect_tcp(); + let mut s = connector + .build() + .configure() + .unwrap() + .connect("127.0.0.1", s) + .unwrap(); + s.read_exact(&mut [0]).unwrap(); + + assert!(CALLED_BACK.load(Ordering::SeqCst)); +} + fn test_mozilla_server(new: fn(SslMethod) -> Result) { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let port = listener.local_addr().unwrap().port(); @@ -1403,6 +1458,9 @@ fn client_hello() { assert!(ssl.client_hello_session_id().is_some()); assert!(ssl.client_hello_ciphers().is_some()); assert!(ssl.client_hello_compression_methods().is_some()); + assert!(ssl + .bytes_to_cipher_list(ssl.client_hello_ciphers().unwrap(), ssl.client_hello_isv2()) + .is_ok()); CALLED_BACK.store(true, Ordering::SeqCst); Ok(ClientHelloResponse::SUCCESS) diff --git a/openssl/src/symm.rs b/openssl/src/symm.rs index 911a7ab2e7530ac59f3ca25f776a9402a095733f..c1dbdfee7b67c688a8a4b7d1a2ebbc061875e59b 100644 --- a/openssl/src/symm.rs +++ b/openssl/src/symm.rs @@ -142,7 +142,7 @@ impl Cipher { } /// Requires OpenSSL 1.1.0 or newer. - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_128_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_128_ocb()) } } @@ -187,7 +187,7 @@ impl Cipher { } /// Requires OpenSSL 1.1.0 or newer. - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_192_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_192_ocb()) } } @@ -237,7 +237,7 @@ impl Cipher { } /// Requires OpenSSL 1.1.0 or newer. - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] pub fn aes_256_ocb() -> Cipher { unsafe { Cipher(ffi::EVP_aes_256_ocb()) } } @@ -283,6 +283,7 @@ impl Cipher { unsafe { Cipher(ffi::EVP_des_ede3_cfb64()) } } + #[cfg(not(osslconf = "OPENSSL_NO_RC4"))] pub fn rc4() -> Cipher { unsafe { Cipher(ffi::EVP_rc4()) } } @@ -401,14 +402,14 @@ impl Cipher { } /// Determines whether the cipher is using OCB mode - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] fn is_ocb(self) -> bool { self == Cipher::aes_128_ocb() || self == Cipher::aes_192_ocb() || self == Cipher::aes_256_ocb() } - #[cfg(not(ossl110))] + #[cfg(any(not(ossl110), osslconf = "OPENSSL_NO_OCB"))] const fn is_ocb(self) -> bool { false } @@ -1421,7 +1422,7 @@ mod tests { } #[test] - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] fn test_aes_128_ocb() { let key = "000102030405060708090a0b0c0d0e0f"; let aad = "0001020304050607"; @@ -1457,7 +1458,7 @@ mod tests { } #[test] - #[cfg(ossl110)] + #[cfg(all(ossl110, not(osslconf = "OPENSSL_NO_OCB")))] fn test_aes_128_ocb_fail() { let key = "000102030405060708090a0b0c0d0e0f"; let aad = "0001020304050607"; @@ -1477,7 +1478,7 @@ mod tests { } #[test] - #[cfg(any(ossl110))] + #[cfg(ossl110)] fn test_chacha20() { let key = "0000000000000000000000000000000000000000000000000000000000000000"; let iv = "00000000000000000000000000000000"; @@ -1492,7 +1493,7 @@ mod tests { } #[test] - #[cfg(any(ossl110))] + #[cfg(ossl110)] fn test_chacha20_poly1305() { let key = "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"; let iv = "070000004041424344454647"; diff --git a/openssl/src/x509/extension.rs b/openssl/src/x509/extension.rs index f04d227960adfcba0fe1cc34819f33fc5d256c0d..11e0151530878ec020e2f22979711c28737b9e14 100644 --- a/openssl/src/x509/extension.rs +++ b/openssl/src/x509/extension.rs @@ -67,6 +67,9 @@ impl BasicConstraints { } /// Return the `BasicConstraints` extension as an `X509Extension`. + // Temporarily silence the deprecation warning - this should be ported to + // `X509Extension::new_internal`. + #[allow(deprecated)] pub fn build(&self) -> Result { let mut value = String::new(); if self.critical { @@ -183,6 +186,9 @@ impl KeyUsage { } /// Return the `KeyUsage` extension as an `X509Extension`. + // Temporarily silence the deprecation warning - this should be ported to + // `X509Extension::new_internal`. + #[allow(deprecated)] pub fn build(&self) -> Result { let mut value = String::new(); let mut first = true; @@ -346,6 +352,9 @@ impl SubjectKeyIdentifier { } /// Return a `SubjectKeyIdentifier` extension as an `X509Extension`. + // Temporarily silence the deprecation warning - this should be ported to + // `X509Extension::new_internal`. + #[allow(deprecated)] pub fn build(&self, ctx: &X509v3Context<'_>) -> Result { let mut value = String::new(); let mut first = true; @@ -398,6 +407,9 @@ impl AuthorityKeyIdentifier { } /// Return a `AuthorityKeyIdentifier` extension as an `X509Extension`. + // Temporarily silence the deprecation warning - this should be ported to + // `X509Extension::new_internal`. + #[allow(deprecated)] pub fn build(&self, ctx: &X509v3Context<'_>) -> Result { let mut value = String::new(); let mut first = true; @@ -422,6 +434,7 @@ enum RustGeneralName { Uri(String), Ip(String), Rid(String), + OtherName(Asn1Object, Vec), } /// An extension that allows additional identities to be bound to the subject @@ -494,12 +507,21 @@ impl SubjectAlternativeName { /// Sets the `otherName` flag. /// - /// Not currently actually supported, always panics. - #[deprecated = "other_name is deprecated and always panics. Please file a bug if you have a use case for this."] + /// Not currently actually supported, always panics. Please use other_name2 + #[deprecated = "other_name is deprecated and always panics. Please use other_name2."] pub fn other_name(&mut self, _other_name: &str) -> &mut SubjectAlternativeName { - unimplemented!( - "This has not yet been adapted for the new internals. File a bug if you need this." - ); + unimplemented!("This has not yet been adapted for the new internals. Use other_name2."); + } + + /// Sets the `otherName` flag. + /// + /// `content` must be a valid der encoded ASN1_TYPE + /// + /// If you want to add just a ia5string use `other_name_ia5string` + pub fn other_name2(&mut self, oid: Asn1Object, content: &[u8]) -> &mut SubjectAlternativeName { + self.items + .push(RustGeneralName::OtherName(oid, content.into())); + self } /// Return a `SubjectAlternativeName` extension as an `X509Extension`. @@ -514,6 +536,9 @@ impl SubjectAlternativeName { GeneralName::new_ip(s.parse().map_err(|_| ErrorStack::get())?)? } RustGeneralName::Rid(s) => GeneralName::new_rid(Asn1Object::from_str(s)?)?, + RustGeneralName::OtherName(oid, content) => { + GeneralName::new_other_name(oid.clone(), content)? + } }; stack.push(gn)?; } diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 5b5591875018f56a8672e22acc5f34737b58ed31..4325b132e3f35e71c9c6dc7858aa295babcbb960 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -24,8 +24,8 @@ use std::slice; use std::str; use crate::asn1::{ - Asn1BitStringRef, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, Asn1StringRef, Asn1TimeRef, - Asn1Type, + Asn1BitStringRef, Asn1Enumerated, Asn1IntegerRef, Asn1Object, Asn1ObjectRef, + Asn1OctetStringRef, Asn1StringRef, Asn1TimeRef, Asn1Type, }; use crate::bio::MemBioSlice; use crate::conf::ConfRef; @@ -50,6 +50,16 @@ pub mod store; #[cfg(test)] mod tests; +/// A type of X509 extension. +/// +/// # Safety +/// The value of NID and Output must match those in OpenSSL so that +/// `Output::from_ptr_opt(*_get_ext_d2i(*, NID, ...))` is valid. +pub unsafe trait ExtensionType { + const NID: Nid; + type Output: ForeignType; +} + foreign_type_and_impl_send_sync! { type CType = ffi::X509_STORE_CTX; fn drop = ffi::X509_STORE_CTX_free; @@ -391,7 +401,10 @@ impl X509Ref { /// Returns the hash of the certificates subject #[corresponds(X509_subject_name_hash)] pub fn subject_name_hash(&self) -> u32 { - unsafe { ffi::X509_subject_name_hash(self.as_ptr()) as u32 } + #[allow(clippy::unnecessary_cast)] + unsafe { + ffi::X509_subject_name_hash(self.as_ptr()) as u32 + } } /// Returns this certificate's issuer name. @@ -406,7 +419,10 @@ impl X509Ref { /// Returns the hash of the certificates issuer #[corresponds(X509_issuer_name_hash)] pub fn issuer_name_hash(&self) -> u32 { - unsafe { ffi::X509_issuer_name_hash(self.as_ptr()) as u32 } + #[allow(clippy::unnecessary_cast)] + unsafe { + ffi::X509_issuer_name_hash(self.as_ptr()) as u32 + } } /// Returns this certificate's subject alternative name entries, if they exist. @@ -423,6 +439,20 @@ impl X509Ref { } } + /// Returns this certificate's CRL distribution points, if they exist. + #[corresponds(X509_get_ext_d2i)] + pub fn crl_distribution_points(&self) -> Option> { + unsafe { + let stack = ffi::X509_get_ext_d2i( + self.as_ptr(), + ffi::NID_crl_distribution_points, + ptr::null_mut(), + ptr::null_mut(), + ); + Stack::from_ptr_opt(stack as *mut _) + } + } + /// Returns this certificate's issuer alternative name entries, if they exist. #[corresponds(X509_get_ext_d2i)] pub fn issuer_alt_names(&self) -> Option> { @@ -453,6 +483,54 @@ impl X509Ref { } } + /// Retrieves the path length extension from a certificate, if it exists. + #[corresponds(X509_get_pathlen)] + #[cfg(ossl110)] + pub fn pathlen(&self) -> Option { + let v = unsafe { ffi::X509_get_pathlen(self.as_ptr()) }; + u32::try_from(v).ok() + } + + /// Returns this certificate's subject key id, if it exists. + #[corresponds(X509_get0_subject_key_id)] + #[cfg(ossl110)] + pub fn subject_key_id(&self) -> Option<&Asn1OctetStringRef> { + unsafe { + let data = ffi::X509_get0_subject_key_id(self.as_ptr()); + Asn1OctetStringRef::from_const_ptr_opt(data) + } + } + + /// Returns this certificate's authority key id, if it exists. + #[corresponds(X509_get0_authority_key_id)] + #[cfg(ossl110)] + pub fn authority_key_id(&self) -> Option<&Asn1OctetStringRef> { + unsafe { + let data = ffi::X509_get0_authority_key_id(self.as_ptr()); + Asn1OctetStringRef::from_const_ptr_opt(data) + } + } + + /// Returns this certificate's authority issuer name entries, if they exist. + #[corresponds(X509_get0_authority_issuer)] + #[cfg(ossl111d)] + pub fn authority_issuer(&self) -> Option<&StackRef> { + unsafe { + let stack = ffi::X509_get0_authority_issuer(self.as_ptr()); + StackRef::from_const_ptr_opt(stack) + } + } + + /// Returns this certificate's authority serial number, if it exists. + #[corresponds(X509_get0_authority_serial)] + #[cfg(ossl111d)] + pub fn authority_serial(&self) -> Option<&Asn1IntegerRef> { + unsafe { + let r = ffi::X509_get0_authority_serial(self.as_ptr()); + Asn1IntegerRef::from_const_ptr_opt(r) + } + } + #[corresponds(X509_get_pubkey)] pub fn public_key(&self) -> Result, ErrorStack> { unsafe { @@ -548,6 +626,7 @@ impl X509Ref { /// Note that `0` return value stands for version 1, `1` for version 2 and so on. #[corresponds(X509_get_version)] #[cfg(ossl110)] + #[allow(clippy::unnecessary_cast)] pub fn version(&self) -> i32 { unsafe { ffi::X509_get_version(self.as_ptr()) as i32 } } @@ -811,6 +890,13 @@ impl X509Extension { /// mini-language that can read arbitrary files. /// /// See the extension module for builder types which will construct certain common extensions. + /// + /// This function is deprecated, `X509Extension::new_from_der` or the + /// types in `x509::extension` should be used in its place. + #[deprecated( + note = "Use x509::extension types or new_from_der instead", + since = "0.10.51" + )] pub fn new( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, @@ -856,6 +942,13 @@ impl X509Extension { /// mini-language that can read arbitrary files. /// /// See the extension module for builder types which will construct certain common extensions. + /// + /// This function is deprecated, `X509Extension::new_from_der` or the + /// types in `x509::extension` should be used in its place. + #[deprecated( + note = "Use x509::extension types or new_from_der instead", + since = "0.10.51" + )] pub fn new_nid( conf: Option<&ConfRef>, context: Option<&X509v3Context<'_>>, @@ -890,6 +983,31 @@ impl X509Extension { } } + /// Constructs a new X509 extension value from its OID, whether it's + /// critical, and its DER contents. + /// + /// The extent structure of the DER value will vary based on the + /// extension type, and can generally be found in the RFC defining the + /// extension. + /// + /// For common extension types, there are Rust APIs provided in + /// `openssl::x509::extensions` which are more ergonomic. + pub fn new_from_der( + oid: &Asn1ObjectRef, + critical: bool, + der_contents: &Asn1OctetStringRef, + ) -> Result { + unsafe { + cvt_p(ffi::X509_EXTENSION_create_by_OBJ( + ptr::null_mut(), + oid.as_ptr(), + critical as _, + der_contents.as_ptr(), + )) + .map(X509Extension) + } + } + pub(crate) unsafe fn new_internal( nid: Nid, critical: bool, @@ -905,6 +1023,10 @@ impl X509Extension { /// /// This method modifies global state without locking and therefore is not thread safe #[corresponds(X509V3_EXT_add_alias)] + #[deprecated( + note = "Use x509::extension types or new_from_der and then this is not necessary", + since = "0.10.51" + )] pub unsafe fn add_alias(to: Nid, from: Nid) -> Result<(), ErrorStack> { ffi::init(); cvt(ffi::X509V3_EXT_add_alias(to.as_raw(), from.as_raw())).map(|_| ()) @@ -955,13 +1077,13 @@ impl X509NameBuilder { pub fn append_entry_by_text(&mut self, field: &str, value: &str) -> Result<(), ErrorStack> { unsafe { let field = CString::new(field).unwrap(); - assert!(value.len() <= c_int::max_value() as usize); + assert!(value.len() <= crate::SLenType::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_txt( self.0.as_ptr(), field.as_ptr() as *mut _, ffi::MBSTRING_UTF8, value.as_ptr(), - value.len() as c_int, + value.len() as crate::SLenType, -1, 0, )) @@ -982,13 +1104,13 @@ impl X509NameBuilder { ) -> Result<(), ErrorStack> { unsafe { let field = CString::new(field).unwrap(); - assert!(value.len() <= c_int::max_value() as usize); + assert!(value.len() <= crate::SLenType::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_txt( self.0.as_ptr(), field.as_ptr() as *mut _, ty.as_raw(), value.as_ptr(), - value.len() as c_int, + value.len() as crate::SLenType, -1, 0, )) @@ -1003,13 +1125,13 @@ impl X509NameBuilder { /// [`X509_NAME_add_entry_by_NID`]: https://www.openssl.org/docs/manmaster/crypto/X509_NAME_add_entry_by_NID.html pub fn append_entry_by_nid(&mut self, field: Nid, value: &str) -> Result<(), ErrorStack> { unsafe { - assert!(value.len() <= c_int::max_value() as usize); + assert!(value.len() <= crate::SLenType::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_NID( self.0.as_ptr(), field.as_raw(), ffi::MBSTRING_UTF8, value.as_ptr() as *mut _, - value.len() as c_int, + value.len() as crate::SLenType, -1, 0, )) @@ -1029,13 +1151,13 @@ impl X509NameBuilder { ty: Asn1Type, ) -> Result<(), ErrorStack> { unsafe { - assert!(value.len() <= c_int::max_value() as usize); + assert!(value.len() <= crate::SLenType::max_value() as usize); cvt(ffi::X509_NAME_add_entry_by_NID( self.0.as_ptr(), field.as_raw(), ty.as_raw(), value.as_ptr() as *mut _, - value.len() as c_int, + value.len() as crate::SLenType, -1, 0, )) @@ -1428,6 +1550,7 @@ impl X509ReqRef { /// This corresponds to [`X509_REQ_get_version`] /// /// [`X509_REQ_get_version`]: https://www.openssl.org/docs/manmaster/crypto/X509_REQ_get_version.html + #[allow(clippy::unnecessary_cast)] pub fn version(&self) -> i32 { unsafe { X509_REQ_get_version(self.as_ptr()) as i32 } } @@ -1481,13 +1604,41 @@ impl X509ReqRef { } } +/// The reason that a certificate was revoked. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct CrlReason(c_int); + +#[allow(missing_docs)] // no need to document the constants +impl CrlReason { + pub const UNSPECIFIED: CrlReason = CrlReason(ffi::CRL_REASON_UNSPECIFIED); + pub const KEY_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_KEY_COMPROMISE); + pub const CA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_CA_COMPROMISE); + pub const AFFILIATION_CHANGED: CrlReason = CrlReason(ffi::CRL_REASON_AFFILIATION_CHANGED); + pub const SUPERSEDED: CrlReason = CrlReason(ffi::CRL_REASON_SUPERSEDED); + pub const CESSATION_OF_OPERATION: CrlReason = CrlReason(ffi::CRL_REASON_CESSATION_OF_OPERATION); + pub const CERTIFICATE_HOLD: CrlReason = CrlReason(ffi::CRL_REASON_CERTIFICATE_HOLD); + pub const REMOVE_FROM_CRL: CrlReason = CrlReason(ffi::CRL_REASON_REMOVE_FROM_CRL); + pub const PRIVILEGE_WITHDRAWN: CrlReason = CrlReason(ffi::CRL_REASON_PRIVILEGE_WITHDRAWN); + pub const AA_COMPROMISE: CrlReason = CrlReason(ffi::CRL_REASON_AA_COMPROMISE); + + /// Constructs an `CrlReason` from a raw OpenSSL value. + pub const fn from_raw(value: c_int) -> Self { + CrlReason(value) + } + + /// Returns the raw OpenSSL value represented by this type. + pub const fn as_raw(&self) -> c_int { + self.0 + } +} + foreign_type_and_impl_send_sync! { type CType = ffi::X509_REVOKED; fn drop = ffi::X509_REVOKED_free; - /// An `X509` certificate request. + /// An `X509` certificate revocation status. pub struct X509Revoked; - /// Reference to `X509Crl`. + /// Reference to `X509Revoked`. pub struct X509RevokedRef; } @@ -1513,6 +1664,13 @@ impl X509RevokedRef { ffi::i2d_X509_REVOKED } + /// Copies the entry to a new `X509Revoked`. + #[corresponds(X509_NAME_dup)] + #[cfg(any(boringssl, ossl110, libressl270))] + pub fn to_owned(&self) -> Result { + unsafe { cvt_p(ffi::X509_REVOKED_dup(self.as_ptr())).map(|n| X509Revoked::from_ptr(n)) } + } + /// Get the date that the certificate was revoked #[corresponds(X509_REVOKED_get0_revocationDate)] pub fn revocation_date(&self) -> &Asn1TimeRef { @@ -1532,13 +1690,67 @@ impl X509RevokedRef { Asn1IntegerRef::from_ptr(r as *mut _) } } + + /// Get the criticality and value of an extension. + /// + /// This returns None if the extension is not present or occurs multiple times. + #[corresponds(X509_REVOKED_get_ext_d2i)] + pub fn extension(&self) -> Result, ErrorStack> { + let mut critical = -1; + let out = unsafe { + // SAFETY: self.as_ptr() is a valid pointer to an X509_REVOKED. + let ext = ffi::X509_REVOKED_get_ext_d2i( + self.as_ptr(), + T::NID.as_raw(), + &mut critical as *mut _, + ptr::null_mut(), + ); + // SAFETY: Extensions's contract promises that the type returned by + // OpenSSL here is T::Output. + T::Output::from_ptr_opt(ext as *mut _) + }; + match (critical, out) { + (0, Some(out)) => Ok(Some((false, out))), + (1, Some(out)) => Ok(Some((true, out))), + // -1 means the extension wasn't found, -2 means multiple were found. + (-1 | -2, _) => Ok(None), + // A critical value of 0 or 1 suggests success, but a null pointer + // was returned so something went wrong. + (0 | 1, None) => Err(ErrorStack::get()), + (c_int::MIN..=-2 | 2.., _) => panic!("OpenSSL should only return -2, -1, 0, or 1 for an extension's criticality but it returned {}", critical), + } + } +} + +/// The CRL entry extension identifying the reason for revocation see [`CrlReason`], +/// this is as defined in RFC 5280 Section 5.3.1. +pub enum ReasonCode {} + +// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC +// and in OpenSSL. +unsafe impl ExtensionType for ReasonCode { + const NID: Nid = Nid::from_raw(ffi::NID_crl_reason); + + type Output = Asn1Enumerated; +} + +/// The CRL entry extension identifying the issuer of a certificate used in +/// indirect CRLs, as defined in RFC 5280 Section 5.3.3. +pub enum CertificateIssuer {} + +// SAFETY: CertificateIssuer is defined to be a stack of GeneralName in the RFC +// and in OpenSSL. +unsafe impl ExtensionType for CertificateIssuer { + const NID: Nid = Nid::from_raw(ffi::NID_certificate_issuer); + + type Output = Stack; } foreign_type_and_impl_send_sync! { type CType = ffi::X509_CRL; fn drop = ffi::X509_CRL_free; - /// An `X509` certificate request. + /// An `X509` certificate revocation list. pub struct X509Crl; /// Reference to `X509Crl`. pub struct X509CrlRef; @@ -1842,6 +2054,37 @@ impl GeneralName { Ok(GeneralName::from_ptr(gn)) } } + + pub(crate) fn new_other_name( + oid: Asn1Object, + value: &Vec, + ) -> Result { + unsafe { + ffi::init(); + + let typ = cvt_p(ffi::d2i_ASN1_TYPE( + ptr::null_mut(), + &mut value.as_ptr().cast(), + value.len().try_into().unwrap(), + ))?; + + let gn = cvt_p(ffi::GENERAL_NAME_new())?; + (*gn).type_ = ffi::GEN_OTHERNAME; + + if let Err(e) = cvt(ffi::GENERAL_NAME_set0_othername( + gn, + oid.as_ptr().cast(), + typ, + )) { + ffi::GENERAL_NAME_free(gn); + return Err(e); + } + + mem::forget(oid); + + Ok(GeneralName::from_ptr(gn)) + } + } } impl GeneralNameRef { @@ -1872,6 +2115,22 @@ impl GeneralNameRef { self.ia5_string(ffi::GEN_EMAIL) } + /// Returns the contents of this `GeneralName` if it is a `directoryName`. + pub fn directory_name(&self) -> Option<&X509NameRef> { + unsafe { + if (*self.as_ptr()).type_ != ffi::GEN_DIRNAME { + return None; + } + + #[cfg(boringssl)] + let d = (*self.as_ptr()).d.ptr; + #[cfg(not(boringssl))] + let d = (*self.as_ptr()).d; + + Some(X509NameRef::from_const_ptr(d as *const _)) + } + } + /// Returns the contents of this `GeneralName` if it is a `dNSName`. pub fn dnsname(&self) -> Option<&str> { self.ia5_string(ffi::GEN_DNS) @@ -1927,6 +2186,49 @@ impl Stackable for GeneralName { type StackType = ffi::stack_st_GENERAL_NAME; } +foreign_type_and_impl_send_sync! { + type CType = ffi::DIST_POINT; + fn drop = ffi::DIST_POINT_free; + + /// A `X509` distribution point. + pub struct DistPoint; + /// Reference to `DistPoint`. + pub struct DistPointRef; +} + +impl DistPointRef { + /// Returns the name of this distribution point if it exists + pub fn distpoint(&self) -> Option<&DistPointNameRef> { + unsafe { DistPointNameRef::from_const_ptr_opt((*self.as_ptr()).distpoint) } + } +} + +foreign_type_and_impl_send_sync! { + type CType = ffi::DIST_POINT_NAME; + fn drop = ffi::DIST_POINT_NAME_free; + + /// A `X509` distribution point. + pub struct DistPointName; + /// Reference to `DistPointName`. + pub struct DistPointNameRef; +} + +impl DistPointNameRef { + /// Returns the contents of this DistPointName if it is a fullname. + pub fn fullname(&self) -> Option<&StackRef> { + unsafe { + if (*self.as_ptr()).type_ != 0 { + return None; + } + StackRef::from_const_ptr_opt((*self.as_ptr()).name.fullname) + } + } +} + +impl Stackable for DistPoint { + type StackType = ffi::stack_st_DIST_POINT; +} + foreign_type_and_impl_send_sync! { type CType = ffi::ACCESS_DESCRIPTION; fn drop = ffi::ACCESS_DESCRIPTION_free; diff --git a/openssl/src/x509/store.rs b/openssl/src/x509/store.rs index c67490b98cefa009e9e8e11bcfe2fc1504288e01..a90bf3515f60c469490f4beb9cbef445c2cdd83c 100644 --- a/openssl/src/x509/store.rs +++ b/openssl/src/x509/store.rs @@ -42,13 +42,13 @@ //! ``` use cfg_if::cfg_if; -use foreign_types::{ForeignType, ForeignTypeRef}; +use foreign_types::ForeignTypeRef; use std::mem; use crate::error::ErrorStack; #[cfg(not(boringssl))] use crate::ssl::SslFiletype; -use crate::stack::{Stack, StackRef}; +use crate::stack::StackRef; #[cfg(any(ossl102, libressl261))] use crate::x509::verify::{X509VerifyFlags, X509VerifyParamRef}; use crate::x509::{X509Object, X509PurposeId, X509}; @@ -260,24 +260,10 @@ foreign_type_and_impl_send_sync! { impl X509StoreRef { /// Get a reference to the cache of certificates in this store. - /// - /// This method is deprecated. It is **unsound** and will be removed in a - /// future version of rust-openssl. `X509StoreRef::all_certificates` - /// should be used instead. - #[deprecated( - note = "This method is unsound, and will be removed in a future version of rust-openssl. X509StoreRef::all_certificates should be used instead." - )] #[corresponds(X509_STORE_get0_objects)] pub fn objects(&self) -> &StackRef { unsafe { StackRef::from_ptr(X509_STORE_get0_objects(self.as_ptr())) } } - - /// Returns a stack of all the certificates in this store. - #[corresponds(X509_STORE_get1_all_certs)] - #[cfg(ossl300)] - pub fn all_certificates(&self) -> Stack { - unsafe { Stack::from_ptr(ffi::X509_STORE_get1_all_certs(self.as_ptr())) } - } } cfg_if! { diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs index 81cb69951aca5335b651f96823bd59e4527c3c7e..da3ce2fed20c9a328071a6699f8f16ebc8a87236 100644 --- a/openssl/src/x509/tests.rs +++ b/openssl/src/x509/tests.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; -use crate::asn1::Asn1Time; +use crate::asn1::{Asn1Object, Asn1OctetString, Asn1Time}; use crate::bn::{BigNum, MsbOption}; use crate::hash::MessageDigest; use crate::nid::Nid; @@ -18,19 +18,24 @@ use crate::x509::store::X509Lookup; use crate::x509::store::X509StoreBuilder; #[cfg(any(ossl102, libressl261))] use crate::x509::verify::{X509VerifyFlags, X509VerifyParam}; -#[cfg(ossl110)] -use crate::x509::X509Builder; #[cfg(ossl102)] use crate::x509::X509PurposeId; #[cfg(any(ossl102, libressl261))] use crate::x509::X509PurposeRef; +#[cfg(ossl110)] +use crate::x509::{CrlReason, X509Builder}; use crate::x509::{ CrlStatus, X509Crl, X509Extension, X509Name, X509Req, X509StoreContext, X509VerifyResult, X509, }; + +#[cfg(ossl110)] +use foreign_types::ForeignType; use hex::{self, FromHex}; #[cfg(any(ossl102, libressl261))] use libc::time_t; +use super::{CertificateIssuer, ReasonCode}; + fn pkey() -> PKey { let rsa = Rsa::generate(2048).unwrap(); PKey::from_rsa(rsa).unwrap() @@ -166,6 +171,70 @@ fn test_subject_alt_name() { assert_eq!(Some("http://www.example.com"), subject_alt_names[4].uri()); } +#[test] +#[cfg(ossl110)] +fn test_retrieve_pathlen() { + let cert = include_bytes!("../../test/root-ca.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert_eq!(cert.pathlen(), None); + + let cert = include_bytes!("../../test/intermediate-ca.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert_eq!(cert.pathlen(), Some(0)); + + let cert = include_bytes!("../../test/alt_name_cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert_eq!(cert.pathlen(), None); +} + +#[test] +#[cfg(ossl110)] +fn test_subject_key_id() { + let cert = include_bytes!("../../test/certv3.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let subject_key_id = cert.subject_key_id().unwrap(); + assert_eq!( + subject_key_id.as_slice(), + &b"\xB6\x73\x2F\x61\xA5\x4B\xA1\xEF\x48\x2C\x15\xB1\x9F\xF3\xDC\x34\x2F\xBC\xAC\x30"[..] + ); +} + +#[test] +#[cfg(ossl110)] +fn test_authority_key_id() { + let cert = include_bytes!("../../test/certv3.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let authority_key_id = cert.authority_key_id().unwrap(); + assert_eq!( + authority_key_id.as_slice(), + &b"\x6C\xD3\xA5\x03\xAB\x0D\x5F\x2C\xC9\x8D\x8A\x9C\x88\xA7\x88\x77\xB8\x37\xFD\x9A"[..] + ); +} + +#[test] +#[cfg(ossl111d)] +fn test_authority_issuer_and_serial() { + let cert = include_bytes!("../../test/authority_key_identifier.pem"); + let cert = X509::from_pem(cert).unwrap(); + + let authority_issuer = cert.authority_issuer().unwrap(); + assert_eq!(1, authority_issuer.len()); + let dn = authority_issuer[0].directory_name().unwrap(); + let mut o = dn.entries_by_nid(Nid::ORGANIZATIONNAME); + let o = o.next().unwrap().data().as_utf8().unwrap(); + assert_eq!(o.as_bytes(), b"PyCA"); + let mut cn = dn.entries_by_nid(Nid::COMMONNAME); + let cn = cn.next().unwrap().data().as_utf8().unwrap(); + assert_eq!(cn.as_bytes(), b"cryptography.io"); + + let authority_serial = cert.authority_serial().unwrap(); + let serial = authority_serial.to_bn().unwrap(); + let expected = BigNum::from_u32(3).unwrap(); + assert_eq!(serial, expected); +} + #[test] fn test_subject_alt_name_iter() { let cert = include_bytes!("../../test/alt_name_cert.pem"); @@ -288,6 +357,8 @@ fn x509_builder() { } #[test] +// This tests `X509Extension::new`, even though its deprecated. +#[allow(deprecated)] fn x509_extension_new() { assert!(X509Extension::new(None, None, "crlDistributionPoints", "section").is_err()); assert!(X509Extension::new(None, None, "proxyCertInfo", "").is_err()); @@ -295,6 +366,20 @@ fn x509_extension_new() { assert!(X509Extension::new(None, None, "subjectAltName", "dirName:section").is_err()); } +#[test] +fn x509_extension_new_from_der() { + let ext = X509Extension::new_from_der( + &Asn1Object::from_str("2.5.29.19").unwrap(), + true, + &Asn1OctetString::new_from_bytes(b"\x30\x03\x01\x01\xff").unwrap(), + ) + .unwrap(); + assert_eq!( + ext.to_der().unwrap(), + b"0\x0f\x06\x03U\x1d\x13\x01\x01\xff\x04\x050\x03\x01\x01\xff" + ); +} + #[test] fn x509_extension_to_der() { let builder = X509::builder().unwrap(); @@ -611,6 +696,42 @@ fn test_load_crl() { ); } +#[test] +fn test_crl_entry_extensions() { + let crl = include_bytes!("../../test/entry_extensions.crl"); + let crl = X509Crl::from_pem(crl).unwrap(); + + let revoked_certs = crl.get_revoked().unwrap(); + let entry = &revoked_certs[0]; + + let (critical, issuer) = entry + .extension::() + .unwrap() + .expect("Certificate issuer extension should be present"); + assert!(critical, "Certificate issuer extension is critical"); + assert_eq!(issuer.len(), 1, "Certificate issuer should have one entry"); + let issuer = issuer[0] + .directory_name() + .expect("Issuer should be a directory name"); + assert_eq!( + format!("{:?}", issuer), + r#"[countryName = "GB", commonName = "Test CA"]"# + ); + + // reason_code can't be inspected without ossl110 + #[allow(unused_variables)] + let (critical, reason_code) = entry + .extension::() + .unwrap() + .expect("Reason code extension should be present"); + assert!(!critical, "Reason code extension is not critical"); + #[cfg(ossl110)] + assert_eq!( + CrlReason::KEY_COMPROMISE, + CrlReason::from_raw(reason_code.get_i64().unwrap() as ffi::c_int) + ); +} + #[test] fn test_save_subject_der() { let cert = include_bytes!("../../test/cert.pem"); @@ -987,17 +1108,54 @@ fn ipv6_as_subject_alternative_name_is_formatted_in_debug() { ]); } +#[cfg(ossl110)] #[test] -#[cfg(ossl300)] -fn test_store_all_certificates() { - let cert = include_bytes!("../../test/cert.pem"); +fn other_name_as_subject_alternative_name() { + let oid = Asn1Object::from_str("1.3.6.1.5.5.7.8.11").unwrap(); + // this is the hex representation of "test" encoded as a ia5string + let content = [0x16, 0x04, 0x74, 0x65, 0x73, 0x74]; + + let mut builder = X509Builder::new().unwrap(); + let san = SubjectAlternativeName::new() + .other_name2(oid, &content) + .build(&builder.x509v3_context(None, None)) + .unwrap(); + builder.append_extension(san).unwrap(); + let cert = builder.build(); + let general_name = cert + .subject_alt_names() + .into_iter() + .flatten() + .next() + .unwrap(); + unsafe { + assert_eq!((*general_name.as_ptr()).type_, 0); + } +} + +#[test] +fn test_dist_point() { + let cert = include_bytes!("../../test/certv3.pem"); let cert = X509::from_pem(cert).unwrap(); - let store = { - let mut b = X509StoreBuilder::new().unwrap(); - b.add_cert(cert).unwrap(); - b.build() - }; + let dps = cert.crl_distribution_points().unwrap(); + let dp = dps.get(0).unwrap(); + let dp_nm = dp.distpoint().unwrap(); + let dp_gns = dp_nm.fullname().unwrap(); + let dp_gn = dp_gns.get(0).unwrap(); + assert_eq!(dp_gn.uri().unwrap(), "http://example.com/crl.pem"); + + let dp = dps.get(1).unwrap(); + let dp_nm = dp.distpoint().unwrap(); + let dp_gns = dp_nm.fullname().unwrap(); + let dp_gn = dp_gns.get(0).unwrap(); + assert_eq!(dp_gn.uri().unwrap(), "http://example.com/crl2.pem"); + assert!(dps.get(2).is_none()) +} - assert_eq!(store.all_certificates().len(), 1); -} \ No newline at end of file +#[test] +fn test_dist_point_null() { + let cert = include_bytes!("../../test/cert.pem"); + let cert = X509::from_pem(cert).unwrap(); + assert!(cert.crl_distribution_points().is_none()); +} diff --git a/openssl/test/authority_key_identifier.pem b/openssl/test/authority_key_identifier.pem new file mode 100644 index 0000000000000000000000000000000000000000..cbe9169fc992f420d2a8a786d96c54ada9a1bc90 --- /dev/null +++ b/openssl/test/authority_key_identifier.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDIjCCAgqgAwIBAgIBAzANBgkqhkiG9w0BAQUFADApMQ0wCwYDVQQKDARQeUNB +MRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW8wHhcNMTUwNTAzMDk0OTU2WhcNMTYw +NTAyMDk0OTU2WjApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFw +aHkuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCadi1UZioxdnP +ajqlRZHeKsSxvXXhgrWvlt91P3gV0dBThRFhJsLOhjNLz6PO6KeRbjz9GhTA2hdk +xtIpXrjvTv9dEJ1/k0xebsHWgFC43aTlgekw0U4cMwMe5NGeeg1tfzbJwldIN+cK +vabc08ADlkmM6DMnUArkzA2yii0DErRFMSIGrkDr6E9puord3h6Mh8Jfnc3TDAq8 +Qo1DI2XM7oFSWNfecQ9KbIC5wzzT+7Shoyz7QmCk/XhRzt8Xcfc3yAXIwazvLf8b +YP1auaSG11a5E+w6onj91h8UHKKOXu+rdq5YYPZ+qUYpxA7ZJ/VAGadMulYbXaO8 +Syi39HTpAgMBAAGjVTBTMFEGA1UdIwRKMEiAFDlFPso9Yh3qhkn2WqtAt6RwmPHs +oS2kKzApMQ0wCwYDVQQKDARQeUNBMRgwFgYDVQQDDA9jcnlwdG9ncmFwaHkuaW+C +AQMwDQYJKoZIhvcNAQEFBQADggEBAFbZYy6aZJUK/f7nJx2Rs/ht6hMbM32/RoXZ +JGbYapNVqVu/vymcfc/se3FHS5OVmPsnRlo/FIKDn/r5DGl73Sn/FvDJiLJZFucT +msyYuHZ+ZRYWzWmN2fcB3cfxj0s3qps6f5OoCOqoINOSe4HRGlw4X9keZSD+3xAt +vHNwQdlPC7zWbPdrzLT+FqR0e/O81vFJJS6drHJWqPcR3NQVtZw+UF7A/HKwbfeL +Nu2zj6165hzOi9HUxa2/mPr/eLUUV1sTzXp2+TFjt3rVCjW1XnpMLdwNBHzjpyAB +dTOX3iw0+BPy3s2jtnCW1PLpc74kvSTaBwhg74sq39EXfIKax00= +-----END CERTIFICATE----- diff --git a/openssl/test/certv3.pem b/openssl/test/certv3.pem new file mode 100644 index 0000000000000000000000000000000000000000..819409164d686cc89cfb01522c03b4e770b980a0 --- /dev/null +++ b/openssl/test/certv3.pem @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDwTCCAqmgAwIBAgIUDeCGNunyJfBd3U/qUtmCcvbMyZwwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMzAxMjMxMzMzNTJaFw0zMzAx +MjAxMzMzNTJaMFoxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmZvb2Jh +ci5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo9CWMRLMXo1CF +/iORh9B4NhtJF/8tR9PlG95sNvyWuQQ/8jfev+8zErplxfLkt0pJqcoiZG8g9NU0 +kU6o5T+/1QgZclCAoZaS0Jqxmoo2Yk/1Qsj16pnMBc10uSDk6V9aJSX1vKwONVNS +wiHA1MhX+i7Wf7/K0niq+k7hOkhleFkWgZtUq41gXh1VfOugka7UktYnk9mrBbAM +jmaloZNn2pMMAQxVg4ThiLm3zvuWqvXASWzUZc7IAd1GbN4AtDuhs252eqE9E4iT +Hk7F14wAS1JWqv666hReGHrmZJGx0xQTM9vPD1HN5t2U3KTfhO/mTlAUWVyg9tCt +OzboKgs1AgMBAAGjgZMwgZAwTgYDVR0fBEcwRTAgoB6gHIYaaHR0cDovL2V4YW1w +bGUuY29tL2NybC5wZW0wIaAfoB2GG2h0dHA6Ly9leGFtcGxlLmNvbS9jcmwyLnBl +bTAdBgNVHQ4EFgQUtnMvYaVLoe9ILBWxn/PcNC+8rDAwHwYDVR0jBBgwFoAUbNOl +A6sNXyzJjYqciKeId7g3/ZowDQYJKoZIhvcNAQELBQADggEBAJZyk6Eo4p3JIyOt +7t6ET3K18BKvlRilze+zrGkaQYvKRsP6YzbZWgcIq59hy5VeFCX5O2WP91CPG3MU +I9eRiih66/ry3G4I8QEdpRKnn0N5unbGjb5qPT5wXrhU4IO+vn3sGZGM4uIM1/3K +N/bOh9CTsu9YqrdHSGeDyNzCy/XZ/j5bP4aNm31ZDNCZDFsbjr3/yTLcpHPL0UP3 +mCX8D16BDu1Nep+wK9VRuOEw6Z9tlT/VjTImzoOUoJO/o2UHfSHahX+n2aC5OpI6 +BdhaFBuJ1vn+yTWf3zIjhWUdp9TlzgRyFiyetP2FcKwremVVGdDq/Y6dfXaq8CA1 +6Fr9KTY= +-----END CERTIFICATE----- diff --git a/openssl/test/certv3_extfile b/openssl/test/certv3_extfile new file mode 100644 index 0000000000000000000000000000000000000000..1b3df49482b954e71a894202d72f7e9755482599 --- /dev/null +++ b/openssl/test/certv3_extfile @@ -0,0 +1 @@ +crlDistributionPoints=URI:http://example.com/crl.pem,URI:http://example.com/crl2.pem diff --git a/openssl/test/entry_extensions.crl b/openssl/test/entry_extensions.crl new file mode 100644 index 0000000000000000000000000000000000000000..9654171cf1131c8c1762413079eee4f55225a4d7 --- /dev/null +++ b/openssl/test/entry_extensions.crl @@ -0,0 +1,10 @@ +-----BEGIN X509 CRL----- +MIIBXDCCAQICAQEwCgYIKoZIzj0EAwIwETEPMA0GA1UEAwwGQ1JMIENBFw0yMzAz +MjgwOTQ5MThaFw0yMzA0MDQwOTUwMDdaMIGAMH4CFE+Y95/1pOqa6c9fUEJ8c04k +xu2PFw0yMzAzMjgwOTQ3MzNaMFcwLwYDVR0dAQH/BCUwI6QhMB8xCzAJBgNVBAYT +AkdCMRAwDgYDVQQDDAdUZXN0IENBMAoGA1UdFQQDCgEBMBgGA1UdGAQRGA8yMDIz +MDMyODA5NDQ0MFqgPTA7MB8GA1UdIwQYMBaAFNX1GZ0RWuC+4gz1wuy5H32T2W+R +MAoGA1UdFAQDAgEUMAwGA1UdHAQFMAOEAf8wCgYIKoZIzj0EAwIDSAAwRQIgbl7x +W+WVAb+zlvKcJLmHVuC+gbqR4jqwGIHHgQl2J8kCIQCo/sAF5sDqy/cL+fbzBeUe +YoY2h6lIkj9ENwU8ZCt03w== +-----END X509 CRL----- diff --git a/systest/build.rs b/systest/build.rs index 34677d204ff6f80069faccfeba6b3061fbec8d60..53407eafad0d7a5b189fe6a228d8f5412c9cc340 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -56,6 +56,7 @@ fn main() { .header("openssl/bio.h") .header("openssl/x509v3.h") .header("openssl/safestack.h") + .header("openssl/cmac.h") .header("openssl/hmac.h") .header("openssl/obj_mac.h") .header("openssl/ssl.h") @@ -68,6 +69,10 @@ fn main() { .header("openssl/evp.h") .header("openssl/x509_vfy.h"); + if libressl_version.is_some() { + cfg.header("openssl/poly1305.h"); + } + if let Some(version) = openssl_version { cfg.header("openssl/cms.h"); if version >= 0x10100000 { @@ -110,7 +115,11 @@ fn main() { || s.starts_with("CRYPTO_EX_") }); cfg.skip_struct(|s| { - s == "ProbeResult" || s == "X509_OBJECT_data" // inline union + s == "ProbeResult" || + s == "X509_OBJECT_data" || // inline union + s == "DIST_POINT_NAME_st_anon_union" || // inline union + s == "PKCS7_data" || + s == "ASN1_TYPE_value" }); cfg.skip_fn(move |s| { s == "CRYPTO_memcmp" || // uses volatile @@ -130,7 +139,10 @@ fn main() { cfg.skip_field_type(|s, field| { (s == "EVP_PKEY" && field == "pkey") || // union (s == "GENERAL_NAME" && field == "d") || // union - (s == "X509_OBJECT" && field == "data") // union + (s == "DIST_POINT_NAME" && field == "name") || // union + (s == "X509_OBJECT" && field == "data") || // union + (s == "PKCS7" && field == "d") || // union + (s == "ASN1_TYPE" && field == "value") // union }); cfg.skip_signededness(|s| { s.ends_with("_cb")