diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 17b6472d..1c67bf50 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -135,6 +135,32 @@ jobs: jdk_version: ${{ matrix.jdk_version }} wolfssl_configure: ${{ matrix.wolfssl_configure }} + # --------------- PQC (ML-KEM + ML-DSA) sanity check ----------------- + # Builds native wolfSSL master with the full PQC option set so that + # ML-KEM standalone groups, ML-KEM PQ/T hybrids (incl. X25519MLKEM* and + # X448MLKEM768), and ML-DSA cert auth all reach the gated tests instead + # of skipping. JDK 24 is required for JEP 497 ML-DSA KeyFactory and + # exercises the standard JCE keystore path. JDK 11 also runs to cover + # the JDK-8-compatible PEM-based PQC code path. The --enable-all + # variant additionally layers wolfSSL's broad feature set on top of + # the PQC flags to catch interaction regressions. + linux-zulu-pqc: + strategy: + matrix: + os: [ 'ubuntu-latest' ] + jdk_version: [ '11', '24' ] + wolfssl_configure: [ + '--enable-jni --enable-mlkem --enable-tls-mlkem-standalone --enable-mldsa --enable-curve25519 --enable-curve448 --enable-ed25519 --enable-ed448', + '--enable-jni --enable-all --enable-mlkem --enable-tls-mlkem-standalone --enable-mldsa --enable-curve25519 --enable-curve448 --enable-ed25519 --enable-ed448', + ] + name: ${{ matrix.os }} (Zulu JDK ${{ matrix.jdk_version }}, PQC full) + uses: ./.github/workflows/linux-common.yml + with: + os: ${{ matrix.os }} + jdk_distro: "zulu" + jdk_version: ${{ matrix.jdk_version }} + wolfssl_configure: ${{ matrix.wolfssl_configure }} + # -------------------- WOLFJNI_USE_IO_SELECT sanity check -------------------- # Only check one Linux and Mac JDK version as a sanity check. # Using Zulu, but this can be expanded if needed. diff --git a/README.md b/README.md index 9595f0a5..d0ab9fb0 100644 --- a/README.md +++ b/README.md @@ -566,7 +566,7 @@ and used by wolfSSL JNI/JSSE. | wolfssl.readWriteByteBufferPool.size | 16 | Integer | Sets the read/write per-thread ByteBuffer pool size | | wolfssl.readWriteByteBufferPool.bufferSize | 17408 | String | Sets the read/write per-thread ByteBuffer size | | wolfjsse.enabledCipherSuites | | String | Restricts enabled cipher suites | -| wolfjsse.enabledSupportedCurves | | String | Restricts enabled ECC curves | +| wolfjsse.enabledSupportedCurves | | String | Restricts enabled named groups (ECC curves and PQC/hybrid groups) | | wolfjsse.enabledSignatureAlgorithms | | String | Restricts enabled signature algorithms | | wolfjsse.keystore.type.required | | String | Restricts KeyStore type | | wolfjsse.clientSessionCache.disabled | | "true" | Disables client session cache | @@ -617,16 +617,24 @@ changing this property. This should be a comma-delimited String. Example use: wolfjsse.enabledCipherSuites=TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ``` -**wolfjsse.enabledSupportedCurves (String)** - Allows setting of specific ECC -curves to be enabled for SSL/TLS connections. This propogates down to the native +**wolfjsse.enabledSupportedCurves (String)** - Allows setting of specific +named groups (ECC curves and post-quantum / hybrid groups such as ML-KEM) +to be enabled for SSL/TLS connections. This propagates down to the native wolfSSL API `wolfSSL_UseSupportedCurve()`. If invalid/bad values are found when processing this property, connection establishment will fail with an -SSLException. This should be a comma-delimited String. Example use: +SSLException. This should be a comma-delimited String. Both compact +(`MLKEM768`, `X25519MLKEM768`) and IETF (`ML-KEM-768`, `SecP256r1MLKEM768`) +spellings are recognized for PQC and hybrid groups when native wolfSSL was +built with `--enable-mlkem`. Example use: ``` wolfjsse.enabledSupportedCurves=secp256r1, secp521r1 ``` +``` +wolfjsse.enabledSupportedCurves=X25519MLKEM768, SecP256r1MLKEM768, ML-KEM-768 +``` + **wolfjsse.enabledSignatureAlgorithms (String)** - Allows restriction of the signature algorithms sent in the TLS ClientHello Signature Algorithms Extension. By using/setting this property, native wolfSSL will not populate @@ -638,6 +646,14 @@ String of signature algorithm + MAC combinations. Example use: wolfjsse.enabledSignatureAlgorithms=RSA+SHA256:ECDSA+SHA256 ``` +Standalone scheme tokens (no MAC component) are also accepted, including +ED25519, ED448, and the FIPS 204 ML-DSA names (`ML-DSA-44`, `ML-DSA-65`, +`ML-DSA-87`) when native wolfSSL was built with `--enable-mldsa`: + +``` +wolfjsse.enabledSignatureAlgorithms=ML-DSA-87:ECDSA+SHA384 +``` + **wolfjsse.keystore.type.required (String)** - Can be used to specify a KeyStore type that is required to be used. If this is set, wolfJSSE will not allow use of any KeyStore instances that are not of this type. One use of this option @@ -724,6 +740,18 @@ advertised and used by the server if set. **jdk.tls.client.SignatureSchemes (String)** - Controls which signature algorithms are advertised and used by the client if set. +**jdk.tls.namedGroups (String)** - Comma-delimited list of TLS named groups +to advertise. Honored alongside `SSLParameters.setNamedGroups()` API (added in +JDK 20, JDK-8281236) and the `wolfjsse.enabledSupportedCurves` Security +property. Recognizes both classical curves (`secp256r1`, `secp384r1`) and +PQC / hybrid groups (`X25519MLKEM768`, `SecP256r1MLKEM768`, `ML-KEM-768`) when +native wolfSSL was built with `--enable-mlkem`. `SSLParameters.setNamedGroups()` +takes precedence over this property when both are set. + +``` +java -Djdk.tls.namedGroups=X25519MLKEM768,secp256r1 ... +``` + **jdk.tls.useExtendedMasterSecret (boolean)** - Can be used to enable or disable the use of the Extended Master Secret (EMS) extension. This extension is enabled by default, unless explicitly disabled by setting this property to diff --git a/examples/Client.java b/examples/Client.java index 773e0745..310d335e 100644 --- a/examples/Client.java +++ b/examples/Client.java @@ -77,6 +77,8 @@ public void run(String[] args) { boolean useSecretCallback = false; /* enable TLS 1.3 secret cb */ String keyLogFile = "sslkeylog.log"; /* output keylog file */ + String pqcAlg = null; /* PQC named group, -pqc */ + long session = 0; /* pointer to WOLFSSL_SESSION */ boolean resumeSession = false; /* try one session resumption */ @@ -219,11 +221,24 @@ public void run(String[] args) { } else if (arg.equals("-cid")) { useDtlsCid = 1; + } else if (arg.equals("-pqc")) { + if (args.length < i+2) { + printUsage(); + } + pqcAlg = args[++i]; + } else { printUsage(); } } + /* PQC named groups are TLS 1.3 only */ + if (pqcAlg != null && sslVersion != 4) { + System.out.println("-pqc requires -v 4 (TLS 1.3); " + + "PQC named groups are TLS 1.3 only"); + System.exit(1); + } + /* sort out DTLS versus TLS versions */ if (doDTLS == 1) { if (sslVersion == 4) { @@ -280,6 +295,27 @@ else if (sslVersion == 3) { /* create context */ WolfSSLContext sslCtx = new WolfSSLContext(method); + /* Restrict TLS supported_groups extension to the single post + * quantum group passed via -pqc */ + if (pqcAlg != null) { + int pqcGid = WolfSSL.getNamedGroupFromString(pqcAlg); + if (pqcGid == WolfSSL.WOLFSSL_NAMED_GROUP_INVALID) { + System.out.println("Unknown -pqc group: " + pqcAlg); + System.exit(1); + } + System.out.println("ML-KEM enabled: " + WolfSSL.MLKEMEnabled()); + System.out.println("ML-DSA enabled: " + WolfSSL.MLDSAEnabled()); + System.out.println("ML-KEM legacy IDs accepted: " + + WolfSSL.MLKEMOldIdsEnabled()); + + ret = sslCtx.useSupportedCurves(new String[] { pqcAlg }); + if (ret != WolfSSL.SSL_SUCCESS) { + System.out.println("Failed to set -pqc group " + pqcAlg + + ", ret = " + ret); + System.exit(1); + } + } + /* set up PSK, if being used */ if (usePsk == 1) { @@ -452,6 +488,21 @@ else if (sslVersion == 3) { /* create SSL object */ ssl = new WolfSSLSession(sslCtx); + /* Pre-send TLS 1.3 key share for the -pqc group to avoid a + * HelloRetryRequest if the server picks it. */ + if (pqcAlg != null) { + int gid = WolfSSL.getNamedGroupFromString(pqcAlg); + if (WolfSSL.isPQCNamedGroup(gid)) { + ret = ssl.useKeyShare(gid); + if (ret != WolfSSL.SSL_SUCCESS && + ret != WolfSSL.NOT_COMPILED_IN) { + System.out.println("useKeyShare failed for " + pqcAlg + + ", ret = " + ret); + System.exit(1); + } + } + } + /* enable/load CRL functionality */ if (WolfSSL.isEnabledCRL() == 1) { ret = ssl.enableCRL(WolfSSL.WOLFSSL_CRL_CHECKALL); @@ -906,6 +957,10 @@ void printUsage() { System.out.println("-P\t\tPublic Key Callbacks"); if (WolfSSL.secretCallbackEnabled()) System.out.println("-tls13secretcb\tEnable TLS 1.3 secret callback"); + if (WolfSSL.MLKEMEnabled()) { + System.out.println("-pqc \tKey Share with specified " + + "post-quantum algorithm only, e.g. X25519MLKEM768"); + } System.exit(1); } diff --git a/examples/README.md b/examples/README.md index 3572a7c1..5fe1209d 100644 --- a/examples/README.md +++ b/examples/README.md @@ -111,6 +111,116 @@ This will write out generated CSRs to the following directory: examples/certs/generated/ ``` +## Post Quantum (ML-KEM, ML-DSA) with ServerJSSE / ClientJSSE + +wolfJSSE supports TLS 1.3 post-quantum key exchange (ML-KEM / FIPS 203) and +post quantum certificate authentication (ML-DSA / FIPS 204) when native wolfSSL +has been built with `--enable-mlkem` and `--enable-mldsa`. To additionally +enable the pure (non-hybrid) `ML-KEM-512` / `ML-KEM-768` / `ML-KEM-1024` named +groups, native wolfSSL also needs `--enable-tls-mlkem-standalone`; without it +the PQ/T hybrid groups (e.g. `X25519MLKEM768`, `SECP384R1MLKEM1024`) still +work but the standalone groups are rejected at the native layer. + +**Native wolfSSL version requirement (ML-DSA cert auth):** the ML-DSA cert +authentication path requires native wolfSSL containing PR +[#10310](https://github.com/wolfSSL/wolfssl/pull/10310), which added ML-DSA +SPKI / PKCS#8 DER support to `d2i_PUBKEY` / `d2i_PrivateKey`. That PR landed +after the wolfSSL 5.9.1 release tag, so a post-5.9.1 stable release is required. +The ML-KEM key-exchange path works fine on 5.9.1, only ML-DSA cert auth is +gated. On older native wolfSSL the handshake will fail with an +`SSLHandshakeException` (typically `error code: -125` on the verifier side and +`-313` on the peer). + +The `ServerJSSE.sh` and `ClientJSSE.sh` examples can use the `-pqc ` +option to specify a PQC named group for TLS 1.3 handshakes. + +A PQC TLS 1.3 handshake can mix and match two independent pieces: + + 1. **Key exchange** -- pass `-pqc ` to use a post-quantum or + PQ/T-hybrid named group instead of the classical default. + 2. **Certificate authentication** -- pass `-c` and/or `-A` to load ML-DSA + entity keys and roots instead of the classical defaults + (`server.jks` / `client.jks` / `ca-server.jks` / `ca-client.jks`). + +The three subsections below show each common combination. All three +require `-v 4` (TLS 1.3). + +### PQ-Hybrid Key Exchange with Classical Certs + +To use classical RSA/ECDSA certs and only switch the key exchange to a PQ/T +hybrid group: + +``` +$ cd +$ ./examples/provider/ServerJSSE.sh -v 4 -pqc X25519MLKEM768 +$ ./examples/provider/ClientJSSE.sh -h 127.0.0.1 -v 4 -pqc X25519MLKEM768 +``` + +Other supported `-pqc` named groups (build flag dependent) include: + + - **Pure ML-KEM (standalone, requires `--enable-tls-mlkem-standalone`):** + `ML-KEM-512`, `ML-KEM-768`, `ML-KEM-1024`. + - **PQ/T hybrids (default with `--enable-mlkem`):** `SECP256R1MLKEM768`, + `SECP384R1MLKEM1024` (CNSA 2.0 level), plus the OQS-assigned hybrids + `SECP256R1MLKEM512`, `SECP384R1MLKEM768`, `SECP521R1MLKEM1024`, + `X25519MLKEM512`, `X448MLKEM768`. + +See `./examples/provider/ServerJSSE.sh -?` for the full list at runtime. + +### ML-DSA Server Cert Authentication + +To replace the classical server cert with an ML-DSA cert, pass an ML-DSA +keystore via `-c` (entity cert/key) on the server, and the matching truststore +via `-A` (trusted CA) on the client. The client still uses the default +classical `client.jks` for client auth: + +``` +$ ./examples/provider/ServerJSSE.sh -v 4 \ + -pqc SECP384R1MLKEM1024 -l TLS_AES_256_GCM_SHA384 \ + -c "../provider/server-mldsa87.jks:wolfSSL test" +$ ./examples/provider/ClientJSSE.sh -h 127.0.0.1 -v 4 \ + -pqc SECP384R1MLKEM1024 -l TLS_AES_256_GCM_SHA384 \ + -A "../provider/ca-mldsa87.jks:wolfSSL test" +``` + +### Mutual ML-DSA Authentication + +For mutual authentication with ML-DSA certs, ServerJSSE verifies the client +by default, so just add `-c client-mldsa.jks` on the client and the shared +truststore (`-A ca-mldsa.jks`) on both sides: + +``` +$ ./examples/provider/ServerJSSE.sh -v 4 \ + -pqc SECP384R1MLKEM1024 -l TLS_AES_256_GCM_SHA384 \ + -c "../provider/server-mldsa87.jks:wolfSSL test" \ + -A "../provider/ca-mldsa87.jks:wolfSSL test" +$ ./examples/provider/ClientJSSE.sh -h 127.0.0.1 -v 4 \ + -pqc SECP384R1MLKEM1024 -l TLS_AES_256_GCM_SHA384 \ + -c "../provider/client-mldsa87.jks:wolfSSL test" \ + -A "../provider/ca-mldsa87.jks:wolfSSL test" +``` + +### Example Keystores + +Example ML-DSA keystores can be found under `examples/provider/`: +`server-mldsa{44,65,87}.jks`, `client-mldsa{44,65,87}.jks`, and +`ca-mldsa{44,65,87}.jks` (password `wolfSSL test`). The server and client +entity certs at each level are signed by the same root, so a single +`ca-mldsa.jks` truststore validates both sides. + +JKS paths in the examples above are relative to the wrapper's working +directory (`examples/build/`). Loading the ML-DSA private keys from a JKS +requires JDK 24 or newer (JEP 497). To regenerate the keystores, run +`./examples/provider/update-keystore-pqc.sh` (also requires JDK 24+). + +### CNSA 2.0 Compliance + +CNSA 2.0 (NSA Commercial National Security Algorithm Suite 2.0) mandates +TLS 1.3 + ML-KEM-1024 (or a hybrid containing it) + AES-256-GCM + ML-DSA-87 +cert auth. The "Mutual ML-DSA Authentication" example above (level **87**, +`SECP384R1MLKEM1024`, `TLS_AES_256_GCM_SHA384`) is the full CNSA 2.0 +recipe. + ## Support Please contact the wolfSSL support team at support@wolfssl.com with any diff --git a/examples/Server.java b/examples/Server.java index dec0f21c..8d06165b 100644 --- a/examples/Server.java +++ b/examples/Server.java @@ -76,6 +76,8 @@ public void run(String[] args) { int sendPskIdentityHint = 1; /* toggle sending PSK ident hint */ int useDtlsCid = 0; /* use DTLS CID extension */ + String pqcAlg = null; /* PQC named group, -pqc */ + /* cert info */ String serverCert = "../certs/server-cert.pem"; String serverKey = "../certs/server-key.pem"; @@ -206,11 +208,24 @@ public void run(String[] args) { } else if (arg.equals("-cid")) { useDtlsCid = 1; + } else if (arg.equals("-pqc")) { + if (args.length < i+2) { + printUsage(); + } + pqcAlg = args[++i]; + } else { printUsage(); } } + /* PQC named groups are TLS 1.3 only */ + if (pqcAlg != null && sslVersion != 4) { + System.out.println("-pqc requires -v 4 (TLS 1.3); PQC named " + + "groups are TLS 1.3 only"); + System.exit(1); + } + /* sort out DTLS versus TLS versions */ if (doDTLS == 1) { if (sslVersion == 4) { @@ -267,6 +282,29 @@ else if (sslVersion == 3) { /* create context */ WolfSSLContext sslCtx = new WolfSSLContext(method); + /* Single -pqc group, restrict the supported_groups extension to + * the named group and pre-generate a TLS 1.3 key share for that + * group per-session below so handshake completes without a + * HelloRetryRequest when the client picks it. */ + if (pqcAlg != null) { + int pqcGid = WolfSSL.getNamedGroupFromString(pqcAlg); + if (pqcGid == WolfSSL.WOLFSSL_NAMED_GROUP_INVALID) { + System.out.println("Unknown -pqc group: " + pqcAlg); + System.exit(1); + } + System.out.println("ML-KEM enabled: " + WolfSSL.MLKEMEnabled()); + System.out.println("ML-DSA enabled: " + WolfSSL.MLDSAEnabled()); + System.out.println("ML-KEM legacy IDs accepted: " + + WolfSSL.MLKEMOldIdsEnabled()); + + ret = sslCtx.useSupportedCurves(new String[] { pqcAlg }); + if (ret != WolfSSL.SSL_SUCCESS) { + System.out.println("Failed to set -pqc group " + pqcAlg + + ", ret = " + ret); + System.exit(1); + } + } + if (usePsk == 1) { MyPskServerCallback pskServerCb = new MyPskServerCallback(); @@ -444,6 +482,22 @@ else if (sslVersion == 3) { /* create SSL object */ WolfSSLSession ssl = new WolfSSLSession(sslCtx); + /* Pre-generate TLS 1.3 key share for the -pqc group so the + * server can respond immediately if the client picks it, + * completing handshake without a HRR round trip. */ + if (pqcAlg != null) { + int gid = WolfSSL.getNamedGroupFromString(pqcAlg); + if (WolfSSL.isPQCNamedGroup(gid)) { + ret = ssl.useKeyShare(gid); + if (ret != WolfSSL.SSL_SUCCESS && + ret != WolfSSL.NOT_COMPILED_IN) { + System.out.println("useKeyShare failed for " + + pqcAlg + ", ret = " + ret); + System.exit(1); + } + } + } + if (usePsk == 0 || cipherList != null || needDH == 1) { ret = ssl.setTmpDHFile(dhParam, WolfSSL.SSL_FILETYPE_PEM); if (ret != WolfSSL.SSL_SUCCESS) { @@ -799,6 +853,10 @@ void printUsage() { System.out.println("-P\t\tPublic Key Callbacks"); if (WolfSSL.isEnabledCRLMonitor() == 1) System.out.println("-m\t\tEnable CRL directory monitor"); + if (WolfSSL.MLKEMEnabled()) { + System.out.println("-pqc \tKey Share with specified " + + "post-quantum algorithm only, e.g. X25519MLKEM768"); + } System.exit(1); } diff --git a/examples/certs/gen-mldsa-certs.sh b/examples/certs/gen-mldsa-certs.sh new file mode 100755 index 00000000..577227bc --- /dev/null +++ b/examples/certs/gen-mldsa-certs.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +# +# gen-mldsa-certs.sh +# +# Generates ML-DSA (FIPS 204) test certificate chains for the three parameter +# sets: ML-DSA-44, ML-DSA-65, and ML-DSA-87 (CNSA 2.0). For each level produces +# a self-signed root CA plus a server entity cert and a client entity cert, +# both signed by the matching root. +# +# Output is always written to examples/certs/pqc/ (the script's own +# directory + /pqc), regardless of the current working directory. Each +# level produces: +# +# pqc/root-mldsaN.pem, pqc/root-mldsaN-priv.pem, pqc/root-mldsaN.der +# pqc/server-mldsaN.pem, pqc/server-mldsaN-priv.pem, pqc/server-mldsaN.der +# pqc/client-mldsaN.pem, pqc/client-mldsaN-priv.pem, pqc/client-mldsaN.der +# +# Run from anywhere, e.g. from the repo root: +# ./examples/certs/gen-mldsa-certs.sh +# +# Requires OpenSSL 3.5 or newer (native ML-DSA support added in 3.5). +# Verified with OpenSSL 3.6.1. +# +# These certs are not pulled from upstream wolfSSL because the wolfSSL +# certs/mldsa/ directory ships only raw private keys (mldsa44_priv-only.der +# and friends), not PKCS#8-wrapped keys or X.509 chains. Once wolfSSL upstream +# adds ML-DSA chain generation, this script can be retired in favor of +# update-certs.sh pulls. + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +OUTDIR="$SCRIPT_DIR/pqc" +mkdir -p "$OUTDIR" + +# Verify OpenSSL knows about ML-DSA-44 before doing anything. +if ! openssl genpkey -algorithm ML-DSA-44 -out /dev/null 2>/dev/null; then + echo "ERROR: This OpenSSL build lacks native ML-DSA support." + echo " openssl version: $(openssl version)" + echo " Need OpenSSL 3.5 or newer." + exit 1 +fi + +# gen_chain +gen_chain() { + local level="$1" + local prefix="$2" + local alg="ML-DSA-${level}" + local out="$OUTDIR" + local subj_base="/O=wolfSSL/C=US" + + echo "=== Generating ${alg} cert chain (root + server + client) ===" + + # Root CA: self-signed, valid 10 years, BasicConstraints CA:true + openssl req -x509 -newkey "$alg" \ + -keyout "$out/root-mldsa${level}-priv.pem" \ + -out "$out/root-mldsa${level}.pem" \ + -days 3650 -nodes \ + -subj "/CN=${prefix} Root CA${subj_base}" \ + -addext "basicConstraints=critical,CA:true" \ + -addext "keyUsage=critical,keyCertSign,cRLSign" \ + 2>/dev/null + openssl x509 -in "$out/root-mldsa${level}.pem" -outform DER \ + -out "$out/root-mldsa${level}.der" + + # Server entity cert + openssl req -newkey "$alg" \ + -keyout "$out/server-mldsa${level}-priv.pem" \ + -out "$out/server-mldsa${level}.csr" \ + -nodes \ + -subj "/CN=${prefix} server${subj_base}" \ + 2>/dev/null + openssl x509 -req -in "$out/server-mldsa${level}.csr" \ + -CA "$out/root-mldsa${level}.pem" \ + -CAkey "$out/root-mldsa${level}-priv.pem" \ + -CAcreateserial \ + -out "$out/server-mldsa${level}.pem" \ + -days 3650 \ + -extfile <(printf "%s\n%s\n%s\n" \ + "subjectAltName=DNS:example.com,IP:127.0.0.1" \ + "extendedKeyUsage=serverAuth" \ + "keyUsage=critical,digitalSignature") \ + 2>/dev/null + openssl x509 -in "$out/server-mldsa${level}.pem" -outform DER \ + -out "$out/server-mldsa${level}.der" + rm "$out/server-mldsa${level}.csr" + + # Client entity cert (for mutual auth tests) + openssl req -newkey "$alg" \ + -keyout "$out/client-mldsa${level}-priv.pem" \ + -out "$out/client-mldsa${level}.csr" \ + -nodes \ + -subj "/CN=${prefix} client${subj_base}" \ + 2>/dev/null + openssl x509 -req -in "$out/client-mldsa${level}.csr" \ + -CA "$out/root-mldsa${level}.pem" \ + -CAkey "$out/root-mldsa${level}-priv.pem" \ + -CAcreateserial \ + -out "$out/client-mldsa${level}.pem" \ + -days 3650 \ + -extfile <(printf "%s\n%s\n" \ + "extendedKeyUsage=clientAuth" \ + "keyUsage=critical,digitalSignature") \ + 2>/dev/null + openssl x509 -in "$out/client-mldsa${level}.pem" -outform DER \ + -out "$out/client-mldsa${level}.der" + rm "$out/client-mldsa${level}.csr" + + # Cleanup OpenSSL serial-number file + rm -f "$out/root-mldsa${level}.srl" +} + +# ML-DSA-44 / Cat 2 -- baseline PQC signatures +gen_chain 44 "ML-DSA-44" + +# ML-DSA-65 / Cat 3 -- balanced signature variant +gen_chain 65 "ML-DSA-65" + +# ML-DSA-87 / Cat 5 -- CNSA 2.0 mandated parameter set +gen_chain 87 "ML-DSA-87" + +echo "" +echo "=== Done. Files in $OUTDIR/ : ===" +ls -1 "$OUTDIR"/ | grep -E "mldsa(44|65|87)" | sort diff --git a/examples/certs/pqc/client-mldsa44-priv.pem b/examples/certs/pqc/client-mldsa44-priv.pem new file mode 100644 index 00000000..6dda6d47 --- /dev/null +++ b/examples/certs/pqc/client-mldsa44-priv.pem @@ -0,0 +1,57 @@ +-----BEGIN PRIVATE KEY----- +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 +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/client-mldsa44.der b/examples/certs/pqc/client-mldsa44.der new file mode 100644 index 00000000..830f24b4 Binary files /dev/null and b/examples/certs/pqc/client-mldsa44.der differ diff --git a/examples/certs/pqc/client-mldsa44.pem b/examples/certs/pqc/client-mldsa44.pem new file mode 100644 index 00000000..1bc7a94d --- /dev/null +++ b/examples/certs/pqc/client-mldsa44.pem @@ -0,0 +1,87 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/examples/certs/pqc/client-mldsa65-priv.pem b/examples/certs/pqc/client-mldsa65-priv.pem new file mode 100644 index 00000000..757f7bfd --- /dev/null +++ b/examples/certs/pqc/client-mldsa65-priv.pem @@ -0,0 +1,88 @@ +-----BEGIN PRIVATE KEY----- +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 +exwkdpQdSS7I/VN3QtRtfkAM +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/client-mldsa65.der b/examples/certs/pqc/client-mldsa65.der new file mode 100644 index 00000000..5ac1deb4 Binary files /dev/null and b/examples/certs/pqc/client-mldsa65.der differ diff --git a/examples/certs/pqc/client-mldsa65.pem b/examples/certs/pqc/client-mldsa65.pem new file mode 100644 index 00000000..18248b6c --- /dev/null +++ b/examples/certs/pqc/client-mldsa65.pem @@ -0,0 +1,119 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/examples/certs/pqc/client-mldsa87-priv.pem b/examples/certs/pqc/client-mldsa87-priv.pem new file mode 100644 index 00000000..e7cdb62a --- /dev/null +++ b/examples/certs/pqc/client-mldsa87-priv.pem @@ -0,0 +1,106 @@ +-----BEGIN PRIVATE KEY----- +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 +u4WDwr9Pyb+mjWrATs5IxqWU +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/client-mldsa87.der b/examples/certs/pqc/client-mldsa87.der new file mode 100644 index 00000000..a387f89e Binary files /dev/null and b/examples/certs/pqc/client-mldsa87.der differ diff --git a/examples/certs/pqc/client-mldsa87.pem b/examples/certs/pqc/client-mldsa87.pem new file mode 100644 index 00000000..0581a94e --- /dev/null +++ b/examples/certs/pqc/client-mldsa87.pem @@ -0,0 +1,160 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/examples/certs/pqc/root-mldsa44-priv.pem b/examples/certs/pqc/root-mldsa44-priv.pem new file mode 100644 index 00000000..5be57920 --- /dev/null +++ b/examples/certs/pqc/root-mldsa44-priv.pem @@ -0,0 +1,57 @@ +-----BEGIN PRIVATE KEY----- +MIIKPgIBADALBglghkgBZQMEAxEEggoqMIIKJgQgbw06GM5T3l1fFhPGLwIwxGPw +XZIBeSkmRjYXd476KIcEggoA1Xg0v7qSxLUqpWUIy0zdncscE8rCCCbcbbSOD7C3 +X810YwGlabCxtVyxRqqZ/apEDQAmT9XiOcS9jCIgxTsTtdxrjx8aLpe7RwQS6v36 +n20PALNG7nC/CdAGEEknDHWiW7sMp2/9OQVFmEaBGoGekJ396ezpQjjDcTjUhlND +0nuJEoDBMEDSAgZESCIIlGRiJEpjIIIMFIFRNJIKGA0jCAkLOG7CKASkIgHUOGkg +InEbQkIKkkABKUlRSCkgMoUcIYJBAiEDB4SDkGHiIHGIGG6SlEkQRRIhOTAcJCGR +BolCGEjLoAhEGI2kOIYJJkBRtCSkqHEAk5ERuEhamI0EEUzhQI6SIlCDtIxhGI6k +CEhSREJkFI5UsigbRgkYBAQLkEgRoVBTwAlBKInEEGLaGEUAES5YRm3aRiAklWwh +mAELtSgKlo0DM4jMxhCAEGCJpmBSsgzMIjHZRhCTyEkYlm1ZGAQCsiFEMgSBpmBC +mIjkBFJjgiVkpDFcNjAMQkxbOGwkSIrhSJCbNkHAFEYIBkIKoVFZAAkaJ3GYRGFi +xiRKEmxjsgkQyTHTMIpiII4Qg4QjFwzEsEwMRoqRiCgUtm0RBjEhRiWhIEahIowc +MQBJQghQmCCblJGLMpADskSiSC4aIgwSohGSSCkKgHAEkowMAEGLBEDQNo3QhoSK +lEWICCiatg3ZIEQjRiaTRJJRNIoJIEwJoIkLGJFZQClSNkIBlgXEgAgAFUhRxpEK +NECbmJBItGAQOSISSQTBgiyAxITKok2RFAqBQGWApoVAoARgIpGYMg0ABQ4aR07c +BC1QIAEhwXFDyJEQGEIDIkojkCBEsAQbJkaDFIyTGGwiJS0YBGIEyISMQCAIFlGc +KI7kMHBEhEwRo3ERNyoJOS0ImRFbNmFIOEAIoQQSyBAUECiMiCHTMk1jRArJpgFk +kgTACG0kh4BauABiRo0ShiRgFkShxEmkggEhIkKjFiTjGEgaKW6jNCCMNGISQkEM +JlBJRoTaEi7hNiGZMhIJyEVUsgWYAA5LBIrkQkLbgk0ARQbEuAhkBACLuATDuI2b +ppHIFoKUpBBMyIwUqFDKEDGTQCJUFmGEkgwiRE6gskQkMyXixjCJRkwYMZDQommD +uGliBCicNEBKJk4as5BMyIgJM5CkCAAQJQxKiEBAJkwTAI1ERpEalwxJhA0EoTEM +pSSubZMY5u5kl5kNli4Zd/BIHUxiykIGISVQEkxSReodAUj3TDgTn+B75IkxuUu1 +TlfvsLsG4scOAHtzhsYrLL8mB7AXtIWqtTo9xHsHeeHeEP/VeRCZM2vo2E1kTg2B +hJB5DSDshERu+aPOdYoY6ZiOY5dFoHjM8LARzgwjk26uH+zH3g947An8XSa8nWw2 +RYUHQbeungnh/0rKJ/QC/gQo9vrPqU7MHPRYsK2R3bJ2hD/i4Woxi7rQy48DrFNt +FWl4KIdfrll8xMwrV+kR9jXfz8nOSF4ubuS/ADYKcT+cFx3P9mxlczK4sXXYWQSJ +1sBPG+Y9eDdKZ2iJvx/su35RPxJdvdxT8i6YjS0GMUau60JTZOmkuJGAjjcVV1Nx +Ru8nsc2wORtlZhJBbz2DnDXD3N2oRO0n2KXpleKg/dM3QrYv9Z9LJLufFqP+xaOh +dkdXSiapLa/iOhzlUet+4nF9BUEzQUHxJhr5OTwqdcwMg1KplmzCTcs8pw3g33id +6uXSIHMM+rZFHb9WHn7NgUy3gyY8W+KAcosspO94t+6FeBHLxoJBfqfXJN4rE4mZ +yF7ofIp9dRt0R6emwamBQfOkk9iFnKMUyPG2JfKXa6hWJcQOqXs/jeT5Urwsdg5Q +B/CH73Zoyfc2uHYyiurCeHCFQI45j1MIDj1WCHpMVmeJA5kSre0Feu3+epTuEaTi +Ot4zi8q0h/jxMSw7aFrL7lg2lGhZqlJCWe6UeOaLNOLCdmSmZRik5JzzD+zvmWy3 +qwpS+7Pc0V/qtBaG+iTRkjK33yByKFCjOlBrIU2D2RAnVi0SWPV+67qAaED4TP/a +pZMeEz6lSBXLhUimc0SfZXo3uzflWefabbvqxFXgpr7XHDEbWjRFOnEh3n7c/S8g +McFbhcD29HZu0AJ+yCDsN6jTiZ14EGJkQm+G2aERLDa6VFiYgoVzKkYy8gRSLgpP +qh+GPU35il7DsoqqMUxZIiI0g1SRd+9B4BEoA5VSUCbJZnjORDZeYPkSqt6IB70m +tolO2a9WKI27UYhfE3NgqbfxL399KTHjEIQMxon1SD0DTCSsnAPsFbmPcbd2GJSh +OyIMXZNZFOWcQLOnGxtlBzjmcNzOaS1G09Fbv9cqN4eFyJEq/s7SsfP4aGtq8HHf +CLxhTsW3o274g5xz1z5D158Td9IQeY0YCLCaU9UmRrHYhtyT2P8+qmCCsv9CTQrs +pGaBn/A+iwpfzVl4pri09Xs6/3HQSIpZ423LNfCG2PtntdKdIn78M2NiAynIamTo +ypgjbVX14kwpcQP6y/dYmM+pGLoWxmpFgtuAvByKXU9yqmJhyUpimR0PleQUQYRi +KU0gJjw7fMxKEvakOYWjaj2SFhxyy2Un2/vgkilys10vGe8jy3vccjoBDpOaJsjS +QBCgLeMP030B7/WdPTN+/k9Knxg0qW6i2NG6brB3e6uWuuJon2nZr7h+t4KdQes4 +d4M1psvS+x3DhCB1kNsXKZp9nUxDtazBi1ZhZ6KHZg0yGO9rcxA3xIxhrFNDVVP+ +B6QkD9h2xMYg9DThNfUc2Il18F5CJhrmrdMg59UFXg23cEac1hsY8/6j5QxNzdnh +KdiKo4xzv8dBM/SVcua+6qss0QptDCcOsYqKhI/kQAzCbkti04ztCu0ZjW0lNAFZ +VEsfTaGfn5UYMeIwKQdDOIEA2ZGeG7sG2WHhdP4cZaUlxuw65xhbig8a01wiAERD +A7Dq0XAp27X1YN0rFyRijoh8q7orJrfozcWSrSmaoE/vJN4KJ6jqEGjjNyCeYLJw +uzk4cUftJ/qj1g249JrQVvL0mvl+IF9w37USHrANxi9F98i6FWm9FxSVxVzEYllA +5518jAjqH6sso+SfPQNgxuCwLzHdrTx/kz6OFJF/T1BTDeJIskebGBkI8GIRKSSR +R5dnZQC4AIGJLmig7WuQxlfzcR8DXjfSIKdQ2IM4/ycoK8O2yUuy3/s1H7NqEyKb +NCADdGGhftga93Ri3itWxJN6bWHGc6/IwvVUh2fWwTFMmmJ6RpcnRwStBxPMsUP+ +iT5YPi7V7sDJNF3m1txGrk8n7wB90xhQ3Py6gAimqLwpuZLac9T5zyoJKS5J31fX +ZWssNKmVDb3c6Q3NVKIug8J8kSTIjyX/bqH+Wo2iPU1IOl7oTUxEQVGKN7DMiVLC +FvPiZ1Rc5kuTzuNEdN8CHixTW1dbvW3dwNqsecw4A7Bwwg== +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/root-mldsa44.der b/examples/certs/pqc/root-mldsa44.der new file mode 100644 index 00000000..ba4ebae6 Binary files /dev/null and b/examples/certs/pqc/root-mldsa44.der differ diff --git a/examples/certs/pqc/root-mldsa44.pem b/examples/certs/pqc/root-mldsa44.pem new file mode 100644 index 00000000..a4d67f4f --- /dev/null +++ b/examples/certs/pqc/root-mldsa44.pem @@ -0,0 +1,87 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/examples/certs/pqc/root-mldsa65-priv.pem b/examples/certs/pqc/root-mldsa65-priv.pem new file mode 100644 index 00000000..9cc1390c --- /dev/null +++ b/examples/certs/pqc/root-mldsa65-priv.pem @@ -0,0 +1,88 @@ +-----BEGIN PRIVATE KEY----- +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 +Y8HyB3J+PNwK519X9qy2Zmtl +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/root-mldsa65.der b/examples/certs/pqc/root-mldsa65.der new file mode 100644 index 00000000..d192090a Binary files /dev/null and b/examples/certs/pqc/root-mldsa65.der differ diff --git a/examples/certs/pqc/root-mldsa65.pem b/examples/certs/pqc/root-mldsa65.pem new file mode 100644 index 00000000..73784725 --- /dev/null +++ b/examples/certs/pqc/root-mldsa65.pem @@ -0,0 +1,119 @@ +-----BEGIN CERTIFICATE----- +MIIV4DCCCN2gAwIBAgIUH6IMsMcyq5y0EaTvMaFJS5HwrnEwCwYJYIZIAWUDBAMS +MDsxGjAYBgNVBAMMEU1MLURTQS02NSBSb290IENBMRAwDgYDVQQKDAd3b2xmU1NM +MQswCQYDVQQGEwJVUzAeFw0yNjA0MjIyMDMzNDhaFw0zNjA0MTkyMDMzNDhaMDsx +GjAYBgNVBAMMEU1MLURTQS02NSBSb290IENBMRAwDgYDVQQKDAd3b2xmU1NMMQsw +CQYDVQQGEwJVUzCCB7IwCwYJYIZIAWUDBAMSA4IHoQCRmzrycLMW1AvD9gbNK/Ud +j8HPigaKMQh9ejGCNanFkeD4cnmTrrpRZzb4DDK7KfTJ0pOSttJ+rWwWZHa56b1h +jaE1VZKdf1JUjr4xZV7XfMpjBhoWD0LpoRx9lJLkSwu4mtnZmLZpHHbSI0SAaJaU +swuVnsnADTWsoLTyJxS9USN2vmqXWQxW0314AAiR6u2WfrERzOCem0oete0mh+OW +42/W74adAYqKe/Y9jIUBjmdCo7lPUGlxdgGDSlt3X2O2d8P/0dmIN33WMWgFIYYH +7a6xDJ/eEWaWQWL2onkB0KkVYRECZSiajjU0aAeDUPMPXj1CaQm7sM07n8tBj+k7 +3LWPI9t2103JzJLfkE3SUUKJJwJRBlQxm5SDBfNWLk40FN6+/c0u5vpArwSDafGt +JoJRqvCMBsy4GNFoC+CLcspNkykNQ/M3bzfa782Cn1K3+8794kg0vugrilUDJS+1 +Vkg4ZIwh8CIad1t3zXjrTxj+lYfwcmK6okLe0g5H7AjWdnWRpZM8MOQDY58rwHX5 +mIQlMneGjQT9Xn3/GMQgjKhDKdobJq3SLbpcY7dCg5+VkJMcljNMb8OPSmvdKlbb +lhdPWAuxrmorBFxdoBoTqmT2+LBYGFQAyc31T7UN7auu77eXgTAKvY+Qpe7Ha0W6 +q/ZM9PaAAQ8OGHbkSS1SW3F9uXRsU/dPNzBgBtn3oeCm29C1c01RtGIC4mHbkoKT +oNfeXR/NGyDqgEd9DLCgX0euoX5KaG2CZbRnXYCwB5rUwBFkFOaDg/qoRkkv5+XZ +qY/G52Ab3ry64+C82SDKSJDNEGJpmRg5c7rX8zafy4mskbIuGsKop6ZcC/YAwSvd +7bq6ePwb19z7QhuXV9Q4AD/lktSgWYVIgI45YTTW8K57C0U1snS6PKAycH3D0uVQ +6YlwzvgEOFrwYifNLU15hoqFfCvJzjymiJOTpbQpgmxTiX4XD13rqAO9ttG/H6eM +Be6U/Hti/CXqT8EzyZnQlh50VrK1JvFlDr1Ppajp04XO6sRlxsZwBGAu+JKN41vV +weIjeDt6A3YoKvgbXXyw490LAwdSDR4XawJBWw4kDvRFAz9fG188L50TT8KbrSkE +v4zf2zINwPOwAw3UOTGICP7ymeG15desYtn87UVJo3XhgCoEbJVW1MYGN4SV7fj9 +3Jdog/jVxGvM/NpMg2dW6/esBZgoCheV0oR7HbTO945eehe+Coc0xSf/ZPNHwpyr +GAvvloXDODo85vCl4FZroSBvn+pQ5tYTpbpI6JeLHpF6QkBdBqFmUHjfjYgMSALj +i1D00HdzWYtAxXgwC2260B9TRRAdG1FKCc1ReuBK/lEcBv+kG5zOEorICXZhfQ+G +AwxfihGcRJYHzUs1TjgRxZdcwk/4aAsUUiO16tV1w9Au9dJzSIJCrfBP+gf8o4NL +5mji3Nczfqil87QoVr/8n/0sgD8On71JC8sQvV+9vq5Y54eUAAKt1DibYCmKsc/R +DJRPHjOfHvzZsXXyYfF1Fiml0X+i6UlkEGxd17cITV7xPNWEdBT6LNji1gt6CPoo +GDrVyXeDy2e2uA9lSQ2o2kaCbWQzOKHaZNRVxJdN8LrKkXDJXLR8jab9wY/onA/S +D9BZcvQNx3Eks7hYrIijRmIqJ3p5Ob8J8bnwqxQ4FjkMzRsC6bN4Th6Ew/9flD8A +KxLiWOnc4KbW/Q4WLyBEdi3g7OqzQnCJ+94R13D3bvm1DBlZBXWo4I+BgfpaV7nM +W88Vixdd/Z0rW5RBsPjaSuBXe+rlqmHkLlK+LpaQP2xgV2DYju6DDmWUqG4aSGV4 +/C7D8JGH7llyUHKG1iMKshvopaGptW6kXXLCnFBc9mn76HtjW1HIM/+6xUh0xxuy +tURUwM+8m0Q6f6DQ001Pyg9gztrwUwECRclGXCf1Mr93JKNLf/+897BjMcJQD9aL +vCiisyk0VPS7GP53rM7tGHRyTm5S3obTLlpLkbOqOi89fbAJ9WZyoP6MTyZlhN1g +NcUPIznOZR1kydyCsYlUmtq8fhkZwycnXTjVm9EXoNvoiAULu8pkbtiDD+5oo1cv +jpZkCh8b80AnkAnVdPfU3VenuWcnj8eq07l5Q+0ZXYb5rfqdCxjzycxt6ov4w+Xa +U1ADKfrC6eg8EsvAGSAIIBVFgicczjVSlmqS3dW4bgX6RrcAcVhOZvzmZFTrrOp+ +IvyWr96K6hgUHT+wIWNWQcbVVN9hk8JzCmUnfag0nIgfe4WKBMpsOF3eAgoKTX0O +VB00P9aZkNkOuLdRLk2fuSdN9i0EnCuPn2Y28RbWA5PTn9NerppwAQClli28F2T6 +TSN5zrvV4fe6z4ReGFWUrzd1Q2gNRnH6eZSI/NfqDBkvivovNpAUL0ct5dQU2wdQ +x8zQIgwT1sr3kZJcggDPh9AXh88r+btgayfLtffSvzAbp9vaS275XPdaeHMqpJFi +r4zNQBys626BdzyA6mh/TuRa7nBUi2cToRrlyhGX3AfeNtPJGHrvnT4FveMlB2Mz +IK6LDFXGrFtfwagaB8Ix1Nju6QXtrY/FZa1aOVX1L8naTrW5E0QzqlnKyzDWbtcv +zJ93DEryVeP8sIb8LKk/gaNjMGEwHQYDVR0OBBYEFGSHjXPXszSwVyJaJhG8RQbL +FS99MB8GA1UdIwQYMBaAFGSHjXPXszSwVyJaJhG8RQbLFS99MA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMAsGCWCGSAFlAwQDEgOCDO4ATHyo7C+uk5Gt +kOqUq6eaUZtFNyg3/V9nvPIdumkls1QGEmrlxZiQFks+6RwZzbqqnxVsEZMAjYqt +7FkxSvRpuPgjkn8QkDLGBElxq4MpVV5SJKKRC1Nu/INveQ56a0UFLKR9YhK7bY3Y +r60Pdket9MiPX0RxDuAN6KEw2M/ha/oy7O5m9ETN//NldfzDuETHbTUtYABUqhDC +fiK8XY8D4JLapYUkUlxcl+0iEiwGwAmyee+z1/4W3ZZbHQ3VrEslh9DkBU/Y/YcL +EHf2mFn5pKmrn79YmN3TLsQGRaVg6/PWSlFOfCNrHM0U5Bp9K/0ShN2v7sBhzOfp +Axx9yNtG4iFApalggrykMmULOY38MD7NT8uhL4swW8N746tt3uP9umbiIEzBzHHy +846tnvHDnut3uUVfBw9UrU8P+l7jN4c1Qf9tlCdDVdD1XuW8uy/PGk1tXLct9Sqy +QrzMYLlrdHsiaOAGzthINuKa8VarEwSdHiQEUmfzGHajLT5vwWv2DGVmjlYtRYvM +BkM/5P1yY9hUf1uPWrTaZmHykXRQ5tUrhfB5aUHLA96HqeSkxvcSezUKsopuFF7u +FrI9fw5zvI3YGMqYNMkfGSMWwKVU9iKDl2eZXGnkqM1MEkSnoMRmgr1q5fi/JceP +F5zcDgW1QEi5v2o2WpoGAPWDX77+WeDBUHRpREnDEdJQGieL94jqxo2AZXpLyDT6 +8T/oLbW4nJmoiXzZQj/396YJc0sPDoS0jwIceeCa0ei7zr8q4STfatQK6xuj6T5n +fB5+cSkHf1YTx+DkpeJudYWZLFOtJmEm3UFtcmjY28/ScjkTrNAmFO62UA9RDZaN +qo4ROSOd6h3c0+spuQ4iorpskEDZOK1xbnQtd5WeY6FgXDYV+QnU0jvvZymP1oEh +9Jr3Yi/vIYABOTIWHBwaUqEg2luO3vm4w2P6oHivbuXnftbK8YnNFu7DgT65yZ7N +jZS8dZFfve5E/3TvIHzf57r31KXqjTZRMLym/EZEwgOIRCWriJ3Nrkl7dUdLbu0n +c15OzVCdoBTpDS8JiHfv6MlCSCzeK8VO5H/CVIWt6xWM2Z0+wPf7Ro092uFugjSb +nUsaTeI3IaRCwrmYr0EL0fyfUdqxUUUtQpZ+HRdkAtCrywp1nnqMGZHbViWYqG9i +vrQzRkCHW8wlaQ2xxJ3UExjNIKYwa5xOAlvVswKwmkC08AFha3+dbKue59npTeej +uPmxIVq+Pi4Bnwwv+yGMWmc0iiJBwDbCXSKfLcOeX0S3Is0jc4ov89oJc0gRw9Fy +GT9rEdz5x+t5RZ9zhkGf0OPgBQvIdAm7jcdu/jvQ0Urhhp07yqtS3DBD0FkKcxKk +IWAZofC13pLMGQd/XIiFkwYMe5RWnCC9KeYtIOPPvnJWNBB27Gfm1LNcyT7OEMVl +T+DBFphMRQ0Ki08q8R1hoQ+IaX2c8LNl69RbyaSBTbNqezRsrvSBfICY1YZmXNYl +HE71zoTDDP4ybJvKzYmB3meiFzgCwkcwAQGSgtURTzktF5ztpFDfrxo6Qif0GIxj +AzqOyIYcUgdJxlTQMmb3ml25WlGYVQbEPPSfX1QzoTfciUtL18OCRqwwVKZZPzPQ +7xcLxZT67A/zqvQrmMa8F11YfAAE5SZxl8wn4BwPhCaQ5S/XREp/PXyQ8NWI6o08 +6mFNKf3zerBBMexMJvA4cRp0QppzjUgXd/ANoTdK8opfC1274QBwychRmcVOfuC4 +arwOZbLdUIynEhhAZozDArCBOb8jPoWMmAgHmuviT70oGtZsytovueEAiYatgkUg +lTwXIpZmkvtrqqMaDIoMpxN26uNWEfPmtGvm81boluhHAfCpiByFJ2u28sB7tlSA +7vv3XJtRYrbnq32tSEOHfV2TWBwzgWvGhwUyAHIPX03QJnHMwAWLBaBJI91aKJju +JF2KtHWrOA9z4H3UzR0vjAaqStNIO2dkDb7QWcigAYfgTUe2sq/QFikbwOINhyI3 +jcnEJDiRlU72aDtEiGZqp2yvvo9VwmJ4sDVb++16b7d3yGuyy1SbHAWvMEoeL8BG +/po23IHPtKk05yt+ud4lW1KwufpbTEv4NJU/x2AXX4XEYXQaRmB95bpBaqPhF4Uh +9XKMpqjIzWIW5bEF1QZWbGvtQUb0gT/R/C7TtvDlhFfbFNLW3LrympIpfo4wMNQW +OgwO5U77bOR5HlS8Book9C1fzAm2tp47G54i6BNcJTQBN4ZG53lqyPAc50l7GqvR +eL6aumpzbiMqixVn16d4rUMTpnVEAvgQeoDjv2SJMdjqIRaEUb3q4Qc13czI4GYL +VjYIgT3l5B/lTksS1bmdQIOR3MUK+e5jDDWtdLtIttt/y+nniJkSa46heo+dItG3 +03Xy5zJGWw9op0d8aB6fmozQ3ALDmlkkpx3rVHbC+h9v0DtRskeI1KHqjl6CvaJC +U+DM2RNIcXFmAkd8Niu8rX1suY569Krev4PXGl8Mkv0jbPbsg3W4TrCH3X7rh/4t +owEtryxEleWyuaj94pZrpscYsswBMLkuDL6qvsmzOsMz09DFe2Iy+gbkJVWGOlqK +TZvPEpicOomxaLQh0zdleBTHBNJTx+kGvqbwzhbRBPith8BrKMwdjoNXLgFyJ2We +UA0Cho2dblVyxnJMIbPIgAz/nCgvIjYpo6d9dRbCjhqmkgTX/9Q46aQ+XI54mlqB +tv21e/hVA1fhZ31cN6FZpnIPHg7aWMsftHgUJzEMWtnVPGbiqW5W8GIjVPPIJ0ex +PvLgh6Fo+BG0RgZmB8LFt932HvZ/TqO0wZmz+6XdsHkErWnz+i361+1XAK9nLjUJ +g9ipTDjXUtgNzA/bMiyf8mpL/gybtFllQxV2wpnoyUd9RzcdedI1epPxB0u9nLQO +ovv9rH/Qr2BUo9eQGgq7h2Bwdlrefjv9X8+bRUvTuOY9IPPlKyquX3oGf0oSbs60 +IRFf10adY1snFjInkx796sD9wysZHZiSCWNMUmUdyvaDfPcXRARDS6QK6tTFzJ3g +vim0bH9jPMVibq2NPdT8xGdyBjmveLC7pCG8/CKbs8FjslFzdN2LTBizul8L79i3 +w+Er1/pvQnahVWrehru7XCQUnRXUZ/WBg+lV2lrppQJlrH8Y8K2zjU0t0U9rTYTW +CY5CVZeDgKpNuutUevtFBKjan6hOM6vhxNKMsCG46kaLz1dv4YXvmEXnQNFUMLsJ +gDVQbaGwsQ59mFRfRNE71MQOhpYj674zFSMayzl5JSk455B8tjt18ZXIQ7hNQ+Ar +3QvuNgvH2eIYAYYsu4TTGTqNkDBmbx4+iegBcDRvNGcGDa3lVpemkSa+uRgNI6PG +CSP1AY7zxSJoPHd/A39aNI8jpnvnAKumHFZXeU5q68zc+yXg1N2J5cev1A7uvLxt +GmAJQTEqaBTqxT7EYpRR+a2UGYAnnCeg6rI+WQsGoLZJ2l7AZHxtc7rr0+j4bMOk +1pyaNOLX6D7bwWUSKjVTrsLF7FCfN2SVA1UN4xZMhx7zEajQHuyUuDUC8HB8WIth +mwvyY0iTAZxoq0rSy5Nlb6s7bYRc7oU6zJ1nw469DwFrbsCLsYKKVLLFwhZ0G0pZ +oOFKCFjdgzc0VK6cJBSvmqvZGy5Ph2G0OeCDx+sEh3/EG5At4YmFF7n5nDMjPtS5 +k6aUfi7qykLS29NeQJZnuemYBUqs2clFcgTHR72pkonucCbpI5JGHm4x6eYWNlWB +1mW30cczlNUnUagCXycVT7pQ3eecrsO9Xb0BIGiPATLC010diBpxE+fiEJtU59BH +rgZYykzxzZIHyXu6eo0onKGVo0MfImlrdl2OrNhE6VN87QmT+zDteEi0Nyx3MkQl +D8ZEgeNwB4qkOeFTg4wnIWqCNqC2NOaAbzmEbQKVcWOB4JVG720qg/d27bYmWp4m +b2ekxvBhY/IA37AIlUVsN0wXLJ84AXbuCS7GHdhxJqYr085d5uykQ/JeVUADZsoO +dutJUYwyrAEtjyKiID7cYeGWOWpktM+fcfKVUXdRtENqv4UH5bLToz9rgzThs8nc +RUiCQ6tsDiQUwmekgU1BmziuF7lDWlojyGKjh/5+JMVX2zKZwd4TjS3bBo7K3IMV +vMqMgPubmszEhYZabaCwbAzzB4Fp/gzdbLaVIRqYlBULIzHRdqCiuk6MrdEByO5M +NCm3ZTd+Wp/be66IhrDihhgIh0R62mlLHFneVFQ9KpS/D4oo/tPOqudCiauvDh+q +jWrZRyjfe5GKc3Mbm4PTEEJR2t1C91zG4dkQLAV8zlxl+PPMiic6bDIhvchMs1ma +aluAo2ezeUOPY7eiBGG8dzKTSalgrSYDMlBocaPK2QYWPbHaJYOYPj9FY3OqrrBI +hJfEBLq98vX3AAAAAAAAAAAAAAAAAAAAAAAAAAAACA0QGBwi +-----END CERTIFICATE----- diff --git a/examples/certs/pqc/root-mldsa87-priv.pem b/examples/certs/pqc/root-mldsa87-priv.pem new file mode 100644 index 00000000..809aac4e --- /dev/null +++ b/examples/certs/pqc/root-mldsa87-priv.pem @@ -0,0 +1,106 @@ +-----BEGIN PRIVATE KEY----- +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 +2X5iuHoU64gAlCOqGevwaUQO +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/root-mldsa87.der b/examples/certs/pqc/root-mldsa87.der new file mode 100644 index 00000000..2d7a3a9a Binary files /dev/null and b/examples/certs/pqc/root-mldsa87.der differ diff --git a/examples/certs/pqc/root-mldsa87.pem b/examples/certs/pqc/root-mldsa87.pem new file mode 100644 index 00000000..23e1290f --- /dev/null +++ b/examples/certs/pqc/root-mldsa87.pem @@ -0,0 +1,160 @@ +-----BEGIN CERTIFICATE----- +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 +BhxCT1CWuAFbbnR+f7PZ6/YACBIjLTE5QEo= +-----END CERTIFICATE----- diff --git a/examples/certs/pqc/server-mldsa44-priv.pem b/examples/certs/pqc/server-mldsa44-priv.pem new file mode 100644 index 00000000..bf774f34 --- /dev/null +++ b/examples/certs/pqc/server-mldsa44-priv.pem @@ -0,0 +1,57 @@ +-----BEGIN PRIVATE KEY----- +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 +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/server-mldsa44.der b/examples/certs/pqc/server-mldsa44.der new file mode 100644 index 00000000..33824da6 Binary files /dev/null and b/examples/certs/pqc/server-mldsa44.der differ diff --git a/examples/certs/pqc/server-mldsa44.pem b/examples/certs/pqc/server-mldsa44.pem new file mode 100644 index 00000000..33edb94d --- /dev/null +++ b/examples/certs/pqc/server-mldsa44.pem @@ -0,0 +1,88 @@ +-----BEGIN CERTIFICATE----- +MIIQCjCCBoCgAwIBAgIUQupqITCX5VOjBCFYb3LRLMqiAZYwCwYJYIZIAWUDBAMR +MDsxGjAYBgNVBAMMEU1MLURTQS00NCBSb290IENBMRAwDgYDVQQKDAd3b2xmU1NM +MQswCQYDVQQGEwJVUzAeFw0yNjA0MjIyMDMzNDhaFw0zNjA0MTkyMDMzNDhaMDox +GTAXBgNVBAMMEE1MLURTQS00NCBzZXJ2ZXIxEDAOBgNVBAoMB3dvbGZTU0wxCzAJ +BgNVBAYTAlVTMIIFMjALBglghkgBZQMEAxEDggUhANTkAow6I/TvExxQ/Dzm9xSS +5tmV6Q801+4gAEJNw/SreTtDH/JSKYjOQLPmydp+QQkwqxwNboBQh1W7XQgR/HvS +z6nZAdOTszsulZqhGMQFF0qwHzqoaI7pneWMWx5TC/VEWFKh9wJHPNmZvH9ygI00 +SA+aVRpCHbZotGJ1ZHe91Sg539Tjl3T3AP0w4ClUi4GSzh9OFosMxMuC0OoA3Rcf +Rx3hr9XM9KjChIQ1DUL+sfA0mu1hsDOxCazxy3+NjjUXbnDD5qtoXpfMHPCVejZl +vAz7WgcTx+/JikDCoHfcR58AtV/A4ebfcQCDBBFEv/6WEwNSJ9kUOYRXlPKqnzDI +oy1i6gTOrAn5wbMMfB4drSWaBn5bjPQ26m/6PDKyOTgVrlwuZp5CaDdSbE2g2aPp +gQcDj7w3sMs67Vv1AQxO4M0/EBuxvMXN9blVbZDkiRMRDHbmFqv0cI7Ee5Ixonfe +xSEap9gWRA5xPBJpIBrW2GXW55xYVp25cYoqcEAUQ8ILoWMg9OrCw7d99ExQ5kxT +w+1/IGgJ95xxLYGHwgxYJvdGCsYiMQaABfpfV04zuo/l3MEIBaO71L8XvhoLlnqk +jrROC4Cr66QC2XnXwHdXXX49yTlL1G2Aqn8Zbgi/isU+Hsx1bXQpAdIyz0jmfn62 +dtfsXkBZLiqbd9CKubtQ+4ZGsWPc9rtcjWCWLKlewwLgf3F5IdLK1hisPUdvebwt +4QwstRz8XPdyC+pqlrM/l2y9qODDAut1KU0nb+mEe8devuyu2YcqaswYTiH2T44D +j9QuGxC8bGfxyMntIqZZnz5ajAO+hgjnkdmnb2H6/cnXT5i6nbBI5kDJ2Zx40xST +BpwPp3GxarH1R9vmZ2d5yp2YL9kuKV9jTgFlH5LJXT0UKRituzVa/eRA4ika8Vn2 +++B2pG8Hpe0Qor/9WHubafWSpWaVAV5ICaBTqrQ5wO5PtF/RPYxdyfGWaRufgv4g +Kj769bzocIsJQT+e3YCqXQX/5NpOkc4AY0ZGgXCQRh1x4KGxAPCPkJ4I+Fcbl1V5 +3zv0XJ6ZUJVy7pc4UKTuwOYutELKMZgAfXSeMLxPkyQ80RMP63THR1Vk9U+VlwK4 +Eka9gjl+Kn/y0HAVErZYK4zHN2xKuz2lzEdXEtnMV/lM1RqxdHqZrPKQBR1p5H7i +G83iCoU1d7YSyHYHAqRd+472lSFT6qaqmkmwN6/O+VPp2aHNdHqM/lPml2Mb/7mi +fvRxQuh9b39Z9pxKQy42L8pItzYk54M5rdj7FybnHIqblQG5p//0r1N0Qpo76w1k +VaqHd/uOlXdOLug4Z5wqvyngNlNFWd4jOTxq8wn6KL28SIifwZ4AgwKP2I4zYd6z +SGV0OHvMK3KaHFHD0sDtGKUBGyJ29vbQJRPkmYsx+X7LVe2wKWDAkWtih7P70+yY +lX0Fh0lGCv9j5qEQnXUmGw2G096z7IJ++GuglSAC6CPNTD4/YxF1cfJgfTx068jp +QlLV0QxRq+ESRDEktdGkF745GdMhfl+Mbr/bzAE8ufN5wYNWMu8C2yUD6NeeauvW +wpgMU6dq9DnzwtGdDO5Ey7B2LCC74Xo5xvlkhPl3MWfRMnITMYN5i/arsSGJpEns +4R+Bk9ELKh5sKLBxLtfF9+roZGK3TqAPdtEM1Wy0AoS558wdevw8diNkoRD6jwmM +XQqkbIO3zInpktzU3/iogHAwSsPMF9OlMupyJjAM5umSKWB3ovq1rWMRi5eBvsyj +gYYwgYMwHAYDVR0RBBUwE4ILZXhhbXBsZS5jb22HBH8AAAEwEwYDVR0lBAwwCgYI +KwYBBQUHAwEwDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBRJtqO9PqflpHNEvT89 +EkL2G1y/UDAfBgNVHSMEGDAWgBT+io/4Fg59u9hRMuM561/ocLPZdDALBglghkgB +ZQMEAxEDggl1AF3vlct/0JHZtL4ASot0+l486vkJnqOaiZP+rKZG3PquEnhOGHb1 +/rauaiEEJaEN9s84ZgHRbHtNHwcVTXKst2+Bjkm4oF2Umxss2dxHHFvS6KfrWF+S +AJnxjFKCG6Aj5OzXvWdQr1kLCwTROaOHJfKYMRBjM6vWX+UZtbwNw1mxiofWbBM+ +O7NrNsRBqGbetpOcGOtkzU+BEandbNIbQ5qTEV/kU96lsclq9WOm+D5+/JgCteav +7K58BfKeatM5wbQCW8LUtWaNacza3yCfqdoW7Eslgk2SC2RjCzQLz4pb4fis92ew +KbaBxR6u39hDcxfQmeXvltYgpcwMo8+RvkyWCMDux+2+Ln3EOZhBB1kAzx8Ktk8+ +Wq4K9RWHu8MyLfB+B0ZRomlDVkUXBm6cVjLUHPt1/nwE/UFTYF6UHA7svgK4nJSk +rH9vKOz3/bsouLBXTYTRD5FIUKpDYWVGF7kufAMj43Edrk1sTf89m9BWdxP4B0GP +6Jt1J5gIGTYq8B9CAubESE0BbJHT1s+9fLY4Kq+lOsIDt02fpLHz5qTU41bUnxMG +W8nvCLN/SxSiTNF4wt7ZJOjGr7/Yk/2mEIEFRaFGkeLmHQ0BDK5TOMsUpFOCVH29 +FIlyIFJGecAW1Qa9WqEBP95BOEMwlABxwWphwIJB8jVNP7jC4JK3JYda/Qg7k7xZ +AAgH/R2Tie3ekRQB7IrbomdeeLY6+Yd7epNYDC1xqDQTTZ/eEMfBYNROtRgF0mqI +zktOw+6QuoW9vi+iFsrz34IuCv5hqoZxG4AKBYf9sYUzgSkvZLlD/TMw/1U3rN+F +OO2oVKxJ0RpcCGaSq8uxibcU99s/2vQv9QTb5bPZLp9AO/HpamGnB2rrY4X7qNmh +D8A8VLR1APIh4jH6sqz2F4dpZxYXYm7gxV1iC+pHOVfDuqm5WAHbqR3Wtqhdh5lm +Bqtnd6pr0bLFXnUwXFnNFnOWJTn0ZPN6v27fRLL0IWRIrink8e2xc9/MHrjngCQm +zEYeB73jjfR+LFr5Egs1pa7jdKQnhqin0+J3PWzoDhVLUdCJeylvH76dMOakTlNE +yrnymtW/sEEbBuNaGY5g2M8vNIwjeSgoPLmA1nYj+8hu/E3qs1yNHPY9TJ6WIVVJ +dPrhJZww3/3owtiEAluBeGTFUcla2yBeF2BxuwQD/ljpGWYqhiyTQ9SEXDyByLf4 +XUTML+uDGq2qJBKjB5osXq4JMlIPM9NplT8I5H4kr8/niq+MDuuSvMp7Ly9lPY63 +rx3JARH1CMP1C8wn8rdVurzrmbxAP3gxihwkRRUf6w1EyVLKPDvTZW3ck+5l/PMA +4jBjhiwuE9IM0vciKwssBWpy0cHVl37KE1pGeSd4I+K+cQQhOOGLRgsoA4L+rFCo +0C2Y8PyfpvrZ0gsrsNtFHKqqV187Zzc6QrXjZpgFaAF/ijTCQHwC8HEAmCM1qbJK +QDMHYgofA9WFlHvH/jasOw+9SG/5dnOJC0lHzqr3SYWr4a7Owmg8Oa9sBrTIDnJB +HD3t40PCojbzu7/ZbdRDLHIhg4stnHxYkda5cwyG2mgwU/f1O4ZIIefhgxWIkBXV +dLkhxos2qxkQxX7yr2QVX2aHh7Wdutbj1iIOxm9BmOKJKo0UQtOJO4d7VjC5b/vx +LX1RgSRZENwy3jUvnuJl3cmVVjo6n+2FHWoG8UrRmYsgeV0tUNg8241mVNzpnbBh +DmDCkPagihoxYhdOLbLVf4NBjs26rZsMA2kZMVChU9cT6aEQuqSGoNuW6B8BuSbM +J4ZIbSTqhiNMDWhgKgpyk+/YF5h1IjTw0H78YD/sngNiyDPteiQ+yAX/7i8aGvM8 +NrkPz3OgIalzJ2qsLwRTBRjHIAWhO6wYLkMWTPp5Yz1U7MdLYKYe6deuHyHSvRgD +dLq80wo92OEO0OH9CeEYDiCXX5gelirfFHvA8j1DEl6Y4vyoi9Jarzjbr7dIAfmR +PiFSe7A+1o1jXpWmYNEjqyMD9N2E/wus99SfQ5u9VpPc8WHu09l9iDNpkvusBjMY +P7Wjl1nYS6DJNlpHhgWuFPn82P4gDuSbpxGtpTmtOassuHIRY0VHa9UJgCCJQhxE +YjJpG1Z4/QHyX+L3zPh25rJocFoGtqGXkb0f0oS1IYfD0mtZLkQXGCWOT/y/tgI9 +6o3rRBVC4iSxfNXYaJdoikS+1pixbQIt3p65ySZy7WwCVMw4h3vUVb82SOEWdnS8 +gBAwVOih45Ucpcx4CMGfi70eUuQvaMbDhncJHJe1oFSDq8yvDj/87gQ2Cx8HKtSG +sLVWu9TFplBq5YCT1G8uCkIE6/qKno08/lYuOpfWCxjinucpjpvwj5gZfEjYJgtw +nUJxH7lXs4ebMxh3s11njpAjivUn3qMHi64mLAQp7VAoyeXLaeeePD+cuhDBsauk +NktO2Xp8lnOOt29svLD3AlGRV2yIaPg64/0cm1Gy8Iii2AEpIZHmt+lDW7jqInxM +CNh6w0urG+WqYknOa8lC6SsMXzaDpYoU+ApWDNvmEsqVCyNHWhzTbClIwqytfnlh +PcuPqwpu0ulC9L7P5VOIsRRkW4Ifi4j0bBwRcx3ZIqsN9i5XjJeqODxZvP9RN0XQ +/xfngPy1rv3hyyV2CieXwOZn5lrqbNne17wx061m2nk8f9dUB9ke/RqM6bmy25rz +4lbbBlZlsTWDZkOiqpnlw6s4Xl+QQ9GHw6vrr3If66iDNTBZD4ueSZTStmnmN2oG +bAglvPpWe1Nqy6enI7W3CZlH8pK/cz1s4GoSzei8UtuBZs1aITQQWTvN0rKCRAQo +N6R5DQZJEe+qAmbW+YZi+v8K9pRusJ4v7J34HPP8RvQXlJMltY43Bto6ssDr9/06 +CL0ZG3uyY4NPA4SIUtK5E2p1ulLN5uRVWKCgujyQjmyT+DDQBEwwQd+o6AScGCVo +N9kiZ2jLaI9YTxopdS/L4+ZBUHWdsC1k4l0BDoeVmWT4wPzaWEoWHRe6S/6gRYQT +13azBV05dyhF1kLUZUFxvWkhoWCtRfU3SRHOVEmNLo07MGynET0Jb5gidCaGJVSw +X9XTm8DvmbexD9iYZknP/ATuZ96RLN0YT++9tFzv8b9omJC7eQ1XZxINARgbJzA3 +RWqPoNPo6QILDxspMjc+SFphZ2t5l8DK2uMNERQbHzFBWF2KjJCxs7/T5QURQUZl +h5mctLbExdz4/gAAAAAAAAAAAAAAAAAAAAANIDFA +-----END CERTIFICATE----- diff --git a/examples/certs/pqc/server-mldsa65-priv.pem b/examples/certs/pqc/server-mldsa65-priv.pem new file mode 100644 index 00000000..ea69113b --- /dev/null +++ b/examples/certs/pqc/server-mldsa65-priv.pem @@ -0,0 +1,88 @@ +-----BEGIN PRIVATE KEY----- +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 +49z0L0xXvsgVlxCIefXwHPdT +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/server-mldsa65.der b/examples/certs/pqc/server-mldsa65.der new file mode 100644 index 00000000..d2f22955 Binary files /dev/null and b/examples/certs/pqc/server-mldsa65.der differ diff --git a/examples/certs/pqc/server-mldsa65.pem b/examples/certs/pqc/server-mldsa65.pem new file mode 100644 index 00000000..4fb64b48 --- /dev/null +++ b/examples/certs/pqc/server-mldsa65.pem @@ -0,0 +1,120 @@ +-----BEGIN CERTIFICATE----- +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 +AAAAAAAAAAAAAAAAAAAAAAAGCAsSHSE= +-----END CERTIFICATE----- diff --git a/examples/certs/pqc/server-mldsa87-priv.pem b/examples/certs/pqc/server-mldsa87-priv.pem new file mode 100644 index 00000000..83117b3a --- /dev/null +++ b/examples/certs/pqc/server-mldsa87-priv.pem @@ -0,0 +1,106 @@ +-----BEGIN PRIVATE KEY----- +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 +94uFMUkwxYTG6Pal0z45Am9/ +-----END PRIVATE KEY----- diff --git a/examples/certs/pqc/server-mldsa87.der b/examples/certs/pqc/server-mldsa87.der new file mode 100644 index 00000000..cb9c65fc Binary files /dev/null and b/examples/certs/pqc/server-mldsa87.der differ diff --git a/examples/certs/pqc/server-mldsa87.pem b/examples/certs/pqc/server-mldsa87.pem new file mode 100644 index 00000000..7faf5588 --- /dev/null +++ b/examples/certs/pqc/server-mldsa87.pem @@ -0,0 +1,161 @@ +-----BEGIN CERTIFICATE----- +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 +AAAAAAAJFBojKi4zOA== +-----END CERTIFICATE----- diff --git a/examples/client.sh b/examples/client.sh index b9982a9b..d2706b15 100755 --- a/examples/client.sh +++ b/examples/client.sh @@ -1,5 +1,11 @@ #!/bin/bash +# Example usage: +# ./examples/client.sh -h 127.0.0.1 -p 11111 -v 4 +# ./examples/client.sh -v 4 -pqc X25519MLKEM768 (PQC hybrid TLS 1.3) +# ./examples/client.sh -v 4 -pqc ML-KEM-768 (PQC standalone) +# Run ./examples/client.sh -? for the full option list. + cd ./examples/build export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../lib/:/usr/local/lib java -classpath ../../lib/wolfssl.jar:./ -Dsun.boot.library.path=../../lib/ -Xcheck:jni Client $@ diff --git a/examples/provider/ClientJSSE.java b/examples/provider/ClientJSSE.java index b50b4954..065d8fd3 100644 --- a/examples/provider/ClientJSSE.java +++ b/examples/provider/ClientJSSE.java @@ -105,6 +105,8 @@ public void run(String[] args) throws Exception { byte[] firstSessionId = null; /* sess ID of first session */ byte[] resumeSessionId = null; /* sess ID of resumed session */ + String pqcAlg = null; /* PQC named group, -pqc */ + /* cert info */ String clientJKS = "../provider/client.jks"; String caJKS = "../provider/ca-server.jks"; @@ -204,6 +206,12 @@ public void run(String[] args) throws Exception { } else if (arg.equals("-ksformat")) { keyStoreFormat = args[++i]; + } else if (arg.equals("-pqc")) { + if (args.length < i+2) { + printUsage(); + } + pqcAlg = args[++i]; + } else { printUsage(); } @@ -221,6 +229,15 @@ public void run(String[] args) throws Exception { return; } + /* PQC named groups are TLS 1.3 only. Allow only -v 4 (TLS 1.3) + * or -v d (generic TLS, which can negotiate TLS 1.3). Reject + * everything else up front rather than letting the handshake + * fail at the TLS layer. */ + if (pqcAlg != null && sslVersion != 4 && sslVersion != -1) { + System.out.println("-pqc requires -v 4 (TLS 1.3) or -v d"); + System.exit(1); + } + /* Add host into HTTP GET */ httpGetMsg = String.format("%s\r\nHost: %s\r\n\r\n", httpGetMsg, host); @@ -230,6 +247,15 @@ public void run(String[] args) throws Exception { Thread.sleep(10000); } + /* Single -pqc group. Set wolfjsse.enabledSupportedCurves before + * SSLContext is built so provider sees the restriction when + * initializing the session. */ + if (pqcAlg != null) { + Security.setProperty("wolfjsse.enabledSupportedCurves", pqcAlg); + System.out.println("Set wolfjsse.enabledSupportedCurves = " + + pqcAlg); + } + /* X509TrustManager that trusts all peer certificates. Used if peer * authentication (-d) has been passed in */ TrustManager[] trustAllCerts = new TrustManager[] { @@ -468,6 +494,8 @@ private void printUsage() { System.out.println("-profile\tSleep for 10 sec before/after running " + "to allow profilers to attach"); System.out.println("-ksformat \tKeyStore format (default: JKS)"); + System.out.println("-pqc \tKey Share with specified " + + "post-quantum algorithm only, e.g. X25519MLKEM768"); System.exit(1); } } diff --git a/examples/provider/ClientJSSE.sh b/examples/provider/ClientJSSE.sh index 38b520f1..d91f0362 100755 --- a/examples/provider/ClientJSSE.sh +++ b/examples/provider/ClientJSSE.sh @@ -1,5 +1,11 @@ #!/bin/bash +# Example usage: +# ./examples/provider/ClientJSSE.sh -h 127.0.0.1 -p 11111 -v 4 +# ./examples/provider/ClientJSSE.sh -v 4 -pqc X25519MLKEM768 +# ./examples/provider/ClientJSSE.sh -v 4 -pqc ML-KEM-768 +# Run ./examples/provider/ClientJSSE.sh -? for the full option list. + cd ./examples/build export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../lib/:/usr/local/lib java -classpath ../../lib/wolfssl.jar:../../lib/wolfssl-jsse.jar:./ -Dsun.boot.library.path=../../lib/ ClientJSSE "$@" diff --git a/examples/provider/ServerJSSE.java b/examples/provider/ServerJSSE.java index 62c45027..36cf36ae 100644 --- a/examples/provider/ServerJSSE.java +++ b/examples/provider/ServerJSSE.java @@ -87,6 +87,8 @@ public void run(String[] args) { /* set/get enabled protocols */ String[] protocols = null; + String pqcAlg = null; /* PQC named group, -pqc */ + try { /* load WolfSSLprovider */ @@ -168,6 +170,12 @@ public void run(String[] args) { } else if (arg.equals("-ksformat")) { keyStoreFormat = args[++i]; + } else if (arg.equals("-pqc")) { + if (args.length < i+2) { + printUsage(); + } + pqcAlg = args[++i]; + } else { printUsage(); } @@ -198,12 +206,29 @@ public void run(String[] args) { System.exit(1); } + /* PQC named groups are TLS 1.3 only. Allow -v 4 (TLS 1.3) + * or -v d (generic TLS, which can negotiate TLS 1.3. Reject + * everything else up front. */ + if (pqcAlg != null && sslVersion != 4 && sslVersion != -1) { + System.out.println("-pqc requires -v 4 (TLS 1.3) or -v d"); + System.exit(1); + } + if (profileSleep) { System.out.println( "Sleeping 10 seconds to allow profiler to attach"); Thread.sleep(10000); } + /* Single -pqc group. wolfJSSE setLocalSupportedCurves uses this + * property in server mode to pre-generate a TLS 1.3 key share for + * the named PQC group, avoiding HRR if client picks it. */ + if (pqcAlg != null) { + Security.setProperty("wolfjsse.enabledSupportedCurves", pqcAlg); + System.out.println("Set wolfjsse.enabledSupportedCurves = " + + pqcAlg); + } + /* set up keystore and truststore */ KeyStore keystore = KeyStore.getInstance(keyStoreFormat); keystore.load(new FileInputStream(serverJKS), @@ -350,6 +375,8 @@ private void printUsage() { System.out.println("-profile\tSleep for 10 sec before/after running " + "to allow profilers to attach"); System.out.println("-ksformat \tKeyStore format (default: JKS)"); + System.out.println("-pqc \tKey Share with specified " + + "post-quantum algorithm only, e.g. X25519MLKEM768"); System.exit(1); } diff --git a/examples/provider/ServerJSSE.sh b/examples/provider/ServerJSSE.sh index 34912b13..f63f6b49 100755 --- a/examples/provider/ServerJSSE.sh +++ b/examples/provider/ServerJSSE.sh @@ -1,5 +1,10 @@ #!/bin/bash +# Example usage: +# ./examples/provider/ServerJSSE.sh -p 11111 -v 4 +# ./examples/provider/ServerJSSE.sh -v 4 -pqc X25519MLKEM768 +# Run ./examples/provider/ServerJSSE.sh -? for the full option list. + cd ./examples/build export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../lib/:/usr/local/lib java -classpath ../../lib/wolfssl-jsse.jar:./ -Dsun.boot.library.path=../../lib/ ServerJSSE "$@" diff --git a/examples/provider/ca-mldsa44.jks b/examples/provider/ca-mldsa44.jks new file mode 100644 index 00000000..06d42a91 Binary files /dev/null and b/examples/provider/ca-mldsa44.jks differ diff --git a/examples/provider/ca-mldsa44.p12 b/examples/provider/ca-mldsa44.p12 new file mode 100644 index 00000000..89f4631f Binary files /dev/null and b/examples/provider/ca-mldsa44.p12 differ diff --git a/examples/provider/ca-mldsa65.jks b/examples/provider/ca-mldsa65.jks new file mode 100644 index 00000000..d18e3291 Binary files /dev/null and b/examples/provider/ca-mldsa65.jks differ diff --git a/examples/provider/ca-mldsa65.p12 b/examples/provider/ca-mldsa65.p12 new file mode 100644 index 00000000..f1086cd6 Binary files /dev/null and b/examples/provider/ca-mldsa65.p12 differ diff --git a/examples/provider/ca-mldsa87.jks b/examples/provider/ca-mldsa87.jks new file mode 100644 index 00000000..3e0045a0 Binary files /dev/null and b/examples/provider/ca-mldsa87.jks differ diff --git a/examples/provider/ca-mldsa87.p12 b/examples/provider/ca-mldsa87.p12 new file mode 100644 index 00000000..4be916ed Binary files /dev/null and b/examples/provider/ca-mldsa87.p12 differ diff --git a/examples/provider/client-mldsa44.jks b/examples/provider/client-mldsa44.jks new file mode 100644 index 00000000..e28c268f Binary files /dev/null and b/examples/provider/client-mldsa44.jks differ diff --git a/examples/provider/client-mldsa44.p12 b/examples/provider/client-mldsa44.p12 new file mode 100644 index 00000000..05be9bfc Binary files /dev/null and b/examples/provider/client-mldsa44.p12 differ diff --git a/examples/provider/client-mldsa65.jks b/examples/provider/client-mldsa65.jks new file mode 100644 index 00000000..066666a1 Binary files /dev/null and b/examples/provider/client-mldsa65.jks differ diff --git a/examples/provider/client-mldsa65.p12 b/examples/provider/client-mldsa65.p12 new file mode 100644 index 00000000..1c832cc7 Binary files /dev/null and b/examples/provider/client-mldsa65.p12 differ diff --git a/examples/provider/client-mldsa87.jks b/examples/provider/client-mldsa87.jks new file mode 100644 index 00000000..0eebf520 Binary files /dev/null and b/examples/provider/client-mldsa87.jks differ diff --git a/examples/provider/client-mldsa87.p12 b/examples/provider/client-mldsa87.p12 new file mode 100644 index 00000000..5780f6cd Binary files /dev/null and b/examples/provider/client-mldsa87.p12 differ diff --git a/examples/provider/server-mldsa44.jks b/examples/provider/server-mldsa44.jks new file mode 100644 index 00000000..fd66d056 Binary files /dev/null and b/examples/provider/server-mldsa44.jks differ diff --git a/examples/provider/server-mldsa44.p12 b/examples/provider/server-mldsa44.p12 new file mode 100644 index 00000000..0a0e32d8 Binary files /dev/null and b/examples/provider/server-mldsa44.p12 differ diff --git a/examples/provider/server-mldsa65.jks b/examples/provider/server-mldsa65.jks new file mode 100644 index 00000000..e7bb10af Binary files /dev/null and b/examples/provider/server-mldsa65.jks differ diff --git a/examples/provider/server-mldsa65.p12 b/examples/provider/server-mldsa65.p12 new file mode 100644 index 00000000..bef3bc09 Binary files /dev/null and b/examples/provider/server-mldsa65.p12 differ diff --git a/examples/provider/server-mldsa87.jks b/examples/provider/server-mldsa87.jks new file mode 100644 index 00000000..fa3b1baf Binary files /dev/null and b/examples/provider/server-mldsa87.jks differ diff --git a/examples/provider/server-mldsa87.p12 b/examples/provider/server-mldsa87.p12 new file mode 100644 index 00000000..e23d64c5 Binary files /dev/null and b/examples/provider/server-mldsa87.p12 differ diff --git a/examples/provider/update-keystore-pqc.sh b/examples/provider/update-keystore-pqc.sh new file mode 100755 index 00000000..a404a9f1 --- /dev/null +++ b/examples/provider/update-keystore-pqc.sh @@ -0,0 +1,171 @@ +#!/usr/bin/env bash +# +# update-keystore-pqc.sh +# +# Generates ML-DSA (FIPS 204) keystores for wolfJSSE PQC tests, in both +# JKS and PKCS12 formats. PKCS12 is the JDK 24+ default keystore type; +# JKS is included for backward-compatibility coverage. +# +# Why this script exists: +# - JDK 24+ added ML-DSA via JEP 497 (KeyFactory, KeyPairGenerator, +# Signature, KeyTool support). Prior JDK versions cannot read ML-DSA +# private keys via standard JCE. +# - OpenSSL 3.5+ and JDK 24+ disagree on the ML-DSA private key encoding +# (seed-only vs expanded form). Cross-toolchain JKS conversion is +# unreliable. +# - Therefore, the simplest portable path is to use JDK 24+ keytool +# to generate self-signed ML-DSA certs directly into the keystore, +# no openssl involvement on the keystore side. +# +# Requirements: +# - JDK 24 or newer in PATH, OR JAVA_HOME pointing at a JDK 24+ install. +# +# Output, per ML-DSA level (44, 65, 87) and per format (jks, p12): +# server-mldsaN.{jks,p12} -- private key + server cert chain +# client-mldsaN.{jks,p12} -- private key + client cert chain +# ca-mldsaN.{jks,p12} -- root cert only (truststore for both sides) +# +# The client and server entity certs are signed by the same root, so a +# single ca-mldsaN.{jks,p12} truststore is sufficient for mutual auth. +# +# Tests that consume these files (WolfSSLPQCAuthKeyStoreTest) skip cleanly +# on JDK < 24 via a runtime KeyFactory.getInstance("ML-DSA") check. + +set -euo pipefail + +PASSWD="wolfSSL test" +OUT_DIR="$(dirname "$0")" + +KT="${JAVA_HOME:+$JAVA_HOME/bin/}keytool" + +# Verify JDK 24+ +if ! "$KT" -genkeypair -keyalg ML-DSA -alias _probe \ + -keystore /tmp/_pqc_probe_$$.jks -storepass "$PASSWD" \ + -dname "CN=probe" >/dev/null 2>&1; then + echo "ERROR: keytool does not support ML-DSA. Need JDK 24+." >&2 + echo " Tried: $KT" >&2 + "$KT" -version 2>&1 || true + rm -f /tmp/_pqc_probe_$$.jks + exit 1 +fi +rm -f /tmp/_pqc_probe_$$.jks + +# Generate one entity keystore (server or client) signed by the supplied +# root. Helper used by gen_keystore() so both roles share one root. +gen_entity_keystore() { + local level="$1" + local storetype="$2" + local ext="$3" + local role="$4" # "server" or "client" + local root_ks="$5" # path to the root keystore (in $work) + local work="$6" # scratch directory + local alg="ML-DSA-${level}" + local entity_ks="${OUT_DIR}/${role}-mldsa${level}.${ext}" + local alias="${role}-mldsa${level}" + + rm -f "$entity_ks" + + # Server cert gets a SAN (dns:example.com, ip:127.0.0.1); the client + # cert does not need one. Both certs share the same root. + local entity_san_args=() + if [ "$role" = "server" ]; then + entity_san_args=(-ext "san=dns:example.com,ip:127.0.0.1") + fi + + # 1. Entity keypair (initially self-signed in its own keystore) + "$KT" -genkeypair -keyalg "$alg" \ + -alias "$alias" \ + -keystore "$entity_ks" -storepass "$PASSWD" \ + -keypass "$PASSWD" -storetype "$storetype" \ + -dname "CN=ML-DSA-${level} ${role}, O=wolfSSL, C=US" \ + ${entity_san_args[@]+"${entity_san_args[@]}"} -validity 3650 + + # 2. CSR from the entity keystore + "$KT" -certreq -alias "$alias" \ + -keystore "$entity_ks" -storepass "$PASSWD" \ + -file "$work/${role}.csr" + + # 3. Sign the CSR with the root CA + "$KT" -gencert -alias "root-mldsa${level}" \ + -keystore "$root_ks" -storepass "$PASSWD" \ + -infile "$work/${role}.csr" -outfile "$work/${role}.crt" \ + ${entity_san_args[@]+"${entity_san_args[@]}"} -validity 3650 + + # 4. Import root into the entity keystore so the next import can chain + "$KT" -importcert -noprompt -trustcacerts \ + -alias "root-mldsa${level}" \ + -keystore "$entity_ks" -storepass "$PASSWD" \ + -storetype "$storetype" \ + -file "$work/root.crt" + + # 5. Replace the self-signed entity cert with the CA-signed one, + # forming a real chain inside the keystore + "$KT" -importcert -noprompt -alias "$alias" \ + -keystore "$entity_ks" -storepass "$PASSWD" \ + -storetype "$storetype" \ + -file "$work/${role}.crt" +} + +# Generate proper cert chain per ML-DSA level + storetype: a CA keypair +# signs server and client entity certs. Output per (level, storetype): +# server-mldsaN. -- private key + server cert chain (server+root) +# client-mldsaN. -- private key + client cert chain (client+root) +# ca-mldsaN. -- root cert only (truststore for both sides) +gen_keystore() { + local level="$1" + local storetype="$2" # JKS or PKCS12 + local ext="$3" # jks or p12 + local alg="ML-DSA-${level}" + local ca_ks="${OUT_DIR}/ca-mldsa${level}.${ext}" + local work="/tmp/_pqc_$$_${level}_${ext}" + local root_ks="${work}/root.${ext}" + + echo "=== Generating ML-DSA-${level} (${storetype}) cert chain ===" + + rm -f "$ca_ks" + mkdir -p "$work" + + # 1. Root CA self-signed (kept in $work; never shipped) + "$KT" -genkeypair -keyalg "$alg" \ + -alias "root-mldsa${level}" \ + -keystore "$root_ks" -storepass "$PASSWD" \ + -keypass "$PASSWD" -storetype "$storetype" \ + -dname "CN=ML-DSA-${level} Root CA, O=wolfSSL, C=US" \ + -ext "bc:c=ca:true" -validity 3650 + + # 2. Export the root cert (used by entity keystores and the truststore) + "$KT" -exportcert -alias "root-mldsa${level}" \ + -keystore "$root_ks" -storepass "$PASSWD" \ + -file "$work/root.crt" + + # 3. Server entity keystore signed by root + gen_entity_keystore "$level" "$storetype" "$ext" "server" \ + "$root_ks" "$work" + + # 4. Client entity keystore signed by the same root + gen_entity_keystore "$level" "$storetype" "$ext" "client" \ + "$root_ks" "$work" + + # 5. Truststore (root cert only) -- valid for both server- and + # client-side verification since both entity certs share this root + "$KT" -importcert -noprompt -trustcacerts \ + -alias "root-mldsa${level}" \ + -keystore "$ca_ks" -storepass "$PASSWD" \ + -storetype "$storetype" \ + -file "$work/root.crt" + + rm -rf "$work" +} + +# Generate (level, storetype) cross product. JKS first for backward-compat +# coverage; PKCS12 second since it's the JDK 24+ default keystore type. +for level in 44 65 87; do + gen_keystore "$level" "JKS" "jks" + gen_keystore "$level" "PKCS12" "p12" +done + +echo "" +echo "=== Done. Generated keystore files: ===" +ls -1 "$OUT_DIR"/server-mldsa*.{jks,p12} \ + "$OUT_DIR"/client-mldsa*.{jks,p12} \ + "$OUT_DIR"/ca-mldsa*.{jks,p12} 2>/dev/null diff --git a/examples/server.sh b/examples/server.sh index d7ec9b58..db420816 100755 --- a/examples/server.sh +++ b/examples/server.sh @@ -1,5 +1,11 @@ #!/bin/bash +# Example usage: +# ./examples/server.sh -p 11111 -v 4 +# ./examples/server.sh -v 4 -pqc X25519MLKEM768 (PQC hybrid TLS 1.3) +# ./examples/server.sh -v 4 -pqc ML-KEM-768 (PQC standalone) +# Run ./examples/server.sh -? for the full option list. + cd ./examples/build export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:../../lib/:/usr/local/lib java -classpath ../../lib/wolfssl.jar:./ -Dsun.boot.library.path=../../lib/ Server $@ diff --git a/native/com_wolfssl_WolfSSL.c b/native/com_wolfssl_WolfSSL.c index 54e022bd..9427d23c 100644 --- a/native/com_wolfssl_WolfSSL.c +++ b/native/com_wolfssl_WolfSSL.c @@ -1082,6 +1082,45 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_Curve448Enabled #endif } +JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_MLKEMEnabled + (JNIEnv* jenv, jclass jcl) +{ + (void)jenv; + (void)jcl; + +#ifdef WOLFSSL_HAVE_MLKEM + return JNI_TRUE; +#else + return JNI_FALSE; +#endif +} + +JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_MLDSAEnabled + (JNIEnv* jenv, jclass jcl) +{ + (void)jenv; + (void)jcl; + +#ifdef HAVE_DILITHIUM + return JNI_TRUE; +#else + return JNI_FALSE; +#endif +} + +JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_MLKEMOldIdsEnabled + (JNIEnv* jenv, jclass jcl) +{ + (void)jenv; + (void)jcl; + +#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS + return JNI_TRUE; +#else + return JNI_FALSE; +#endif +} + JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_FileSystemEnabled (JNIEnv* jenv, jclass jcl) { diff --git a/native/com_wolfssl_WolfSSL.h b/native/com_wolfssl_WolfSSL.h index 7a62d784..3f521215 100644 --- a/native/com_wolfssl_WolfSSL.h +++ b/native/com_wolfssl_WolfSSL.h @@ -323,6 +323,28 @@ extern "C" { #define com_wolfssl_WolfSSL_WOLFSSL_FFDHE_6144 259L #undef com_wolfssl_WolfSSL_WOLFSSL_FFDHE_8192 #define com_wolfssl_WolfSSL_WOLFSSL_FFDHE_8192 260L +#undef com_wolfssl_WolfSSL_WOLFSSL_ML_KEM_512 +#define com_wolfssl_WolfSSL_WOLFSSL_ML_KEM_512 512L +#undef com_wolfssl_WolfSSL_WOLFSSL_ML_KEM_768 +#define com_wolfssl_WolfSSL_WOLFSSL_ML_KEM_768 513L +#undef com_wolfssl_WolfSSL_WOLFSSL_ML_KEM_1024 +#define com_wolfssl_WolfSSL_WOLFSSL_ML_KEM_1024 514L +#undef com_wolfssl_WolfSSL_WOLFSSL_SECP256R1MLKEM768 +#define com_wolfssl_WolfSSL_WOLFSSL_SECP256R1MLKEM768 4587L +#undef com_wolfssl_WolfSSL_WOLFSSL_X25519MLKEM768 +#define com_wolfssl_WolfSSL_WOLFSSL_X25519MLKEM768 4588L +#undef com_wolfssl_WolfSSL_WOLFSSL_SECP384R1MLKEM1024 +#define com_wolfssl_WolfSSL_WOLFSSL_SECP384R1MLKEM1024 4589L +#undef com_wolfssl_WolfSSL_WOLFSSL_SECP256R1MLKEM512 +#define com_wolfssl_WolfSSL_WOLFSSL_SECP256R1MLKEM512 12107L +#undef com_wolfssl_WolfSSL_WOLFSSL_SECP384R1MLKEM768 +#define com_wolfssl_WolfSSL_WOLFSSL_SECP384R1MLKEM768 12108L +#undef com_wolfssl_WolfSSL_WOLFSSL_SECP521R1MLKEM1024 +#define com_wolfssl_WolfSSL_WOLFSSL_SECP521R1MLKEM1024 12109L +#undef com_wolfssl_WolfSSL_WOLFSSL_X25519MLKEM512 +#define com_wolfssl_WolfSSL_WOLFSSL_X25519MLKEM512 12214L +#undef com_wolfssl_WolfSSL_WOLFSSL_X448MLKEM768 +#define com_wolfssl_WolfSSL_WOLFSSL_X448MLKEM768 12215L #undef com_wolfssl_WolfSSL_INVALID_DEVID #define com_wolfssl_WolfSSL_INVALID_DEVID -2L #undef com_wolfssl_WolfSSL_WOLFSSL_LEFT_MOST_WILDCARD_ONLY @@ -847,6 +869,30 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_Curve25519Enabled JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_Curve448Enabled (JNIEnv *, jclass); +/* + * Class: com_wolfssl_WolfSSL + * Method: MLKEMEnabled + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_MLKEMEnabled + (JNIEnv *, jclass); + +/* + * Class: com_wolfssl_WolfSSL + * Method: MLDSAEnabled + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_MLDSAEnabled + (JNIEnv *, jclass); + +/* + * Class: com_wolfssl_WolfSSL + * Method: MLKEMOldIdsEnabled + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_MLKEMOldIdsEnabled + (JNIEnv *, jclass); + /* * Class: com_wolfssl_WolfSSL * Method: FileSystemEnabled diff --git a/native/com_wolfssl_WolfSSLCertificate.c b/native/com_wolfssl_WolfSSLCertificate.c index 5442f75d..cbbe3815 100644 --- a/native/com_wolfssl_WolfSSLCertificate.c +++ b/native/com_wolfssl_WolfSSLCertificate.c @@ -1490,7 +1490,18 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLCertificate_X509_1get_1signatu return (*jenv)->NewStringUTF(jenv, "ED25519"); case CTC_RSASSAPSS: return (*jenv)->NewStringUTF(jenv, "RSASSA-PSS"); - +#ifdef HAVE_ED448 + case CTC_ED448: + return (*jenv)->NewStringUTF(jenv, "ED448"); +#endif +#ifdef HAVE_DILITHIUM + case CTC_ML_DSA_LEVEL2: + return (*jenv)->NewStringUTF(jenv, "ML-DSA-44"); + case CTC_ML_DSA_LEVEL3: + return (*jenv)->NewStringUTF(jenv, "ML-DSA-65"); + case CTC_ML_DSA_LEVEL5: + return (*jenv)->NewStringUTF(jenv, "ML-DSA-87"); +#endif default: throwWolfSSLJNIException(jenv, "Unknown signature type"); return NULL; diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c index 32bcda0a..28113160 100644 --- a/native/com_wolfssl_WolfSSLSession.c +++ b/native/com_wolfssl_WolfSSLSession.c @@ -6459,6 +6459,30 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSupportedCurve #endif } +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useKeyShare + (JNIEnv* jenv, jobject jcl, jlong sslPtr, jint group) +{ +#ifdef WOLFSSL_TLS13 + int ret = 0; + WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr; + (void)jcl; + + if (jenv == NULL || ssl == NULL) { + return (jint)SSL_FAILURE; + } + + ret = wolfSSL_UseKeyShare(ssl, (word16)group); + + return (jint)ret; +#else + (void)jenv; + (void)jcl; + (void)sslPtr; + (void)group; + return (jint)NOT_COMPILED_IN; +#endif +} + JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_disableExtendedMasterSecret (JNIEnv* jenv, jobject jcl, jlong sslPtr) { diff --git a/native/com_wolfssl_WolfSSLSession.h b/native/com_wolfssl_WolfSSLSession.h index a9cc9fe5..04ad4e4f 100644 --- a/native/com_wolfssl_WolfSSLSession.h +++ b/native/com_wolfssl_WolfSSLSession.h @@ -1039,6 +1039,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_set1SigAlgsList JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSupportedCurve (JNIEnv *, jobject, jlong, jint); +/* + * Class: com_wolfssl_WolfSSLSession + * Method: useKeyShare + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useKeyShare + (JNIEnv *, jobject, jlong, jint); + /* * Class: com_wolfssl_WolfSSLSession * Method: disableExtendedMasterSecret diff --git a/src/java/com/wolfssl/WolfSSL.java b/src/java/com/wolfssl/WolfSSL.java index b9ab4218..6a928790 100644 --- a/src/java/com/wolfssl/WolfSSL.java +++ b/src/java/com/wolfssl/WolfSSL.java @@ -588,6 +588,36 @@ public enum TLS_VERSION { /** FFDHE 8192 */ public static final int WOLFSSL_FFDHE_8192 = 260; + /* ----------------- ML-KEM (FIPS 203) Named Groups ----------------- */ + /** ML-KEM-512 (FIPS 203, NIST Security Category 1) */ + public static final int WOLFSSL_ML_KEM_512 = 512; + /** ML-KEM-768 (FIPS 203, NIST Security Category 3) */ + public static final int WOLFSSL_ML_KEM_768 = 513; + /** ML-KEM-1024 (FIPS 203, NIST Security Category 5, CNSA 2.0) */ + public static final int WOLFSSL_ML_KEM_1024 = 514; + + /* Hybrid IETF final codepoints (draft-ietf-tls-ecdhe-mlkem). */ + /** Hybrid SECP256R1 + ML-KEM-768 (IETF final codepoint 0x11EB) */ + public static final int WOLFSSL_SECP256R1MLKEM768 = 4587; + /** Hybrid X25519 + ML-KEM-768 (IETF final codepoint 0x11EC) */ + public static final int WOLFSSL_X25519MLKEM768 = 4588; + /** Hybrid SECP384R1 + ML-KEM-1024 (IETF final codepoint 0x11ED, + * CNSA 2.0 with hybrid bridge) */ + public static final int WOLFSSL_SECP384R1MLKEM1024 = 4589; + + /* Hybrid OQS-assigned codepoints (legacy interop). + * No IETF-final equivalents exist for these combinations. */ + /** Hybrid SECP256R1 + ML-KEM-512 (OQS codepoint) */ + public static final int WOLFSSL_SECP256R1MLKEM512 = 12107; + /** Hybrid SECP384R1 + ML-KEM-768 (OQS codepoint) */ + public static final int WOLFSSL_SECP384R1MLKEM768 = 12108; + /** Hybrid SECP521R1 + ML-KEM-1024 (OQS codepoint) */ + public static final int WOLFSSL_SECP521R1MLKEM1024 = 12109; + /** Hybrid X25519 + ML-KEM-512 (OQS codepoint) */ + public static final int WOLFSSL_X25519MLKEM512 = 12214; + /** Hybrid X448 + ML-KEM-768 (OQS codepoint) */ + public static final int WOLFSSL_X448MLKEM768 = 12215; + /* -------------------- Crypto Callback DevID ----------------------- */ /** Invalid DevID value, when used as devId software crypto is used */ public static final int INVALID_DEVID = -2; @@ -1096,6 +1126,37 @@ protected static byte[] fileToBytes(File file) */ public static native boolean Curve448Enabled(); + /** + * Tests if ML-KEM (FIPS 203, formerly Kyber) support has been + * compiled into native wolfSSL library. + * + * @return true if enabled, otherwise false if not compiled in. + */ + public static native boolean MLKEMEnabled(); + + /** + * Tests if ML-DSA (FIPS 204, formerly Dilithium) support has been + * compiled into native wolfSSL library (HAVE_DILITHIUM). + * + * @return true if enabled, otherwise false if not compiled in. + */ + public static native boolean MLDSAEnabled(); + + /** + * Tests if native wolfSSL was built with WOLFSSL_ML_KEM_USE_OLD_IDS. + * When enabled, the server accepts the pre-IETF-final legacy hybrid + * ML-KEM codepoints in addition to the IETF final codepoints exposed + * as {@link #WOLFSSL_X25519MLKEM768}, {@link #WOLFSSL_SECP256R1MLKEM768}, + * and {@link #WOLFSSL_SECP384R1MLKEM1024}. The legacy codepoints are not + * exposed as Java constants because wolfJSSE always sends only the + * IETF final codepoints in ClientHello regardless of this setting. It is + * purely a server-side compatibility flag for accepting older clients + * still using the draft codepoints. + * + * @return true if enabled, otherwise false if not compiled in. + */ + public static native boolean MLKEMOldIdsEnabled(); + /** * Tests if filesystem support has been compiled into the wolfSSL library. * @@ -1941,7 +2002,7 @@ public static int cryptoCbUnRegisterDevice(int devId) { * String, or WolfSSL.WOLFSSL_NAMED_GROUP_INVALID if curve * String not supported. */ - protected static int getNamedGroupFromString(String curveName) { + public static int getNamedGroupFromString(String curveName) { switch (curveName) { case "sect163k1": @@ -2018,12 +2079,78 @@ protected static int getNamedGroupFromString(String curveName) { return WolfSSL.WOLFSSL_FFDHE_6144; case "ffdhe8192": return WolfSSL.WOLFSSL_FFDHE_8192; + /* ML-KEM standalone (FIPS 203). Accept both the FIPS 203 spelling + * ("ML-KEM-N", per JDK 24 JEP 496 standard algo name registration) + * and the compact form. */ + case "MLKEM512": + case "ML-KEM-512": + return WolfSSL.WOLFSSL_ML_KEM_512; + case "MLKEM768": + case "ML-KEM-768": + return WolfSSL.WOLFSSL_ML_KEM_768; + case "MLKEM1024": + case "ML-KEM-1024": + return WolfSSL.WOLFSSL_ML_KEM_1024; + /* Hybrid IETF final codepoints. The IETF / IANA spellings use + * mixed case ("SecP256r1MLKEM768", "SecP384r1MLKEM1024"). Accept + * all caps variants too for usability. */ + case "X25519MLKEM768": + return WolfSSL.WOLFSSL_X25519MLKEM768; + case "SecP256r1MLKEM768": + case "SECP256R1MLKEM768": + return WolfSSL.WOLFSSL_SECP256R1MLKEM768; + case "SecP384r1MLKEM1024": + case "SECP384R1MLKEM1024": + return WolfSSL.WOLFSSL_SECP384R1MLKEM1024; + /* Hybrid OQS-assigned codepoints (legacy interop). */ + case "SECP256R1MLKEM512": + return WolfSSL.WOLFSSL_SECP256R1MLKEM512; + case "SECP384R1MLKEM768": + return WolfSSL.WOLFSSL_SECP384R1MLKEM768; + case "SECP521R1MLKEM1024": + return WolfSSL.WOLFSSL_SECP521R1MLKEM1024; + case "X25519MLKEM512": + return WolfSSL.WOLFSSL_X25519MLKEM512; + case "X448MLKEM768": + return WolfSSL.WOLFSSL_X448MLKEM768; default: return WolfSSL.WOLFSSL_NAMED_GROUP_INVALID; } } + /** + * Returns true if the given native named-group enum value identifies + * a post-quantum (ML-KEM) standalone or PQ/T hybrid TLS 1.3 group. + * + * @param namedGroup native named-group enum value, typically the + * result of {@link #getNamedGroupFromString(String)} + * or one of the WOLFSSL_ML_KEM_* / WOLFSSL_*MLKEM* + * constants on this class. + * @return true if the group is a PQC standalone or hybrid TLS 1.3 + * named group, false otherwise (including for + * {@link #WOLFSSL_NAMED_GROUP_INVALID} and any non-PQC + * named group). + */ + public static boolean isPQCNamedGroup(int namedGroup) { + switch (namedGroup) { + case WOLFSSL_ML_KEM_512: + case WOLFSSL_ML_KEM_768: + case WOLFSSL_ML_KEM_1024: + case WOLFSSL_X25519MLKEM768: + case WOLFSSL_SECP256R1MLKEM768: + case WOLFSSL_SECP384R1MLKEM1024: + case WOLFSSL_SECP256R1MLKEM512: + case WOLFSSL_SECP384R1MLKEM768: + case WOLFSSL_SECP521R1MLKEM1024: + case WOLFSSL_X25519MLKEM512: + case WOLFSSL_X448MLKEM768: + return true; + default: + return false; + } + } + @SuppressWarnings("deprecation") @Override protected void finalize() throws Throwable diff --git a/src/java/com/wolfssl/WolfSSLContext.java b/src/java/com/wolfssl/WolfSSLContext.java index 9a50d940..b560ee54 100644 --- a/src/java/com/wolfssl/WolfSSLContext.java +++ b/src/java/com/wolfssl/WolfSSLContext.java @@ -2364,7 +2364,7 @@ WolfSSLDebug.INFO, getContextPtr(), * @return WolfSSL.SSL_SUCCESS on success, otherwise negative * value on error. BAD_FUNC_ARG when groups is null, not using * TLS 1.3 or size is greater than WOLFSSL_MAX_GROUP_COUNT (which - * defaults to 10, unless HAVE_PQC is defined then is 36. + * defaults to 10, unless WOLFSSL_HAVE_MLKEM is defined then is 36. * @throws IllegalStateException WolfSSLContext has been freed */ public int setGroups(int[] groups) diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java index bb9ecb0e..4792ec23 100644 --- a/src/java/com/wolfssl/WolfSSLSession.java +++ b/src/java/com/wolfssl/WolfSSLSession.java @@ -709,6 +709,7 @@ private native int useALPNByteArray(long ssl, byte[] protocols, private native int rehandshake(long ssl); private native int set1SigAlgsList(long ssl, String list); private native int useSupportedCurve(long ssl, int name); + private native int useKeyShare(long ssl, int group); private native int disableExtendedMasterSecret(long ssl); private native int hasTicket(long session); private native int useClientSuites(long ssl); @@ -2638,33 +2639,38 @@ public int setSignatureAlgorithms(String list) } /** - * Sets the TLS Supported Curves to be used in the ClientHello - * extension if enabled in native wolfSSL. + * Sets the TLS Supported Curves to be used in the ClientHello extension + * if enabled in native wolfSSL. Multiple curves are appended to the + * extension via calls into native wolfSSL_UseSupportedCurve(). Iteration + * continues across all entries even after one fails. Curves that succeed + * are added, curves that fail are not. * - * @param curveNames String array of ECC curve names to set into the - * Supported Curve extension. String values should match names from - * the following list: - * "sect163k1", "sect163r1", "sect163r2", "sect193r1", - * "sect193r2", "sect233k1", "sect233r1", "sect239k1", - * "sect283k1", "sect283r1", "sect409k1", "sect409r1", - * "sect571k1", "sect571r1", "secp160k1", "secp160r1", - * "secp160r2", "secp192k1", "secp192r1", "secp224k1", - * "secp224r1", "secp256k1", "secp256r1", "secp384r1", - * "secp521r1", "brainpoolP256r1", "brainpoolP384r1", - * "brainpoolP512r1", "x25519", "x448", "sm2P256v1", - * "ffdhe2048", "ffdhe3072", "ffdhe4096", "ffdhe6144", - * "ffdhe8192" + * @param curveNames String array of named-group names to set into the + * Supported Curves extension. String values may be any token + * recognized by {@link WolfSSL#getNamedGroupFromString}, including + * classical curves (e.g. "secp256r1", "x25519", "ffdhe2048") and + * PQC ML-KEM standalone / hybrid groups (e.g. "ML-KEM-768", + * "X25519MLKEM768", "SECP384R1MLKEM1024"). * - * @return WolfSSL.SSL_SUCCESS on success, otherwise - * negative on error. + * @return WolfSSL.SSL_SUCCESS when every entry was accepted + * by native wolfSSL. Otherwise the first non-success return value + * encountered while iterating (typically BAD_FUNC_ARG for an + * unknown / unsupported group, or NOT_COMPILED_IN when + * supported_groups support is not compiled into native wolfSSL). + * Note: the call may have partially succeeded. Curves before/after + * the failing entry that were valid are still added to the + * extension. * @throws IllegalStateException WolfSSLSession has been freed */ public int useSupportedCurves(String[] curveNames) throws IllegalStateException { - int ret = 0; + int ret = WolfSSL.SSL_SUCCESS; + int firstError = WolfSSL.SSL_SUCCESS; int curveEnum = 0; + confirmObjectIsActive(); + synchronized (sslLock) { WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, WolfSSLDebug.INFO, this.sslPtr, @@ -2677,9 +2683,52 @@ public int useSupportedCurves(String[] curveNames) synchronized (sslLock) { ret = useSupportedCurve(this.sslPtr, curveEnum); } + /* Best-effort: keep adding subsequent curves even if this one + * failed. Remember the first failure so the caller can see + * something went wrong. Without this aggregation the return value + * would silently mask any failure that wasn't the last in list. */ + if ((ret != WolfSSL.SSL_SUCCESS) && + (firstError == WolfSSL.SSL_SUCCESS)) { + firstError = ret; + } } - return ret; + return firstError; + } + + /** + * Pre-generate a TLS 1.3 key share for the specified named group and + * include it in the ClientHello key_share extension. By default, native + * wolfSSL only sends key shares for the highest-priority group(s). + * For large PQC key shares (ML-KEM and hybrid groups) this typically + * forces a HelloRetryRequest round trip when the server selects a + * different group than the client guessed. + * + * Calling this for a PQC named group ensures the key share is sent up + * front, avoiding extra round trip when both peers agree on the PQC group. + * + * @param group named group constant from {@link WolfSSL}, for + * example {@link WolfSSL#WOLFSSL_X25519MLKEM768}. + * @return WolfSSL.SSL_SUCCESS on success. + * WolfSSL.NOT_COMPILED_IN when native wolfSSL was + * built without TLS 1.3. When TLS 1.3 is built but the requested + * named group is not supported by this build (ie: a PQC group on + * a non-PQC build, or X25519MLKEM768 without HAVE_CURVE25519), + * native wolfSSL_UseKeyShare() returns BAD_FUNC_ARG. + * Other negative values on internal error. + * @throws IllegalStateException WolfSSLSession has been freed + */ + public int useKeyShare(int group) throws IllegalStateException { + + confirmObjectIsActive(); + + synchronized (sslLock) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI, + WolfSSLDebug.INFO, this.sslPtr, + () -> "entered useKeyShare(" + group + ")"); + + return useKeyShare(this.sslPtr, group); + } } /** diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java index aa248c80..1a7045f0 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java @@ -260,6 +260,14 @@ private String GetKeyAndCertChainAlias(X509KeyManager km, Socket sock, } } + /* ML-DSA (FIPS 204) certificates, when enabled in native wolfSSL. + * Uses the JDK 24 / JEP 497 family name "ML-DSA". KeyManagers surface + * the family name regardless of the parameter set (ML-DSA-44/65/87) + * of the underlying key. */ + if (WolfSSL.MLDSAEnabled()) { + keyAlgos.add("ML-DSA"); + } + String[] keyTypes = new String[keyAlgos.size()]; keyTypes = keyAlgos.toArray(keyTypes); @@ -366,12 +374,31 @@ protected synchronized void loadKeyAndCertChain( "Private key is not in PKCS#8 format"); } - /* Skip past PKCS#8 offset */ - offset = WolfSSL.getPkcs8TraditionalOffset(privKeyEncoded, 0, - privKeyEncoded.length); + /* ML-DSA keys have no defined "traditional" (non-PKCS#8) form. + * The algorithm identifier in the PKCS#8 wrapper is what tells + * native wolfSSL which parameter set (44/65/87) to use. Pass + * the full PKCS#8 buffer through to native wolfSSL, which auto + * detects PKCS#8 and dispatches to wc_dilithium_import_private. + * Stripping the wrapper for ML-DSA would lose the algorithm + * identifier and cause native parse to fail. */ + String alg = privKey.getAlgorithm(); + boolean isMlDsa = (alg != null) && + (alg.startsWith("ML-DSA") || alg.startsWith("MLDSA") || + alg.equals("2.16.840.1.101.3.4.3.17") || + alg.equals("2.16.840.1.101.3.4.3.18") || + alg.equals("2.16.840.1.101.3.4.3.19")); + + if (isMlDsa) { + privKeyTraditional = privKeyEncoded; + } + else { + /* Skip past PKCS#8 offset */ + offset = WolfSSL.getPkcs8TraditionalOffset(privKeyEncoded, + 0, privKeyEncoded.length); - privKeyTraditional = Arrays.copyOfRange(privKeyEncoded, - offset, privKeyEncoded.length); + privKeyTraditional = Arrays.copyOfRange(privKeyEncoded, + offset, privKeyEncoded.length); + } try { ret = this.ssl.usePrivateKeyBuffer(privKeyTraditional, @@ -392,7 +419,10 @@ protected synchronized void loadKeyAndCertChain( if (privKeyEncoded != null) { Arrays.fill(privKeyEncoded, (byte)0); } - if (privKeyTraditional != null) { + /* For ML-DSA, privKeyTraditional aliases privKeyEncoded. + * Guard against redundant second array fill. */ + if (privKeyTraditional != null && + privKeyTraditional != privKeyEncoded) { Arrays.fill(privKeyTraditional, (byte)0); } } @@ -1360,35 +1390,181 @@ private void setLocalSigAlgorithms() { private void setLocalSupportedCurves() throws SSLException { - int ret = 0; + /* User-restricted curves list, if any. */ + String[] curves = WolfSSLUtil.getSupportedCurves(); + if (curves == null) { + return; + } - if (this.clientMode) { - /* Get restricted supported curves for ClientHello if set by - * user in "wolfjsse.enabledSupportedCurves" Security property */ - String[] curves = WolfSSLUtil.getSupportedCurves(); + applyToSupportedGroupsExtension(curves, + "wolfjsse.enabledSupportedCurves Security property", false); + } - if (curves != null) { - ret = this.ssl.useSupportedCurves(curves); - if (ret != WolfSSL.SSL_SUCCESS) { - if (ret == WolfSSL.NOT_COMPILED_IN) { - WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - () -> "Unable to set requested TLS Supported " + - "Curves, native support not compiled in."); - } - else { - throw new SSLException( - "Error setting TLS Supported Curves based on " + - "wolfjsse.enabledSupportedCurves property, ret = " + - ret + ", curves: " + Arrays.toString(curves)); - } + /** + * Apply NamedGroups configuration from both SSLParameters and + * jdk.tls.namedGroups System property. + * + * SSLParameters.setNamedGroups() takes precedence when set. The method was + * added in JDK 20 (JDK-8281236). If not set, fall back to the JSSE + * jdk.tls.namedGroups System property, which applies client-side only. + * + * Runs in addition to {@link #setLocalSupportedCurves()}; native + * useSupportedCurves accumulates across calls so both sources + * contribute to the final supported_groups extension. + */ + private void setLocalNamedGroups() throws SSLException { + + String[] namedGroups = + WolfSSLParametersHelper.getNamedGroupsFromParams(this.params); + + if (namedGroups != null) { + applyToSupportedGroupsExtension(namedGroups, + "SSLParameters.setNamedGroups()", true); + return; + } + + namedGroups = WolfSSLUtil.getJdkTlsNamedGroups(); + if (namedGroups != null) { + applyToSupportedGroupsExtension(namedGroups, + "jdk.tls.namedGroups System property", false); + } + } + + /** + * Apply a list of group identifiers to the TLS supported_groups + * extension on the native wolfSSL session. Filter PQC entries when + * TLS 1.3 is unavailable. + * + * @param groups list of group identifiers to apply + * @param source human-readable label used in log/error messages to + * identify which configuration produced the list + * @param serverSideRestrict when true, also restrict the server's + * accepted supported_groups; when false, restriction + * applies only in client mode + */ + private void applyToSupportedGroupsExtension(String[] groups, + String source, boolean serverSideRestrict) throws SSLException { + + /* Filter PQC named groups out of the list when TLS 1.3 is not in the + * enabled protocols. ML-KEM standalone and hybrid groups are TLS 1.3 + * only. Including them in TLS 1.2 ClientHello supported_groups results + * in either an empty effective list after the peer ignores them or, + * for our native useKeyShare call, a BAD_FUNC_ARG return. */ + String[] effectiveGroups = + filterPQCGroupsIfNoTLS13(groups, isTLS13Enabled()); + + if (effectiveGroups.length == 0) { + /* Every requested group was PQC and TLS 1.3 is off. */ + return; + } + + if (this.clientMode || serverSideRestrict) { + int ret = this.ssl.useSupportedCurves(effectiveGroups); + if (ret != WolfSSL.SSL_SUCCESS) { + if (ret == WolfSSL.NOT_COMPILED_IN) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + () -> "Unable to set supported_groups, native " + + "support not compiled in."); + return; } - else { + throw new SSLException( + "Error setting TLS supported_groups from " + source + + ", ret = " + ret + ", groups: " + + Arrays.toString(effectiveGroups)); + } + final String srcLog = source; + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + () -> "set TLS supported_groups from " + srcLog); + } + + /* On both client and server, pre-generate a TLS 1.3 key share for the + * first PQC group in the user's list. ML-KEM key shares are large + * (1+ KB). Having the keypair ready lets us avoid a HelloRetryRequest + * round trip when both peers agree on that group. */ + for (String groupName : effectiveGroups) { + int group = WolfSSL.getNamedGroupFromString(groupName); + if (WolfSSL.isPQCNamedGroup(group)) { + int ksRet = this.ssl.useKeyShare(group); + final int ksResult = ksRet; + final String name = groupName; + if (ksRet == WolfSSL.SSL_SUCCESS) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + () -> "pre-generated TLS 1.3 key share for PQC " + + "group: " + name); + } + else if (ksRet != WolfSSL.NOT_COMPILED_IN) { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - () -> "set TLS Supported Curves based on " + - "wolfjsse.enabledSupportedCurves property"); + () -> "failed to pre-generate key share for PQC " + + "group " + name + ", ret = " + ksResult); } + break; + } + } + } + + /** + * Returns true if "TLSv1.3" is part of the effective enabled protocols + * list for this engine. Used to decide whether PQC named groups are + * compatible with the active session. + */ + private boolean isTLS13Enabled() { + + String[] enabled = this.params.getProtocols(); + + if (enabled == null) { + /* Implementation default: TLS 1.3 is on iff native has it compiled + * in and it survives jdk.tls.disabledAlgorithms. */ + if (!WolfSSL.TLSv13Enabled()) { + return false; + } + String[] probe = WolfSSLUtil.sanitizeProtocols( + new String[] { "TLSv1.3" }, WolfSSL.TLS_VERSION.INVALID); + + return probe != null && probe.length > 0; + } + + for (String p : enabled) { + if ("TLSv1.3".equals(p)) { + return true; + } + } + return false; + } + + /** + * If TLS 1.3 is not enabled, returns a copy of {@code curves} with any + * PQC standalone or hybrid groups removed (they are TLS 1.3 only). Drops + * are logged at INFO. If TLS 1.3 is enabled, the input array is + * returned unchanged. + */ + private String[] filterPQCGroupsIfNoTLS13(String[] curves, + boolean tls13Enabled) { + + if (tls13Enabled) { + return curves; + } + + List kept = new ArrayList(curves.length); + List dropped = new ArrayList(); + + for (String c : curves) { + int g = WolfSSL.getNamedGroupFromString(c); + if (WolfSSL.isPQCNamedGroup(g)) { + dropped.add(c); + } + else { + kept.add(c); } } + + if (!dropped.isEmpty()) { + final String dl = dropped.toString(); + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + () -> "Filtering PQC named groups out of supported_groups " + + "(TLS 1.3 not enabled): " + dl); + } + + return kept.toArray(new String[0]); } private void setLocalMaximumPacketSize() { @@ -1529,6 +1705,7 @@ private void setLocalParams(SSLSocket socket, SSLEngine engine) this.setLocalSecureRenegotiation(); this.setLocalSigAlgorithms(); this.setLocalSupportedCurves(); + this.setLocalNamedGroups(); this.setLocalMaximumPacketSize(); this.setLocalExtendedMasterSecret(); this.setLocalPskSettings(); diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java b/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java index 58c2998a..f50cc0dd 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java @@ -1113,6 +1113,11 @@ public String[] getLocalSupportedSignatureAlgorithms() { if (WolfSSL.RsaPssEnabled()) { algs.add("RSASSA-PSS"); } + if (WolfSSL.MLDSAEnabled()) { + algs.add("ML-DSA-44"); + algs.add("ML-DSA-65"); + algs.add("ML-DSA-87"); + } return algs.toArray(new String[algs.size()]); } diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java b/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java index fdd13f41..2f931caa 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLInternalVerifyCb.java @@ -439,7 +439,7 @@ else if (eng != null) { * Native wolfSSL verify callback. * * @param preverify_ok Will be 1 if native wolfSSL verification - * procedured have passed, otherwise 0. + * procedures have passed, otherwise 0. * @param x509StorePtr Native pointer to WOLFSSL_X509_STORE structure * * @return 1 if verification should be considered successful and @@ -479,8 +479,7 @@ public int verifyCallback(int preverify_ok, long x509StorePtr) { try { /* Get WolfSSLCertificate[] from x509StorePtr, certs from * store.getCerts() should be listed in order of peer to root */ - WolfSSLX509StoreCtx store = - new WolfSSLX509StoreCtx(x509StorePtr); + WolfSSLX509StoreCtx store = new WolfSSLX509StoreCtx(x509StorePtr); certs = store.getCerts(); } catch (WolfSSLException e) { @@ -511,9 +510,12 @@ public int verifyCallback(int preverify_ok, long x509StorePtr) { x509certs = new X509Certificate[0]; } - /* get authType, use first cert */ + /* get authType, use first cert. Order matters: check "ML-DSA" + * before "DSA" since the latter is a substring of the former. */ String sigType = certs[0].getSignatureType(); - if (sigType.contains("RSA")) { + if (sigType.contains("ML-DSA")) { + authType = "ML-DSA"; + } else if (sigType.contains("RSA")) { authType = "RSA"; } else if (sigType.contains("ECDSA")) { authType = "ECDSA"; diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java b/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java index 1681b80a..625d87fd 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java @@ -127,6 +127,14 @@ protected synchronized WolfSSLParameters copy() { cp.setSNIMatchers(this.getSNIMatchers()); cp.setServerNames(this.getServerNames()); + /* SSLParameters.setNamedGroups() (added in JDK 20, JDK-8281236). + * Round-trip via reflection so this compiles on Java 8 baseline, + * otherwise no-op. */ + String[] ng = WolfSSLParametersHelper.getNamedGroupsFromParams(this); + if (ng != null) { + WolfSSLParametersHelper.setNamedGroupsOnParams(cp, ng); + } + return cp; } diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java index e8103aa5..ce596ce0 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java @@ -45,6 +45,8 @@ public class WolfSSLParametersHelper private static Method setMaximumPacketSize = null; private static Method setUseCipherSuitesOrder = null; private static Method getUseCipherSuitesOrder = null; + private static Method getNamedGroups = null; + private static Method setNamedGroups = null; /** Default WolfSSLParametersHelper constructor */ public WolfSSLParametersHelper() { } @@ -99,6 +101,12 @@ public Object run() { case "getUseCipherSuitesOrder": getUseCipherSuitesOrder = m; continue; + case "getNamedGroups": + getNamedGroups = m; + continue; + case "setNamedGroups": + setNamedGroups = m; + continue; default: continue; } @@ -215,6 +223,15 @@ protected static SSLParameters decoupleParams(WolfSSLParameters in) { /* Not available, just ignore and continue */ } + try { + String[] groups = getNamedGroupsFromParams(in); + if (groups != null) { + setNamedGroupsOnParams(ret, groups); + } + } catch (Exception e) { + /* Not available, just ignore and continue */ + } + /* The following SSLParameters features are not yet supported * by wolfJSSE (see Android API 23 note above). They are supported * with newer versions of SSLParameters, but will need to be added @@ -337,6 +354,15 @@ protected static void importParams(SSLParameters in, /* Not available, just ignore and continue */ } + try { + String[] groups = getNamedGroupsFromParams(in); + if (groups != null) { + setNamedGroupsOnParams(out, groups); + } + } catch (Exception e) { + /* Not available, just ignore and continue */ + } + /* If input is a WolfSSLParameters, copy wolfJSSE specific fields * that are not part of the standard SSLParameters API */ if (in instanceof WolfSSLParameters) { @@ -376,5 +402,53 @@ protected static void importParams(SSLParameters in, } } } + + /** + * Reflective accessor for SSLParameters.getNamedGroups(). Returns the + * named groups array if the host JDK has the method and the application + * set a value, otherwise null. + * + * @param in SSLParameters instance to read from (may be null) + * @return cloned named-groups array, or null if unset / unavailable + */ + public static String[] getNamedGroupsFromParams(SSLParameters in) { + + if (in == null || getNamedGroups == null) { + return null; + } + + try { + Object val = getNamedGroups.invoke(in); + if (val instanceof String[]) { + String[] arr = (String[]) val; + return arr.clone(); + } + } catch (IllegalAccessException | InvocationTargetException e) { + /* fall through to null */ + } + + return null; + } + + /** + * Reflective mutator for SSLParameters.setNamedGroups(). Noop when the + * host JDK does not expose the method. + * + * @param out SSLParameters instance to write to (must be non-null) + * @param groups named-groups array to set (may be null to clear) + */ + public static void setNamedGroupsOnParams(SSLParameters out, + String[] groups) { + + if (out == null || setNamedGroups == null) { + return; + } + + try { + setNamedGroups.invoke(out, (Object) groups); + } catch (IllegalAccessException | InvocationTargetException e) { + /* Noop on failure */ + } + } } diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java b/src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java index b04a78f0..f0a53a50 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java @@ -249,8 +249,7 @@ else if (sigAlgs != null && sigSchemes == null) { sigSchemes = sigSchemes.trim(); String[] schemes = sigSchemes.split(","); - /* Tokenize scheme components and convert to signature - algorithm format */ + /* Tokenize scheme components and convert to signature algo format */ for (String scheme : schemes) { scheme = scheme.toUpperCase(); if (scheme.isEmpty()) { @@ -268,10 +267,29 @@ else if (sigAlgs != null && sigSchemes == null) { sigAlgList.add(algorithm); } continue; - } else { - /* Invalid format, skip */ + } + /* Map the compact IETF SignatureScheme spelling "MLDSA44/65/87" + * (as accepted in jdk.tls.{client,server}.SignatureSchemes) to + * the canonical FIPS 204 name "ML-DSA-44/65/87" used by + * native wolfSSL. */ + String mldsaCanonical = null; + if (algorithm.equals("MLDSA44")) { + mldsaCanonical = "ML-DSA-44"; + } + else if (algorithm.equals("MLDSA65")) { + mldsaCanonical = "ML-DSA-65"; + } + else if (algorithm.equals("MLDSA87")) { + mldsaCanonical = "ML-DSA-87"; + } + if (mldsaCanonical != null) { + if (!sigAlgList.contains(mldsaCanonical)) { + sigAlgList.add(mldsaCanonical); + } continue; } + /* Invalid format, skip */ + continue; } if (schemeComp.length < 2) { @@ -405,16 +423,22 @@ protected static String getSignatureSchemes(boolean clientMode) { } /** - * Return TLS Supported Curves allowed if set in - * wolfjsse.enabledSupportedCurves system Security property. - * - * @return String array of Supported Curves to be set into the - * TLS ClientHello. + * Return TLS supported curves to be set in the supported_groups extension, + * as configured by wolfJSSE {@code wolfjsse.enabledSupportedCurves} + * Security property. + * + *

