Skip to content

feat(sdk)!: remove bouncycastle and ayza libraries#367

Open
mkleene wants to merge 54 commits into
mainfrom
remove-ayza-and-bouncycastle
Open

feat(sdk)!: remove bouncycastle and ayza libraries#367
mkleene wants to merge 54 commits into
mainfrom
remove-ayza-and-bouncycastle

Conversation

@mkleene
Copy link
Copy Markdown
Contributor

@mkleene mkleene commented May 18, 2026

This pull makes this library provider-agnostic. Users can control how cryptography is provided by configuring
their java.security configuration, as we do in the FIPS-profile tests. We add two new maven profiles fips and
non-fips. These profiles are used solely for testing; the library itself is agnostic to which providers are used
for cryptography.

In the non-fips profile we use the normal providers configured on the JVM. The BouncyCastle provider is included
just for some test verification.

In the fips profile 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:

  • verify that the JWK libraries we use are FIPS compliant with the correct providers to claim that this
    library can be made FIPS compliant
  • verify that we generate random numbers in a FIPS-compliant way. Because BouncyCastle does not provide a
    FIPS-compliant source of entropy we need to include the SUN provider to get at /dev/rand. This is OK, since
    • we should pick up this provider and use it for all cryptographic operations (but we may want to provide ways to guarantee that a particular provider is used)
    • the FIPS boundary for random numbers starts at the provider. We don't have tools to verify this now, though

The breaking API changes are as follows:

Area Change Related to
SDKBuilder.sslFactory(SSLFactory) Removed. Replaced by sslFactory(SSLSocketFactory) and sslFactory(SSLSocketFactory, X509TrustManager) Ayza removal
SDKBuilder.sslFactoryFromTrustManager(X509TrustManager) New method Ayza removal
ECKeyPair(ECCurve, ECAlgorithm) constructor Removed. Replaced by ECKeyPair(ECCurve) BouncyCastle removal
ECKeyPair.publicKeyFromPem Removed method from public interface since it should not have been exposed and since the types were changing anyway BouncyCastle removal
ECKeyPair.privateKeyFromPem, getPEMPublicKeyFromX509Cert, publicKeyFromECPoint, static compressECPublickey(String) Removed from public API (moved to test-only PemTestUtils) BouncyCastle removal
Dependencies Drops io.github.hakky54:ayza* and the runtime BC dep; adds bc-fips, bcpkix-fips, bctls-fips (via new fips/non-fips Maven profiles) Both

Summary by CodeRabbit

  • New Features

    • Added FIPS-profile cryptography support and improved TLS trust material loading from certificate directories and keystores.
  • Improvements

    • Migrated crypto operations to standard Java security APIs for broader compatibility.
    • Added AES-GCM key generation helper and tightened TLS/trust-manager handling.
  • Chores

    • Updated build/test configuration and pinned Bouncy Castle FIPS dependencies for FIPS profiles.

Review Change Stack

mkleene and others added 30 commits May 11, 2026 15:42
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>
@mkleene mkleene requested review from a team as code owners May 18, 2026 16:59
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

📝 Walkthrough

Walkthrough

This PR refactors the Java SDK to migrate from third-party cryptographic libraries (Ayza, explicit Bouncy Castle) to native JCA/JCE APIs, adds FIPS/non‑FIPS Maven profiles and CI steps, implements TrustProvider and CompositeX509ExtendedTrustManager, rewires SDK TLS to use SSLSocketFactory/X509TrustManager, migrates EC/AES helpers to JCA, and updates tests to use new utilities.

Changes

Cryptography library migration and TLS refactoring

