Skip to content

fix(sdk): add methods to examine Manifest and Policy #278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.opentdf.platform;

import io.opentdf.platform.sdk.Manifest;
import io.opentdf.platform.sdk.PolicyObject;
import io.opentdf.platform.sdk.SDK;

import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

public class GetManifestInformation {
public static void main(String[] args) throws IOException {
if (args.length < 1) {
System.err.println("TDF file path must be provided as an argument.");
return;
}

try (FileChannel tdfStream = FileChannel.open(Path.of(args[0]), StandardOpenOption.READ)) {
Manifest manifest = SDK.readManifest(tdfStream);
System.out.println("loaded a TDF with key access type: " + manifest.encryptionInformation.keyAccessType);

PolicyObject policyObject = SDK.decodePolicyObject(manifest);
System.out.println("the policy has uuid: " + policyObject.uuid);
}
}
}

8 changes: 3 additions & 5 deletions sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.erdtman.jcs.JsonCanonicalizer;

import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
Expand Down Expand Up @@ -500,8 +499,8 @@ public AssertionConfig.Statement deserialize(JsonElement json, Type typeOfT, Jso
public EncryptionInformation encryptionInformation;
public Payload payload;
public List<Assertion> assertions = new ArrayList<>();
protected static Manifest readManifest(Reader reader) {
Manifest result = gson.fromJson(reader, Manifest.class);
protected static Manifest readManifest(String manifestJson) {
Manifest result = gson.fromJson(manifestJson, Manifest.class);
if (result.assertions == null) {
result.assertions = new ArrayList<>();
}
Expand Down Expand Up @@ -539,8 +538,7 @@ protected static Manifest readManifest(Reader reader) {
return result;
}

static PolicyObject readPolicyObject(Reader reader) {
var manifest = readManifest(reader);
static PolicyObject decodePolicyObject(Manifest manifest) {
var policyBase64 = manifest.encryptionInformation.policy;
var policyBytes = Base64.getDecoder().decode(policyBase64);
var policyJson = new String(policyBytes, StandardCharsets.UTF_8);
Expand Down
24 changes: 24 additions & 0 deletions sdk/src/main/java/io/opentdf/platform/sdk/SDK.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,30 @@ public static boolean isTDF(SeekableByteChannel channel) {
&& entries.stream().anyMatch(e -> "0.payload".equals(e.getName()));
}

/**
* Reads the {@link Manifest} without decrypting the TDF
* @param tdfBytes A SeekableByteChannel containing the TDF data
* @return The parsed {@link Manifest} object
* @throws SDKException if an SDK-specific error occurs
* @throws IOException if an I/O error occurs
*/
public static Manifest readManifest(SeekableByteChannel tdfBytes) throws SDKException, IOException {
TDFReader reader = new TDFReader(tdfBytes);
String manifestJson = reader.manifest();
return Manifest.readManifest(manifestJson);
}

/**
* Decodes a PolicyObject from the manifest. Use {@link SDK#readManifest(SeekableByteChannel)}
* to get the {@link Manifest} from a TDF.
* @param manifest The {@link Manifest} containing the policy.
* @return The decoded {@link PolicyObject}.
* @throws SDKException if there is an error during decoding.
*/
public static PolicyObject decodePolicyObject(Manifest manifest) throws SDKException {
return Manifest.decodePolicyObject(manifest);
}

public String getPlatformUrl() {
return platformUrl;
}
Expand Down
3 changes: 1 addition & 2 deletions sdk/src/main/java/io/opentdf/platform/sdk/TDF.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.StandardCharsets;
import java.security.*;
Expand Down Expand Up @@ -607,7 +606,7 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig)
TDFReader tdfReader = new TDFReader(tdf);
String manifestJson = tdfReader.manifest();
// use Manifest.readManifest in order to validate the Manifest input
Manifest manifest = Manifest.readManifest(new StringReader(manifestJson));
Manifest manifest = Manifest.readManifest(manifestJson);
byte[] payloadKey = new byte[GCM_KEY_SIZE];
String unencryptedMetadata = null;

Expand Down
10 changes: 3 additions & 7 deletions sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package io.opentdf.platform.sdk;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.StandardCharsets;
import java.util.Map;
Expand Down Expand Up @@ -64,10 +62,8 @@ int readPayloadBytes(byte[] buf) {
}

PolicyObject readPolicyObject() {
try (var reader = new BufferedReader(new InputStreamReader(manifestEntry.getData()))){
return Manifest.readPolicyObject(reader);
} catch (IOException e) {
throw new SDKException("error reading policy object", e);
}
String manifestJson = manifest();
Manifest manifest = Manifest.readManifest(manifestJson);
return Manifest.decodePolicyObject(manifest);
}
}
12 changes: 6 additions & 6 deletions sdk/src/test/java/io/opentdf/platform/sdk/ManifestTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -62,7 +61,7 @@ void testManifestMarshalAndUnMarshal() {
" }\n" +
"}";

Manifest manifest = Manifest.readManifest(new StringReader(kManifestJsonFromTDF));
Manifest manifest = Manifest.readManifest(kManifestJsonFromTDF);

// Test payload
assertEquals(manifest.payload.url, "0.payload");
Expand All @@ -85,7 +84,7 @@ void testManifestMarshalAndUnMarshal() {
assertEquals(manifest.encryptionInformation.integrityInformation.segments.get(0).segmentSize, 1048576);

var serialized = Manifest.toJson(manifest);
var deserializedAgain = Manifest.readManifest(new StringReader(serialized));
var deserializedAgain = Manifest.readManifest(serialized);

assertEquals(manifest, deserializedAgain, "something changed when we deserialized -> serialized -> deserialized");
}
Expand Down Expand Up @@ -140,7 +139,7 @@ void testAssertionNull() {
" \"assertions\": null\n"+
"}";

Manifest manifest = Manifest.readManifest(new StringReader(kManifestJsonFromTDF));
Manifest manifest = Manifest.readManifest(kManifestJsonFromTDF);

// Test payload for sanity check
assertEquals(manifest.payload.url, "0.payload");
Expand All @@ -155,7 +154,8 @@ void testReadingManifestWithObjectStatementValue() throws IOException {
final Manifest manifest;
try (var mStream = getClass().getResourceAsStream("/io.opentdf.platform.sdk.TestData/manifest-with-object-statement-value.json")) {
assert mStream != null;
manifest = Manifest.readManifest(new InputStreamReader(mStream)) ;
var manifestJson = new String(mStream.readAllBytes(), StandardCharsets.UTF_8);
manifest = Manifest.readManifest(manifestJson);
}

assertThat(manifest.assertions).hasSize(2);
Expand Down
15 changes: 15 additions & 0 deletions sdk/src/test/java/io/opentdf/platform/sdk/SDKTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,21 @@ public SeekableByteChannel truncate(long size) {
assertThat(SDK.isTDF(chan)).isFalse();
}

@Test
void testExaminingManifest() throws IOException {
try (var tdfStream = SDKTest.class.getClassLoader().getResourceAsStream("sample.txt.tdf")) {
assertThat(tdfStream)
.withFailMessage("sample.txt.tdf not found in classpath")
.isNotNull();
var manifest = SDK.readManifest(new SeekableInMemoryByteChannel(tdfStream.readAllBytes()));
assertThat(manifest).isNotNull();
assertThat(manifest.encryptionInformation.integrityInformation.encryptedSegmentSizeDefault)
.isEqualTo(1048604);
var policyObject = SDK.decodePolicyObject(manifest);
assertThat(policyObject.uuid).isEqualTo("98bb8a81-5217-4a31-8852-932d29d71aac");
}
}

@Test
void testReadingRandomBytes() {
var tdf = new byte[2023];
Expand Down