Skip to content

Commit

Permalink
gosling: added fuzz test for gosling identity server
Browse files Browse the repository at this point in the history
  • Loading branch information
Richard Pospesel committed Oct 15, 2023
1 parent 0e17ffd commit 4d5dce4
Show file tree
Hide file tree
Showing 6 changed files with 1,187 additions and 1 deletion.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,7 @@ fuzz-honk-rpc-session: config-release
@$(call fuzz,"honk_rpc_cargo_fuzz_session","release/gosling/crates/honk-rpc")

fuzz-tor-interface-crypto: config-release
@$(call fuzz,"tor_interface_cargo_fuzz_crypto","release/gosling/crates/tor-interface")
@$(call fuzz,"tor_interface_cargo_fuzz_crypto","release/gosling/crates/tor-interface")

fuzz-gosling-identity-server: config-release
@$(call fuzz,"gosling_cargo_fuzz_identity_server","release/gosling/crates/gosling")
8 changes: 8 additions & 0 deletions source/gosling/crates/gosling/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,11 @@ add_custom_target(gosling_cargo_test_offline
COMMAND RUSTFLAGS=${RUSTFLAGS} CARGO_TARGET_DIR=${CARGO_TARGET_DIR} RUST_BACKTRACE=full cargo test ${CARGO_FLAGS} --features offline-test
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

#
# fuzz target
#
add_custom_target(gosling_cargo_fuzz_identity_server
COMMAND RUSTFLAGS=${RUSTFLAGS} CARGO_TARGET_DIR=${CARGO_TARGET_DIR} RUST_BACKTRACE=full cargo fuzz run fuzz_identity_server ${CARGO_FLAGS}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
4 changes: 4 additions & 0 deletions source/gosling/crates/gosling/fuzz/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
target
corpus
artifacts
coverage
31 changes: 31 additions & 0 deletions source/gosling/crates/gosling/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "gosling-fuzz"
version = "0.0.0"
publish = false
edition = "2021"

[package.metadata]
cargo-fuzz = true

[dependencies]
bson = "2.2.0"
data-encoding = "2.3.2"
libfuzzer-sys = { version = "0.4.0", features = ["arbitrary-derive"] }
tor-interface = { path = "../../tor-interface" }
honk-rpc = { path = "../../honk-rpc" }

[dependencies.gosling]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[profile.release]
debug = 1

[[bin]]
name = "fuzz_identity_server"
path = "fuzz_targets/fuzz_identity_server.rs"
test = false
doc = false
191 changes: 191 additions & 0 deletions source/gosling/crates/gosling/fuzz/fuzz_targets/arbitrary_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
// extern
use bson::Document;
use bson::spec::BinarySubtype::Generic;
use tor_interface::tor_crypto::*;

// fuzzing
use libfuzzer_sys::arbitrary;
use libfuzzer_sys::arbitrary::{Arbitrary, Error, Unstructured};

// Generate Arbitray Types

// Ed25519 Private Key
#[derive(Debug)]
pub(crate) struct ArbitraryEd25519PrivateKey {
pub value: Ed25519PrivateKey,
}

impl<'a> Arbitrary<'a> for ArbitraryEd25519PrivateKey {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
let mut raw: [u8; 64] = [0u8; 64];
u.fill_buffer(&mut raw)?;

raw[0] &= 248;
raw[31] &= 63;
raw[31] |= 64;

let value = Ed25519PrivateKey::from_raw(&raw).unwrap();

Ok(ArbitraryEd25519PrivateKey{value})
}
}

// Ed25519 Public Key
#[derive(Debug)]
pub(crate) struct ArbitraryEd25519PublicKey {
pub value: Ed25519PublicKey,
}

impl<'a> Arbitrary<'a> for ArbitraryEd25519PublicKey {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
let private = ArbitraryEd25519PrivateKey::arbitrary(u)?;
let value = Ed25519PublicKey::from_private_key(&private.value);

Ok(ArbitraryEd25519PublicKey{value})
}
}

// Ed25519 Signature
#[derive(Debug)]
pub(crate) struct ArbitraryEd25519Signature {
pub value: Ed25519Signature,
}

