From 33d9460b4d83cd2e4dc94c7080de1e65b29fe5e8 Mon Sep 17 00:00:00 2001 From: Monica Moniot Date: Thu, 5 Oct 2023 17:55:37 -0400 Subject: [PATCH] Added support for OpenSSL<1.1.0 --- Cargo.toml | 2 ++ build.rs | 11 ++++++++++ src/lib.rs | 2 +- src/p384.rs | 61 +++++++++++++++++++++++++++++++++++++-------------- src/random.rs | 14 ++++++------ 5 files changed, 65 insertions(+), 25 deletions(-) create mode 100644 build.rs diff --git a/Cargo.toml b/Cargo.toml index e671bff..ad27867 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,10 +7,12 @@ readme = "README.md" categories = ["cryptography", "api-bindings"] edition = "2021" version = "0.2.0" +build = "build.rs" [features] [dependencies] +openssl-sys = "0.9.91" x25519-dalek = { version = "2.0.0", features = ["static_secrets"], default-features = false } ed25519-dalek = { version = "2.0.0", features = ["digest", "rand_core"], default-features = false } poly1305 = { version = "0.8.0", features = [], default-features = false } diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..2a41a6c --- /dev/null +++ b/build.rs @@ -0,0 +1,11 @@ +use std::env; + +fn main() { + if let Ok(v) = env::var("DEP_OPENSSL_VERSION_NUMBER") { + let version = u64::from_str_radix(&v, 16).unwrap(); + + if version < 0x1_01_00_00_0 { + println!("cargo:rustc-cfg=no_get0set0"); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 81a7540..1a0ad44 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,7 +52,7 @@ macro_rules! impl_zssp_crypto { type SessionData = $session_data; type IncomingPacketBuffer = $packet_buffer; } - } + }; } use ctor::ctor; diff --git a/src/p384.rs b/src/p384.rs index 4a0af87..537b81c 100644 --- a/src/p384.rs +++ b/src/p384.rs @@ -128,21 +128,32 @@ impl P384PublicKey { if let (Ok(r), Ok(s)) = (r, s) { // Create the OpenSSL object that actually supports verification. if let Ok(sig) = check_ptr(ffi::ECDSA_SIG_new()) { - let is_valid = if ffi::ECDSA_SIG_set0(sig, r.0, s.0) == 1 { - // For some reason this one random function, `ECDSA_SIG_set0`, takes - // ownership of its parameters. I've double checked and it is the only one - // we call that does that. We `forget` the memory so we don't double free. - mem::forget(r); - mem::forget(s); - // Digest the message. - let digest = create_digest(domain, data); + cfg_if::cfg_if! { + if #[cfg(no_get0set0)] { + let sig_deref = sig.as_mut().unwrap(); + if !sig_deref.r.is_null() { + ffi::BN_free(sig_deref.r); + } + if !sig_deref.s.is_null() { + ffi::BN_free(sig_deref.s); + } + sig_deref.r = r.0; + sig_deref.s = s.0; + } else { + assert!(ffi::ECDSA_SIG_set0(sig, r.0, s.0) == 1); + } + } + // For some reason this one random function, `ECDSA_SIG_set0`, takes + // ownership of its parameters. I've double checked and it is the only one + // we call that does that. We `forget` the memory so we don't double free. + mem::forget(r); + mem::forget(s); + // Digest the message. + let digest = create_digest(domain, data); - let key = self.key.lock().unwrap(); - // Actually perform the verification. - ffi::ECDSA_do_verify(digest.as_ptr(), digest.len() as c_int, sig, key.0) == 1 - } else { - false - }; + let key = self.key.lock().unwrap(); + // Actually perform the verification. + let is_valid = ffi::ECDSA_do_verify(digest.as_ptr(), digest.len() as c_int, sig, key.0) == 1; // Guarantee signature free. ffi::ECDSA_SIG_free(sig); return is_valid; @@ -209,7 +220,10 @@ impl P384KeyPair { /// Create a p384 keypair from raw bytes. /// `public_bytes` should have length `P384_PUBLIC_KEY_SIZE` and `secret_bytes` should have length /// `P384_SECRET_KEY_SIZE`. - pub fn from_bytes(public_bytes: &[u8; P384_PUBLIC_KEY_SIZE], secret_bytes: &[u8; P384_SECRET_KEY_SIZE]) -> Option { + pub fn from_bytes( + public_bytes: &[u8; P384_PUBLIC_KEY_SIZE], + secret_bytes: &[u8; P384_SECRET_KEY_SIZE], + ) -> Option { unsafe { // Write the raw bytes into OpenSSL. let pair = OSSLKey::pub_from_slice(public_bytes).ok()?; @@ -285,6 +299,7 @@ impl P384KeyPair { /// The signature will only be valid when verified with the same "domain". /// Restricting signatures to domains reduces the risk of a valid signature being used for a /// purpose the signer did not intend. + #[allow(unused_assignments)] pub fn sign_all(&self, domain: &[u8], data: &[&[u8]]) -> [u8; P384_ECDSA_SIGNATURE_SIZE] { let digest = create_digest(domain, data); unsafe { @@ -297,7 +312,16 @@ impl P384KeyPair { // Get handles to the OpenSSL objects that actually support reading out into bytes. let mut r = ptr::null(); let mut s = ptr::null(); - ffi::ECDSA_SIG_get0(sig, &mut r, &mut s); + cfg_if::cfg_if! { + if #[cfg(no_get0set0)] { + let sig_deref = sig.as_ref().unwrap(); + r = sig_deref.r; + s = sig_deref.s; + } else { + ffi::ECDSA_SIG_get0(sig, &mut r, &mut s); + } + } + if r.is_null() || s.is_null() { ffi::ECDSA_SIG_free(sig); assert!(false); @@ -479,7 +503,10 @@ impl zssp::crypto::P384KeyPair for P384KeyPair { #[cfg(test)] mod tests { use crate::{ - p384::{P384KeyPair, P384_ECDH_SHARED_SECRET_SIZE, P384_PUBLIC_KEY_SIZE, P384_SECRET_KEY_SIZE, P384_ECDSA_SIGNATURE_SIZE}, + p384::{ + P384KeyPair, P384_ECDH_SHARED_SECRET_SIZE, P384_ECDSA_SIGNATURE_SIZE, P384_PUBLIC_KEY_SIZE, + P384_SECRET_KEY_SIZE, + }, secure_eq, }; diff --git a/src/random.rs b/src/random.rs index b5ad7f1..1ace1e3 100644 --- a/src/random.rs +++ b/src/random.rs @@ -13,7 +13,6 @@ use libc::c_int; use once_cell::unsync::Lazy; use zssp::crypto::rand_core::{CryptoRng, Error, RngCore, SeedableRng}; -pub use zssp::crypto::rand_core; /// This crate contains the most modern, feature rich and high-quality variants of the Xorshift family of random /// number generators. /// While they are not cryptographically secure, they are also faster and several times harder to @@ -23,6 +22,7 @@ pub use rand_xoshiro; /// Xoshiro256** according to my benchmarking is surprisingly twice as fast as vanilla /// Xorshift64 because there are fewer dependency chains in Xoshiro256** compared to Xorshift64. pub use rand_xoshiro::Xoshiro256StarStar; +pub use zssp::crypto::rand_core; /// The cryptographically secure random number generator of OpenSSL. #[derive(Default, Clone, Copy)] @@ -113,31 +113,31 @@ impl RngCore for XorshiftRandom { } } -#[deprecated(since="0.2.0", note="please use `SecureRandom.next_u32()` instead")] +#[deprecated(since = "0.2.0", note = "please use `SecureRandom.next_u32()` instead")] pub fn next_u32_secure() -> u32 { SecureRandom.next_u32() } -#[deprecated(since="0.2.0", note="please use `SecureRandom.next_u64()` instead")] +#[deprecated(since = "0.2.0", note = "please use `SecureRandom.next_u64()` instead")] pub fn next_u64_secure() -> u64 { SecureRandom.next_u64() } -#[deprecated(since="0.2.0", note="please use `SecureRandom.next_u128()` instead")] +#[deprecated(since = "0.2.0", note = "please use `SecureRandom.next_u128()` instead")] pub fn next_u128_secure() -> u128 { SecureRandom.next_u128() } -#[deprecated(since="0.2.0", note="please use `SecureRandom.fill_bytes(dest)` instead")] +#[deprecated(since = "0.2.0", note = "please use `SecureRandom.fill_bytes(dest)` instead")] pub fn fill_bytes_secure(dest: &mut [u8]) { SecureRandom.fill_bytes(dest) } -#[deprecated(since="0.2.0", note="please use `SecureRandom.get_bytes()` instead")] +#[deprecated(since = "0.2.0", note = "please use `SecureRandom.get_bytes()` instead")] pub fn get_bytes_secure() -> [u8; COUNT] { SecureRandom.get_bytes() } -#[deprecated(since="0.2.0", note="please use `XorshiftRandom.next_u64()` instead")] +#[deprecated(since = "0.2.0", note = "please use `XorshiftRandom.next_u64()` instead")] pub fn xorshift64_random() -> u64 { XorshiftRandom.next_u64() }