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 075919da..04f929f7 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Config.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Config.java @@ -30,6 +30,7 @@ public enum IntegrityAlgorithm { public static class KASInfo { public String URL; public String PublicKey; + public String KID; } public static class TDFConfig { diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java b/sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java index 7a2b7f5d..2eddec57 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java @@ -67,6 +67,13 @@ public String getPublicKey(Config.KASInfo kasInfo) { .getPublicKey(); } + @Override + public String getKid(Config.KASInfo kasInfo) { + return getStub(kasInfo.URL) + .publicKey(PublicKeyRequest.getDefaultInstance()) + .getKid(); + } + private String normalizeAddress(String urlString) { URL url; try { diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java index b7692ec9..ac428798 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/Manifest.java @@ -34,6 +34,7 @@ static public class KeyAccess { public String wrappedKey; public String policyBinding; public String encryptedMetadata; + public String kid; } static public class Method { 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 56ef360d..46c897f1 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/SDK.java @@ -26,6 +26,7 @@ public void close() throws Exception { public interface KAS extends AutoCloseable { String getPublicKey(Config.KASInfo kasInfo); + String getKid(Config.KASInfo kasInfo); String getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve); byte[] unwrap(Manifest.KeyAccess keyAccess, String policy); byte[] unwrapNanoTDF(NanoTDFType.ECCurve curve, String header, String kasURL); 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 5466daf2..1be399f6 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -170,6 +170,7 @@ private void prepareManifest(Config.TDFConfig tdfConfig) { Manifest.KeyAccess keyAccess = new Manifest.KeyAccess(); keyAccess.keyType = kWrapped; keyAccess.url = kasInfo.URL; + keyAccess.kid = kasInfo.KID; keyAccess.protocol = kKasProtocol; // Add policyBinding @@ -369,6 +370,7 @@ private void fillInPublicKeyInfo(List kasInfoList, SDK.KAS kas) } logger.info("no public key provided for KAS at {}, retrieving", kasInfo.URL); kasInfo.PublicKey = kas.getPublicKey(kasInfo); + kasInfo.KID = kas.getKid(kasInfo); } } diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ConfigTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ConfigTest.java index 2b651b06..3eb9ecbc 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ConfigTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ConfigTest.java @@ -32,6 +32,7 @@ void withKasInformation_shouldAddKasInfo() { Config.KASInfo kasInfo = new Config.KASInfo(); kasInfo.URL = "http://example.com"; kasInfo.PublicKey = "publicKey"; + kasInfo.KID = "r1"; Config.TDFConfig config = Config.newTDFConfig(Config.withKasInformation(kasInfo)); assertEquals(1, config.kasInfoList.size()); assertEquals(kasInfo, config.kasInfoList.get(0)); diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/KASClientTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/KASClientTest.java index b8ab9d95..14b79bfc 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/KASClientTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/KASClientTest.java @@ -70,6 +70,39 @@ public void publicKey(PublicKeyRequest request, StreamObserver responseObserver) { + var response = PublicKeyResponse.newBuilder().setKid("r1").build(); + responseObserver.onNext(response); + responseObserver.onCompleted(); + } + }; + + Server server = null; + try { + server = startServer(accessService); + Function channelFactory = (String url) -> ManagedChannelBuilder + .forTarget(url) + .usePlaintext() + .build(); + + var keypair = CryptoUtils.generateRSAKeypair(); + var dpopKey = new RSAKey.Builder((RSAPublicKey) keypair.getPublic()).privateKey(keypair.getPrivate()).build(); + try (var kas = new KASClient(channelFactory, dpopKey)) { + Config.KASInfo kasInfo = new Config.KASInfo(); + kasInfo.URL = "localhost:" + server.getPort(); + assertThat(kas.getKid(kasInfo)).isEqualTo("r1"); + } + } finally { + if (server != null) { + server.shutdownNow(); + } + } + } + @Test void testCallingRewrap() throws IOException { var dpopKeypair = CryptoUtils.generateRSAKeypair(); 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 411e433a..e0aec19f 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/NanoTDFTest.java @@ -43,6 +43,11 @@ public String getPublicKey(Config.KASInfo kasInfo) { return kasPublicKey; } + @Override + public String getKid(Config.KASInfo kasInfo) { + return "r1"; + } + @Override public String getECPublicKey(Config.KASInfo kasInfo, NanoTDFType.ECCurve curve) { return kasPublicKey; 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 284bec5b..0981c0c5 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java @@ -35,6 +35,11 @@ public String getPublicKey(Config.KASInfo kasInfo) { return CryptoUtils.getRSAPublicKeyPEM(keypairs.get(index).getPublic()); } + @Override + public String getKid(Config.KASInfo kasInfo) { + return "r1"; + } + @Override public byte[] unwrap(Manifest.KeyAccess keyAccess, String policy) { int index = Integer.parseInt(keyAccess.url);