feat(fuzzing): Add initial set of fuzzing targets

These targets can be used with rust nightly and cargo-fuzz to fuzz
several bits of Rosenpass's API. Fuzzing is an automated way of
exploring code paths that may not be hit in unit tests or normal
operation. For example the `handle_msg` target exposed the DoS condition
fixed in 0.2.1.

The other targets focus on the FFI with libsodium and liboqs.

Co-authored-by: Karolin Varner <karo@cupdev.net>
This commit is contained in:
Morgan Hill
2023-11-19 16:52:44 +01:00
committed by Karolin Varner
parent 86300ca936
commit a49254a021
10 changed files with 1501 additions and 0 deletions

53
Cargo.lock generated
View File

@@ -107,6 +107,15 @@ dependencies = [
"backtrace", "backtrace",
] ]
[[package]]
name = "arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110"
dependencies = [
"derive_arbitrary",
]
[[package]] [[package]]
name = "atty" name = "atty"
version = "0.2.14" version = "0.2.14"
@@ -213,6 +222,7 @@ version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [ dependencies = [
"jobserver",
"libc", "libc",
] ]
@@ -438,6 +448,17 @@ version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca" checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca"
[[package]]
name = "derive_arbitrary"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "either" name = "either"
version = "1.9.0" version = "1.9.0"
@@ -646,6 +667,15 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]]
name = "jobserver"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.65" version = "0.3.65"
@@ -697,6 +727,17 @@ dependencies = [
"rle-decode-fast", "rle-decode-fast",
] ]
[[package]]
name = "libfuzzer-sys"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7"
dependencies = [
"arbitrary",
"cc",
"once_cell",
]
[[package]] [[package]]
name = "libloading" name = "libloading"
version = "0.7.4" version = "0.7.4"
@@ -1047,6 +1088,18 @@ dependencies = [
name = "rosenpass-constant-time" name = "rosenpass-constant-time"
version = "0.1.0" version = "0.1.0"
[[package]]
name = "rosenpass-fuzzing"
version = "0.0.1"
dependencies = [
"arbitrary",
"libfuzzer-sys",
"rosenpass",
"rosenpass-ciphers",
"rosenpass-sodium",
"stacker",
]
[[package]] [[package]]
name = "rosenpass-sodium" name = "rosenpass-sodium"
version = "0.1.0" version = "0.1.0"

View File

@@ -7,6 +7,7 @@ members = [
"util", "util",
"constant-time", "constant-time",
"sodium", "sodium",
"fuzzing",
] ]
[workspace.metadata.release] [workspace.metadata.release]

4
fuzzing/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
target
corpus
artifacts
coverage

1286
fuzzing/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

52
fuzzing/Cargo.toml Normal file
View File

@@ -0,0 +1,52 @@
[package]
name = "rosenpass-fuzzing"
version = "0.0.1"
publish = false
edition = "2021"
[package.metadata]
cargo-fuzz = true
[dependencies]
arbitrary = { version = "1.3.2", features = ["derive"]}
libfuzzer-sys = "0.4"
stacker = "0.1.15"
[dependencies.rosenpass]
path = "../rosenpass"
[dependencies.rosenpass-sodium]
path = "../sodium"
[dependencies.rosenpass-ciphers]
path = "../ciphers"
[[bin]]
name = "fuzz_handle_msg"
path = "fuzz_targets/handle_msg.rs"
test = false
doc = false
[[bin]]
name = "fuzz_blake2b"
path = "fuzz_targets/blake2b.rs"
test = false
doc = false
[[bin]]
name = "fuzz_aead_enc_into"
path = "fuzz_targets/aead_enc_into.rs"
test = false
doc = false
[[bin]]
name = "fuzz_mceliece_encaps"
path = "fuzz_targets/mceliece_encaps.rs"
test = false
doc = false
[[bin]]
name = "fuzz_kyber_encaps"
path = "fuzz_targets/kyber_encaps.rs"
test = false
doc = false

View File

@@ -0,0 +1,32 @@
#![no_main]
extern crate arbitrary;
extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass_ciphers::aead;
use rosenpass_sodium::init as sodium_init;
#[derive(arbitrary::Arbitrary, Debug)]
pub struct Input {
pub key: [u8; 32],
pub nonce: [u8; 12],
pub ad: Box<[u8]>,
pub plaintext: Box<[u8]>,
}
fuzz_target!(|input: Input| {
sodium_init().unwrap();
let mut ciphertext: Vec<u8> = Vec::with_capacity(input.plaintext.len() + 16);
ciphertext.resize(input.plaintext.len() + 16, 0);
aead::encrypt(
ciphertext.as_mut_slice(),
&input.key,
&input.nonce,
&input.ad,
&input.plaintext,
)
.unwrap();
});

View File

@@ -0,0 +1,22 @@
#![no_main]
extern crate arbitrary;
extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass::sodium::mac_into;
use rosenpass_sodium::init as sodium_init;
#[derive(arbitrary::Arbitrary, Debug)]
pub struct Blake2b {
pub key: [u8; 32],
pub data: Box<[u8]>,
}
fuzz_target!(|input: Blake2b| {
sodium_init().unwrap();
let mut out = [0u8; 32];
mac_into(&mut out, &input.key, &input.data).unwrap();
});

View File

@@ -0,0 +1,19 @@
#![no_main]
extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass::coloring::Secret;
use rosenpass::protocol::CryptoServer;
use rosenpass_sodium::init as sodium_init;
fuzz_target!(|rx_buf: &[u8]| {
sodium_init().unwrap();
let sk = Secret::from_slice(&[0; 13568]);
let pk = Secret::from_slice(&[0; 524160]);
let mut cs = CryptoServer::new(sk, pk);
let mut tx_buf = [0; 10240];
cs.handle_msg(rx_buf, &mut tx_buf).unwrap();
});

View File

@@ -0,0 +1,19 @@
#![no_main]
extern crate arbitrary;
extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass::pqkem::{EphemeralKEM, KEM};
#[derive(arbitrary::Arbitrary, Debug)]
pub struct Input {
pub pk: [u8; 800],
}
fuzz_target!(|input: Input| {
let mut ciphertext = [0u8; 768];
let mut shared_secret = [0u8; 32];
EphemeralKEM::encaps(&mut shared_secret, &mut ciphertext, &input.pk).unwrap();
});

View File

@@ -0,0 +1,13 @@
#![no_main]
extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass::pqkem::{StaticKEM, KEM};
fuzz_target!(|input: &[u8]| {
let mut ciphertext = [0u8; 188];
let mut shared_secret = [0u8; 32];
StaticKEM::encaps(&mut shared_secret, &mut ciphertext, input).unwrap();
});