diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java index c83a8bd9..4424c27b 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java @@ -12,6 +12,9 @@ public class TDFReader { + private static final int MAX_MANIFEST_SIZE_MB = 10; + private static final int BYTES_IN_MB = 1024 * 1024; + private static final int MAX_MANIFEST_SIZE_BYTES = MAX_MANIFEST_SIZE_MB * BYTES_IN_MB; private final ZipReader.Entry manifest; private final InputStream payload; @@ -28,6 +31,10 @@ public TDFReader(SeekableByteChannel tdf) throws IOException { } manifest = entries.get(TDF_MANIFEST_FILE_NAME); + if (manifest.getFileSize() > MAX_MANIFEST_SIZE_BYTES) { + throw new SDKException("manifest file too large: " + (manifest.getFileSize() / (double) BYTES_IN_MB) + " MB"); + } + payload = entries.get(TDF_PAYLOAD_FILE_NAME).getData(); } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/ZipReader.java b/sdk/src/main/java/io/opentdf/platform/sdk/ZipReader.java index 17bc51c5..af6ed375 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/ZipReader.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/ZipReader.java @@ -139,6 +139,10 @@ public class Entry { private final String fileName; final long offsetToLocalHeader; + public long getFileSize() { + return fileSize; + } + private Entry(byte[] fileName, long offsetToLocalHeader, long fileSize) { this.fileName = new String(fileName, StandardCharsets.UTF_8); this.offsetToLocalHeader = offsetToLocalHeader; diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/TDFWriterTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/TDFWriterTest.java index ad446bdb..128a0f85 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFWriterTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFWriterTest.java @@ -7,7 +7,10 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.channels.SeekableByteChannel; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -72,4 +75,36 @@ void simpleTDFCreate() throws IOException { writer.finish(); fileOutStream.close(); } + + @Test + void testLargeManifest() throws IOException { + // Generate a large manifest string more than 10MB + StringBuilder largeManifestBuilder = new StringBuilder(); + for (int i = 0; i < ((10 * 1024 * 1024) + 1); i++) { + largeManifestBuilder.append("a"); + } + String largeManifest = largeManifestBuilder.toString(); + + String payload = "Hello, world!"; + FileOutputStream fileOutStream = new FileOutputStream("sample.tdf"); + TDFWriter writer = new TDFWriter(fileOutStream); + try (var p = writer.payload()) { + new ByteArrayInputStream(payload.getBytes(StandardCharsets.UTF_8)).transferTo(p); + } + writer.appendManifest(largeManifest); + writer.finish(); + fileOutStream.close(); + + // Read the TDF file and check if the manifest is too large + SeekableByteChannel tdfChannel = Files.newByteChannel(Paths.get("sample.tdf")); + try { + TDFReader reader = new TDFReader(tdfChannel); + assertEquals(largeManifest, reader.manifest()); + } catch (SDKException e) { + assertTrue(e.getMessage().contains("manifest file too large:")); + } finally { + Files.deleteIfExists(Paths.get("sample.tdf")); + } + } + }