
Post-Quantum Cryptography (PQC) TLS 1.3 examples with Apache Camel using X25519MLKEM768 hybrid key exchange on JDK 21 (BouncyCastle) and JDK 27 (native)
This repository contains three examples demonstrating Post-Quantum Cryptography (PQC) TLS 1.3 handshakes with Apache Camel, using the X25519MLKEM768 hybrid key exchange.
X25519MLKEM768 combines classical X25519 elliptic curve Diffie-Hellman with ML-KEM-768, a post-quantum lattice-based key encapsulation mechanism (NIST FIPS 203). Both algorithms run together, so security is maintained even if one is broken.
| Example | JDK | TLS Provider | Approach |
|---|---|---|---|
pqc-ssl-context | JDK 27 | SunJSSE (JDK native) | JEP 527 adds PQC named groups to the JDK's built-in TLS stack |
pqc-kem-jdk24 | JDK 24 | BouncyCastle JSSE 1.83 | BCJSSE for PQC TLS, JDK has native ML-KEM primitives via JEP 496 |
pqc-ssl-context-jdk21 | JDK 21 | BouncyCastle JSSE 1.83 | BCJSSE replaces SunJSSE to provide PQC TLS support today |
All three examples are configured entirely through camel.ssl.* properties and perform a self-contained TLS 1.3 handshake using X25519MLKEM768 for post-quantum key exchange, verified at startup and available on demand via REST endpoints.
pqc-ssl-context)Uses the JDK's built-in SunJSSE provider, which gains PQC TLS support through JEP 527 in JDK 27.
camel.ssl.namedGroups=X25519MLKEM768,x25519camel.ssl.selfSigned=true)SSLParameters.setNamedGroups() (standard JDK API)pqc-kem-jdk24)Uses BouncyCastle's JSSE provider (BCJSSE) to bring PQC TLS support to JDK 24. While JDK 24 includes native ML-KEM as a standalone crypto primitive (JEP 496), it does not expose PQC named groups in its TLS stack. BCJSSE bridges that gap.
camel.ssl.provider=BCJSSE and camel.ssl.namedGroups=X25519MLKEM768,secp256r1camel.ssl.selfSigned=true)/api/verify-kem endpoint demonstrates JDK 24's native javax.crypto.KEM API with cross-provider interop testspqc-ssl-context-jdk21)Uses BouncyCastle's JSSE provider (BCJSSE) to bring PQC TLS support to JDK 21, without waiting for JDK 27.
camel.ssl.provider=BCJSSE and camel.ssl.namedGroups=X25519MLKEM768,secp256r1camel.ssl.selfSigned=true)ECDH from jdk.tls.disabledAlgorithmscd pqc-ssl-context
sdk use java 27.ea.11-open
mvn clean compile exec:exec
curl -k https://localhost:8443/api/verify-pqc
cd pqc-kem-jdk24
sdk use java 24.0.1-tem
mvn clean compile exec:exec
curl -k https://localhost:8443/api/verify-pqc
curl -k https://localhost:8443/api/verify-kem
cd pqc-ssl-context-jdk21
sdk use java 21.0.10-tem
mvn clean compile exec:exec
curl -k https://localhost:8443/api/verify-pqc
All three will return "pqcVerified": true when the PQC TLS handshake succeeds.
If you hit any problem using Camel or have some feedback, then please let us know.
We also love contributors, so get involved :-)
The Camel riders!
| Aspect | JDK 27 Native | JDK 24 + BouncyCastle | JDK 21 + BouncyCastle |
|---|
| JDK requirement | JDK 27 EA | JDK 24+ | JDK 21+ |
| TLS provider | SunJSSE | BCJSSE 1.83 | BCJSSE 1.83 |
| PQC mechanism | JEP 527 (built-in) | BouncyCastle TLS library | BouncyCastle TLS library |
| Native ML-KEM (KEM API) | Yes | Yes (JEP 496) | No |
| Configuration | camel.ssl.* properties | camel.ssl.* properties | camel.ssl.* properties |
| Certificate management | camel.ssl.selfSigned=true | camel.ssl.selfSigned=true | camel.ssl.selfSigned=true |
| REST port | 8443 (HTTPS) | 8443 (HTTPS) | 8443 (HTTPS) |
| Extra dependencies | None (JDK native) | bcprov, bctls | bcprov, bctls |
| JDK Version | ML-KEM KEM API | PQC in TLS | Approach |
|---|
| 21 | No | Yes (via BouncyCastle) | pqc-ssl-context-jdk21 - BCJSSE provides PQC TLS support |
| 24 | Yes (JEP 496) | Yes (via BouncyCastle) | pqc-kem-jdk24 - BCJSSE for TLS, JDK has native ML-KEM primitives |
| 27 | Yes | Yes (native) | pqc-ssl-context - JEP 527 adds PQC to SunJSSE |