summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-02-10 13:20:58 +0100
committerJustus Winter <justus@sequoia-pgp.org>2023-10-10 11:16:07 +0200
commitf03b2b721fa8b2fc9c0e7cd41d9f7686303dd1a7 (patch)
tree97fb77363d0abcfc2056d0c8cc89bb6e71f944f4
parenta4c2b9f50a9f6e6539154eb3bcef8a0a062b331f (diff)
openpgp: Add fuzz targets.
-rw-r--r--openpgp/fuzz/.gitignore4
-rw-r--r--openpgp/fuzz/Cargo.toml47
-rw-r--r--openpgp/fuzz/fuzz_targets/cert_from_bytes.rs16
-rw-r--r--openpgp/fuzz/fuzz_targets/csf_verify_from_bytes.rs77
-rw-r--r--openpgp/fuzz/fuzz_targets/decrypt_from_bytes.rs90
-rw-r--r--openpgp/fuzz/fuzz_targets/inline_verify_from_bytes.rs72
6 files changed, 306 insertions, 0 deletions
diff --git a/openpgp/fuzz/.gitignore b/openpgp/fuzz/.gitignore
new file mode 100644
index 00000000..1a45eee7
--- /dev/null
+++ b/openpgp/fuzz/.gitignore
@@ -0,0 +1,4 @@
+target
+corpus
+artifacts
+coverage
diff --git a/openpgp/fuzz/Cargo.toml b/openpgp/fuzz/Cargo.toml
new file mode 100644
index 00000000..55609cf1
--- /dev/null
+++ b/openpgp/fuzz/Cargo.toml
@@ -0,0 +1,47 @@
+[package]
+name = "sequoia-openpgp-fuzz"
+version = "0.0.0"
+publish = false
+edition = "2021"
+
+[package.metadata]
+cargo-fuzz = true
+
+[dependencies]
+anyhow = "1"
+lazy_static = "1"
+libfuzzer-sys = "0.4"
+
+[dependencies.sequoia-openpgp]
+path = ".."
+default-features = false
+features = ["crypto-fuzzing", "allow-experimental-crypto", "allow-variable-time-crypto"]
+
+# Prevent this from interfering with workspaces
+[workspace]
+members = ["."]
+
+[profile.release]
+debug = 1
+
+[[bin]]
+name = "cert_from_bytes"
+path = "fuzz_targets/cert_from_bytes.rs"
+test = false
+doc = false
+
+[[bin]]
+name = "inline_verify_from_bytes"
+path = "fuzz_targets/inline_verify_from_bytes.rs"
+
+[[bin]]
+name = "csf_verify_from_bytes"
+path = "fuzz_targets/csf_verify_from_bytes.rs"
+test = false
+doc = false
+
+[[bin]]
+name = "decrypt_from_bytes"
+path = "fuzz_targets/decrypt_from_bytes.rs"
+test = false
+doc = false
diff --git a/openpgp/fuzz/fuzz_targets/cert_from_bytes.rs b/openpgp/fuzz/fuzz_targets/cert_from_bytes.rs
new file mode 100644
index 00000000..905095d2
--- /dev/null
+++ b/openpgp/fuzz/fuzz_targets/cert_from_bytes.rs
@@ -0,0 +1,16 @@
+#![no_main]
+
+use libfuzzer_sys::{Corpus, fuzz_target};
+
+use sequoia_openpgp as openpgp;
+use openpgp::{
+ Cert,
+ parse::Parse,
+};
+
+fuzz_target!(|data: &[u8]| -> Corpus {
+ match Cert::from_bytes(data) {
+ Ok(_) => Corpus::Keep,
+ Err(_) => Corpus::Reject,
+ }
+});
diff --git a/openpgp/fuzz/fuzz_targets/csf_verify_from_bytes.rs b/openpgp/fuzz/fuzz_targets/csf_verify_from_bytes.rs
new file mode 100644
index 00000000..a2025c44
--- /dev/null
+++ b/openpgp/fuzz/fuzz_targets/csf_verify_from_bytes.rs
@@ -0,0 +1,77 @@
+#![no_main]
+
+use libfuzzer_sys::{Corpus, fuzz_target};
+
+use sequoia_openpgp as openpgp;
+use openpgp::{
+ Cert,
+ KeyHandle,
+ parse::{Parse, stream::*},
+ policy::StandardPolicy,
+};
+
+const P: &StandardPolicy = &StandardPolicy::new();
+
+lazy_static::lazy_static! {
+ /// This is an example for using doc comment attributes
+ static ref CERT: Cert = Cert::from_bytes(b"
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEWlNvABYJKwYBBAHaRw8BAQdA+EC2pvebpEbzPA9YplVgVXzkIG5eK+7wEAez
+lcBgLJq0MVRlc3R5IE1jVGVzdGZhY2UgKG15IG5ldyBrZXkpIDx0ZXN0eUBleGFt
+cGxlLm9yZz6IkAQTFggAOBYhBDnRAKtn1b2MBAECBfs3UfFYfa7xBQJaU28AAhsD
+BQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEPs3UfFYfa7xJHQBAO4/GABMWUcJ
+5D/DZ9b+6YiFnysSjCT/gILJgxMgl7uoAPwJherI1pAAh49RnPHBR1IkWDtwzX65
+CJG8sDyO2FhzDrg4BFpTbwASCisGAQQBl1UBBQEBB0B+A0GRHuBgdDX50T1nePjb
+mKQ5PeqXJbWEtVrUtVJaPwMBCAeIeAQYFggAIBYhBDnRAKtn1b2MBAECBfs3UfFY
+fa7xBQJaU28AAhsMAAoJEPs3UfFYfa7xzjIBANX2/FgDX3WkmvwpEHg/sn40zACM
+W2hrBY5x0sZ8H7JlAP47mCfCuRVBqyaePuzKbxLJeLe2BpDdc0n2izMVj8t9Cg==
+=bbbT
+-----END PGP PUBLIC KEY BLOCK-----
+").unwrap();
+}
+
+
+fuzz_target!(|data: &[u8]| -> Corpus {
+ const NEEDLE: &[u8] = b"-----BEGIN PGP SIGNED MESSAGE-----";
+ if data.len() < NEEDLE.len() || &data[..NEEDLE.len()] != NEEDLE {
+ return Corpus::Reject;
+ }
+
+ struct Helper {}
+ impl VerificationHelper for Helper {
+ fn get_certs(&mut self, _ids: &[KeyHandle])
+ -> openpgp::Result<Vec<Cert>> {
+ Ok(vec![CERT.clone()])
+ }
+
+ fn check(&mut self, structure: MessageStructure)
+ -> openpgp::Result<()> {
+ for (i, layer) in structure.into_iter().enumerate() {
+ match layer {
+ MessageLayer::Encryption { .. } if i == 0 => (),
+ MessageLayer::Compression { .. } if i == 1 => (),
+ MessageLayer::SignatureGroup { ref results } => {
+ if ! results.iter().any(|r| r.is_ok()) {
+ return Err(anyhow::anyhow!(
+ "No valid signature"));
+ }
+ }
+ _ => return Err(anyhow::anyhow!(
+ "Unexpected message structure")),
+ }
+ }
+ Ok(())
+ }
+ }
+
+ let h = Helper {};
+ if let Ok(mut v) = VerifierBuilder::from_bytes(data)
+ .and_then(|b| b.with_policy(P, None, h))
+ {
+ let _ = std::io::copy(&mut v, &mut std::io::sink());
+ Corpus::Keep
+ } else {
+ Corpus::Keep
+ }
+});
diff --git a/openpgp/fuzz/fuzz_targets/decrypt_from_bytes.rs b/openpgp/fuzz/fuzz_targets/decrypt_from_bytes.rs
new file mode 100644
index 00000000..517a936c
--- /dev/null
+++ b/openpgp/fuzz/fuzz_targets/decrypt_from_bytes.rs
@@ -0,0 +1,90 @@
+#![no_main]
+
+use libfuzzer_sys::{Corpus, fuzz_target};
+
+use sequoia_openpgp as openpgp;
+use openpgp::{
+ Cert,
+ Fingerprint,
+ KeyHandle,
+ Result,
+ crypto::SessionKey,
+ packet::prelude::*,
+ parse::{Parse, stream::*},
+ policy::StandardPolicy,
+ types::*,
+};
+
+const P: &StandardPolicy = &StandardPolicy::new();
+const CERT_BYTES: &[u8; 665] = b"
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEWlNvABYJKwYBBAHaRw8BAQdA+EC2pvebpEbzPA9YplVgVXzkIG5eK+7wEAez
+lcBgLJq0MVRlc3R5IE1jVGVzdGZhY2UgKG15IG5ldyBrZXkpIDx0ZXN0eUBleGFt
+cGxlLm9yZz6IkAQTFggAOBYhBDnRAKtn1b2MBAECBfs3UfFYfa7xBQJaU28AAhsD
+BQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEPs3UfFYfa7xJHQBAO4/GABMWUcJ
+5D/DZ9b+6YiFnysSjCT/gILJgxMgl7uoAPwJherI1pAAh49RnPHBR1IkWDtwzX65
+CJG8sDyO2FhzDrg4BFpTbwASCisGAQQBl1UBBQEBB0B+A0GRHuBgdDX50T1nePjb
+mKQ5PeqXJbWEtVrUtVJaPwMBCAeIeAQYFggAIBYhBDnRAKtn1b2MBAECBfs3UfFY
+fa7xBQJaU28AAhsMAAoJEPs3UfFYfa7xzjIBANX2/FgDX3WkmvwpEHg/sn40zACM
+W2hrBY5x0sZ8H7JlAP47mCfCuRVBqyaePuzKbxLJeLe2BpDdc0n2izMVj8t9Cg==
+=bbbT
+-----END PGP PUBLIC KEY BLOCK-----
+";
+
+lazy_static::lazy_static! {
+ /// This is an example for using doc comment attributes
+ static ref CERT: Cert = Cert::from_bytes(&CERT_BYTES[..]).unwrap();
+ static ref FP: Fingerprint = CERT.fingerprint();
+ static ref SK: SessionKey = vec![].into();
+}
+
+
+fuzz_target!(|data: &[u8]| -> Corpus {
+ struct Helper {}
+ impl VerificationHelper for Helper {
+ fn get_certs(&mut self, _ids: &[KeyHandle])
+ -> openpgp::Result<Vec<Cert>> {
+ Ok(vec![CERT.clone()])
+ }
+
+ fn check(&mut self, structure: MessageStructure)
+ -> openpgp::Result<()> {
+ for (i, layer) in structure.into_iter().enumerate() {
+ match layer {
+ MessageLayer::Encryption { .. } if i == 0 => (),
+ MessageLayer::Compression { .. } if i == 1 => (),
+ MessageLayer::SignatureGroup { ref results } => {
+ if ! results.iter().any(|r| r.is_ok()) {
+ return Err(anyhow::anyhow!(
+ "No valid signature"));
+ }
+ }
+ _ => return Err(anyhow::anyhow!(
+ "Unexpected message structure")),
+ }
+ }
+ Ok(())
+ }
+ }
+ impl DecryptionHelper for Helper {
+ fn decrypt<D>(&mut self, _: &[PKESK], _: &[SKESK],
+ _sym_algo: Option<SymmetricAlgorithm>,
+ mut decrypt: D) -> Result<Option<openpgp::Fingerprint>>
+ where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool
+ {
+ decrypt(SymmetricAlgorithm::AES128, &SK);
+ Ok(Some(FP.clone()))
+ }
+ }
+
+ let h = Helper {};
+ if let Ok(mut v) = DecryptorBuilder::from_bytes(data)
+ .and_then(|b| b.with_policy(P, None, h))
+ {
+ let _ = std::io::copy(&mut v, &mut std::io::sink());
+ Corpus::Keep
+ } else {
+ Corpus::Keep
+ }
+});
diff --git a/openpgp/fuzz/fuzz_targets/inline_verify_from_bytes.rs b/openpgp/fuzz/fuzz_targets/inline_verify_from_bytes.rs
new file mode 100644
index 00000000..5ade8f8d
--- /dev/null
+++ b/openpgp/fuzz/fuzz_targets/inline_verify_from_bytes.rs
@@ -0,0 +1,72 @@
+#![no_main]
+
+use libfuzzer_sys::{Corpus, fuzz_target};
+
+use sequoia_openpgp as openpgp;
+use openpgp::{
+ Cert,
+ KeyHandle,
+ parse::{Parse, stream::*},
+ policy::StandardPolicy,
+};
+
+const P: &StandardPolicy = &StandardPolicy::new();
+
+lazy_static::lazy_static! {
+ /// This is an example for using doc comment attributes
+ static ref CERT: Cert = Cert::from_bytes(b"
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mDMEWlNvABYJKwYBBAHaRw8BAQdA+EC2pvebpEbzPA9YplVgVXzkIG5eK+7wEAez
+lcBgLJq0MVRlc3R5IE1jVGVzdGZhY2UgKG15IG5ldyBrZXkpIDx0ZXN0eUBleGFt
+cGxlLm9yZz6IkAQTFggAOBYhBDnRAKtn1b2MBAECBfs3UfFYfa7xBQJaU28AAhsD
+BQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEPs3UfFYfa7xJHQBAO4/GABMWUcJ
+5D/DZ9b+6YiFnysSjCT/gILJgxMgl7uoAPwJherI1pAAh49RnPHBR1IkWDtwzX65
+CJG8sDyO2FhzDrg4BFpTbwASCisGAQQBl1UBBQEBB0B+A0GRHuBgdDX50T1nePjb
+mKQ5PeqXJbWEtVrUtVJaPwMBCAeIeAQYFggAIBYhBDnRAKtn1b2MBAECBfs3UfFY
+fa7xBQJaU28AAhsMAAoJEPs3UfFYfa7xzjIBANX2/FgDX3WkmvwpEHg/sn40zACM
+W2hrBY5x0sZ8H7JlAP47mCfCuRVBqyaePuzKbxLJeLe2BpDdc0n2izMVj8t9Cg==
+=bbbT
+-----END PGP PUBLIC KEY BLOCK-----
+").unwrap();
+}
+
+
+fuzz_target!(|data: &[u8]| -> Corpus {
+ struct Helper {}
+ impl VerificationHelper for Helper {
+ fn get_certs(&mut self, _ids: &[KeyHandle])
+ -> openpgp::Result<Vec<Cert>> {
+ Ok(vec![CERT.clone()])
+ }
+
+ fn check(&mut self, structure: MessageStructure)
+ -> openpgp::Result<()> {
+ for (i, layer) in structure.into_iter().enumerate() {
+ match layer {
+ MessageLayer::Encryption { .. } if i == 0 => (),
+ MessageLayer::Compression { .. } if i == 1 => (),
+ MessageLayer::SignatureGroup { ref results } => {
+ if ! results.iter().any(|r| r.is_ok()) {
+ return Err(anyhow::anyhow!(
+ "No valid signature"));
+ }
+ }
+ _ => return Err(anyhow::anyhow!(
+ "Unexpected message structure")),
+ }
+ }
+ Ok(())
+ }
+ }
+
+ let h = Helper {};
+ if let Ok(mut v) = VerifierBuilder::from_bytes(data)
+ .and_then(|b| b.with_policy(P, None, h))
+ {
+ let _ = std::io::copy(&mut v, &mut std::io::sink());
+ Corpus::Keep
+ } else {
+ Corpus::Keep
+ }
+});