From 9a31922abd282fb6132ee07e049f01df7ba0010f Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 1 May 2025 15:02:14 -0400 Subject: [PATCH 01/16] log stuff --- .github/workflows/checks.yaml | 6 +- cmdline/src/main/resources/logging.properties | 56 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 cmdline/src/main/resources/logging.properties diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 0b472b2a..50671c1f 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -297,21 +297,21 @@ jobs: run: | printf 'here is some data to encrypt' > data - java -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=./src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ encrypt --kas-url=http://localhost:8080,http://localhost:8282 -f data -m 'here is some metadata' > test.tdf - java -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=./src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ decrypt -f test.tdf --kas-allowlist http://localhost:8080,http://localhost:8282 > decrypted - java -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=./src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ diff --git a/cmdline/src/main/resources/logging.properties b/cmdline/src/main/resources/logging.properties new file mode 100644 index 00000000..5cc13c55 --- /dev/null +++ b/cmdline/src/main/resources/logging.properties @@ -0,0 +1,56 @@ +############################################################ +# Default Logging Configuration File +# +# You can use a different file by specifying a filename +# with the java.util.logging.config.file system property. +# For example, java -Djava.util.logging.config.file=myfile +############################################################ + +############################################################ +# Global properties +############################################################ + +# "handlers" specifies a comma-separated list of log Handler +# classes. These handlers will be installed during VM startup. +# Note that these classes must be on the system classpath. +# By default we only configure a ConsoleHandler, which will only +# show messages at the INFO and above levels. +handlers= java.util.logging.ConsoleHandler + +# To also add the FileHandler, use the following line instead. +#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler + +# Default global logging level. +# This specifies which kinds of events are logged across +# all loggers. For any given facility this global level +# can be overridden by a facility-specific level +# Note that the ConsoleHandler also has a separate level +# setting to limit messages printed to the console. +.level= FINE + +############################################################ +# Handler specific properties. +# Describes specific configuration info for Handlers. +############################################################ + +io.grpc.level = FINE +io.grpc.netty.level = INFO + +# Limit the messages that are printed on the console to INFO and above. +java.util.logging.ConsoleHandler.level = FINE +java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter + +# Example to customize the SimpleFormatter output format +# to print one-line log message like this: +# : [] +# +# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n + +############################################################ +# Facility-specific properties. +# Provides extra control for each logger. +############################################################ + +# For example, set the com.xyz.foo logger to only log SEVERE +# messages: +# com.xyz.foo.level = SEVERE From 5426ae55f90dc0fdd071e08db43c66a3ee0fc63b Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 1 May 2025 15:22:22 -0400 Subject: [PATCH 02/16] absolute path? --- .github/workflows/checks.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 50671c1f..391384a1 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -149,21 +149,21 @@ jobs: run: | printf 'here is some data to encrypt' > data - java -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ encrypt --kas-url=http://localhost:8080 --mime-type=text/plain --attr https://example.com/attr/attr1/value/value1 --autoconfigure=false -f data -m 'here is some metadata' > test.tdf - java -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ decrypt -f test.tdf > decrypted - java -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ @@ -297,21 +297,21 @@ jobs: run: | printf 'here is some data to encrypt' > data - java -Djava.util.logging.config.file=./src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ encrypt --kas-url=http://localhost:8080,http://localhost:8282 -f data -m 'here is some metadata' > test.tdf - java -Djava.util.logging.config.file=./src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ decrypt -f test.tdf --kas-allowlist http://localhost:8080,http://localhost:8282 > decrypted - java -Djava.util.logging.config.file=./src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ From 50dbfb68f36e58be7e8099ddba37bf49a4540336 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 1 May 2025 15:33:34 -0400 Subject: [PATCH 03/16] fix the path --- .github/workflows/checks.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 391384a1..0bc27649 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -149,21 +149,21 @@ jobs: run: | printf 'here is some data to encrypt' > data - java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=$(pwd)/src/main/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ encrypt --kas-url=http://localhost:8080 --mime-type=text/plain --attr https://example.com/attr/attr1/value/value1 --autoconfigure=false -f data -m 'here is some metadata' > test.tdf - java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -Djava.util.logging.config.file=$(pwd)/src/main/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ decrypt -f test.tdf > decrypted - java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -Dio.grpc.level=FINE -Djava.util.logging.config.file=$(pwd)/src/main/resources/logging.properties -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ From 05c78a9b07106ac5e0552dea7b1525fa067c8aa2 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 2 May 2025 16:58:20 -0400 Subject: [PATCH 04/16] pass services in the context --- .../java/io/opentdf/platform/Command.java | 8 +- .../java/io/opentdf/platform/sdk/NanoTDF.java | 42 +++++----- .../java/io/opentdf/platform/sdk/SDK.java | 21 ++++- .../java/io/opentdf/platform/sdk/TDF.java | 41 ++++------ .../io/opentdf/platform/sdk/FakeServices.java | 78 ++++++++++++++++++ .../platform/sdk/FakeServicesBuilder.java | 57 +++++++++++++ .../java/io/opentdf/platform/sdk/Fuzzing.java | 10 +-- .../io/opentdf/platform/sdk/NanoTDFTest.java | 32 ++++---- .../io/opentdf/platform/sdk/TDFE2ETest.java | 12 +-- .../java/io/opentdf/platform/sdk/TDFTest.java | 79 ++++++++----------- 10 files changed, 254 insertions(+), 126 deletions(-) create mode 100644 sdk/src/test/java/io/opentdf/platform/sdk/FakeServices.java create mode 100644 sdk/src/test/java/io/opentdf/platform/sdk/FakeServicesBuilder.java diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 28235d76..3456c9f0 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -221,9 +221,7 @@ void encrypt( var tdfConfig = Config.newTDFConfig(configs.toArray(Consumer[]::new)); try (var in = file.isEmpty() ? new BufferedInputStream(System.in) : new FileInputStream(file.get())) { try (var out = new BufferedOutputStream(System.out)) { - new TDF().createTDF(in, out, tdfConfig, - sdk.getServices().kas(), - sdk.getServices().attributes()); + new TDF(sdk.getServices()).createTDF(in, out, tdfConfig); } } } @@ -297,7 +295,7 @@ void decrypt(@Option(names = { "-f", "--file" }, required = true) Path tdfPath, } var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); - var reader = new TDF().loadTDF(in, sdk.getServices().kas(), readerConfig, sdk.getServices().kasRegistry(), sdk.getPlatformUrl()); + var reader = new TDF(sdk.getServices()).loadTDF(in, readerConfig, sdk.getPlatformUrl()); reader.readPayload(stdout); } } @@ -321,7 +319,7 @@ void readMetadata(@Option(names = { "-f", "--file" }, required = true) Path tdfP } var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); - var reader = new TDF().loadTDF(in, sdk.getServices().kas(), readerConfig, sdk.getServices().kasRegistry(), sdk.getPlatformUrl()); + var reader = new TDF(sdk.getServices()).loadTDF(in, readerConfig, sdk.getPlatformUrl()); stdout.write(reader.getMetadata() == null ? "" : reader.getMetadata()); } } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java index 315ce915..a5d0b39a 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java @@ -1,6 +1,5 @@ package io.opentdf.platform.sdk; -import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub; import io.opentdf.platform.policy.kasregistry.ListKeyAccessServersRequest; import io.opentdf.platform.policy.kasregistry.ListKeyAccessServersResponse; import io.opentdf.platform.sdk.TDF.KasAllowlistException; @@ -38,17 +37,19 @@ public class NanoTDF { private static final int kIvPadding = 9; private static final int kNanoTDFIvSize = 3; private static final byte[] kEmptyIV = new byte[] { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + private final SDK.Services services; private final CollectionStore collectionStore; - public NanoTDF() { - this(new CollectionStore.NoOpCollectionStore()); + NanoTDF(SDK.Services services) { + this(services, new CollectionStore.NoOpCollectionStore()); } - public NanoTDF(boolean collectionStoreEnabled) { - this(collectionStoreEnabled ? new CollectionStoreImpl() : null); + NanoTDF(SDK.Services services, boolean collectionStoreEnabled) { + this(services, collectionStoreEnabled ? new CollectionStoreImpl() : null); } - public NanoTDF(CollectionStore collectionStore) { + NanoTDF(SDK.Services services, CollectionStore collectionStore) { + this.services = services; this.collectionStore = collectionStore; } @@ -70,7 +71,7 @@ public InvalidNanoTDFConfig(String errorMessage) { } } - private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig, SDK.KAS kas) + private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) throws InvalidNanoTDFConfig, UnsupportedNanoTDFFeature, NoSuchAlgorithmException, InterruptedException { if (nanoTDFConfig.collectionConfig.useCollection) { Config.HeaderInfo headerInfo = nanoTDFConfig.collectionConfig.getHeaderInfo(); @@ -88,7 +89,7 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig, SDK. String url = kasInfo.URL; if (kasInfo.PublicKey == null || kasInfo.PublicKey.isEmpty()) { logger.info("no public key provided for KAS at {}, retrieving", url); - kasInfo = kas.getECPublicKey(kasInfo, nanoTDFConfig.eccMode.getEllipticCurveType()); + kasInfo = services.kas().getECPublicKey(kasInfo, nanoTDFConfig.eccMode.getEllipticCurveType()); } // Kas url resource locator @@ -148,8 +149,7 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig, SDK. } public int createNanoTDF(ByteBuffer data, OutputStream outputStream, - Config.NanoTDFConfig nanoTDFConfig, - SDK.KAS kas) throws IOException, NanoTDFMaxSizeLimit, InvalidNanoTDFConfig, + Config.NanoTDFConfig nanoTDFConfig) throws IOException, NanoTDFMaxSizeLimit, InvalidNanoTDFConfig, NoSuchAlgorithmException, UnsupportedNanoTDFFeature, InterruptedException { int nanoTDFSize = 0; @@ -158,7 +158,7 @@ public int createNanoTDF(ByteBuffer data, OutputStream outputStream, throw new NanoTDFMaxSizeLimit("exceeds max size for nano tdf"); } - Config.HeaderInfo headerKeyPair = getHeaderInfo(nanoTDFConfig, kas); + Config.HeaderInfo headerKeyPair = getHeaderInfo(nanoTDFConfig); Header header = headerKeyPair.getHeader(); AesGcm gcm = headerKeyPair.getKey(); int iteration = headerKeyPair.getIteration(); @@ -205,22 +205,20 @@ public int createNanoTDF(ByteBuffer data, OutputStream outputStream, return nanoTDFSize; } - public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, - SDK.KAS kas) throws IOException, URISyntaxException { - readNanoTDF(nanoTDF, outputStream,kas, Config.newNanoTDFReaderConfig()); + public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream) throws IOException, URISyntaxException { + readNanoTDF(nanoTDF, outputStream, Config.newNanoTDFReaderConfig()); } - public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, - SDK.KAS kas, KeyAccessServerRegistryServiceFutureStub kasRegistryService, String platformUrl) throws IOException, InterruptedException, ExecutionException, URISyntaxException { - readNanoTDF(nanoTDF, outputStream,kas, Config.newNanoTDFReaderConfig(), kasRegistryService, platformUrl); + public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, String platformUrl) throws IOException, InterruptedException, ExecutionException, URISyntaxException { + readNanoTDF(nanoTDF, outputStream, Config.newNanoTDFReaderConfig(), platformUrl); } public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, - SDK.KAS kas, Config.NanoTDFReaderConfig nanoTdfReaderConfig, KeyAccessServerRegistryServiceFutureStub kasRegistryService, String platformUrl) throws IOException, InterruptedException, ExecutionException, URISyntaxException { + Config.NanoTDFReaderConfig nanoTdfReaderConfig, String platformUrl) throws IOException, InterruptedException, ExecutionException, URISyntaxException { if (!nanoTdfReaderConfig.ignoreKasAllowlist && (nanoTdfReaderConfig.kasAllowlist == null || nanoTdfReaderConfig.kasAllowlist.isEmpty())) { ListKeyAccessServersRequest request = ListKeyAccessServersRequest.newBuilder() .build(); - ListKeyAccessServersResponse response = kasRegistryService.listKeyAccessServers(request).get(); + ListKeyAccessServersResponse response = services.kasRegistry().listKeyAccessServers(request).get(); nanoTdfReaderConfig.kasAllowlist = new HashSet<>(); var kases = response.getKeyAccessServersList(); @@ -230,12 +228,12 @@ public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, nanoTdfReaderConfig.kasAllowlist.add(Config.getKasAddress(platformUrl)); } - readNanoTDF(nanoTDF, outputStream, kas, nanoTdfReaderConfig); + readNanoTDF(nanoTDF, outputStream, nanoTdfReaderConfig); } public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, - SDK.KAS kas, Config.NanoTDFReaderConfig nanoTdfReaderConfig) throws IOException, URISyntaxException { + Config.NanoTDFReaderConfig nanoTdfReaderConfig) throws IOException, URISyntaxException { Header header = new Header(nanoTDF); CollectionKey cachedKey = collectionStore.getKey(header); @@ -264,7 +262,7 @@ public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, } - key = kas.unwrapNanoTDF(header.getECCMode().getEllipticCurveType(), + key = services.kas().unwrapNanoTDF(header.getECCMode().getEllipticCurveType(), base64HeaderData, kasUrl); collectionStore.store(header, new CollectionKey(key)); diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java index d23d106f..85c0bae3 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java @@ -1,11 +1,8 @@ package io.opentdf.platform.sdk; -import io.grpc.CallOptions; -import io.grpc.Channel; -import io.grpc.ClientCall; +import com.nimbusds.jose.JOSEException; import io.grpc.ClientInterceptor; import io.grpc.ManagedChannel; -import io.grpc.MethodDescriptor; import io.opentdf.platform.authorization.AuthorizationServiceGrpc; import io.opentdf.platform.authorization.AuthorizationServiceGrpc.AuthorizationServiceFutureStub; import io.opentdf.platform.policy.attributes.AttributesServiceGrpc; @@ -19,13 +16,19 @@ import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceGrpc; import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub; import io.opentdf.platform.sdk.nanotdf.NanoTDFType; +import org.apache.commons.codec.DecoderException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.net.ssl.TrustManager; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.nio.channels.SeekableByteChannel; +import java.security.NoSuchAlgorithmException; +import java.text.ParseException; import java.util.Optional; +import java.util.concurrent.ExecutionException; /** * The SDK class represents a software development kit for interacting with the @@ -159,6 +162,16 @@ public Services getServices() { return this.services; } + public TDF.Reader loadTDF(SeekableByteChannel channel, Config.TDFReaderConfig config) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException { + var tdf = new TDF(services); + return tdf.loadTDF(channel, config); + } + + public TDF.TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig config) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, ExecutionException, InterruptedException { + var tdf = new TDF(services); + return tdf.createTDF(payload, outputStream, config); + } + /** * Checks to see if this has the structure of a Z-TDF in that it is a zip file * containing diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index 598522eb..5787fb73 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -5,8 +5,6 @@ import com.nimbusds.jose.*; import io.opentdf.platform.policy.Value; -import io.opentdf.platform.policy.attributes.AttributesServiceGrpc.AttributesServiceFutureStub; -import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub; import io.opentdf.platform.policy.kasregistry.ListKeyAccessServersRequest; import io.opentdf.platform.policy.kasregistry.ListKeyAccessServersResponse; import io.opentdf.platform.sdk.Config.TDFConfig; @@ -59,6 +57,8 @@ private static byte[] tdfECKeySaltCompute() { private static final String KEY_ACCESS_SECHMA_VERSION = "1.0"; private final long maximumSize; + private final SDK.Services services; + /** * Constructs a new TDF instance using the default maximum input size defined by MAX_TDF_INPUT_SIZE. *

