diff --git a/.github/workflows/async.yml b/.github/workflows/async.yml
index 8a572c328f5..74c073fe1c3 100644
--- a/.github/workflows/async.yml
+++ b/.github/workflows/async.yml
@@ -18,6 +18,10 @@ jobs:
matrix:
config: [
# Add new configs here
+ '--enable-asynccrypt --enable-all --enable-dtls13 --disable-mlkem CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT"',
+ '--enable-asynccrypt-sw --enable-ocspstapling --enable-ocspstapling2 --disable-mlkem CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
+ '--enable-asynccrypt --enable-all --enable-dtls13 --disable-pqc-hybrids --enable-tls-mlkem-standalone CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT"',
+ '--enable-asynccrypt-sw --enable-ocspstapling --enable-ocspstapling2 --disable-pqc-hybrids --enable-tls-mlkem-standalone CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
'--enable-asynccrypt --enable-all --enable-dtls13 CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFCRYPT_TEST_LINT"',
'--enable-asynccrypt-sw --enable-ocspstapling --enable-ocspstapling2 CFLAGS="-pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
'--enable-ocsp CFLAGS="-DTEST_NONBLOCK_CERTS -pedantic -Wdeclaration-after-statement -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
index 092c8f7d651..8570fb5cac6 100644
--- a/.github/workflows/cmake.yml
+++ b/.github/workflows/cmake.yml
@@ -73,6 +73,7 @@ jobs:
-DWOLFSSL_X963KDF:BOOL=yes -DWOLFSSL_DILITHIUM:BOOL=yes -DWOLFSSL_PKCS11:BOOL=yes \
-DWOLFSSL_ECCSI:BOOL=yes -DWOLFSSL_SAKKE:BOOL=yes -DWOLFSSL_SIPHASH:BOOL=yes \
-DWOLFSSL_WC_RSA_DIRECT:BOOL=yes -DWOLFSSL_PUBLIC_MP:BOOL=yes \
+ -DWOLFSSL_EXTRA_PQC_HYBRIDS:BOOL=yes -DWOLFSSL_TLS_NO_MLKEM_STANDALONE:BOOL=no \
..
cmake --build .
ctest -j $(nproc)
diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml
index 461c0b0df9c..a91657a9c62 100644
--- a/.github/workflows/os-check.yml
+++ b/.github/workflows/os-check.yml
@@ -38,6 +38,12 @@ jobs:
'--enable-experimental --enable-kyber --enable-dtls --enable-dtls13
--enable-dtls-frag-ch',
'--enable-all --enable-dtls13 --enable-dtls-frag-ch',
+ '--enable-all --enable-dtls13 --enable-dtls-frag-ch --disable-mlkem',
+ '--enable-all --enable-dtls13 --enable-dtls-frag-ch
+ --enable-tls-mlkem-standalone',
+ '--enable-all --enable-dtls13 --enable-dtls-frag-ch
+ --enable-tls-mlkem-standalone --enable-experimental
+ --enable-extra-pqc-hybrids',
'--enable-dtls --enable-dtls13 --enable-dtls-frag-ch
--enable-dtls-mtu',
'--enable-dtls --enable-dtlscid --enable-dtls13 --enable-secure-renegotiation
diff --git a/.github/workflows/pq-all.yml b/.github/workflows/pq-all.yml
index cabd5f367c4..b4ba3a22ec7 100644
--- a/.github/workflows/pq-all.yml
+++ b/.github/workflows/pq-all.yml
@@ -27,9 +27,13 @@ jobs:
'--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem --enable-lms --enable-xmss --enable-slhdsa --enable-dilithium --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_TLSX_PQC_MLKEM_STORE_OBJ"',
'--disable-intelasm --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem,small --enable-lms=yes,small --enable-xmss=yes,small --enable-slhdsa=yes,small --enable-dilithium=yes,small --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_MLKEM_MAKEKEY_SMALL_MEM -DWOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM -DWOLFSSL_MLKEM_NO_LARGE_CODE -DWOLFSSL_DILITHIUM_SIGN_SMALL_MEM -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"',
'--disable-intelasm --enable-smallstack --enable-smallstackcache --enable-all --enable-testcert --enable-acert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-quic --with-sys-crypto-policy --enable-experimental --enable-mlkem=yes,kyber,ml-kem,small --enable-lms=yes,small --enable-xmss=yes,small --enable-slhdsa=yes,small --enable-dilithium=yes,small --enable-dual-alg-certs --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE -DWOLFSSL_MLKEM_MAKEKEY_SMALL_MEM -DWOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM -DWOLFSSL_MLKEM_NO_LARGE_CODE -DWOLFSSL_DILITHIUM_SIGN_SMALL_MEM -DWOLFSSL_DILITHIUM_VERIFY_SMALL_MEM -DWOLFSSL_DILITHIUM_MAKE_KEY_SMALL_MEM -DWOLFSSL_DILITHIUM_NO_LARGE_CODE"',
- '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,512 --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
+ '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,512 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
'--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
+ '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
+ '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,768 --enable-tls-mlkem-standalone --disable-pqc-hybrids --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
'--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
+ '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --enable-tls-mlkem-standalone --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
+ '--enable-intelasm --enable-sp-asm --enable-all --enable-testcert --enable-dtls13 --enable-dtls-mtu --enable-dtls-frag-ch --enable-dtlscid --enable-mlkem=make,enc,dec,1024 --enable-tls-mlkem-standalone --disable-pqc-hybrids --disable-qt CPPFLAGS="-pedantic -Wdeclaration-after-statement -DWOLFCRYPT_TEST_LINT -DNO_WOLFSSL_CIPHER_SUITE_TEST -DTEST_LIBWOLFSSL_SOURCES_INCLUSION_SEQUENCE"',
]
name: make check
if: github.repository_owner == 'wolfssl'
diff --git a/.github/workflows/psk.yml b/.github/workflows/psk.yml
index 4b1373579af..f1cd0c64df3 100644
--- a/.github/workflows/psk.yml
+++ b/.github/workflows/psk.yml
@@ -18,10 +18,10 @@ jobs:
matrix:
config: [
# Add new configs here
- '--enable-psk C_EXTRA_FLAGS="-DWOLFSSL_STATIC_PSK -DWOLFSSL_OLDTLS_SHA2_CIPHERSUITES"',
- '--enable-psk C_EXTRA_FLAGS=-DWOLFSSL_STATIC_PSK --disable-rsa --disable-ecc --disable-dh',
- '--disable-oldtls --disable-tls13 --enable-psk -disable-rsa --disable-dh -disable-ecc --disable-asn C_EXTRA_FLAGS=-DWOLFSSL_STATIC_PSK --enable-lowresource --enable-singlethreaded --disable-asm --disable-errorstrings --disable-pkcs12 --disable-sha3 --disable-sha224 --disable-sha384 --disable-sha512 --disable-sha --disable-md5 -disable-aescbc --disable-chacha --disable-poly1305 --disable-coding --disable-sp-math-all',
- '--disable-oldtls --disable-tlsv12 --enable-tls13 --enable-psk -disable-rsa --disable-dh -disable-ecc --disable-asn C_EXTRA_FLAGS=-DWOLFSSL_STATIC_PSK --enable-lowresource --enable-singlethreaded --disable-asm --disable-errorstrings --disable-pkcs12 --disable-sha3 --disable-sha224 --disable-sha384 --disable-sha512 --disable-sha --disable-md5 -disable-aescbc --disable-chacha --disable-poly1305 --disable-coding --disable-sp-math-all'
+ '--enable-psk --disable-mlkem C_EXTRA_FLAGS="-DWOLFSSL_STATIC_PSK -DWOLFSSL_OLDTLS_SHA2_CIPHERSUITES"',
+ '--enable-psk --disable-mlkem C_EXTRA_FLAGS=-DWOLFSSL_STATIC_PSK --disable-rsa --disable-ecc --disable-dh',
+ '--disable-oldtls --disable-tls13 --enable-psk -disable-rsa --disable-dh -disable-ecc --disable-asn C_EXTRA_FLAGS=-DWOLFSSL_STATIC_PSK --enable-lowresource --enable-singlethreaded --disable-asm --disable-errorstrings --disable-pkcs12 --disable-sha3 --disable-sha224 --disable-sha384 --disable-sha512 --disable-sha --disable-md5 -disable-aescbc --disable-chacha --disable-poly1305 --disable-coding --disable-sp-math-all --disable-mlkem',
+ '--disable-oldtls --disable-tlsv12 --enable-tls13 --enable-psk -disable-rsa --disable-dh -disable-ecc --disable-asn C_EXTRA_FLAGS=-DWOLFSSL_STATIC_PSK --enable-lowresource --enable-singlethreaded --disable-asm --disable-errorstrings --disable-pkcs12 --disable-sha3 --disable-sha224 --disable-sha384 --disable-sha512 --disable-sha --disable-md5 -disable-aescbc --disable-chacha --disable-poly1305 --disable-coding --disable-sp-math-all --disable-mlkem'
]
name: make check
if: github.repository_owner == 'wolfssl'
diff --git a/.github/workflows/rust-wrapper.yml b/.github/workflows/rust-wrapper.yml
index 8a27b8fb131..667960d944b 100644
--- a/.github/workflows/rust-wrapper.yml
+++ b/.github/workflows/rust-wrapper.yml
@@ -41,36 +41,36 @@ jobs:
'--enable-all --enable-dilithium',
'--enable-all --enable-mlkem',
'--enable-cryptonly --disable-examples',
- '--enable-cryptonly --disable-examples --disable-aes --disable-aesgcm',
- '--enable-cryptonly --disable-examples --disable-aescbc',
- '--enable-cryptonly --disable-examples --disable-aeseax',
- '--enable-cryptonly --disable-examples --disable-aesecb',
- '--enable-cryptonly --disable-examples --disable-aesccm',
- '--enable-cryptonly --disable-examples --disable-aescfb',
- '--enable-cryptonly --disable-examples --disable-aesctr',
- '--enable-cryptonly --disable-examples --disable-aescts',
- '--enable-cryptonly --disable-examples --disable-aesgcm',
- '--enable-cryptonly --disable-examples --disable-aesgcm-stream',
- '--enable-cryptonly --disable-examples --disable-aesofb',
- '--enable-cryptonly --disable-examples --disable-aesxts',
- '--enable-cryptonly --disable-examples --disable-cmac',
- '--enable-cryptonly --disable-examples --disable-dh',
- '--enable-cryptonly --disable-examples --disable-ecc',
- '--enable-cryptonly --disable-examples --disable-ed25519',
- '--enable-cryptonly --disable-examples --disable-ed25519-stream',
- '--enable-cryptonly --disable-examples --disable-ed448',
- '--enable-cryptonly --disable-examples --disable-ed448-stream',
- '--enable-cryptonly --disable-examples --disable-hkdf',
- '--enable-cryptonly --disable-examples --disable-hmac',
- '--enable-cryptonly --disable-examples --disable-rng',
- '--enable-cryptonly --disable-examples --disable-rsa',
- '--enable-cryptonly --disable-examples --disable-rsapss',
- '--enable-cryptonly --disable-examples --disable-sha224',
- '--enable-cryptonly --disable-examples --disable-sha3',
- '--enable-cryptonly --disable-examples --disable-sha384',
- '--enable-cryptonly --disable-examples --disable-sha512',
- '--enable-cryptonly --disable-examples --disable-shake128',
- '--enable-cryptonly --disable-examples --disable-shake256',
- '--enable-cryptonly --disable-examples --disable-srtp-kdf',
- '--enable-cryptonly --disable-examples --disable-x963kdf',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aes --disable-aesgcm',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aescbc',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aeseax',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aesecb',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aesccm',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aescfb',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aesctr',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aescts',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aesgcm',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aesgcm-stream',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aesofb',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-aesxts',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-cmac',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-dh',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-ecc',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-ed25519',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-ed25519-stream',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-ed448',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-ed448-stream',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-hkdf',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-hmac',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-rng',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-rsa',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-rsapss',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-sha224',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-sha3',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-sha384',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-sha512',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-shake128',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-shake256',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-srtp-kdf',
+ '--enable-cryptonly --disable-examples --disable-mlkem --disable-x963kdf',
]
diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml
index df1b2e1cddb..922dce92c67 100644
--- a/.github/workflows/zephyr.yml
+++ b/.github/workflows/zephyr.yml
@@ -28,7 +28,7 @@ jobs:
if: github.repository_owner == 'wolfssl'
runs-on: ubuntu-22.04
# This should be a safe limit for the tests to run.
- timeout-minutes: 25
+ timeout-minutes: 45
steps:
- name: Install dependencies
run: |
diff --git a/.wolfssl_known_macro_extras b/.wolfssl_known_macro_extras
index e147b902c69..931d8da31ca 100644
--- a/.wolfssl_known_macro_extras
+++ b/.wolfssl_known_macro_extras
@@ -174,6 +174,7 @@ CONFIG_WOLFSSL_EXAMPLE_NAME_WOLFSSH_ECHOSERVER
CONFIG_WOLFSSL_EXAMPLE_NAME_WOLFSSH_TEMPLATE
CONFIG_WOLFSSL_HKDF
CONFIG_WOLFSSL_MAX_FRAGMENT_LEN
+CONFIG_WOLFSSL_MLKEM
CONFIG_WOLFSSL_NO_ASN_STRICT
CONFIG_WOLFSSL_PSK
CONFIG_WOLFSSL_RSA_PSS
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3f2f9923136..75275d857b5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -610,7 +610,7 @@ add_option(WOLFSSL_OQS
# ML-KEM/Kyber
add_option(WOLFSSL_MLKEM
"Enable the wolfSSL PQ ML-KEM library (default: disabled)"
- "no" "yes;no")
+ "yes" "yes;no")
if (WOLFSSL_MLKEM)
list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_HAVE_MLKEM")
@@ -626,6 +626,32 @@ if (WOLFSSL_MLKEM)
set_wolfssl_definitions("WOLFSSL_SHAKE256" RESULT)
endif()
+# When MLKEM and DTLS 1.3 are both enabled, DTLS ClientHello fragmenting is
+# required (PQC keys in ClientHello can exceed MTU), so enable it automatically.
+if(WOLFSSL_MLKEM AND WOLFSSL_DTLS13 AND NOT WOLFSSL_DTLS_CH_FRAG)
+ message(STATUS "MLKEM and DTLS 1.3 are enabled; enabling DTLS ClientHello fragmenting")
+ override_cache(WOLFSSL_DTLS_CH_FRAG "yes")
+ list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_DTLS_CH_FRAG")
+endif()
+
+# Disable ML-KEM as standalone TLS key exchange (non-hybrid); when enabled (default), standalone is disabled
+add_option(WOLFSSL_TLS_NO_MLKEM_STANDALONE
+ "Disable ML-KEM as standalone TLS key exchange (non-hybrid) (default: enabled, i.e. standalone disabled)"
+ "yes" "yes;no")
+
+if (WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_TLS_NO_MLKEM_STANDALONE")
+endif()
+
+# PQ/T hybrid combinations
+add_option(WOLFSSL_PQC_HYBRIDS
+ "Enable PQ/T hybrid combinations (default: enabled)"
+ "yes" "yes;no")
+
+if (WOLFSSL_PQC_HYBRIDS)
+ list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_PQC_HYBRIDS")
+endif()
+
# Dilithium
add_option(WOLFSSL_DILITHIUM
"Enable the wolfSSL PQ Dilithium (ML-DSA) implementation (default: disabled)"
@@ -675,6 +701,10 @@ add_option(WOLFSSL_EXPERIMENTAL
"Enable experimental features (default: disabled)"
"no" "yes;no")
+add_option(WOLFSSL_EXTRA_PQC_HYBRIDS
+ "Enable extra PQ/T hybrid combinations (default: disabled)"
+ "no" "yes;no")
+
message(STATUS "Looking for WOLFSSL_EXPERIMENTAL")
if (WOLFSSL_EXPERIMENTAL)
message(STATUS "Looking for WOLFSSL_EXPERIMENTAL - found")
@@ -710,6 +740,16 @@ if (WOLFSSL_EXPERIMENTAL)
message(STATUS "Looking for WOLFSSL_OQS - not found")
endif()
+ # Checking for experimental feature: extra PQ/T hybrid combinations
+ message(STATUS "Looking for WOLFSSL_EXTRA_PQC_HYBRIDS")
+ if (WOLFSSL_EXTRA_PQC_HYBRIDS)
+ set(WOLFSSL_FOUND_EXPERIMENTAL_FEATURE 1)
+ message(STATUS "Looking for WOLFSSL_EXTRA_PQC_HYBRIDS - found")
+ list(APPEND WOLFSSL_DEFINITIONS "-DWOLFSSL_EXTRA_PQC_HYBRIDS")
+ else()
+ message(STATUS "Looking for WOLFSSL_EXTRA_PQC_HYBRIDS - not found")
+ endif()
+
# Other experimental feature detection can be added here...
# Were any experimental features found? Display a message.
diff --git a/IDE/WIN10/wolfssl-fips.vcxproj b/IDE/WIN10/wolfssl-fips.vcxproj
index 42d574220fd..eac076eb3ae 100644
--- a/IDE/WIN10/wolfssl-fips.vcxproj
+++ b/IDE/WIN10/wolfssl-fips.vcxproj
@@ -292,6 +292,8 @@
+
+
diff --git a/cmake/options.h.in b/cmake/options.h.in
index 31df488e1e8..985b54241d6 100644
--- a/cmake/options.h.in
+++ b/cmake/options.h.in
@@ -380,6 +380,8 @@ extern "C" {
#cmakedefine WOLFSSL_HAVE_MLKEM
#undef WOLFSSL_WC_MLKEM
#cmakedefine WOLFSSL_WC_MLKEM
+#undef WOLFSSL_TLS_NO_MLKEM_STANDALONE
+#cmakedefine WOLFSSL_TLS_NO_MLKEM_STANDALONE
#undef WOLFSSL_WC_DILITHIUM
#cmakedefine WOLFSSL_WC_DILITHIUM
#undef NO_WOLFSSL_STUB
@@ -414,6 +416,10 @@ extern "C" {
#cmakedefine WOLFSSL_HAVE_SLHDSA
#undef WOLFSSL_WC_SLHDSA
#cmakedefine WOLFSSL_WC_SLHDSA
+#undef WOLFSSL_PQC_HYBRIDS
+#cmakedefine WOLFSSL_PQC_HYBRIDS
+#undef WOLFSSL_EXTRA_PQC_HYBRIDS
+#cmakedefine WOLFSSL_EXTRA_PQC_HYBRIDS
#ifdef __cplusplus
}
diff --git a/configure.ac b/configure.ac
index dc5ca6715d1..6e7ed2cc552 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1711,9 +1711,9 @@ AC_ARG_WITH([liboqs],
# Used:
# - SHA3, Shake128 and Shake256
AC_ARG_ENABLE([mlkem],
- [AS_HELP_STRING([--enable-mlkem],[Enable ML-KEM/Kyber (default: disabled)])],
+ [AS_HELP_STRING([--enable-mlkem],[Enable ML-KEM/Kyber (default: enabled)])],
[ ENABLED_MLKEM=$enableval ],
- [ ENABLED_MLKEM=no ]
+ [ ENABLED_MLKEM=yes ]
)
# note, inherits default from "mlkem" clause above.
AC_ARG_ENABLE([kyber],
@@ -1721,6 +1721,13 @@ AC_ARG_ENABLE([kyber],
[ ENABLED_MLKEM=$enableval ]
)
+# FIPS traditionally does not support SHAKE 128 and SHAKE 256 (v6 does), so disable
+# ML-KEM if FIPS is enabled and version is less than 6
+AS_IF([test "x$ENABLED_FIPS" = "xyes" && test $HAVE_FIPS_VERSION -lt 6],[
+ AC_MSG_NOTICE([Disabling MLKEM because FIPS < 6 does not support required SHAKE])
+ ENABLED_MLKEM="no"
+])
+
ENABLED_WC_MLKEM=no
ENABLED_ML_KEM=unset
ENABLED_MLKEM_MAKE_KEY=no
@@ -1847,8 +1854,61 @@ then
fi
fi
+AC_ARG_ENABLE([tls-mlkem-standalone],
+ [AS_HELP_STRING([--enable-tls-mlkem-standalone],[Enable ML-KEM as standalone TLS key exchange (non-hybrid) (default: disabled)])],
+ [ ENABLED_MLKEM_STANDALONE=$enableval ],
+ [ ENABLED_MLKEM_STANDALONE=no ]
+ )
+
+AS_IF([ test "$ENABLED_MLKEM_STANDALONE" = "yes" && test "$ENABLED_ML_KEM" = "no" ],[AC_MSG_ERROR([ML-KEM as standalone TLS key exchange (non-hybrid) requires ML-KEM.])])
+if test "$ENABLED_MLKEM_STANDALONE" != "yes"
+then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_TLS_NO_MLKEM_STANDALONE"
+fi
+
+AC_ARG_ENABLE([pqc-hybrids],
+ [AS_HELP_STRING([--enable-pqc-hybrids],[Enable PQ/T hybrid combinations (default: enabled)])],
+ [ ENABLED_PQC_HYBRIDS=$enableval ],
+ [ ENABLED_PQC_HYBRIDS=yes ]
+ )
+
+if test "$ENABLED_PQC_HYBRIDS" = "yes"
+then
+ if test "$ENABLED_ML_KEM" = "no" || test "$ENABLED_MLKEM" = "no"
+ then
+ ENABLED_PQC_HYBRIDS=no
+ elif test "$ENABLED_MLKEM768" = "" && test "$ENABLED_MLKEM1024" = ""; then
+ AC_MSG_NOTICE([PQC hybrid combinations require either ML-KEM 768 or ML-KEM 1024, but both disabled.])
+ ENABLED_PQC_HYBRIDS=no
+ else
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PQC_HYBRIDS"
+ fi
+fi
+
+if test "$ENABLED_ML_KEM" != "no" && test "$ENABLED_MLKEM" != "no"
+then
+ if test "$ENABLED_PQC_HYBRIDS" = "no" && test "$ENABLED_MLKEM_STANDALONE" = "no" && test "$ENABLED_CRYPTONLY" = "no"
+ then
+ AC_MSG_ERROR([Both hybrid PQ/T and standalone ML-KEM are disabled, so no PQC hybrid combinations will be available.])
+ fi
+fi
+
+# Extra PQ/T Hybrid combinations
+AC_ARG_ENABLE([extra-pqc-hybrids],
+ [AS_HELP_STRING([--enable-extra-pqc-hybrids],[Enable extra PQ/T hybrid combinations (default: disabled)])],
+ [ ENABLED_EXTRA_PQC_HYBRIDS=$enableval ],
+ [ ENABLED_EXTRA_PQC_HYBRIDS=no ]
+ )
+
+if test "$ENABLED_EXTRA_PQC_HYBRIDS" = "yes"
+then
+ AS_IF([ test "$ENABLED_EXPERIMENTAL" != "yes" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires --enable-experimental.]) ])
+ AS_IF([ test "$ENABLED_ML_KEM" = "no" ],[ AC_MSG_ERROR([extra-pqc-hybrids requires ML-KEM.]) ])
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_EXTRA_PQC_HYBRIDS"
+fi
+
# Dilithium
-# - SHA3, Shake128, Shake256 and AES-CTR
+# - SHA3, Shake128 and Shake256
AC_ARG_ENABLE([mldsa],
[AS_HELP_STRING([--enable-mldsa],[Enable ML-DSA/Dilithium (default: disabled)])],
[ ENABLED_DILITHIUM=$enableval ],
@@ -4628,6 +4688,17 @@ then
AM_CFLAGS="$AM_CFLAGS -DWC_SHA3_NO_ASM"
fi
+# MLKEM requires SHA-3. Force-enable SHA-3 when MLKEM is enabled.
+if test "$ENABLED_MLKEM" != "no"
+then
+ if test "$ENABLED_SHA3" = "no"
+ then
+ AC_MSG_NOTICE([MLKEM enabled (not explicitly disabled); overriding --disable-sha3 to enable SHA-3])
+ ENABLED_SHA3=yes
+ enable_sha3=yes
+ fi
+fi
+
# SHAKE128
AC_ARG_ENABLE([shake128],
[AS_HELP_STRING([--enable-shake128],[Enable wolfSSL SHAKE128 support (default: disabled)])],
@@ -4635,6 +4706,17 @@ AC_ARG_ENABLE([shake128],
[ ENABLED_SHAKE128=no ]
)
+# MLKEM requires SHAKE128. Force-enable when MLKEM is enabled.
+if test "$ENABLED_MLKEM" != "no"
+then
+ if test "$ENABLED_SHAKE128" = "no"
+ then
+ AC_MSG_WARN([MLKEM enabled (not explicitly disabled); overriding --disable-shake128 to enable SHAKE128])
+ ENABLED_SHAKE128=yes
+ enable_shake128=yes
+ fi
+fi
+
# SHAKE256
AC_ARG_ENABLE([shake256],
[AS_HELP_STRING([--enable-shake256],[Enable wolfSSL SHAKE256 support (default: disabled)])],
@@ -4642,6 +4724,17 @@ AC_ARG_ENABLE([shake256],
[ ENABLED_SHAKE256=no ]
)
+# MLKEM requires SHAKE256. Force-enable when MLKEM is enabled.
+if test "$ENABLED_MLKEM" != "no"
+then
+ if test "$ENABLED_SHAKE256" = "no"
+ then
+ AC_MSG_WARN([MLKEM enabled (not explicitly disabled); overriding --disable-shake256 to enable SHAKE256])
+ ENABLED_SHAKE256=yes
+ enable_shake256=yes
+ fi
+fi
+
# SHA512
AC_ARG_ENABLE([sha512],
[AS_HELP_STRING([--enable-sha512],[Enable wolfSSL SHA-512 support (default: enabled)])],
@@ -5828,6 +5921,15 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS_CH_FRAG"
fi
+# When MLKEM and DTLS 1.3 are both enabled, DTLS ClientHello fragmenting is
+# required (PQC keys in ClientHello can exceed MTU), so enable it automatically.
+if test "x$ENABLED_MLKEM" != "xno" && test "x$ENABLED_DTLS13" = "xyes" && test "x$ENABLED_DTLS_CH_FRAG" != "xyes"
+then
+ AC_MSG_NOTICE([MLKEM and DTLS 1.3 are enabled; enabling DTLS ClientHello fragmenting])
+ ENABLED_DTLS_CH_FRAG=yes
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS_CH_FRAG"
+fi
+
# CODING
AC_ARG_ENABLE([coding],
[AS_HELP_STRING([--enable-coding],[Enable Coding base 16/64 (default: enabled)])],
@@ -7964,6 +8066,11 @@ then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_SEND_HRR_COOKIE"
ENABLED_SEND_HRR_COOKIE="yes"
fi
+ if test "x$ENABLED_MLKEM" != "xno" && test "x$ENABLED_DTLS_CH_FRAG" != "xyes"
+ then
+ AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_DTLS_CH_FRAG"
+ ENABLED_DTLS_CH_FRAG="yes"
+ fi
if test "x$ENABLED_AES" = "xyes"
then
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_DIRECT"
@@ -12073,6 +12180,9 @@ echo " * ERR Queues per Thread: $ENABLED_ERRORQUEUEPERTHREAD"
echo " * rwlock: $ENABLED_RWLOCK"
echo " * keylog export: $ENABLED_KEYLOG_EXPORT"
echo " * AutoSAR : $ENABLED_AUTOSAR"
+echo " * ML-KEM standalone: $ENABLED_MLKEM_STANDALONE"
+echo " * PQ/T hybrids: $ENABLED_PQC_HYBRIDS"
+echo " * Extra PQ/T hybrids: $ENABLED_EXTRA_PQC_HYBRIDS"
echo ""
echo "---"
diff --git a/examples/benchmark/tls_bench.c b/examples/benchmark/tls_bench.c
index 25355943683..85645224fdb 100644
--- a/examples/benchmark/tls_bench.c
+++ b/examples/benchmark/tls_bench.c
@@ -296,17 +296,23 @@ static struct group_info groups[] = {
{ WOLFSSL_FFDHE_8192, "FFDHE_8192" },
#ifdef HAVE_PQC
#ifndef WOLFSSL_NO_ML_KEM
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
{ WOLFSSL_ML_KEM_512, "ML_KEM_512" },
{ WOLFSSL_ML_KEM_768, "ML_KEM_768" },
{ WOLFSSL_ML_KEM_1024, "ML_KEM_1024" },
+ #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */
+ #ifdef WOLFSSL_PQC_HYBRIDS
+ { WOLFSSL_SECP256R1MLKEM768, "SecP256r1MLKEM768" },
+ { WOLFSSL_SECP384R1MLKEM1024, "SecP384r1MLKEM1024" },
+ { WOLFSSL_X25519MLKEM768, "X25519MLKEM768" },
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
{ WOLFSSL_SECP256R1MLKEM512, "SecP256r1MLKEM512" },
{ WOLFSSL_SECP384R1MLKEM768, "SecP384r1MLKEM768" },
- { WOLFSSL_SECP256R1MLKEM768, "SecP256r1MLKEM768" },
{ WOLFSSL_SECP521R1MLKEM1024, "SecP521r1MLKEM1024" },
- { WOLFSSL_SECP384R1MLKEM1024, "SecP384r1MLKEM1024" },
{ WOLFSSL_X25519MLKEM512, "X25519MLKEM512" },
{ WOLFSSL_X448MLKEM768, "X448MLKEM768" },
- { WOLFSSL_X25519MLKEM768, "X25519MLKEM768" },
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
#endif
#ifdef WOLFSSL_MLKEM_KYBER
{ WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" },
diff --git a/examples/client/client.c b/examples/client/client.c
index c3f8d67d535..8e925f41173 100644
--- a/examples/client/client.c
+++ b/examples/client/client.c
@@ -426,61 +426,78 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519,
int group = 0;
#ifndef WOLFSSL_NO_ML_KEM
- #ifndef WOLFSSL_NO_ML_KEM_512
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
if (XSTRCMP(pqcAlg, "ML_KEM_512") == 0) {
group = WOLFSSL_ML_KEM_512;
}
else
#endif
- #ifndef WOLFSSL_NO_ML_KEM_768
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
if (XSTRCMP(pqcAlg, "ML_KEM_768") == 0) {
group = WOLFSSL_ML_KEM_768;
}
else
#endif
- #ifndef WOLFSSL_NO_ML_KEM_1024
+ #if !defined(WOLFSSL_NO_ML_KEM_1024) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
if (XSTRCMP(pqcAlg, "ML_KEM_1024") == 0) {
group = WOLFSSL_ML_KEM_1024;
}
else
#endif
- #ifndef WOLFSSL_NO_ML_KEM_512
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
if (XSTRCMP(pqcAlg, "SecP256r1MLKEM512") == 0) {
group = WOLFSSL_SECP256R1MLKEM512;
}
else
#endif
#ifndef WOLFSSL_NO_ML_KEM_768
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
if (XSTRCMP(pqcAlg, "SecP384r1MLKEM768") == 0) {
group = WOLFSSL_SECP384R1MLKEM768;
}
- else if (XSTRCMP(pqcAlg, "SecP256r1MLKEM768") == 0) {
+ else
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ #ifdef WOLFSSL_PQC_HYBRIDS
+ if (XSTRCMP(pqcAlg, "SecP256r1MLKEM768") == 0) {
group = WOLFSSL_SECP256R1MLKEM768;
}
else
+ #endif /* WOLFSSL_PQC_HYBRIDS */
#endif
#ifndef WOLFSSL_NO_ML_KEM_1024
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
if (XSTRCMP(pqcAlg, "SecP521r1MLKEM1024") == 0) {
group = WOLFSSL_SECP521R1MLKEM1024;
}
- else if (XSTRCMP(pqcAlg, "SecP384r1MLKEM1024") == 0) {
+ else
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ #ifdef WOLFSSL_PQC_HYBRIDS
+ if (XSTRCMP(pqcAlg, "SecP384r1MLKEM1024") == 0) {
group = WOLFSSL_SECP384R1MLKEM1024;
}
else
+ #endif /* WOLFSSL_PQC_HYBRIDS */
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519)
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
if (XSTRCMP(pqcAlg, "X25519MLKEM512") == 0) {
group = WOLFSSL_X25519MLKEM512;
}
else
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519)
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) && \
+ defined(WOLFSSL_PQC_HYBRIDS)
if (XSTRCMP(pqcAlg, "X25519MLKEM768") == 0) {
group = WOLFSSL_X25519MLKEM768;
}
else
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448)
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
if (XSTRCMP(pqcAlg, "X448MLKEM768") == 0) {
group = WOLFSSL_X448MLKEM768;
}
@@ -551,12 +568,17 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519,
}
printf("Using Post-Quantum KEM: %s\n", pqcAlg);
- if (wolfSSL_UseKeyShare(ssl, group) == WOLFSSL_SUCCESS) {
- groups[count++] = group;
- }
- else {
- err_sys("unable to use post-quantum KEM");
- }
+ do {
+ ret = wolfSSL_UseKeyShare(ssl, group);
+ if (ret == WOLFSSL_SUCCESS)
+ groups[count++] = group;
+ #ifdef WOLFSSL_ASYNC_CRYPT
+ else if (ret == WC_NO_ERR_TRACE(WC_PENDING_E))
+ wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
+ #endif
+ else
+ err_sys("unable to use post-quantum KEM");
+ } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
#ifdef WOLFSSL_DTLS13
if (wolfSSL_dtls(ssl)) {
diff --git a/examples/server/server.c b/examples/server/server.c
index e642b695092..e52d611fbb6 100644
--- a/examples/server/server.c
+++ b/examples/server/server.c
@@ -717,61 +717,78 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519,
#ifdef HAVE_PQC
groups[count] = 0;
#ifndef WOLFSSL_NO_ML_KEM
- #ifndef WOLFSSL_NO_ML_KEM_512
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
if (XSTRCMP(pqcAlg, "ML_KEM_512") == 0) {
groups[count] = WOLFSSL_ML_KEM_512;
}
else
#endif
- #ifndef WOLFSSL_NO_ML_KEM_768
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
if (XSTRCMP(pqcAlg, "ML_KEM_768") == 0) {
groups[count] = WOLFSSL_ML_KEM_768;
}
else
#endif
- #ifndef WOLFSSL_NO_ML_KEM_1024
+ #if !defined(WOLFSSL_NO_ML_KEM_1024) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
if (XSTRCMP(pqcAlg, "ML_KEM_1024") == 0) {
groups[count] = WOLFSSL_ML_KEM_1024;
}
else
#endif
- #ifndef WOLFSSL_NO_ML_KEM_512
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
if (XSTRCMP(pqcAlg, "SecP256r1MLKEM512") == 0) {
groups[count] = WOLFSSL_SECP256R1MLKEM512;
}
else
#endif
#ifndef WOLFSSL_NO_ML_KEM_768
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
if (XSTRCMP(pqcAlg, "SecP384r1MLKEM768") == 0) {
groups[count] = WOLFSSL_SECP384R1MLKEM768;
}
- else if (XSTRCMP(pqcAlg, "SecP256r1MLKEM768") == 0) {
+ else
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ #ifdef WOLFSSL_PQC_HYBRIDS
+ if (XSTRCMP(pqcAlg, "SecP256r1MLKEM768") == 0) {
groups[count] = WOLFSSL_SECP256R1MLKEM768;
}
else
+ #endif /* WOLFSSL_PQC_HYBRIDS */
#endif
#ifndef WOLFSSL_NO_ML_KEM_1024
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
if (XSTRCMP(pqcAlg, "SecP521r1MLKEM1024") == 0) {
groups[count] = WOLFSSL_SECP521R1MLKEM1024;
}
- else if (XSTRCMP(pqcAlg, "SecP384r1MLKEM1024") == 0) {
+ else
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ #ifdef WOLFSSL_PQC_HYBRIDS
+ if (XSTRCMP(pqcAlg, "SecP384r1MLKEM1024") == 0) {
groups[count] = WOLFSSL_SECP384R1MLKEM1024;
}
else
+ #endif /* WOLFSSL_PQC_HYBRIDS */
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519)
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
if (XSTRCMP(pqcAlg, "X25519MLKEM512") == 0) {
groups[count] = WOLFSSL_X25519MLKEM512;
}
else
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519)
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) && \
+ defined(WOLFSSL_PQC_HYBRIDS)
if (XSTRCMP(pqcAlg, "X25519MLKEM768") == 0) {
groups[count] = WOLFSSL_X25519MLKEM768;
}
else
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448)
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
if (XSTRCMP(pqcAlg, "X448MLKEM768") == 0) {
groups[count] = WOLFSSL_X448MLKEM768;
}
@@ -845,14 +862,21 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519,
err_sys("invalid post-quantum KEM specified");
}
else {
- if (wolfSSL_UseKeyShare(ssl, groups[count]) == WOLFSSL_SUCCESS) {
- printf("Using Post-Quantum KEM: %s\n", pqcAlg);
- count++;
- }
- else {
- groups[count] = 0;
- err_sys("unable to use post-quantum algorithm");
- }
+ do {
+ ret = wolfSSL_UseKeyShare(ssl, groups[count]);
+ if (ret == WOLFSSL_SUCCESS) {
+ printf("Using Post-Quantum KEM: %s\n", pqcAlg);
+ count++;
+ }
+ #ifdef WOLFSSL_ASYNC_CRYPT
+ else if (ret == WC_NO_ERR_TRACE(WC_PENDING_E))
+ wolfSSL_AsyncPoll(ssl, WOLF_POLL_FLAG_CHECK_HW);
+ #endif
+ else {
+ groups[count] = 0;
+ err_sys("unable to use post-quantum algorithm");
+ }
+ } while (ret == WC_NO_ERR_TRACE(WC_PENDING_E));
}
#endif
}
diff --git a/src/internal.c b/src/internal.c
index 0ffe6c51f06..0b201c5b5de 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -35172,21 +35172,28 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
/* Returns 1 when the given group is a PQC hybrid group, 0 otherwise. */
int NamedGroupIsPqcHybrid(int group)
{
+ #if defined(WOLFSSL_PQC_HYBRIDS) || defined(WOLFSSL_EXTRA_PQC_HYBRIDS) || \
+ defined(WOLFSSL_MLKEM_KYBER)
+
switch (group) {
#ifndef WOLFSSL_NO_ML_KEM
+ #ifdef WOLFSSL_PQC_HYBRIDS
case WOLFSSL_SECP256R1MLKEM768:
case WOLFSSL_X25519MLKEM768:
case WOLFSSL_SECP384R1MLKEM1024:
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
case WOLFSSL_SECP256R1MLKEM512:
case WOLFSSL_SECP384R1MLKEM768:
case WOLFSSL_SECP521R1MLKEM1024:
case WOLFSSL_X25519MLKEM512:
case WOLFSSL_X448MLKEM768:
-#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
+ #ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
case WOLFSSL_P256_ML_KEM_512_OLD:
case WOLFSSL_P384_ML_KEM_768_OLD:
case WOLFSSL_P521_ML_KEM_1024_OLD:
-#endif
+ #endif
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
#endif
#ifdef WOLFSSL_MLKEM_KYBER
case WOLFSSL_P256_KYBER_LEVEL3:
@@ -35201,6 +35208,10 @@ static int DoSessionTicket(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
default:
return 0;
}
+ #else
+ (void)group;
+ return 0;
+ #endif
}
#endif /* WOLFSSL_HAVE_MLKEM */
diff --git a/src/ssl.c b/src/ssl.c
index 9772b85e4ef..b21558da1c8 100644
--- a/src/ssl.c
+++ b/src/ssl.c
@@ -2967,18 +2967,24 @@ static int isValidCurveGroup(word16 name)
#ifdef WOLFSSL_HAVE_MLKEM
#ifndef WOLFSSL_NO_ML_KEM
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
case WOLFSSL_ML_KEM_512:
case WOLFSSL_ML_KEM_768:
case WOLFSSL_ML_KEM_1024:
+ #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */
#if defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS)
+ #ifdef WOLFSSL_PQC_HYBRIDS
+ case WOLFSSL_SECP384R1MLKEM1024:
+ case WOLFSSL_X25519MLKEM768:
+ case WOLFSSL_SECP256R1MLKEM768:
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
case WOLFSSL_SECP256R1MLKEM512:
case WOLFSSL_SECP384R1MLKEM768:
case WOLFSSL_SECP521R1MLKEM1024:
- case WOLFSSL_SECP384R1MLKEM1024:
case WOLFSSL_X25519MLKEM512:
case WOLFSSL_X448MLKEM768:
- case WOLFSSL_X25519MLKEM768:
- case WOLFSSL_SECP256R1MLKEM768:
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
#endif
#endif /* !WOLFSSL_NO_ML_KEM */
#ifdef WOLFSSL_MLKEM_KYBER
@@ -10610,49 +10616,59 @@ const char* wolfSSL_get_curve_name(WOLFSSL* ssl)
#ifndef WOLFSSL_NO_ML_KEM_512
case WOLFSSL_ML_KEM_512:
return "ML_KEM_512";
- case WOLFSSL_SECP256R1MLKEM512:
- return "SecP256r1MLKEM512";
-#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ #ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
case WOLFSSL_P256_ML_KEM_512_OLD:
return "P256_ML_KEM_512_OLD";
-#endif
+ #endif /* WOLFSSL_ML_KEM_USE_OLD_IDS */
+ case WOLFSSL_SECP256R1MLKEM512:
+ return "SecP256r1MLKEM512";
#ifdef HAVE_CURVE25519
case WOLFSSL_X25519MLKEM512:
return "X25519MLKEM512";
- #endif
- #endif
+ #endif /* HAVE_CURVE25519 */
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ #endif /* WOLFSSL_NO_ML_KEM_512 */
#ifndef WOLFSSL_NO_ML_KEM_768
case WOLFSSL_ML_KEM_768:
return "ML_KEM_768";
- case WOLFSSL_SECP384R1MLKEM768:
- return "SecP384r1MLKEM768";
-#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
- case WOLFSSL_P384_ML_KEM_768_OLD:
- return "P384_ML_KEM_768_OLD";
-#endif
+ #ifdef WOLFSSL_PQC_HYBRIDS
case WOLFSSL_SECP256R1MLKEM768:
return "SecP256r1MLKEM768";
#ifdef HAVE_CURVE25519
case WOLFSSL_X25519MLKEM768:
return "X25519MLKEM768";
#endif
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ #ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
+ case WOLFSSL_P384_ML_KEM_768_OLD:
+ return "P384_ML_KEM_768_OLD";
+ #endif /* WOLFSSL_ML_KEM_USE_OLD_IDS */
+ case WOLFSSL_SECP384R1MLKEM768:
+ return "SecP384r1MLKEM768";
#ifdef HAVE_CURVE448
case WOLFSSL_X448MLKEM768:
return "X448MLKEM768";
- #endif
- #endif
+ #endif /* HAVE_CURVE448 */
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ #endif /* WOLFSSL_NO_ML_KEM_768 */
#ifndef WOLFSSL_NO_ML_KEM_1024
case WOLFSSL_ML_KEM_1024:
return "ML_KEM_1024";
- case WOLFSSL_SECP521R1MLKEM1024:
- return "SecP521r1MLKEM1024";
-#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
- case WOLFSSL_P521_ML_KEM_1024_OLD:
- return "P521_ML_KEM_1024_OLD";
-#endif
+ #ifdef WOLFSSL_PQC_HYBRIDS
case WOLFSSL_SECP384R1MLKEM1024:
return "SecP384r1MLKEM1024";
- #endif
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ #ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
+ case WOLFSSL_P521_ML_KEM_1024_OLD:
+ return "P521_ML_KEM_1024_OLD";
+ #endif /* WOLFSSL_ML_KEM_USE_OLD_IDS */
+ case WOLFSSL_SECP521R1MLKEM1024:
+ return "SecP521r1MLKEM1024";
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ #endif /* WOLFSSL_NO_ML_KEM_1024 */
#elif defined(HAVE_LIBOQS)
case WOLFSSL_ML_KEM_512:
return "ML_KEM_512";
@@ -16847,22 +16863,26 @@ const WOLF_EC_NIST_NAME kNistCurves[] = {
{CURVE_NAME("ML_KEM_768"), WOLFSSL_ML_KEM_768, WOLFSSL_ML_KEM_768},
{CURVE_NAME("ML_KEM_1024"), WOLFSSL_ML_KEM_1024, WOLFSSL_ML_KEM_1024},
#if (defined(WOLFSSL_WC_MLKEM) || defined(HAVE_LIBOQS)) && defined(HAVE_ECC)
+ #ifdef WOLFSSL_PQC_HYBRIDS
+ {CURVE_NAME("SecP256r1MLKEM768"), WOLFSSL_SECP256R1MLKEM768,
+ WOLFSSL_SECP256R1MLKEM768},
+ {CURVE_NAME("SecP384r1MLKEM1024"), WOLFSSL_SECP384R1MLKEM1024,
+ WOLFSSL_SECP384R1MLKEM1024},
+ {CURVE_NAME("X25519MLKEM768"), WOLFSSL_X25519MLKEM768,
+ WOLFSSL_X25519MLKEM768},
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
{CURVE_NAME("SecP256r1MLKEM512"), WOLFSSL_SECP256R1MLKEM512,
WOLFSSL_SECP256R1MLKEM512},
{CURVE_NAME("SecP384r1MLKEM768"), WOLFSSL_SECP384R1MLKEM768,
WOLFSSL_SECP384R1MLKEM768},
- {CURVE_NAME("SecP256r1MLKEM768"), WOLFSSL_SECP256R1MLKEM768,
- WOLFSSL_SECP256R1MLKEM768},
{CURVE_NAME("SecP521r1MLKEM1024"), WOLFSSL_SECP521R1MLKEM1024,
WOLFSSL_SECP521R1MLKEM1024},
- {CURVE_NAME("SecP384r1MLKEM1024"), WOLFSSL_SECP384R1MLKEM1024,
- WOLFSSL_SECP384R1MLKEM1024},
{CURVE_NAME("X25519MLKEM512"), WOLFSSL_X25519MLKEM512,
WOLFSSL_X25519MLKEM512},
{CURVE_NAME("X448MLKEM768"), WOLFSSL_X448MLKEM768,
WOLFSSL_X448MLKEM768},
- {CURVE_NAME("X25519MLKEM768"), WOLFSSL_X25519MLKEM768,
- WOLFSSL_X25519MLKEM768},
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
#endif
#endif /* !WOLFSSL_NO_ML_KEM */
#ifdef WOLFSSL_MLKEM_KYBER
diff --git a/src/tls.c b/src/tls.c
index a4dc98e592b..26ebcf713e4 100644
--- a/src/tls.c
+++ b/src/tls.c
@@ -4465,7 +4465,7 @@ static void findEccPqc(int *ecc, int *pqc, int *pqc_first, int group);
* namedGroup The named group to check.
* returns 1 when supported or 0 otherwise.
*/
-static int TLSX_IsGroupSupported(int namedGroup)
+int TLSX_IsGroupSupported(int namedGroup)
{
switch (namedGroup) {
#ifdef HAVE_FFDHE_2048
@@ -4577,37 +4577,55 @@ static int TLSX_IsGroupSupported(int namedGroup)
#ifndef WOLFSSL_NO_ML_KEM
#ifdef WOLFSSL_WC_MLKEM
#ifndef WOLFSSL_NO_ML_KEM_512
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
case WOLFSSL_ML_KEM_512:
+ break;
+ #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
case WOLFSSL_SECP256R1MLKEM512:
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
+ #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
case WOLFSSL_X25519MLKEM512:
- #endif
- break;
- #endif
+ #endif /* HAVE_CURVE25519 */
+ break;
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ #endif /* WOLFSSL_NO_ML_KEM_512 */
#ifndef WOLFSSL_NO_ML_KEM_768
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
case WOLFSSL_ML_KEM_768:
- case WOLFSSL_SECP384R1MLKEM768:
+ #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */
+ #ifdef WOLFSSL_PQC_HYBRIDS
case WOLFSSL_SECP256R1MLKEM768:
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
+ #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
case WOLFSSL_X25519MLKEM768:
- #endif
- #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
+ #endif /* HAVE_CURVE25519 */
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ case WOLFSSL_SECP384R1MLKEM768:
+ #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
case WOLFSSL_X448MLKEM768:
- #endif
- break;
- #endif
+ #endif /* HAVE_CURVE448 */
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+ break;
+ #endif /* WOLFSSL_NO_ML_KEM_768 */
#ifndef WOLFSSL_NO_ML_KEM_1024
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
case WOLFSSL_ML_KEM_1024:
- case WOLFSSL_SECP521R1MLKEM1024:
+ #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */
+ #ifdef WOLFSSL_PQC_HYBRIDS
case WOLFSSL_SECP384R1MLKEM1024:
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ case WOLFSSL_SECP521R1MLKEM1024:
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
break;
#endif
-#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
+ #if defined(WOLFSSL_ML_KEM_USE_OLD_IDS) && \
+ defined (WOLFSSL_EXTRA_PQC_HYBRIDS)
case WOLFSSL_P256_ML_KEM_512_OLD:
case WOLFSSL_P384_ML_KEM_768_OLD:
case WOLFSSL_P521_ML_KEM_1024_OLD:
break;
-#endif
+ #endif /* WOLFSSL_ML_KEM_USE_OLD_IDS && WOLFSSL_EXTRA_PQC_HYBRIDS */
#elif defined(HAVE_LIBOQS)
case WOLFSSL_ML_KEM_512:
case WOLFSSL_ML_KEM_768:
@@ -5914,7 +5932,8 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap)
heap);
if (ret != 0)
return ret;
-#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
+ #if defined(WOLFSSL_ML_KEM_USE_OLD_IDS) && \
+ defined (WOLFSSL_EXTRA_PQC_HYBRIDS)
if (name == WOLFSSL_SECP256R1MLKEM512) {
ret = TLSX_SupportedCurve_Append((SupportedCurve*)extension->data,
WOLFSSL_P256_ML_KEM_512_OLD, heap);
@@ -5930,7 +5949,7 @@ int TLSX_UseSupportedCurve(TLSX** extensions, word16 name, void* heap)
if (ret != 0) {
return ret;
}
-#endif
+ #endif /* WOLFSSL_ML_KEM_USE_OLD_IDS && WOLFSSL_EXTRA_PQC_HYBRIDS */
}
return WOLFSSL_SUCCESS;
@@ -8292,26 +8311,22 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
word16 curveId = (word16) ECC_CURVE_INVALID;
ecc_key* eccKey = (ecc_key*)kse->key;
- /* TODO: [TLS13] Get key sizes using wc_ecc_get_curve_size_from_id. */
/* Translate named group to a curve id. */
switch (kse->group) {
#if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
#ifndef NO_ECC_SECP
case WOLFSSL_ECC_SECP256R1:
curveId = ECC_SECP256R1;
- keySize = 32;
break;
#endif /* !NO_ECC_SECP */
#ifdef WOLFSSL_SM2
case WOLFSSL_ECC_SM2P256V1:
curveId = ECC_SM2P256V1;
- keySize = 32;
break;
#endif /* !WOLFSSL_SM2 */
#ifdef HAVE_ECC_BRAINPOOL
case WOLFSSL_ECC_BRAINPOOLP256R1TLS13:
curveId = ECC_BRAINPOOLP256R1;
- keySize = 32;
break;
#endif /* HAVE_ECC_BRAINPOOL */
#endif
@@ -8319,13 +8334,11 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
#ifndef NO_ECC_SECP
case WOLFSSL_ECC_SECP384R1:
curveId = ECC_SECP384R1;
- keySize = 48;
break;
#endif /* !NO_ECC_SECP */
#ifdef HAVE_ECC_BRAINPOOL
case WOLFSSL_ECC_BRAINPOOLP384R1TLS13:
curveId = ECC_BRAINPOOLP384R1;
- keySize = 48;
break;
#endif /* HAVE_ECC_BRAINPOOL */
#endif
@@ -8333,7 +8346,6 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
#ifdef HAVE_ECC_BRAINPOOL
case WOLFSSL_ECC_BRAINPOOLP512R1TLS13:
curveId = ECC_BRAINPOOLP512R1;
- keySize = 64;
break;
#endif /* HAVE_ECC_BRAINPOOL */
#endif
@@ -8341,7 +8353,6 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
#ifndef NO_ECC_SECP
case WOLFSSL_ECC_SECP521R1:
curveId = ECC_SECP521R1;
- keySize = 66;
break;
#endif /* !NO_ECC_SECP */
#endif
@@ -8350,6 +8361,15 @@ static int TLSX_KeyShare_GenEccKey(WOLFSSL *ssl, KeyShareEntry* kse)
return BAD_FUNC_ARG;
}
+ {
+ int size = wc_ecc_get_curve_size_from_id(curveId);
+ if (size < 0) {
+ WOLFSSL_ERROR_VERBOSE(size);
+ return size;
+ }
+ keySize = (word32)size;
+ }
+
if (kse->key == NULL) {
/* Allocate an ECC key to hold private key. */
kse->key = (byte*)XMALLOC(sizeof(ecc_key), ssl->heap, DYNAMIC_TYPE_ECC);
@@ -8543,6 +8563,11 @@ static int mlkem_id2type(int id, int *type)
}
#endif
+#if defined(WOLFSSL_NO_ML_KEM_768) && defined(WOLFSSL_NO_ML_KEM_1024) && \
+ defined(WOLFSSL_PQC_HYBRIDS)
+ #error "PQC hybrid combinations require either ML-KEM 768 or ML-KEM 1024"
+#endif
+
/* Structures and objects needed for hybrid key exchanges using both classic
* ECDHE and PQC KEM key material. */
typedef struct PqcHybridMapping {
@@ -8554,23 +8579,33 @@ typedef struct PqcHybridMapping {
static const PqcHybridMapping pqc_hybrid_mapping[] = {
#ifndef WOLFSSL_NO_ML_KEM
+#ifdef WOLFSSL_PQC_HYBRIDS
+ {WOLFSSL_SECP256R1MLKEM768, WOLFSSL_ECC_SECP256R1, WOLFSSL_ML_KEM_768, 0},
+ {WOLFSSL_SECP384R1MLKEM1024, WOLFSSL_ECC_SECP384R1, WOLFSSL_ML_KEM_1024, 0},
+#endif /* WOLFSSL_PQC_HYBRIDS */
+#ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
{WOLFSSL_SECP256R1MLKEM512, WOLFSSL_ECC_SECP256R1, WOLFSSL_ML_KEM_512, 0},
{WOLFSSL_SECP384R1MLKEM768, WOLFSSL_ECC_SECP384R1, WOLFSSL_ML_KEM_768, 0},
- {WOLFSSL_SECP256R1MLKEM768, WOLFSSL_ECC_SECP256R1, WOLFSSL_ML_KEM_768, 0},
{WOLFSSL_SECP521R1MLKEM1024, WOLFSSL_ECC_SECP521R1, WOLFSSL_ML_KEM_1024, 0},
- {WOLFSSL_SECP384R1MLKEM1024, WOLFSSL_ECC_SECP384R1, WOLFSSL_ML_KEM_1024, 0},
#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
{WOLFSSL_P256_ML_KEM_512_OLD, WOLFSSL_ECC_SECP256R1, WOLFSSL_ML_KEM_512, 0},
{WOLFSSL_P384_ML_KEM_768_OLD, WOLFSSL_ECC_SECP384R1, WOLFSSL_ML_KEM_768, 0},
{WOLFSSL_P521_ML_KEM_1024_OLD, WOLFSSL_ECC_SECP521R1, WOLFSSL_ML_KEM_1024, 0},
-#endif
+#endif /* WOLFSSL_ML_KEM_USE_OLD_IDS */
+#endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
#ifdef HAVE_CURVE25519
- {WOLFSSL_X25519MLKEM512, WOLFSSL_ECC_X25519, WOLFSSL_ML_KEM_512, 1},
+#ifdef WOLFSSL_PQC_HYBRIDS
{WOLFSSL_X25519MLKEM768, WOLFSSL_ECC_X25519, WOLFSSL_ML_KEM_768, 1},
-#endif
+#endif /* WOLFSSL_PQC_HYBRIDS */
+#ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ {WOLFSSL_X25519MLKEM512, WOLFSSL_ECC_X25519, WOLFSSL_ML_KEM_512, 1},
+#endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+#endif /* HAVE_CURVE25519 */
#ifdef HAVE_CURVE448
+#ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
{WOLFSSL_X448MLKEM768, WOLFSSL_ECC_X448, WOLFSSL_ML_KEM_768, 1},
-#endif
+#endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
+#endif /* HAVE_CURVE448 */
#endif /* WOLFSSL_NO_ML_KEM */
#ifdef WOLFSSL_MLKEM_KYBER
{WOLFSSL_P256_KYBER_LEVEL1, WOLFSSL_ECC_SECP256R1, WOLFSSL_KYBER_LEVEL1, 0},
@@ -8823,6 +8858,21 @@ static int TLSX_KeyShare_GenPqcHybridKeyClient(WOLFSSL *ssl, KeyShareEntry* kse)
/* Generate ECC key share part */
if (ret == 0) {
ecc_kse->group = ecc_group;
+
+ #ifdef WOLFSSL_ASYNC_CRYPT
+ /* Check if the provided kse already contains an ECC key and the
+ * last error was WC_PENDING_E. In this case, we already tried to
+ * generate an ECC key. Hence, we have to restore it. */
+ if (kse->key != NULL && kse->keyLen > 0 &&
+ kse->lastRet == WC_NO_ERR_TRACE(WC_PENDING_E)) {
+ ecc_kse->key = kse->key;
+ ecc_kse->keyLen = kse->keyLen;
+ ecc_kse->pubKeyLen = kse->pubKeyLen;
+ ecc_kse->lastRet = kse->lastRet;
+ kse->key = NULL;
+ }
+ #endif
+
#ifdef HAVE_CURVE25519
if (ecc_group == WOLFSSL_ECC_X25519) {
ret = TLSX_KeyShare_GenX25519Key(ssl, ecc_kse);
@@ -8838,7 +8888,17 @@ static int TLSX_KeyShare_GenPqcHybridKeyClient(WOLFSSL *ssl, KeyShareEntry* kse)
{
ret = TLSX_KeyShare_GenEccKey(ssl, ecc_kse);
}
- /* No error message, TLSX_KeyShare_Gen*Key will do it. */
+
+ #ifdef WOLFSSL_ASYNC_CRYPT
+ if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
+ /* Store the generated ECC key in the provided kse to later
+ * restore it.*/
+ kse->key = ecc_kse->key;
+ kse->keyLen = ecc_kse->keyLen;
+ kse->pubKeyLen = ecc_kse->pubKeyLen;
+ ecc_kse->key = NULL;
+ }
+ #endif
}
/* Generate PQC key share part */
@@ -9835,7 +9895,6 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl,
KeyShareEntry *ecc_kse = NULL;
word32 ctSz = 0;
word32 ssSzPqc = 0;
- word32 ssSzEcc = 0;
if (ssl->options.side == WOLFSSL_SERVER_END) {
/* I am the server, the shared secret has already been generated and
@@ -9970,6 +10029,9 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl,
XMEMCPY(ecc_kse->ke, keyShareEntry->ke + offset, ecc_kse->keLen);
}
+ #ifdef WOLFSSL_ASYNC_CRYPT
+ ecc_kse->lastRet = keyShareEntry->lastRet;
+ #endif
}
/* Process ECDH key share part. The generated shared secret is directly
@@ -9979,36 +10041,46 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl,
if (ret == 0) {
int offset = 0;
- /* Set the ECC size variable to the initial buffer size */
- ssSzEcc = ssl->arrays->preMasterSz;
-
if (pqc_first)
offset = ssSzPqc;
#ifdef HAVE_CURVE25519
if (ecc_group == WOLFSSL_ECC_X25519) {
ret = TLSX_KeyShare_ProcessX25519_ex(ssl, ecc_kse,
- ssl->arrays->preMasterSecret + offset, &ssSzEcc);
+ ssl->arrays->preMasterSecret + offset,
+ &ssl->arrays->preMasterSz);
}
else
#endif
#ifdef HAVE_CURVE448
if (ecc_group == WOLFSSL_ECC_X448) {
ret = TLSX_KeyShare_ProcessX448_ex(ssl, ecc_kse,
- ssl->arrays->preMasterSecret + offset, &ssSzEcc);
+ ssl->arrays->preMasterSecret + offset,
+ &ssl->arrays->preMasterSz);
}
else
#endif
{
ret = TLSX_KeyShare_ProcessEcc_ex(ssl, ecc_kse,
- ssl->arrays->preMasterSecret + offset, &ssSzEcc);
+ ssl->arrays->preMasterSecret + offset,
+ &ssl->arrays->preMasterSz);
}
+
+ #ifdef WOLFSSL_ASYNC_CRYPT
+ if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
+ keyShareEntry->lastRet = WC_PENDING_E;
+ /* Prevent freeing of the ECC and ML-KEM private keys */
+ ecc_kse->key = NULL;
+ pqc_kse->privKey = NULL;
+ }
+ #endif
}
if (ret == 0) {
keyShareEntry->key = ecc_kse->key;
- if ((ret == 0) && ((ssSzEcc + ssSzPqc) > ENCRYPT_LEN)) {
+ if ((ret == 0) &&
+ ((ssl->arrays->preMasterSz + ssSzPqc) > ENCRYPT_LEN)) {
WOLFSSL_MSG("shared secret is too long.");
ret = LENGTH_ERROR;
}
@@ -10017,7 +10089,7 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl,
/* Process PQC KEM key share part. Depending on the pqc_first flag, the
* KEM shared secret part goes before or after the ECDH part. */
if (ret == 0) {
- int offset = ssSzEcc;
+ int offset = ssl->arrays->preMasterSz;
if (pqc_first)
offset = 0;
@@ -10029,7 +10101,7 @@ static int TLSX_KeyShare_ProcessPqcHybridClient(WOLFSSL* ssl,
if (ret == 0) {
keyShareEntry->privKey = (byte*)pqc_kse->key;
- ssl->arrays->preMasterSz = ssSzEcc + ssSzPqc;
+ ssl->arrays->preMasterSz += ssSzPqc;
}
else
#ifdef WOLFSSL_ASYNC_CRYPT
@@ -10146,10 +10218,12 @@ static int TLSX_KeyShareEntry_Parse(const WOLFSSL* ssl, const byte* input,
*seenGroupsCnt = i + 1;
}
-#ifdef WOLFSSL_HAVE_MLKEM
- if ((WOLFSSL_NAMED_GROUP_IS_PQC(group) ||
- WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group)) &&
- ssl->options.side == WOLFSSL_SERVER_END) {
+#if defined(WOLFSSL_HAVE_MLKEM)
+ if ((WOLFSSL_NAMED_GROUP_IS_PQC(group)
+ #if !defined(WOLFSSL_ASYNC_CRYPT)
+ || WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group)
+ #endif
+ ) && ssl->options.side == WOLFSSL_SERVER_END) {
/* When handling a key share containing a KEM public key on the server
* end, we have to perform the encapsulation immediately in order to
* send the resulting ciphertext back to the client in the ServerHello
@@ -10157,7 +10231,12 @@ static int TLSX_KeyShareEntry_Parse(const WOLFSSL* ssl, const byte* input,
* don't have to create a copy of it.
* In case of a hybrid key exchange, the ECDH part is also performed
* immediately (to not split the generation of the master secret).
- * Hence, we also don't have to store this public key either. */
+ * Hence, we also don't have to store this public key either.
+ *
+ * When WOLFSSL_ASYNC_CRYPT is enabled, this handling is not possible
+ * for the hybrid case, as the ECC part is performed asynchronously,
+ * requiring the key share data to be stored.
+ */
ke = (byte *)&input[offset];
} else
#endif
@@ -10552,7 +10631,7 @@ static int TLSX_KeyShare_HandlePqcKeyServer(WOLFSSL* ssl,
return ret;
}
-static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
+int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
KeyShareEntry* keyShareEntry, byte* data, word16 len)
{
/* I am the server. The data parameter is the concatenation of the client's
@@ -10572,7 +10651,6 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
word32 pubSz = 0;
word32 ctSz = 0;
word32 ssSzPqc = 0;
- word32 ssSzEcc = 0;
if (data == NULL) {
WOLFSSL_MSG("No hybrid key share data from the client.");
@@ -10596,14 +10674,17 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
ret = MEMORY_ERROR;
}
}
+ if (ret == 0) {
+ XMEMSET(ecc_kse, 0, sizeof(*ecc_kse));
+ ecc_kse->group = ecc_group;
+ XMEMSET(pqc_kse, 0, sizeof(*pqc_kse));
+ pqc_kse->group = pqc_group;
+ }
/* The ciphertext and shared secret sizes of a KEM are fixed. Hence, we
* decode these sizes to properly concatenate the KEM ciphertext with the
* ECDH public key. */
if (ret == 0) {
- XMEMSET(pqc_kse, 0, sizeof(*pqc_kse));
- pqc_kse->group = pqc_group;
-
/* Allocate a Kyber key to hold private key. */
pqc_kse->key = (KyberKey*) XMALLOC(sizeof(KyberKey), ssl->heap,
DYNAMIC_TYPE_PRIVATE_KEY);
@@ -10639,10 +10720,26 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
}
}
+#ifdef WOLFSSL_ASYNC_CRYPT
+ if (ret == 0) {
+ /* Check if the provided kse already contains ECC data and the
+ * last error was WC_PENDING_E. In this case, we already tried to
+ * process ECC kse data. Hence, we have to restore it. */
+ if (keyShareEntry->key != NULL && keyShareEntry->keyLen > 0 &&
+ keyShareEntry->lastRet == WC_NO_ERR_TRACE(WC_PENDING_E)) {
+ ecc_kse->key = keyShareEntry->key;
+ ecc_kse->keyLen = keyShareEntry->keyLen;
+ ecc_kse->pubKey = keyShareEntry->pubKey;
+ ecc_kse->pubKeyLen = keyShareEntry->pubKeyLen;
+ ecc_kse->lastRet = keyShareEntry->lastRet;
+ keyShareEntry->key = NULL;
+ keyShareEntry->pubKey = NULL;
+ }
+ }
+#endif
+
/* Generate the ECDH key share part to be sent to the client */
- if (ret == 0 && ecc_group != 0) {
- XMEMSET(ecc_kse, 0, sizeof(*ecc_kse));
- ecc_kse->group = ecc_group;
+ if (ret == 0 && ecc_group != 0 && ecc_kse->pubKey == NULL) {
#ifdef HAVE_CURVE25519
if (ecc_group == WOLFSSL_ECC_X25519) {
ret = TLSX_KeyShare_GenX25519Key(ssl, ecc_kse);
@@ -10658,7 +10755,22 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
{
ret = TLSX_KeyShare_GenEccKey(ssl, ecc_kse);
}
- /* No error message, TLSX_KeyShare_GenKey will do it. */
+ #ifdef WOLFSSL_ASYNC_CRYPT
+ if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
+ /* Store the generated ECC key in the provided kse to later
+ * restore it.*/
+ keyShareEntry->key = ecc_kse->key;
+ keyShareEntry->keyLen = ecc_kse->keyLen;
+ keyShareEntry->pubKeyLen = ecc_kse->pubKeyLen;
+ keyShareEntry->lastRet = WC_PENDING_E;
+ ecc_kse->key = NULL;
+ }
+ else if (ret == 0 &&
+ keyShareEntry->lastRet == WC_NO_ERR_TRACE(WC_PENDING_E)) {
+ keyShareEntry->lastRet = 0;
+ ecc_kse->lastRet = 0;
+ }
+ #endif
}
if (ret == 0 && len != pubSz + ecc_kse->pubKeyLen) {
@@ -10694,9 +10806,6 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
int pubOffset = 0;
int ssOffset = 0;
- /* Set the ECC size variable to the initial buffer size */
- ssSzEcc = ssl->arrays->preMasterSz;
-
if (pqc_first) {
pubOffset = pubSz;
ssOffset = ssSzPqc;
@@ -10707,31 +10816,44 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
#ifdef HAVE_CURVE25519
if (ecc_group == WOLFSSL_ECC_X25519) {
ret = TLSX_KeyShare_ProcessX25519_ex(ssl, ecc_kse,
- ssl->arrays->preMasterSecret + ssOffset, &ssSzEcc);
+ ssl->arrays->preMasterSecret + ssOffset,
+ &ssl->arrays->preMasterSz);
}
else
#endif
#ifdef HAVE_CURVE448
if (ecc_group == WOLFSSL_ECC_X448) {
ret = TLSX_KeyShare_ProcessX448_ex(ssl, ecc_kse,
- ssl->arrays->preMasterSecret + ssOffset, &ssSzEcc);
+ ssl->arrays->preMasterSecret + ssOffset,
+ &ssl->arrays->preMasterSz);
}
else
#endif
{
ret = TLSX_KeyShare_ProcessEcc_ex(ssl, ecc_kse,
- ssl->arrays->preMasterSecret + ssOffset, &ssSzEcc);
+ ssl->arrays->preMasterSecret + ssOffset,
+ &ssl->arrays->preMasterSz);
}
}
if (ret == 0) {
- if (ssSzEcc != ecc_kse->keyLen) {
+ if (ssl->arrays->preMasterSz != ecc_kse->keyLen) {
WOLFSSL_MSG("Data length mismatch.");
ret = BAD_FUNC_ARG;
}
}
+ #ifdef WOLFSSL_ASYNC_CRYPT
+ else if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
+ keyShareEntry->lastRet = WC_PENDING_E;
+ keyShareEntry->key = ecc_kse->key;
+ keyShareEntry->pubKey = ecc_kse->pubKey;
+ keyShareEntry->pubKeyLen = ecc_kse->pubKeyLen;
+ ecc_kse->key = NULL;
+ ecc_kse->pubKey = NULL;
+ }
+ #endif
}
- if (ret == 0 && ssSzEcc + ssSzPqc > ENCRYPT_LEN) {
+ if (ret == 0 && ssl->arrays->preMasterSz + ssSzPqc > ENCRYPT_LEN) {
WOLFSSL_MSG("shared secret is too long.");
ret = LENGTH_ERROR;
}
@@ -10740,7 +10862,7 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
* KEM shared secret part goes before or after the ECDH part. */
if (ret == 0) {
int input_offset = ecc_kse->keLen;
- int output_offset = ssSzEcc;
+ int output_offset = ssl->arrays->preMasterSz;
if (pqc_first) {
input_offset = 0;
@@ -10755,7 +10877,7 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
if (ret == 0) {
XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
- ssl->arrays->preMasterSz = ssSzEcc + ssSzPqc;
+ ssl->arrays->preMasterSz += ssSzPqc;
keyShareEntry->ke = NULL;
keyShareEntry->keLen = 0;
@@ -10832,7 +10954,8 @@ int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group, word16 len, byte* data,
/* Try to find the key share entry with this group. */
keyShareEntry = (KeyShareEntry*)extension->data;
while (keyShareEntry != NULL) {
-#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
+ #if defined(WOLFSSL_ML_KEM_USE_OLD_IDS) && \
+ defined (WOLFSSL_EXTRA_PQC_HYBRIDS)
if ((group == WOLFSSL_P256_ML_KEM_512_OLD &&
keyShareEntry->group == WOLFSSL_SECP256R1MLKEM512) ||
(group == WOLFSSL_P384_ML_KEM_768_OLD &&
@@ -10843,7 +10966,7 @@ int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group, word16 len, byte* data,
break;
}
else
-#endif
+ #endif /* WOLFSSL_ML_KEM_USE_OLD_IDS && WOLFSSL_EXTRA_PQC_HYBRIDS */
if (keyShareEntry->group == group)
break;
keyShareEntry = keyShareEntry->next;
@@ -10876,7 +10999,9 @@ int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group, word16 len, byte* data,
keyShareEntry->keLen = 0;
}
}
- else if (ssl->options.side == WOLFSSL_SERVER_END &&
+ else
+#if !defined(WOLFSSL_ASYNC_CRYPT)
+ if (ssl->options.side == WOLFSSL_SERVER_END &&
WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group)) {
if (TLSX_IsGroupSupported(group)) {
ret = TLSX_KeyShare_HandlePqcHybridKeyServer((WOLFSSL*)ssl,
@@ -10892,6 +11017,7 @@ int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group, word16 len, byte* data,
}
}
else
+#endif
#endif
if (data != NULL) {
XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
@@ -10939,21 +11065,39 @@ int TLSX_KeyShare_Empty(WOLFSSL* ssl)
}
static const word16 preferredGroup[] = {
-#if defined(HAVE_ECC) && (!defined(NO_ECC256) || \
- defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 256
- WOLFSSL_ECC_SECP256R1,
-#if !defined(HAVE_FIPS) && defined(WOLFSSL_SM2)
- WOLFSSL_ECC_SM2P256V1,
-#endif
-#if defined(HAVE_ECC_BRAINPOOL)
- WOLFSSL_ECC_BRAINPOOLP256R1TLS13,
+ /* Sort by strength, but prefer non-experimental PQ/T hybrid groups */
+#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_NO_ML_KEM) && \
+ defined(WOLFSSL_PQC_HYBRIDS)
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) && \
+ ECC_MIN_KEY_SZ <= 256
+ WOLFSSL_X25519MLKEM768,
+ #endif
+ #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \
+ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \
+ ECC_MIN_KEY_SZ <= 384
+ WOLFSSL_SECP384R1MLKEM1024,
+ #endif
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
+ (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \
+ ECC_MIN_KEY_SZ <= 256
+ WOLFSSL_SECP256R1MLKEM768,
+ #endif
+#endif /* WOLFSSL_HAVE_MLKEM && !WOLFSSL_NO_ML_KEM && WOLFSSL_PQC_HYBRIDS */
+#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_NO_ML_KEM) && \
+ !defined(WOLFSSL_NO_ML_KEM_1024) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ WOLFSSL_ML_KEM_1024,
#endif
+#if defined(HAVE_ECC) && (!defined(NO_ECC521) || \
+ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 521
+ WOLFSSL_ECC_SECP521R1,
#endif
-#if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- WOLFSSL_ECC_X25519,
+#if defined(HAVE_ECC) && defined(HAVE_ECC512) && \
+ defined(HAVE_ECC_BRAINPOOL) && ECC_MIN_KEY_SZ <= 512
+ WOLFSSL_ECC_BRAINPOOLP512R1TLS13,
#endif
-#if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
- WOLFSSL_ECC_X448,
+#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_NO_ML_KEM) && \
+ !defined(WOLFSSL_NO_ML_KEM_768) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ WOLFSSL_ML_KEM_768,
#endif
#if defined(HAVE_ECC) && (!defined(NO_ECC384) || \
defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 384
@@ -10962,81 +11106,65 @@ static const word16 preferredGroup[] = {
WOLFSSL_ECC_BRAINPOOLP384R1TLS13,
#endif
#endif
-#if defined(HAVE_ECC) && (!defined(NO_ECC521) || \
- defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 521
- WOLFSSL_ECC_SECP521R1,
+#if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
+ WOLFSSL_ECC_X448,
#endif
-#if defined(HAVE_ECC) && defined(HAVE_ECC512) && \
- defined(HAVE_ECC_BRAINPOOL) && ECC_MIN_KEY_SZ <= 512
- WOLFSSL_ECC_BRAINPOOLP512R1TLS13,
+#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_NO_ML_KEM) && \
+ !defined(WOLFSSL_NO_ML_KEM_512) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ WOLFSSL_ML_KEM_512,
#endif
-#if defined(HAVE_FFDHE_2048)
- WOLFSSL_FFDHE_2048,
+#if defined(HAVE_ECC) && (!defined(NO_ECC256) || \
+ defined(HAVE_ALL_CURVES)) && !defined(NO_ECC_SECP) && ECC_MIN_KEY_SZ <= 256
+ WOLFSSL_ECC_SECP256R1,
+#if !defined(HAVE_FIPS) && defined(WOLFSSL_SM2)
+ WOLFSSL_ECC_SM2P256V1,
#endif
-#if defined(HAVE_FFDHE_3072)
- WOLFSSL_FFDHE_3072,
+#if defined(HAVE_ECC_BRAINPOOL)
+ WOLFSSL_ECC_BRAINPOOLP256R1TLS13,
#endif
-#if defined(HAVE_FFDHE_4096)
- WOLFSSL_FFDHE_4096,
#endif
-#if defined(HAVE_FFDHE_6144)
- WOLFSSL_FFDHE_6144,
+#if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
+ WOLFSSL_ECC_X25519,
#endif
#if defined(HAVE_FFDHE_8192)
WOLFSSL_FFDHE_8192,
#endif
+#if defined(HAVE_FFDHE_6144)
+ WOLFSSL_FFDHE_6144,
+#endif
+#if defined(HAVE_FFDHE_4096)
+ WOLFSSL_FFDHE_4096,
+#endif
+#if defined(HAVE_FFDHE_3072)
+ WOLFSSL_FFDHE_3072,
+#endif
+#if defined(HAVE_FFDHE_2048)
+ WOLFSSL_FFDHE_2048,
+#endif
#ifndef WOLFSSL_NO_ML_KEM
-#ifdef WOLFSSL_WC_MLKEM
- #ifndef WOLFSSL_NO_ML_KEM_512
- WOLFSSL_ML_KEM_512,
- WOLFSSL_SECP256R1MLKEM512,
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- WOLFSSL_X25519MLKEM512,
- #endif
+ #if !defined(WOLFSSL_NO_ML_KEM_1024) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
+ WOLFSSL_SECP521R1MLKEM1024,
#endif
- #ifndef WOLFSSL_NO_ML_KEM_768
- WOLFSSL_ML_KEM_768,
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
WOLFSSL_SECP384R1MLKEM768,
- WOLFSSL_SECP256R1MLKEM768,
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- WOLFSSL_X25519MLKEM768,
- #endif
#if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
WOLFSSL_X448MLKEM768,
+ #endif /* HAVE_CURVE448 */
#endif
- #endif
- #ifndef WOLFSSL_NO_ML_KEM_1024
- WOLFSSL_ML_KEM_1024,
- WOLFSSL_SECP521R1MLKEM1024,
- WOLFSSL_SECP384R1MLKEM1024,
- #endif
-#elif defined(HAVE_LIBOQS)
- /* These require a runtime call to TLSX_IsGroupSupported to use */
- WOLFSSL_ML_KEM_512,
- WOLFSSL_ML_KEM_768,
- WOLFSSL_ML_KEM_1024,
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && \
+ defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
WOLFSSL_SECP256R1MLKEM512,
- WOLFSSL_SECP384R1MLKEM768,
- WOLFSSL_SECP256R1MLKEM768,
- WOLFSSL_SECP521R1MLKEM1024,
- WOLFSSL_SECP384R1MLKEM1024,
#if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
WOLFSSL_X25519MLKEM512,
- WOLFSSL_X25519MLKEM768,
- #endif
- #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
- WOLFSSL_X448MLKEM768,
+ #endif /* HAVE_CURVE25519 */
#endif
-#endif
#endif /* !WOLFSSL_NO_ML_KEM */
#ifdef WOLFSSL_MLKEM_KYBER
-#ifdef WOLFSSL_WC_MLKEM
- #ifdef WOLFSSL_KYBER512
- WOLFSSL_KYBER_LEVEL1,
- WOLFSSL_P256_KYBER_LEVEL1,
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- WOLFSSL_X25519_KYBER_LEVEL1,
- #endif
+ #ifdef WOLFSSL_KYBER1024
+ WOLFSSL_KYBER_LEVEL5,
+ WOLFSSL_P521_KYBER_LEVEL5,
#endif
#ifdef WOLFSSL_KYBER768
WOLFSSL_KYBER_LEVEL3,
@@ -11049,27 +11177,13 @@ static const word16 preferredGroup[] = {
WOLFSSL_X448_KYBER_LEVEL3,
#endif
#endif
- #ifdef WOLFSSL_KYBER1024
- WOLFSSL_KYBER_LEVEL5,
- WOLFSSL_P521_KYBER_LEVEL5,
- #endif
-#elif defined(HAVE_LIBOQS)
- /* These require a runtime call to TLSX_IsGroupSupported to use */
+ #ifdef WOLFSSL_KYBER512
WOLFSSL_KYBER_LEVEL1,
- WOLFSSL_KYBER_LEVEL3,
- WOLFSSL_KYBER_LEVEL5,
WOLFSSL_P256_KYBER_LEVEL1,
- WOLFSSL_P384_KYBER_LEVEL3,
- WOLFSSL_P256_KYBER_LEVEL3,
- WOLFSSL_P521_KYBER_LEVEL5,
#if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
WOLFSSL_X25519_KYBER_LEVEL1,
- WOLFSSL_X25519_KYBER_LEVEL3,
#endif
- #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
- WOLFSSL_X448_KYBER_LEVEL3,
#endif
-#endif
#endif /* WOLFSSL_MLKEM_KYBER */
WOLFSSL_NAMED_GROUP_INVALID
};
@@ -11106,7 +11220,8 @@ static int TLSX_KeyShare_GroupRank(const WOLFSSL* ssl, int group)
#endif
for (i = 0; i < numGroups; i++) {
-#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
+#if defined(WOLFSSL_ML_KEM_USE_OLD_IDS) && \
+ defined (WOLFSSL_EXTRA_PQC_HYBRIDS)
if ((group == WOLFSSL_P256_ML_KEM_512_OLD &&
groups[i] == WOLFSSL_SECP256R1MLKEM512) ||
(group == WOLFSSL_P384_ML_KEM_768_OLD &&
@@ -11486,8 +11601,11 @@ int TLSX_KeyShare_Setup(WOLFSSL *ssl, KeyShareEntry* clientKSE)
if (clientKSE->key == NULL) {
#ifdef WOLFSSL_HAVE_MLKEM
- if (WOLFSSL_NAMED_GROUP_IS_PQC(clientKSE->group) ||
- WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(clientKSE->group)) {
+ if (WOLFSSL_NAMED_GROUP_IS_PQC(clientKSE->group)
+ #if !defined(WOLFSSL_ASYNC_CRYPT)
+ || WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(clientKSE->group)
+ #endif
+ ) {
/* Going to need the public key (AKA ciphertext). */
serverKSE->pubKey = clientKSE->pubKey;
clientKSE->pubKey = NULL;
@@ -11495,6 +11613,13 @@ int TLSX_KeyShare_Setup(WOLFSSL *ssl, KeyShareEntry* clientKSE)
clientKSE->pubKeyLen = 0;
}
else
+ #if defined(WOLFSSL_ASYNC_CRYPT)
+ if (WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(clientKSE->group)) {
+ ret = TLSX_KeyShare_HandlePqcHybridKeyServer(ssl, serverKSE,
+ clientKSE->ke, clientKSE->keLen);
+ }
+ else
+ #endif
#endif
{
ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
@@ -15012,144 +15137,204 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions)
}
#endif /* WOLFSSL_TLS13 */
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
+ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_PQC_HYBRIDS)
+ /* Prefer non-experimental PQ/T hybrid groups (only for TLS 1.3) */
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519) && \
+ ECC_MIN_KEY_SZ <= 256
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519MLKEM768,
+ ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \
+ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \
+ ECC_MIN_KEY_SZ <= 384
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP384R1MLKEM1024,
+ ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
+ (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \
+ ECC_MIN_KEY_SZ <= 256
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP256R1MLKEM768,
+ ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ }
+#endif
+
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
+ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_1024) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_1024,
+ ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ }
+#endif
+
#if defined(HAVE_ECC)
- /* list in order by strength, since not all servers choose by strength */
- #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521
- #ifndef NO_ECC_SECP
+ /* list in order by strength, since not all servers choose by strength */
+ #if (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP521R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #endif
+ #if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512
+ #ifdef HAVE_ECC_BRAINPOOL
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ /* TLS 1.3 BrainpoolP512 curve */
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP512R1TLS13, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+
+ /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */
+ if (ssl->options.downgrade &&
+ (ssl->options.minDowngrade <= TLSv1_2_MINOR ||
+ ssl->options.minDowngrade <= DTLSv1_2_MINOR)) {
ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_SECP521R1, ssl->heap);
+ WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
+ }
+ }
+ else {
+ /* TLS 1.2 only */
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ }
#endif
- #if (defined(HAVE_ECC512) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 512
- #ifdef HAVE_ECC_BRAINPOOL
- if (IsAtLeastTLSv1_3(ssl->version)) {
- /* TLS 1.3 BrainpoolP512 curve */
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP512R1TLS13, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
-
- /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */
- if (ssl->options.downgrade &&
- (ssl->options.minDowngrade <= TLSv1_2_MINOR ||
- ssl->options.minDowngrade <= DTLSv1_2_MINOR)) {
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- }
- }
- else {
- /* TLS 1.2 only */
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP512R1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- }
- #endif
+ #endif
+#endif
+
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
+ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_768) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_768,
+ ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ }
+#endif
+
+#if defined(HAVE_ECC)
+ #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP384R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
#endif
- #if (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
- #ifndef NO_ECC_SECP
+ #ifdef HAVE_ECC_BRAINPOOL
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ /* TLS 1.3 BrainpoolP384 curve */
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP384R1TLS13, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+
+ /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */
+ if (ssl->options.downgrade &&
+ (ssl->options.minDowngrade <= TLSv1_2_MINOR ||
+ ssl->options.minDowngrade <= DTLSv1_2_MINOR)) {
ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_SECP384R1, ssl->heap);
+ WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
- #ifdef HAVE_ECC_BRAINPOOL
- if (IsAtLeastTLSv1_3(ssl->version)) {
- /* TLS 1.3 BrainpoolP384 curve */
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP384R1TLS13, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
-
- /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */
- if (ssl->options.downgrade &&
- (ssl->options.minDowngrade <= TLSv1_2_MINOR ||
- ssl->options.minDowngrade <= DTLSv1_2_MINOR)) {
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- }
- }
- else {
- /* TLS 1.2 only */
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- }
- #endif
+ }
+ }
+ else {
+ /* TLS 1.2 only */
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP384R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ }
#endif
+ #endif
#endif /* HAVE_ECC */
- #ifndef HAVE_FIPS
- #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_X448, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
- #endif /* HAVE_FIPS */
+#ifndef HAVE_FIPS
+ #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_X448, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+#endif /* HAVE_FIPS */
+
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
+ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_512) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_512,
+ ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ }
+#endif
#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
- #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
- #ifndef NO_ECC_SECP
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_SECP256R1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
- #ifdef HAVE_ECC_KOBLITZ
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_SECP256K1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
- #ifdef HAVE_ECC_BRAINPOOL
- if (IsAtLeastTLSv1_3(ssl->version)) {
- /* TLS 1.3 BrainpoolP256 curve */
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP256R1TLS13, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
-
- /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */
- if (ssl->options.downgrade &&
- (ssl->options.minDowngrade <= TLSv1_2_MINOR ||
- ssl->options.minDowngrade <= DTLSv1_2_MINOR)) {
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- }
- }
- else {
- /* TLS 1.2 only */
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- }
- #endif
- #ifdef WOLFSSL_SM2
+ #if (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP256R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_KOBLITZ
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP256K1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_BRAINPOOL
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+ /* TLS 1.3 BrainpoolP256 curve */
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP256R1TLS13, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+
+ /* If TLS 1.2 is allowed, also add the TLS 1.2 curve */
+ if (ssl->options.downgrade &&
+ (ssl->options.minDowngrade <= TLSv1_2_MINOR ||
+ ssl->options.minDowngrade <= DTLSv1_2_MINOR)) {
ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_SM2P256V1, ssl->heap);
+ WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
+ }
+ }
+ else {
+ /* TLS 1.2 only */
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_BRAINPOOLP256R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ }
+ #endif
+ #ifdef WOLFSSL_SM2
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SM2P256V1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
#endif
+ #endif
#endif /* HAVE_ECC */
- #ifndef HAVE_FIPS
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_X25519, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
- #endif /* HAVE_FIPS */
+#ifndef HAVE_FIPS
+ #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_X25519, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+#endif /* HAVE_FIPS */
#if defined(HAVE_ECC) && defined(HAVE_SUPPORTED_CURVES)
- #if (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 224
- #ifndef NO_ECC_SECP
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_SECP224R1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
- #ifdef HAVE_ECC_KOBLITZ
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_ECC_SECP224K1, ssl->heap);
- if (ret != WOLFSSL_SUCCESS) return ret;
- #endif
+ #if (defined(HAVE_ECC224) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 224
+ #ifndef NO_ECC_SECP
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP224R1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
+ #endif
+ #ifdef HAVE_ECC_KOBLITZ
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_ECC_SECP224K1, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
#endif
+ #endif
#ifndef HAVE_FIPS
#if (defined(HAVE_ECC192) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 192
@@ -15185,220 +15370,149 @@ static int TLSX_PopulateSupportedGroups(WOLFSSL* ssl, TLSX** extensions)
#endif /* HAVE_ECC */
#ifndef NO_DH
- /* Add FFDHE supported groups. */
- #ifdef HAVE_FFDHE_8192
- if (8192/8 >= ssl->options.minDhKeySz &&
- 8192/8 <= ssl->options.maxDhKeySz) {
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_FFDHE_8192, ssl->heap);
- if (ret != WOLFSSL_SUCCESS)
- return ret;
- }
- #endif
- #ifdef HAVE_FFDHE_6144
- if (6144/8 >= ssl->options.minDhKeySz &&
- 6144/8 <= ssl->options.maxDhKeySz) {
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_FFDHE_6144, ssl->heap);
- if (ret != WOLFSSL_SUCCESS)
- return ret;
- }
- #endif
- #ifdef HAVE_FFDHE_4096
- if (4096/8 >= ssl->options.minDhKeySz &&
- 4096/8 <= ssl->options.maxDhKeySz) {
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_FFDHE_4096, ssl->heap);
- if (ret != WOLFSSL_SUCCESS)
- return ret;
- }
- #endif
- #ifdef HAVE_FFDHE_3072
- if (3072/8 >= ssl->options.minDhKeySz &&
- 3072/8 <= ssl->options.maxDhKeySz) {
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_FFDHE_3072, ssl->heap);
- if (ret != WOLFSSL_SUCCESS)
- return ret;
- }
- #endif
- #ifdef HAVE_FFDHE_2048
- if (2048/8 >= ssl->options.minDhKeySz &&
- 2048/8 <= ssl->options.maxDhKeySz) {
- ret = TLSX_UseSupportedCurve(extensions,
- WOLFSSL_FFDHE_2048, ssl->heap);
- if (ret != WOLFSSL_SUCCESS)
- return ret;
- }
- #endif
-#endif
-
-#ifdef WOLFSSL_HAVE_MLKEM
-#ifndef WOLFSSL_NO_ML_KEM
-#ifdef WOLFSSL_WC_MLKEM
-#ifndef WOLFSSL_NO_ML_KEM_512
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_512,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP256R1MLKEM512,
- ssl->heap);
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519MLKEM512,
- ssl->heap);
+ /* Add FFDHE supported groups. */
+ #ifdef HAVE_FFDHE_8192
+ if (8192/8 >= ssl->options.minDhKeySz &&
+ 8192/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_8192, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
#endif
-#endif
-#ifndef WOLFSSL_NO_ML_KEM_768
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_768,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP384R1MLKEM768,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP256R1MLKEM768,
- ssl->heap);
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519MLKEM768,
- ssl->heap);
+ #ifdef HAVE_FFDHE_6144
+ if (6144/8 >= ssl->options.minDhKeySz &&
+ 6144/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_6144, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
#endif
- #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448MLKEM768,
- ssl->heap);
+ #ifdef HAVE_FFDHE_4096
+ if (4096/8 >= ssl->options.minDhKeySz &&
+ 4096/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_4096, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_3072
+ if (3072/8 >= ssl->options.minDhKeySz &&
+ 3072/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_3072, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
+ #endif
+ #ifdef HAVE_FFDHE_2048
+ if (2048/8 >= ssl->options.minDhKeySz &&
+ 2048/8 <= ssl->options.maxDhKeySz) {
+ ret = TLSX_UseSupportedCurve(extensions,
+ WOLFSSL_FFDHE_2048, ssl->heap);
+ if (ret != WOLFSSL_SUCCESS)
+ return ret;
+ }
#endif
#endif
-#ifndef WOLFSSL_NO_ML_KEM_1024
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_1024,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
+
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
+ !defined(WOLFSSL_NO_ML_KEM) && defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+#if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC) && \
+ (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 521
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP521R1MLKEM1024,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP384R1MLKEM1024,
- ssl->heap);
+ if (ret != WOLFSSL_SUCCESS) return ret;
#endif
-#elif defined(HAVE_LIBOQS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_512, ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_768,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_ML_KEM_1024,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP256R1MLKEM512,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
+#if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC) && \
+ (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 384
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP384R1MLKEM768,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP256R1MLKEM768,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP521R1MLKEM1024,
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+#if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448) && \
+ ECC_MIN_KEY_SZ <= 448
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448MLKEM768,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP384R1MLKEM1024,
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+#if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_ECC) && \
+ (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && ECC_MIN_KEY_SZ <= 256
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_SECP256R1MLKEM512,
ssl->heap);
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- if (ret == WOLFSSL_SUCCESS)
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+#if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519) && \
+ ECC_MIN_KEY_SZ <= 256
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519MLKEM512,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519MLKEM768,
- ssl->heap);
- #endif
- #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448MLKEM768,
- ssl->heap);
- #endif
-#endif /* HAVE_LIBOQS */
-#endif /* !WOLFSSL_NO_ML_KEM */
-#ifdef WOLFSSL_MLKEM_KYBER
-#ifdef WOLFSSL_WC_MLKEM
-#ifdef WOLFSSL_KYBER512
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL1,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL1,
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+ }
+#endif
+
+#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_HAVE_MLKEM) && \
+ defined(WOLFSSL_MLKEM_KYBER)
+ if (IsAtLeastTLSv1_3(ssl->version)) {
+#ifdef WOLFSSL_KYBER1024
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL5,
ssl->heap);
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL1,
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#if defined(HAVE_ECC) && (defined(HAVE_ECC521) || defined(HAVE_ALL_CURVES)) && \
+ ECC_MIN_KEY_SZ <= 521
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_KYBER_LEVEL5,
ssl->heap);
- #endif
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
#endif
#ifdef WOLFSSL_KYBER768
- if (ret == WOLFSSL_SUCCESS)
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL3,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#if defined(HAVE_ECC) && (defined(HAVE_ECC384) || defined(HAVE_ALL_CURVES)) && \
+ ECC_MIN_KEY_SZ <= 384
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER_LEVEL3,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+#if defined(HAVE_ECC) && (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \
+ ECC_MIN_KEY_SZ <= 256
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL3,
ssl->heap);
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- if (ret == WOLFSSL_SUCCESS)
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+#if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL3,
ssl->heap);
- #endif
- #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
- if (ret == WOLFSSL_SUCCESS)
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+#if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448_KYBER_LEVEL3,
ssl->heap);
- #endif
+ if (ret != WOLFSSL_SUCCESS) return ret;
#endif
-#ifdef WOLFSSL_KYBER1024
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL5,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_KYBER_LEVEL5,
- ssl->heap);
#endif
-#elif defined(HAVE_LIBOQS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL1, ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL3,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL5,
+#ifdef WOLFSSL_KYBER512
+ ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_KYBER_LEVEL1,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#if defined(HAVE_ECC) && (!defined(NO_ECC256) || defined(HAVE_ALL_CURVES)) && \
+ ECC_MIN_KEY_SZ <= 256
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL1,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P384_KYBER_LEVEL3,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P256_KYBER_LEVEL3,
- ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_P521_KYBER_LEVEL5,
- ssl->heap);
- #if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
- if (ret == WOLFSSL_SUCCESS)
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+#if defined(HAVE_CURVE25519) && ECC_MIN_KEY_SZ <= 256
ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL1,
ssl->heap);
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X25519_KYBER_LEVEL3,
- ssl->heap);
- #endif
- #if defined(HAVE_CURVE448) && ECC_MIN_KEY_SZ <= 448
- if (ret == WOLFSSL_SUCCESS)
- ret = TLSX_UseSupportedCurve(extensions, WOLFSSL_X448_KYBER_LEVEL3,
- ssl->heap);
- #endif
-#endif /* HAVE_LIBOQS */
-#endif /* WOLFSSL_MLKEM_KYBER */
-#endif /* WOLFSSL_HAVE_MLKEM */
+ if (ret != WOLFSSL_SUCCESS) return ret;
+#endif
+#endif
+ }
+#endif
(void)ssl;
(void)extensions;
diff --git a/src/tls13.c b/src/tls13.c
index 27d1ec0c3fa..c01604c1030 100644
--- a/src/tls13.c
+++ b/src/tls13.c
@@ -7371,7 +7371,16 @@ int DoTls13ClientHello(WOLFSSL* ssl, const byte* input, word32* inOutIdx,
KeyShareEntry* serverKSE = (KeyShareEntry*)extension->data;
if (serverKSE != NULL &&
serverKSE->lastRet == WC_NO_ERR_TRACE(WC_PENDING_E)) {
- ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
+ #if defined(WOLFSSL_HAVE_MLKEM)
+ if (WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(serverKSE->group)) {
+ ret = TLSX_KeyShare_HandlePqcHybridKeyServer(ssl, serverKSE,
+ serverKSE->ke, serverKSE->keLen);
+ }
+ else
+ #endif
+ {
+ ret = TLSX_KeyShare_GenKey(ssl, serverKSE);
+ }
if (ret != 0)
goto exit_dch;
}
@@ -14038,6 +14047,12 @@ int wolfSSL_UseKeyShare(WOLFSSL* ssl, word16 group)
(void)ret;
(void)group;
#else
+ /* Check if the group is supported. */
+ if (!TLSX_IsGroupSupported(group)) {
+ WOLFSSL_MSG("Group not supported.");
+ return BAD_FUNC_ARG;
+ }
+
ret = TLSX_KeyShare_Use(ssl, group, 0, NULL, NULL, &ssl->extensions);
if (ret != 0)
return ret;
diff --git a/tests/api.c b/tests/api.c
index fd16b4d5b22..5add85836a3 100644
--- a/tests/api.c
+++ b/tests/api.c
@@ -30437,6 +30437,10 @@ static int test_dtls13_bad_epoch_ch(void)
WOLFSSL *ssl_s = NULL;
struct test_memio_ctx test_ctx;
const int EPOCH_OFF = 3;
+ int groups[] = {
+ WOLFSSL_ECC_SECP256R1,
+ WOLFSSL_ECC_SECP384R1,
+ };
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
@@ -30446,6 +30450,9 @@ static int test_dtls13_bad_epoch_ch(void)
* with just one message */
ExpectIntEQ(wolfSSL_disable_hrr_cookie(ssl_s), WOLFSSL_SUCCESS);
+ /* Set client groups to traditional only to avoid CH fragmentation */
+ ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);
+
ExpectIntNE(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_get_error(ssl_c, WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR)),
WOLFSSL_ERROR_WANT_READ);
@@ -31060,6 +31067,10 @@ static int test_TLSX_CA_NAMES_bad_extension(void)
0x0d, 0x00, 0x00, 0x11, 0x00, 0x00, 0x0d, 0x00, 0x2f, 0x00, 0x06, 0x00,
0x04, 0x00, 0x03, 0x30, 0x00, 0x13, 0x94, 0x00, 0x06, 0x00, 0x04, 0x02
};
+ int groups[2] = {
+ WOLFSSL_ECC_SECP256R1,
+ WOLFSSL_ECC_SECP521R1,
+ };
int i = 0;
for (i = 0; i < 2; i++) {
@@ -31082,6 +31093,9 @@ static int test_TLSX_CA_NAMES_bad_extension(void)
break;
}
+ /* Ensure the correct groups are used for the test */
+ ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);
+
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
#ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WC_NO_ERR_TRACE(EXT_MISSING));
@@ -32035,7 +32049,7 @@ static int test_dtls13_frag_ch_pq(void)
int group = WOLFSSL_KYBER_LEVEL1;
const char *group_name = "KYBER_LEVEL1";
#endif
-#else
+#elif !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
#if !defined(WOLFSSL_NO_ML_KEM_1024)
int group = WOLFSSL_ML_KEM_1024;
const char *group_name = "ML_KEM_1024";
@@ -32046,6 +32060,17 @@ static int test_dtls13_frag_ch_pq(void)
int group = WOLFSSL_ML_KEM_512;
const char *group_name = "ML_KEM_512";
#endif
+#elif defined(WOLFSSL_PQC_HYBRIDS)
+ #if defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)
+ int group = WOLFSSL_X25519MLKEM768;
+ const char *group_name = "X25519MLKEM768";
+ #elif !defined(WOLFSSL_NO_ML_KEM_768)
+ int group = WOLFSSL_SECP256R1MLKEM768;
+ const char *group_name = "SecP256r1MLKEM768";
+ #else
+ int group = WOLFSSL_SECP384R1MLKEM1024;
+ const char *group_name = "SecP384r1MLKEM1024";
+ #endif
#endif
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
diff --git a/tests/api/test_dtls.c b/tests/api/test_dtls.c
index 39c14e8bd3d..bc277066dcf 100644
--- a/tests/api/test_dtls.c
+++ b/tests/api/test_dtls.c
@@ -1614,6 +1614,43 @@ int test_dtls_rtx_across_epoch_change(void)
WOLFSSL_CTX *ctx_c = NULL, *ctx_s = NULL;
WOLFSSL *ssl_c = NULL, *ssl_s = NULL;
struct test_memio_ctx test_ctx;
+#if defined(WOLFSSL_HAVE_MLKEM)
+ /* When ML-KEM is used in the key share, the hello messages are fragmented
+ *into two messages */
+ int helloMsgCount = 2;
+ int groups[2] = {
+ #if defined(HAVE_CURVE25519) && defined(WOLFSSL_PQC_HYBRIDS) && \
+ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_768)
+ WOLFSSL_X25519MLKEM768,
+ #elif defined(HAVE_ECC) && defined(WOLFSSL_PQC_HYBRIDS) && \
+ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_768)
+ WOLFSSL_SECP256R1MLKEM768,
+ #elif defined(HAVE_ECC) && defined(WOLFSSL_PQC_HYBRIDS) && \
+ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_NO_ML_KEM_1024)
+ WOLFSSL_SECP384R1MLKEM1024,
+ #elif !defined(WOLFSSL_NO_ML_KEM_1024) && !defined(WOLFSSL_NO_ML_KEM) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ WOLFSSL_ML_KEM_1024,
+ #elif !defined(WOLFSSL_NO_ML_KEM_768) && !defined(WOLFSSL_NO_ML_KEM) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ WOLFSSL_ML_KEM_768,
+ #elif !defined(WOLFSSL_NO_ML_KEM_512) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ WOLFSSL_ML_KEM_512,
+ #elif defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_KYBER1024)
+ WOLFSSL_KYBER_LEVEL5,
+ #elif defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_KYBER768)
+ WOLFSSL_KYBER_LEVEL3,
+ #elif defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_KYBER512)
+ WOLFSSL_KYBER_LEVEL1,
+ #endif
+ WOLFSSL_ECC_SECP256R1,
+ };
+#else
+ /* When ECC is used in the key share, the hello messages are not
+ * fragmented */
+ int helloMsgCount = 1;
+#endif
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
@@ -1622,6 +1659,11 @@ int test_dtls_rtx_across_epoch_change(void)
wolfDTLSv1_3_client_method, wolfDTLSv1_3_server_method),
0);
+#if defined(WOLFSSL_HAVE_MLKEM)
+ ExpectIntEQ(wolfSSL_set_groups(ssl_c, groups, 2), WOLFSSL_SUCCESS);
+ ExpectIntEQ(wolfSSL_set_groups(ssl_s, groups, 2), WOLFSSL_SUCCESS);
+#endif
+
/* CH0 */
wolfSSL_SetLoggingPrefix("client:");
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
@@ -1646,7 +1688,7 @@ int test_dtls_rtx_across_epoch_change(void)
ExpectIntGE(test_ctx.c_msg_count, 2);
/* drop everything but the SH */
- while (test_ctx.c_msg_count > 1 && EXPECT_SUCCESS()) {
+ while (test_ctx.c_msg_count > helloMsgCount && EXPECT_SUCCESS()) {
ExpectIntEQ(test_memio_drop_message(&test_ctx, 1, test_ctx.c_msg_count - 1), 0);
}
diff --git a/tests/api/test_tls13.c b/tests/api/test_tls13.c
index 6e5b1930e5d..4650fa0946d 100644
--- a/tests/api/test_tls13.c
+++ b/tests/api/test_tls13.c
@@ -102,7 +102,7 @@ int test_tls13_apis(void)
#else
WOLFSSL_KYBER_LEVEL5
#endif
-#else
+#elif !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
#ifndef WOLFSSL_NO_ML_KEM_512
WOLFSSL_ML_KEM_512
#elif !defined(WOLFSSL_NO_ML_KEM_768)
@@ -110,6 +110,12 @@ int test_tls13_apis(void)
#else
WOLFSSL_ML_KEM_1024
#endif
+#else
+ #ifndef WOLFSSL_NO_ML_KEM_768
+ WOLFSSL_SECP256R1MLKEM768
+ #else
+ WOLFSSL_ECC_SECP256R1
+ #endif
#endif
#else
WOLFSSL_ECC_SECP256R1
@@ -153,12 +159,18 @@ int test_tls13_apis(void)
":P256_KYBER_LEVEL5"
#endif
#else
- #ifndef WOLFSSL_NO_ML_KEM_512
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(WOLFSSL_EXTRA_PQC_HYBRIDS)
":SecP256r1MLKEM512"
- #elif !defined(WOLFSSL_NO_ML_KEM_768)
- ":SecP384r1MLKEM768"
- #elif !defined(WOLFSSL_NO_ML_KEM_1024)
- ":SecP521r1MLKEM1024"
+ #elif !defined(WOLFSSL_NO_ML_KEM_768) && defined(WOLFSSL_PQC_HYBRIDS)
+ ":SecP256r1MLKEM768"
+ #elif !defined(WOLFSSL_NO_ML_KEM_1024) && defined(WOLFSSL_PQC_HYBRIDS)
+ ":SecP384r1MLKEM1024"
+ #elif !defined(WOLFSSL_NO_ML_KEM_1024) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ ":ML_KEM_1024"
+ #elif !defined(WOLFSSL_NO_ML_KEM_768) && \
+ !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ ":ML_KEM_768"
#endif
#endif
#endif
@@ -176,8 +188,8 @@ int test_tls13_apis(void)
#elif !defined(WOLFSSL_NO_KYBER1024)
":KYBER_LEVEL5"
#endif
-#else
- #ifndef WOLFSSL_NO_ML_KEM_512
+#elif !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ #if !defined(WOLFSSL_NO_ML_KEM_512)
":ML_KEM_512"
#elif !defined(WOLFSSL_NO_ML_KEM_768)
":ML_KEM_768"
@@ -191,7 +203,11 @@ int test_tls13_apis(void)
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MALLOC) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
- !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
+ !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
+ defined(HAVE_SUPPORTED_CURVES) && \
+ (!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \
+ (defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)) || \
+ (defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)))
int mlkemLevel;
#endif
@@ -354,8 +370,12 @@ int test_tls13_apis(void)
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_MALLOC) && \
!defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
!defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
- !defined(WOLFSSL_MLKEM_NO_DECAPSULATE)
+ !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
+ (!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \
+ (defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)) || \
+ (defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)))
#ifndef WOLFSSL_NO_ML_KEM
+#ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
#ifndef WOLFSSL_NO_ML_KEM_768
mlkemLevel = WOLFSSL_ML_KEM_768;
#elif !defined(WOLFSSL_NO_ML_KEM_1024)
@@ -364,6 +384,13 @@ int test_tls13_apis(void)
mlkemLevel = WOLFSSL_ML_KEM_512;
#endif
#else
+#if defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)
+ mlkemLevel = WOLFSSL_X25519MLKEM768;
+#elif defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)
+ mlkemLevel = WOLFSSL_SECP256R1MLKEM768;
+#endif
+#endif
+#else
#ifndef WOLFSSL_NO_KYBER768
mlkemLevel = WOLFSSL_KYBER_LEVEL3;
#elif !defined(WOLFSSL_NO_KYBER1024)
@@ -1933,27 +1960,34 @@ int test_tls13_rpk_handshake(void)
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
- !defined(WOLFSSL_MLKEM_NO_MAKE_KEY)
+ !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
+ (!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \
+ (defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)) || \
+ (defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)))
static void test_tls13_pq_groups_ctx_ready(WOLFSSL_CTX* ctx)
{
-#ifndef WOLFSSL_NO_ML_KEM_1024
#ifdef WOLFSSL_MLKEM_KYBER
+ #if !defined(WOLFSSL_NO_KYBER1024)
int group = WOLFSSL_KYBER_LEVEL5;
-#else
- int group = WOLFSSL_ML_KEM_1024;
-#endif /* WOLFSSL_MLKEM_KYBER */
-#elif !defined(WOLFSSL_NO_ML_KEM_768)
-#ifdef WOLFSSL_MLKEM_KYBER
+ #elif !defined(WOLFSSL_NO_KYBER768)
int group = WOLFSSL_KYBER_LEVEL3;
-#else
- int group = WOLFSSL_ML_KEM_768;
-#endif /* WOLFSSL_MLKEM_KYBER */
-#else
-#ifdef WOLFSSL_MLKEM_KYBER
+ #else
int group = WOLFSSL_KYBER_LEVEL1;
-#else
+ #endif
+#elif !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ #if !defined(WOLFSSL_NO_ML_KEM_1024)
+ int group = WOLFSSL_ML_KEM_1024;
+ #elif !defined(WOLFSSL_NO_ML_KEM_768)
+ int group = WOLFSSL_ML_KEM_768;
+ #else
int group = WOLFSSL_ML_KEM_512;
-#endif /* WOLFSSL_MLKEM_KYBER */
+ #endif
+#elif defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768) && \
+ defined(WOLFSSL_PQC_HYBRIDS)
+ int group = WOLFSSL_SECP256R1MLKEM768;
+#elif defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768) && \
+ defined(WOLFSSL_PQC_HYBRIDS)
+ int group = WOLFSSL_X25519MLKEM768;
#endif
AssertIntEQ(wolfSSL_CTX_set_groups(ctx, &group, 1), WOLFSSL_SUCCESS);
@@ -1961,24 +1995,28 @@ static void test_tls13_pq_groups_ctx_ready(WOLFSSL_CTX* ctx)
static void test_tls13_pq_groups_on_result(WOLFSSL* ssl)
{
-#ifndef WOLFSSL_NO_ML_KEM_1024
#ifdef WOLFSSL_MLKEM_KYBER
+ #if !defined(WOLFSSL_NO_KYBER1024)
AssertStrEQ(wolfSSL_get_curve_name(ssl), "KYBER_LEVEL5");
-#else
- AssertStrEQ(wolfSSL_get_curve_name(ssl), "ML_KEM_1024");
-#endif /* WOLFSSL_MLKEM_KYBER */
-#elif !defined(WOLFSSL_NO_ML_KEM_768)
-#ifdef WOLFSSL_MLKEM_KYBER
+ #elif !defined(WOLFSSL_NO_KYBER768)
AssertStrEQ(wolfSSL_get_curve_name(ssl), "KYBER_LEVEL3");
-#else
- AssertStrEQ(wolfSSL_get_curve_name(ssl), "ML_KEM_768");
-#endif /* WOLFSSL_MLKEM_KYBER */
-#else
-#ifdef WOLFSSL_MLKEM_KYBER
+ #else
AssertStrEQ(wolfSSL_get_curve_name(ssl), "KYBER_LEVEL1");
-#else
+ #endif
+#elif !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE)
+ #if !defined(WOLFSSL_NO_ML_KEM_1024)
+ AssertStrEQ(wolfSSL_get_curve_name(ssl), "ML_KEM_1024");
+ #elif !defined(WOLFSSL_NO_ML_KEM_768)
+ AssertStrEQ(wolfSSL_get_curve_name(ssl), "ML_KEM_768");
+ #else
AssertStrEQ(wolfSSL_get_curve_name(ssl), "ML_KEM_512");
-#endif /* WOLFSSL_MLKEM_KYBER */
+ #endif
+#elif defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768) && \
+ defined(WOLFSSL_PQC_HYBRIDS)
+ AssertStrEQ(wolfSSL_get_curve_name(ssl), "SecP256r1MLKEM768");
+#elif defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768) && \
+ defined(WOLFSSL_PQC_HYBRIDS)
+ AssertStrEQ(wolfSSL_get_curve_name(ssl), "X25519MLKEM768");
#endif
}
#endif
@@ -1989,7 +2027,10 @@ int test_tls13_pq_groups(void)
#if defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(WOLFSSL_TLS13) && \
defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \
!defined(WOLFSSL_MLKEM_NO_DECAPSULATE) && \
- !defined(WOLFSSL_MLKEM_NO_MAKE_KEY)
+ !defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \
+ (!defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) || \
+ (defined(HAVE_CURVE25519) && !defined(WOLFSSL_NO_ML_KEM_768)) || \
+ (defined(HAVE_ECC) && !defined(WOLFSSL_NO_ML_KEM_768)))
callback_functions func_cb_client;
callback_functions func_cb_server;
@@ -2174,6 +2215,25 @@ int test_tls13_early_data(void)
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c,
&ssl_s, params[i].client_meth, params[i].server_meth), 0);
+ if (params[i].isUdp) {
+ /* Early data is incompatible with HRR usage. Hence, we have to make
+ * sure a group is negotiated that does not cause a fragemented CH.
+ */
+ int group[1] = {
+ #ifdef HAVE_ECC
+ WOLFSSL_ECC_SECP256R1,
+ #elif defined(HAVE_CURVE25519)
+ WOLFSSL_ECC_X25519,
+ #elif defined(HAVE_CURVE448)
+ WOLFSSL_ECC_X448,
+ #elif defined(HAVE_FFDHE_2048)
+ WOLFSSL_FFDHE_2048,
+ #endif
+ };
+ ExpectIntEQ(wolfSSL_set_groups(ssl_c, group, 1), WOLFSSL_SUCCESS);
+ ExpectIntEQ(wolfSSL_set_groups(ssl_s, group, 1), WOLFSSL_SUCCESS);
+ }
+
/* Get a ticket so that we can do 0-RTT on the next connection */
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
/* Make sure we read the ticket */
diff --git a/tests/include.am b/tests/include.am
index 7b4e6f17e78..fc1359d3d52 100644
--- a/tests/include.am
+++ b/tests/include.am
@@ -33,12 +33,14 @@ EXTRA_DIST += tests/unit.h \
tests/test-tls13-down.conf \
tests/test-tls13-ecc.conf \
tests/test-tls13-psk.conf \
- tests/test-tls13-pq.conf \
+ tests/test-tls13-pq-standalone.conf \
tests/test-tls13-pq-hybrid.conf \
- tests/test-dtls13-pq.conf \
- tests/test-dtls13-pq-frag.conf \
- tests/test-dtls13-pq-hybrid.conf \
+ tests/test-tls13-pq-hybrid-extra.conf \
+ tests/test-dtls13-pq-standalone.conf \
+ tests/test-dtls13-pq-standalone-frag.conf \
tests/test-dtls13-pq-hybrid-frag.conf \
+ tests/test-dtls13-pq-hybrid-extra.conf \
+ tests/test-dtls13-pq-hybrid-extra-frag.conf \
tests/test-psk.conf \
tests/test-psk-no-id.conf \
tests/test-psk-no-id-sha2.conf \
diff --git a/tests/suites.c b/tests/suites.c
index 3b461b77691..67bc85fb21f 100644
--- a/tests/suites.c
+++ b/tests/suites.c
@@ -196,6 +196,7 @@ static int IsKyberLevelAvailable(const char* line)
if (begin != NULL && len > 0) {
#ifndef WOLFSSL_NO_ML_KEM
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
#ifndef WOLFSSL_NO_ML_KEM_512
if (MATCH_PQC(begin, "ML_KEM_512", len)) {
available = 1;
@@ -211,7 +212,25 @@ static int IsKyberLevelAvailable(const char* line)
available = 1;
}
#endif
-
+ #endif /* WOLFSSL_TLS_NO_MLKEM_STANDALONE */
+ #ifdef WOLFSSL_PQC_HYBRIDS
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC)
+ if (MATCH_PQC(begin, "SecP256r1MLKEM768", len)) {
+ available = 1;
+ }
+ #endif
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519)
+ if (MATCH_PQC(begin, "X25519MLKEM768", len)) {
+ available = 1;
+ }
+ #endif
+ #if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC)
+ if (MATCH_PQC(begin, "SecP384r1MLKEM1024", len)) {
+ available = 1;
+ }
+ #endif
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
#if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_ECC)
if (MATCH_PQC(begin, "SecP256r1MLKEM512", len)) {
available = 1;
@@ -222,11 +241,13 @@ static int IsKyberLevelAvailable(const char* line)
}
#endif
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC)
- if (MATCH_PQC(begin, "SecP384r1MLKEM768", len)) {
+ #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519)
+ if (MATCH_PQC(begin, "X25519MLKEM512", len)) {
available = 1;
}
- if (MATCH_PQC(begin, "SecP256r1MLKEM768", len)) {
+ #endif
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC)
+ if (MATCH_PQC(begin, "SecP384r1MLKEM768", len)) {
available = 1;
}
#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
@@ -235,8 +256,8 @@ static int IsKyberLevelAvailable(const char* line)
}
#endif
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519)
- if (MATCH_PQC(begin, "X25519MLKEM768", len)) {
+ #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448)
+ if (MATCH_PQC(begin, "X448MLKEM768", len)) {
available = 1;
}
#endif
@@ -244,26 +265,15 @@ static int IsKyberLevelAvailable(const char* line)
if (MATCH_PQC(begin, "SecP521r1MLKEM1024", len)) {
available = 1;
}
- if (MATCH_PQC(begin, "SecP384r1MLKEM1024", len)) {
- available = 1;
- }
#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
if (MATCH_PQC(begin, "P521_ML_KEM_1024_OLD", len)) {
available = 1;
}
#endif
#endif
- #if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519)
- if (MATCH_PQC(begin, "X25519MLKEM512", len)) {
- available = 1;
- }
- #endif
- #if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448)
- if (MATCH_PQC(begin, "X448MLKEM768", len)) {
- available = 1;
- }
- #endif
+ #endif /* WOLFSSL_EXTRA_PQC_HYBRIDS */
#endif /* !WOLFSSL_NO_ML_KEM */
+
#ifdef WOLFSSL_MLKEM_KYBER
#ifndef WOLFSSL_NO_KYBER512
if (MATCH_PQC(begin, "KYBER_LEVEL1", len)) {
@@ -1118,8 +1128,9 @@ int SuiteTest(int argc, char** argv)
}
#endif
#ifdef HAVE_PQC
- /* add TLSv13 pq tests */
- XSTRLCPY(argv0[1], "tests/test-tls13-pq.conf", sizeof(argv0[1]));
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
+ /* add TLSv13 pq standalone tests */
+ XSTRLCPY(argv0[1], "tests/test-tls13-pq-standalone.conf", sizeof(argv0[1]));
printf("starting TLSv13 post-quantum groups tests\n");
test_harness(&args);
if (args.return_code != 0) {
@@ -1127,6 +1138,8 @@ int SuiteTest(int argc, char** argv)
args.return_code = EXIT_FAILURE;
goto exit;
}
+ #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */
+ #ifdef WOLFSSL_PQC_HYBRIDS
/* add TLSv13 pq hybrid tests */
XSTRLCPY(argv0[1], "tests/test-tls13-pq-hybrid.conf", sizeof(argv0[1]));
printf("starting TLSv13 post-quantum groups tests\n");
@@ -1136,10 +1149,23 @@ int SuiteTest(int argc, char** argv)
args.return_code = EXIT_FAILURE;
goto exit;
}
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ /* add TLSv13 pq extra hybrid tests */
+ XSTRLCPY(argv0[1], "tests/test-tls13-pq-hybrid-extra.conf", sizeof(argv0[1]));
+ printf("starting TLSv13 post-quantum groups tests\n");
+ test_harness(&args);
+ if (args.return_code != 0) {
+ printf("error from script %d\n", args.return_code);
+ args.return_code = EXIT_FAILURE;
+ goto exit;
+ }
+ #endif
#endif
#if defined(HAVE_PQC) && defined(WOLFSSL_DTLS13)
- /* add DTLSv13 pq tests */
- XSTRLCPY(argv0[1], "tests/test-dtls13-pq.conf", sizeof(argv0[1]));
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
+ /* add DTLSv13 pq standalone tests */
+ XSTRLCPY(argv0[1], "tests/test-dtls13-pq-standalone.conf", sizeof(argv0[1]));
printf("starting DTLSv13 post-quantum groups tests\n");
test_harness(&args);
if (args.return_code != 0) {
@@ -1147,8 +1173,10 @@ int SuiteTest(int argc, char** argv)
args.return_code = EXIT_FAILURE;
goto exit;
}
- /* add DTLSv13 pq hybrid tests */
- XSTRLCPY(argv0[1], "tests/test-dtls13-pq-hybrid.conf", sizeof(argv0[1]));
+ #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ /* add DTLSv13 pq extra hybrid tests */
+ XSTRLCPY(argv0[1], "tests/test-dtls13-pq-hybrid-extra.conf", sizeof(argv0[1]));
printf("starting DTLSv13 post-quantum 2 groups tests\n");
test_harness(&args);
if (args.return_code != 0) {
@@ -1156,9 +1184,11 @@ int SuiteTest(int argc, char** argv)
args.return_code = EXIT_FAILURE;
goto exit;
}
+ #endif
#ifdef WOLFSSL_DTLS_CH_FRAG
- /* add DTLSv13 pq frag tests */
- XSTRLCPY(argv0[1], "tests/test-dtls13-pq-frag.conf", sizeof(argv0[1]));
+ #ifndef WOLFSSL_TLS_NO_MLKEM_STANDALONE
+ /* add DTLSv13 pq standalone frag tests */
+ XSTRLCPY(argv0[1], "tests/test-dtls13-pq-standalone-frag.conf", sizeof(argv0[1]));
printf("starting DTLSv13 post-quantum groups tests with fragmentation\n");
test_harness(&args);
if (args.return_code != 0) {
@@ -1166,6 +1196,8 @@ int SuiteTest(int argc, char** argv)
args.return_code = EXIT_FAILURE;
goto exit;
}
+ #endif /* !WOLFSSL_TLS_NO_MLKEM_STANDALONE */
+ #ifdef WOLFSSL_PQC_HYBRIDS
/* add DTLSv13 pq hybrid frag tests */
XSTRLCPY(argv0[1], "tests/test-dtls13-pq-hybrid-frag.conf", sizeof(argv0[1]));
printf("starting DTLSv13 post-quantum 2 groups tests with fragmentation\n");
@@ -1175,6 +1207,18 @@ int SuiteTest(int argc, char** argv)
args.return_code = EXIT_FAILURE;
goto exit;
}
+ #endif /* WOLFSSL_PQC_HYBRIDS */
+ #ifdef WOLFSSL_EXTRA_PQC_HYBRIDS
+ /* add DTLSv13 pq extra hybrid frag tests */
+ XSTRLCPY(argv0[1], "tests/test-dtls13-pq-hybrid-extra-frag.conf", sizeof(argv0[1]));
+ printf("starting DTLSv13 post-quantum 2 groups tests with fragmentation\n");
+ test_harness(&args);
+ if (args.return_code != 0) {
+ printf("error from script %d\n", args.return_code);
+ args.return_code = EXIT_FAILURE;
+ goto exit;
+ }
+ #endif
#endif
#endif
#endif
diff --git a/tests/test-dtls13-pq-hybrid-extra-frag.conf b/tests/test-dtls13-pq-hybrid-extra-frag.conf
new file mode 100644
index 00000000000..3048d53ded0
--- /dev/null
+++ b/tests/test-dtls13-pq-hybrid-extra-frag.conf
@@ -0,0 +1,95 @@
+# server DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP384r1MLKEM768
+
+# client DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP384r1MLKEM768
+
+# server DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP521r1MLKEM1024
+
+# client DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP521r1MLKEM1024
+
+# server DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X448MLKEM768
+
+# client DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X448MLKEM768
+
+# server DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P384_KYBER_LEVEL3
+
+# client DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P384_KYBER_LEVEL3
+
+# server DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P256_KYBER_LEVEL3
+
+# client DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P256_KYBER_LEVEL3
+
+# server DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P521_KYBER_LEVEL5
+
+# client DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P521_KYBER_LEVEL5
+
+# server DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X25519_KYBER_LEVEL3
+
+# client DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X25519_KYBER_LEVEL3
+
+# server DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X448_KYBER_LEVEL3
+
+# client DTLSv1.3 with post-quantum hybrid group
+-u
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X448_KYBER_LEVEL3
diff --git a/tests/test-dtls13-pq-hybrid.conf b/tests/test-dtls13-pq-hybrid-extra.conf
similarity index 100%
rename from tests/test-dtls13-pq-hybrid.conf
rename to tests/test-dtls13-pq-hybrid-extra.conf
diff --git a/tests/test-dtls13-pq-hybrid-frag.conf b/tests/test-dtls13-pq-hybrid-frag.conf
index 267468887ef..19aebb0e1a2 100644
--- a/tests/test-dtls13-pq-hybrid-frag.conf
+++ b/tests/test-dtls13-pq-hybrid-frag.conf
@@ -1,15 +1,3 @@
-# server DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP384r1MLKEM768
-
-# client DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP384r1MLKEM768
-
# server DTLSv1.3 with post-quantum hybrid group
-u
-v 4
@@ -22,18 +10,6 @@
-l TLS13-AES256-GCM-SHA384
--pqc SecP256r1MLKEM768
-# server DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP521r1MLKEM1024
-
-# client DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP521r1MLKEM1024
-
# server DTLSv1.3 with post-quantum hybrid group
-u
-v 4
@@ -57,75 +33,3 @@
-v 4
-l TLS13-AES256-GCM-SHA384
--pqc X25519MLKEM768
-
-# server DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X448MLKEM768
-
-# client DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X448MLKEM768
-
-# server DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P384_KYBER_LEVEL3
-
-# client DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P384_KYBER_LEVEL3
-
-# server DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P256_KYBER_LEVEL3
-
-# client DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P256_KYBER_LEVEL3
-
-# server DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P521_KYBER_LEVEL5
-
-# client DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P521_KYBER_LEVEL5
-
-# server DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X25519_KYBER_LEVEL3
-
-# client DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X25519_KYBER_LEVEL3
-
-# server DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X448_KYBER_LEVEL3
-
-# client DTLSv1.3 with post-quantum hybrid group
--u
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X448_KYBER_LEVEL3
diff --git a/tests/test-dtls13-pq-frag.conf b/tests/test-dtls13-pq-standalone-frag.conf
similarity index 100%
rename from tests/test-dtls13-pq-frag.conf
rename to tests/test-dtls13-pq-standalone-frag.conf
diff --git a/tests/test-dtls13-pq.conf b/tests/test-dtls13-pq-standalone.conf
similarity index 100%
rename from tests/test-dtls13-pq.conf
rename to tests/test-dtls13-pq-standalone.conf
diff --git a/tests/test-tls13-pq-hybrid-extra.conf b/tests/test-tls13-pq-hybrid-extra.conf
new file mode 100644
index 00000000000..2d0e601ce91
--- /dev/null
+++ b/tests/test-tls13-pq-hybrid-extra.conf
@@ -0,0 +1,119 @@
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP256r1MLKEM512
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP256r1MLKEM512
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP384r1MLKEM768
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP384r1MLKEM768
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP521r1MLKEM1024
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc SecP521r1MLKEM1024
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X25519MLKEM512
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X25519MLKEM512
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X448MLKEM768
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X448MLKEM768
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P256_KYBER_LEVEL1
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P256_KYBER_LEVEL1
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P384_KYBER_LEVEL3
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P384_KYBER_LEVEL3
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P256_KYBER_LEVEL3
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P256_KYBER_LEVEL3
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P521_KYBER_LEVEL5
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc P521_KYBER_LEVEL5
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X25519_KYBER_LEVEL1
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X25519_KYBER_LEVEL1
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X25519_KYBER_LEVEL3
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X25519_KYBER_LEVEL3
+
+# server TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X448_KYBER_LEVEL3
+
+# client TLSv1.3 with post-quantum hybrid group
+-v 4
+-l TLS13-AES256-GCM-SHA384
+--pqc X448_KYBER_LEVEL3
diff --git a/tests/test-tls13-pq-hybrid.conf b/tests/test-tls13-pq-hybrid.conf
index 76c8e57696f..0c4f4303a8f 100644
--- a/tests/test-tls13-pq-hybrid.conf
+++ b/tests/test-tls13-pq-hybrid.conf
@@ -1,23 +1,3 @@
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP256r1MLKEM512
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP256r1MLKEM512
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP384r1MLKEM768
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP384r1MLKEM768
-
# server TLSv1.3 with post-quantum hybrid group
-v 4
-l TLS13-AES256-GCM-SHA384
@@ -28,16 +8,6 @@
-l TLS13-AES256-GCM-SHA384
--pqc SecP256r1MLKEM768
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP521r1MLKEM1024
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc SecP521r1MLKEM1024
-
# server TLSv1.3 with post-quantum hybrid group
-v 4
-l TLS13-AES256-GCM-SHA384
@@ -48,16 +18,6 @@
-l TLS13-AES256-GCM-SHA384
--pqc SecP384r1MLKEM1024
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X25519MLKEM512
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X25519MLKEM512
-
# server TLSv1.3 with post-quantum hybrid group
-v 4
-l TLS13-AES256-GCM-SHA384
@@ -67,83 +27,3 @@
-v 4
-l TLS13-AES256-GCM-SHA384
--pqc X25519MLKEM768
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X448MLKEM768
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X448MLKEM768
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P256_KYBER_LEVEL1
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P256_KYBER_LEVEL1
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P384_KYBER_LEVEL3
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P384_KYBER_LEVEL3
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P256_KYBER_LEVEL3
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P256_KYBER_LEVEL3
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P521_KYBER_LEVEL5
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc P521_KYBER_LEVEL5
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X25519_KYBER_LEVEL1
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X25519_KYBER_LEVEL1
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X25519_KYBER_LEVEL3
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X25519_KYBER_LEVEL3
-
-# server TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X448_KYBER_LEVEL3
-
-# client TLSv1.3 with post-quantum hybrid group
--v 4
--l TLS13-AES256-GCM-SHA384
---pqc X448_KYBER_LEVEL3
diff --git a/tests/test-tls13-pq.conf b/tests/test-tls13-pq-standalone.conf
similarity index 100%
rename from tests/test-tls13-pq.conf
rename to tests/test-tls13-pq-standalone.conf
diff --git a/wolfssl/internal.h b/wolfssl/internal.h
index e40ded4e7d8..4e91e95e186 100644
--- a/wolfssl/internal.h
+++ b/wolfssl/internal.h
@@ -3425,6 +3425,7 @@ WOLFSSL_LOCAL int TLSX_UseSupportedCurve(TLSX** extensions, word16 name,
WOLFSSL_LOCAL int TLSX_UsePointFormat(TLSX** extensions, byte point,
void* heap);
+WOLFSSL_LOCAL int TLSX_IsGroupSupported(int namedGroup);
#ifndef NO_WOLFSSL_SERVER
WOLFSSL_LOCAL int TLSX_ValidateSupportedCurves(const WOLFSSL* ssl, byte first,
@@ -3675,6 +3676,8 @@ WOLFSSL_LOCAL int TLSX_KeyShare_Parse(WOLFSSL* ssl, const byte* input,
word16 length, byte msgType);
WOLFSSL_LOCAL int TLSX_KeyShare_Parse_ClientHello(const WOLFSSL* ssl,
const byte* input, word16 length, TLSX** extensions);
+WOLFSSL_LOCAL int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
+ KeyShareEntry* keyShareEntry, byte* data, word16 len);
#ifdef WOLFSSL_DUAL_ALG_CERTS
WOLFSSL_LOCAL int TLSX_CKS_Parse(WOLFSSL* ssl, byte* input,
word16 length, TLSX** extensions);
diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h
index be31fa63abb..dd66a3d7e22 100644
--- a/wolfssl/wolfcrypt/settings.h
+++ b/wolfssl/wolfcrypt/settings.h
@@ -4558,6 +4558,13 @@ extern void uITRON4_free(void *p) ;
#error "WOLFSSL_DTLS_CH_FRAG only works with DTLS 1.3"
#endif
+#if defined(HAVE_PQC) && defined(WOLFSSL_HAVE_MLKEM) && \
+ !defined(WOLFSSL_NO_ML_KEM) && !defined(WOLFSSL_PQC_HYBRIDS) && \
+ defined(WOLFSSL_TLS_NO_MLKEM_STANDALONE) && !defined(WOLFCRYPT_ONLY)
+#error "Neither PQ/T hybrid combinations nor ML-KEM as standalone TLS key " \
+ "exchange are enabled"
+#endif
+
/* SRTP requires DTLS */
#if defined(WOLFSSL_SRTP) && !defined(WOLFSSL_DTLS)
#error The SRTP extension requires DTLS
diff --git a/zephyr/Kconfig b/zephyr/Kconfig
index 0de97943cb9..ff05e74d23b 100644
--- a/zephyr/Kconfig
+++ b/zephyr/Kconfig
@@ -85,6 +85,11 @@ config WOLFSSL_PSK
help
Enable PSK support
+config WOLFSSL_MLKEM
+ bool "wolfSSL PQC ML-KEM support"
+ help
+ Enable PQC ML-KEM support for Key Exchange
+
config WOLFSSL_MAX_FRAGMENT_LEN
int
default 3
diff --git a/zephyr/samples/wolfssl_tls_sock/prj.conf b/zephyr/samples/wolfssl_tls_sock/prj.conf
index a51becba375..e48f28362ca 100644
--- a/zephyr/samples/wolfssl_tls_sock/prj.conf
+++ b/zephyr/samples/wolfssl_tls_sock/prj.conf
@@ -45,3 +45,4 @@ CONFIG_WOLFSSL_KEY_EXCHANGE_ALL_ENABLED=y
CONFIG_WOLFSSL_CIPHER_ALL_ENABLED=y
CONFIG_WOLFSSL_MAC_ALL_ENABLED=y
CONFIG_WOLFSSL_HMAC_DRBG_ENABLED=y
+CONFIG_WOLFSSL_MLKEM=y
diff --git a/zephyr/samples/wolfssl_tls_thread/prj.conf b/zephyr/samples/wolfssl_tls_thread/prj.conf
index 6fb19d3aa9f..b2b48c98c15 100644
--- a/zephyr/samples/wolfssl_tls_thread/prj.conf
+++ b/zephyr/samples/wolfssl_tls_thread/prj.conf
@@ -35,3 +35,4 @@ CONFIG_WOLFSSL_KEY_EXCHANGE_ALL_ENABLED=y
CONFIG_WOLFSSL_CIPHER_ALL_ENABLED=y
CONFIG_WOLFSSL_MAC_ALL_ENABLED=y
CONFIG_WOLFSSL_HMAC_DRBG_ENABLED=y
+CONFIG_WOLFSSL_MLKEM=y
diff --git a/zephyr/user_settings.h b/zephyr/user_settings.h
index 6f2606bdbf3..cc333bdaaa7 100644
--- a/zephyr/user_settings.h
+++ b/zephyr/user_settings.h
@@ -333,9 +333,21 @@ extern "C" {
#define NO_MD4
#define NO_MD5
//#define NO_DES3 /* Necessary for pkcs12 tests */
-#define WOLFSSL_NO_SHAKE128
-#define WOLFSSL_NO_SHAKE256
+/* PQC ML-KEM */
+#if defined(CONFIG_WOLFSSL_MLKEM)
+ #define WOLFSSL_HAVE_MLKEM
+ #define WOLFSSL_WC_MLKEM
+ #define WOLFSSL_MLKEM_NO_LARGE_CODE
+ #define WOLFSSL_MLKEM_SMALL
+ #define WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM
+ #define WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM
+ #define WOLFSSL_SHAKE128
+ #define WOLFSSL_SHAKE256
+#else
+ #define WOLFSSL_NO_SHAKE128
+ #define WOLFSSL_NO_SHAKE256
+#endif
/* ------------------------------------------------------------------------- */