feat(sdk)!: remove bouncycastle and ayza libraries#367
Conversation
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Remove the three io.github.hakky54:ayza* dependencies and replace their TLS trust-material role with an SDK-owned TrustProvider built on provider-agnostic JCA APIs (CertificateFactory, KeyStore, TrustManagerFactory, SSLContext). This works under any registered crypto provider, including BC-FIPS, and avoids hardcoded provider names. - Add TrustProvider and package-private CompositeX509ExtendedTrustManager for combining JVM default + custom trust material. - SDKBuilder: replace SSLFactory field with SSLSocketFactory + X509TrustManager. sslFactory(SSLFactory) becomes sslFactory(SSLSocketFactory); add sslFactory(SSLSocketFactory, X509TrustManager) for callers that have a matching trust manager. sslFactoryFromDirectory / sslFactoryFromKeyStore signatures and semantics are preserved, now backed by TrustProvider internally. - TokenSource takes SSLSocketFactory directly. - Command.java --insecure path uses TrustProvider.insecure(). - SDKBuilderTest reworked to drop nl.altindag imports and use TrustProvider + standard JCA. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Dependency ReviewThe following issues were found:
Vulnerabilitiespom.xml
License Issuessdk/pom.xml
Denied Licenses: GPL-2.0, AGPL-1.0, AGPL-1.0-or-later, AGPL-1.0-only, AGPL-3.0, AGPL-3.0-only, AGPL-3.0-or-later, GPL-1.0, GPL-1.0+, GPL-1.0-only, GPL-1.0-or-later, CNRI-Python-GPL-Compatible, GPL-2.0+, GPL-2.0-only, GPL-2.0-or-later, GPL-2.0-with-GCC-exception, GPL-2.0-with-autoconf-exception, GPL-2.0-with-bison-exception, GPL-2.0-with-classpath-exception, GPL-2.0-with-font-exception, GPL-3.0, GPL-3.0+, GPL-3.0-only, GPL-3.0-or-later, GPL-3.0-with-GCC-exception, GPL-3.0-with-autoconf-exception, LGPL-2.0, LGPL-2.0+, LGPL-2.0-only, LGPL-2.0-or-later, LGPL-2.1, LGPL-2.1+, LGPL-2.1-only, LGPL-2.1-or-later, LGPL-3.0, LGPL-3.0+, LGPL-3.0-only, LGPL-3.0-or-later, LGPLLR, NGPL OpenSSF Scorecard
Scanned Files
|
X-Test Failure Report |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java (1)
95-99: ⚡ Quick winSpecify minimum TLS version instead of generic "TLS" string to prevent negotiation of deprecated protocols.
The generic
SSLContext.getInstance("TLS")(lines 96 and 211) permits negotiation of deprecated TLS 1.0/1.1. While modern JDKs disable these by default viajdk.tls.disabledAlgorithms, relying on JVM configuration is fragile. Since BC-FIPS supports"TLSv1.2"and"TLSv1.3"protocol strings, use one of these instead for stronger guarantees.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java` around lines 95 - 99, Replace the generic SSLContext.getInstance("TLS") usages with a specific, minimum protocol like "TLSv1.2" (or "TLSv1.3" if you require/guarantee support) to avoid negotiating deprecated TLS 1.0/1.1; update the call in TrustProvider.fromTrustManager (and the other SSLContext.getInstance("TLS") occurrence referenced in this review) to use SSLContext.getInstance("TLSv1.2") and ensure the rest of TrustProvider construction (sslContext.init(...), returned TrustProvider) remains unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java`:
- Around line 95-99: Replace the generic SSLContext.getInstance("TLS") usages
with a specific, minimum protocol like "TLSv1.2" (or "TLSv1.3" if you
require/guarantee support) to avoid negotiating deprecated TLS 1.0/1.1; update
the call in TrustProvider.fromTrustManager (and the other
SSLContext.getInstance("TLS") occurrence referenced in this review) to use
SSLContext.getInstance("TLSv1.2") and ensure the rest of TrustProvider
construction (sslContext.init(...), returned TrustProvider) remains unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 348f7f1d-b626-4140-961a-d2cc299dfa3f
📒 Files selected for processing (5)
pom.xmlsdk/src/main/java/io/opentdf/platform/sdk/AesGcm.javasdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.javasdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.javasdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java
🚧 Files skipped from review as they are similar to previous changes (3)
- pom.xml
- sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java
- sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java
marythought
left a comment
There was a problem hiding this comment.
Overall — this is a real DX improvement, even with the breaking changes. From the consumer's seat:
- Dropping ayza is a long-term win. Removes a niche third-party type from the public surface;
SSLSocketFactory/X509TrustManagerare types every Java dev already knows. - The new
SDKBuildermethod set is well-shaped.sslFactoryFromTrustManager/sslFactoryFromDirectory/sslFactoryFromKeyStorecover the common cases; the bare/pairedsslFactory(SSLSocketFactory[, X509TrustManager])overloads handle the escape hatches; naming is consistent and the javadoc explicitly tells callers to prefer the paired form. Good guidance built into the API. - Sensible defaults —
fromDirectory/fromKeyStoreinclude JVM default cacerts automatically. The common "my certs plus system trust" case works without customers having to think about composition. - The breaking-change table in the PR description is exactly the format consumers need. Old → new in one place.
- ECKeyPair public-surface tightening is principled. The moved-to-test-only helpers were marked as "should not have been exposed" and would have broken under FIPS anyway. Better to fix now.
Three specific notes as inline comments below.
X-Test Failure Report |
|
marythought
left a comment
There was a problem hiding this comment.
Re-reviewed after the latest commits. Both items from my first review are addressed:
insecureSslFactory()convenience method added toSDKBuilder— clean one-liner for local-dev consumers.- ADR documenting the BouncyCastle/Ayza removal rationale.
CI is green on all test/integration/xtest jobs. The SonarCloud and dependency-review failures look infrastructure-related.
LGTM — nice work on the provider-agnostic JCA migration.
🤖 I have created a release *beep* *boop* --- <details><summary>0.16.0</summary> ## [0.16.0](v0.15.0...v0.16.0) (2026-06-22) ### ⚠ BREAKING CHANGES * **sdk:** remove bouncycastle and ayza libraries ([#367](#367)) ### Features * **sdk:** remove bouncycastle and ayza libraries ([#367](#367)) ([63b49af](63b49af)) * verify that BC works with `approved_only` mode set ([#375](#375)) ([36fd6cf](36fd6cf)) ### Bug Fixes * **main:** Update bc module sdk version. ([#377](#377)) ([9b38f82](9b38f82)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: opentdf-automation[bot] <149537512+opentdf-automation[bot]@users.noreply.github.com> Co-authored-by: Morgan Kleene <mkleene@virtru.com>
…Wing, ECDH+ML-KEM) (#368) Add hybrid post-quantum key wrapping to the Java SDK so TDFs can be protected against "harvest now, decrypt later" attacks while preserving classical security guarantees during the PQC transition. Introduces three new `KeyType` values backed by hybrid KEMs: - `HybridXWingKey` (`hpqt:xwing`) — X-Wing (X25519 + ML-KEM-768) - `HybridSecp256r1MLKEM768Key` (`hpqt:secp256r1-mlkem768`) - `HybridSecp384r1MLKEM1024Key` (`hpqt:secp384r1-mlkem1024`) When a KAS advertises one of these algorithms,`TDF.upsertAndGetNewKeyAccess` routes through `HybridCrypto.wrapDEK`, which performs both a classical ECDH/X25519 key agreement and an ML-KEM encapsulation, combines the two shared secrets (HKDF-SHA256 with the standard TDF salt), and uses the result to wrap the DEK with AES-256-GCM. A new `hybrid-wrapped` key-access type is emitted; the ephemeral classical public key and ML-KEM ciphertext are packaged together inside an ASN.1 envelope stored in `wrappedKey` (rather than the separate `ephemeralPublicKey` field used for EC-wrapped keys). New supporting classes: `HybridCrypto`, `HybridNISTKeyPair`, `XWingKeyPair`, plus unit tests and a full-manifest TDF round-trip test. ## Provider-agnostic implementation In line with #367's removal of BouncyCastle as a compile dependency, this PR limits BC usage to the only primitives JDK 11 stdlib cannot supply — ML-KEM keygen/encap/decap and X-Wing keygen/encap/decap (the JCA `KEM` API is JDK21+; ML-KEM in stdlib is 24+). Everything else is stdlib JCA or an existing SDK helper: - **ASN.1 envelope** — minimal hand-rolled DER codec for `SEQUENCE { [0] IMPLICIT OCTET STRING, [1] IMPLICIT OCTET STRING }` with multi-byte length support. No `org.bouncycastle.asn1.*` imports. - **HKDF** — delegates to the existing `ECKeyPair.calculateHKDF(salt, secret)` (RFC 5869, empty info, L=32 — what all three algorithms need). - **EC keygen / ECDH / curve parameters** — stdlib `KeyPairGenerator.getInstance("EC")`, `KeyAgreement.getInstance("ECDH")`, `AlgorithmParameters.getInstance("EC")` with `ECGenParameterSpec`. No `BouncyCastleProvider` registration; consumers control providers via `java.security` as the ADR intends. `bcprov-jdk18on` is declared at compile/runtime scope in the default `non-fips` Maven profile, version pinned via the existing parent dep-management entry. ## Out of scope (follow-ups) - **`fips` profile support for hybrid PQC** — needs verification of which `bc-fips` version ships ML-KEM and X-Wing and how it registers them. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/opentdf/java-sdk/pull/368?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Added support for hybrid post-quantum cryptography with three new key types: X-Wing, secp256r1+ML-KEM-768, and secp384r1+ML-KEM-1024. * Introduced hybrid key wrapping mechanism for TDF encryption, enabling classical and post-quantum algorithm combinations. * **Tests** * Added end-to-end testing suite for hybrid post-quantum key wrapping workflows. * **Documentation** * Updated test documentation with hybrid PQC integration workflow and troubleshooting guidance. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/opentdf/java-sdk/pull/368?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->

This pull makes this library provider-agnostic. Users can control how cryptography is provided by configuring
their
java.securityconfiguration, as we do in the FIPS-profile tests. We add two new maven profilesfipsandnon-fips. These profiles are used solely for testing; the library itself is agnostic to which providers are usedfor cryptography.
In the
non-fipsprofile we use the normal providers configured on the JVM. The BouncyCastle provider is includedjust for some test verification.
In the
fipsprofile we include the BouncyCastle FIPS providers we need at runtime to verify that our library works with a FIPS-compliant setup.Ayza removal
I believe it's necessary to remove ayza since it loads a BouncyCastleProvider explicitly. Since the FIPS provider
occupies the same namespace loading both providers can't work.
BouncyCastle moved to test-only
Removing BouncyCastle as a compile dependency isn't strictly necessary but it results in much less rework and
eliminates a transitive dependency for consumers.
Remaining FIPS work
We still need to:
library can be made FIPS compliant
FIPS-compliant source of entropy we need to include the SUN provider to get at
/dev/rand. This is OK, sinceThe breaking API changes are as follows:
SDKBuilder.sslFactory(SSLFactory)sslFactory(SSLSocketFactory)andsslFactory(SSLSocketFactory, X509TrustManager)SDKBuilder.sslFactoryFromTrustManager(X509TrustManager)ECKeyPair(ECCurve, ECAlgorithm)constructorECKeyPair(ECCurve)ECKeyPair.publicKeyFromPemECKeyPair.privateKeyFromPem,getPEMPublicKeyFromX509Cert,publicKeyFromECPoint, staticcompressECPublickey(String)PemTestUtils)io.github.hakky54:ayza*and the runtime BC dep; addsbc-fips,bcpkix-fips,bctls-fips(via newfips/non-fipsMaven profiles)Summary by CodeRabbit
New Features
Improvements
Tests
Chores