diff --git a/.travis.yml b/.travis.yml index 23321e96b..b7a7885da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,7 @@ script: - cargo test --verbose --features=rand - cargo test --verbose --features="rand serde" - cargo test --verbose --features="rand serde recovery endomorphism" + - cargo test --lib --features=fuzztarget - cargo build --verbose - cargo test --verbose - cargo build --verbose --release diff --git a/src/ecdh.rs b/src/ecdh.rs index ebe38b94f..b4a36b7dc 100644 --- a/src/ecdh.rs +++ b/src/ecdh.rs @@ -96,7 +96,7 @@ impl ops::Index for SharedSecret { } } -#[cfg(test)] +#[cfg(all(test, not(feature = "fuzztarget")))] mod tests { use rand::thread_rng; use super::SharedSecret; diff --git a/src/key.rs b/src/key.rs index 38f3cdfbf..f0ea52f02 100644 --- a/src/key.rs +++ b/src/key.rs @@ -443,7 +443,7 @@ impl<'de> ::serde::Deserialize<'de> for PublicKey { } } -#[cfg(test)] +#[cfg(all(test, not(feature = "fuzztarget")))] mod test { use Secp256k1; use from_hex; diff --git a/src/lib.rs b/src/lib.rs index 0863ded86..f3ff44566 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -693,7 +693,7 @@ fn from_hex(hex: &str, target: &mut [u8]) -> Result { } -#[cfg(test)] +#[cfg(all(test, not(feature = "fuzztarget")))] mod tests { use rand::{RngCore, thread_rng}; use std::str::FromStr; @@ -1084,3 +1084,84 @@ mod benches { }); } } + +#[cfg(all(test, feature = "fuzztarget"))] +mod test_fuzz { + use super::*; + use std::str::FromStr; + use std::panic::{self, UnwindSafe}; + use std::sync::MutexGuard; + + + pub fn lock_crypto_var() -> MutexGuard<'static, ()> { + use std::sync::{Mutex, Once, ONCE_INIT}; + + static mut CRYPTO_VAR_LOCK: Option> = None; + static INIT_CONTEXT: Once = ONCE_INIT; + + INIT_CONTEXT.call_once(|| unsafe { + CRYPTO_VAR_LOCK = Some(Default::default()); + }); + unsafe { CRYPTO_VAR_LOCK.as_ref().unwrap().lock().unwrap() } + } + + + + pub fn crashed_for_fuzz R + UnwindSafe, R>(f: F) -> bool { + let description = "Tried fuzzing without setting the UNSAFE_CRYPTO_FUZZING variable"; + if let Err(e) = panic::catch_unwind(f) { + if let Some(st) = e.downcast_ref::<&str>() { + return st.contains(description); + } + } + false + } + + #[test] + fn fuzz_not_set_var() { + let _lock = lock_crypto_var(); + unsafe {ffi::UNSAFE_CRYPTO_FUZZING = false}; + assert!(crashed_for_fuzz(|| SecretKey::from_slice(&[2; 32]))); + assert!(crashed_for_fuzz(|| PublicKey::from_slice(&[2; 33]))); + assert!(crashed_for_fuzz(|| Signature::from_compact(&[3; 64]))); + assert!(crashed_for_fuzz(|| Secp256k1::new())); + assert!(crashed_for_fuzz(|| { + let mut sec = SecretKey::from_str("01010101010101010001020304050607ffff0000ffff00006363636363636363").unwrap(); + let _ = sec.add_assign(&[2u8; 32]); + })); + assert!(crashed_for_fuzz(|| { + let mut sec = SecretKey::from_str("01010101010101010001020304050607ffff0000ffff00006363636363636363").unwrap(); + let _ = sec.mul_assign(&[2u8; 32]); + })); + assert!(crashed_for_fuzz(|| { + let sig: Signature = unsafe { std::mem::transmute::<_, ffi::Signature>([3u8; 64]).into() }; + let _ = sig.serialize_compact(); + })); + + assert!(crashed_for_fuzz(|| { + let pubkey1: PublicKey = unsafe { std::mem::transmute::<_, ffi::PublicKey>([3u8; 64]).into() }; + let pubkey2: PublicKey = unsafe { std::mem::transmute::<_, ffi::PublicKey>([5u8; 64]).into() }; + let _ = pubkey1.combine(&pubkey2); + })); + } + + #[test] + fn fuzz_set_var_not_crash() { + let _lock = lock_crypto_var(); + unsafe {ffi::UNSAFE_CRYPTO_FUZZING = true;} + let _ = SecretKey::from_slice(&[2; 32]); + let _ = PublicKey::from_slice(&[2; 33]); + let _ = Signature::from_compact(&[3; 64]); + let _ = Secp256k1::new(); + let mut sec = SecretKey::from_str("01010101010101010001020304050607ffff0000ffff00006363636363636363").unwrap(); + let _ = sec.add_assign(&[2u8; 32]); + let mut sec = SecretKey::from_str("01010101010101010001020304050607ffff0000ffff00006363636363636363").unwrap(); + let _ = sec.mul_assign(&[2u8; 32]); + let sig: Signature = unsafe { std::mem::transmute::<_, ffi::Signature>([3u8; 64]).into() }; + let _ = sig.serialize_compact(); + let pubkey1: PublicKey = unsafe { std::mem::transmute::<_, ffi::PublicKey>([3u8; 64]).into() }; + let pubkey2: PublicKey = unsafe { std::mem::transmute::<_, ffi::PublicKey>([5u8; 64]).into() }; + let _ = pubkey1.combine(&pubkey2); + } +} +