Layer / File(s) Summary
Build configuration and dependency management
.github/workflows/checks.yaml, pom.xml, sdk/pom.xml
Add FIPS-related Maven properties and profiles, remove Ayza dependencies, configure test JVM security properties and Surefire argLine, and split CI mavenverify into FIPS and non‑FIPS steps with Sonar run in non‑FIPS verify.
Composite trust manager
sdk/src/main/java/io/opentdf/platform/sdk/CompositeX509ExtendedTrustManager.java
New composite X509ExtendedTrustManager aggregates multiple delegates, iterating delegates for client/server checks and aggregating accepted issuers defensively.
TrustProvider and Builder
sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java
New TrustProvider builds SSLContext/SSLSocketFactory and X509TrustManager from directories, keystores, or existing trust managers; Builder composes default JVM material, explicit certs, and keystores.
SDKBuilder TLS refactor to native SSL APIs
sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java
Replace SSLFactory with SSLSocketFactory and X509TrustManager fields; add sslFactoryFromTrustManager and sslFactory(SSLSocketFactory,X509TrustManager) overloads; use TrustProvider for directory/keystore wiring; update OkHttp TLS setup and token/auth wiring.
TokenSource, KASClient and command-line TLS wiring
sdk/src/main/java/io/opentdf/platform/sdk/TokenSource.java, sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java, cmdline/src/main/java/io/opentdf/platform/Command.java
TokenSource accepts SSLSocketFactory and applies it to HTTP requests; KASClient EC unwrap decodes PEM into ECPublicKey and surfaces decode errors as SDKException; CLI insecure mode builds permissive X509TrustManager and calls sdkBuilder.sslFactoryFromTrustManager().
AES key generation and ECKeyPair JCA migration
sdk/src/main/java/io/opentdf/platform/sdk/AesGcm.java, sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java
Add AesGcm.generateKey() for 256-bit AES keys; refactor ECKeyPair to JCA KeyPairGenerator/KeyAgreement/Signature, rewrite PEM encode/decode, compressed point helpers, and replace BC HKDF with HmacSHA256 RFC5869 implementation.
TDF symmetric key and EC-wrapped key handling
sdk/src/main/java/io/opentdf/platform/sdk/TDF.java
Generate symmetric split keys via AesGcm.generateKey(); update createECWrappedKey to use new ECKeyPair constructor and catch PEM decoding exceptions.
PemTestUtils and test updates
sdk/src/test/java/io/opentdf/platform/sdk/PemTestUtils.java, sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java, sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java, sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java, sdk/src/test/resources/java.security.fips.test
Add PemTestUtils for PEM/X.509/EC point helpers; update tests to use PemTestUtils and AesGcm.generateKey(); adjust SDKBuilder tests for new trust wiring and add FIPS test security properties.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~65 minutes

Poem

🐰 From Ayza's burrow we hopped to JCA light,
Keys now blossom in native Java's sight,
TrustProviders gather certs with care,
FIPS profiles hum their steady air,
Tests dance on PEMs — secure and bright.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(sdk)!: remove bouncycastle and ayza libraries' directly and accurately summarizes the main objective: removing BouncyCastle and Ayza dependencies from the SDK and replacing them with JCA-based implementations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch remove-ayza-and-bouncycastle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the SDK's cryptographic and SSL handling to support FIPS compliance by transitioning from provider-specific libraries to standard Java Cryptography Architecture (JCA) APIs. Key changes include the removal of external dependencies like ayza and nl.altindag.ssl, the introduction of a TrustProvider for managing SSL contexts, and the addition of Maven profiles to manage FIPS-specific dependencies. A high-severity bug was identified in the TrustProvider class where the use of Set.of() with potentially duplicate keystore types would cause a runtime crash during initialization.

Comment thread sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
sdk/src/main/java/io/opentdf/platform/sdk/TDF.java (1)

163-164: ⚡ Quick win

Derive the split-key size from AesGcm instead of keeping a second 32-byte contract.

Line 163 now makes TDF depend on AesGcm.generateKey(), but this class still hardcodes GCM_KEY_SIZE = 32 for payloadKey sizing and XOR reconstruction. That duplication is easy to miss on future key-size changes and would silently desynchronize the two layers.

