-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add cargo-fuzz test harness for the qos_p256 crate for automated cove…
…rage guided testing
- Loading branch information
Showing
10 changed files
with
300 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
[package] | ||
name = "qos_p256_fuzz" | ||
version = "0.0.0" | ||
publish = false | ||
edition = "2021" | ||
|
||
[package.metadata] | ||
cargo-fuzz = true | ||
|
||
[dependencies] | ||
libfuzzer-sys = "0.4" | ||
|
||
qos_p256 = { path = "../"} | ||
|
||
# arbitrary = { version = "1", features = ["derive"] } | ||
|
||
# Prevent this from interfering with workspaces | ||
[workspace] | ||
members = ["."] | ||
|
||
[profile.release] | ||
debug = 1 | ||
|
||
[[bin]] | ||
name = "1_sign_then_verify" | ||
path = "fuzz_targets/1_sign_then_verify.rs" | ||
test = false | ||
doc = false | ||
|
||
[[bin]] | ||
name = "2_public_sign_key_round_trip" | ||
path = "fuzz_targets/2_public_sign_key_round_trip.rs" | ||
test = false | ||
doc = false | ||
|
||
[[bin]] | ||
name = "3_public_sign_key_round_trip" | ||
path = "fuzz_targets/3_public_sign_key_round_trip.rs" | ||
test = false | ||
doc = false | ||
|
||
[[bin]] | ||
name = "4_public_sign_key_import" | ||
path = "fuzz_targets/4_public_sign_key_import.rs" | ||
test = false | ||
doc = false | ||
|
||
[[bin]] | ||
name = "5_basic_encrypt_decrypt" | ||
path = "fuzz_targets/5_basic_encrypt_decrypt.rs" | ||
test = false | ||
doc = false | ||
|
||
[[bin]] | ||
name = "6_basic_encrypt_decrypt_aesgcm" | ||
path = "fuzz_targets/6_basic_encrypt_decrypt_aesgcm.rs" | ||
test = false | ||
doc = false | ||
|
||
[[bin]] | ||
name = "7_decrypt_aesgcm" | ||
path = "fuzz_targets/7_decrypt_aesgcm.rs" | ||
test = false | ||
doc = false | ||
|
||
[[bin]] | ||
name = "8_decrypt_p256" | ||
path = "fuzz_targets/8_decrypt_p256.rs" | ||
test = false | ||
doc = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
#![no_main] | ||
|
||
use libfuzzer_sys::fuzz_target; | ||
|
||
use qos_p256::P256Pair; | ||
|
||
// this harness is based on the sign_and_verification_works() unit test | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
// let the fuzzer control data that is going to be signed | ||
|
||
// Generate a non-deterministically random P256 key | ||
// | ||
// This deviates from fully deterministic fuzz behavior, | ||
// but gives us a chance to randomly discover key-specific issues | ||
let random_key_pair = P256Pair::generate().unwrap(); | ||
|
||
// produce a signature over the data input the fuzzer controls | ||
let signature = random_key_pair.sign(data).unwrap(); | ||
|
||
// verify the just-generated signature | ||
// this should always succeed | ||
assert!(random_key_pair.public_key().verify(data, &signature).is_ok()); | ||
}); |
33 changes: 33 additions & 0 deletions
33
src/qos_p256/fuzz/fuzz_targets/2_public_sign_key_round_trip.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
#![no_main] | ||
|
||
use libfuzzer_sys::fuzz_target; | ||
|
||
use qos_p256::sign::P256SignPair; | ||
use qos_p256::sign::P256SignPublic; | ||
|
||
// this harness is based on the public_key_round_trip_bytes_works() unit test | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
|
||
// This setup is not ideal, as the fuzzer-controlled data input only has a | ||
// minor influence on the tested public key round trip check | ||
|
||
// Generate a non-deterministically random P256 key | ||
// | ||
// This deviates from fully deterministic fuzz behavior, | ||
// but gives us a chance to randomly discover key-specific issues | ||
let pair = P256SignPair::generate(); | ||
|
||
// derive public key and export it to bytes | ||
let bytes_public = pair.public_key().to_bytes(); | ||
|
||
// create valid signature | ||
let signature = pair.sign(data).unwrap(); | ||
|
||
// re-import public key from bytes | ||
// this should always succeed since we just generated and exported it | ||
let public = P256SignPublic::from_bytes(&bytes_public).unwrap(); | ||
|
||
// expect the signature verification with the reconstructed pubkey to always succeed | ||
assert!(public.verify(data, &signature).is_ok()); | ||
}); |
39 changes: 39 additions & 0 deletions
39
src/qos_p256/fuzz/fuzz_targets/3_public_sign_key_round_trip.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#![no_main] | ||
|
||
use libfuzzer_sys::fuzz_target; | ||
|
||
use qos_p256::sign::P256SignPair; | ||
use qos_p256::sign::P256SignPublic; | ||
|
||
// this harness is based on the public_key_round_trip_bytes_works() unit test | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
|
||
// let the fuzzer control the P256 secret key | ||
|
||
// create private key from bytes, derive public key | ||
// silently abort on failures | ||
// we expect only 32 byte vector inputs to succeed here | ||
let pair = match P256SignPair::from_bytes(data) { | ||
Ok(pair) => pair, | ||
Err(_err) => { | ||
return; | ||
}, | ||
}; | ||
|
||
// derive public key and export it | ||
let bytes_public = pair.public_key().to_bytes(); | ||
|
||
// static plaintext message | ||
let message = b"a message to authenticate"; | ||
|
||
// sign with private key | ||
let signature = pair.sign(message).unwrap(); | ||
|
||
// re-import public key from bytes | ||
// this should always succeed since we just generated it | ||
let public = P256SignPublic::from_bytes(&bytes_public).unwrap(); | ||
|
||
// expect the signature verification with the reconstructed pubkey to always succeed | ||
assert!(pubkey_special.verify(message, &signature).is_ok()); | ||
}); |
32 changes: 32 additions & 0 deletions
32
src/qos_p256/fuzz/fuzz_targets/4_public_sign_key_import.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
#![no_main] | ||
|
||
use libfuzzer_sys::fuzz_target; | ||
|
||
use qos_p256::sign::P256SignPair; | ||
use qos_p256::sign::P256SignPublic; | ||
|
||
// this harness is partially based on the public_key_round_trip_bytes_works() unit test | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
// let the fuzzer control the P256 signing pubkey | ||
|
||
// import public key from bytes | ||
// silently exit in case of errors | ||
let pubkey_special = match P256SignPublic::from_bytes(data) { | ||
Ok(pubkey) => pubkey, | ||
Err(_err) => { | ||
return; | ||
}, | ||
}; | ||
|
||
// static plaintext message | ||
let message = b"a message to authenticate"; | ||
|
||
// Improvement: replace this with a static pre-recorded signature, we just need a (wrong) signature | ||
let pair = P256SignPair::generate(); | ||
// sign with secret key | ||
let signature = pair.sign(message).unwrap(); | ||
|
||
// we expect this to not succeed since the pubkeys do not match up | ||
assert!(!pubkey_special.verify(message, &signature).is_ok()); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#![no_main] | ||
|
||
use libfuzzer_sys::fuzz_target; | ||
|
||
use qos_p256::encrypt::P256EncryptPair; | ||
|
||
|
||
// this harness is partially based on the basic_encrypt_decrypt_works() unit test | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
// let the fuzzer control a message plaintext that is encrypted and then decrypted again | ||
|
||
// private key generation is non-deterministic: not ideal | ||
let random_key_pair = P256EncryptPair::generate(); | ||
let random_key_public = random_key_pair.public_key(); | ||
|
||
// the encryption is non-deterministic due to the internal random nonce generation | ||
// not ideal, can't be avoided due to API structure? | ||
let serialized_envelope = random_key_public.encrypt(data).unwrap(); | ||
|
||
// expected to always succeed | ||
let decrypted_data = random_key_pair.decrypt(&serialized_envelope).unwrap(); | ||
|
||
// check roundtrip data consistency, assert should always hold | ||
assert_eq!(decrypted_data, data); | ||
}); |
26 changes: 26 additions & 0 deletions
26
src/qos_p256/fuzz/fuzz_targets/6_basic_encrypt_decrypt_aesgcm.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
#![no_main] | ||
|
||
use libfuzzer_sys::fuzz_target; | ||
|
||
use qos_p256::encrypt::AesGcm256Secret; | ||
|
||
|
||
// this harness is partially based on the encrypt_decrypt_round_trip() unit test | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
// let the fuzzer control a message plaintext that is encrypted and then decrypted again | ||
|
||
// private key generation is non-deterministic: not ideal | ||
let random_key = AesGcm256Secret::generate(); | ||
|
||
// the encryption is non-deterministic due to the internal random nonce generation | ||
// not ideal, can't be avoided due to API structure? | ||
// expected to always succeed | ||
let encrypted_envelope = random_key.encrypt(data).unwrap(); | ||
|
||
// expected to always succeed | ||
let decrypted_data = random_key.decrypt(&encrypted_envelope).unwrap(); | ||
|
||
// check roundtrip data consistency, assert should always hold | ||
assert_eq!(decrypted_data, data); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#![no_main] | ||
|
||
use libfuzzer_sys::fuzz_target; | ||
|
||
use qos_p256::encrypt::AesGcm256Secret; | ||
|
||
|
||
fuzz_target!(|data: &[u8]| { | ||
// let the fuzzer create an encrypted envelope to test decrypt() robustness | ||
|
||
// private key generation is non-deterministic: not ideal | ||
let random_key = AesGcm256Secret::generate(); | ||
|
||
// we expect this to fail | ||
match random_key.decrypt(&data) { | ||
Ok(_res) => panic!("the fuzzer can't create valid AEAD protected encrypted messages"), | ||
Err(_err) => { | ||
return; | ||
}, | ||
}; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#![no_main] | ||
|
||
use libfuzzer_sys::fuzz_target; | ||
|
||
use qos_p256::encrypt::P256EncryptPair; | ||
|
||
fuzz_target!(|data: &[u8]| { | ||
// let the fuzzer control an encrypted message ciphertext to test decrypt() robustness | ||
|
||
// private key generation is non-deterministic: not ideal | ||
let random_key_pair = P256EncryptPair::generate(); | ||
|
||
match random_key_pair.decrypt(&data) { | ||
Ok(_res) => panic!("the fuzzer should be unable to create a validly signed message"), | ||
Err(_err) => { | ||
return; | ||
}, | ||
}; | ||
}); |