From: Matt Corallo Date: Sun, 11 Feb 2024 22:49:44 +0000 (+0000) Subject: Add a parse + validate fuzzer X-Git-Tag: v0.5.4~64 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=e69c4acd6a582f74e8488a6edb0fec4e98bf86d8;p=dnssec-prover Add a parse + validate fuzzer --- diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index c613c87..56ed89c 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -44,3 +44,7 @@ opt-level = 1 [[bin]] name = "parse_response" path = "src/parse_response.rs" + +[[bin]] +name = "parse_stream_validate" +path = "src/parse_stream_validate.rs" diff --git a/fuzz/src/parse_stream_validate.rs b/fuzz/src/parse_stream_validate.rs new file mode 100644 index 0000000..48fc259 --- /dev/null +++ b/fuzz/src/parse_stream_validate.rs @@ -0,0 +1,74 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + +#![cfg_attr(feature = "libfuzzer_fuzz", no_main)] + +#[cfg(not(fuzzing))] +compile_error!("Fuzz targets need cfg=fuzzing"); + +extern crate dnssec_prover; +use dnssec_prover::ser::parse_rr_stream; +use dnssec_prover::validation::verify_rr_stream; + +#[cfg(feature = "afl")] +#[macro_use] extern crate afl; +#[cfg(feature = "afl")] +fn main() { + fuzz!(|data| { + let _ = parse_rr_stream(data).as_ref() + .map(|rrs| verify_rr_stream(rrs)); + }); +} + +#[cfg(feature = "honggfuzz")] +#[macro_use] extern crate honggfuzz; +#[cfg(feature = "honggfuzz")] +fn main() { + loop { + fuzz!(|data| { + let _ = parse_rr_stream(data).as_ref() + .map(|rrs| verify_rr_stream(rrs)); + }); + } +} + +#[cfg(feature = "libfuzzer_fuzz")] +#[macro_use] extern crate libfuzzer_sys; +#[cfg(feature = "libfuzzer_fuzz")] +fuzz_target!(|data: &[u8]| { + let _ = parse_rr_stream(data).as_ref() + .map(|rrs| verify_rr_stream(rrs)); +}); + +#[cfg(feature = "stdin_fuzz")] +fn main() { + use std::io::Read; + + let mut data = Vec::with_capacity(8192); + std::io::stdin().read_to_end(&mut data).unwrap(); + let _ = parse_rr_stream(data).as_ref() + .map(|rrs| verify_rr_stream(rrs)); +} + +#[test] +fn run_test_cases() { + use std::fs; + use std::io::Read; + + if let Ok(tests) = fs::read_dir("test_cases/parse_response") { + for test in tests { + let mut data: Vec = Vec::new(); + let path = test.unwrap().path(); + fs::File::open(&path).unwrap().read_to_end(&mut data).unwrap(); + + let _ = parse_rr_stream(data).as_ref() + .map(|rrs| verify_rr_stream(rrs)); + } + } +} diff --git a/src/validation.rs b/src/validation.rs index 5fee46a..8b27fce 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -111,7 +111,7 @@ where Keys: IntoIterator { record.write_u16_len_prefixed_data(&mut signed_data); } - match sig.alg { + let sig_validation = match sig.alg { 8|10 => { let alg = if sig.alg == 8 { &signature::RSA_PKCS1_1024_8192_SHA256_FOR_LEGACY_USE_ONLY @@ -120,7 +120,7 @@ where Keys: IntoIterator { }; bytes_to_rsa_pk(&dnskey.pubkey).map_err(|_| ValidationError::Invalid)? .verify(alg, &signed_data, &sig.signature) - .map_err(|_| ValidationError::Invalid)?; + .map_err(|_| ValidationError::Invalid) }, 13|14 => { let alg = if sig.alg == 13 { @@ -136,15 +136,23 @@ where Keys: IntoIterator { signature::UnparsedPublicKey::new(alg, &key) .verify(&signed_data, &sig.signature) - .map_err(|_| ValidationError::Invalid)?; + .map_err(|_| ValidationError::Invalid) }, 15 => { signature::UnparsedPublicKey::new(&signature::ED25519, &dnskey.pubkey) .verify(&signed_data, &sig.signature) - .map_err(|_| ValidationError::Invalid)?; + .map_err(|_| ValidationError::Invalid) }, _ => return Err(ValidationError::UnsupportedAlgorithm), + }; + #[cfg(fuzzing)] { + // When fuzzing, treat any signature starting with a 1 as valid, but only after + // parsing and checking signatures to give that code a chance to panic. + if sig.signature.get(0) == Some(&1) { + return Ok(()); + } } + sig_validation?; return Ok(()); }