@@ -111,6 +111,116 @@ This will write out generated CSRs to the following directory:
111111examples/certs/generated/
112112```
113113
114+ ## Post Quantum (ML-KEM, ML-DSA) with ServerJSSE / ClientJSSE
115+
116+ wolfJSSE supports TLS 1.3 post-quantum key exchange (ML-KEM / FIPS 203) and
117+ post quantum certificate authentication (ML-DSA / FIPS 204) when native wolfSSL
118+ has been built with ` --enable-mlkem ` and ` --enable-mldsa ` . To additionally
119+ enable the pure (non-hybrid) ` ML-KEM-512 ` / ` ML-KEM-768 ` / ` ML-KEM-1024 ` named
120+ groups, native wolfSSL also needs ` --enable-tls-mlkem-standalone ` ; without it
121+ the PQ/T hybrid groups (e.g. ` X25519MLKEM768 ` , ` SECP384R1MLKEM1024 ` ) still
122+ work but the standalone groups are rejected at the native layer.
123+
124+ ** Native wolfSSL version requirement (ML-DSA cert auth):** the ML-DSA cert
125+ authentication path requires native wolfSSL containing PR
126+ [ #10310 ] ( https://github.com/wolfSSL/wolfssl/pull/10310 ) , which added ML-DSA
127+ SPKI / PKCS #8 DER support to ` d2i_PUBKEY ` / ` d2i_PrivateKey ` . That PR landed
128+ after the wolfSSL 5.9.1 release tag, so a post-5.9.1 stable release is required.
129+ The ML-KEM key-exchange path works fine on 5.9.1, only ML-DSA cert auth is
130+ gated. On older native wolfSSL the handshake will fail with an
131+ ` SSLHandshakeException ` (typically ` error code: -125 ` on the verifier side and
132+ ` -313 ` on the peer).
133+
134+ The ` ServerJSSE.sh ` and ` ClientJSSE.sh ` examples can use the ` -pqc <alg> `
135+ option to specify a PQC named group for TLS 1.3 handshakes.
136+
137+ A PQC TLS 1.3 handshake can mix and match two independent pieces:
138+
139+ 1 . ** Key exchange** -- pass ` -pqc <named-group> ` to use a post-quantum or
140+ PQ/T-hybrid named group instead of the classical default.
141+ 2 . ** Certificate authentication** -- pass ` -c ` and/or ` -A ` to load ML-DSA
142+ entity keys and roots instead of the classical defaults
143+ (` server.jks ` / ` client.jks ` / ` ca-server.jks ` / ` ca-client.jks ` ).
144+
145+ The three subsections below show each common combination. All three
146+ require ` -v 4 ` (TLS 1.3).
147+
148+ ### PQ-Hybrid Key Exchange with Classical Certs
149+
150+ To use classical RSA/ECDSA certs and only switch the key exchange to a PQ/T
151+ hybrid group:
152+
153+ ```
154+ $ cd <wolfssljni_root>
155+ $ ./examples/provider/ServerJSSE.sh -v 4 -pqc X25519MLKEM768
156+ $ ./examples/provider/ClientJSSE.sh -h 127.0.0.1 -v 4 -pqc X25519MLKEM768
157+ ```
158+
159+ Other supported ` -pqc ` named groups (build flag dependent) include:
160+
161+ - ** Pure ML-KEM (standalone, requires ` --enable-tls-mlkem-standalone ` ):**
162+ ` ML-KEM-512 ` , ` ML-KEM-768 ` , ` ML-KEM-1024 ` .
163+ - ** PQ/T hybrids (default with ` --enable-mlkem ` ):** ` SECP256R1MLKEM768 ` ,
164+ ` SECP384R1MLKEM1024 ` (CNSA 2.0 level), plus the OQS-assigned hybrids
165+ ` SECP256R1MLKEM512 ` , ` SECP384R1MLKEM768 ` , ` SECP521R1MLKEM1024 ` ,
166+ ` X25519MLKEM512 ` , ` X448MLKEM768 ` .
167+
168+ See ` ./examples/provider/ServerJSSE.sh -? ` for the full list at runtime.
169+
170+ ### ML-DSA Server Cert Authentication
171+
172+ To replace the classical server cert with an ML-DSA cert, pass an ML-DSA
173+ keystore via ` -c ` (entity cert/key) on the server, and the matching truststore
174+ via ` -A ` (trusted CA) on the client. The client still uses the default
175+ classical ` client.jks ` for client auth:
176+
177+ ```
178+ $ ./examples/provider/ServerJSSE.sh -v 4 \
179+ -pqc SECP384R1MLKEM1024 -l TLS_AES_256_GCM_SHA384 \
180+ -c "../provider/server-mldsa87.jks:wolfSSL test"
181+ $ ./examples/provider/ClientJSSE.sh -h 127.0.0.1 -v 4 \
182+ -pqc SECP384R1MLKEM1024 -l TLS_AES_256_GCM_SHA384 \
183+ -A "../provider/ca-mldsa87.jks:wolfSSL test"
184+ ```
185+
186+ ### Mutual ML-DSA Authentication
187+
188+ For mutual authentication with ML-DSA certs, ServerJSSE verifies the client
189+ by default, so just add ` -c client-mldsa<N>.jks ` on the client and the shared
190+ truststore (` -A ca-mldsa<N>.jks ` ) on both sides:
191+
192+ ```
193+ $ ./examples/provider/ServerJSSE.sh -v 4 \
194+ -pqc SECP384R1MLKEM1024 -l TLS_AES_256_GCM_SHA384 \
195+ -c "../provider/server-mldsa87.jks:wolfSSL test" \
196+ -A "../provider/ca-mldsa87.jks:wolfSSL test"
197+ $ ./examples/provider/ClientJSSE.sh -h 127.0.0.1 -v 4 \
198+ -pqc SECP384R1MLKEM1024 -l TLS_AES_256_GCM_SHA384 \
199+ -c "../provider/client-mldsa87.jks:wolfSSL test" \
200+ -A "../provider/ca-mldsa87.jks:wolfSSL test"
201+ ```
202+
203+ ### Example Keystores
204+
205+ Example ML-DSA keystores can be found under ` examples/provider/ ` :
206+ ` server-mldsa{44,65,87}.jks ` , ` client-mldsa{44,65,87}.jks ` , and
207+ ` ca-mldsa{44,65,87}.jks ` (password ` wolfSSL test ` ). The server and client
208+ entity certs at each level are signed by the same root, so a single
209+ ` ca-mldsa<N>.jks ` truststore validates both sides.
210+
211+ JKS paths in the examples above are relative to the wrapper's working
212+ directory (` examples/build/ ` ). Loading the ML-DSA private keys from a JKS
213+ requires JDK 24 or newer (JEP 497). To regenerate the keystores, run
214+ ` ./examples/provider/update-keystore-pqc.sh ` (also requires JDK 24+).
215+
216+ ### CNSA 2.0 Compliance
217+
218+ CNSA 2.0 (NSA Commercial National Security Algorithm Suite 2.0) mandates
219+ TLS 1.3 + ML-KEM-1024 (or a hybrid containing it) + AES-256-GCM + ML-DSA-87
220+ cert auth. The "Mutual ML-DSA Authentication" example above (level ** 87** ,
221+ ` SECP384R1MLKEM1024 ` , ` TLS_AES_256_GCM_SHA384 ` ) is the full CNSA 2.0
222+ recipe.
223+
114224## Support
115225
116226Please contact the wolfSSL support team at support@wolfssl.com with any
0 commit comments