@@ -66,14 +66,15 @@ private static byte[] tdfECKeySaltCompute() { * input size, which controls the maximum size of the input data that can be processed. * For test purposes, an alternative constructor allows for setting a custom maximum input size. */ - public TDF() { - this(MAX_TDF_INPUT_SIZE); + TDF(SDK.Services services) { + this(MAX_TDF_INPUT_SIZE, services); } // constructor for tests so that we can set a maximum size that's tractable for // tests - TDF(long maximumInputSize) { + TDF(long maximumInputSize, SDK.Services services) { this.maximumSize = maximumInputSize; + this.services = services; } public static Logger logger = LoggerFactory.getLogger(TDF.class); @@ -483,9 +484,7 @@ private static byte[] calculateSignature(byte[] data, byte[] secret, Config.Inte return Arrays.copyOfRange(data, data.length - kGMACPayloadLength, data.length); } - public TDFObject createTDF(InputStream payload, - OutputStream outputStream, - Config.TDFConfig tdfConfig, SDK.KAS kas, AttributesServiceFutureStub attrService) + public TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig tdfConfig) throws IOException, JOSEException, AutoConfigureException, InterruptedException, ExecutionException, DecoderException { if (tdfConfig.autoconfigure) { @@ -493,7 +492,7 @@ public TDFObject createTDF(InputStream payload, if (tdfConfig.attributeValues != null && !tdfConfig.attributeValues.isEmpty()) { granter = Autoconfigure.newGranterFromAttributes(tdfConfig.attributeValues.toArray(new Value[0])); } else if (tdfConfig.attributes != null && !tdfConfig.attributes.isEmpty()) { - granter = Autoconfigure.newGranterFromService(attrService, kas.getKeyCache(), + granter = Autoconfigure.newGranterFromService(services.attributes(), services.kas().getKeyCache(), tdfConfig.attributes.toArray(new AttributeValueFQN[0])); } @@ -515,7 +514,7 @@ public TDFObject createTDF(InputStream payload, } TDFObject tdfObject = new TDFObject(); - tdfObject.prepareManifest(tdfConfig, kas); + tdfObject.prepareManifest(tdfConfig, services.kas()); long encryptedSegmentSize = tdfConfig.defaultSegmentSize + kGcmIvSize + kAesBlockSize; TDFWriter tdfWriter = new TDFWriter(outputStream); @@ -637,7 +636,7 @@ public TDFObject createTDF(InputStream payload, return tdfObject; } - public List defaultKases(TDFConfig config) { + public static List defaultKases(TDFConfig config) { List allk = new ArrayList<>(); List defk = new ArrayList<>(); @@ -654,22 +653,17 @@ public List defaultKases(TDFConfig config) { return defk; } - public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas) - throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException { - return loadTDF(tdf, kas, Config.newTDFReaderConfig()); - } - - public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, KeyAccessServerRegistryServiceFutureStub kasRegistryService, String platformUrl) + public Reader loadTDF(SeekableByteChannel tdf, String platformUrl) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, InterruptedException, ExecutionException, URISyntaxException { - return loadTDF(tdf, kas, Config.newTDFReaderConfig(), kasRegistryService, platformUrl); + return loadTDF(tdf, Config.newTDFReaderConfig(), platformUrl); } - public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.TDFReaderConfig tdfReaderConfig, KeyAccessServerRegistryServiceFutureStub kasRegistryService, String platformUrl) + public Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, String platformUrl) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, InterruptedException, ExecutionException, URISyntaxException { if (!tdfReaderConfig.ignoreKasAllowlist && (tdfReaderConfig.kasAllowlist == null || tdfReaderConfig.kasAllowlist.isEmpty())) { ListKeyAccessServersRequest request = ListKeyAccessServersRequest.newBuilder() .build(); - ListKeyAccessServersResponse response = kasRegistryService.listKeyAccessServers(request).get(); + ListKeyAccessServersResponse response = services.kasRegistry().listKeyAccessServers(request).get(); tdfReaderConfig.kasAllowlist = new HashSet<>(); for (var entry : response.getKeyAccessServersList()) { @@ -677,11 +671,10 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, Config.TDFReaderConf } tdfReaderConfig.kasAllowlist.add(Config.getKasAddress(platformUrl)); } - return loadTDF(tdf, kas, tdfReaderConfig); + return loadTDF(tdf, tdfReaderConfig); } - public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, - Config.TDFReaderConfig tdfReaderConfig) + public Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) throws RootSignatureValidationException, SegmentSizeMismatch, IOException, FailedToCreateGMAC, JOSEException, ParseException, NoSuchAlgorithmException, DecoderException { @@ -718,7 +711,7 @@ public Reader loadTDF(SeekableByteChannel tdf, SDK.KAS kas, logger.error("KasAllowlist: kas url {} is not allowed", realAddress); throw new KasAllowlistException("KasAllowlist: kas url "+realAddress+" is not allowed"); } - unwrappedKey = kas.unwrap(keyAccess, manifest.encryptionInformation.policy, tdfReaderConfig.sessionKeyType); + unwrappedKey = services.kas().unwrap(keyAccess, manifest.encryptionInformation.policy, tdfReaderConfig.sessionKeyType); } catch (Exception e) { skippedSplits.put(ss, e); continue; diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/FakeServices.java b/sdk/src/test/java/io/opentdf/platform/sdk/FakeServices.java new file mode 100644 index 00000000..dca1e6e1 --- /dev/null +++ b/sdk/src/test/java/io/opentdf/platform/sdk/FakeServices.java @@ -0,0 +1,78 @@ +package io.opentdf.platform.sdk; + +import io.opentdf.platform.authorization.AuthorizationServiceGrpc; +import io.opentdf.platform.policy.attributes.AttributesServiceGrpc; +import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceGrpc; +import io.opentdf.platform.policy.namespaces.NamespaceServiceGrpc; +import io.opentdf.platform.policy.resourcemapping.ResourceMappingServiceGrpc; +import io.opentdf.platform.policy.subjectmapping.SubjectMappingServiceGrpc; + +import java.util.Objects; + +public class FakeServices implements SDK.Services { + + private final AuthorizationServiceGrpc.AuthorizationServiceFutureStub authorizationService; + private final AttributesServiceGrpc.AttributesServiceFutureStub attributesService; + private final NamespaceServiceGrpc.NamespaceServiceFutureStub namespaceService; + private final SubjectMappingServiceGrpc.SubjectMappingServiceFutureStub subjectMappingService; + private final ResourceMappingServiceGrpc.ResourceMappingServiceFutureStub resourceMappingService; + private final KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub keyAccessServerRegistryServiceFutureStub; + private final SDK.KAS kas; + + public FakeServices( + AuthorizationServiceGrpc.AuthorizationServiceFutureStub authorizationService, + AttributesServiceGrpc.AttributesServiceFutureStub attributesService, + NamespaceServiceGrpc.NamespaceServiceFutureStub namespaceService, + SubjectMappingServiceGrpc.SubjectMappingServiceFutureStub subjectMappingService, + ResourceMappingServiceGrpc.ResourceMappingServiceFutureStub resourceMappingService, + KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub keyAccessServerRegistryServiceFutureStub, + SDK.KAS kas) { + this.authorizationService = authorizationService; + this.attributesService = attributesService; + this.namespaceService = namespaceService; + this.subjectMappingService = subjectMappingService; + this.resourceMappingService = resourceMappingService; + this.keyAccessServerRegistryServiceFutureStub = keyAccessServerRegistryServiceFutureStub; + this.kas = kas; + } + + @Override + public AuthorizationServiceGrpc.AuthorizationServiceFutureStub authorization() { + return Objects.requireNonNull(authorizationService); + } + + @Override + public AttributesServiceGrpc.AttributesServiceFutureStub attributes() { + return Objects.requireNonNull(attributesService); + } + + @Override + public NamespaceServiceGrpc.NamespaceServiceFutureStub namespaces() { + return Objects.requireNonNull(namespaceService); + } + + @Override + public SubjectMappingServiceGrpc.SubjectMappingServiceFutureStub subjectMappings() { + return Objects.requireNonNull(subjectMappingService); + } + + @Override + public ResourceMappingServiceGrpc.ResourceMappingServiceFutureStub resourceMappings() { + return Objects.requireNonNull(resourceMappingService); + } + + @Override + public KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub kasRegistry() { + return Objects.requireNonNull(keyAccessServerRegistryServiceFutureStub); + } + + @Override + public SDK.KAS kas() { + return Objects.requireNonNull(kas); + } + + @Override + public void close() { + // no-op for this fake stuff in tests + } +} diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/FakeServicesBuilder.java b/sdk/src/test/java/io/opentdf/platform/sdk/FakeServicesBuilder.java new file mode 100644 index 00000000..31e33087 --- /dev/null +++ b/sdk/src/test/java/io/opentdf/platform/sdk/FakeServicesBuilder.java @@ -0,0 +1,57 @@ +package io.opentdf.platform.sdk; + +import io.opentdf.platform.authorization.AuthorizationServiceGrpc; +import io.opentdf.platform.policy.attributes.AttributesServiceGrpc; +import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceGrpc; +import io.opentdf.platform.policy.namespaces.NamespaceServiceGrpc; +import io.opentdf.platform.policy.resourcemapping.ResourceMappingServiceGrpc; +import io.opentdf.platform.policy.subjectmapping.SubjectMappingServiceGrpc; + +public class FakeServicesBuilder { + private AuthorizationServiceGrpc.AuthorizationServiceFutureStub authorizationService; + private AttributesServiceGrpc.AttributesServiceFutureStub attributesService; + private NamespaceServiceGrpc.NamespaceServiceFutureStub namespaceService; + private SubjectMappingServiceGrpc.SubjectMappingServiceFutureStub subjectMappingService; + private ResourceMappingServiceGrpc.ResourceMappingServiceFutureStub resourceMappingService; + private KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub keyAccessServerRegistryServiceFutureStub; + private SDK.KAS kas; + + public FakeServicesBuilder setAuthorizationService(AuthorizationServiceGrpc.AuthorizationServiceFutureStub authorizationService) { + this.authorizationService = authorizationService; + return this; + } + + public FakeServicesBuilder setAttributesService(AttributesServiceGrpc.AttributesServiceFutureStub attributesService) { + this.attributesService = attributesService; + return this; + } + + public FakeServicesBuilder setNamespaceService(NamespaceServiceGrpc.NamespaceServiceFutureStub namespaceService) { + this.namespaceService = namespaceService; + return this; + } + + public FakeServicesBuilder setSubjectMappingService(SubjectMappingServiceGrpc.SubjectMappingServiceFutureStub subjectMappingService) { + this.subjectMappingService = subjectMappingService; + return this; + } + + public FakeServicesBuilder setResourceMappingService(ResourceMappingServiceGrpc.ResourceMappingServiceFutureStub resourceMappingService) { + this.resourceMappingService = resourceMappingService; + return this; + } + + public FakeServicesBuilder setKeyAccessServerRegistryService(KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub keyAccessServerRegistryServiceFutureStub) { + this.keyAccessServerRegistryServiceFutureStub = keyAccessServerRegistryServiceFutureStub; + return this; + } + + public FakeServicesBuilder setKas(SDK.KAS kas) { + this.kas = kas; + return this; + } + + public FakeServices build() { + return new FakeServices(authorizationService, attributesService, namespaceService, subjectMappingService, resourceMappingService, keyAccessServerRegistryServiceFutureStub, kas); + } +} \ No newline at end of file diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java b/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java index 6b406038..089a884b 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java @@ -35,22 +35,22 @@ public void write(byte[] b, int off, int len) { @FuzzTest(maxDuration=TEST_DURATION) public void fuzzNanoTDF(FuzzedDataProvider data) throws IOException, URISyntaxException { byte[] fuzzBytes = data.consumeRemainingAsBytes(); - NanoTDF nanoTDF = new NanoTDF(); - nanoTDF.readNanoTDF(ByteBuffer.wrap(fuzzBytes), IGNORE_OUTPUT_STREAM, NanoTDFTest.kas); + NanoTDF nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(NanoTDFTest.kas).build()); + nanoTDF.readNanoTDF(ByteBuffer.wrap(fuzzBytes), IGNORE_OUTPUT_STREAM); } @FuzzTest(maxDuration=TEST_DURATION) - public void fuzzTDF(FuzzedDataProvider data) throws FailedToCreateGMAC, NoSuchAlgorithmException, IOException, JOSEException, ParseException, DecoderException { + public void fuzzTDF(FuzzedDataProvider data) throws FailedToCreateGMAC, NoSuchAlgorithmException, 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(); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(TDFTest.kas).build()); try { - Reader reader = tdf.loadTDF(new SeekableInMemoryByteChannel(fuzzBytes), TDFTest.kas, readerConfig); + Reader reader = tdf.loadTDF(new SeekableInMemoryByteChannel(fuzzBytes), readerConfig); reader.readPayload(IGNORE_OUTPUT_STREAM); } catch (SDKException | InvalidZipException | JsonParseException | IOException | IllegalArgumentException e) { 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 e6bf21ca..2eeb4af3 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java @@ -163,13 +163,13 @@ void encryptionAndDecryptionWithValidKey() throws Exception { ByteBuffer byteBuffer = ByteBuffer.wrap(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - NanoTDF nanoTDF = new NanoTDF(); - nanoTDF.createNanoTDF(byteBuffer, tdfOutputStream, config, kas); + NanoTDF nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + nanoTDF.createNanoTDF(byteBuffer, tdfOutputStream, config); byte[] nanoTDFBytes = tdfOutputStream.toByteArray(); ByteArrayOutputStream plainTextStream = new ByteArrayOutputStream(); - nanoTDF = new NanoTDF(); - nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, kas, kasRegistryService, platformUrl); + nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, platformUrl); String out = new String(plainTextStream.toByteArray(), StandardCharsets.UTF_8); assertThat(out).isEqualTo(plainText); @@ -184,12 +184,12 @@ void encryptionAndDecryptionWithValidKey() throws Exception { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - NanoTDF nTDF = new NanoTDF(); - nTDF.createNanoTDF(ByteBuffer.wrap(data), outputStream, config, kas); + NanoTDF nTDF = new NanoTDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + nTDF.createNanoTDF(ByteBuffer.wrap(data), outputStream, config); byte[] nTDFBytes = outputStream.toByteArray(); ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); - nanoTDF.readNanoTDF(ByteBuffer.wrap(nTDFBytes), dataStream, kas, kasRegistryService, platformUrl); + nanoTDF.readNanoTDF(ByteBuffer.wrap(nTDFBytes), dataStream, platformUrl); assertThat(dataStream.toByteArray()).isEqualTo(data); } } @@ -211,26 +211,26 @@ void runBasicTest(String kasUrl, boolean allowed, KeyAccessServerRegistryService ByteBuffer byteBuffer = ByteBuffer.wrap(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - NanoTDF nanoTDF = new NanoTDF(); - nanoTDF.createNanoTDF(byteBuffer, tdfOutputStream, config, kas); + NanoTDF nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasReg).build()); + nanoTDF.createNanoTDF(byteBuffer, tdfOutputStream, config); byte[] nanoTDFBytes = tdfOutputStream.toByteArray(); ByteArrayOutputStream plainTextStream = new ByteArrayOutputStream(); - nanoTDF = new NanoTDF(); + nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasReg).build()); if (allowed) { if (decryptConfig != null) { - nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, kas, decryptConfig); + nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, decryptConfig); } else { - nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, kas, kasReg, platformUrl); + nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, platformUrl); } String out = new String(plainTextStream.toByteArray(), StandardCharsets.UTF_8); assertThat(out).isEqualTo(plainText); } else { try { if (decryptConfig != null) { - nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, kas, decryptConfig); + nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, decryptConfig); } else { - nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, kas, kasReg, platformUrl); + nanoTDF.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, platformUrl); } assertThat(false).isTrue(); } catch (SDKException e) { @@ -290,7 +290,7 @@ void collection() throws Exception { ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[]{}); - NanoTDF nanoTDF = new NanoTDF(); + NanoTDF nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(kas).build()); ByteBuffer header = getHeaderBuffer(byteBuffer,nanoTDF, config); for (int i = 0; i < Config.MAX_COLLECTION_ITERATION - 10; i++) { config.collectionConfig.getHeaderInfo(); @@ -307,7 +307,7 @@ void collection() throws Exception { private ByteBuffer getHeaderBuffer(ByteBuffer input, NanoTDF nanoTDF, Config.NanoTDFConfig config) throws Exception { ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - nanoTDF.createNanoTDF(input, tdfOutputStream, config, kas); + nanoTDF.createNanoTDF(input, tdfOutputStream, config); ByteBuffer tdf = ByteBuffer.wrap(tdfOutputStream.toByteArray()); Header header = new Header(tdf); return tdf.position(0).slice().limit(header.getTotalSize()); diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/TDFE2ETest.java b/sdk/src/test/java/io/opentdf/platform/sdk/TDFE2ETest.java index fb2441b7..ea79d77a 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFE2ETest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFE2ETest.java @@ -54,11 +54,11 @@ public void createAndDecryptTdfIT() throws Exception { InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, configPair.tdfConfig, sdk.getServices().kas(), sdk.getServices().attributes()); + TDF tdf = new TDF(sdk.getServices()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, configPair.tdfConfig); var unwrappedData = new java.io.ByteArrayOutputStream(); - var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), sdk.getServices().kas(), configPair.tdfReaderConfig, sdk.getServices().kasRegistry(), sdk.getPlatformUrl()); + var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), configPair.tdfReaderConfig, sdk.getPlatformUrl()); reader.readPayload(unwrappedData); assertThat(unwrappedData.toString(StandardCharsets.UTF_8)).isEqualTo("text"); @@ -85,12 +85,12 @@ public void createAndDecryptNanoTDF() throws Exception { String plainText = "text"; ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - NanoTDF ntdf = new NanoTDF(); - ntdf.createNanoTDF(ByteBuffer.wrap(plainText.getBytes()), tdfOutputStream, config, sdk.kas()); + NanoTDF ntdf = new NanoTDF(sdk); + ntdf.createNanoTDF(ByteBuffer.wrap(plainText.getBytes()), tdfOutputStream, config); byte[] nanoTDFBytes = tdfOutputStream.toByteArray(); ByteArrayOutputStream plainTextStream = new ByteArrayOutputStream(); - ntdf.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream, sdk.kas()); + ntdf.readNanoTDF(ByteBuffer.wrap(nanoTDFBytes), plainTextStream); String out = new String(plainTextStream.toByteArray(), "UTF-8"); assertThat(out).isEqualTo("text"); diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java index 592694e6..cb516a1c 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java @@ -22,7 +22,6 @@ import java.io.OutputStream; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; -import java.security.Key; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; @@ -210,12 +209,11 @@ public TDFConfigPair(Config.TDFConfig tdfConfig, Config.TDFReaderConfig tdfReade InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, configPair.tdfConfig, kas, null); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, configPair.tdfConfig); var unwrappedData = new ByteArrayOutputStream(); - var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, - configPair.tdfReaderConfig, kasRegistryService, platformUrl); + var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), configPair.tdfReaderConfig, platformUrl); assertThat(reader.getManifest().payload.mimeType).isEqualTo("application/octet-stream"); reader.readPayload(unwrappedData); @@ -260,8 +258,8 @@ void testSimpleTDFWithAssertionWithRS256() throws Exception { InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); var assertionVerificationKeys = new Config.AssertionVerificationKeys(); assertionVerificationKeys.keys.put(assertion1Id, @@ -270,8 +268,7 @@ void testSimpleTDFWithAssertionWithRS256() throws Exception { var unwrappedData = new ByteArrayOutputStream(); Config.TDFReaderConfig readerConfig = Config.newTDFReaderConfig( Config.withAssertionVerificationKeys(assertionVerificationKeys)); - var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, - readerConfig, kasRegistryService, platformUrl); + var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), readerConfig, platformUrl); reader.readPayload(unwrappedData); assertThat(unwrappedData.toString(StandardCharsets.UTF_8)) @@ -304,8 +301,8 @@ void testWithAssertionVerificationDisabled() throws Exception { InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); var assertionVerificationKeys = new Config.AssertionVerificationKeys(); assertionVerificationKeys.keys.put(assertion1Id, @@ -313,15 +310,13 @@ void testWithAssertionVerificationDisabled() throws Exception { var unwrappedData = new ByteArrayOutputStream(); assertThrows(JOSEException.class, () -> { - tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, - Config.newTDFReaderConfig(), kasRegistryService, platformUrl); + tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), Config.newTDFReaderConfig(), platformUrl); }); // try with assertion verification disabled and not passing the assertion verification keys Config.TDFReaderConfig readerConfig = Config.newTDFReaderConfig( Config.withDisableAssertionVerification(true)); - var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, - readerConfig, kasRegistryService, platformUrl); + var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), readerConfig, platformUrl); reader.readPayload(unwrappedData); assertThat(unwrappedData.toString(StandardCharsets.UTF_8)) @@ -364,12 +359,11 @@ void testSimpleTDFWithAssertionWithHS256() throws Exception { InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); var unwrappedData = new ByteArrayOutputStream(); - var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), - kas, Config.newTDFReaderConfig(), kasRegistryService, platformUrl); + var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), Config.newTDFReaderConfig(), platformUrl); reader.readPayload(unwrappedData); assertThat(unwrappedData.toString(StandardCharsets.UTF_8)) @@ -428,8 +422,8 @@ void testSimpleTDFWithAssertionWithHS256Failure() throws Exception { InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); byte[] notkey = new byte[32]; secureRandom.nextBytes(notkey); @@ -439,10 +433,8 @@ void testSimpleTDFWithAssertionWithHS256Failure() throws Exception { Config.TDFReaderConfig readerConfig = Config.newTDFReaderConfig( Config.withAssertionVerificationKeys(assertionVerificationKeys)); - var unwrappedData = new ByteArrayOutputStream(); - Reader reader; try { - reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, readerConfig, kasRegistryService, platformUrl); + tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), readerConfig, platformUrl); throw new RuntimeException("assertion verify key error thrown"); } catch (SDKException e) { @@ -464,10 +456,10 @@ public void testCreatingTDFWithMultipleSegments() throws Exception { random.nextBytes(data); var plainTextInputStream = new ByteArrayInputStream(data); var tdfOutputStream = new ByteArrayOutputStream(); - var tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + var tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); var unwrappedData = new ByteArrayOutputStream(); - var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, kasRegistryService, platformUrl); + var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), platformUrl); reader.readPayload(unwrappedData); assertThat(unwrappedData.toByteArray()) @@ -511,13 +503,13 @@ public void write(byte[] b, int off, int len) { } }; - var tdf = new TDF(maxSize); + var tdf = new TDF(maxSize, new FakeServicesBuilder().setKas(kas).build()); var tdfConfig = Config.newTDFConfig( Config.withAutoconfigure(false), Config.withKasInformation(getRSAKASInfos()), Config.withSegmentSize(Config.MIN_SEGMENT_SIZE)); assertThrows(TDF.DataSizeNotSupported.class, - () -> tdf.createTDF(is, os, tdfConfig, kas, null), + () -> tdf.createTDF(is, os, tdfConfig), "didn't throw an exception when we created TDF that was too large"); assertThat(numReturned.get()) .withFailMessage("test returned the wrong number of bytes") @@ -537,10 +529,10 @@ public void testCreateTDFWithMimeType() throws Exception { InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); - var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, kasRegistryService, platformUrl); + var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), platformUrl); assertThat(reader.getManifest().payload.mimeType).isEqualTo(mimeType); } @@ -569,12 +561,12 @@ public void legacyTDFRoundTrips() throws DecoderException, IOException, Executio InputStream plainTextInputStream = new ByteArrayInputStream(data); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryService).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); var dataOutputStream = new ByteArrayOutputStream(); - var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, kasRegistryService, platformUrl); + var reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), platformUrl); var integrityInformation = reader.getManifest().encryptionInformation.integrityInformation; assertThat(reader.getManifest().tdfVersion).isNull(); var decodedSignature = Base64.getDecoder().decode(integrityInformation.rootSignature.signature); @@ -636,15 +628,14 @@ void testKasAllowlist() throws Exception { InputStream plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); ByteArrayOutputStream tdfOutputStream = new ByteArrayOutputStream(); - TDF tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + TDF tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryServiceNoUrl).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); var unwrappedData = new ByteArrayOutputStream(); - Reader reader; // should throw error because the kas url is not in the allowlist try { - reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, Config.newTDFReaderConfig(), kasRegistryServiceNoUrl, platformUrl); + tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), Config.newTDFReaderConfig(), platformUrl); throw new RuntimeException("expected allowlist error to be thrown"); } catch (Exception e) { assertThat(e).hasMessageContaining("KasAllowlist"); @@ -653,12 +644,12 @@ void testKasAllowlist() throws Exception { // with custom allowlist should succeed Config.TDFReaderConfig readerConfig = Config.newTDFReaderConfig( Config.WithKasAllowlist("https://example.com")); - reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, readerConfig, kasRegistryServiceNoUrl, platformUrl); + tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), readerConfig, platformUrl); // with ignore allowlist should succeed readerConfig = Config.newTDFReaderConfig( Config.WithIgnoreKasAllowlist(true)); - reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, readerConfig, kasRegistryServiceNoUrl, platformUrl); + Reader reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), readerConfig, platformUrl); reader.readPayload(unwrappedData); assertThat(unwrappedData.toString(StandardCharsets.UTF_8)) @@ -674,11 +665,11 @@ void testKasAllowlist() throws Exception { Config.withKasInformation(platformKasInfo)); plainTextInputStream = new ByteArrayInputStream(plainText.getBytes()); tdfOutputStream = new ByteArrayOutputStream(); - tdf = new TDF(); - tdf.createTDF(plainTextInputStream, tdfOutputStream, config, kas, null); + tdf = new TDF(new FakeServicesBuilder().setKas(kas).setKeyAccessServerRegistryService(kasRegistryServiceNoUrl).build()); + tdf.createTDF(plainTextInputStream, tdfOutputStream, config); unwrappedData = new ByteArrayOutputStream(); - reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), kas, Config.newTDFReaderConfig(), kasRegistryServiceNoUrl, platformUrl); + reader = tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), Config.newTDFReaderConfig(), platformUrl); reader.readPayload(unwrappedData); assertThat(unwrappedData.toString(StandardCharsets.UTF_8)) From 6e6d4ee52622894ef0988e9e4d718f956a26dcf5 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Sat, 3 May 2025 10:59:10 -0400 Subject: [PATCH 05/16] fix api calls --- .../src/main/java/io/opentdf/platform/Command.java | 14 ++++++-------- .../opentdf/platform/DecryptCollectionExample.java | 4 +--- .../java/io/opentdf/platform/DecryptExample.java | 2 +- .../opentdf/platform/EncryptCollectionExample.java | 8 +------- .../java/io/opentdf/platform/EncryptExample.java | 4 +--- sdk/src/main/java/io/opentdf/platform/sdk/SDK.java | 14 +++++++++++++- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 4 ++-- 7 files changed, 25 insertions(+), 25 deletions(-) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 3456c9f0..3d292c54 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -192,8 +192,8 @@ void encrypt( } catch (JsonSyntaxException e) { // try it as a file path try { - String fielJson = new String(Files.readAllBytes(Paths.get(assertionConfig))); - assertionConfigs = gson.fromJson(fielJson, AssertionConfig[].class); + String fileJson = new String(Files.readAllBytes(Paths.get(assertionConfig))); + assertionConfigs = gson.fromJson(fileJson, AssertionConfig[].class); } catch (JsonSyntaxException e2) { throw new RuntimeException("Failed to parse assertion from file, expects an list of assertions", e2); } catch(Exception e3) { @@ -221,7 +221,7 @@ void encrypt( var tdfConfig = Config.newTDFConfig(configs.toArray(Consumer[]::new)); try (var in = file.isEmpty() ? new BufferedInputStream(System.in) : new FileInputStream(file.get())) { try (var out = new BufferedOutputStream(System.out)) { - new TDF(sdk.getServices()).createTDF(in, out, tdfConfig); + sdk.createTDF(in, out, tdfConfig); } } } @@ -319,7 +319,7 @@ void readMetadata(@Option(names = { "-f", "--file" }, required = true) Path tdfP } var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); - var reader = new TDF(sdk.getServices()).loadTDF(in, readerConfig, sdk.getPlatformUrl()); + var reader = sdk.loadTDF(in, readerConfig); stdout.write(reader.getMetadata() == null ? "" : reader.getMetadata()); } } @@ -349,8 +349,7 @@ void createNanoTDF( var nanoTDFConfig = Config.newNanoTDFConfig(configs.toArray(Consumer[]::new)); try (var in = file.isEmpty() ? new BufferedInputStream(System.in) : new FileInputStream(file.get())) { try (var out = new BufferedOutputStream(System.out)) { - NanoTDF ntdf = new NanoTDF(); - ntdf.createNanoTDF(ByteBuffer.wrap(in.readAllBytes()), out, nanoTDFConfig, sdk.getServices().kas()); + sdk.createNanoTDF(ByteBuffer.wrap(in.readAllBytes()), out, nanoTDFConfig); } } } @@ -362,7 +361,6 @@ void readNanoTDF(@Option(names = { "-f", "--file" }, required = true) Path nanoT var sdk = buildSDK(); try (var in = FileChannel.open(nanoTDFPath, StandardOpenOption.READ)) { try (var stdout = new BufferedOutputStream(System.out)) { - NanoTDF ntdf = new NanoTDF(); ByteBuffer buffer = ByteBuffer.allocate((int) in.size()); in.read(buffer); buffer.flip(); @@ -374,7 +372,7 @@ void readNanoTDF(@Option(names = { "-f", "--file" }, required = true) Path nanoT opts.add(Config.WithNanoKasAllowlist(kasAllowlistStr.get().split(","))); } var readerConfig = Config.newNanoTDFReaderConfig(opts.toArray(new Consumer[0])); - ntdf.readNanoTDF(buffer, stdout, sdk.getServices().kas(), readerConfig, sdk.getServices().kasRegistry(), sdk.getPlatformUrl()); + sdk.readNanoTDF(buffer, stdout, readerConfig); } } } diff --git a/examples/src/main/java/io/opentdf/platform/DecryptCollectionExample.java b/examples/src/main/java/io/opentdf/platform/DecryptCollectionExample.java index 7a03c764..d1992caf 100644 --- a/examples/src/main/java/io/opentdf/platform/DecryptCollectionExample.java +++ b/examples/src/main/java/io/opentdf/platform/DecryptCollectionExample.java @@ -31,11 +31,9 @@ public static void main(String[] args) throws IOException, NanoTDF.NanoTDFMaxSiz // Convert String to InputStream - NanoTDF nanoTDFClient = new NanoTDF(true); - for (int i = 0; i < 50; i++) { FileInputStream fis = new FileInputStream(String.format("out/my.%d_ciphertext", i)); - nanoTDFClient.readNanoTDF(ByteBuffer.wrap(fis.readAllBytes()), System.out, sdk.getServices().kas(), sdk.getServices().kasRegistry(), sdk.getPlatformUrl()); + sdk.readNanoTDF(ByteBuffer.wrap(fis.readAllBytes()), System.out, Config.newNanoTDFReaderConfig()); fis.close(); } diff --git a/examples/src/main/java/io/opentdf/platform/DecryptExample.java b/examples/src/main/java/io/opentdf/platform/DecryptExample.java index e2f43f7c..fe608598 100644 --- a/examples/src/main/java/io/opentdf/platform/DecryptExample.java +++ b/examples/src/main/java/io/opentdf/platform/DecryptExample.java @@ -56,7 +56,7 @@ public static void main(String[] args) throws IOException, Path path = Paths.get("my.ciphertext"); try (var in = FileChannel.open(path, StandardOpenOption.READ)) { - var reader = new TDF().loadTDF(in, sdk.getServices().kas(), Config.newTDFReaderConfig(Config.WithSessionKeyType(sessionKeyType)), sdk.getServices().kasRegistry(), sdk.getPlatformUrl()); + var reader = sdk.loadTDF(in, Config.newTDFReaderConfig(Config.WithSessionKeyType(sessionKeyType))); reader.readPayload(System.out); } diff --git a/examples/src/main/java/io/opentdf/platform/EncryptCollectionExample.java b/examples/src/main/java/io/opentdf/platform/EncryptCollectionExample.java index 7f431a2c..585ba6b4 100644 --- a/examples/src/main/java/io/opentdf/platform/EncryptCollectionExample.java +++ b/examples/src/main/java/io/opentdf/platform/EncryptCollectionExample.java @@ -35,15 +35,9 @@ public static void main(String[] args) throws IOException, NanoTDF.NanoTDFMaxSiz String str = "Hello, World!"; - // Convert String to InputStream - var in = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8)); - NanoTDF nanoTDFClient = new NanoTDF(); - for (int i = 0; i < 50; i++) { FileOutputStream fos = new FileOutputStream(String.format("out/my.%d_ciphertext", i)); - nanoTDFClient.createNanoTDF(ByteBuffer.wrap(str.getBytes()), fos, tdfConfig, - sdk.getServices().kas()); + sdk.createNanoTDF(ByteBuffer.wrap(str.getBytes(StandardCharsets.UTF_8)), fos, tdfConfig); } - } } diff --git a/examples/src/main/java/io/opentdf/platform/EncryptExample.java b/examples/src/main/java/io/opentdf/platform/EncryptExample.java index f9ac0176..0231ede4 100644 --- a/examples/src/main/java/io/opentdf/platform/EncryptExample.java +++ b/examples/src/main/java/io/opentdf/platform/EncryptExample.java @@ -53,8 +53,6 @@ public static void main(String[] args) throws IOException, JOSEException, AutoCo FileOutputStream fos = new FileOutputStream("my.ciphertext"); - new TDF().createTDF(in, fos, tdfConfig, - sdk.getServices().kas(), - sdk.getServices().attributes()); + sdk.createTDF(in, fos, tdfConfig); } } \ No newline at end of file diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java index 85c0bae3..7f43db50 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java @@ -24,6 +24,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.net.URISyntaxException; +import java.nio.ByteBuffer; import java.nio.channels.SeekableByteChannel; import java.security.NoSuchAlgorithmException; import java.text.ParseException; @@ -167,11 +169,21 @@ public TDF.Reader loadTDF(SeekableByteChannel channel, Config.TDFReaderConfig co return tdf.loadTDF(channel, config); } - public TDF.TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig config) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, ExecutionException, InterruptedException { + public TDF.TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig config) throws DecoderException, IOException, JOSEException, ExecutionException, InterruptedException { var tdf = new TDF(services); return tdf.createTDF(payload, outputStream, config); } + public int createNanoTDF(ByteBuffer payload, OutputStream outputStream, Config.NanoTDFConfig config) throws IOException, NoSuchAlgorithmException, InterruptedException, NanoTDF.NanoTDFMaxSizeLimit, NanoTDF.UnsupportedNanoTDFFeature, NanoTDF.InvalidNanoTDFConfig { + var ntdf = new NanoTDF(services); + return ntdf.createNanoTDF(payload, outputStream, config); + } + + public void readNanoTDF(ByteBuffer nanoTDF, OutputStream out, Config.NanoTDFReaderConfig config) throws IOException, URISyntaxException, ExecutionException, InterruptedException { + var ntdf = new NanoTDF(services); + ntdf.readNanoTDF(nanoTDF, out, config, platformUrl); + } + /** * Checks to see if this has the structure of a Z-TDF in that it is a zip file * containing diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index 5787fb73..3e233ae4 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -66,13 +66,13 @@ private static byte[] tdfECKeySaltCompute() { * input size, which controls the maximum size of the input data that can be processed. * For test purposes, an alternative constructor allows for setting a custom maximum input size. */ - TDF(SDK.Services services) { + public TDF(SDK.Services services) { this(MAX_TDF_INPUT_SIZE, services); } // constructor for tests so that we can set a maximum size that's tractable for // tests - TDF(long maximumInputSize, SDK.Services services) { + public TDF(long maximumInputSize, SDK.Services services) { this.maximumSize = maximumInputSize; this.services = services; } From e33412b8041a071e32931258b7bf068824d07a21 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Sat, 3 May 2025 11:10:14 -0400 Subject: [PATCH 06/16] Delete cmdline/src/main/resources/logging.properties --- cmdline/src/main/resources/logging.properties | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 cmdline/src/main/resources/logging.properties diff --git a/cmdline/src/main/resources/logging.properties b/cmdline/src/main/resources/logging.properties deleted file mode 100644 index 5cc13c55..00000000 --- a/cmdline/src/main/resources/logging.properties +++ /dev/null @@ -1,56 +0,0 @@ -############################################################ -# Default Logging Configuration File -# -# You can use a different file by specifying a filename -# with the java.util.logging.config.file system property. -# For example, java -Djava.util.logging.config.file=myfile -############################################################ - -############################################################ -# Global properties -############################################################ - -# "handlers" specifies a comma-separated list of log Handler -# classes. These handlers will be installed during VM startup. -# Note that these classes must be on the system classpath. -# By default we only configure a ConsoleHandler, which will only -# show messages at the INFO and above levels. -handlers= java.util.logging.ConsoleHandler - -# To also add the FileHandler, use the following line instead. -#handlers= java.util.logging.FileHandler, java.util.logging.ConsoleHandler - -# Default global logging level. -# This specifies which kinds of events are logged across -# all loggers. For any given facility this global level -# can be overridden by a facility-specific level -# Note that the ConsoleHandler also has a separate level -# setting to limit messages printed to the console. -.level= FINE - -############################################################ -# Handler specific properties. -# Describes specific configuration info for Handlers. -############################################################ - -io.grpc.level = FINE -io.grpc.netty.level = INFO - -# Limit the messages that are printed on the console to INFO and above. -java.util.logging.ConsoleHandler.level = FINE -java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter - -# Example to customize the SimpleFormatter output format -# to print one-line log message like this: -# : [] -# -# java.util.logging.SimpleFormatter.format=%4$s: %5$s [%1$tc]%n - -############################################################ -# Facility-specific properties. -# Provides extra control for each logger. -############################################################ - -# For example, set the com.xyz.foo logger to only log SEVERE -# messages: -# com.xyz.foo.level = SEVERE From 8a5773a108fbff652942b5747efb65efdf00a8a6 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Sat, 3 May 2025 11:11:06 -0400 Subject: [PATCH 07/16] this should not change --- .github/workflows/checks.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 0bc27649..0b472b2a 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -149,21 +149,21 @@ jobs: run: | printf 'here is some data to encrypt' > data - java -Djava.util.logging.config.file=$(pwd)/src/main/resources/logging.properties -jar target/cmdline.jar \ + java -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ encrypt --kas-url=http://localhost:8080 --mime-type=text/plain --attr https://example.com/attr/attr1/value/value1 --autoconfigure=false -f data -m 'here is some metadata' > test.tdf - java -Djava.util.logging.config.file=$(pwd)/src/main/resources/logging.properties -jar target/cmdline.jar \ + java -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ decrypt -f test.tdf > decrypted - java -Dio.grpc.level=FINE -Djava.util.logging.config.file=$(pwd)/src/main/resources/logging.properties -jar target/cmdline.jar \ + java -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ @@ -297,21 +297,21 @@ jobs: run: | printf 'here is some data to encrypt' > data - java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ encrypt --kas-url=http://localhost:8080,http://localhost:8282 -f data -m 'here is some metadata' > test.tdf - java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h\ decrypt -f test.tdf --kas-allowlist http://localhost:8080,http://localhost:8282 > decrypted - java -Djava.util.logging.config.file=$(pwd)/src/main/java/resources/logging.properties -jar target/cmdline.jar \ + java -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ From 6d21192a21ad8477de666351078cae88ffef11b1 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Sat, 3 May 2025 11:21:26 -0400 Subject: [PATCH 08/16] cleanup --- cmdline/src/main/java/io/opentdf/platform/Command.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 3d292c54..37139053 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -365,12 +365,8 @@ void readNanoTDF(@Option(names = { "-f", "--file" }, required = true) Path nanoT in.read(buffer); buffer.flip(); var opts = new ArrayList>(); - if (ignoreAllowlist.isPresent()) { - opts.add(Config.WithNanoIgnoreKasAllowlist(ignoreAllowlist.get())); - } - if (kasAllowlistStr.isPresent()) { - opts.add(Config.WithNanoKasAllowlist(kasAllowlistStr.get().split(","))); - } + ignoreAllowlist.map(Config::WithNanoIgnoreKasAllowlist).ifPresent(opts::add); + kasAllowlistStr.map(s -> s.split(",")).map(Config::WithNanoKasAllowlist).ifPresent(opts::add); var readerConfig = Config.newNanoTDFReaderConfig(opts.toArray(new Consumer[0])); sdk.readNanoTDF(buffer, stdout, readerConfig); } From dd787d40738fb03ff08090d64f1e53fa2d065b61 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Sat, 3 May 2025 11:26:42 -0400 Subject: [PATCH 09/16] use new api --- cmdline/src/main/java/io/opentdf/platform/Command.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 37139053..bff395a2 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -287,15 +287,11 @@ void decrypt(@Option(names = { "-f", "--file" }, required = true) Path tdfPath, } rewrapKeyType.map(Config::WithSessionKeyType).ifPresent(opts::add); - if (ignoreAllowlist.isPresent()) { - opts.add(Config.WithIgnoreKasAllowlist(ignoreAllowlist.get())); - } - if (kasAllowlistStr.isPresent()) { - opts.add(Config.WithKasAllowlist(kasAllowlistStr.get().split(","))); - } + ignoreAllowlist.ifPresent(aBoolean -> opts.add(Config.WithIgnoreKasAllowlist(aBoolean))); + kasAllowlistStr.ifPresent(s -> opts.add(Config.WithKasAllowlist(s.split(",")))); var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); - var reader = new TDF(sdk.getServices()).loadTDF(in, readerConfig, sdk.getPlatformUrl()); + var reader = sdk.loadTDF(in, readerConfig); reader.readPayload(stdout); } } From f911d64551164e95b81e93a0f69e789f1f092114 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Sat, 3 May 2025 18:43:09 -0400 Subject: [PATCH 10/16] do autoconfiguration of kas servers --- .../java/io/opentdf/platform/Command.java | 78 +++++++++---------- .../java/io/opentdf/platform/sdk/SDK.java | 4 +- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index bff395a2..104e0b1a 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -8,7 +8,6 @@ import io.opentdf.platform.sdk.Config; import io.opentdf.platform.sdk.KeyType; import io.opentdf.platform.sdk.Config.AssertionVerificationKeys; -import io.opentdf.platform.sdk.NanoTDF; import io.opentdf.platform.sdk.SDK; import io.opentdf.platform.sdk.SDKBuilder; import io.opentdf.platform.sdk.TDF; @@ -247,52 +246,53 @@ void decrypt(@Option(names = { "-f", "--file" }, required = true) Path tdfPath, @Option(names = { "--with-assertion-verification-keys" }, defaultValue = Option.NULL_VALUE) Optional assertionVerification, @Option(names = { "--kas-allowlist" }, defaultValue = Option.NULL_VALUE) Optional kasAllowlistStr, @Option(names = { "--ignore-kas-allowlist" }, defaultValue = Option.NULL_VALUE) Optional ignoreAllowlist) - throws IOException, TDF.FailedToCreateGMAC, JOSEException, ParseException, NoSuchAlgorithmException, DecoderException, InterruptedException, ExecutionException, URISyntaxException { - var sdk = buildSDK(); - var opts = new ArrayList>(); - try (var in = FileChannel.open(tdfPath, StandardOpenOption.READ)) { - try (var stdout = new BufferedOutputStream(System.out)) { - if (assertionVerification.isPresent()) { - var assertionVerificationInput = assertionVerification.get(); - Gson gson = new Gson(); - - AssertionVerificationKeys assertionVerificationKeys; - try { - assertionVerificationKeys = gson.fromJson(assertionVerificationInput, AssertionVerificationKeys.class); - } catch (JsonSyntaxException e) { - // try it as a file path + throws Exception { + try (var sdk = buildSDK()) { + var opts = new ArrayList>(); + try (var in = FileChannel.open(tdfPath, StandardOpenOption.READ)) { + try (var stdout = new BufferedOutputStream(System.out)) { + if (assertionVerification.isPresent()) { + var assertionVerificationInput = assertionVerification.get(); + Gson gson = new Gson(); + + AssertionVerificationKeys assertionVerificationKeys; try { - String fileJson = new String(Files.readAllBytes(Paths.get(assertionVerificationInput))); - assertionVerificationKeys = gson.fromJson(fileJson, AssertionVerificationKeys.class); - } catch (JsonSyntaxException e2) { - throw new RuntimeException("Failed to parse assertion verification keys from file", e2); - } catch(Exception e3) { - throw new RuntimeException("Could not parse assertion verification keys as json string or path to file", e3); + assertionVerificationKeys = gson.fromJson(assertionVerificationInput, AssertionVerificationKeys.class); + } catch (JsonSyntaxException e) { + // try it as a file path + try { + String fileJson = new String(Files.readAllBytes(Paths.get(assertionVerificationInput))); + assertionVerificationKeys = gson.fromJson(fileJson, AssertionVerificationKeys.class); + } catch (JsonSyntaxException e2) { + throw new RuntimeException("Failed to parse assertion verification keys from file", e2); + } catch (Exception e3) { + throw new RuntimeException("Could not parse assertion verification keys as json string or path to file", e3); + } } - } - for (Map.Entry entry : assertionVerificationKeys.keys.entrySet()){ - try { - Object correctedKey = correctKeyType(entry.getValue().alg, entry.getValue().key, true); - entry.setValue(new AssertionConfig.AssertionKey(entry.getValue().alg, correctedKey)); - } catch (Exception e) { - throw new RuntimeException("Error with assertion verification key: " + e.getMessage(), e); + for (Map.Entry entry : assertionVerificationKeys.keys.entrySet()) { + try { + Object correctedKey = correctKeyType(entry.getValue().alg, entry.getValue().key, true); + entry.setValue(new AssertionConfig.AssertionKey(entry.getValue().alg, correctedKey)); + } catch (Exception e) { + throw new RuntimeException("Error with assertion verification key: " + e.getMessage(), e); + } } + opts.add(Config.withAssertionVerificationKeys(assertionVerificationKeys)); } - opts.add(Config.withAssertionVerificationKeys(assertionVerificationKeys)); - } - if (disableAssertionVerification) { - opts.add(Config.withDisableAssertionVerification(true)); - } - rewrapKeyType.map(Config::WithSessionKeyType).ifPresent(opts::add); + if (disableAssertionVerification) { + opts.add(Config.withDisableAssertionVerification(true)); + } + rewrapKeyType.map(Config::WithSessionKeyType).ifPresent(opts::add); - ignoreAllowlist.ifPresent(aBoolean -> opts.add(Config.WithIgnoreKasAllowlist(aBoolean))); - kasAllowlistStr.ifPresent(s -> opts.add(Config.WithKasAllowlist(s.split(",")))); + ignoreAllowlist.ifPresent(aBoolean -> opts.add(Config.WithIgnoreKasAllowlist(aBoolean))); + kasAllowlistStr.ifPresent(s -> opts.add(Config.WithKasAllowlist(s.split(",")))); - var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); - var reader = sdk.loadTDF(in, readerConfig); - reader.readPayload(stdout); + var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); + var reader = sdk.loadTDF(in, readerConfig); + reader.readPayload(stdout); + } } } } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java index 7f43db50..564edfa2 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java @@ -164,9 +164,9 @@ public Services getServices() { return this.services; } - public TDF.Reader loadTDF(SeekableByteChannel channel, Config.TDFReaderConfig config) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException { + public TDF.Reader loadTDF(SeekableByteChannel channel, Config.TDFReaderConfig config) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, URISyntaxException, ExecutionException, InterruptedException { var tdf = new TDF(services); - return tdf.loadTDF(channel, config); + return tdf.loadTDF(channel, config, platformUrl); } public TDF.TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig config) throws DecoderException, IOException, JOSEException, ExecutionException, InterruptedException { From d5626f68d8a59df9e73057a656a4aef05bfd6482 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 5 May 2025 09:54:00 -0400 Subject: [PATCH 11/16] change visibility --- cmdline/src/main/java/io/opentdf/platform/Command.java | 8 ++------ sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 6 +++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 104e0b1a..408998f1 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -307,12 +307,8 @@ void readMetadata(@Option(names = { "-f", "--file" }, required = true) Path tdfP try (var in = FileChannel.open(tdfPath, StandardOpenOption.READ)) { try (var stdout = new PrintWriter(System.out)) { - if (ignoreAllowlist.isPresent()) { - opts.add(Config.WithIgnoreKasAllowlist(ignoreAllowlist.get())); - } - if (kasAllowlistStr.isPresent()) { - opts.add(Config.WithKasAllowlist(kasAllowlistStr.get().split(","))); - } + ignoreAllowlist.map(Config::WithIgnoreKasAllowlist).ifPresent(opts::add); + kasAllowlistStr.map(s -> s.split(",")).map(Config::WithKasAllowlist).ifPresent(opts::add); var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); var reader = sdk.loadTDF(in, readerConfig); diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index 3e233ae4..976953f1 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -484,7 +484,7 @@ private static byte[] calculateSignature(byte[] data, byte[] secret, Config.Inte return Arrays.copyOfRange(data, data.length - kGMACPayloadLength, data.length); } - public TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig tdfConfig) + TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig tdfConfig) throws IOException, JOSEException, AutoConfigureException, InterruptedException, ExecutionException, DecoderException { if (tdfConfig.autoconfigure) { @@ -636,7 +636,7 @@ public TDFObject createTDF(InputStream payload, OutputStream outputStream, Confi return tdfObject; } - public static List defaultKases(TDFConfig config) { + static List defaultKases(TDFConfig config) { List allk = new ArrayList<>(); List defk = new ArrayList<>(); @@ -674,7 +674,7 @@ public Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderC return loadTDF(tdf, tdfReaderConfig); } - public Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) + Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) throws RootSignatureValidationException, SegmentSizeMismatch, IOException, FailedToCreateGMAC, JOSEException, ParseException, NoSuchAlgorithmException, DecoderException { From 2407517e556bc8fb23c71c9e7994aeb1f475c48e Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 5 May 2025 09:59:11 -0400 Subject: [PATCH 12/16] these should not be public --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index 976953f1..d47f0031 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -653,12 +653,12 @@ static List defaultKases(TDFConfig config) { return defk; } - public Reader loadTDF(SeekableByteChannel tdf, String platformUrl) + Reader loadTDF(SeekableByteChannel tdf, String platformUrl) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, InterruptedException, ExecutionException, URISyntaxException { return loadTDF(tdf, Config.newTDFReaderConfig(), platformUrl); } - public Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, String platformUrl) + Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, String platformUrl) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, InterruptedException, ExecutionException, URISyntaxException { if (!tdfReaderConfig.ignoreKasAllowlist && (tdfReaderConfig.kasAllowlist == null || tdfReaderConfig.kasAllowlist.isEmpty())) { ListKeyAccessServersRequest request = ListKeyAccessServersRequest.newBuilder() From 2472948efd4dbe69daeee4ea1f8c1b1b97f628ae Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 5 May 2025 13:54:46 -0400 Subject: [PATCH 13/16] only throw well-controlled types --- .../platform/sdk/AutoConfigureException.java | 11 +-- .../opentdf/platform/sdk/Autoconfigure.java | 12 ++- .../java/io/opentdf/platform/sdk/Config.java | 46 +++++----- .../java/io/opentdf/platform/sdk/NanoTDF.java | 41 ++++++--- .../java/io/opentdf/platform/sdk/SDK.java | 8 +- .../java/io/opentdf/platform/sdk/TDF.java | 89 +++++++++++-------- .../io/opentdf/platform/sdk/TDFReader.java | 5 +- .../java/io/opentdf/platform/sdk/TDFTest.java | 5 +- 8 files changed, 127 insertions(+), 90 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/AutoConfigureException.java b/sdk/src/main/java/io/opentdf/platform/sdk/AutoConfigureException.java index 157e6a8a..02217452 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/AutoConfigureException.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/AutoConfigureException.java @@ -3,16 +3,11 @@ /** * Exception thrown when automatic configuration fails. */ -public class AutoConfigureException extends RuntimeException { +public class AutoConfigureException extends SDKException { public AutoConfigureException(String message) { super(message); } - - public AutoConfigureException(Exception e) { - super(e); - } - - public AutoConfigureException(String message, Exception e) { - super(message, e); + public AutoConfigureException(String message, Exception cause) { + super(message, cause); } } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java b/sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java index 6113a681..7db8476a 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Autoconfigure.java @@ -699,14 +699,22 @@ public static Granter newGranterFromAttributes(Value... attrValues) throws AutoC } // Gets a list of directory of KAS grants for a list of attribute FQNs - public static Granter newGranterFromService(AttributesServiceFutureStub as, KASKeyCache keyCache, AttributeValueFQN... fqns) throws AutoConfigureException, ExecutionException, InterruptedException { + static Granter newGranterFromService(AttributesServiceFutureStub as, KASKeyCache keyCache, AttributeValueFQN... fqns) throws AutoConfigureException { GetAttributeValuesByFqnsRequest request = GetAttributeValuesByFqnsRequest.newBuilder() .addAllFqns(Arrays.stream(fqns).map(AttributeValueFQN::toString).collect(Collectors.toList())) .setWithValue(AttributeValueSelector.newBuilder().setWithKeyAccessGrants(true).build()) .build(); - GetAttributeValuesByFqnsResponse av = as.getAttributeValuesByFqns(request).get(); + GetAttributeValuesByFqnsResponse av = null; + try { + av = as.getAttributeValuesByFqns(request).get(); + } catch (ExecutionException e) { + throw new AutoConfigureException("error getting attributes during autoconfiguration", e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new AutoConfigureException("interrupted while getting attributes during autoconfiguration", e); + } return getGranter(keyCache, new ArrayList<>(av.getFqnAttributeValuesMap().values())); } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Config.java b/sdk/src/main/java/io/opentdf/platform/sdk/Config.java index bf3b9d2a..090cdaad 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Config.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Config.java @@ -130,16 +130,9 @@ public static Consumer WithSessionKeyType(KeyType keyType) { return (TDFReaderConfig config) -> config.sessionKeyType = keyType; } public static Consumer WithKasAllowlist(String... kasAllowlist) { - return (TDFReaderConfig config) -> { - config.kasAllowlist = Arrays.stream(kasAllowlist) - .map(s -> { - try { - return getKasAddress(s); - } catch (URISyntaxException e) { - throw new RuntimeException("Invalid URI: " + s, e); - } - }).collect(Collectors.toCollection(HashSet::new)); - }; + return (TDFReaderConfig config) -> config.kasAllowlist = Arrays + .stream(kasAllowlist) + .map(Config::getKasAddress).collect(Collectors.toSet()); } public static Consumer withKasAllowlist(Set kasAllowlist) { @@ -401,13 +394,8 @@ public static Consumer WithNanoKasAllowlist(String... kasAl return (NanoTDFReaderConfig config) -> { // apply getKasAddress to each kasAllowlist entry and add to hashset config.kasAllowlist = Arrays.stream(kasAllowlist) - .map(s -> { - try { - return getKasAddress(s); - } catch (URISyntaxException e) { - throw new RuntimeException("Invalid URI: " + s, e); - } - }).collect(Collectors.toCollection(HashSet::new)); + .map(Config::getKasAddress) + .collect(Collectors.toSet()); }; } @@ -456,7 +444,7 @@ public CollectionConfig(boolean useCollection) { this.useCollection = useCollection; } - public synchronized HeaderInfo getHeaderInfo() throws InterruptedException { + public synchronized HeaderInfo getHeaderInfo() throws SDKException { int iteration = iterationCounter; iterationCounter = (iterationCounter + 1) % MAX_COLLECTION_ITERATION; @@ -465,7 +453,12 @@ public synchronized HeaderInfo getHeaderInfo() throws InterruptedException { return null; } while (!updatedHeaderInfo) { - this.wait(); + try { + this.wait(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new SDKException("interrupted while waiting for header info", e); + } } return new HeaderInfo(headerInfo.getHeader(), headerInfo.getKey(), iteration); } @@ -477,13 +470,18 @@ public synchronized void updateHeaderInfo(HeaderInfo headerInfo) { } } - public static String getKasAddress(String kasURL) throws URISyntaxException { + public static String getKasAddress(String kasURL) throws SDKException { // Prepend "https://" if no scheme is provided if (!kasURL.contains("://")) { kasURL = "https://" + kasURL; } - URI uri = new URI(kasURL); + URI uri; + try { + uri = new URI(kasURL); + } catch (URISyntaxException e) { + throw new SDKException("error constructing KAS url", e); + } // Default to "https" if no scheme is provided String scheme = uri.getScheme(); @@ -498,6 +496,10 @@ public static String getKasAddress(String kasURL) throws URISyntaxException { } // Reconstruct the URL with only the scheme, host, and port - return new URI(scheme, null, uri.getHost(), port, null, null, null).toString(); + try { + return new URI(scheme, null, uri.getHost(), port, null, null, null).toString(); + } catch (URISyntaxException e) { + throw new SDKException("error creating KAS URL from host and port", e); + } } } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java index a5d0b39a..381ce3cd 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java @@ -53,26 +53,25 @@ public class NanoTDF { this.collectionStore = collectionStore; } - public static class NanoTDFMaxSizeLimit extends Exception { + public static class NanoTDFMaxSizeLimit extends SDKException { public NanoTDFMaxSizeLimit(String errorMessage) { super(errorMessage); } } - public static class UnsupportedNanoTDFFeature extends Exception { + public static class UnsupportedNanoTDFFeature extends SDKException { public UnsupportedNanoTDFFeature(String errorMessage) { super(errorMessage); } } - public static class InvalidNanoTDFConfig extends Exception { + public static class InvalidNanoTDFConfig extends SDKException { public InvalidNanoTDFConfig(String errorMessage) { super(errorMessage); } } - private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) - throws InvalidNanoTDFConfig, UnsupportedNanoTDFFeature, NoSuchAlgorithmException, InterruptedException { + private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) throws InvalidNanoTDFConfig, UnsupportedNanoTDFFeature { if (nanoTDFConfig.collectionConfig.useCollection) { Config.HeaderInfo headerInfo = nanoTDFConfig.collectionConfig.getHeaderInfo(); if (headerInfo != null) { @@ -103,7 +102,12 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) byte[] symmetricKey = ECKeyPair.computeECDHKey(kasPublicKey, keyPair.getPrivateKey()); // Generate HKDF key - MessageDigest digest = MessageDigest.getInstance("SHA-256"); + MessageDigest digest = null; + try { + digest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new SDKException("error getting instance of SHA-256 digest", e); + } byte[] hashOfSalt = digest.digest(MAGIC_NUMBER_AND_VERSION); byte[] key = ECKeyPair.calculateHKDF(hashOfSalt, symmetricKey); @@ -149,8 +153,7 @@ private Config.HeaderInfo getHeaderInfo(Config.NanoTDFConfig nanoTDFConfig) } public int createNanoTDF(ByteBuffer data, OutputStream outputStream, - Config.NanoTDFConfig nanoTDFConfig) throws IOException, NanoTDFMaxSizeLimit, InvalidNanoTDFConfig, - NoSuchAlgorithmException, UnsupportedNanoTDFFeature, InterruptedException { + Config.NanoTDFConfig nanoTDFConfig) throws SDKException, IOException { int nanoTDFSize = 0; int dataSize = data.limit(); @@ -183,7 +186,11 @@ public int createNanoTDF(ByteBuffer data, OutputStream outputStream, } else { do { byte[] iv = new byte[kNanoTDFIvSize]; - SecureRandom.getInstanceStrong().nextBytes(iv); + try { + SecureRandom.getInstanceStrong().nextBytes(iv); + } catch (NoSuchAlgorithmException e) { + throw new SDKException("error getting instance of strong SecureRandom", e); + } System.arraycopy(iv, 0, actualIV, kIvPadding, iv.length); } while (Arrays.equals(actualIV, kEmptyIV)); // if match, we need to retry to prevent key + iv reuse with the policy } @@ -209,16 +216,24 @@ public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream) throws IO readNanoTDF(nanoTDF, outputStream, Config.newNanoTDFReaderConfig()); } - public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, String platformUrl) throws IOException, InterruptedException, ExecutionException, URISyntaxException { + public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, String platformUrl) throws IOException { readNanoTDF(nanoTDF, outputStream, Config.newNanoTDFReaderConfig(), platformUrl); } public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, - Config.NanoTDFReaderConfig nanoTdfReaderConfig, String platformUrl) throws IOException, InterruptedException, ExecutionException, URISyntaxException { + Config.NanoTDFReaderConfig nanoTdfReaderConfig, String platformUrl) throws IOException, SDKException { if (!nanoTdfReaderConfig.ignoreKasAllowlist && (nanoTdfReaderConfig.kasAllowlist == null || nanoTdfReaderConfig.kasAllowlist.isEmpty())) { ListKeyAccessServersRequest request = ListKeyAccessServersRequest.newBuilder() .build(); - ListKeyAccessServersResponse response = services.kasRegistry().listKeyAccessServers(request).get(); + ListKeyAccessServersResponse response = null; + try { + response = services.kasRegistry().listKeyAccessServers(request).get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new SDKException("interrupted while getting kas registry", e); + } catch (ExecutionException e) { + throw new SDKException("error getting kas registry", e); + } nanoTdfReaderConfig.kasAllowlist = new HashSet<>(); var kases = response.getKeyAccessServersList(); @@ -233,7 +248,7 @@ public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream, - Config.NanoTDFReaderConfig nanoTdfReaderConfig) throws IOException, URISyntaxException { + Config.NanoTDFReaderConfig nanoTdfReaderConfig) throws IOException { Header header = new Header(nanoTDF); CollectionKey cachedKey = collectionStore.getKey(header); diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java index 564edfa2..a9fc2603 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java @@ -164,22 +164,22 @@ public Services getServices() { return this.services; } - public TDF.Reader loadTDF(SeekableByteChannel channel, Config.TDFReaderConfig config) throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, URISyntaxException, ExecutionException, InterruptedException { + public TDF.Reader loadTDF(SeekableByteChannel channel, Config.TDFReaderConfig config) throws SDKException, IOException { var tdf = new TDF(services); return tdf.loadTDF(channel, config, platformUrl); } - public TDF.TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig config) throws DecoderException, IOException, JOSEException, ExecutionException, InterruptedException { + public TDF.TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig config) throws SDKException, IOException { var tdf = new TDF(services); return tdf.createTDF(payload, outputStream, config); } - public int createNanoTDF(ByteBuffer payload, OutputStream outputStream, Config.NanoTDFConfig config) throws IOException, NoSuchAlgorithmException, InterruptedException, NanoTDF.NanoTDFMaxSizeLimit, NanoTDF.UnsupportedNanoTDFFeature, NanoTDF.InvalidNanoTDFConfig { + public int createNanoTDF(ByteBuffer payload, OutputStream outputStream, Config.NanoTDFConfig config) throws SDKException, IOException { var ntdf = new NanoTDF(services); return ntdf.createNanoTDF(payload, outputStream, config); } - public void readNanoTDF(ByteBuffer nanoTDF, OutputStream out, Config.NanoTDFReaderConfig config) throws IOException, URISyntaxException, ExecutionException, InterruptedException { + public void readNanoTDF(ByteBuffer nanoTDF, OutputStream out, Config.NanoTDFReaderConfig config) throws SDKException, IOException { var ntdf = new NanoTDF(services); ntdf.readNanoTDF(nanoTDF, out, config, platformUrl); } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index d47f0031..bf8b4ffb 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -23,7 +23,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; -import java.net.URISyntaxException; import java.nio.channels.SeekableByteChannel; import java.nio.charset.StandardCharsets; import java.security.*; @@ -100,49 +99,37 @@ public TDF(long maximumInputSize, SDK.Services services) { private static final Gson gson = new GsonBuilder().create(); - public class SplitKeyException extends IOException { + public class SplitKeyException extends SDKException { public SplitKeyException(String errorMessage) { super(errorMessage); } } - public static class DataSizeNotSupported extends RuntimeException { + public static class DataSizeNotSupported extends SDKException { public DataSizeNotSupported(String errorMessage) { super(errorMessage); } } - public static class FailedToCreateEncodedTDF extends RuntimeException { - public FailedToCreateEncodedTDF(String errorMessage) { - super(errorMessage); - } - } - - public static class KasInfoMissing extends RuntimeException { + public static class KasInfoMissing extends SDKException { public KasInfoMissing(String errorMessage) { super(errorMessage); } } - public static class KasPublicKeyMissing extends RuntimeException { + public static class KasPublicKeyMissing extends SDKException { public KasPublicKeyMissing(String errorMessage) { super(errorMessage); } } - public static class InputStreamReadFailed extends RuntimeException { - public InputStreamReadFailed(String errorMessage) { - super(errorMessage); - } - } - - public static class FailedToCreateGMAC extends RuntimeException { + public static class FailedToCreateGMAC extends SDKException { public FailedToCreateGMAC(String errorMessage) { super(errorMessage); } } - public static class TDFReadFailed extends RuntimeException { + public static class TDFReadFailed extends SDKException { public TDFReadFailed(String errorMessage) { super(errorMessage); } @@ -484,8 +471,7 @@ private static byte[] calculateSignature(byte[] data, byte[] secret, Config.Inte return Arrays.copyOfRange(data, data.length - kGMACPayloadLength, data.length); } - TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig tdfConfig) - throws IOException, JOSEException, AutoConfigureException, InterruptedException, ExecutionException, DecoderException { + TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFConfig tdfConfig) throws SDKException, IOException { if (tdfConfig.autoconfigure) { Autoconfigure.Granter granter = new Autoconfigure.Granter(new ArrayList<>()); @@ -605,9 +591,16 @@ TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFCo assertion.appliesToState = assertionConfig.appliesToState.toString(); var assertionHashAsHex = assertion.hash(); - var assertionHash = tdfConfig.hexEncodeRootAndSegmentHashes - ? assertionHashAsHex.getBytes(StandardCharsets.UTF_8) - : Hex.decodeHex(assertionHashAsHex); + byte[] assertionHash; + if (tdfConfig.hexEncodeRootAndSegmentHashes) { + assertionHash = assertionHashAsHex.getBytes(StandardCharsets.UTF_8); + } else { + try { + assertionHash = Hex.decodeHex(assertionHashAsHex); + } catch (DecoderException e) { + throw new SDKException("error decoding assertion hash", e); + } + } byte[] completeHash = new byte[aggregateHash.size() + assertionHash.length]; System.arraycopy(aggregateHash.toByteArray(), 0, completeHash, 0, aggregateHash.size()); System.arraycopy(assertionHash, 0, completeHash, aggregateHash.size(), assertionHash.length); @@ -623,7 +616,11 @@ TDFObject createTDF(InputStream payload, OutputStream outputStream, Config.TDFCo assertionHashAsHex, encodedHash ); - assertion.sign(hashValues, assertionSigningKey); + try { + assertion.sign(hashValues, assertionSigningKey); + } catch (KeyLengthException e) { + throw new SDKException("error signing assertion hash", e); + } signedAssertions.add(assertion); } @@ -653,17 +650,20 @@ static List defaultKases(TDFConfig config) { return defk; } - Reader loadTDF(SeekableByteChannel tdf, String platformUrl) - throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, InterruptedException, ExecutionException, URISyntaxException { + Reader loadTDF(SeekableByteChannel tdf, String platformUrl) throws SDKException, IOException { return loadTDF(tdf, Config.newTDFReaderConfig(), platformUrl); } - Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, String platformUrl) - throws DecoderException, IOException, ParseException, NoSuchAlgorithmException, JOSEException, InterruptedException, ExecutionException, URISyntaxException { + Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, String platformUrl) throws SDKException, IOException { if (!tdfReaderConfig.ignoreKasAllowlist && (tdfReaderConfig.kasAllowlist == null || tdfReaderConfig.kasAllowlist.isEmpty())) { ListKeyAccessServersRequest request = ListKeyAccessServersRequest.newBuilder() .build(); - ListKeyAccessServersResponse response = services.kasRegistry().listKeyAccessServers(request).get(); + ListKeyAccessServersResponse response; + try { + response = services.kasRegistry().listKeyAccessServers(request).get(); + } catch (InterruptedException | ExecutionException e) { + throw new SDKException("error getting key access servers", e); + } tdfReaderConfig.kasAllowlist = new HashSet<>(); for (var entry : response.getKeyAccessServersList()) { @@ -674,9 +674,7 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, return loadTDF(tdf, tdfReaderConfig); } - Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) - throws RootSignatureValidationException, SegmentSizeMismatch, - IOException, FailedToCreateGMAC, JOSEException, ParseException, NoSuchAlgorithmException, DecoderException { + Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) throws SDKException, IOException { TDFReader tdfReader = new TDFReader(tdf); String manifestJson = tdfReader.manifest(); @@ -689,7 +687,12 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) Set foundSplits = new HashSet<>(); Map skippedSplits = new HashMap<>(); - MessageDigest digest = MessageDigest.getInstance("SHA-256"); + MessageDigest digest = null; + try { + digest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new SDKException("error getting instance of SHA-256 digest", e); + } if (manifest.payload.isEncrypted) { for (Manifest.KeyAccess keyAccess : manifest.encryptionInformation.keyAccessObj) { @@ -818,14 +821,28 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) } } - var hashValues = assertion.verify(assertionKey); + Manifest.Assertion.HashValues hashValues = null; + try { + hashValues = assertion.verify(assertionKey); + } catch (ParseException | JOSEException e) { + throw new SDKException("error validating assertion hash", e); + } var hashOfAssertionAsHex = assertion.hash(); if (!Objects.equals(hashOfAssertionAsHex, hashValues.getAssertionHash())) { throw new AssertionException("assertion hash mismatch", assertion.id); } - byte[] hashOfAssertion = isLegacyTdf ? hashOfAssertionAsHex.getBytes(StandardCharsets.UTF_8) : Hex.decodeHex(hashOfAssertionAsHex); + byte[] hashOfAssertion; + if (isLegacyTdf) { + hashOfAssertion = hashOfAssertionAsHex.getBytes(StandardCharsets.UTF_8); + } else { + try { + hashOfAssertion = Hex.decodeHex(hashOfAssertionAsHex); + } catch (DecoderException e) { + throw new SDKException("error decoding assertion hash", e); + } + } var signature = new byte[aggregateHashByteArrayBytes.length + hashOfAssertion.length]; System.arraycopy(aggregateHashByteArrayBytes, 0, signature, 0, aggregateHashByteArrayBytes.length); System.arraycopy(hashOfAssertion, 0, signature, aggregateHashByteArrayBytes.length, hashOfAssertion.length); 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 6691888a..61395075 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java @@ -7,6 +7,7 @@ import java.io.InputStreamReader; import java.nio.channels.SeekableByteChannel; import java.nio.charset.StandardCharsets; +import java.util.Map; import java.util.stream.Collectors; import static io.opentdf.platform.sdk.TDFWriter.TDF_MANIFEST_FILE_NAME; @@ -22,8 +23,8 @@ public class TDFReader { private final ZipReader.Entry manifestEntry; private final InputStream payload; - public TDFReader(SeekableByteChannel tdf) throws IOException { - var entries = new ZipReader(tdf).getEntries() + public TDFReader(SeekableByteChannel tdf) throws SDKException, IOException { + Map entries = new ZipReader(tdf).getEntries() .stream() .collect(Collectors.toMap(ZipReader.Entry::getName, e -> e)); diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java index cb516a1c..670fc31e 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java @@ -309,9 +309,8 @@ void testWithAssertionVerificationDisabled() throws Exception { new AssertionConfig.AssertionKey(AssertionConfig.AssertionKeyAlg.RS256, keypair.getPublic())); var unwrappedData = new ByteArrayOutputStream(); - assertThrows(JOSEException.class, () -> { - tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), Config.newTDFReaderConfig(), platformUrl); - }); + var thrown = assertThrows(SDKException.class, () -> tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), Config.newTDFReaderConfig(), platformUrl)); + assertThat(thrown.getCause()).isInstanceOf(JOSEException.class); // try with assertion verification disabled and not passing the assertion verification keys Config.TDFReaderConfig readerConfig = Config.newTDFReaderConfig( From a4982671cb1bfe4141cbde6fb5064e306b119864 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 5 May 2025 14:17:29 -0400 Subject: [PATCH 14/16] deal with interruption --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java index bf8b4ffb..47d03e48 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -661,8 +661,11 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, ListKeyAccessServersResponse response; try { response = services.kasRegistry().listKeyAccessServers(request).get(); - } catch (InterruptedException | ExecutionException e) { + } catch (ExecutionException e) { throw new SDKException("error getting key access servers", e); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new SDKException("interrupted while getting list of kases", e); } tdfReaderConfig.kasAllowlist = new HashSet<>(); From 878c213613bd0e75b77f4aaf2782c519f8922895 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Tue, 6 May 2025 15:59:59 -0400 Subject: [PATCH 15/16] sonar --- sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java | 3 +-- sdk/src/main/java/io/opentdf/platform/sdk/SDK.java | 10 ---------- sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java | 8 ++------ sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java | 6 +++++- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java index 381ce3cd..4890d859 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/NanoTDF.java @@ -7,7 +7,6 @@ import java.io.IOException; import java.io.OutputStream; -import java.net.URISyntaxException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; @@ -212,7 +211,7 @@ public int createNanoTDF(ByteBuffer data, OutputStream outputStream, return nanoTDFSize; } - public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream) throws IOException, URISyntaxException { + public void readNanoTDF(ByteBuffer nanoTDF, OutputStream outputStream) throws IOException { readNanoTDF(nanoTDF, outputStream, Config.newNanoTDFReaderConfig()); } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java index a9fc2603..541eb200 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java @@ -1,6 +1,5 @@ package io.opentdf.platform.sdk; -import com.nimbusds.jose.JOSEException; import io.grpc.ClientInterceptor; import io.grpc.ManagedChannel; import io.opentdf.platform.authorization.AuthorizationServiceGrpc; @@ -16,21 +15,14 @@ import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceGrpc; import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceGrpc.KeyAccessServerRegistryServiceFutureStub; import io.opentdf.platform.sdk.nanotdf.NanoTDFType; -import org.apache.commons.codec.DecoderException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import javax.net.ssl.TrustManager; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.URISyntaxException; import java.nio.ByteBuffer; import java.nio.channels.SeekableByteChannel; -import java.security.NoSuchAlgorithmException; -import java.text.ParseException; import java.util.Optional; -import java.util.concurrent.ExecutionException; /** * The SDK class represents a software development kit for interacting with the @@ -44,8 +36,6 @@ public class SDK implements AutoCloseable { private final ClientInterceptor authInterceptor; private final String platformUrl; - private static final Logger log = LoggerFactory.getLogger(SDK.class); - /** * Closes the SDK, including its associated services. * diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java b/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java index 089a884b..12694121 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/Fuzzing.java @@ -2,18 +2,14 @@ import java.io.IOException; import java.io.OutputStream; -import java.net.URISyntaxException; 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; @@ -33,14 +29,14 @@ public void write(byte[] b, int off, int len) { }; @FuzzTest(maxDuration=TEST_DURATION) - public void fuzzNanoTDF(FuzzedDataProvider data) throws IOException, URISyntaxException { + public void fuzzNanoTDF(FuzzedDataProvider data) throws IOException { byte[] fuzzBytes = data.consumeRemainingAsBytes(); NanoTDF nanoTDF = new NanoTDF(new FakeServicesBuilder().setKas(NanoTDFTest.kas).build()); nanoTDF.readNanoTDF(ByteBuffer.wrap(fuzzBytes), IGNORE_OUTPUT_STREAM); } @FuzzTest(maxDuration=TEST_DURATION) - public void fuzzTDF(FuzzedDataProvider data) throws FailedToCreateGMAC, NoSuchAlgorithmException, JOSEException, ParseException, DecoderException { + public void fuzzTDF(FuzzedDataProvider data) throws FailedToCreateGMAC, NoSuchAlgorithmException { 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(); diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java index 670fc31e..d0fa3c5c 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java @@ -309,7 +309,11 @@ void testWithAssertionVerificationDisabled() throws Exception { new AssertionConfig.AssertionKey(AssertionConfig.AssertionKeyAlg.RS256, keypair.getPublic())); var unwrappedData = new ByteArrayOutputStream(); - var thrown = assertThrows(SDKException.class, () -> tdf.loadTDF(new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()), Config.newTDFReaderConfig(), platformUrl)); + var dataToUnwrap = new SeekableInMemoryByteChannel(tdfOutputStream.toByteArray()); + var emptyConfig= Config.newTDFReaderConfig(); + var thrown = assertThrows(SDKException.class, () -> { + tdf.loadTDF(dataToUnwrap, emptyConfig, platformUrl); + }); assertThat(thrown.getCause()).isInstanceOf(JOSEException.class); // try with assertion verification disabled and not passing the assertion verification keys From 81907fd2f9728157d106313ffa2cdd781103fe6e Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Tue, 6 May 2025 16:12:47 -0400 Subject: [PATCH 16/16] more sonar --- sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java index d0fa3c5c..8b1becc3 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java @@ -351,7 +351,7 @@ void testSimpleTDFWithAssertionWithHS256() throws Exception { assertionConfig2.statement.value = "{\"uuid\":\"f74efb60-4a9a-11ef-a6f1-8ee1a61c148a\",\"body\":{\"dataAttributes\":null,\"dissem\":null}}"; var rsaKasInfo = new Config.KASInfo(); - rsaKasInfo.URL = "https://example.com/kas"+Integer.toString(0); + rsaKasInfo.URL = "https://example.com/kas"+ 0; Config.TDFConfig config = Config.newTDFConfig( Config.withAutoconfigure(false), @@ -414,7 +414,7 @@ void testSimpleTDFWithAssertionWithHS256Failure() throws Exception { assertionConfig1.signingKey = new AssertionConfig.AssertionKey(AssertionConfig.AssertionKeyAlg.HS256, key); var rsaKasInfo = new Config.KASInfo(); - rsaKasInfo.URL = "https://example.com/kas"+Integer.toString(0); + rsaKasInfo.URL = "https://example.com/kas"+ 0; Config.TDFConfig config = Config.newTDFConfig( Config.withAutoconfigure(false), @@ -472,7 +472,7 @@ public void testCreatingTDFWithMultipleSegments() throws Exception { } @Test - public void testCreatingTooLargeTDF() throws Exception { + public void testCreatingTooLargeTDF() { var random = new Random(); var maxSize = random.nextInt(1024); var numReturned = new AtomicInteger(0); @@ -540,7 +540,7 @@ public void testCreateTDFWithMimeType() throws Exception { } @Test - public void legacyTDFRoundTrips() throws DecoderException, IOException, ExecutionException, JOSEException, InterruptedException, ParseException, NoSuchAlgorithmException, URISyntaxException { + public void legacyTDFRoundTrips() throws IOException, NoSuchAlgorithmException { final String mimeType = "application/pdf"; var assertionConfig1 = new AssertionConfig(); assertionConfig1.id = "assertion1";