diff --git a/README.md b/README.md
index e83d3bd6..fc24ae39 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,12 @@ public class Example {
.platformEndpoint("https://your.cluster/")
.build();
+ // Fetch the platform base key (if configured)
+ sdk.getBaseKey().ifPresent(baseKey -> {
+ System.out.println(baseKey.getKasUri());
+ System.out.println(baseKey.getPublicKey().getKid());
+ });
+
// Encrypt a file
try (InputStream in = new FileInputStream("input.plaintext")) {
Config.TDFConfig c = Config.newTDFConfig(Config.withDataAttributes("attr1", "attr2"));
diff --git a/pom.xml b/pom.xml
index c7308b44..fc4654da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,6 +18,7 @@
4.29.2
1.82
10.0.0
+ 1.14.12
0.8.13
jacoco
@@ -156,6 +157,20 @@
bcprov-jdk18on
${bouncycastle.version}
+
+
+ net.bytebuddy
+ byte-buddy
+ ${bytebuddy.version}
+
+
+ net.bytebuddy
+ byte-buddy-agent
+ ${bytebuddy.version}
+
diff --git a/sdk/pom.xml b/sdk/pom.xml
index 29a933c3..5767f5b3 100644
--- a/sdk/pom.xml
+++ b/sdk/pom.xml
@@ -592,4 +592,4 @@
-
\ 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 3f0325f9..1194bdd7 100644
--- a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java
+++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java
@@ -4,6 +4,7 @@
import com.connectrpc.impl.ProtocolClient;
import io.opentdf.platform.authorization.AuthorizationServiceClientInterface;
+import io.opentdf.platform.policy.SimpleKasKey;
import io.opentdf.platform.policy.attributes.AttributesServiceClientInterface;
import io.opentdf.platform.policy.kasregistry.KeyAccessServerRegistryServiceClientInterface;
import io.opentdf.platform.policy.namespaces.NamespaceServiceClientInterface;
@@ -98,6 +99,15 @@ public Services getServices() {
return this.services;
}
+ /**
+ * Fetch the platform "base key" from the well-known configuration, if present.
+ *
+ * This is read from the {@code base_key} field returned by {@code GetWellKnownConfiguration}.
+ */
+ public Optional getBaseKey() {
+ return Planner.fetchBaseKey(services.wellknown());
+ }
+
public TDF.Reader loadTDF(SeekableByteChannel channel, Config.TDFReaderConfig config) throws SDKException, IOException {
var tdf = new TDF(services);
return tdf.loadTDF(channel, config, platformUrl);
diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/SDKTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/SDKTest.java
index c5dda9eb..44e30dce 100644
--- a/sdk/src/test/java/io/opentdf/platform/sdk/SDKTest.java
+++ b/sdk/src/test/java/io/opentdf/platform/sdk/SDKTest.java
@@ -1,8 +1,14 @@
package io.opentdf.platform.sdk;
import com.connectrpc.impl.ProtocolClient;
+import com.google.protobuf.Struct;
+import com.google.protobuf.Value;
+import io.opentdf.platform.policy.Algorithm;
+import io.opentdf.platform.wellknownconfiguration.GetWellKnownConfigurationResponse;
+import io.opentdf.platform.wellknownconfiguration.WellKnownServiceClientInterface;
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -30,6 +36,33 @@ void testReadingProtocolClient() {
assertThat(sdk.getPlatformServicesClient()).isSameAs(platformServicesClient);
}
+ @Test
+ void testGettingBaseKey() {
+ var platformServicesClient = mock(ProtocolClient.class);
+ var wellknownService = Mockito.mock(WellKnownServiceClientInterface.class);
+ var baseKeyJson = "{\"kas_url\":\"https://example.com/base_key\",\"public_key\":{\"algorithm\":\"ALGORITHM_RSA_2048\",\"kid\":\"thekid\",\"pem\": \"thepem\"}}";
+ var val = Value.newBuilder().setStringValue(baseKeyJson).build();
+ var config = Struct.newBuilder().putFields("base_key", val).build();
+ var response = GetWellKnownConfigurationResponse
+ .newBuilder()
+ .setConfiguration(config)
+ .build();
+
+ Mockito.when(wellknownService.getWellKnownConfigurationBlocking(Mockito.any(), Mockito.anyMap()))
+ .thenReturn(TestUtil.successfulUnaryCall(response));
+
+ var services = new FakeServicesBuilder().setWellknownService(wellknownService).build();
+ var sdk = new SDK(services, null, null, platformServicesClient, null);
+
+ var baseKey = sdk.getBaseKey();
+ assertThat(baseKey).isPresent();
+ var simpleKasKey = baseKey.get();
+ assertThat(simpleKasKey.getKasUri()).isEqualTo("https://example.com/base_key");
+ assertThat(simpleKasKey.getPublicKey().getAlgorithm()).isEqualTo(Algorithm.ALGORITHM_RSA_2048);
+ assertThat(simpleKasKey.getPublicKey().getKid()).isEqualTo("thekid");
+ assertThat(simpleKasKey.getPublicKey().getPem()).isEqualTo("thepem");
+ }
+
@Test
void testAuthorizationServiceClientV2() {
var platformServicesClient = mock(ProtocolClient.class);
@@ -108,4 +141,4 @@ void testReadingRandomBytes() {
assertThat(SDK.isTDF(new SeekableInMemoryByteChannel(tdf))).isFalse();
}
-}
\ No newline at end of file
+}