From 9bf8ebcd0bfd62a468d0699af7d42376ece8d6be Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Tue, 9 Jun 2026 14:13:57 -0400 Subject: [PATCH 01/58] set bc in approved only --- .github/workflows/checks.yaml | 5 ++- .../sdk/FipsProviderVerificationTest.java | 45 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 sdk/src/test/java/io/opentdf/platform/sdk/FipsProviderVerificationTest.java diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 2c7eedd7..fe67d63e 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -92,7 +92,10 @@ jobs: BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }} run: mvn clean --batch-mode clean generate-sources - name: Tests and enforcer (fips) - run: mvn --batch-mode test enforcer:enforce -P 'fips,!non-fips' -Dmaven.antrun.skip + run: | + mvn --batch-mode test enforcer:enforce -P 'fips,!non-fips' \ + -Dmaven.antrun.skip \ + -Dorg.bouncycastle.fips.approved_only=true - name: Tests with coverage and javadoc (non-fips) env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/FipsProviderVerificationTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/FipsProviderVerificationTest.java new file mode 100644 index 00000000..b269ddb0 --- /dev/null +++ b/sdk/src/test/java/io/opentdf/platform/sdk/FipsProviderVerificationTest.java @@ -0,0 +1,45 @@ +package io.opentdf.platform.sdk; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; + +import java.security.Security; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Verifies that the java.security.fips.test properties file was actually loaded when running + * under the fips Maven profile. Without this check, a misconfigured argLine would silently run + * all other tests against the default (non-FIPS) provider stack. + */ +@EnabledIfSystemProperty(named = "org.bouncycastle.fips.approved_only", matches = "true") +class FipsProviderVerificationTest { + + @Test + void bcFipsIsFirstProvider() { + var providers = Security.getProviders(); + assertNotNull(providers, "No security providers registered"); + assertTrue(providers.length > 0, "Provider list is empty"); + assertEquals("BCFIPS", providers[0].getName(), + "Expected BCFIPS as the first security provider but got: " + providers[0].getName() + + " — the java.security.fips.test file was likely not loaded"); + } + + @Test + void bcJsseIsRegistered() { + assertNotNull(Security.getProvider("BCJSSE"), + "BCJSSE provider is not registered — the java.security.fips.test file was likely not loaded"); + } + + @Test + void sunJceIsNotRegistered() { + assertNull(Security.getProvider("SunJCE"), + "SunJCE provider is still registered — it should have been removed by java.security.fips.test"); + } + + @Test + void keyManagerFactoryAlgorithmIsPkix() { + assertEquals("PKIX", Security.getProperty("ssl.KeyManagerFactory.algorithm"), + "ssl.KeyManagerFactory.algorithm was not overridden to PKIX — the java.security.fips.test file was likely not loaded"); + } +} From 47d455ca847177723854d55ecb98e038284ed83c Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Tue, 9 Jun 2026 14:54:04 -0400 Subject: [PATCH 02/58] feat(sdk): use cipher wrap/unwrap for RSA key operations Switch AsymEncryption from ENCRYPT_MODE+doFinal to WRAP_MODE+wrap, and AsymDecryption from DECRYPT_MODE+doFinal to UNWRAP_MODE+unwrap, treating the key material as AES SecretKeySpec for FIPS compatibility. Co-Authored-By: Claude Sonnet 4.6 --- .../java/io/opentdf/platform/sdk/AsymDecryption.java | 9 ++++----- .../java/io/opentdf/platform/sdk/AsymEncryption.java | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/AsymDecryption.java b/sdk/src/main/java/io/opentdf/platform/sdk/AsymDecryption.java index b76d1523..23ae25fe 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/AsymDecryption.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/AsymDecryption.java @@ -1,8 +1,6 @@ package io.opentdf.platform.sdk; -import javax.crypto.BadPaddingException; import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.security.*; import java.security.spec.InvalidKeySpecException; @@ -67,13 +65,14 @@ public byte[] decrypt(byte[] data) { throw new SDKException("error getting instance of cipher", e); } try { - cipher.init(Cipher.DECRYPT_MODE, this.privateKey); + cipher.init(Cipher.UNWRAP_MODE, this.privateKey); } catch (InvalidKeyException e) { throw new SDKException("error initializing cipher", e); } try { - return cipher.doFinal(data); - } catch (IllegalBlockSizeException | BadPaddingException e) { + Key key = cipher.unwrap(data, "AES", Cipher.SECRET_KEY); + return key.getEncoded(); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { throw new SDKException("error performing decryption", e); } } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/AsymEncryption.java b/sdk/src/main/java/io/opentdf/platform/sdk/AsymEncryption.java index 3a81b1f5..93989fca 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/AsymEncryption.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/AsymEncryption.java @@ -1,9 +1,9 @@ package io.opentdf.platform.sdk; -import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayInputStream; import java.security.*; @@ -99,13 +99,13 @@ public byte[] encrypt(byte[] data) { throw new SDKException("error getting instance of cipher during encryption", e); } try { - cipher.init(Cipher.ENCRYPT_MODE, this.publicKey); + cipher.init(Cipher.WRAP_MODE, this.publicKey); } catch (InvalidKeyException e) { throw new SDKException("error encrypting with private key", e); } try { - return cipher.doFinal(data); - } catch (IllegalBlockSizeException | BadPaddingException e) { + return cipher.wrap(new SecretKeySpec(data, "AES")); + } catch (IllegalBlockSizeException | InvalidKeyException e) { throw new SDKException("error performing encryption", e); } } From ff37ca6ef8172d183426634c1b78fc8f43514337 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Wed, 10 Jun 2026 12:00:46 -0400 Subject: [PATCH 03/58] add an empty default key store in FIPS mode --- sdk/pom.xml | 2 +- .../test/resources/empty-fips-truststore.bcfks | Bin 0 -> 408 bytes sdk/src/test/resources/empty-fips-truststore.p12 | 0 sdk/src/test/resources/java.security.fips.test | 14 +------------- 4 files changed, 2 insertions(+), 14 deletions(-) create mode 100644 sdk/src/test/resources/empty-fips-truststore.bcfks create mode 100644 sdk/src/test/resources/empty-fips-truststore.p12 diff --git a/sdk/pom.xml b/sdk/pom.xml index de6b7618..5f00db15 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -496,7 +496,7 @@ false - -Djava.security.properties=${project.basedir}/src/test/resources/java.security.fips.test + -Djava.security.properties==${project.basedir}/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${project.basedir}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS diff --git a/sdk/src/test/resources/empty-fips-truststore.bcfks b/sdk/src/test/resources/empty-fips-truststore.bcfks new file mode 100644 index 0000000000000000000000000000000000000000..bbd77772931ea956435ccbd1633ba732b8eb396c GIT binary patch literal 408 zcmXqLVw_^oc*CG^3LB?Zn@8JsUPe}4gT^+46a=5gAe_bF8Ta91OLKh>wJpuF2=iO> zbMmD_-b-b_c9gPDW<7X@CDCKXCymheLLWF{!gUS1Tei&QSbBGfuuSSp?cAD)m5Z#H zm>d|G7!?e7*f=2eFmbao7|5}4CbW4lrZTfI>Kh2M@VvU3r!q5QtFofuuP7!)4ipmM1lO3^BWj7zLObqpe_{#y+78VE2rU!9>J09#m zc&dd>+kE+7mc@}fb(OzyPL|_6dX+beDMN5CLp#@^?J7Qz0%4C>f9}udFaNKuGEedP Lt*3Ku{%-;Ruy>kk literal 0 HcmV?d00001 diff --git a/sdk/src/test/resources/empty-fips-truststore.p12 b/sdk/src/test/resources/empty-fips-truststore.p12 new file mode 100644 index 00000000..e69de29b diff --git a/sdk/src/test/resources/java.security.fips.test b/sdk/src/test/resources/java.security.fips.test index d14bb542..7b6d74fe 100644 --- a/sdk/src/test/resources/java.security.fips.test +++ b/sdk/src/test/resources/java.security.fips.test @@ -2,6 +2,7 @@ # support them. tell it to use PKIX instead which is supported by BC ssl.KeyManagerFactory.algorithm=PKIX ssl.TrustManagerFactory.algorithm=PKIX +keystore.type=FIPS # the SUN provider is required so that we can get the NativePRNGBlocking algorithm securerandom.strongAlgorithms=NativePRNGBlocking:SUN @@ -9,16 +10,3 @@ securerandom.strongAlgorithms=NativePRNGBlocking:SUN security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider fips:BCFIPS security.provider.3=SUN - -# since this file is appended we need to make sure that we remove the other providers -security.provider.4= -security.provider.5= -security.provider.6= -security.provider.7= -security.provider.8= -security.provider.9= -security.provider.10= -security.provider.11= -security.provider.12= -security.provider.13= -security.provider.14= \ No newline at end of file From 335cfd43a0e668d2695d81bab477cf96adf33ab1 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 11:32:50 -0400 Subject: [PATCH 04/58] add new module --- .github/workflows/checks.yaml | 46 +++++++++++++++++++ pom.xml | 1 + sdk-fips-bouncycastle/pom.xml | 42 +++++++++++++++++ .../BouncyCastleFipsHkdfProvider.java | 27 +++++++++++ .../io.opentdf.platform.sdk.HkdfProvider | 1 + .../BouncyCastleFipsHkdfProviderTest.java | 44 ++++++++++++++++++ .../io/opentdf/platform/sdk/ECKeyPair.java | 8 ++++ .../io/opentdf/platform/sdk/HkdfProvider.java | 18 ++++++++ .../io/opentdf/platform/sdk/HkdfResolver.java | 30 ++++++++++++ .../opentdf/platform/sdk/ECKeyPairTest.java | 9 +++- 10 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 sdk-fips-bouncycastle/pom.xml create mode 100644 sdk-fips-bouncycastle/src/main/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProvider.java create mode 100644 sdk-fips-bouncycastle/src/main/resources/META-INF/services/io.opentdf.platform.sdk.HkdfProvider create mode 100644 sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java create mode 100644 sdk/src/main/java/io/opentdf/platform/sdk/HkdfProvider.java create mode 100644 sdk/src/main/java/io/opentdf/platform/sdk/HkdfResolver.java diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index fe67d63e..5de1eaad 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -176,6 +176,52 @@ jobs: fi working-directory: cmdline + - name: Validate the SDK through the command line interface (FIPS) + run: | + printf 'here is some data to encrypt' > data + + CP="$(mvn -pl sdk-fips-bouncycastle dependency:build-classpath -DincludeScope=compile)" + + java \ + -Djava.security.properties==${project.basedir}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${project.basedir}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -cp ${CP}" \ + -jar cmdline/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.security.properties==${project.basedir}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${project.basedir}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -cp ${CP}" \ + -jar cmdline/target/cmdline.jar \ + --client-id=opentdf-sdk \ + --client-secret=secret \ + --platform-endpoint=http://localhost:8080 \ + -h\ + decrypt -f test.tdf > decrypted + + java \ + -Djava.security.properties==${project.basedir}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${project.basedir}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -cp ${CP}" \ + -jar cmdline/target/cmdline.jar \ + --client-id=opentdf-sdk \ + --client-secret=secret \ + --platform-endpoint=http://localhost:8080 \ + -h\ + metadata -f test.tdf > metadata + + if ! diff -q data decrypted; then + printf 'decrypted data is incorrect [%s]' "$(< decrypted)" + exit 1 + fi + + if [ "$(< metadata)" != 'here is some metadata' ]; then + printf 'metadata is incorrect [%s]\n' "$(< metadata)" + exit 1 + fi + - name: Encrypt/Decrypt Assertions run: | echo "basic assertions" diff --git a/pom.xml b/pom.xml index 6ce3488c..482b05e8 100644 --- a/pom.xml +++ b/pom.xml @@ -286,6 +286,7 @@ develop sdk + sdk-fips-bouncycastle cmdline examples diff --git a/sdk-fips-bouncycastle/pom.xml b/sdk-fips-bouncycastle/pom.xml new file mode 100644 index 00000000..385c2ecd --- /dev/null +++ b/sdk-fips-bouncycastle/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + io.opentdf.platform + sdk-pom + 0.15.0 + + sdk-fips-bouncycastle + io.opentdf.platform:sdk-fips-bouncycastle + BouncyCastle FIPS-backed HkdfProvider SPI implementation (FIPS 140-approved HKDF via bc-fips). + jar + + UTF-8 + + + + io.opentdf.platform + sdk + ${project.version} + + + + org.bouncycastle + bc-fips + + + + org.junit.jupiter + junit-jupiter + test + + + org.assertj + assertj-core + 3.27.7 + test + + + diff --git a/sdk-fips-bouncycastle/src/main/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProvider.java b/sdk-fips-bouncycastle/src/main/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProvider.java new file mode 100644 index 00000000..c07898b0 --- /dev/null +++ b/sdk-fips-bouncycastle/src/main/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProvider.java @@ -0,0 +1,27 @@ +package io.opentdf.platform.sdk.fips.bouncycastle; + +import io.opentdf.platform.sdk.HkdfProvider; +import org.bouncycastle.crypto.KDFCalculator; +import org.bouncycastle.crypto.fips.FipsKDF; + +/** + * FIPS 140-approved {@link HkdfProvider} backed by the BouncyCastle FIPS KDF API. + * Discovered at runtime via {@code META-INF/services/io.opentdf.platform.sdk.HkdfProvider}. + */ +public final class BouncyCastleFipsHkdfProvider implements HkdfProvider { + + @Override + public byte[] computeHKDF(byte[] salt, byte[] secret) { + var key = FipsKDF.HKDF_KEY_BUILDER + .withPrf(FipsKDF.AgreementKDFPRF.SHA256_HMAC) + .withSalt(salt) + .build(secret); + + var factory = new FipsKDF.AgreementOperatorFactory(); + KDFCalculator kdfCalculator = factory.createKDFCalculator( + FipsKDF.HKDF.withPRF(FipsKDF.AgreementKDFPRF.SHA256_HMAC).using(key.getKey())); + byte[] hkdf = new byte[32]; + kdfCalculator.generateBytes(hkdf); + return hkdf; + } +} diff --git a/sdk-fips-bouncycastle/src/main/resources/META-INF/services/io.opentdf.platform.sdk.HkdfProvider b/sdk-fips-bouncycastle/src/main/resources/META-INF/services/io.opentdf.platform.sdk.HkdfProvider new file mode 100644 index 00000000..bc38f948 --- /dev/null +++ b/sdk-fips-bouncycastle/src/main/resources/META-INF/services/io.opentdf.platform.sdk.HkdfProvider @@ -0,0 +1 @@ +io.opentdf.platform.sdk.fips.bouncycastle.BouncyCastleFipsHkdfProvider diff --git a/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java b/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java new file mode 100644 index 00000000..ce180520 --- /dev/null +++ b/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java @@ -0,0 +1,44 @@ +package io.opentdf.platform.sdk.fips.bouncycastle; + +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; + +import static org.assertj.core.api.Assertions.assertThat; + +class BouncyCastleFipsHkdfProviderTest { + + private final BouncyCastleFipsHkdfProvider provider = new BouncyCastleFipsHkdfProvider(); + + @Test + void computeHKDF_returns32Bytes() { + byte[] salt = "test-salt".getBytes(StandardCharsets.UTF_8); + byte[] secret = "test-secret".getBytes(StandardCharsets.UTF_8); + + byte[] result = provider.computeHKDF(salt, secret); + + assertThat(result).hasSize(32); + } + + @Test + void computeHKDF_isDeterministic() { + byte[] salt = "salt".getBytes(StandardCharsets.UTF_8); + byte[] secret = "secret".getBytes(StandardCharsets.UTF_8); + + byte[] first = provider.computeHKDF(salt, secret); + byte[] second = provider.computeHKDF(salt, secret); + + assertThat(first).isEqualTo(second); + } + + @Test + void computeHKDF_matchesJdkFallback() { + byte[] salt = "ECKeysSalt".getBytes(StandardCharsets.UTF_8); + byte[] secret = new byte[32]; // simulated shared secret + + byte[] fipsResult = provider.computeHKDF(salt, secret); + byte[] jdkResult = io.opentdf.platform.sdk.ECKeyPair.calculateHKDF(salt, secret); + + assertThat(fipsResult).isEqualTo(jdkResult); + } +} diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java index 92d778bd..03f788c7 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java @@ -106,8 +106,16 @@ public static byte[] computeECDHKey(ECPublicKey publicKey, ECPrivateKey privateK /** * Returns a HKDF key derived from the provided salt and secret * that is 32 bytes (256 bits) long. + * + * Delegates to a registered {@link HkdfProvider} when one is available on the + * classpath (e.g. {@code sdk-fips-bouncycastle}); otherwise falls back to the + * JDK-native HmacSHA256 implementation. */ public static byte[] calculateHKDF(byte[] salt, byte[] secret) { + HkdfProvider provider = HkdfResolver.get(); + if (provider != null) { + return provider.computeHKDF(salt, secret); + } try { // RFC 5869: if salt is absent, substitute a zero-filled buffer of Hash output size. byte[] effectiveSalt = (salt == null || salt.length == 0) ? new byte[SHA256_BYTES] : salt; diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/HkdfProvider.java b/sdk/src/main/java/io/opentdf/platform/sdk/HkdfProvider.java new file mode 100644 index 00000000..57581619 --- /dev/null +++ b/sdk/src/main/java/io/opentdf/platform/sdk/HkdfProvider.java @@ -0,0 +1,18 @@ +package io.opentdf.platform.sdk; + +/** + * Service Provider Interface for HKDF (RFC 5869) key derivation. + * Implementations are discovered at runtime via {@link java.util.ServiceLoader}. + * When no implementation is on the classpath, {@link ECKeyPair#calculateHKDF} falls + * back to the JDK-native HmacSHA256 implementation. + * + * The FIPS-approved implementation is {@code io.opentdf.platform:sdk-fips-bouncycastle}, + * which uses the BouncyCastle FIPS KDF API directly. + */ +public interface HkdfProvider { + /** + * Derive a 32-byte key using HKDF-Extract+Expand with SHA-256 HMAC PRF + * and empty info, per RFC 5869. + */ + byte[] computeHKDF(byte[] salt, byte[] secret); +} diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/HkdfResolver.java b/sdk/src/main/java/io/opentdf/platform/sdk/HkdfResolver.java new file mode 100644 index 00000000..140bb458 --- /dev/null +++ b/sdk/src/main/java/io/opentdf/platform/sdk/HkdfResolver.java @@ -0,0 +1,30 @@ +package io.opentdf.platform.sdk; + +import java.util.ServiceLoader; + +/** + * Locates a registered {@link HkdfProvider} via {@link ServiceLoader}. + * Returns {@code null} when no provider is registered, signalling + * the caller to use the JDK-native fallback. + */ +final class HkdfResolver { + + private HkdfResolver() {} + + private static final class Holder { + static final HkdfProvider PROVIDER = load(); + + private static HkdfProvider load() { + for (HkdfProvider p : ServiceLoader.load( + HkdfProvider.class, + HkdfResolver.class.getClassLoader())) { + return p; + } + return null; + } + } + + static HkdfProvider get() { + return Holder.PROVIDER; + } +} diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java index be9e813b..9c0f2f44 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java @@ -2,7 +2,10 @@ import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; + +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -84,8 +87,8 @@ void ecPublicKeyInPemformat() { } @Test - void extractPemPubKeyFromX509() throws CertificateException, IOException, NoSuchAlgorithmException, - InvalidKeySpecException, NoSuchProviderException, InvalidAlgorithmParameterException, InvalidKeyException { + @DisabledIfSystemProperty(named = "org.bouncycastle.fips.approved_only", matches = "true") + void extractPemPubKeyFromX509() { String x509ECPubKey = "-----BEGIN CERTIFICATE-----\n" + "MIIBCzCBsgIJAK3Uxk7fP5oWMAoGCCqGSM49BAMCMA4xDDAKBgNVBAMMA2thczAe\n" + "Fw0yMzA0MjQxNzQ2MTVaFw0yNDA0MjMxNzQ2MTVaMA4xDDAKBgNVBAMMA2thczBZ\n" + @@ -123,6 +126,7 @@ void extractPemPubKeyFromX509() throws CertificateException, IOException, NoSuch } @Test + @DisabledIfSystemProperty(named = "org.bouncycastle.fips.approved_only", matches = "true") void createSymmetricKeysWithOtherCurves() { ECKeyPair pubPair = new ECKeyPair(ECCurve.SECP384R1); ECKeyPair keyPair = new ECKeyPair(ECCurve.SECP384R1); @@ -134,6 +138,7 @@ void createSymmetricKeysWithOtherCurves() { } @Test + @DisabledIfSystemProperty(named = "org.bouncycastle.fips.approved_only", matches = "true") void testECDH() { String expectedKey = "3KGgsptHbTsbxJtql6sHUcx255KcUhxdeJWKjmPMlcc="; From 25d4b2a0b2635749f1643ae66218ccdedb537365 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 11:52:36 -0400 Subject: [PATCH 05/58] use a good envvar --- .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 5de1eaad..b504ea0f 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -183,7 +183,7 @@ jobs: CP="$(mvn -pl sdk-fips-bouncycastle dependency:build-classpath -DincludeScope=compile)" java \ - -Djava.security.properties==${project.basedir}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${project.basedir}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ -cp ${CP}" \ -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ @@ -193,7 +193,7 @@ jobs: 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.security.properties==${project.basedir}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${project.basedir}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ -cp ${CP}" \ -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ @@ -203,7 +203,7 @@ jobs: decrypt -f test.tdf > decrypted java \ - -Djava.security.properties==${project.basedir}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${project.basedir}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ -cp ${CP}" \ -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ From debc0cfe92994f05b66bee2e7c02bac3df1afa4c Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 12:11:16 -0400 Subject: [PATCH 06/58] deal with the CP correctly --- .github/workflows/checks.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index b504ea0f..487ddb10 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -180,7 +180,8 @@ jobs: run: | printf 'here is some data to encrypt' > data - CP="$(mvn -pl sdk-fips-bouncycastle dependency:build-classpath -DincludeScope=compile)" + mvn -pl sdk-fips-bouncycastle dependency:build-classpath -DincludeScope=compile -Dmdep.outputFile="${GITHUB_WORKSPACE}/cp.txt" + CP="$(< "${GITHUB_WORKSPACE}/cp.txt")" java \ -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ From 9d7543051d6dd55005b520fc577c112c4dbb86a4 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 12:19:21 -0400 Subject: [PATCH 07/58] do this faster --- .github/workflows/checks.yaml | 70 ++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 487ddb10..f2271cc1 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -127,38 +127,38 @@ jobs: BUF_INPUT_HTTPS_USERNAME: opentdf-bot BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }} - - name: Check out and start up platform with deps/containers - id: run-platform - uses: opentdf/platform/test/start-up-with-containers@main - with: - platform-ref: main - - - name: Get grpcurl - run: go install github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.8.9 - - name: Make sure that the platform is up - run: | - grpcurl -plaintext localhost:8080 list && \ - grpcurl -plaintext localhost:8080 kas.AccessService/PublicKey - - - name: Validate the SDK through the command line interface + - name: Validate the SDK through the command line interface (FIPS) run: | printf 'here is some data to encrypt' > data - java -jar target/cmdline.jar \ + mvn -pl sdk-fips-bouncycastle dependency:build-classpath -DincludeScope=compile -Dmdep.outputFile="${GITHUB_WORKSPACE}/cp.txt" + CP="$(< "${GITHUB_WORKSPACE}/cp.txt")" + echo "${CP}" + + java \ + -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -cp ${CP}" \ + -jar cmdline/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 \ + -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -cp ${CP}" \ + -jar cmdline/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 \ + -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + -cp ${CP}" \ + -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ @@ -174,39 +174,40 @@ jobs: printf 'metadata is incorrect [%s]\n' "$(< metadata)" exit 1 fi - working-directory: cmdline - - name: Validate the SDK through the command line interface (FIPS) + + - name: Check out and start up platform with deps/containers + id: run-platform + uses: opentdf/platform/test/start-up-with-containers@main + with: + platform-ref: main + + - name: Get grpcurl + run: go install github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.8.9 + - name: Make sure that the platform is up run: | - printf 'here is some data to encrypt' > data + grpcurl -plaintext localhost:8080 list && \ + grpcurl -plaintext localhost:8080 kas.AccessService/PublicKey - mvn -pl sdk-fips-bouncycastle dependency:build-classpath -DincludeScope=compile -Dmdep.outputFile="${GITHUB_WORKSPACE}/cp.txt" - CP="$(< "${GITHUB_WORKSPACE}/cp.txt")" + - name: Validate the SDK through the command line interface + run: | + printf 'here is some data to encrypt' > data - java \ - -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ - -cp ${CP}" \ - -jar cmdline/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 \ - -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ - -cp ${CP}" \ - -jar cmdline/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 \ - -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ - -cp ${CP}" \ - -jar cmdline/target/cmdline.jar \ + java -jar target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ @@ -222,6 +223,7 @@ jobs: printf 'metadata is incorrect [%s]\n' "$(< metadata)" exit 1 fi + working-directory: cmdline - name: Encrypt/Decrypt Assertions run: | From 49aae55864d5a2d4616950912189d4e82cbc6e9c Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 14:47:48 -0400 Subject: [PATCH 08/58] set this up --- .github/workflows/checks.yaml | 26 ++++++++++++------- cmdline/pom.xml | 10 +++++++ .../java/io/opentdf/platform/Command.java | 4 +++ sdk/pom.xml | 4 +-- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index f2271cc1..ae9a3a1e 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -120,9 +120,10 @@ jobs: java-version: "17" distribution: "temurin" server-id: github + - name: Build java SDK run: | - mvn --batch-mode clean install -DskipTests + mvn --batch-mode clean install -P 'fips,!non-fips' -DskipTests env: BUF_INPUT_HTTPS_USERNAME: opentdf-bot BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }} @@ -131,14 +132,19 @@ jobs: run: | printf 'here is some data to encrypt' > data - mvn -pl sdk-fips-bouncycastle dependency:build-classpath -DincludeScope=compile -Dmdep.outputFile="${GITHUB_WORKSPACE}/cp.txt" - CP="$(< "${GITHUB_WORKSPACE}/cp.txt")" - echo "${CP}" + mvn dependency:copy -Dartifact=org.bouncycastle:bc-fips:2.1.2:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" + mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" + mvn dependency:copy -Dartifact=org.bouncycastle:bctls-fips:2.1.23:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" - java \ - -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ - -cp ${CP}" \ - -jar cmdline/target/cmdline.jar \ + CP="${GITHUB_WORKSPACE}/sdk-fips-bouncycastle/target/*:${GITHUB_WORKSPACE}/commandline/target/commandline.jar" + CP="${CP}:${GITHUB_WORKSPACE}/bc-fips.jar" + CP="${CP}:${GITHUB_WORKSPACE}/bcutil-fips.jar" + CP="${CP}:${GITHUB_WORKSPACE}/bctls-fips.jar" + + SECURITY_PROPERTIES="-Djava.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS" + + java "${SECURITY_PROPERTIES}" \ + -cp "${CP}" \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ @@ -146,7 +152,7 @@ jobs: 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 \ - -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + "${SECURITY_PROPERTIES}" \ -cp ${CP}" \ -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ @@ -156,7 +162,7 @@ jobs: decrypt -f test.tdf > decrypted java \ - -D"java.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test" -Dorg.bouncycastle.fips.approved_only=true -D"javax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks" -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS \ + "${SECURITY_PROPERTIES}" \ -cp ${CP}" \ -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ diff --git a/cmdline/pom.xml b/cmdline/pom.xml index 3f82579a..91046f3b 100644 --- a/cmdline/pom.xml +++ b/cmdline/pom.xml @@ -76,6 +76,16 @@ io.opentdf.platform sdk ${project.version} + + + org.bouncycastle + bc-fips + + + org.bouncycastle + bctls-fips + + diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 685f8782..0c5dfc6d 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -10,6 +10,7 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; +import java.security.Security; import java.security.cert.X509Certificate; import java.text.ParseException; import com.google.gson.JsonSyntaxException; @@ -200,6 +201,8 @@ void encrypt( throws IOException, AutoConfigureException { + System.out.println("here are the providers" + List.of(Security.getProviders())); + var sdk = buildSDK(); var kasInfos = kas.stream().map(k -> { var ki = new Config.KASInfo(); @@ -207,6 +210,7 @@ void encrypt( return ki; }).toArray(Config.KASInfo[]::new); + List> configs = new ArrayList<>(); configs.add(Config.withKasInformation(kasInfos)); metadata.map(Config::withMetaData).ifPresent(configs::add); diff --git a/sdk/pom.xml b/sdk/pom.xml index 5f00db15..240e0d63 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -502,12 +502,12 @@ org.bouncycastle bc-fips - runtime + test org.bouncycastle bctls-fips - runtime + test org.bouncycastle From 0d79a1f430246e38a4e2d73e9495570788c2028f Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 14:51:34 -0400 Subject: [PATCH 09/58] include the main class --- .github/workflows/checks.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index ae9a3a1e..67f882b0 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -145,6 +145,7 @@ jobs: java "${SECURITY_PROPERTIES}" \ -cp "${CP}" \ + io.opentdf.platform.TDF \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ @@ -154,6 +155,7 @@ jobs: java \ "${SECURITY_PROPERTIES}" \ -cp ${CP}" \ + io.opentdf.platform.TDF \ -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ @@ -164,6 +166,7 @@ jobs: java \ "${SECURITY_PROPERTIES}" \ -cp ${CP}" \ + io.opentdf.platform.TDF \ -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ From 057d260942e2cf4b8f64895314fc529cdd1b580b Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 14:57:53 -0400 Subject: [PATCH 10/58] get the property right --- .github/workflows/checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 67f882b0..6ee66b37 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -136,7 +136,7 @@ jobs: mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bctls-fips:2.1.23:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" - CP="${GITHUB_WORKSPACE}/sdk-fips-bouncycastle/target/*:${GITHUB_WORKSPACE}/commandline/target/commandline.jar" + CP="${GITHUB_WORKSPACE}/sdk-fips-bouncycastle/target/*:${GITHUB_WORKSPACE}/cmdline/target/cmdline.jar" CP="${CP}:${GITHUB_WORKSPACE}/bc-fips.jar" CP="${CP}:${GITHUB_WORKSPACE}/bcutil-fips.jar" CP="${CP}:${GITHUB_WORKSPACE}/bctls-fips.jar" From f27230105b148346ddf28da278435aa6f7803b06 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 15:04:07 -0400 Subject: [PATCH 11/58] one more segment --- .github/workflows/checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 6ee66b37..d17c9f08 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -136,7 +136,7 @@ jobs: mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bctls-fips:2.1.23:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" - CP="${GITHUB_WORKSPACE}/sdk-fips-bouncycastle/target/*:${GITHUB_WORKSPACE}/cmdline/target/cmdline.jar" + CP="${GITHUB_WORKSPACE}/java-sdk/sdk-fips-bouncycastle/target/*:${GITHUB_WORKSPACE}/java-sdk/cmdline/target/cmdline.jar" CP="${CP}:${GITHUB_WORKSPACE}/bc-fips.jar" CP="${CP}:${GITHUB_WORKSPACE}/bcutil-fips.jar" CP="${CP}:${GITHUB_WORKSPACE}/bctls-fips.jar" From 1c807572e23cd3aa637a71080086fc88c34f0c00 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 15:09:07 -0400 Subject: [PATCH 12/58] print stuff out --- .github/workflows/checks.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index d17c9f08..d110471a 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -136,7 +136,10 @@ jobs: mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bctls-fips:2.1.23:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" - CP="${GITHUB_WORKSPACE}/java-sdk/sdk-fips-bouncycastle/target/*:${GITHUB_WORKSPACE}/java-sdk/cmdline/target/cmdline.jar" + find . -name 'cmdline.jar' + pwd + + CP="${GITHUB_WORKSPACE}/sdk-fips-bouncycastle/target/*:${GITHUB_WORKSPACE}/cmdline/target/cmdline.jar" CP="${CP}:${GITHUB_WORKSPACE}/bc-fips.jar" CP="${CP}:${GITHUB_WORKSPACE}/bcutil-fips.jar" CP="${CP}:${GITHUB_WORKSPACE}/bctls-fips.jar" From f00598dee994f4123cc75d34a37828ef0cafe8a4 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 15:13:32 -0400 Subject: [PATCH 13/58] see if this works --- .github/workflows/checks.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index d110471a..e92f6af2 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -138,8 +138,9 @@ jobs: find . -name 'cmdline.jar' pwd + jar tf cmdline/target/cmdline.jar - CP="${GITHUB_WORKSPACE}/sdk-fips-bouncycastle/target/*:${GITHUB_WORKSPACE}/cmdline/target/cmdline.jar" + CP="sdk-fips-bouncycastle/target/*:cmdline/target/cmdline.jar" CP="${CP}:${GITHUB_WORKSPACE}/bc-fips.jar" CP="${CP}:${GITHUB_WORKSPACE}/bcutil-fips.jar" CP="${CP}:${GITHUB_WORKSPACE}/bctls-fips.jar" From 7e081170ee9621fcfe0c409070cee519ba77a554 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 15:18:02 -0400 Subject: [PATCH 14/58] oops --- .github/workflows/checks.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index e92f6af2..308acd38 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -138,7 +138,6 @@ jobs: find . -name 'cmdline.jar' pwd - jar tf cmdline/target/cmdline.jar CP="sdk-fips-bouncycastle/target/*:cmdline/target/cmdline.jar" CP="${CP}:${GITHUB_WORKSPACE}/bc-fips.jar" From 6a137c437b715483137c4d8a32fc5fe90227777c Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 15:28:54 -0400 Subject: [PATCH 15/58] one more --- .github/workflows/checks.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 308acd38..a7953e23 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -140,9 +140,9 @@ jobs: pwd CP="sdk-fips-bouncycastle/target/*:cmdline/target/cmdline.jar" - CP="${CP}:${GITHUB_WORKSPACE}/bc-fips.jar" - CP="${CP}:${GITHUB_WORKSPACE}/bcutil-fips.jar" - CP="${CP}:${GITHUB_WORKSPACE}/bctls-fips.jar" + CP="${CP}:bc-fips.jar" + CP="${CP}:bcutil-fips.jar" + CP="${CP}:bctls-fips.jar" SECURITY_PROPERTIES="-Djava.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS" @@ -153,7 +153,7 @@ jobs: --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 + 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' java \ "${SECURITY_PROPERTIES}" \ From af427fc3ba91befa6a3e789e4b587fa3c64411aa Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 15:42:02 -0400 Subject: [PATCH 16/58] one more --- .github/workflows/checks.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index a7953e23..f956f0a8 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -144,9 +144,12 @@ jobs: CP="${CP}:bcutil-fips.jar" CP="${CP}:bctls-fips.jar" + SECURITY_PROPERTIES="-Djava.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS" - - java "${SECURITY_PROPERTIES}" \ + + echo "this is the CP ${CP}" + + java \ -cp "${CP}" \ io.opentdf.platform.TDF \ --client-id=opentdf-sdk \ From e4b4aa1146cd4d7acd7129f53b6ced7dd3f6920b Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 15:53:38 -0400 Subject: [PATCH 17/58] try this --- .github/workflows/checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index f956f0a8..ccb0ece7 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -149,7 +149,7 @@ jobs: echo "this is the CP ${CP}" - java \ + java ${SECURITY_PROPERTIES} \ -cp "${CP}" \ io.opentdf.platform.TDF \ --client-id=opentdf-sdk \ From 81afe20307f252b796c89aef4f7eb9248ae08d53 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 15:59:07 -0400 Subject: [PATCH 18/58] move this back to the right place --- .github/workflows/checks.yaml | 41 +++++++++++++++-------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index ccb0ece7..1decde44 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -128,26 +128,35 @@ jobs: BUF_INPUT_HTTPS_USERNAME: opentdf-bot BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }} - - name: Validate the SDK through the command line interface (FIPS) + + + - name: Check out and start up platform with deps/containers + id: run-platform + uses: opentdf/platform/test/start-up-with-containers@main + with: + platform-ref: main + + - name: Get grpcurl + run: go install github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.8.9 + - name: Make sure that the platform is up run: | - printf 'here is some data to encrypt' > data + grpcurl -plaintext localhost:8080 list && \ + grpcurl -plaintext localhost:8080 kas.AccessService/PublicKey + - name: Validate the SDK through the command line interface (FIPS) + run: | mvn dependency:copy -Dartifact=org.bouncycastle:bc-fips:2.1.2:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bctls-fips:2.1.23:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" - find . -name 'cmdline.jar' - pwd - CP="sdk-fips-bouncycastle/target/*:cmdline/target/cmdline.jar" CP="${CP}:bc-fips.jar" CP="${CP}:bcutil-fips.jar" CP="${CP}:bctls-fips.jar" - SECURITY_PROPERTIES="-Djava.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS" - echo "this is the CP ${CP}" + printf 'here is some data to encrypt' > data java ${SECURITY_PROPERTIES} \ -cp "${CP}" \ @@ -159,7 +168,7 @@ jobs: 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' java \ - "${SECURITY_PROPERTIES}" \ + ${SECURITY_PROPERTIES} \ -cp ${CP}" \ io.opentdf.platform.TDF \ -jar cmdline/target/cmdline.jar \ @@ -170,7 +179,7 @@ jobs: decrypt -f test.tdf > decrypted java \ - "${SECURITY_PROPERTIES}" \ + ${SECURITY_PROPERTIES} \ -cp ${CP}" \ io.opentdf.platform.TDF \ -jar cmdline/target/cmdline.jar \ @@ -190,20 +199,6 @@ jobs: exit 1 fi - - - name: Check out and start up platform with deps/containers - id: run-platform - uses: opentdf/platform/test/start-up-with-containers@main - with: - platform-ref: main - - - name: Get grpcurl - run: go install github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.8.9 - - name: Make sure that the platform is up - run: | - grpcurl -plaintext localhost:8080 list && \ - grpcurl -plaintext localhost:8080 kas.AccessService/PublicKey - - name: Validate the SDK through the command line interface run: | printf 'here is some data to encrypt' > data From d03af4b9855700ed8f6be6164bdba31a99ab3884 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 16:05:14 -0400 Subject: [PATCH 19/58] one more --- .github/workflows/checks.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 1decde44..2e90b7fc 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -171,7 +171,6 @@ jobs: ${SECURITY_PROPERTIES} \ -cp ${CP}" \ io.opentdf.platform.TDF \ - -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ @@ -182,7 +181,6 @@ jobs: ${SECURITY_PROPERTIES} \ -cp ${CP}" \ io.opentdf.platform.TDF \ - -jar cmdline/target/cmdline.jar \ --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ From 2014c3dc2e75c610e2c53a7d0ffcd8ccff127d16 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 16:09:00 -0400 Subject: [PATCH 20/58] make sure to get output it --- .github/workflows/checks.yaml | 2 +- cmdline/src/main/java/io/opentdf/platform/Command.java | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 2e90b7fc..08f15f85 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -165,7 +165,7 @@ jobs: --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' + 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 \ ${SECURITY_PROPERTIES} \ diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 0c5dfc6d..dcfe26c4 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -10,8 +10,6 @@ import com.google.gson.GsonBuilder; import com.google.gson.reflect.TypeToken; -import java.security.Security; -import java.security.cert.X509Certificate; import java.text.ParseException; import com.google.gson.JsonSyntaxException; import io.opentdf.platform.sdk.AssertionConfig; @@ -24,7 +22,6 @@ import picocli.CommandLine.HelpCommand; import picocli.CommandLine.Option; -import javax.net.ssl.X509TrustManager; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; @@ -201,8 +198,6 @@ void encrypt( throws IOException, AutoConfigureException { - System.out.println("here are the providers" + List.of(Security.getProviders())); - var sdk = buildSDK(); var kasInfos = kas.stream().map(k -> { var ki = new Config.KASInfo(); From 2629f07bdb5f9a28f19fb2815d06a81733b9a078 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 16:19:12 -0400 Subject: [PATCH 21/58] debug --- .github/workflows/checks.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 08f15f85..958f165f 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -145,6 +145,8 @@ jobs: - name: Validate the SDK through the command line interface (FIPS) run: | + set -e + mvn dependency:copy -Dartifact=org.bouncycastle:bc-fips:2.1.2:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bctls-fips:2.1.23:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" @@ -167,6 +169,8 @@ jobs: -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 + echo 'we encrypted it' + java \ ${SECURITY_PROPERTIES} \ -cp ${CP}" \ @@ -177,6 +181,9 @@ jobs: -h\ decrypt -f test.tdf > decrypted + echo 'we decrypted it' + ls -l + java \ ${SECURITY_PROPERTIES} \ -cp ${CP}" \ From 2309106bfd612f4fc196f4725002a931d63e3c1e Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 16:58:24 -0400 Subject: [PATCH 22/58] maybe this --- .github/workflows/checks.yaml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 958f165f..2d69d915 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -166,8 +166,12 @@ jobs: --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 + -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 echo 'we encrypted it' @@ -178,8 +182,8 @@ jobs: --client-id=opentdf-sdk \ --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ - -h\ - decrypt -f test.tdf > decrypted + -h \ + decrypt -f test.tdf echo 'we decrypted it' ls -l From f24d41a2bbf0f4f48bd5f1ae5a1b8fa97d856f2e Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 17:07:24 -0400 Subject: [PATCH 23/58] see about this --- .github/workflows/checks.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 2d69d915..6c904276 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -171,9 +171,7 @@ jobs: --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 - - echo 'we encrypted it' + --autoconfigure=false -f data -m 'here is some metadata' > tests.tdf java \ ${SECURITY_PROPERTIES} \ @@ -183,7 +181,7 @@ jobs: --client-secret=secret \ --platform-endpoint=http://localhost:8080 \ -h \ - decrypt -f test.tdf + decrypt -f test.tdf > decrypted echo 'we decrypted it' ls -l From c999916f4c4a9d45425a7890283935e42ed190d1 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 17:15:00 -0400 Subject: [PATCH 24/58] crazy --- .github/workflows/checks.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 6c904276..3fdfe7c2 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -171,7 +171,9 @@ jobs: --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' > tests.tdf + --autoconfigure=false -f data -m 'here is some metadata' > test.tdf + + ls -lh java \ ${SECURITY_PROPERTIES} \ @@ -183,6 +185,7 @@ jobs: -h \ decrypt -f test.tdf > decrypted + cat decrypted echo 'we decrypted it' ls -l From 027ab7d74fa7cdaada14bc1fd4eda61d27473192 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 17:22:15 -0400 Subject: [PATCH 25/58] one more try --- .github/workflows/checks.yaml | 2 +- cmdline/src/main/resources/log4j2.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 3fdfe7c2..904b1503 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -145,7 +145,7 @@ jobs: - name: Validate the SDK through the command line interface (FIPS) run: | - set -e + set -euo pipefail mvn dependency:copy -Dartifact=org.bouncycastle:bc-fips:2.1.2:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" diff --git a/cmdline/src/main/resources/log4j2.xml b/cmdline/src/main/resources/log4j2.xml index da185a60..59539c9b 100644 --- a/cmdline/src/main/resources/log4j2.xml +++ b/cmdline/src/main/resources/log4j2.xml @@ -6,7 +6,7 @@ - + From fad0435579fd37d13849a64f70893e30b6b2993f Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 17:37:17 -0400 Subject: [PATCH 26/58] one more --- .github/workflows/checks.yaml | 2 +- cmdline/src/main/resources/log4j2.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 904b1503..b3950828 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -145,7 +145,7 @@ jobs: - name: Validate the SDK through the command line interface (FIPS) run: | - set -euo pipefail + set -exuo pipefail mvn dependency:copy -Dartifact=org.bouncycastle:bc-fips:2.1.2:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" diff --git a/cmdline/src/main/resources/log4j2.xml b/cmdline/src/main/resources/log4j2.xml index 59539c9b..da185a60 100644 --- a/cmdline/src/main/resources/log4j2.xml +++ b/cmdline/src/main/resources/log4j2.xml @@ -6,7 +6,7 @@ - + From 8f1fd511986041f5029d318a965410193d61b51e Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 17:48:37 -0400 Subject: [PATCH 27/58] more logging --- .github/workflows/checks.yaml | 2 +- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index b3950828..da56af5d 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -172,7 +172,7 @@ jobs: --mime-type=text/plain \ --attr https://example.com/attr/attr1/value/value1 \ --autoconfigure=false -f data -m 'here is some metadata' > test.tdf - + ls -lh java \ 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 b30460eb..4cde3e6b 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -58,6 +58,8 @@ private static byte[] tdfECKeySaltCompute() { private final SDK.Services services; + private static final Logger LOG = LoggerFactory.getLogger(TDF.class); + /** * Constructs a new TDF instance using the default maximum input size defined by * MAX_TDF_INPUT_SIZE. @@ -296,6 +298,7 @@ public Manifest getManifest() { } public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMismatch, IOException { + LOG.info("about to read payload"); MessageDigest digest = null; try { @@ -321,6 +324,8 @@ public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMi var isLegacyTdf = manifest.tdfVersion == null || manifest.tdfVersion.isEmpty(); + LOG.info("reading a segment"); + if (manifest.payload.isEncrypted) { String segHashAlg = manifest.encryptionInformation.integrityInformation.segmentHashAlg; Config.IntegrityAlgorithm sigAlg = Config.IntegrityAlgorithm.HS256; @@ -349,6 +354,7 @@ public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMi outputStream.write(readBuf); } } + LOG.info("finished reading payload"); } public PolicyObject readPolicyObject() { From 36b71418ebcd9d461c78504b5178af54584884ea Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 17:53:38 -0400 Subject: [PATCH 28/58] ok --- .github/workflows/checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index da56af5d..6c343873 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -145,7 +145,7 @@ jobs: - name: Validate the SDK through the command line interface (FIPS) run: | - set -exuo pipefail + set -euo pipefail mvn dependency:copy -Dartifact=org.bouncycastle:bc-fips:2.1.2:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" From 6669843b5174dc394f3738b74c1fbb830574c3eb Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 18:06:47 -0400 Subject: [PATCH 29/58] more logging --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 2 ++ sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java | 6 ++++++ 2 files changed, 8 insertions(+) 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 4cde3e6b..26b8f3a0 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -551,7 +551,9 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) throws SDKException, IOException { TDFReader tdfReader = new TDFReader(tdf); + LOG.info("loaded the tdf reader"); String manifestJson = tdfReader.manifest(); + LOG.info("here is the manifest json {}", manifestJson); // use Manifest.readManifest in order to validate the Manifest input Manifest manifest = Manifest.readManifest(manifestJson); 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 6e9f32d2..70b3c731 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java @@ -1,5 +1,8 @@ package io.opentdf.platform.sdk; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -20,6 +23,7 @@ public class TDFReader { private final ZipReader.Entry manifestEntry; private final InputStream payload; + private static final Logger LOG = LoggerFactory.getLogger(TDFReader.class); public TDFReader(SeekableByteChannel tdf) throws SDKException, IOException { Map entries = new ZipReader(tdf).getEntries() @@ -35,6 +39,8 @@ public TDFReader(SeekableByteChannel tdf) throws SDKException, IOException { manifestEntry = entries.get(TDF_MANIFEST_FILE_NAME); payload = entries.get(TDF_PAYLOAD_FILE_NAME).getData(); + + LOG.info("Manifest found: {}", manifestEntry.getName()); } String manifest() { From da712ee437f83e3e9848035ef2f22d4eec822b73 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 18:17:18 -0400 Subject: [PATCH 30/58] more logging --- cmdline/src/main/java/io/opentdf/platform/Command.java | 5 ++++- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index dcfe26c4..5f994a91 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -18,6 +18,8 @@ import io.opentdf.platform.sdk.KeyType; import io.opentdf.platform.sdk.SDK; import io.opentdf.platform.sdk.SDKBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import picocli.CommandLine; import picocli.CommandLine.HelpCommand; import picocli.CommandLine.Option; @@ -61,7 +63,7 @@ class Versions { @CommandLine.Command(name = "tdf", subcommands = { HelpCommand.class }, version = "{\"version\":\"" + Versions.SDK + "\",\"tdfSpecVersion\":\"" + Versions.TDF_SPEC + "\"}") class Command { - + private static final Logger LOG = LoggerFactory.getLogger(Command.class); @Option(names = { "-V", "--version" }, versionHelp = true, description = "display version info") boolean versionInfoRequested; @@ -332,6 +334,7 @@ void decrypt( var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); var reader = sdk.loadTDF(in, readerConfig); + LOG.info("loaded the tdf"); reader.readPayload(stdout); } } 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 26b8f3a0..bab0a8ea 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -298,7 +298,6 @@ public Manifest getManifest() { } public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMismatch, IOException { - LOG.info("about to read payload"); MessageDigest digest = null; try { @@ -650,6 +649,7 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) } } + String rootSigValue; boolean isLegacyTdf = manifest.tdfVersion == null || manifest.tdfVersion.isEmpty(); if (manifest.payload.isEncrypted) { @@ -674,6 +674,8 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) rootSigValue = Base64.getEncoder().encodeToString(digest.digest(aggregateHash.toString().getBytes())); } + LOG.info("validated the signature"); + if (rootSignature.compareTo(rootSigValue) != 0) { throw new SDK.RootSignatureValidationException("root signature validation failed"); } @@ -736,6 +738,8 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) } } + LOG.info("returning payload reader"); + return new Reader(tdfReader, manifest, payloadKey, unencryptedMetadata); } } From 815be2aba21b3e3671201742b48df557afe2ca88 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 18:24:23 -0400 Subject: [PATCH 31/58] one more --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 4 +++- 1 file changed, 3 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 bab0a8ea..34a426c1 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -299,6 +299,7 @@ public Manifest getManifest() { public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMismatch, IOException { + LOG.info("Reading payload"); MessageDigest digest = null; try { digest = MessageDigest.getInstance("SHA-256"); @@ -307,6 +308,7 @@ public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMi } for (Manifest.Segment segment : manifest.encryptionInformation.integrityInformation.segments) { + LOG.info("reading a segment"); if (segment.encryptedSegmentSize > Config.MAX_SEGMENT_SIZE) { throw new IllegalStateException("Segment size " + segment.encryptedSegmentSize + " exceeded limit " + Config.MAX_SEGMENT_SIZE); @@ -323,7 +325,6 @@ public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMi var isLegacyTdf = manifest.tdfVersion == null || manifest.tdfVersion.isEmpty(); - LOG.info("reading a segment"); if (manifest.payload.isEncrypted) { String segHashAlg = manifest.encryptionInformation.integrityInformation.segmentHashAlg; @@ -352,6 +353,7 @@ public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMi outputStream.write(readBuf); } + LOG.info("read a segment"); } LOG.info("finished reading payload"); } From 3511f0224a2a798572e68a5630aa62173309cbd6 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Thu, 11 Jun 2026 18:30:25 -0400 Subject: [PATCH 32/58] one more log --- cmdline/src/main/java/io/opentdf/platform/Command.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 5f994a91..120556f1 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -333,6 +333,7 @@ void decrypt( kasAllowlistStr.ifPresent(s -> opts.add(Config.WithKasAllowlist(s.split(",")))); var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); + LOG.info("aboud to load the tdf"); var reader = sdk.loadTDF(in, readerConfig); LOG.info("loaded the tdf"); reader.readPayload(stdout); From fa5c26f818a159dcef3432d97b51b66424f417db Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 07:57:51 -0400 Subject: [PATCH 33/58] try changing the log level --- cmdline/src/main/resources/log4j2.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmdline/src/main/resources/log4j2.xml b/cmdline/src/main/resources/log4j2.xml index da185a60..51a5a102 100644 --- a/cmdline/src/main/resources/log4j2.xml +++ b/cmdline/src/main/resources/log4j2.xml @@ -6,9 +6,9 @@ - - - + + + From f3c811b5bf23a9219be107ad761871578beac2a1 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 08:06:28 -0400 Subject: [PATCH 34/58] more explicit logging --- cmdline/src/main/resources/log4j2.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmdline/src/main/resources/log4j2.xml b/cmdline/src/main/resources/log4j2.xml index 51a5a102..164424ef 100644 --- a/cmdline/src/main/resources/log4j2.xml +++ b/cmdline/src/main/resources/log4j2.xml @@ -9,6 +9,9 @@ + + + From 6dd35f2014ac792ca05d7e3e3772724a34d4ed5f Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 08:11:56 -0400 Subject: [PATCH 35/58] get some logs --- cmdline/src/main/java/io/opentdf/platform/Command.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 120556f1..2f99bf93 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -333,9 +333,9 @@ void decrypt( kasAllowlistStr.ifPresent(s -> opts.add(Config.WithKasAllowlist(s.split(",")))); var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); - LOG.info("aboud to load the tdf"); + System.err.println("about to do it"); var reader = sdk.loadTDF(in, readerConfig); - LOG.info("loaded the tdf"); + System.err.println("aboud to load the tdf"); reader.readPayload(stdout); } } From 32d7d423ad605ddbb78d75a16d3033a1f0c7c4e6 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 09:45:13 -0400 Subject: [PATCH 36/58] yikes --- .github/workflows/checks.yaml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 6c343873..5df37152 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -173,11 +173,9 @@ jobs: --attr https://example.com/attr/attr1/value/value1 \ --autoconfigure=false -f data -m 'here is some metadata' > test.tdf - ls -lh - java \ ${SECURITY_PROPERTIES} \ - -cp ${CP}" \ + -cp "${CP}" \ io.opentdf.platform.TDF \ --client-id=opentdf-sdk \ --client-secret=secret \ @@ -185,10 +183,6 @@ jobs: -h \ decrypt -f test.tdf > decrypted - cat decrypted - echo 'we decrypted it' - ls -l - java \ ${SECURITY_PROPERTIES} \ -cp ${CP}" \ From d24c1a904cf1b3507c39d03757d198ccae90bdfd Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 09:56:50 -0400 Subject: [PATCH 37/58] one more --- .github/workflows/checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 5df37152..b8e22d33 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -185,7 +185,7 @@ jobs: java \ ${SECURITY_PROPERTIES} \ - -cp ${CP}" \ + -cp "${CP}" \ io.opentdf.platform.TDF \ --client-id=opentdf-sdk \ --client-secret=secret \ From 54752b94bb6b77608f1f685d183a2e6cd66dc63f Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 10:37:55 -0400 Subject: [PATCH 38/58] just run it in FIPS mode all the time --- .github/workflows/checks.yaml | 64 +------------------ cmdline/pom.xml | 25 +++++--- .../java/io/opentdf/platform/Command.java | 2 - .../io/opentdf/platform/sdk/ECKeyPair.java | 9 +++ 4 files changed, 25 insertions(+), 75 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index b8e22d33..e3492793 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -123,13 +123,11 @@ jobs: - name: Build java SDK run: | - mvn --batch-mode clean install -P 'fips,!non-fips' -DskipTests + mvn --batch-mode clean install -pl cmdline -am -P 'fips,!non-fips' -DskipTests env: BUF_INPUT_HTTPS_USERNAME: opentdf-bot BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }} - - - name: Check out and start up platform with deps/containers id: run-platform uses: opentdf/platform/test/start-up-with-containers@main @@ -143,66 +141,6 @@ jobs: grpcurl -plaintext localhost:8080 list && \ grpcurl -plaintext localhost:8080 kas.AccessService/PublicKey - - name: Validate the SDK through the command line interface (FIPS) - run: | - set -euo pipefail - - mvn dependency:copy -Dartifact=org.bouncycastle:bc-fips:2.1.2:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" - mvn dependency:copy -Dartifact=org.bouncycastle:bcutil-fips:2.1.6:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" - mvn dependency:copy -Dartifact=org.bouncycastle:bctls-fips:2.1.23:jar -Dmdep.stripVersion=true -DoutputDirectory="${GITHUB_WORKSPACE}" - - CP="sdk-fips-bouncycastle/target/*:cmdline/target/cmdline.jar" - CP="${CP}:bc-fips.jar" - CP="${CP}:bcutil-fips.jar" - CP="${CP}:bctls-fips.jar" - - SECURITY_PROPERTIES="-Djava.security.properties==${GITHUB_WORKSPACE}/sdk/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${GITHUB_WORKSPACE}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS" - - printf 'here is some data to encrypt' > data - - java ${SECURITY_PROPERTIES} \ - -cp "${CP}" \ - io.opentdf.platform.TDF \ - --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 \ - ${SECURITY_PROPERTIES} \ - -cp "${CP}" \ - io.opentdf.platform.TDF \ - --client-id=opentdf-sdk \ - --client-secret=secret \ - --platform-endpoint=http://localhost:8080 \ - -h \ - decrypt -f test.tdf > decrypted - - java \ - ${SECURITY_PROPERTIES} \ - -cp "${CP}" \ - io.opentdf.platform.TDF \ - --client-id=opentdf-sdk \ - --client-secret=secret \ - --platform-endpoint=http://localhost:8080 \ - -h\ - metadata -f test.tdf > metadata - - if ! diff -q data decrypted; then - printf 'decrypted data is incorrect [%s]' "$(< decrypted)" - exit 1 - fi - - if [ "$(< metadata)" != 'here is some metadata' ]; then - printf 'metadata is incorrect [%s]\n' "$(< metadata)" - exit 1 - fi - - name: Validate the SDK through the command line interface run: | printf 'here is some data to encrypt' > data diff --git a/cmdline/pom.xml b/cmdline/pom.xml index 91046f3b..b7061f0a 100644 --- a/cmdline/pom.xml +++ b/cmdline/pom.xml @@ -76,16 +76,21 @@ io.opentdf.platform sdk ${project.version} - - - org.bouncycastle - bc-fips - - - org.bouncycastle - bctls-fips - - + + + fips + + false + + + + io.opentdf.platform + sdk-fips-bouncycastle + ${project.version} + + + + diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 2f99bf93..948d0a6a 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -333,9 +333,7 @@ void decrypt( kasAllowlistStr.ifPresent(s -> opts.add(Config.WithKasAllowlist(s.split(",")))); var readerConfig = Config.newTDFReaderConfig(opts.toArray(new Consumer[0])); - System.err.println("about to do it"); var reader = sdk.loadTDF(in, readerConfig); - System.err.println("aboud to load the tdf"); reader.readPayload(stdout); } } diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java index 03f788c7..36bc6934 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java @@ -1,5 +1,8 @@ package io.opentdf.platform.sdk; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import javax.crypto.KeyAgreement; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -26,6 +29,7 @@ public class ECKeyPair { private static final int SHA256_BYTES = 32; private static final String EC_ALGORITHM = "EC"; + private static final Logger log = LoggerFactory.getLogger(ECKeyPair.class); private final ECCurve curve; @@ -114,8 +118,13 @@ public static byte[] computeECDHKey(ECPublicKey publicKey, ECPrivateKey privateK public static byte[] calculateHKDF(byte[] salt, byte[] secret) { HkdfProvider provider = HkdfResolver.get(); if (provider != null) { + if (log.isDebugEnabled()) { + log.debug("Using resolved HKDF provider of type {}", provider.getClass().getName()); + } return provider.computeHKDF(salt, secret); } + + log.debug("using SDK HKDF implementation"); try { // RFC 5869: if salt is absent, substitute a zero-filled buffer of Hash output size. byte[] effectiveSalt = (salt == null || salt.length == 0) ? new byte[SHA256_BYTES] : salt; From b5e820f1746b1add280c5a63a8d2833a2c421786 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 11:05:55 -0400 Subject: [PATCH 39/58] sonarcloud --- .../main/java/io/opentdf/platform/sdk/HkdfResolver.java | 9 +++------ .../test/java/io/opentdf/platform/sdk/ECKeyPairTest.java | 4 ---- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/HkdfResolver.java b/sdk/src/main/java/io/opentdf/platform/sdk/HkdfResolver.java index 140bb458..45c99fc4 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/HkdfResolver.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/HkdfResolver.java @@ -15,12 +15,9 @@ private static final class Holder { static final HkdfProvider PROVIDER = load(); private static HkdfProvider load() { - for (HkdfProvider p : ServiceLoader.load( - HkdfProvider.class, - HkdfResolver.class.getClassLoader())) { - return p; - } - return null; + return ServiceLoader.load(HkdfProvider.class, HkdfResolver.class.getClassLoader()) + .findFirst() + .orElse(null); } } diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java index 9c0f2f44..8f4b6987 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java @@ -3,15 +3,11 @@ import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIfSystemProperty; -import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.*; -import java.security.cert.CertificateException; -import java.security.spec.InvalidKeySpecException; import java.util.Arrays; import java.util.Base64; From 5b07fa8723d148d5a222a7ccf2215c8f0516f85d Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 12:22:31 -0400 Subject: [PATCH 40/58] fix mvnverify --- .github/workflows/checks.yaml | 4 ++ .../BouncyCastleFipsHkdfProviderTest.java | 11 ------ sdk/pom.xml | 15 ++++++++ .../opentdf/platform/sdk/ECKeyPairTest.java | 3 -- .../sdk/FipsProviderVerificationTest.java | 37 +++++++++++++------ 5 files changed, 44 insertions(+), 26 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index e3492793..cca78ef7 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -93,6 +93,10 @@ jobs: run: mvn clean --batch-mode clean generate-sources - name: Tests and enforcer (fips) run: | + # install the the sdk-fips-bouncycastle jar so that FIPS mode tests work + mvn --batch mode install -pl sdk-fips-bouncycastle -am \ + -Dmaven.antrun.skip \ + -Dmaven.test.skip mvn --batch-mode test enforcer:enforce -P 'fips,!non-fips' \ -Dmaven.antrun.skip \ -Dorg.bouncycastle.fips.approved_only=true diff --git a/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java b/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java index ce180520..8e513ecf 100644 --- a/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java +++ b/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java @@ -30,15 +30,4 @@ void computeHKDF_isDeterministic() { assertThat(first).isEqualTo(second); } - - @Test - void computeHKDF_matchesJdkFallback() { - byte[] salt = "ECKeysSalt".getBytes(StandardCharsets.UTF_8); - byte[] secret = new byte[32]; // simulated shared secret - - byte[] fipsResult = provider.computeHKDF(salt, secret); - byte[] jdkResult = io.opentdf.platform.sdk.ECKeyPair.calculateHKDF(salt, secret); - - assertThat(fipsResult).isEqualTo(jdkResult); - } } diff --git a/sdk/pom.xml b/sdk/pom.xml index 240e0d63..e11eddd3 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -498,6 +498,21 @@ -Djava.security.properties==${project.basedir}/src/test/resources/java.security.fips.test -Dorg.bouncycastle.fips.approved_only=true -Djavax.net.ssl.trustStore=${project.basedir}/src/test/resources/empty-fips-truststore.bcfks -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=BCFKS + + + + org.apache.maven.plugins + maven-surefire-plugin + + + + ${project.basedir}/../sdk-fips-bouncycastle/target/sdk-fips-bouncycastle-${project.version}jar + + + + + org.bouncycastle diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java index 8f4b6987..df3f79f5 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java @@ -83,7 +83,6 @@ void ecPublicKeyInPemformat() { } @Test - @DisabledIfSystemProperty(named = "org.bouncycastle.fips.approved_only", matches = "true") void extractPemPubKeyFromX509() { String x509ECPubKey = "-----BEGIN CERTIFICATE-----\n" + "MIIBCzCBsgIJAK3Uxk7fP5oWMAoGCCqGSM49BAMCMA4xDDAKBgNVBAMMA2thczAe\n" + @@ -122,7 +121,6 @@ void extractPemPubKeyFromX509() { } @Test - @DisabledIfSystemProperty(named = "org.bouncycastle.fips.approved_only", matches = "true") void createSymmetricKeysWithOtherCurves() { ECKeyPair pubPair = new ECKeyPair(ECCurve.SECP384R1); ECKeyPair keyPair = new ECKeyPair(ECCurve.SECP384R1); @@ -134,7 +132,6 @@ void createSymmetricKeysWithOtherCurves() { } @Test - @DisabledIfSystemProperty(named = "org.bouncycastle.fips.approved_only", matches = "true") void testECDH() { String expectedKey = "3KGgsptHbTsbxJtql6sHUcx255KcUhxdeJWKjmPMlcc="; diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/FipsProviderVerificationTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/FipsProviderVerificationTest.java index b269ddb0..c86a6082 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/FipsProviderVerificationTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/FipsProviderVerificationTest.java @@ -5,7 +5,7 @@ import java.security.Security; -import static org.junit.jupiter.api.Assertions.*; +import static org.assertj.core.api.Assertions.assertThat; /** * Verifies that the java.security.fips.test properties file was actually loaded when running @@ -18,28 +18,41 @@ class FipsProviderVerificationTest { @Test void bcFipsIsFirstProvider() { var providers = Security.getProviders(); - assertNotNull(providers, "No security providers registered"); - assertTrue(providers.length > 0, "Provider list is empty"); - assertEquals("BCFIPS", providers[0].getName(), - "Expected BCFIPS as the first security provider but got: " + providers[0].getName() - + " — the java.security.fips.test file was likely not loaded"); + assertThat(providers) + .as("No security providers registered") + .isNotNull() + .isNotEmpty(); + assertThat(providers[0].getName()) + .as("Expected BCFIPS as the first security provider but got: %s - the java.security.fips.test file was likely not loaded", + providers[0].getName()) + .isEqualTo("BCFIPS"); } @Test void bcJsseIsRegistered() { - assertNotNull(Security.getProvider("BCJSSE"), - "BCJSSE provider is not registered — the java.security.fips.test file was likely not loaded"); + assertThat(Security.getProvider("BCJSSE")) + .as("BCJSSE provider is not registered - the java.security.fips.test file was likely not loaded") + .isNotNull(); } @Test void sunJceIsNotRegistered() { - assertNull(Security.getProvider("SunJCE"), - "SunJCE provider is still registered — it should have been removed by java.security.fips.test"); + assertThat(Security.getProvider("SunJCE")) + .as("SunJCE provider is still registered - it should have been removed by java.security.fips.test") + .isNull(); } @Test void keyManagerFactoryAlgorithmIsPkix() { - assertEquals("PKIX", Security.getProperty("ssl.KeyManagerFactory.algorithm"), - "ssl.KeyManagerFactory.algorithm was not overridden to PKIX — the java.security.fips.test file was likely not loaded"); + assertThat(Security.getProperty("ssl.KeyManagerFactory.algorithm")) + .as("ssl.KeyManagerFactory.algorithm was not overridden to PKIX - the java.security.fips.test file was likely not loaded") + .isEqualTo("PKIX"); + } + + @Test + void providerResolves() { + assertThat(HkdfResolver.get()) + .as("the sdk-fips-bouncycastle library must be on the path so that the Hkdf provider resolves. this is configured in the surefire plugin and the sdk-fips-bouncycastle project must be packaged") + .isNotNull(); } } From 887ba9df288e4d13e0f484758ae531c09b96dfa4 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 13:33:51 -0400 Subject: [PATCH 41/58] refer to the module in a simpler way --- .github/workflows/checks.yaml | 2 +- pom.xml | 2 +- sdk/pom.xml | 10 +++++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index cca78ef7..da9f6587 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -94,7 +94,7 @@ jobs: - name: Tests and enforcer (fips) run: | # install the the sdk-fips-bouncycastle jar so that FIPS mode tests work - mvn --batch mode install -pl sdk-fips-bouncycastle -am \ + mvn --batch-mode install -pl sdk-fips-bouncycastle -am \ -Dmaven.antrun.skip \ -Dmaven.test.skip mvn --batch-mode test enforcer:enforce -P 'fips,!non-fips' \ diff --git a/pom.xml b/pom.xml index 482b05e8..4323ef13 100644 --- a/pom.xml +++ b/pom.xml @@ -181,7 +181,7 @@ maven-surefire-plugin - 3.0.0 + 3.5.6 maven-jar-plugin diff --git a/sdk/pom.xml b/sdk/pom.xml index e11eddd3..e269c85e 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -506,9 +506,13 @@ - - ${project.basedir}/../sdk-fips-bouncycastle/target/sdk-fips-bouncycastle-${project.version}jar - + + + io.opentdf.platform + sdk-fips-bouncycastle + ${project.version} + + From d7621b7ef237aae638dd349a97cfe132976355bb Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 13:58:45 -0400 Subject: [PATCH 42/58] refactor scripts some --- .github/scripts/verify_assertions_basic.sh | 34 +++++ .github/scripts/verify_assertions_hs256.sh | 36 ++++++ .github/scripts/verify_assertions_rs256.sh | 41 ++++++ .github/scripts/verify_cmdline_roundtrip.sh | 44 +++++++ .github/workflows/checks.yaml | 135 +++----------------- 5 files changed, 175 insertions(+), 115 deletions(-) create mode 100755 .github/scripts/verify_assertions_basic.sh create mode 100755 .github/scripts/verify_assertions_hs256.sh create mode 100755 .github/scripts/verify_assertions_rs256.sh create mode 100644 .github/scripts/verify_cmdline_roundtrip.sh diff --git a/.github/scripts/verify_assertions_basic.sh b/.github/scripts/verify_assertions_basic.sh new file mode 100755 index 00000000..51a472b4 --- /dev/null +++ b/.github/scripts/verify_assertions_basic.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "basic assertions" +printf 'here is some data to encrypt' > data + +ASSERTIONS='[{"id":"assertion1","type":"handling","scope":"tdo","appliesToState":"encrypted","statement":{"format":"json+stanag5636","schema":"urn:nato:stanag:5636:A:1:elements:json","value":"{\"ocl\":\"2024-10-21T20:47:36Z\"}"}}]' + +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 \ + --with-assertions="$ASSERTIONS" \ + --autoconfigure=false \ + -f data \ + -m 'here is some metadata' > test.tdf + +java -jar target/cmdline.jar \ + --client-id=opentdf-sdk \ + --client-secret=secret \ + --platform-endpoint=http://localhost:8080 \ + -h \ + decrypt \ + -f test.tdf > decrypted + +if ! diff -q data decrypted; then + printf 'decrypted data is incorrect [%s]\n' "$(< decrypted)" + exit 1 +fi + diff --git a/.github/scripts/verify_assertions_hs256.sh b/.github/scripts/verify_assertions_hs256.sh new file mode 100755 index 00000000..65f01007 --- /dev/null +++ b/.github/scripts/verify_assertions_hs256.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "hs256 assertions" +printf 'here is some data to encrypt' > data + +HS256_KEY=$(openssl rand -base64 32) +SIGNED_ASSERTIONS_HS256='[{"id":"assertion1","type":"handling","scope":"tdo","appliesToState":"encrypted","statement":{"format":"json+stanag5636","schema":"urn:nato:stanag:5636:A:1:elements:json","value":"{\"ocl\":\"2024-10-21T20:47:36Z\"}"},"signingKey":{"alg":"HS256","key":"'"$HS256_KEY"'"}}]' +SIGNED_ASSERTION_VERIFICATON_HS256='{"keys":{"assertion1":{"alg":"HS256","key":"'"$HS256_KEY"'"}}}' + +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 \ + --with-assertions="$SIGNED_ASSERTIONS_HS256" \ + --autoconfigure=false \ + -f data \ + -m 'here is some metadata' > test.tdf + +java -jar target/cmdline.jar \ + --client-id=opentdf-sdk \ + --client-secret=secret \ + --platform-endpoint=http://localhost:8080 \ + -h \ + decrypt \ + --with-assertion-verification-keys="$SIGNED_ASSERTION_VERIFICATON_HS256" \ + -f test.tdf > decrypted + +if ! diff -q data decrypted; then + printf 'decrypted data is incorrect [%s]\n' "$(< decrypted)" + exit 1 +fi diff --git a/.github/scripts/verify_assertions_rs256.sh b/.github/scripts/verify_assertions_rs256.sh new file mode 100755 index 00000000..52d964a1 --- /dev/null +++ b/.github/scripts/verify_assertions_rs256.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -euo pipefail + +echo "rs256 assertions" +printf 'here is some data to encrypt' > data + +openssl genpkey -algorithm RSA -out rs_private_key.pem -pkeyopt rsa_keygen_bits:2048 +openssl rsa -pubout -in rs_private_key.pem -out rs_public_key.pem + +RS256_PRIVATE_KEY=$(awk '{printf "%s\\n", $0}' rs_private_key.pem) +RS256_PUBLIC_KEY=$(awk '{printf "%s\\n", $0}' rs_public_key.pem) +SIGNED_ASSERTIONS_RS256='[{"id":"assertion1","type":"handling","scope":"tdo","appliesToState":"encrypted","statement":{"format":"json+stanag5636","schema":"urn:nato:stanag:5636:A:1:elements:json","value":"{\"ocl\":\"2024-10-21T20:47:36Z\"}"},"signingKey":{"alg":"RS256","key":"'"$RS256_PRIVATE_KEY"'"}}]' +SIGNED_ASSERTION_VERIFICATON_RS256='{"keys":{"assertion1":{"alg":"RS256","key":"'"$RS256_PUBLIC_KEY"'"}}}' + +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 \ + --with-assertions "$SIGNED_ASSERTIONS_RS256" \ + --autoconfigure=false \ + -f data \ + -m 'here is some metadata' > test.tdf + +java -jar target/cmdline.jar \ + --client-id=opentdf-sdk \ + --client-secret=secret \ + --platform-endpoint=http://localhost:8080 \ + -h \ + decrypt \ + --with-assertion-verification-keys "$SIGNED_ASSERTION_VERIFICATON_RS256" \ + -f test.tdf > decrypted + +if ! diff -q data decrypted; then + printf 'decrypted data is incorrect [%s]\n' "$(< decrypted)" + exit 1 +fi + diff --git a/.github/scripts/verify_cmdline_roundtrip.sh b/.github/scripts/verify_cmdline_roundtrip.sh new file mode 100644 index 00000000..6ce47fd5 --- /dev/null +++ b/.github/scripts/verify_cmdline_roundtrip.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -euo pipefail + +printf 'here is some data to encrypt' > data + +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 -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 \ + --client-id=opentdf-sdk \ + --client-secret=secret \ + --platform-endpoint=http://localhost:8080 \ + -h \ + metadata \ + -f test.tdf > metadata + +if ! diff -q data decrypted; then + printf 'decrypted data is incorrect [%s]\n' "$(< decrypted)" + exit 1 +fi + +if [ "$(< metadata)" != 'here is some metadata' ]; then + printf 'metadata is incorrect [%s]\n' "$(< metadata)" + exit 1 +fi + diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index da9f6587..123f86b7 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -112,6 +112,13 @@ jobs: platform-integration: runs-on: ubuntu-22.04 + strategy: + matrix: + include: + - label: "" + maven_profile: "" + - label: " (FIPS)" + maven_profile: "-P 'fips,!non-fips'" steps: - name: Checkout Java SDK uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 @@ -125,13 +132,6 @@ jobs: distribution: "temurin" server-id: github - - name: Build java SDK - run: | - mvn --batch-mode clean install -pl cmdline -am -P 'fips,!non-fips' -DskipTests - env: - BUF_INPUT_HTTPS_USERNAME: opentdf-bot - BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }} - - name: Check out and start up platform with deps/containers id: run-platform uses: opentdf/platform/test/start-up-with-containers@main @@ -145,121 +145,26 @@ jobs: grpcurl -plaintext localhost:8080 list && \ grpcurl -plaintext localhost:8080 kas.AccessService/PublicKey - - name: Validate the SDK through the command line interface + - name: Build java SDK${{ matrix.label }} run: | - printf 'here is some data to encrypt' > data - - 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 -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 \ - --client-id=opentdf-sdk \ - --client-secret=secret \ - --platform-endpoint=http://localhost:8080 \ - -h\ - metadata -f test.tdf > metadata - - if ! diff -q data decrypted; then - printf 'decrypted data is incorrect [%s]' "$(< decrypted)" - exit 1 - fi + mvn --batch-mode clean install -pl cmdline -am ${{ matrix.maven_profile }} -DskipTests + env: + BUF_INPUT_HTTPS_USERNAME: opentdf-bot + BUF_INPUT_HTTPS_PASSWORD: ${{ secrets.PERSONAL_ACCESS_TOKEN_OPENTDF }} - if [ "$(< metadata)" != 'here is some metadata' ]; then - printf 'metadata is incorrect [%s]\n' "$(< metadata)" - exit 1 - fi + - name: Validate the SDK through the command line interface${{ matrix.label }} + run: | + ../.github/scripts/verify_cmdline_roundtrip.sh working-directory: cmdline - - name: Encrypt/Decrypt Assertions + - name: Encrypt/Decrypt Assertions${{ matrix.label }} run: | - echo "basic assertions" - echo 'here is some data to encrypt' > data - - ASSERTIONS='[{"id":"assertion1","type":"handling","scope":"tdo","appliesToState":"encrypted","statement":{"format":"json+stanag5636","schema":"urn:nato:stanag:5636:A:1:elements:json","value":"{\"ocl\":\"2024-10-21T20:47:36Z\"}"}}]' - - 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 --with-assertions=$ASSERTIONS --autoconfigure=false -f data -m 'here is some metadata' > test.tdf - - java -jar target/cmdline.jar \ - --client-id=opentdf-sdk \ - --client-secret=secret \ - --platform-endpoint=http://localhost:8080 \ - -h\ - decrypt -f test.tdf > decrypted - - if ! diff -q data decrypted; then - printf 'decrypted data is incorrect [%s]' "$(< decrypted)" - exit 1 - fi - - HS256_KEY=$(openssl rand -base64 32) - openssl genpkey -algorithm RSA -out rs_private_key.pem -pkeyopt rsa_keygen_bits:2048 - openssl rsa -pubout -in rs_private_key.pem -out rs_public_key.pem - RS256_PRIVATE_KEY=$(awk '{printf "%s\\n", $0}' rs_private_key.pem) - RS256_PUBLIC_KEY=$(awk '{printf "%s\\n", $0}' rs_public_key.pem) - SIGNED_ASSERTIONS_HS256='[{"id":"assertion1","type":"handling","scope":"tdo","appliesToState":"encrypted","statement":{"format":"json+stanag5636","schema":"urn:nato:stanag:5636:A:1:elements:json","value":"{\"ocl\":\"2024-10-21T20:47:36Z\"}"},"signingKey":{"alg":"HS256","key":"'$HS256_KEY'"}}]' - SIGNED_ASSERTION_VERIFICATON_HS256='{"keys":{"assertion1":{"alg":"HS256","key":"'$HS256_KEY'"}}}' - SIGNED_ASSERTIONS_RS256='[{"id":"assertion1","type":"handling","scope":"tdo","appliesToState":"encrypted","statement":{"format":"json+stanag5636","schema":"urn:nato:stanag:5636:A:1:elements:json","value":"{\"ocl\":\"2024-10-21T20:47:36Z\"}"},"signingKey":{"alg":"RS256","key":"'$RS256_PRIVATE_KEY'"}}]' - SIGNED_ASSERTION_VERIFICATON_RS256='{"keys":{"assertion1":{"alg":"RS256","key":"'$RS256_PUBLIC_KEY'"}}}' - - echo "hs256 assertions" - - 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 --with-assertions="$SIGNED_ASSERTIONS_HS256" --autoconfigure=false -f data -m 'here is some metadata' > test.tdf - - java -jar target/cmdline.jar \ - --client-id=opentdf-sdk \ - --client-secret=secret \ - --platform-endpoint=http://localhost:8080 \ - -h\ - decrypt --with-assertion-verification-keys="$SIGNED_ASSERTION_VERIFICATON_HS256" -f test.tdf > decrypted - - if ! diff -q data decrypted; then - printf 'decrypted data is incorrect [%s]' "$(< decrypted)" - exit 1 - fi - - echo "rs256 assertions" - - 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 --with-assertions "$SIGNED_ASSERTIONS_RS256" --autoconfigure=false -f data -m 'here is some metadata' > test.tdf - - java -jar target/cmdline.jar \ - --client-id=opentdf-sdk \ - --client-secret=secret \ - --platform-endpoint=http://localhost:8080 \ - -h\ - decrypt --with-assertion-verification-keys "$SIGNED_ASSERTION_VERIFICATON_RS256" -f test.tdf > decrypted - - if ! diff -q data decrypted; then - printf 'decrypted data is incorrect [%s]' "$(< decrypted)" - exit 1 - fi + ../.github/scripts/verify_assertions_basic.sh + ../.github/scripts/verify_assertions_hs256.sh + ../.github/scripts/verify_assertions_rs256.sh working-directory: cmdline + platform-xtest: permissions: contents: read From 2a8bd54a17acce7d8494539cd985f6adb7721e7a Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 14:03:35 -0400 Subject: [PATCH 43/58] update permissions --- .github/scripts/verify_cmdline_roundtrip.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 .github/scripts/verify_cmdline_roundtrip.sh diff --git a/.github/scripts/verify_cmdline_roundtrip.sh b/.github/scripts/verify_cmdline_roundtrip.sh old mode 100644 new mode 100755 From 9369d07eecab181c6ace088ef5a6281108d55821 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 14:09:57 -0400 Subject: [PATCH 44/58] Update TDFReader.java --- sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java | 5 ----- 1 file changed, 5 deletions(-) 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 70b3c731..33e329fa 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java @@ -1,8 +1,5 @@ package io.opentdf.platform.sdk; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -39,8 +36,6 @@ public TDFReader(SeekableByteChannel tdf) throws SDKException, IOException { manifestEntry = entries.get(TDF_MANIFEST_FILE_NAME); payload = entries.get(TDF_PAYLOAD_FILE_NAME).getData(); - - LOG.info("Manifest found: {}", manifestEntry.getName()); } String manifest() { From 46d1d87e63abce81a744019d94e206faa449dc64 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 14:10:17 -0400 Subject: [PATCH 45/58] Remove static logger from TDFReader Removed static logger initialization from TDFReader class. --- sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java | 1 - 1 file changed, 1 deletion(-) 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 33e329fa..6e9f32d2 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDFReader.java @@ -20,7 +20,6 @@ public class TDFReader { private final ZipReader.Entry manifestEntry; private final InputStream payload; - private static final Logger LOG = LoggerFactory.getLogger(TDFReader.class); public TDFReader(SeekableByteChannel tdf) throws SDKException, IOException { Map entries = new ZipReader(tdf).getEntries() From baee6113177ac11b4433b210d490d1bd904b8aaf Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 14:11:22 -0400 Subject: [PATCH 46/58] Update log4j2.xml --- cmdline/src/main/resources/log4j2.xml | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmdline/src/main/resources/log4j2.xml b/cmdline/src/main/resources/log4j2.xml index 164424ef..51a5a102 100644 --- a/cmdline/src/main/resources/log4j2.xml +++ b/cmdline/src/main/resources/log4j2.xml @@ -9,9 +9,6 @@ - - - From 9d21147d47383ea66f1a559e7395495955c7c002 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 14:12:50 -0400 Subject: [PATCH 47/58] Update TDF.java --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 12 ------------ 1 file changed, 12 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 34a426c1..66e26d5b 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -58,8 +58,6 @@ private static byte[] tdfECKeySaltCompute() { private final SDK.Services services; - private static final Logger LOG = LoggerFactory.getLogger(TDF.class); - /** * Constructs a new TDF instance using the default maximum input size defined by * MAX_TDF_INPUT_SIZE. @@ -299,7 +297,6 @@ public Manifest getManifest() { public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMismatch, IOException { - LOG.info("Reading payload"); MessageDigest digest = null; try { digest = MessageDigest.getInstance("SHA-256"); @@ -308,7 +305,6 @@ public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMi } for (Manifest.Segment segment : manifest.encryptionInformation.integrityInformation.segments) { - LOG.info("reading a segment"); if (segment.encryptedSegmentSize > Config.MAX_SEGMENT_SIZE) { throw new IllegalStateException("Segment size " + segment.encryptedSegmentSize + " exceeded limit " + Config.MAX_SEGMENT_SIZE); @@ -353,9 +349,7 @@ public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMi outputStream.write(readBuf); } - LOG.info("read a segment"); } - LOG.info("finished reading payload"); } public PolicyObject readPolicyObject() { @@ -552,9 +546,7 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig, Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) throws SDKException, IOException { TDFReader tdfReader = new TDFReader(tdf); - LOG.info("loaded the tdf reader"); String manifestJson = tdfReader.manifest(); - LOG.info("here is the manifest json {}", manifestJson); // use Manifest.readManifest in order to validate the Manifest input Manifest manifest = Manifest.readManifest(manifestJson); @@ -676,8 +668,6 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) rootSigValue = Base64.getEncoder().encodeToString(digest.digest(aggregateHash.toString().getBytes())); } - LOG.info("validated the signature"); - if (rootSignature.compareTo(rootSigValue) != 0) { throw new SDK.RootSignatureValidationException("root signature validation failed"); } @@ -740,8 +730,6 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) } } - LOG.info("returning payload reader"); - return new Reader(tdfReader, manifest, payloadKey, unencryptedMetadata); } } From a8c39b464118b95bf64106d29b2e8dcb10546e93 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 14:13:33 -0400 Subject: [PATCH 48/58] Remove blank lines in TDF.java Removed unnecessary blank lines for cleaner code. --- sdk/src/main/java/io/opentdf/platform/sdk/TDF.java | 2 -- 1 file changed, 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 66e26d5b..b30460eb 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/TDF.java @@ -321,7 +321,6 @@ public void readPayload(OutputStream outputStream) throws SDK.SegmentSignatureMi var isLegacyTdf = manifest.tdfVersion == null || manifest.tdfVersion.isEmpty(); - if (manifest.payload.isEncrypted) { String segHashAlg = manifest.encryptionInformation.integrityInformation.segmentHashAlg; Config.IntegrityAlgorithm sigAlg = Config.IntegrityAlgorithm.HS256; @@ -643,7 +642,6 @@ Reader loadTDF(SeekableByteChannel tdf, Config.TDFReaderConfig tdfReaderConfig) } } - String rootSigValue; boolean isLegacyTdf = manifest.tdfVersion == null || manifest.tdfVersion.isEmpty(); if (manifest.payload.isEncrypted) { From 517bd278b4f6d5aa845d23e3379365e817f66489 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Fri, 12 Jun 2026 14:40:16 -0400 Subject: [PATCH 49/58] fix label --- .github/workflows/checks.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 123f86b7..0ae21193 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -111,6 +111,7 @@ jobs: -P 'coverage,non-fips,!fips' platform-integration: + name: "Platform Integration ${{ matrix.label }}" runs-on: ubuntu-22.04 strategy: matrix: From 16301f34a8b4b342800d85d5b870f3ead219997d Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Sun, 14 Jun 2026 06:22:41 -0400 Subject: [PATCH 50/58] sonarcloud --- sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java index df3f79f5..a49bb724 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java @@ -4,10 +4,8 @@ import java.security.interfaces.ECPublicKey; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.DisabledIfSystemProperty; import java.nio.charset.StandardCharsets; -import java.security.*; import java.util.Arrays; import java.util.Base64; From 5522ff278f9d99e1c57b6fc5e891c536e9000757 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 15 Jun 2026 10:12:29 -0400 Subject: [PATCH 51/58] Update checks.yaml --- .github/workflows/checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 0ae21193..1773e92d 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -93,7 +93,7 @@ jobs: run: mvn clean --batch-mode clean generate-sources - name: Tests and enforcer (fips) run: | - # install the the sdk-fips-bouncycastle jar so that FIPS mode tests work + # install the sdk-fips-bouncycastle jar so that FIPS mode tests work mvn --batch-mode install -pl sdk-fips-bouncycastle -am \ -Dmaven.antrun.skip \ -Dmaven.test.skip From 40b9050f699099eb551fecd7b96bd5c8f6753aa0 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 15 Jun 2026 10:20:53 -0400 Subject: [PATCH 52/58] publish the JAR --- sdk-fips-bouncycastle/pom.xml | 29 +++++++++++++++++++++++++++++ sdk/pom.xml | 1 - 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/sdk-fips-bouncycastle/pom.xml b/sdk-fips-bouncycastle/pom.xml index 385c2ecd..1cd4df8b 100644 --- a/sdk-fips-bouncycastle/pom.xml +++ b/sdk-fips-bouncycastle/pom.xml @@ -39,4 +39,33 @@ test + + + + + org.sonatype.central + central-publishing-maven-plugin + 0.6.0 + true + + true + published + + central + + + + + org.apache.maven.plugins + maven-deploy-plugin + 3.1.2 + + + default-deploy + none + + + + + diff --git a/sdk/pom.xml b/sdk/pom.xml index e269c85e..c8ffddaa 100644 --- a/sdk/pom.xml +++ b/sdk/pom.xml @@ -420,7 +420,6 @@ src/main/kotlin - target/generated-sources From 07a85770000142afc1a1d3e2adda14e44795f907 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 15 Jun 2026 14:15:39 -0400 Subject: [PATCH 53/58] Delete sdk/src/test/resources/empty-fips-truststore.p12 --- sdk/src/test/resources/empty-fips-truststore.p12 | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 sdk/src/test/resources/empty-fips-truststore.p12 diff --git a/sdk/src/test/resources/empty-fips-truststore.p12 b/sdk/src/test/resources/empty-fips-truststore.p12 deleted file mode 100644 index e69de29b..00000000 From fce41f12e59aeb38517c07461bb7f05350c8aefa Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Mon, 15 Jun 2026 14:18:05 -0400 Subject: [PATCH 54/58] Remove unused Logger imports Removed unused Logger imports from Command.java --- cmdline/src/main/java/io/opentdf/platform/Command.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cmdline/src/main/java/io/opentdf/platform/Command.java b/cmdline/src/main/java/io/opentdf/platform/Command.java index 948d0a6a..af9b2b1c 100644 --- a/cmdline/src/main/java/io/opentdf/platform/Command.java +++ b/cmdline/src/main/java/io/opentdf/platform/Command.java @@ -18,8 +18,6 @@ import io.opentdf.platform.sdk.KeyType; import io.opentdf.platform.sdk.SDK; import io.opentdf.platform.sdk.SDKBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import picocli.CommandLine; import picocli.CommandLine.HelpCommand; import picocli.CommandLine.Option; @@ -63,7 +61,6 @@ class Versions { @CommandLine.Command(name = "tdf", subcommands = { HelpCommand.class }, version = "{\"version\":\"" + Versions.SDK + "\",\"tdfSpecVersion\":\"" + Versions.TDF_SPEC + "\"}") class Command { - private static final Logger LOG = LoggerFactory.getLogger(Command.class); @Option(names = { "-V", "--version" }, versionHelp = true, description = "display version info") boolean versionInfoRequested; @@ -207,7 +204,6 @@ void encrypt( return ki; }).toArray(Config.KASInfo[]::new); - List> configs = new ArrayList<>(); configs.add(Config.withKasInformation(kasInfos)); metadata.map(Config::withMetaData).ifPresent(configs::add); From 1e1c214c9f3701457fa77ebdaa244443b4b904d3 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Tue, 16 Jun 2026 23:10:17 -0400 Subject: [PATCH 55/58] make implementations consistent --- .../BouncyCastleFipsHkdfProvider.java | 7 ++++- .../BouncyCastleFipsHkdfProviderTest.java | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/sdk-fips-bouncycastle/src/main/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProvider.java b/sdk-fips-bouncycastle/src/main/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProvider.java index c07898b0..6e7c734c 100644 --- a/sdk-fips-bouncycastle/src/main/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProvider.java +++ b/sdk-fips-bouncycastle/src/main/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProvider.java @@ -12,9 +12,14 @@ public final class BouncyCastleFipsHkdfProvider implements HkdfProvider { @Override public byte[] computeHKDF(byte[] salt, byte[] secret) { + if (secret == null) { + throw new NullPointerException("secret must not be null"); + } + // RFC 5869 §2.2: if salt is absent, use a zeroed buffer of HashLen bytes. + byte[] effectiveSalt = (salt == null || salt.length == 0) ? new byte[32] : salt; var key = FipsKDF.HKDF_KEY_BUILDER .withPrf(FipsKDF.AgreementKDFPRF.SHA256_HMAC) - .withSalt(salt) + .withSalt(effectiveSalt) .build(secret); var factory = new FipsKDF.AgreementOperatorFactory(); diff --git a/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java b/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java index 8e513ecf..95b98fcc 100644 --- a/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java +++ b/sdk-fips-bouncycastle/src/test/java/io/opentdf/platform/sdk/fips/bouncycastle/BouncyCastleFipsHkdfProviderTest.java @@ -5,6 +5,7 @@ import java.nio.charset.StandardCharsets; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNullPointerException; class BouncyCastleFipsHkdfProviderTest { @@ -30,4 +31,33 @@ void computeHKDF_isDeterministic() { assertThat(first).isEqualTo(second); } + + @Test + void computeHKDF_nullSaltMatchesEmptySalt() { + byte[] secret = "secret".getBytes(StandardCharsets.UTF_8); + + byte[] withNull = provider.computeHKDF(null, secret); + byte[] withEmpty = provider.computeHKDF(new byte[0], secret); + + assertThat(withNull).isEqualTo(withEmpty); + } + + @Test + void computeHKDF_nullSaltMatchesZeroSalt() { + byte[] secret = "secret".getBytes(StandardCharsets.UTF_8); + + byte[] withNull = provider.computeHKDF(null, secret); + byte[] withZero = provider.computeHKDF(new byte[32], secret); + + assertThat(withNull).isEqualTo(withZero); + } + + @Test + void computeHKDF_throwsOnNullSecret() { + byte[] salt = "salt".getBytes(StandardCharsets.UTF_8); + + assertThatNullPointerException() + .isThrownBy(() -> provider.computeHKDF(salt, null)) + .withMessage("secret must not be null"); + } } From 33612b59f64f7d4aaeacfb790fe5d8ab93f6c45d Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Wed, 17 Jun 2026 10:07:04 -0400 Subject: [PATCH 56/58] Update checks.yaml --- .github/workflows/checks.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml index 1773e92d..36acfebd 100644 --- a/.github/workflows/checks.yaml +++ b/.github/workflows/checks.yaml @@ -98,8 +98,7 @@ jobs: -Dmaven.antrun.skip \ -Dmaven.test.skip mvn --batch-mode test enforcer:enforce -P 'fips,!non-fips' \ - -Dmaven.antrun.skip \ - -Dorg.bouncycastle.fips.approved_only=true + -Dmaven.antrun.skip - name: Tests with coverage and javadoc (non-fips) env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 0df2caf01622300f0c2dae2e27d99484016aa379 Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Wed, 17 Jun 2026 17:23:50 -0400 Subject: [PATCH 57/58] let people know when they need the new jar --- .../main/java/io/opentdf/platform/sdk/ECKeyPair.java | 11 +++++++++-- .../java/io/opentdf/platform/sdk/ECKeyPairTest.java | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java index 36bc6934..2830179c 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java @@ -23,6 +23,7 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; +import java.util.Locale; import java.util.Objects; public class ECKeyPair { @@ -136,8 +137,14 @@ public static byte[] calculateHKDF(byte[] salt, byte[] secret) { hmac.init(new SecretKeySpec(prk, HMAC_SHA_256)); hmac.update((byte) 0x01); return hmac.doFinal(); - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - throw new RuntimeException(e); + } catch (NoSuchAlgorithmException e) { + throw new SDKException("error computing HKDF", e) ; + } catch (Exception e) { + String className = e.getClass().getName(); + if (className.contains("bouncycastle") && className.endsWith("IllegalKeyException")) { + throw new SDKException("if running bouncycastle FIPS in approved_only mode include the sdk-fips-bouncycastle jar to use HKDF", e); + } + throw new SDKException("error computing HKDF", e); } } diff --git a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java index a49bb724..537e2f8f 100644 --- a/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java +++ b/sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java @@ -3,7 +3,9 @@ import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -13,6 +15,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; public class ECKeyPairTest { @@ -174,4 +177,12 @@ void testECDSA() { assertEquals(verify, true); } } + + @Test + @Disabled("remove the additionalClassDependencies element in the FIPS profile to execute this test") + @EnabledIfSystemProperty(named = "org.bouncycastle.fips.approved_only", matches = "true") + void testInformativeException() { + var thrown = assertThrows(SDKException.class, () -> ECKeyPair.calculateHKDF(new byte[]{0}, new byte[]{1,2,3})); + assertThat(thrown).hasMessage("if running bouncycastle FIPS in approved_only mode include the sdk-fips-bouncycastle jar to use HKDF"); + } } From 3c60aa0bcd6d3405f226a644930f73cfc746f13f Mon Sep 17 00:00:00 2001 From: Morgan Kleene Date: Wed, 17 Jun 2026 19:25:38 -0400 Subject: [PATCH 58/58] Update ECKeyPair.java --- sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java | 1 - 1 file changed, 1 deletion(-) diff --git a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java index 2830179c..ef906d06 100644 --- a/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java +++ b/sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java @@ -23,7 +23,6 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; -import java.util.Locale; import java.util.Objects; public class ECKeyPair {