diff --git a/sdk/fuzz.sh b/sdk/fuzz.sh new file mode 100755 index 00000000..88a803ae --- /dev/null +++ b/sdk/fuzz.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +tests=("fuzzNanoTDF", "fuzzTDF", "fuzzZipRead") +base_seed_dir="src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/" + +for test in "${tests[@]}"; do + seed_dir="${base_seed_dir}${test}" + echo "Running $test fuzzing with seeds from $seed_dir" + mvn verify -P fuzz -Djazzer.testDir=$seed_dir +done diff --git a/sdk/pom.xml b/sdk/pom.xml index 678c78b0..6685f513 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -9,6 +9,10 @@ 0.7.5 jar + + 0.22.1 + https://github.com/CodeIntelligenceTesting/jazzer/releases/download/v${jazzer.version} + @@ -121,6 +125,18 @@ 4.13.2 test + + com.code-intelligence + jazzer-api + ${jazzer.version} + test + + + com.code-intelligence + jazzer-junit + ${jazzer.version} + test + org.apache.commons commons-compress @@ -307,4 +323,110 @@ - \ No newline at end of file + + + + fuzz + + false + + + true + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + download-and-unpack-jazzer + process-test-classes + + + + + + + + + + + + + + + + + + + run + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.4.0 + + + copy-dependencies + process-test-classes + + copy-dependencies + + + ${project.build.directory}/dependency-jars + test + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 3.1.0 + + + run-jazzer-fuzzing + verify + + + + + + + + + + + + + + + + + + + + + + + + run + + + + + + + + + diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java b/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java new file mode 100644 index 00000000..776a107e --- /dev/null +++ b/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java @@ -0,0 +1,69 @@ +package io.opentdf.platform.sdk; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.text.ParseException; + +import org.apache.commons.codec.DecoderException; +import org.apache.commons.compress.utils.SeekableInMemoryByteChannel; + +import com.code_intelligence.jazzer.api.FuzzedDataProvider; +import com.code_intelligence.jazzer.junit.FuzzTest; +import com.google.gson.JsonParseException; +import com.nimbusds.jose.JOSEException; + +import io.opentdf.platform.sdk.TDF.FailedToCreateGMAC; +import io.opentdf.platform.sdk.TDF.Reader; + +public class Fuzzing { + private static final String testDuration = "600s"; + private static final OutputStream ignoreOutputStream = new OutputStream() { + @Override + public void write(int b) { + // ignored + } + + @Override + public void write(byte b[], int off, int len) { + // ignored + } + }; + + @FuzzTest(maxDuration=testDuration) + public void fuzzNanoTDF(FuzzedDataProvider data) throws IOException { + byte[] fuzzBytes = data.consumeRemainingAsBytes(); + NanoTDF nanoTDF = new NanoTDF(); + nanoTDF.readNanoTDF(ByteBuffer.wrap(fuzzBytes), ignoreOutputStream, NanoTDFTest.kas); + } + + @FuzzTest(maxDuration=testDuration) + public void fuzzTDF(FuzzedDataProvider data) throws FailedToCreateGMAC, NoSuchAlgorithmException, IOException, JOSEException, ParseException, DecoderException { + byte[] fuzzBytes = data.consumeRemainingAsBytes(); + byte[] key = new byte[32]; // use consistent zero key for performance and so fuzz can relate to seed + var assertionVerificationKeys = new Config.AssertionVerificationKeys(); + assertionVerificationKeys.defaultKey = new AssertionConfig.AssertionKey(AssertionConfig.AssertionKeyAlg.HS256, key); + Config.TDFReaderConfig readerConfig = Config.newTDFReaderConfig( + Config.withAssertionVerificationKeys(assertionVerificationKeys)); + TDF tdf = new TDF(); + + try { + Reader reader = tdf.loadTDF(new SeekableInMemoryByteChannel(fuzzBytes), TDFTest.kas, readerConfig); + + reader.readPayload(ignoreOutputStream); + } catch (SDKException | InvalidZipException | JsonParseException | IOException | IllegalArgumentException e) { + // expected failure cases + } + } + + @FuzzTest(maxDuration=testDuration) + public void fuzzZipRead(FuzzedDataProvider data) { + byte[] fuzzBytes = data.consumeRemainingAsBytes(); + try { + ZipReaderTest.testReadingZipChannel(new SeekableInMemoryByteChannel(fuzzBytes), false); + } catch (InvalidZipException | IllegalArgumentException | JsonParseException | IOException e) { + // cases which are expected with invalid fuzzed inputs + } + } +} diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java index 87bae33b..cd4c056d 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java @@ -37,7 +37,7 @@ public class NanoTDFTest { private static final String KID = "r1"; - private static SDK.KAS kas = new SDK.KAS() { + protected static SDK.KAS kas = new SDK.KAS() { @Override public void close() throws Exception { } diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ZipReaderTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ZipReaderTest.java index 5c47710c..29769b2b 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ZipReaderTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ZipReaderTest.java @@ -12,9 +12,13 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.nio.channels.SeekableByteChannel; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Random; @@ -32,21 +36,31 @@ public class ZipReaderTest { public void testReadingExistingZip() throws Exception { try (RandomAccessFile raf = new RandomAccessFile("src/test/resources/sample.txt.tdf", "r")) { var fileChannel = raf.getChannel(); - var zipReader = new ZipReader(fileChannel); - var entries = zipReader.getEntries(); + ZipReaderTest.testReadingZipChannel(fileChannel, true); + } + } + + protected static void testReadingZipChannel(SeekableByteChannel fileChannel, boolean test) throws IOException { + var zipReader = new ZipReader(fileChannel); + var entries = zipReader.getEntries(); + if (test) { assertThat(entries.size()).isEqualTo(2); - for (var entry: entries) { - var stream = new ByteArrayOutputStream(); - if (entry.getName().endsWith(".json")) { - entry.getData().transferTo(stream); - var data = stream.toString(StandardCharsets.UTF_8); - var gson = new GsonBuilder() - .registerTypeAdapter(Manifest.class, new ManifestDeserializer()) - .create(); - var map = gson.fromJson(data, Map.class); - + } + for (var entry: entries) { + var stream = new ByteArrayOutputStream(); + if (entry.getName().endsWith(".json")) { + entry.getData().transferTo(stream); + var data = stream.toString(StandardCharsets.UTF_8); + var gson = new GsonBuilder() + .registerTypeAdapter(Manifest.class, new ManifestDeserializer()) + .create(); + var map = gson.fromJson(data, Map.class); + + if (test) { assertThat(map.get("encryptionInformation")).isNotNull(); } + } else if (!test) { + entry.getData().transferTo(stream); // still invoke getData logic } } } diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzNanoTDF/sample.ntdf b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzNanoTDF/sample.ntdf new file mode 100644 index 00000000..7dd6dcbb Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzNanoTDF/sample.ntdf differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-1 b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-1 new file mode 100644 index 00000000..5e0b5c99 Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-1 differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-2 b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-2 new file mode 100644 index 00000000..de7914cd Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-2 differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-3 b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-3 new file mode 100644 index 00000000..bfe79806 Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-3 differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-4 b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-4 new file mode 100644 index 00000000..da6463a9 Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-4 differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-NullKeyAccessObj b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-NullKeyAccessObj new file mode 100644 index 00000000..d55d907b Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-NullKeyAccessObj differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-NullSegment b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-NullSegment new file mode 100644 index 00000000..4537beda Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/crash-InvalidManifest-NullSegment differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/sample.tdf b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/sample.tdf new file mode 100644 index 00000000..cc27081a Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzTDF/sample.tdf differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/crash-NullSignature b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/crash-NullSignature new file mode 100644 index 00000000..24ea0b1c Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/crash-NullSignature differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/crash-f39ad8416aef7cf275f84683aaa0efd15f24272a b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/crash-f39ad8416aef7cf275f84683aaa0efd15f24272a new file mode 100644 index 00000000..2fc1da22 Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/crash-f39ad8416aef7cf275f84683aaa0efd15f24272a differ diff --git a/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/sample.txt.tdf b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/sample.txt.tdf new file mode 100644 index 00000000..2bb81265 Binary files /dev/null and b/sdk/src/test/resources/io/opentdf/platform/sdk/FuzzingInputs/fuzzZipRead/sample.txt.tdf differ