For the broader TLS 1.3 named-groups configuration (the JSSE + * {@code jdk.tls.namedGroups} System property and + * {@code SSLParameters.setNamedGroups()} API added in JDK 20 + * (JDK-8281236)), see {@link #getJdkTlsNamedGroups()} and + * {@link WolfSSLParametersHelper#getNamedGroupsFromParams}. Each + * source is read and applied independently. + * + * @return String array of named groups, or null if property unset. */ protected static String[] getSupportedCurves() { - String curves = - Security.getProperty("wolfjsse.enabledSupportedCurves"); + String curves = Security.getProperty("wolfjsse.enabledSupportedCurves"); if (curves == null || curves.isEmpty()) { return null; @@ -432,6 +456,33 @@ protected static String[] getSupportedCurves() { return curves.split(","); } + /** + * Return TLS named groups to be set in the supported_groups extension, + * as configured by the JSSE {@code jdk.tls.namedGroups} System property. + * + *

{@code SSLParameters.setNamedGroups()} takes precedence over this + * System property. + * + * @return String array of named groups, or null if property unset. + */ + protected static String[] getJdkTlsNamedGroups() { + + String groups = System.getProperty("jdk.tls.namedGroups"); + + if (groups == null || groups.isEmpty()) { + return null; + } + + final String tmpGroups = groups; + WolfSSLDebug.log(WolfSSLUtil.class, WolfSSLDebug.INFO, + () -> "jdk.tls.namedGroups: " + tmpGroups); + + /* Remove spaces between commas if present */ + groups = groups.replaceAll(", ", ","); + + return groups.split(","); + } + /** * Return KeyStore type restriction if set in java.security * with 'wolfjsse.keystore.type.required' Security property. diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLCNSA2Test.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLCNSA2Test.java new file mode 100644 index 00000000..a615f3ea --- /dev/null +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLCNSA2Test.java @@ -0,0 +1,236 @@ +/* WolfSSLCNSA2Test.java + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +package com.wolfssl.provider.jsse.test; + +import com.wolfssl.WolfSSL; +import com.wolfssl.WolfSSLException; +import com.wolfssl.provider.jsse.WolfSSLProvider; +import com.wolfssl.test.TimedTestWatcher; +import java.security.NoSuchProviderException; +import java.security.Security; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Composite CNSA 2.0 (Commercial National Security Algorithm Suite 2.0) + * compliance test. + * - TLS 1.3 only + * - Key exchange: SECP384R1MLKEM1024 (ML-KEM-1024 hybrid w/ classical + * bridge, the highest-security ML-KEM parameter set per FIPS 203) + * - Authentication: ML-DSA-87 X.509 certificates (FIPS 204 Cat 5) + * - Cipher suite: TLS_AES_256_GCM_SHA384 (mandated by CNSA 2.0) + * + * Skipped when native wolfSSL was not built with --enable-mlkem or + * --enable-mldsa, when TLS 1.3 is not compiled in, or when the + * gen-mldsa-certs.sh PEM artifacts are absent. + */ +public class WolfSSLCNSA2Test { + + private static final String PROVIDER = "wolfJSSE"; + private static final String CURVES_PROP = "wolfjsse.enabledSupportedCurves"; + + private static final String SERVER_CERT = + "examples/certs/pqc/server-mldsa87.pem"; + private static final String SERVER_KEY = + "examples/certs/pqc/server-mldsa87-priv.pem"; + private static final String ROOT_CERT = + "examples/certs/pqc/root-mldsa87.pem"; + + /* Process-global lock around wolfjsse.enabledSupportedCurves */ + private static final Object curvesPropLock = new Object(); + + private static WolfSSLTestFactory tf; + + @Rule + public TestRule testWatcher = TimedTestWatcher.create(); + + @BeforeClass + public static void setUp() + throws NoSuchProviderException, WolfSSLException { + + System.out.println("WolfSSLCNSA2 Class"); + + Security.insertProviderAt(new WolfSSLProvider(), 1); + tf = new WolfSSLTestFactory(); + } + + @Test + public void testCNSA2_FullStack() throws Exception { + + Assume.assumeTrue(WolfSSL.MLKEMEnabled() && WolfSSL.MLDSAEnabled() && + WolfSSL.TLSv13Enabled()); + + Assume.assumeTrue("PQC cert PEM missing; run gen-mldsa-certs.sh first", + WolfSSLPQCTestUtil.pqcCertExists(ROOT_CERT)); + + Assume.assumeTrue(WolfSSLPQCTestUtil.MLDSA_CERT_PARSING_SKIP_MSG, + WolfSSLPQCTestUtil.nativeMlDsaCertParsingSupported()); + + synchronized (curvesPropLock) { + String prevCurves = Security.getProperty(CURVES_PROP); + try { + /* Restrict supported_groups to ML-KEM-1024 hybrid (CNSA 2.0 + * level). With no classical fallback in the list, a + * successful handshake proves PQC kex actually happened. */ + Security.setProperty(CURVES_PROP, "SECP384R1MLKEM1024"); + + KeyManager[] serverKm = WolfSSLPQCTestUtil.keyManagerFromPem( + "server-mldsa87", SERVER_CERT, SERVER_KEY, "ML-DSA-87"); + TrustManager[] clientTm = + WolfSSLPQCTestUtil.trustManagerFromPem(ROOT_CERT); + + SSLContext serverCtx = tf.createSSLContext("TLSv1.3", + PROVIDER, null, serverKm); + SSLContext clientCtx = tf.createSSLContext("TLSv1.3", + PROVIDER, clientTm, null); + + SSLEngine server = serverCtx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + /* Restrict to the CNSA-mandated cipher suite. */ + server.setEnabledCipherSuites( + new String[] { "TLS_AES_256_GCM_SHA384" }); + + SSLEngine client = clientCtx.createSSLEngine( + "wolfSSL CNSA2 test", 11111); + client.setUseClientMode(true); + client.setEnabledCipherSuites( + new String[] { "TLS_AES_256_GCM_SHA384" }); + + int ret = tf.testConnection(server, client, + new String[] { "TLS_AES_256_GCM_SHA384" }, + new String[] { "TLSv1.3" }, "CNSA 2.0 test"); + assertEquals("CNSA 2.0 handshake should succeed", 0, ret); + + /* Confirm post-handshake session attributes match the + * CNSA 2.0 mandate. */ + SSLSession sess = client.getSession(); + assertEquals("TLS protocol must be TLSv1.3", + "TLSv1.3", sess.getProtocol()); + assertEquals("Cipher suite must be TLS_AES_256_GCM_SHA384", + "TLS_AES_256_GCM_SHA384", sess.getCipherSuite()); + + } finally { + if (prevCurves == null) { + Security.setProperty(CURVES_PROP, ""); + } + else { + Security.setProperty(CURVES_PROP, prevCurves); + } + } + } + } + + /** + * Negative case: a client offers TLS 1.2 against a TLS-1.3-only server + * must fail. CNSA 2.0 mandates TLS 1.3. This verifies we do not silently + * downgrade to TLS 1.2. + * + * The client SSLContext is built with the wildcard protocol "TLS" so we + * can downgrade test it. setEnabledProtocols() is called SSLEngine, not + * via testConnection protocols argument. + */ + @Test + public void testCNSA2_NoFallbackToTls12() throws Exception { + + Assume.assumeTrue(WolfSSL.MLKEMEnabled() && WolfSSL.MLDSAEnabled() && + WolfSSL.TLSv13Enabled() && WolfSSL.TLSv12Enabled()); + + Assume.assumeTrue("PQC cert PEM missing; run gen-mldsa-certs.sh first", + WolfSSLPQCTestUtil.pqcCertExists(ROOT_CERT)); + + synchronized (curvesPropLock) { + String prevCurves = Security.getProperty(CURVES_PROP); + try { + Security.setProperty(CURVES_PROP, "SECP384R1MLKEM1024"); + + KeyManager[] serverKm = WolfSSLPQCTestUtil.keyManagerFromPem( + "server-mldsa87", SERVER_CERT, SERVER_KEY, "ML-DSA-87"); + TrustManager[] clientTm = + WolfSSLPQCTestUtil.trustManagerFromPem(ROOT_CERT); + + /* Server context locked to TLS 1.3 (CNSA 2.0 mandate). */ + SSLContext serverCtx = tf.createSSLContext("TLSv1.3", + PROVIDER, null, serverKm); + /* Client context "TLS" so we can choose to offer TLS 1.2 and + * observe whether the server agrees to downgrade. */ + SSLContext clientCtx = tf.createSSLContext("TLS", PROVIDER, + clientTm, null); + + SSLEngine server = serverCtx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + server.setEnabledProtocols(new String[] { "TLSv1.3" }); + server.setEnabledCipherSuites( + new String[] { "TLS_AES_256_GCM_SHA384" }); + + SSLEngine client = clientCtx.createSSLEngine( + "wolfSSL CNSA2 test", 11111); + client.setUseClientMode(true); + /* Client offers only TLS 1.2. No TLS 1.3 in the + * supported_versions extension, means server has no shared + * version and handshake must fail. */ + client.setEnabledProtocols(new String[] { "TLSv1.2" }); + + /* Pick any TLS 1.2 cipher the client supports so the + * ClientHello is well formed. The test isn't checking cipher + * selection, just protocol selection. */ + String picked = null; + for (String s : client.getSupportedCipherSuites()) { + if (s.startsWith("TLS_ECDHE_") || + s.startsWith("TLS_RSA_")) { + picked = s; + break; + } + } + Assume.assumeNotNull(picked); + client.setEnabledCipherSuites(new String[] { picked }); + + /* Pass null protocols so testConnection does not make both + * engines have the same. */ + int ret = tf.testConnection(server, client, null, null, + "CNSA 2.0 test"); + assertTrue("Handshake must fail when client offers TLS 1.2 " + + "to a TLS-1.3-only CNSA server (no downgrade allowed), " + + "got ret = " + ret, ret != 0); + + } finally { + if (prevCurves == null) { + Security.setProperty(CURVES_PROP, ""); + } + else { + Security.setProperty(CURVES_PROP, prevCurves); + } + } + } + } +} diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLJSSETestSuite.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLJSSETestSuite.java index e1d79c91..2a45790d 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLJSSETestSuite.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLJSSETestSuite.java @@ -39,7 +39,12 @@ WolfSSLX509Test.class, WolfSSLKeyX509Test.class, WolfSSLServiceLoaderTest.class, - WolfSSLParametersPskTest.class + WolfSSLParametersPskTest.class, + WolfSSLNamedGroupsTest.class, + WolfSSLPQCKeyExchangeTest.class, + WolfSSLPQCAuthenticationTest.class, + WolfSSLPQCAuthKeyStoreTest.class, + WolfSSLCNSA2Test.class }) diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLNamedGroupsTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLNamedGroupsTest.java new file mode 100644 index 00000000..ec24a88d --- /dev/null +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLNamedGroupsTest.java @@ -0,0 +1,470 @@ +/* WolfSSLNamedGroupsTest.java + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +package com.wolfssl.provider.jsse.test; + +import com.wolfssl.WolfSSL; +import com.wolfssl.WolfSSLException; +import com.wolfssl.provider.jsse.WolfSSLParametersHelper; +import com.wolfssl.provider.jsse.WolfSSLProvider; +import com.wolfssl.test.TimedTestWatcher; +import java.lang.reflect.Method; +import java.security.NoSuchProviderException; +import java.security.Security; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +/** + * Tests for SSLParameters.setNamedGroups() / getNamedGroups() integration in + * wolfJSSE. + * + * Coverage: + * - Reflection bridge in WolfSSLParametersHelper returns null cleanly + * when the host JDK lacks the methods. + * - When present, per-engine/socket setNamedGroups() overrides the global + * wolfjsse.enabledSupportedCurves Security property. + * - getNamedGroups() round-trips through SSLEngine via reflection. + * + * Per-method Assume.assume* skips handle JDKs that don't expose the methods. + */ +public class WolfSSLNamedGroupsTest { + + private static final String PROVIDER = "wolfJSSE"; + private static final String CURVES_PROP = "wolfjsse.enabledSupportedCurves"; + private static final String JDK_GROUPS_PROP = "jdk.tls.namedGroups"; + private static final String APP_DATA = "named groups test"; + + /* Process-global lock around the named-groups static properties. */ + private static final Object curvesPropLock = new Object(); + + private static WolfSSLTestFactory tf; + private static boolean jdkHasNamedGroups = false; + + @Rule + public TestRule testWatcher = TimedTestWatcher.create(); + + @BeforeClass + public static void setUp() + throws NoSuchProviderException, WolfSSLException { + + System.out.println("WolfSSLNamedGroups Class"); + + Security.insertProviderAt(new WolfSSLProvider(), 1); + tf = new WolfSSLTestFactory(); + + try { + SSLParameters.class.getMethod("setNamedGroups", String[].class); + SSLParameters.class.getMethod("getNamedGroups"); + jdkHasNamedGroups = true; + + } catch (NoSuchMethodException e) { + jdkHasNamedGroups = false; + } + } + + /** + * Reflection helper must return null cleanly when the host JDK does not + * expose SSLParameters.set/getNamedGroups, so callers can safely fall back + * to the Security property without special handling for the JDK version. + */ + @Test + public void testHelper_returnsNullWhenApiAbsent() { + + Assume.assumeFalse( + "Host JDK has SSLParameters.setNamedGroups/getNamedGroups", + jdkHasNamedGroups); + + SSLParameters p = new SSLParameters(); + assertNull("getNamedGroupsFromParams must return null on a JDK " + + "without SSLParameters.getNamedGroups", + WolfSSLParametersHelper.getNamedGroupsFromParams(p)); + + /* setNamedGroupsOnParams must be a clean no-op on a JDK without + * SSLParameters.setNamedGroups. */ + WolfSSLParametersHelper.setNamedGroupsOnParams(p, + new String[] { "X25519MLKEM768" }); + assertNull(WolfSSLParametersHelper.getNamedGroupsFromParams(p)); + } + + /** + * When the host JDK exposes SSLParameters.setNamedGroups, the helper must + * round-trip the value through reflection. + */ + @Test + public void testHelper_roundTripsViaReflection() throws Exception { + + Assume.assumeTrue("Host JDK lacks SSLParameters.setNamedGroups", + jdkHasNamedGroups); + + SSLParameters p = new SSLParameters(); + String[] groups = new String[] { + "X25519MLKEM768", "SecP256r1MLKEM768", "x25519" + }; + + Method setM = SSLParameters.class.getMethod("setNamedGroups", + String[].class); + setM.invoke(p, (Object) groups); + + String[] back = WolfSSLParametersHelper.getNamedGroupsFromParams(p); + assertArrayEquals("Round-tripped named groups must match", groups, + back); + + /* Mutating the returned array must not affect the stored value + * (helper returns a clone). */ + if (back != null) { + back[0] = "MUTATED"; + String[] back2 = + WolfSSLParametersHelper.getNamedGroupsFromParams(p); + assertEquals("getNamedGroupsFromParams must return a defensive " + + "copy", "X25519MLKEM768", back2[0]); + } + } + + /** + * Per SSLEngine SSLParameters.setNamedGroups() must override the global + * wolfjsse.enabledSupportedCurves Security property and successfully + * do a TLS 1.3 PQC handshake. + */ + @Test + public void testEngineHonorsPerEngineNamedGroups() throws Exception { + + Assume.assumeTrue("Host JDK lacks SSLParameters.setNamedGroups", + jdkHasNamedGroups); + Assume.assumeTrue("ML-KEM not enabled in native wolfSSL", + WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + + synchronized (curvesPropLock) { + String prev = Security.getProperty(CURVES_PROP); + try { + /* Set a wrong group at the global property level. + * SSLEngine setNamedGroups should take precedence. */ + Security.setProperty(CURVES_PROP, "secp256r1"); + + SSLContext ctx = tf.createSSLContext("TLSv1.3", PROVIDER); + SSLEngine server = ctx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + SSLEngine client = + ctx.createSSLEngine("wolfSSL named groups test", 11111); + client.setUseClientMode(true); + + /* Apply SSLEngine override on both sides. */ + Method setM = SSLParameters.class.getMethod( + "setNamedGroups", String[].class); + String[] perEngine = new String[] { "SECP256R1MLKEM768" }; + + SSLParameters cp = client.getSSLParameters(); + setM.invoke(cp, (Object) perEngine); + client.setSSLParameters(cp); + + SSLParameters sp = server.getSSLParameters(); + setM.invoke(sp, (Object) perEngine); + server.setSSLParameters(sp); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + assertEquals("Per-engine setNamedGroups should drive a " + + "successful PQC handshake", 0, ret); + } + finally { + if (prev == null) { + Security.setProperty(CURVES_PROP, ""); + } + else { + Security.setProperty(CURVES_PROP, prev); + } + } + } + } + + /** + * Server-side application of SSLEngine setNamedGroups. When the server + * restricts itself to a PQC group via setNamedGroups but the client + * offers only classical groups, the handshake must fail (no common group). + */ + @Test + public void testServerNamedGroupsRestriction() throws Exception { + + Assume.assumeTrue("Host JDK lacks SSLParameters.setNamedGroups", + jdkHasNamedGroups); + Assume.assumeTrue("ML-KEM not enabled in native wolfSSL", + WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + + synchronized (curvesPropLock) { + String prev = Security.getProperty(CURVES_PROP); + try { + Security.setProperty(CURVES_PROP, ""); + + SSLContext ctx = tf.createSSLContext("TLSv1.3", PROVIDER); + + /* Server restricts to PQC only. */ + SSLEngine server = ctx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + Method setM = SSLParameters.class.getMethod( + "setNamedGroups", String[].class); + SSLParameters sp = server.getSSLParameters(); + setM.invoke(sp, (Object) new String[] { + "SECP384R1MLKEM1024" + }); + server.setSSLParameters(sp); + + /* Client offers only classical groups. */ + SSLEngine client = + ctx.createSSLEngine("wolfSSL named groups test", 11111); + client.setUseClientMode(true); + SSLParameters cp = client.getSSLParameters(); + setM.invoke(cp, (Object) new String[] { "secp256r1" }); + client.setSSLParameters(cp); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + assertFalse("Handshake must fail: server restricts to PQC, " + + "client offers classical only", ret == 0); + } + finally { + if (prev == null) { + Security.setProperty(CURVES_PROP, ""); + } + else { + Security.setProperty(CURVES_PROP, prev); + } + } + } + } + + /** + * With no SSLEngine override and no Security property set, the helper + * must report null. + */ + @Test + public void testHelper_unsetReturnsNull() { + + SSLParameters p = new SSLParameters(); + String[] result = WolfSSLParametersHelper.getNamedGroupsFromParams(p); + assertNull("Unset SSLParameters.namedGroups must surface as null", + result); + } + + /** + * getNamedGroupsFromParams must tolerate a null input without throwing. + */ + @Test + public void testHelper_nullInputReturnsNull() { + + assertNull(WolfSSLParametersHelper.getNamedGroupsFromParams(null)); + } + + /** + * jdk.tls.namedGroups System property alone (no wolfJSSE Security prop or + * SSLEngine override) must do a successful PQC handshake. + */ + @Test + public void testJdkTlsNamedGroupsAloneDrivesHandshake() throws Exception { + + Assume.assumeTrue("ML-KEM not enabled in native wolfSSL", + WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + + synchronized (curvesPropLock) { + String prevWolf = Security.getProperty(CURVES_PROP); + String prevJdk = System.getProperty(JDK_GROUPS_PROP); + try { + Security.setProperty(CURVES_PROP, ""); + System.setProperty(JDK_GROUPS_PROP, "SECP256R1MLKEM768"); + + SSLContext ctx = tf.createSSLContext("TLSv1.3", PROVIDER); + SSLEngine server = ctx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + SSLEngine client = + ctx.createSSLEngine("wolfSSL named groups test", 11111); + client.setUseClientMode(true); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + assertEquals("jdk.tls.namedGroups alone should drive a " + + "successful PQC handshake", 0, ret); + } + finally { + if (prevWolf == null) { + Security.setProperty(CURVES_PROP, ""); + } + else { + Security.setProperty(CURVES_PROP, prevWolf); + } + if (prevJdk == null) { + System.clearProperty(JDK_GROUPS_PROP); + } + else { + System.setProperty(JDK_GROUPS_PROP, prevJdk); + } + } + } + } + + /** + * Both static properties set. Each is read by its own helper and applied + * via separate native useSupportedCurves call. The two lists accumulate in + * native wolfSSL's supported_groups extension. + * + * Verifies that each property is read independently (no cross + * contamination), and successful handshake negotiates supported groups. + */ + @Test + public void testStaticPropertiesIndependentlyApplied() throws Exception { + + Assume.assumeTrue("ML-KEM not enabled in native wolfSSL", + WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + + synchronized (curvesPropLock) { + String prevWolf = Security.getProperty(CURVES_PROP); + String prevJdk = System.getProperty(JDK_GROUPS_PROP); + try { + /* wolfJSSE property has only the legacy hybrid (server won't + * accept this if alone); jdk.tls.namedGroups has the working + * IETF hybrid. Both should be applied. The handshake must + * succeed because the IETF hybrid is in the union. */ + Security.setProperty(CURVES_PROP, "secp256r1"); + System.setProperty(JDK_GROUPS_PROP, "SECP256R1MLKEM768"); + + /* Each helper returns only its own property's contents. */ + Method getSC = com.wolfssl.provider.jsse.WolfSSLUtil.class + .getDeclaredMethod("getSupportedCurves"); + getSC.setAccessible(true); + String[] sc = (String[]) getSC.invoke(null); + assertArrayEquals( + "getSupportedCurves must read only wolfJSSE property", + new String[] { "secp256r1" }, sc); + + Method getJdk = com.wolfssl.provider.jsse.WolfSSLUtil.class + .getDeclaredMethod("getJdkTlsNamedGroups"); + getJdk.setAccessible(true); + String[] jdk = (String[]) getJdk.invoke(null); + assertArrayEquals( + "getJdkTlsNamedGroups must read only JDK property", + new String[] { "SECP256R1MLKEM768" }, jdk); + + /* End-to-end: both apply, native union enables both groups, + * handshake picks one. */ + SSLContext ctx = tf.createSSLContext("TLSv1.3", PROVIDER); + SSLEngine server = ctx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + SSLEngine client = + ctx.createSSLEngine("wolfSSL named groups test", 11111); + client.setUseClientMode(true); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + assertEquals("Both static properties together should " + + "drive a successful handshake", 0, ret); + } + finally { + if (prevWolf == null) { + Security.setProperty(CURVES_PROP, ""); + } + else { + Security.setProperty(CURVES_PROP, prevWolf); + } + if (prevJdk == null) { + System.clearProperty(JDK_GROUPS_PROP); + } + else { + System.setProperty(JDK_GROUPS_PROP, prevJdk); + } + } + } + } + + /** + * SSLEngine setNamedGroups must override jdk.tls.namedGroups, like it + * overrides the wolfJSSE Security property. Sets a wrong group + * jdk.tls.namedGroups, then SSLEngine overrides with the right one, and + * the handshake must succeed. + */ + @Test + public void testPerEngineOverridesJdkProperty() throws Exception { + + Assume.assumeTrue("Host JDK lacks SSLParameters.setNamedGroups", + jdkHasNamedGroups); + Assume.assumeTrue("ML-KEM not enabled in native wolfSSL", + WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + + synchronized (curvesPropLock) { + String prevWolf = Security.getProperty(CURVES_PROP); + String prevJdk = System.getProperty(JDK_GROUPS_PROP); + + try { + Security.setProperty(CURVES_PROP, ""); + System.setProperty(JDK_GROUPS_PROP, "secp256r1"); + + SSLContext ctx = tf.createSSLContext("TLSv1.3", PROVIDER); + SSLEngine server = ctx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + SSLEngine client = + ctx.createSSLEngine("wolfSSL named groups test", 11111); + client.setUseClientMode(true); + + Method setM = SSLParameters.class.getMethod( + "setNamedGroups", String[].class); + String[] perEngine = new String[] { "SECP256R1MLKEM768" }; + + SSLParameters cp = client.getSSLParameters(); + setM.invoke(cp, (Object) perEngine); + client.setSSLParameters(cp); + + SSLParameters sp = server.getSSLParameters(); + setM.invoke(sp, (Object) perEngine); + server.setSSLParameters(sp); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + assertEquals("Per-engine setNamedGroups must override " + + "jdk.tls.namedGroups", 0, ret); + } + finally { + if (prevWolf == null) { + Security.setProperty(CURVES_PROP, ""); + } + else { + Security.setProperty(CURVES_PROP, prevWolf); + } + if (prevJdk == null) { + System.clearProperty(JDK_GROUPS_PROP); + } + else { + System.setProperty(JDK_GROUPS_PROP, prevJdk); + } + } + } + } +} diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCAuthKeyStoreTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCAuthKeyStoreTest.java new file mode 100644 index 00000000..941fbd28 --- /dev/null +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCAuthKeyStoreTest.java @@ -0,0 +1,211 @@ +/* WolfSSLPQCAuthKeyStoreTest.java + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +package com.wolfssl.provider.jsse.test; + +import com.wolfssl.WolfSSL; +import com.wolfssl.provider.jsse.WolfSSLProvider; +import com.wolfssl.test.TimedTestWatcher; +import java.io.File; +import java.io.FileInputStream; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManagerFactory; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import static org.junit.Assert.assertEquals; + +/** + * ML-DSA cert authentication tests via standard JCE KeyStore. Covers both + * JKS and PKCS12 store types. PKCS12 is the JDK 24+ default keystore type, + * JKS is included for backward-compatibility coverage. + * + * Exercises the standard Java security stack that a typical JDK 24+ app + * would use: + * - KeyStore.getInstance() to load an ML-DSA private key + cert chain + * - KeyManagerFactory / TrustManagerFactory through wolfJSSE + * - Standard SSLContext.init() + * + * Skipped on JDK less than 24: ML-DSA KeyFactory was added in JEP 497 (JDK 24). + * Older JDKs cannot load ML-DSA private keys from a standard keystore, but the + * keystore files themselves are only opened when this test runs. + * + * The test fixtures (server-mldsa{44,65,87}.{jks,p12} and + * ca-mldsa{44,65,87}.{jks,p12} under examples/provider/) are produced by + * examples/provider/update-keystore-pqc.sh, which requires JDK 24+. + * + * For coverage on older JDKs (or when not relying on a JCE keystore at all), + * see {@link WolfSSLPQCAuthenticationTest}, which loads PEM keys through a + * custom KeyManager. + */ +public class WolfSSLPQCAuthKeyStoreTest { + + private static final String PROVIDER = "wolfJSSE"; + private static final String APP_DATA = "PQC keystore test"; + private static final char[] STORE_PASS = "wolfSSL test".toCharArray(); + + private static WolfSSLTestFactory tf; + private static boolean jdkHasMlDsa = false; + + @Rule + public TestRule testWatcher = TimedTestWatcher.create(); + + @BeforeClass + public static void setUp() throws Exception { + + System.out.println("WolfSSLPQCAuthKeyStore Class"); + + Security.insertProviderAt(new WolfSSLProvider(), 1); + tf = new WolfSSLTestFactory(); + + /* Probe for ML-DSA KeyFactory (JEP 497, JDK 24+). Cached for lifetime + * of the test class so all @Test methods can do a cheap check. */ + try { + KeyFactory.getInstance("ML-DSA"); + jdkHasMlDsa = true; + } catch (NoSuchAlgorithmException e) { + jdkHasMlDsa = false; + } + } + + /** + * Shared per-test precondition check. Routes through Assume so the + * TimedTestWatcher reports SKIP rather than the test failing. + */ + private void preconditions(String storeFilename) { + + Assume.assumeTrue(WolfSSL.MLDSAEnabled() && WolfSSL.TLSv13Enabled()); + + Assume.assumeTrue("JDK < 24, no JCE ML-DSA KeyFactory", jdkHasMlDsa); + + Assume.assumeTrue("Keystore missing; run examples/provider/" + + "update-keystore-pqc.sh first", + new File("examples/provider/" + storeFilename).isFile()); + + Assume.assumeTrue(WolfSSLPQCTestUtil.MLDSA_CERT_PARSING_SKIP_MSG, + WolfSSLPQCTestUtil.nativeMlDsaCertParsingSupported()); + } + + /** + * Do a TLS 1.3 ML-DSA-N handshake using the given store type and file + * extension. Both server keystore and client truststore use the same + * format, mirroring how an app typically picks one keystore convention. + * + * @param level ML-DSA parameter set: 44, 65, or 87 + * @param storeType JCE KeyStore type: "JKS" or "PKCS12" + * @param ext file extension matching storeType: "jks" or "p12" + */ + private void runHandshake(int level, String storeType, String ext) + throws Exception { + + String serverPath = + "examples/provider/server-mldsa" + level + "." + ext; + String caPath = "examples/provider/ca-mldsa" + level + "." + ext; + + /* Server keystore: private key + CA-signed cert chain. */ + KeyStore serverKs = KeyStore.getInstance(storeType); + FileInputStream in = new FileInputStream(serverPath); + try { + serverKs.load(in, STORE_PASS); + } finally { + in.close(); + } + KeyManagerFactory kmf = + KeyManagerFactory.getInstance("SunX509", PROVIDER); + kmf.init(serverKs, STORE_PASS); + + /* Client truststore: just the root CA cert (no private key). */ + KeyStore caKs = KeyStore.getInstance(storeType); + in = new FileInputStream(caPath); + try { + caKs.load(in, STORE_PASS); + } finally { + in.close(); + } + TrustManagerFactory tmf = + TrustManagerFactory.getInstance("SunX509", PROVIDER); + tmf.init(caKs); + + SSLContext serverCtx = tf.createSSLContext("TLSv1.3", PROVIDER, + null, kmf.getKeyManagers()); + SSLContext clientCtx = tf.createSSLContext("TLSv1.3", PROVIDER, + tmf.getTrustManagers(), null); + + SSLEngine server = serverCtx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + + SSLEngine client = clientCtx.createSSLEngine( + "wolfSSL " + storeType + " PQC test", 11111); + client.setUseClientMode(true); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + assertEquals("ML-DSA-" + level + " " + storeType + + " handshake should succeed", 0, ret); + } + + /* JKS coverage. */ + @Test + public void testJksServerAuth_MLDSA44() throws Exception { + preconditions("server-mldsa44.jks"); + runHandshake(44, "JKS", "jks"); + } + + @Test + public void testJksServerAuth_MLDSA65() throws Exception { + preconditions("server-mldsa65.jks"); + runHandshake(65, "JKS", "jks"); + } + + @Test + public void testJksServerAuth_MLDSA87() throws Exception { + preconditions("server-mldsa87.jks"); + runHandshake(87, "JKS", "jks"); + } + + /* PKCS12 coverage (JDK 24+ default keystore type). */ + @Test + public void testPkcs12ServerAuth_MLDSA44() throws Exception { + preconditions("server-mldsa44.p12"); + runHandshake(44, "PKCS12", "p12"); + } + + @Test + public void testPkcs12ServerAuth_MLDSA65() throws Exception { + preconditions("server-mldsa65.p12"); + runHandshake(65, "PKCS12", "p12"); + } + + @Test + public void testPkcs12ServerAuth_MLDSA87() throws Exception { + preconditions("server-mldsa87.p12"); + runHandshake(87, "PKCS12", "p12"); + } +} diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCAuthenticationTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCAuthenticationTest.java new file mode 100644 index 00000000..abd2298d --- /dev/null +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCAuthenticationTest.java @@ -0,0 +1,301 @@ +/* WolfSSLPQCAuthenticationTest.java + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +package com.wolfssl.provider.jsse.test; + +import java.util.List; +import java.util.Arrays; +import com.wolfssl.WolfSSL; +import com.wolfssl.WolfSSLException; +import com.wolfssl.provider.jsse.WolfSSLProvider; +import com.wolfssl.test.TimedTestWatcher; +import java.security.NoSuchProviderException; +import java.security.Security; +import javax.net.ssl.ExtendedSSLSession; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * Integration tests for ML-DSA (FIPS 204) X.509 cert authentication via + * wolfJSSE TLS 1.3. + * + * Uses {@link WolfSSLPQCTestUtil}'s custom KeyManager helper, which loads PEM + * certs and PKCS#8 DER keys directly without invoking JCE KeyFactory. This + * makes the same test runnable on Java 8 (no ML-DSA in JEP 497) through + * JDK 24+ alike. Cert verification is delegated to native wolfSSL via wolfJSSE. + * + * Skipped automatically when: + * - native wolfSSL was not built with --enable-mldsa, OR + * - TLS 1.3 is not compiled in, OR + * - the gen-mldsa-certs.sh script has not been run (no PQC PEM files + * under examples/certs/pqc/). + */ +public class WolfSSLPQCAuthenticationTest { + + private static final String PROVIDER = "wolfJSSE"; + private static final String APP_DATA = "PQC auth test"; + + /* ML-DSA-87 (CNSA 2.0) cert paths. + * Generated by examples/certs/gen-mldsa-certs.sh */ + private static final String SERVER_CERT = + "examples/certs/pqc/server-mldsa87.pem"; + private static final String SERVER_KEY = + "examples/certs/pqc/server-mldsa87-priv.pem"; + private static final String CLIENT_CERT = + "examples/certs/pqc/client-mldsa87.pem"; + private static final String CLIENT_KEY = + "examples/certs/pqc/client-mldsa87-priv.pem"; + private static final String ROOT_CERT = + "examples/certs/pqc/root-mldsa87.pem"; + + private static WolfSSLTestFactory tf; + + @Rule + public TestRule testWatcher = TimedTestWatcher.create(); + + @BeforeClass + public static void setUp() + throws NoSuchProviderException, WolfSSLException { + + System.out.println("WolfSSLPQCAuthentication Class"); + + Security.insertProviderAt(new WolfSSLProvider(), 1); + tf = new WolfSSLTestFactory(); + } + + /** + * Common skip preconditions for every test in this class. Routes + * through Assume so the TimedTestWatcher reports SKIP rather than + * the test failing. + */ + private void preconditions() { + Assume.assumeTrue(WolfSSL.MLDSAEnabled() && WolfSSL.TLSv13Enabled()); + + Assume.assumeTrue("PQC cert PEM missing; run gen-mldsa-certs.sh first", + WolfSSLPQCTestUtil.pqcCertExists(ROOT_CERT)); + + Assume.assumeTrue(WolfSSLPQCTestUtil.MLDSA_CERT_PARSING_SKIP_MSG, + WolfSSLPQCTestUtil.nativeMlDsaCertParsingSupported()); + } + + /** + * Server presents an ML-DSA-87 cert. Client trusts the matching root and + * verifies. No client auth. + */ + @Test + public void testServerAuth_MLDSA87() throws Exception { + + preconditions(); + + KeyManager[] serverKm = WolfSSLPQCTestUtil.keyManagerFromPem( + "server-mldsa87", SERVER_CERT, SERVER_KEY, "ML-DSA-87"); + TrustManager[] clientTm = + WolfSSLPQCTestUtil.trustManagerFromPem(ROOT_CERT); + + SSLContext serverCtx = tf.createSSLContext("TLSv1.3", PROVIDER, + null, serverKm); + SSLContext clientCtx = tf.createSSLContext("TLSv1.3", PROVIDER, + clientTm, null); + + SSLEngine server = serverCtx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + + SSLEngine client = clientCtx.createSSLEngine( + "wolfSSL ML-DSA test", 11111); + client.setUseClientMode(true); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + + assertEquals("ML-DSA-87 server-auth handshake should succeed", 0, ret); + } + + /** + * Mutual auth: both server and client present ML-DSA-87 certs, each side + * trusts the matching root. + */ + @Test + public void testMutualAuth_MLDSA87() throws Exception { + + preconditions(); + + KeyManager[] serverKm = WolfSSLPQCTestUtil.keyManagerFromPem( + "server-mldsa87", SERVER_CERT, SERVER_KEY, "ML-DSA-87"); + TrustManager[] serverTm = + WolfSSLPQCTestUtil.trustManagerFromPem(ROOT_CERT); + KeyManager[] clientKm = WolfSSLPQCTestUtil.keyManagerFromPem( + "client-mldsa87", CLIENT_CERT, CLIENT_KEY, "ML-DSA-87"); + TrustManager[] clientTm = + WolfSSLPQCTestUtil.trustManagerFromPem(ROOT_CERT); + + SSLContext serverCtx = tf.createSSLContext("TLSv1.3", PROVIDER, + serverTm, serverKm); + SSLContext clientCtx = tf.createSSLContext("TLSv1.3", PROVIDER, + clientTm, clientKm); + + SSLEngine server = serverCtx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(true); + + SSLEngine client = clientCtx.createSSLEngine( + "wolfSSL ML-DSA test", 11111); + client.setUseClientMode(true); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + + assertEquals("ML-DSA-87 mutual-auth handshake should succeed", 0, ret); + } + + /** + * Run server auth handshakes for ML-DSA-44 and ML-DSA-65 too, so we + * verify all three FIPS 204 parameter sets actually flow through wolfJSSE + * cert selection and native verification. + */ + @Test + public void testServerAuth_MLDSA44_and_65() throws Exception { + + preconditions(); + runServerAuthAtLevel(44); + runServerAuthAtLevel(65); + } + + private void runServerAuthAtLevel(int level) throws Exception { + + String serverCert = "examples/certs/pqc/server-mldsa" + level + + ".pem"; + String serverKey = "examples/certs/pqc/server-mldsa" + level + + "-priv.pem"; + String rootCert = "examples/certs/pqc/root-mldsa" + level + + ".pem"; + + if (!WolfSSLPQCTestUtil.pqcCertExists(serverCert)) { + return; + } + + KeyManager[] km = WolfSSLPQCTestUtil.keyManagerFromPem( + "server-mldsa" + level, serverCert, serverKey, "ML-DSA-" + level); + TrustManager[] tm = WolfSSLPQCTestUtil.trustManagerFromPem(rootCert); + + SSLContext serverCtx = tf.createSSLContext("TLSv1.3", PROVIDER, + null, km); + SSLContext clientCtx = tf.createSSLContext("TLSv1.3", PROVIDER, + tm, null); + + SSLEngine server = serverCtx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + SSLEngine client = clientCtx.createSSLEngine( + "wolfSSL ML-DSA test", 11111); + client.setUseClientMode(true); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, APP_DATA); + + if (ret != 0) { + fail("ML-DSA-" + level + + " server-auth handshake failed, ret=" + ret); + } + } + + /** + * SSLSession.getLocalSupportedSignatureAlgorithms() must advertise the + * three ML-DSA parameter set names registered by JEP 497 when native + * wolfSSL has ML-DSA enabled. + */ + @Test + public void testLocalSupportedSignatureAlgorithms_includesMLDSA() + throws Exception { + + Assume.assumeTrue("ML-DSA not enabled in native wolfSSL", + WolfSSL.MLDSAEnabled()); + Assume.assumeTrue("TLS 1.3 not enabled in native wolfSSL", + WolfSSL.TLSv13Enabled()); + + SSLContext ctx = tf.createSSLContext("TLSv1.3", PROVIDER); + SSLEngine engine = ctx.createSSLEngine(); + engine.setUseClientMode(true); + + SSLSession session = engine.getSession(); + Assume.assumeTrue("SSLSession is not an ExtendedSSLSession; " + + "cannot query getLocalSupportedSignatureAlgorithms", + session instanceof ExtendedSSLSession); + String[] sigAlgs = ((ExtendedSSLSession) session) + .getLocalSupportedSignatureAlgorithms(); + + List list = Arrays.asList(sigAlgs); + assertTrue("getLocalSupportedSignatureAlgorithms() must include " + + "ML-DSA-44 when native ML-DSA is enabled, got: " + list, + list.contains("ML-DSA-44")); + assertTrue("getLocalSupportedSignatureAlgorithms() must include " + + "ML-DSA-65 when native ML-DSA is enabled, got: " + list, + list.contains("ML-DSA-65")); + assertTrue("getLocalSupportedSignatureAlgorithms() must include " + + "ML-DSA-87 when native ML-DSA is enabled, got: " + list, + list.contains("ML-DSA-87")); + } + + /** + * WolfSSLUtil.formatSigSchemes() must not silently drop ML-DSA scheme + * names from jdk.tls.{client,server}.SignatureSchemes input. The + * standalone branch (no hash component, parallel to ED25519/ED448) + * recognizes the IETF MLDSA{44,65,87} scheme names and emits the + * canonical FIPS 204 form (ML-DSA-N) into the colon-list passed to + * native wolfSSL_set1_sigalgs_list(). + * + * Reflection-based invocation since formatSigSchemes is package-private. + */ + @Test + public void testFormatSigSchemes_acceptsMLDSAStandalones() + throws Exception { + + java.lang.reflect.Method m = com.wolfssl.provider.jsse.WolfSSLUtil + .class.getDeclaredMethod("formatSigSchemes", + String.class, String.class); + m.setAccessible(true); + + String result = (String) m.invoke(null, null, + "mldsa44,mldsa65,mldsa87"); + assertNotNull("formatSigSchemes must not return null when ML-DSA " + + "schemes are the only input", result); + + List tokens = Arrays.asList(result.split(":")); + assertTrue("Output must include ML-DSA-44 when input has mldsa44, " + + "got: " + result, tokens.contains("ML-DSA-44")); + assertTrue("Output must include ML-DSA-65 when input has mldsa65, " + + "got: " + result, tokens.contains("ML-DSA-65")); + assertTrue("Output must include ML-DSA-87 when input has mldsa87, " + + "got: " + result, tokens.contains("ML-DSA-87")); + } +} diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCKeyExchangeTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCKeyExchangeTest.java new file mode 100644 index 00000000..fbe18413 --- /dev/null +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCKeyExchangeTest.java @@ -0,0 +1,257 @@ +/* WolfSSLPQCKeyExchangeTest.java + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +package com.wolfssl.provider.jsse.test; + +import com.wolfssl.WolfSSL; +import com.wolfssl.WolfSSLContext; +import com.wolfssl.WolfSSLException; +import com.wolfssl.WolfSSLSession; +import com.wolfssl.provider.jsse.WolfSSLProvider; +import com.wolfssl.test.TimedTestWatcher; +import java.security.Security; +import java.security.NoSuchProviderException; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * Integration tests for ML-KEM (FIPS 203) named-group support in wolfJSSE. Each + * test sets the wolfjsse.enabledSupportedCurves Security property to a single + * PQC group and runs an end-to-end SSLEngine handshake against itself with + * classical ECC certs. With only one group in the list, a successful handshake + * proves the PQC group was negotiated. + * + * Skipped when native wolfSSL was not built with --enable-mlkem or when + * TLS 1.3 is not compiled in. + */ +public class WolfSSLPQCKeyExchangeTest { + + private static final String PROVIDER = "wolfJSSE"; + private static final String CURVES_PROP = + "wolfjsse.enabledSupportedCurves"; + private static final String APP_DATA = "PQC handshake test"; + + private static WolfSSLTestFactory tf; + + @Rule + public TestRule testWatcher = TimedTestWatcher.create(); + + @BeforeClass + public static void setUp() + throws NoSuchProviderException, WolfSSLException { + + System.out.println("WolfSSLPQCKeyExchange Class"); + + Security.insertProviderAt(new WolfSSLProvider(), 1); + tf = new WolfSSLTestFactory(); + } + + /** + * Run a single SSLEngine handshake using protocol+curve. Caller must hold + * WolfSSLTestFactory.jdkTlsDisabledAlgorithmsLock if mutating shared JDK + * Security properties; we hold a separate lock around the + * wolfjsse.enabledSupportedCurves mutation. + * + * @param protocol JSSE protocol string, e.g. "TLSv1.3" + * @param curve named-group string for the curves property, + * e.g. "ML-KEM-768" or null to leave property unset + * (use native default ordering) + * @return testConnection result: 0 success, -1 failure + */ + private int handshakeWithCurve(String protocol, String curve) + throws Exception { + + synchronized (curvesPropLock) { + String prev = Security.getProperty(CURVES_PROP); + try { + if (curve != null) { + Security.setProperty(CURVES_PROP, curve); + } + else { + Security.setProperty(CURVES_PROP, ""); + } + + SSLContext ctx = tf.createSSLContext(protocol, PROVIDER); + SSLEngine server = ctx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + SSLEngine client = ctx.createSSLEngine( + "wolfSSL PQC test", 11111); + client.setUseClientMode(true); + + return tf.testConnection(server, client, null, + new String[] { protocol }, APP_DATA); + + } finally { + if (prev == null) { + Security.setProperty(CURVES_PROP, ""); + } + else { + Security.setProperty(CURVES_PROP, prev); + } + } + } + } + + /* Process-global lock around wolfjsse.enabledSupportedCurves prop */ + private static final Object curvesPropLock = new Object(); + + /** + * Check whether the given named group codepoint is usable in the current + * native wolfSSL build, by creating a throwaway TLS 1.3 session and + * trying useKeyShare(). Returns true only when native key-share generation + * succeeds. + */ + private static boolean isNamedGroupAvailable(int group) { + + WolfSSLContext ctx = null; + WolfSSLSession ssl = null; + + try { + ctx = new WolfSSLContext(WolfSSL.TLSv1_3_ClientMethod()); + ssl = new WolfSSLSession(ctx); + + return ssl.useKeyShare(group) == WolfSSL.SSL_SUCCESS; + + } catch (Throwable t) { + return false; + + } finally { + try { + if (ssl != null) { + ssl.freeSSL(); + } + if (ctx != null) { + ctx.free(); + } + } catch (Throwable t) { + /* cleanup, just swallow */ + } + } + } + + @Test + public void testHandshake_X25519MLKEM768() throws Exception { + + Assume.assumeTrue(WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + /* If native wolfSSL is built without HAVE_CURVE25519, X25519MLKEM768 + * is not a valid named group. Check up front so handshake regressions + * below show up as failure rather than a silent skip. */ + Assume.assumeTrue("X25519MLKEM768 unavailable in native build " + + "(likely missing HAVE_CURVE25519)", + isNamedGroupAvailable(WolfSSL.WOLFSSL_X25519MLKEM768)); + + int ret = handshakeWithCurve("TLSv1.3", "X25519MLKEM768"); + assertEquals("TLS 1.3 handshake with X25519MLKEM768 should succeed", + 0, ret); + } + + @Test + public void testHandshake_SECP256R1MLKEM768() throws Exception { + + Assume.assumeTrue(WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + + /* Hybrid SECP256R1MLKEM768 only needs ECC + ML-KEM, both of which are + * present in any reasonable PQC-capable build, so this is the most + * portable PQC handshake. */ + int ret = handshakeWithCurve("TLSv1.3", "SECP256R1MLKEM768"); + assertEquals("TLS 1.3 handshake with SECP256R1MLKEM768 should succeed", + 0, ret); + } + + @Test + public void testHandshake_SECP384R1MLKEM1024() throws Exception { + + Assume.assumeTrue(WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + + int ret = handshakeWithCurve("TLSv1.3", "SECP384R1MLKEM1024"); + assertEquals("TLS 1.3 handshake with SECP384R1MLKEM1024 should succeed", + 0, ret); + } + + @Test + public void testHandshake_MLKEM768_standalone() throws Exception { + + Assume.assumeTrue(WolfSSL.MLKEMEnabled() && WolfSSL.TLSv13Enabled()); + /* Native wolfSSL builds with WOLFSSL_TLS_NO_MLKEM_STANDALONE + * (default unless --enable-tls-mlkem-standalone) reject standalone + * ML-KEM groups. Check up front so handshake regressions below + * show up as failure, not a silent skip. */ + Assume.assumeTrue("Standalone ML-KEM-768 unavailable in native " + + "build (likely missing --enable-tls-mlkem-standalone)", + isNamedGroupAvailable(WolfSSL.WOLFSSL_ML_KEM_768)); + + int ret = handshakeWithCurve("TLSv1.3", "ML-KEM-768"); + assertEquals("TLS 1.3 handshake with ML-KEM-768 should succeed", + 0, ret); + } + + /** + * Engine-filter integration test: the JSSE engine helper must silently + * filter PQC named groups out of the supported_groups extension when + * TLS 1.3 is not in the active protocols. This matches SunJSSE/BCJSSE + * behavior. The handshake should not throw. An unrelated handshake failure + * (no common group) is the expected downstream outcome since we restricted + * to PQC only and the negotiated TLS 1.2 cannot use PQC. + */ + @Test + public void testEngineFilter_TLS12_PQC_doesNotThrow() throws Exception { + + Assume.assumeTrue(WolfSSL.MLKEMEnabled() && WolfSSL.TLSv12Enabled()); + + /* TLS 1.2 only + PQC group. wolfJSSE engine helper should filter the + * PQC group out before calling useSupportedCurves on native wolfSSL. + * The handshake is expected to fail because the supported_groups list + * ends up empty (no common group), but it must NOT throw an + * exception. */ + int ret = handshakeWithCurve("TLSv1.2", "ML-KEM-768"); + /* Either outcome is acceptable: a clean handshake failure + * (-1, peer rejects empty supported_groups) or an unexpected success + * if native picked a default. Anything that throws out of + * testConnection itself would indicate the filter regressed. */ + assertTrue("TLS 1.2 + PQC should fall through to handshake step " + + "without throwing in the engine helper, got ret=" + ret, + ret == 0 || ret == -1); + } + + /** + * Mixed list with both PQC and classical groups under TLS 1.2: + * filter strips PQC, classical group remains, handshake should succeed. + */ + @Test + public void testEngineFilter_TLS12_MixedFallsBackToClassical() + throws Exception { + + Assume.assumeTrue(WolfSSL.MLKEMEnabled() && WolfSSL.TLSv12Enabled()); + + int ret = handshakeWithCurve("TLSv1.2", "X25519MLKEM768,secp256r1"); + assertEquals("TLS 1.2 with PQC filtered out should succeed via " + + "classical secp256r1, got ret=" + ret, + 0, ret); + } +} diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCTestUtil.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCTestUtil.java new file mode 100644 index 00000000..56c1e559 --- /dev/null +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLPQCTestUtil.java @@ -0,0 +1,364 @@ +/* WolfSSLPQCTestUtil.java + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +package com.wolfssl.provider.jsse.test; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectOutputStream; +import java.net.Socket; +import java.security.KeyStore; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; +import javax.net.ssl.KeyManager; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509KeyManager; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; + +import com.wolfssl.WolfSSL; + +/** + * Test helper for wolfJSSE PQC (ML-DSA) certificate scenarios. + * + * Avoids JCE KeyFactory entirely for ML-DSA private keys, which lets the same + * test run on Java 8 (where JEP 497 ML-DSA support is absent) as well as + * JDK 24+. Used by WolfSSLPQCAuthenticationTest and WolfSSLCNSA2Test. + * + * Approach: bypass standard JCE KeyStore for the private key half of the test + * fixtures. Cert-only trust stores work on Java 8 via standard KeyStore (X.509 + * parsing is OID-tolerant). Only the private key extraction would normally + * fail, so this util wraps PKCS#8 DER bytes in a custom PrivateKey that + * returns the bytes verbatim to wolfJSSE, which forwards them to native + * wolfSSL for actual ML-DSA processing. + * + * Once wolfcryptjni WolfSSLKeyStore (WKS) gains ML-DSA branches, WKS becomes + * the recommended cross-version path for users. It will handle ML-DSA opaquely + * without requiring JDK 24+ or custom KeyManagers. + */ +class WolfSSLPQCTestUtil { + + /** Default location of generated ML-DSA cert chains. */ + static final String PQC_CERT_DIR = "examples/certs/pqc"; + + private WolfSSLPQCTestUtil() { + } + + /** + * Build a one-entry X509KeyManager from a PEM cert file and a PEM PKCS#8 + * private key file. The certificate file may contain a single cert/chain. + * + * @param alias alias to surface from the KeyManager + * @param certPemPath path to the PEM cert (or chain) + * @param keyPemPath path to the PEM PKCS#8 private key + * @param algorithm advertised algorithm name, e.g. "ML-DSA-87" + * @return KeyManager array suitable for SSLContext.init() + */ + static KeyManager[] keyManagerFromPem(String alias, String certPemPath, + String keyPemPath, String algorithm) throws Exception { + + X509Certificate[] chain = loadCertChain(certPemPath); + byte[] pkcs8 = pemFileToDer(keyPemPath); + + PrivateKey key = new PemPrivateKey(pkcs8, algorithm); + + return new KeyManager[] { + new SinglePemKeyManager(alias, chain, key) + }; + } + + /** + * Build a TrustManager array containing only the supplied root cert as a + * trusted CA. Uses an in-memory JKS-format KeyStore, no private keys, + * so this works on Java 8 even when the trusted cert is signed with ML-DSA + * (cert-only entries don't trigger KeyFactory on load). + * + * @param rootCertPemPath path to the trusted root cert PEM + * @return TrustManager array suitable for SSLContext.init() + */ + static TrustManager[] trustManagerFromPem(String rootCertPemPath) + throws Exception { + + X509Certificate[] chain = loadCertChain(rootCertPemPath); + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, null); + for (int i = 0; i < chain.length; i++) { + ks.setCertificateEntry("trust-" + i, chain[i]); + } + + TrustManagerFactory tmf = + TrustManagerFactory.getInstance("SunX509", "wolfJSSE"); + tmf.init(ks); + + return tmf.getTrustManagers(); + } + + /* Resolve a path relative to the repo root, similar to what + * WolfSSLTestFactory.getPath() does, so tests work whether run from the + * repo root or from a build subdirectory. */ + static String resolveRepoPath(String relative) { + + if (new File(relative).exists()) { + return relative; + } + + File f = new File("..", relative); + if (f.exists()) { + return f.getPath(); + } + f = new File("../..", relative); + if (f.exists()) { + return f.getPath(); + } + + return relative; + } + + /* Returns true if the given PQC cert file exists at the resolved test-time + * path. Tests use this to skip cleanly when the cert generation step + * (gen-mldsa-certs.sh) has not been run. */ + static boolean pqcCertExists(String relative) { + String path = resolveRepoPath(relative); + return new File(path).isFile(); + } + + /* Cached probe result. null = not yet probed. */ + private static Boolean nativeMlDsaCertParsingSupported = null; + + /** + * Returns true if native wolfSSL can complete an ML-DSA TLS 1.3 cert-auth + * handshake via wolfJSSE. Drives test SKIP decisions for ML-DSA cert-auth + * tests so they pass cleanly on older native wolfSSL. + * + * wolfJSSE's ML-DSA cert-auth path needs native wolfSSL PR #10310, which + * added ML-DSA SPKI / PKCS#8 DER support to d2i_PUBKEY / d2i_PrivateKey. + * That PR landed after the 5.9.1 release tag, so 5.9.1 (and earlier) fail + * the cert-auth handshake while master and post-5.9.1 stable releases + * succeed. + * + * Buffer-level probes (e.g. ctx.usePrivateKeyBuffer alone) do not detect + * the gap because some failures only show up during the handshake verify + * pass. So this check does a real ML-DSA-44 SSLEngine handshake, which + * exercises the code paths the gated tests will exercise. + */ + static synchronized boolean nativeMlDsaCertParsingSupported() { + + if (nativeMlDsaCertParsingSupported != null) { + return nativeMlDsaCertParsingSupported.booleanValue(); + } + + if (!WolfSSL.MLDSAEnabled() || !WolfSSL.TLSv13Enabled()) { + nativeMlDsaCertParsingSupported = Boolean.FALSE; + return false; + } + + String serverCert = PQC_CERT_DIR + "/server-mldsa44.pem"; + String serverKey = PQC_CERT_DIR + "/server-mldsa44-priv.pem"; + String rootCert = PQC_CERT_DIR + "/root-mldsa44.pem"; + + if (!pqcCertExists(serverCert) || !pqcCertExists(serverKey) || + !pqcCertExists(rootCert)) { + /* Certs missing. Treat as unsupported so tests are skipped. */ + nativeMlDsaCertParsingSupported = Boolean.FALSE; + return false; + } + + try { + KeyManager[] km = keyManagerFromPem("server-mldsa44", + serverCert, serverKey, "ML-DSA-44"); + TrustManager[] tm = trustManagerFromPem(rootCert); + + WolfSSLTestFactory tf = new WolfSSLTestFactory(); + SSLContext serverCtx = tf.createSSLContext("TLSv1.3", "wolfJSSE", + null, km); + SSLContext clientCtx = tf.createSSLContext("TLSv1.3", "wolfJSSE", + tm, null); + + SSLEngine server = serverCtx.createSSLEngine(); + server.setUseClientMode(false); + server.setNeedClientAuth(false); + SSLEngine client = clientCtx.createSSLEngine( + "wolfSSL ML-DSA probe", 11111); + client.setUseClientMode(true); + + int ret = tf.testConnection(server, client, null, + new String[] { "TLSv1.3" }, "probe"); + nativeMlDsaCertParsingSupported = + (ret == 0) ? Boolean.TRUE : Boolean.FALSE; + + } catch (Throwable t) { + nativeMlDsaCertParsingSupported = Boolean.FALSE; + } + + return nativeMlDsaCertParsingSupported.booleanValue(); + } + + /** Skip message used by all tests that gate on the probe. Centralized + * so the wolfSSL version / PR reference stays consistent. */ + static final String MLDSA_CERT_PARSING_SKIP_MSG = + "Native wolfSSL lacks ML-DSA TLS 1.3 cert-auth support " + + "(requires post-5.9.1 release with wolfSSL PR #10310)"; + + private static X509Certificate[] loadCertChain(String pemPath) + throws Exception { + + FileInputStream in = new FileInputStream(resolveRepoPath(pemPath)); + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + java.util.Collection certs = + cf.generateCertificates(in); + + return certs.toArray(new X509Certificate[0]); + + } finally { + in.close(); + } + } + + /* Strip "-----BEGIN ...-----" / "-----END ...-----" markers and + * surrounding whitespace, base64-decode the inner body. */ + private static byte[] pemFileToDer(String pemPath) throws IOException { + + File f = new File(resolveRepoPath(pemPath)); + byte[] all = new byte[(int) f.length()]; + FileInputStream in = new FileInputStream(f); + try { + int off = 0; + int n; + while ((n = in.read(all, off, all.length - off)) > 0) { + off += n; + } + } finally { + in.close(); + } + + String pem = new String(all, "UTF-8"); + StringBuilder b64 = new StringBuilder(); + for (String line : pem.split("\n")) { + String t = line.trim(); + if (t.isEmpty() || t.startsWith("-----")) { + continue; + } + b64.append(t); + } + + return Base64.getDecoder().decode(b64.toString()); + } + + /** + * Custom PrivateKey that just stores PKCS#8 DER bytes and returns them + * verbatim. wolfJSSE forwards getEncoded() bytes to native wolfSSL via + * wolfSSL_use_PrivateKey_buffer, which handles all algorithm-specific + * parsing in C, so the JDK never needs its own ML-DSA KeyFactory. + */ + private static final class PemPrivateKey implements PrivateKey { + + private static final long serialVersionUID = 1L; + + private final transient byte[] encoded; + private final String algorithm; + + PemPrivateKey(byte[] pkcs8, String algorithm) { + this.encoded = pkcs8.clone(); + this.algorithm = algorithm; + } + + public String getAlgorithm() { + return algorithm; + } + + public String getFormat() { + return "PKCS#8"; + } + + public byte[] getEncoded() { + return encoded.clone(); + } + + /* PrivateKey extends Serializable. This test only key wrapper holds + * raw PKCS#8 private key material and must never end up on a + * serialization stream. */ + private void writeObject(ObjectOutputStream out) + throws IOException { + throw new NotSerializableException( + "PemPrivateKey is a test wrapper around raw private key " + + "material and must not be serialized"); + } + } + + /** + * Single-entry X509KeyManager. Returns the one alias for any keyType / + * issuer query. Callers create a new instance per test fixture, so there's + * no ambiguity to resolve. + */ + private static final class SinglePemKeyManager implements X509KeyManager { + + private final String alias; + private final X509Certificate[] chain; + private final PrivateKey key; + private final String[] aliases; + + SinglePemKeyManager(String alias, X509Certificate[] chain, + PrivateKey key) { + this.alias = alias; + this.chain = chain.clone(); + this.key = key; + this.aliases = new String[] { alias }; + } + + public String chooseClientAlias(String[] keyTypes, + Principal[] issuers, Socket socket) { + return alias; + } + + public String chooseServerAlias(String keyType, + Principal[] issuers, Socket socket) { + return alias; + } + + public X509Certificate[] getCertificateChain(String a) { + return alias.equals(a) ? chain.clone() : null; + } + + public String[] getClientAliases(String keyType, + Principal[] issuers) { + return aliases.clone(); + } + + public PrivateKey getPrivateKey(String a) { + return alias.equals(a) ? key : null; + } + + public String[] getServerAliases(String keyType, + Principal[] issuers) { + return aliases.clone(); + } + } +} diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java index 7d831abb..61987473 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java @@ -92,7 +92,7 @@ class WolfSSLTestFactory { protected final static String jksPassStr = "wolfSSL test"; protected final static char[] jksPass = jksPassStr.toCharArray(); protected String keyStoreType = "JKS"; - private boolean extraDebug = false; + private boolean extraDebug = Boolean.getBoolean("wolfjsse.test.extraDebug"); /** * Shared lock for synchronization around tests that modify or use the Java @@ -600,16 +600,28 @@ private boolean verifyReceivedData(ByteBuffer buf, String expected) { protected int testConnection(SSLEngine server, SSLEngine client, String[] cipherSuites, String[] protocols, String appData) { - /* Max loop protection against infinite loops */ + /* Max loop protection against infinite loops. Bumped from 50 to 200 to + * accommodate handshakes with large PQC signatures (eg ML-DSA-87 + * CertificateVerify is ~4.6 KB) that need more SSLEngine wrap/unwrap + * rounds to drain through the fragment-sized in-memory buffers. + * Classical handshakes still complete in ~20 iterations. */ int loops = 0; - int maxLoops = 50; + int maxLoops = 200; boolean handshakeComplete = false; - /* Allocate buffers large enough for protocol packets */ - ByteBuffer serToCli = ByteBuffer.allocateDirect( - server.getSession().getPacketBufferSize()); - ByteBuffer cliToSer = ByteBuffer.allocateDirect( + /* Allocate network buffers with headroom for handshakes whose server + * flight is split across multiple wrap() calls (each up to one TLS + * record). With ML-DSA-87 the server flight needs two wraps of ~17 KB + * each; if the peer only partially drains the first record before the + * next wrap fires, a buffer sized at exactly one packet would + * BUFFER_OVERFLOW on the second wrap. 4x packet size gives enough + * headroom for the largest PQC handshakes we test while still + * bounding allocation. */ + int netBufSize = 4 * Math.max( + server.getSession().getPacketBufferSize(), client.getSession().getPacketBufferSize()); + ByteBuffer serToCli = ByteBuffer.allocateDirect(netBufSize); + ByteBuffer cliToSer = ByteBuffer.allocateDirect(netBufSize); /* Application data buffers */ ByteBuffer toSendCli = ByteBuffer.wrap(appData.getBytes()); diff --git a/src/test/com/wolfssl/test/WolfSSLSessionTest.java b/src/test/com/wolfssl/test/WolfSSLSessionTest.java index 9fd45db8..bd788207 100644 --- a/src/test/com/wolfssl/test/WolfSSLSessionTest.java +++ b/src/test/com/wolfssl/test/WolfSSLSessionTest.java @@ -4312,5 +4312,131 @@ public void test_WolfSSLSession_readSlicedByteBuffer() throws Exception { } } } + + @Test + public void test_WolfSSLSession_useKeyShare_PQC() + throws WolfSSLJNIException, WolfSSLException { + + /* useKeyShare requires TLS 1.3. PQC named groups require native ML-KEM. + * Skip if either is missing in this build. */ + Assume.assumeTrue(WolfSSL.TLSv13Enabled() && WolfSSL.MLKEMEnabled()); + + WolfSSLContext tls13Ctx = null; + WolfSSLSession ssl = null; + + try { + tls13Ctx = new WolfSSLContext(WolfSSL.TLSv1_3_ClientMethod()); + ssl = new WolfSSLSession(tls13Ctx); + + /* Standalone ML-KEM-768. Builds without + * --enable-tls-mlkem-standalone reject the group at runtime with + * BAD_FUNC_ARG. Old builds without ML-KEM at all return + * NOT_COMPILED_IN. Either is a valid skip reason. */ + int ret = ssl.useKeyShare(WolfSSL.WOLFSSL_ML_KEM_768); + assertTrue("useKeyShare(WOLFSSL_ML_KEM_768) on TLS 1.3 should " + + "return SSL_SUCCESS, NOT_COMPILED_IN, or BAD_FUNC_ARG, got " + + ret, ret == WolfSSL.SSL_SUCCESS || + ret == WolfSSL.NOT_COMPILED_IN || ret == WolfSSL.BAD_FUNC_ARG); + + /* Hybrid SECP256R1MLKEM768 needs only standard ECC on the + * classical side. BAD_FUNC_ARG can still come back on builds where + * the hybrid is gated out (e.g. --disable-pqc-hybrids). */ + ret = ssl.useKeyShare(WolfSSL.WOLFSSL_SECP256R1MLKEM768); + assertTrue("useKeyShare(WOLFSSL_SECP256R1MLKEM768) on TLS 1.3 " + + "should return SSL_SUCCESS, NOT_COMPILED_IN, or BAD_FUNC_ARG, " + + "got " + ret, ret == WolfSSL.SSL_SUCCESS || + ret == WolfSSL.NOT_COMPILED_IN || ret == WolfSSL.BAD_FUNC_ARG); + + } finally { + if (ssl != null) { + ssl.freeSSL(); + } + if (tls13Ctx != null) { + tls13Ctx.free(); + } + } + } + + @Test + public void test_WolfSSLSession_useKeyShare_AfterFree_Throws() + throws WolfSSLJNIException, WolfSSLException { + + Assume.assumeTrue(WolfSSL.TLSv13Enabled()); + + WolfSSLContext tls13Ctx = + new WolfSSLContext(WolfSSL.TLSv1_3_ClientMethod()); + WolfSSLSession ssl = new WolfSSLSession(tls13Ctx); + ssl.freeSSL(); + + try { + ssl.useKeyShare(WolfSSL.WOLFSSL_ML_KEM_768); + tls13Ctx.free(); + fail("useKeyShare() after freeSSL() should throw " + + "IllegalStateException"); + } catch (IllegalStateException e) { + /* expected */ + } + + tls13Ctx.free(); + } + + /** + * useSupportedCurves(String[]) must report a non-success return when any + * per-curve native call fails, even when later entries in the list succeed. + * + * Verified by passing a mixed list [bogus, secp256r1]: the bogus entry's + * failure code must propagate as the function return value even though + * secp256r1 added cleanly. + */ + @Test + public void test_WolfSSLSession_useSupportedCurves_AggregateFailure() + throws WolfSSLJNIException, WolfSSLException { + + Assume.assumeTrue(WolfSSL.TLSv12Enabled() || + WolfSSL.TLSv13Enabled()); + + WolfSSLContext ctx = null; + WolfSSLSession ssl = null; + + try { + if (WolfSSL.TLSv13Enabled()) { + ctx = new WolfSSLContext(WolfSSL.TLSv1_3_ClientMethod()); + } + else { + ctx = new WolfSSLContext(WolfSSL.TLSv1_2_ClientMethod()); + } + ssl = new WolfSSLSession(ctx); + + /* Success baseline. All valid entries should return SSL_SUCCESS. */ + int ret = ssl.useSupportedCurves(new String[] { "secp256r1" }); + Assume.assumeTrue("native does not support secp256r1 in this " + + "build, cannot run aggregate-failure test", + ret == WolfSSL.SSL_SUCCESS); + + /* Mixed list: [bogus_curve_name_xyz, secp256r1]. + * Invalid name resolves to WOLFSSL_NAMED_GROUP_INVALID, which + * native rejects with BAD_FUNC_ARG. secp256r1 is valid. */ + int mixedRet = ssl.useSupportedCurves( + new String[] { "bogus_curve_name_xyz", "secp256r1" }); + assertTrue("Mixed list with one invalid entry must NOT report " + + "success (was: ret=" + mixedRet + ")", + mixedRet != WolfSSL.SSL_SUCCESS); + + /* Reverse order, should fail */ + int reverseRet = ssl.useSupportedCurves( + new String[] { "secp256r1", "bogus_curve_name_xyz" }); + assertTrue("Mixed list (reverse order) with one invalid entry " + + "must NOT report success (was: ret=" + reverseRet + ")", + reverseRet != WolfSSL.SSL_SUCCESS); + } + finally { + if (ssl != null) { + ssl.freeSSL(); + } + if (ctx != null) { + ctx.free(); + } + } + } } diff --git a/src/test/com/wolfssl/test/WolfSSLTest.java b/src/test/com/wolfssl/test/WolfSSLTest.java index 2b43d1d4..8d5f1320 100644 --- a/src/test/com/wolfssl/test/WolfSSLTest.java +++ b/src/test/com/wolfssl/test/WolfSSLTest.java @@ -372,4 +372,135 @@ public void test_SettingPropertyAfterLoadHasNoEffect() { System.clearProperty("wolfssl.skipLibraryLoad"); } } + + @Test + public void test_PQC_NamedGroup_Constants() { + + /* Values must match wolfssl/ssl.h enum exactly. Drift here would + * cause silent codepoint mismatch. */ + assertEquals(512, WolfSSL.WOLFSSL_ML_KEM_512); + assertEquals(513, WolfSSL.WOLFSSL_ML_KEM_768); + assertEquals(514, WolfSSL.WOLFSSL_ML_KEM_1024); + + assertEquals(4587, WolfSSL.WOLFSSL_SECP256R1MLKEM768); + assertEquals(4588, WolfSSL.WOLFSSL_X25519MLKEM768); + assertEquals(4589, WolfSSL.WOLFSSL_SECP384R1MLKEM1024); + + assertEquals(12107, WolfSSL.WOLFSSL_SECP256R1MLKEM512); + assertEquals(12108, WolfSSL.WOLFSSL_SECP384R1MLKEM768); + assertEquals(12109, WolfSSL.WOLFSSL_SECP521R1MLKEM1024); + assertEquals(12214, WolfSSL.WOLFSSL_X25519MLKEM512); + assertEquals(12215, WolfSSL.WOLFSSL_X448MLKEM768); + } + + @Test + public void test_getNamedGroupFromString_PQC() { + + /* ML-KEM standalone: both compact ("MLKEMN") and FIPS 203 standard + * name ("ML-KEM-N") spellings */ + assertEquals(WolfSSL.WOLFSSL_ML_KEM_512, + WolfSSL.getNamedGroupFromString("MLKEM512")); + assertEquals(WolfSSL.WOLFSSL_ML_KEM_512, + WolfSSL.getNamedGroupFromString("ML-KEM-512")); + assertEquals(WolfSSL.WOLFSSL_ML_KEM_768, + WolfSSL.getNamedGroupFromString("MLKEM768")); + assertEquals(WolfSSL.WOLFSSL_ML_KEM_768, + WolfSSL.getNamedGroupFromString("ML-KEM-768")); + assertEquals(WolfSSL.WOLFSSL_ML_KEM_1024, + WolfSSL.getNamedGroupFromString("MLKEM1024")); + assertEquals(WolfSSL.WOLFSSL_ML_KEM_1024, + WolfSSL.getNamedGroupFromString("ML-KEM-1024")); + + /* IETF hybrids: IANA mixed-case ("SecP256r1MLKEM768") and the all caps + * variants we accept */ + assertEquals(WolfSSL.WOLFSSL_X25519MLKEM768, + WolfSSL.getNamedGroupFromString("X25519MLKEM768")); + assertEquals(WolfSSL.WOLFSSL_SECP256R1MLKEM768, + WolfSSL.getNamedGroupFromString("SecP256r1MLKEM768")); + assertEquals(WolfSSL.WOLFSSL_SECP256R1MLKEM768, + WolfSSL.getNamedGroupFromString("SECP256R1MLKEM768")); + assertEquals(WolfSSL.WOLFSSL_SECP384R1MLKEM1024, + WolfSSL.getNamedGroupFromString("SecP384r1MLKEM1024")); + assertEquals(WolfSSL.WOLFSSL_SECP384R1MLKEM1024, + WolfSSL.getNamedGroupFromString("SECP384R1MLKEM1024")); + + /* OQS hybrids */ + assertEquals(WolfSSL.WOLFSSL_SECP256R1MLKEM512, + WolfSSL.getNamedGroupFromString("SECP256R1MLKEM512")); + assertEquals(WolfSSL.WOLFSSL_SECP384R1MLKEM768, + WolfSSL.getNamedGroupFromString("SECP384R1MLKEM768")); + assertEquals(WolfSSL.WOLFSSL_SECP521R1MLKEM1024, + WolfSSL.getNamedGroupFromString("SECP521R1MLKEM1024")); + assertEquals(WolfSSL.WOLFSSL_X25519MLKEM512, + WolfSSL.getNamedGroupFromString("X25519MLKEM512")); + assertEquals(WolfSSL.WOLFSSL_X448MLKEM768, + WolfSSL.getNamedGroupFromString("X448MLKEM768")); + + /* Unknown / typo / null-equivalent fall through to INVALID */ + assertEquals(WolfSSL.WOLFSSL_NAMED_GROUP_INVALID, + WolfSSL.getNamedGroupFromString("X25519MLKEM")); + assertEquals(WolfSSL.WOLFSSL_NAMED_GROUP_INVALID, + WolfSSL.getNamedGroupFromString("nonsense")); + assertEquals(WolfSSL.WOLFSSL_NAMED_GROUP_INVALID, + WolfSSL.getNamedGroupFromString("")); + + /* Existing classical curves still resolve correctly. */ + assertEquals(WolfSSL.WOLFSSL_ECC_X25519, + WolfSSL.getNamedGroupFromString("X25519")); + assertEquals(WolfSSL.WOLFSSL_ECC_SECP256R1, + WolfSSL.getNamedGroupFromString("secp256r1")); + } + + @Test + public void test_isPQCNamedGroup() { + + /* All PQC standalone + hybrids return true. */ + assertTrue(WolfSSL.isPQCNamedGroup(WolfSSL.WOLFSSL_ML_KEM_512)); + assertTrue(WolfSSL.isPQCNamedGroup(WolfSSL.WOLFSSL_ML_KEM_768)); + assertTrue(WolfSSL.isPQCNamedGroup(WolfSSL.WOLFSSL_ML_KEM_1024)); + assertTrue(WolfSSL.isPQCNamedGroup( + WolfSSL.WOLFSSL_X25519MLKEM768)); + assertTrue(WolfSSL.isPQCNamedGroup( + WolfSSL.WOLFSSL_SECP256R1MLKEM768)); + assertTrue(WolfSSL.isPQCNamedGroup( + WolfSSL.WOLFSSL_SECP384R1MLKEM1024)); + assertTrue(WolfSSL.isPQCNamedGroup( + WolfSSL.WOLFSSL_SECP256R1MLKEM512)); + assertTrue(WolfSSL.isPQCNamedGroup( + WolfSSL.WOLFSSL_SECP384R1MLKEM768)); + assertTrue(WolfSSL.isPQCNamedGroup( + WolfSSL.WOLFSSL_SECP521R1MLKEM1024)); + assertTrue(WolfSSL.isPQCNamedGroup( + WolfSSL.WOLFSSL_X25519MLKEM512)); + assertTrue(WolfSSL.isPQCNamedGroup(WolfSSL.WOLFSSL_X448MLKEM768)); + + /* Classical curves and FFDHE return false. */ + assertFalse(WolfSSL.isPQCNamedGroup(WolfSSL.WOLFSSL_ECC_X25519)); + assertFalse(WolfSSL.isPQCNamedGroup(WolfSSL.WOLFSSL_ECC_SECP256R1)); + assertFalse(WolfSSL.isPQCNamedGroup(WolfSSL.WOLFSSL_ECC_SECP384R1)); + assertFalse(WolfSSL.isPQCNamedGroup(WolfSSL.WOLFSSL_FFDHE_2048)); + + /* Sentinel and out-of-range integers return false. */ + assertFalse(WolfSSL.isPQCNamedGroup( + WolfSSL.WOLFSSL_NAMED_GROUP_INVALID)); + assertFalse(WolfSSL.isPQCNamedGroup(0)); + assertFalse(WolfSSL.isPQCNamedGroup(99999)); + assertFalse(WolfSSL.isPQCNamedGroup(-1)); + } + + @Test + public void test_PQC_FeatureDetect_NativeReturns() { + + /* Each native call should be reachable and return a boolean + * consistent with the build. The only invariant we can assert is + * that native calls returned without crashing. Reference variables + * to silence "unused" warnings on older toolchains. */ + boolean mlkem = WolfSSL.MLKEMEnabled(); + boolean mldsa = WolfSSL.MLDSAEnabled(); + boolean oldIds = WolfSSL.MLKEMOldIdsEnabled(); + + if (mlkem || mldsa || oldIds) { + /* nothing */ + } + } }