Suggested fix
-    private static final int GCM_KEY_SIZE = 32;
+    private static final int GCM_KEY_SIZE = AesGcm.GCM_KEY_SIZE_BITS / Byte.SIZE;
🤖 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/TDF.java` around lines 163 - 164,
The code duplicates the 32-byte key size: TDF uses a hardcoded GCM_KEY_SIZE = 32
while calling AesGcm.generateKey(), risking divergence; update TDF to derive the
split-key size from AesGcm instead of the hardcoded constant (e.g., replace uses
of GCM_KEY_SIZE for payloadKey sizing and XOR reconstruction with a value
obtained from AesGcm such as AesGcm.KEY_SIZE if available, or by using
AesGcm.generateKey().length/returnedKeyLength helper), and ensure all places
that allocate payloadKey or perform XOR use that single derived size so key
generation and reconstruction remain consistent (reference symbols: class TDF,
GCM_KEY_SIZE, payloadKey, XOR reconstruction, and AesGcm.generateKey()).
.github/workflows/checks.yaml (1)

94-104: ⚡ Quick win

Isolate the FIPS and non-FIPS Maven runs.

These two steps switch dependency profiles in the same workspace and both reuse the existing target/ trees. That makes the non-FIPS verify partially depend on artifacts emitted by the earlier FIPS run, which can hide profile-specific regressions. Please add clean to each profile-specific invocation or run them in separate jobs.

🤖 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 @.github/workflows/checks.yaml around lines 94 - 104, The two workflow steps
"Tests and enforcer (fips)" and "Tests with coverage and javadoc (non-fips)"
reuse the same workspace and target/ artifacts, causing the non-FIPS mvn verify
to depend on FIPS artifacts; update the Maven invocations in those steps (the
lines invoking mvn --batch-mode test enforcer:enforce -P 'fips,!non-fips'
-Dmaven.antrun.skip and the mvn --batch-mode verify ... -P
'coverage,non-fips,!fips') to include a clean phase (e.g., prepend clean so they
become mvn --batch-mode clean test ... and mvn --batch-mode clean verify ...) or
alternatively move each profile run into separate jobs to ensure isolation.
🤖 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.

Inline comments:
In `@pom.xml`:
- Around line 20-22: The bc-fips.version property is pinned to 2.0.1 while
bcpkix-fips.version and bctls-fips.version are 2.1.x, which causes
incompatibility; update the bc-fips.version property to a 2.1.x release that
matches the PKIX/TLS modules (e.g., 2.1.23 or the same release series used by
bcpkix-fips/bctls-fips) and ensure the dependencyManagement entries that
reference bc-fips, bcpkix-fips, and bctls-fips all use the same 2.1.x release
set so all Bouncy Castle FIPS artifacts come from the same release.

In `@sdk/pom.xml`:
- Around line 493-517: The fips profile currently hides the bc-fips, bctls-fips,
and bcpkix-fips dependencies (profile id "fips") from downstream consumers; move
those three dependencies out of the inactive <profile id="fips"> into the main
<dependencies> section and mark each with <optional>true</optional> so SDK
consumers can opt in to FIPS provider jars (keep the same groupId/artifactId
values: org.bouncycastle:bc-fips, org.bouncycastle:bctls-fips,
org.bouncycastle:bcpkix-fips).

In `@sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java`:
- Around line 54-64: The method visibility for ECKeyPair.publicKeyFromPem was
reduced to package-private, which silently removes a public SDK entry point;
restore its visibility to public by changing the method signature back to public
(i.e., make publicKeyFromPem(...) public in class ECKeyPair) so external callers
keep working, or if removal is intentional, add explicit breaking-change
documentation and update the SDK changelog and API docs referencing
ECKeyPair.publicKeyFromPem to announce the removal.

In `@sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java`:
- Around line 162-163: Replace the incorrect enum name usage passed to
PemTestUtils.publicKeyFromECPoint — it's calling SECP256R1.name() (which yields
"SECP256R1") but ECGenParameterSpec requires the JCA curve alias; change the
call to use SECP256R1.getCurveName() (the same form used earlier on line 67) so
the publicKeyFromECPoint invocation receives "secp256r1" instead of the
uppercase enum constant.

In `@sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java`:
- Around line 208-212: The server certificate built in SDKBuilderTest (the
HeldCertificate assigned to serverCertificate) only adds the canonical hostname
SAN; update the HeldCertificate.Builder usage in the serverCertificate creation
to include the literal string "localhost" as an additional subject alternative
name (i.e., add a SAN entry for the literal "localhost" in addition to the
existing localhost variable) so hostname verification succeeds in environments
where getCanonicalHostName() is not the literal "localhost".

---

Nitpick comments:
In @.github/workflows/checks.yaml:
- Around line 94-104: The two workflow steps "Tests and enforcer (fips)" and
"Tests with coverage and javadoc (non-fips)" reuse the same workspace and
target/ artifacts, causing the non-FIPS mvn verify to depend on FIPS artifacts;
update the Maven invocations in those steps (the lines invoking mvn --batch-mode
test enforcer:enforce -P 'fips,!non-fips' -Dmaven.antrun.skip and the mvn
--batch-mode verify ... -P 'coverage,non-fips,!fips') to include a clean phase
(e.g., prepend clean so they become mvn --batch-mode clean test ... and mvn
--batch-mode clean verify ...) or alternatively move each profile run into
separate jobs to ensure isolation.

In `@sdk/src/main/java/io/opentdf/platform/sdk/TDF.java`:
- Around line 163-164: The code duplicates the 32-byte key size: TDF uses a
hardcoded GCM_KEY_SIZE = 32 while calling AesGcm.generateKey(), risking
divergence; update TDF to derive the split-key size from AesGcm instead of the
hardcoded constant (e.g., replace uses of GCM_KEY_SIZE for payloadKey sizing and
XOR reconstruction with a value obtained from AesGcm such as AesGcm.KEY_SIZE if
available, or by using AesGcm.generateKey().length/returnedKeyLength helper),
and ensure all places that allocate payloadKey or perform XOR use that single
derived size so key generation and reconstruction remain consistent (reference
symbols: class TDF, GCM_KEY_SIZE, payloadKey, XOR reconstruction, and
AesGcm.generateKey()).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1959f667-867f-4fe5-902c-1230a1063ad3

📥 Commits

Reviewing files that changed from the base of the PR and between 9991b07 and fafe689.

📒 Files selected for processing (17)
  • .github/workflows/checks.yaml
  • cmdline/src/main/java/io/opentdf/platform/Command.java
  • pom.xml
  • sdk/pom.xml
  • sdk/src/main/java/io/opentdf/platform/sdk/AesGcm.java
  • sdk/src/main/java/io/opentdf/platform/sdk/CompositeX509ExtendedTrustManager.java
  • sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java
  • sdk/src/main/java/io/opentdf/platform/sdk/KASClient.java
  • sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java
  • sdk/src/main/java/io/opentdf/platform/sdk/TDF.java
  • sdk/src/main/java/io/opentdf/platform/sdk/TokenSource.java
  • sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java
  • sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java
  • sdk/src/test/java/io/opentdf/platform/sdk/PemTestUtils.java
  • sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java
  • sdk/src/test/java/io/opentdf/platform/sdk/TDFTest.java
  • sdk/src/test/resources/java.security.fips.test

Comment thread pom.xml Outdated
Comment thread sdk/pom.xml
Comment thread sdk/src/main/java/io/opentdf/platform/sdk/ECKeyPair.java
Comment thread sdk/src/test/java/io/opentdf/platform/sdk/ECKeyPairTest.java Outdated
Comment on lines 208 to 212
HeldCertificate serverCertificate = new HeldCertificate.Builder()
.addSubjectAlternativeName(localhost)
.commonName("CN=localhost")
.rsa2048()
.commonName("localhost")
.signedBy(rootCertificate)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "-- canonical hostname for localhost on this machine --"
python - <<'PY'
import socket
print(socket.getfqdn("localhost"))
PY

echo
echo "-- localhost endpoint literals and SAN inputs in SDKBuilderTest --"
rg -n -C1 '://localhost:|addSubjectAlternativeName|commonName\("localhost"\)' \
  sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java

Repository: opentdf/java-sdk

Length of output: 1544


🏁 Script executed:

# Get the context around the certificate building code and find the localhost variable definition
cat -n sdk/src/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java | sed -n '195,225p'

Repository: opentdf/java-sdk

Length of output: 1572


Include literal localhost in the certificate SANs.

These tests connect to https://localhost:..., but the certificate only includes the canonical hostname of "localhost" as a SAN. On systems where InetAddress.getByName("localhost").getCanonicalHostName() resolves to something other than the literal string "localhost" (e.g., certain Docker or CI environments), hostname verification will fail.

Suggested fix
        HeldCertificate serverCertificate = new HeldCertificate.Builder()
+               .addSubjectAlternativeName("localhost")
                .addSubjectAlternativeName(localhost)
                .rsa2048()
                .commonName("localhost")
                .signedBy(rootCertificate)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
HeldCertificate serverCertificate = new HeldCertificate.Builder()
.addSubjectAlternativeName(localhost)
.commonName("CN=localhost")
.rsa2048()
.commonName("localhost")
.signedBy(rootCertificate)
HeldCertificate serverCertificate = new HeldCertificate.Builder()
.addSubjectAlternativeName("localhost")
.addSubjectAlternativeName(localhost)
.rsa2048()
.commonName("localhost")
.signedBy(rootCertificate)
🤖 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/test/java/io/opentdf/platform/sdk/SDKBuilderTest.java` around lines
208 - 212, The server certificate built in SDKBuilderTest (the HeldCertificate
assigned to serverCertificate) only adds the canonical hostname SAN; update the
HeldCertificate.Builder usage in the serverCertificate creation to include the
literal string "localhost" as an additional subject alternative name (i.e., add
a SAN entry for the literal "localhost" in addition to the existing localhost
variable) so hostname verification succeeds in environments where
getCanonicalHostName() is not the literal "localhost".

