diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 33c352cd2c..dcdd28f32a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -158,10 +158,10 @@ jobs: - name: openssl version: vendored - name: openssl - version: 3.1.0 + version: 3.1.2 dl-path: / - name: openssl - version: 1.1.1t + version: 1.1.1v dl-path: / - name: openssl version: 1.1.0l diff --git a/openssl-errors/Cargo.toml b/openssl-errors/Cargo.toml index 1f60f0ee08..5285b266e1 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/Cargo.toml b/openssl-macros/Cargo.toml index 5337de751e..7f0c1c7e44 100644 --- a/openssl-macros/Cargo.toml +++ b/openssl-macros/Cargo.toml @@ -2,7 +2,7 @@ name = "openssl-macros" 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] diff --git a/openssl-sys/CHANGELOG.md b/openssl-sys/CHANGELOG.md index 13c3f32a6c..3a1a1f1865 100644 --- a/openssl-sys/CHANGELOG.md +++ b/openssl-sys/CHANGELOG.md @@ -2,6 +2,23 @@ ## [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 @@ -473,7 +490,9 @@ 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.89..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 diff --git a/openssl-sys/Cargo.toml b/openssl-sys/Cargo.toml index 0c261c5719..3caa72fa79 100644 --- a/openssl-sys/Cargo.toml +++ b/openssl-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl-sys" -version = "0.9.89" +version = "0.9.91" authors = [ "Alex Crichton ", "Steven Fackler ", @@ -27,8 +27,6 @@ bindgen = { version = "0.64.0", optional = true, features = ["experimental"] } cc = "1.0.61" openssl-src = { version = "111", optional = true } pkg-config = "0.3.9" - -[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/expando.c b/openssl-sys/build/expando.c index 5d003d9022..cd7456b4f0 100644 --- a/openssl-sys/build/expando.c +++ b/openssl-sys/build/expando.c @@ -111,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 791fc33985..4d461039c2 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 3359165a33..21ccf3d037 100644 --- a/openssl-sys/build/main.rs +++ b/openssl-sys/build/main.rs @@ -4,7 +4,6 @@ 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; diff --git a/openssl-sys/build/run_bindgen.rs b/openssl-sys/build/run_bindgen.rs index 6743403161..1eeaad225d 100644 --- a/openssl-sys/build/run_bindgen.rs +++ b/openssl-sys/build/run_bindgen.rs @@ -55,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")] @@ -167,7 +171,9 @@ pub fn run_boringssl(include_dirs: &[PathBuf]) { bindgen_cmd .arg("-o") .arg(out_dir.join("bindgen.rs")) - .arg("--rust-target=1.56") + // 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") diff --git a/openssl-sys/src/evp.rs b/openssl-sys/src/evp.rs index 56eaa4bbff..d2ca215407 100644 --- a/openssl-sys/src/evp.rs +++ b/openssl-sys/src/evp.rs @@ -27,6 +27,9 @@ 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; @@ -186,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; @@ -288,6 +293,18 @@ pub unsafe fn EVP_PKEY_CTX_add1_hkdf_info( ) } +#[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) } diff --git a/openssl-sys/src/handwritten/bio.rs b/openssl-sys/src/handwritten/bio.rs index 7d97522251..5f65ec5e5c 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 5457f61710..fc42c13946 100644 --- a/openssl-sys/src/handwritten/bn.rs +++ b/openssl-sys/src/handwritten/bn.rs @@ -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/ec.rs b/openssl-sys/src/handwritten/ec.rs index 182a5559a3..f199bc891c 100644 --- a/openssl-sys/src/handwritten/ec.rs +++ b/openssl-sys/src/handwritten/ec.rs @@ -152,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 4041d8b671..7da92eeeb8 100644 --- a/openssl-sys/src/handwritten/evp.rs +++ b/openssl-sys/src/handwritten/evp.rs @@ -283,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; @@ -329,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; @@ -340,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; @@ -352,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")))] @@ -413,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; @@ -513,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, @@ -572,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 9c0f844501..d3adfa5a13 100644 --- a/openssl-sys/src/handwritten/mod.rs +++ b/openssl-sys/src/handwritten/mod.rs @@ -18,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::*; @@ -52,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/poly1305.rs b/openssl-sys/src/handwritten/poly1305.rs new file mode 100644 index 0000000000..8ff22f3580 --- /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/CHANGELOG.md b/openssl/CHANGELOG.md index a0622ecccd..b6bbbb9ce7 100644 --- a/openssl/CHANGELOG.md +++ b/openssl/CHANGELOG.md @@ -2,6 +2,17 @@ ## [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 @@ -776,7 +787,8 @@ Look at the [release tags] for information about older releases. -[Unreleased]: https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.55...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 diff --git a/openssl/Cargo.toml b/openssl/Cargo.toml index 956d08cf9e..17f82ca843 100644 --- a/openssl/Cargo.toml +++ b/openssl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "openssl" -version = "0.10.55" +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.89", path = "../openssl-sys" } +ffi = { package = "openssl-sys", version = "0.9.91", path = "../openssl-sys" } [dev-dependencies] hex = "0.3" diff --git a/openssl/src/bn.rs b/openssl/src/bn.rs index 5cfe4b375d..c75fac1d70 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( @@ -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 87f7660cde..f81895e513 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 _) } diff --git a/openssl/src/cipher_ctx.rs b/openssl/src/cipher_ctx.rs index 216c09e5b0..56d0d26700 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). @@ -915,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/ec.rs b/openssl/src/ec.rs index b648aec334..d541ddfc23 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 @@ -463,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 { @@ -631,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! { @@ -1121,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(); diff --git a/openssl/src/pkey_ctx.rs b/openssl/src/pkey_ctx.rs index aba8a66a32..4ac32a8517 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 { @@ -641,11 +722,12 @@ mod test { #[cfg(not(boringssl))] use crate::cipher::Cipher; use crate::ec::{EcGroup, EcKey}; - #[cfg(any(ossl102, libressl310, boringssl))] + 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() { @@ -671,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(); @@ -698,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(); @@ -807,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/sign.rs b/openssl/src/sign.rs index a32f5c9144..1c770d18b7 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 } diff --git a/systest/build.rs b/systest/build.rs index 6d3ac3a3d3..53407eafad 100644 --- a/systest/build.rs +++ b/systest/build.rs @@ -69,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 {