Skip to content

[feature] Add post-quantum ML-DSA keys and mutual TLS - #389

Open
Enucatl wants to merge 1 commit into
jruby:masterfrom
Enucatl:feature/ml-dsa
Open

Enucatl wants to merge 1 commit into
jruby:masterfrom
Enucatl:feature/ml-dsa

Conversation

@Enucatl

@Enucatl Enucatl commented Oct 21, 2026

Copy link
Copy Markdown

This change lets JRuby applications use ML-DSA through the existing OpenSSL API. It supports ML-DSA-44, ML-DSA-65, and ML-DSA-87.

Applications can generate and import keys, sign and verify messages, and use ML-DSA with certificates, certificate requests, and revocation lists. Net::HTTP clients can present an ML-DSA identity without Java-specific application code.

The implementation uses Bouncy Castle and existing PKey and TLS helpers. Key operations require BC 1.80 or later. TLS requires BCJSSE 1.82 or later, with ML-DSA signature schemes enabled.

Tests cover independent OpenSSL fixtures, invalid inputs, mixed certificate chains, and real TLS GET and POST requests. Negative TLS tests check certificate trust, hostname, expiry, and client identity.

Inspired by Filippo's post-quantum cryptographic guidance: https://words.filippo.io/right-answers/

Expose ML-DSA-44, ML-DSA-65, and ML-DSA-87 through the existing PKey
API, including pure signatures and X.509 operations.

Use BC key specs to accept standard seed encodings on BC 1.80 and
emit standard expanded PKCS#8 across supported BC versions. Report
the exact parameter-set key type so BCJSSE can select a credential.

Select the existing TLS provider path for default SSL contexts with
ML-DSA credentials. Let Net::HTTP present the identity without
Java-specific application code or an SSL method override. Keep cipher
queries and their cache consistent with the selected provider. Preserve
classical defaults, callback timing, and explicit provider and protocol
policies.

Add independent OpenSSL fixtures, regression tests, and TLS acceptance
coverage on Java 11 with BCJSSE 1.82 and Java 25 with current BC.
Run acceptance through a separate task with the required startup
properties. Document BC 1.80 key support, BCJSSE 1.82 TLS support,
and explicit signature-scheme policy.

Test all three ML-DSA server identities with a default SSL context.
Add an optional native OpenSSL task to check JRuby key exports and
signatures independently for all three parameter sets.
@kares

kares commented Oct 21, 2026

Copy link
Copy Markdown
Member

Hey, seems like a lot is in here.
This is going to need a thorough review, looks like the aim is feature parity with OpenSSL >= 3.5.

Would you mind sharing the prompting and LLM used?

JOSSL doesn't even have full 3.0 (Ruby API) compatibility yet and given the minimal BC requirements bump this might take a bit to (review and) merge. We also need to check what to do with BC-FIPS regarding these, which might be a blocker. We would very likely not be shipping this in a patch release.

@kares kares added this to the 0.20.0 milestone Oct 21, 2026
@Enucatl

Enucatl commented Oct 21, 2026

Copy link
Copy Markdown
Author

Hello, thanks for the very quick review. This was assisted by GPT-6-Astra, with several conversations to refine the implementation, so I don't have one single prompt to report here.

The guiding principle was to maintain backwards compatibility, follow the established example of ECDSA with a similar implementation and style, and cover all the new functionality with tests.

We don't really need to bump BC requirements, however: with BC 1.80, ML-DSA keys and certificates work, only mTLS would fail the handshake when the client or server tries to negotiate ML-DSA. This part does require 1.82.

For BC-FIPS, I found that this is going to be released soon, it's already early access:
https://www.bouncycastle.org/download/bouncy-castle-java-fips/roadmap/

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.

2 participants