@github-actions
Copy link
Copy Markdown
Contributor

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 18, 2026

Dependency Review

The following issues were found:
  • ❌ 1 vulnerable package(s)
  • ✅ 0 package(s) with incompatible licenses
  • ✅ 0 package(s) with invalid SPDX license definitions
  • ⚠️ 3 package(s) with unknown licenses.
See the Details below.

Vulnerabilities

pom.xml

NameVersionVulnerabilitySeverity
org.bouncycastle:bc-fips2.1.2Bouncy Castle has a vulnerability in program files gcm128w, gcm512wmoderate

License Issues

sdk/pom.xml

PackageVersionLicenseIssue Type
org.apache.maven.plugins:maven-surefire-pluginNullUnknown License
org.bouncycastle:bc-fipsNullUnknown License
org.bouncycastle:bctls-fipsNullUnknown License
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

PackageVersionScoreDetails
maven/org.bouncycastle:bc-fips 2.1.2 UnknownUnknown
maven/org.bouncycastle:bcpkix-fips 2.1.11 UnknownUnknown
maven/org.bouncycastle:bctls-fips 2.1.23 UnknownUnknown
maven/org.bouncycastle:bctls-jdk18on 1.82 🟢 6.4
Details
CheckScoreReason
Maintained🟢 1030 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10
Packaging⚠️ -1packaging workflow not detected
Code-Review⚠️ 0Found 0/30 approved changesets -- score normalized to 0
Token-Permissions🟢 9detected GitHub workflow tokens with excessive permissions
Security-Policy🟢 10security policy file detected
CII-Best-Practices⚠️ 0no effort to earn an OpenSSF best practices badge detected
Dangerous-Workflow🟢 10no dangerous workflow patterns detected
License🟢 10license file detected
SAST🟢 10SAST tool detected: CodeQL
Binary-Artifacts⚠️ 0binaries present in source code
Signed-Releases⚠️ -1no releases found
Pinned-Dependencies⚠️ 0dependency not pinned by hash detected -- score normalized to 0
Fuzzing🟢 10project is fuzzed
Branch-Protection⚠️ -1internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md
maven/org.apache.maven.plugins:maven-surefire-plugin UnknownUnknown
maven/org.bouncycastle:bc-fips UnknownUnknown
maven/org.bouncycastle:bcpkix-fips UnknownUnknown
maven/org.bouncycastle:bcpkix-jdk18on UnknownUnknown
maven/org.bouncycastle:bctls-fips UnknownUnknown