impl<'a> Arbitrary<'a> for ArbitraryEd25519Signature {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
let mut message: [u8; 32] = [0u8; 32];
u.fill_buffer(&mut message)?;

let private = ArbitraryEd25519PrivateKey::arbitrary(u)?;
let value = private.value.sign_message(&message);

Ok(ArbitraryEd25519Signature{value})
}
}

// V3OnionServicId
// x25519 Private Key
#[derive(Debug)]
pub(crate) struct ArbitraryV3OnionServiceId {
pub value: V3OnionServiceId,
}

impl<'a> Arbitrary<'a> for ArbitraryV3OnionServiceId {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
let private = ArbitraryEd25519PrivateKey::arbitrary(u)?;
let value = V3OnionServiceId::from_private_key(&private.value);

Ok(ArbitraryV3OnionServiceId{value})
}
}

// x25519 Private Key
#[derive(Debug)]
pub(crate) struct ArbitraryX25519PrivateKey {
pub value: X25519PrivateKey,
}

impl<'a> Arbitrary<'a> for ArbitraryX25519PrivateKey {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
let mut raw: [u8; 32] = [0u8; 32];
u.fill_buffer(&mut raw)?;

raw[0] &= 240;
raw[31] &= 127;
raw[31] |= 64;

let value = X25519PrivateKey::from_raw(&raw).unwrap();

Ok(ArbitraryX25519PrivateKey{value})
}
}

// x25519 Public Key
#[derive(Debug)]
pub(crate) struct ArbitraryX25519PublicKey {
pub value: X25519PublicKey,
}

impl<'a> Arbitrary<'a> for ArbitraryX25519PublicKey {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
let mut raw: [u8; 32] = [0u8; 32];
u.fill_buffer(&mut raw)?;

let value = X25519PublicKey::from_raw(&raw);

Ok(ArbitraryX25519PublicKey{value})
}
}

// Bson
#[derive(Debug)]
pub(crate) struct ArbitraryBSON {
pub value: bson::Bson,
}

impl<'a> Arbitrary<'a> for ArbitraryBSON {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
#[derive(Arbitrary)]
enum BSONType {
Null, // 0
Boolean, // 1
Int32, // 2
Int64, // 3
Double, // 4
String, // 5
Binary, // 6
Array, // 7
Document, // 8
}

let value = match BSONType::arbitrary(u)? {
BSONType::Null => bson::Bson::Null,
BSONType::Boolean => bson::Bson::Boolean(bool::arbitrary(u)?),
BSONType::Int32 => bson::Bson::Int32(i32::arbitrary(u)?),
BSONType::Int64 => bson::Bson::Int64(i64::arbitrary(u)?),
BSONType::Double => bson::Bson::Double(f64::arbitrary(u)?),
BSONType::String => {
match std::ffi::CString::arbitrary(u)?.into_string() {
Ok(value) => bson::Bson::String(value),
Err(_) => bson::Bson::Null,
}
},
BSONType::Binary => bson::Bson::Binary(bson::Binary {subtype: Generic, bytes: Vec::<u8>::arbitrary(u)?}),
BSONType::Array => bson::Bson::Array(Vec::<ArbitraryBSON>::arbitrary(u)?.drain(..).map(|val| val.value).collect()),
BSONType::Document => bson::Bson::Document(ArbitraryBSONDocument::arbitrary(u)?.value),
};

Ok(ArbitraryBSON{value})
}
}

#[derive(Debug)]
pub(crate) struct ArbitraryBSONDocument {
pub value: Document,
}

impl<'a> Arbitrary<'a> for ArbitraryBSONDocument {
fn arbitrary(u: &mut Unstructured<'a>) -> Result<Self, Error> {
let mut value = Document::new();
for key in Vec::<std::ffi::CString>::arbitrary(u)?.drain(..) {
match key.into_string() {
Ok(key) => value.insert(key, ArbitraryBSON::arbitrary(u)?.value),
Err(_) => None,
};
}
Ok(ArbitraryBSONDocument{value})
}
}

// argument for
#[derive(Arbitrary, Debug)]
pub(crate) enum Argument<T> {
// no value
Missing,
// a valid value
Valid,
// an invalid value of the same type
Invalid(T),
// an invalid value of an arbitrary type
Random(ArbitraryBSON),
}
Loading

0 comments on commit 4d5dce4

Please sign in to comment.