Scanned Files

  • pom.xml
  • sdk/pom.xml

@github-actions
Copy link
Copy Markdown
Contributor

X-Test Failure Report

Comment thread sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java Dismissed
@github-actions
Copy link
Copy Markdown
Contributor

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java (1)

95-99: ⚡ Quick win

Specify 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 via jdk.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

📥 Commits

Reviewing files that changed from the base of the PR and between fafe689 and 5fdaea0.

📒 Files selected for processing (5)
  • pom.xml
  • sdk/src/main/java/io/opentdf/platform/sdk/AesGcm.java
  • sdk/src/main/java/io/opentdf/platform/sdk/SDKBuilder.java
  • sdk/src/main/java/io/opentdf/platform/sdk/TrustProvider.java
  • sdk/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

@github-actions
Copy link
Copy Markdown
Contributor

Copy link
Copy Markdown
Contributor

@marythought marythought left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 / X509TrustManager are types every Java dev already knows.
  • The new SDKBuilder method set is well-shaped. sslFactoryFromTrustManager / sslFactoryFromDirectory / sslFactoryFromKeyStore cover the common cases; the bare/paired sslFactory(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 / fromKeyStore include 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.

Comment on lines +267 to +272
X509TrustManager insecureTrustManager = new X509TrustManager() {
@Override public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@Override public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
};
builder.sslFactoryFromTrustManager(insecureTrustManager);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The insecure-trust path is now ~5 lines of boilerplate every consumer who wants local-dev "trust everything" will rewrite. The pre-ayza one-liner was SSLFactory.builder().withUnsafeTrustMaterial().build(). Worth a no-arg SDKBuilder.useInsecureSkipVerify() (or similar) that wraps this same anonymous trust-manager internally? useInsecurePlaintextConnection is already alongside it as precedent for "we provide the unsafe option explicitly because consumers will ask for it anyway."

import java.util.Objects;
// https://www.bouncycastle.org/latest_releases.html

public class ECKeyPair {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description's breaking-change table lists what's removed from ECKeyPair's public API, but doesn't say what consumers should use instead. For each removed static helper, a one-line JCA recipe in the table would save callers a JCA-docs hunt — e.g., publicKeyFromPem(pem)KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(...)), or getPEMPublicKeyFromX509Cert(...)CertificateFactory.getInstance("X.509").generateCertificate(...).getPublicKey(). If any of the removed helpers have no public replacement (genuinely test-only), saying so explicitly avoids a search that ends in disappointment.

* work is fulfilled by whichever {@link java.security.Provider} is registered with the JVM,
* including FIPS-mode providers.
*/
final class TrustProvider {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Load-bearing architectural shift here — provider-agnostic JCA + an internal trust composition abstraction, driven by FIPS-readiness and removing the BC namespace conflict with ayza. The rationale is solid but lives only in the PR description today. Worth recording in a repo ADR (e.g., adr/000X-provider-agnostic-cryptography.md) so future maintainers don't have to dig through PR history to understand why BC stopped being a compile dep and why TrustProvider exists. Could also capture the trade-offs that aren't visible in code — e.g., why TrustProvider is package-private today, and what the FIPS-readiness gaps are (the "Remaining FIPS work" list in the PR body).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants