Skip to content

Commit 76b1300

Browse files
committed
ML-KEM fixes
* DTLS 1.3 cookie and CH frag handling * static memory handling * Fix memory leak in TLS server PQC handling in case of ECH * Make sure hybrids are actually tested in testsuite
1 parent b5c5327 commit 76b1300

9 files changed

Lines changed: 207 additions & 49 deletions

File tree

examples/client/client.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,18 @@ static void SetKeyShare(WOLFSSL* ssl, int onlyKeyShare, int useX25519,
557557
else {
558558
err_sys("unable to use post-quantum KEM");
559559
}
560+
561+
#ifdef WOLFSSL_DTLS13
562+
if (wolfSSL_dtls(ssl)) {
563+
/* When the KeyShare is too large for an unfragmented
564+
* ClientHello, DTLS sends an empty KeyShare extension to
565+
* use the Hello Retry Request to enable fragmentation.
566+
* In order to enforce our desired PQC algorithm in the
567+
* second ClientHello, we need to set it as the only one
568+
* allowed in the SupportedGroups extension. */
569+
setGroups = 1;
570+
}
571+
#endif /* WOLFSSL_DTLS13 */
560572
}
561573
}
562574
#endif
@@ -2299,8 +2311,8 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
22992311

23002312

23012313
#ifdef WOLFSSL_STATIC_MEMORY
2302-
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \
2303-
|| defined(SESSION_CERTS)
2314+
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) || \
2315+
defined(SESSION_CERTS) || defined(WOLFSSL_HAVE_MLKEM)
23042316
/* big enough to handle most cases including session certs */
23052317
byte memory[320000];
23062318
#else

examples/server/server.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,8 +1763,8 @@ THREAD_RETURN WOLFSSL_THREAD server_test(void* args)
17631763
/* Note: Actual memory used is much less, this is the entire buffer buckets,
17641764
* which is partitioned into pools of common sizes. To adjust the buckets
17651765
* sizes see WOLFMEM_BUCKETS in memory.h */
1766-
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) \
1767-
|| defined(SESSION_CERTS)
1766+
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) || \
1767+
defined(SESSION_CERTS) || defined(WOLFSSL_HAVE_MLKEM)
17681768
/* big enough to handle most cases including session certs */
17691769
#if !defined(WOLFSSL_NO_CLIENT_AUTH) && \
17701770
((defined(HAVE_ED25519) && !defined(NO_ED25519_CLIENT_AUTH)) || \

src/internal.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,26 @@ int InitSSL_Side(WOLFSSL* ssl, word16 side)
22512251
WOLFSSL_MSG("DTLS Cookie Secret error");
22522252
return ret;
22532253
}
2254+
#if defined(WOLFSSL_DTLS13)
2255+
if (IsAtLeastTLSv1_3(ssl->version)) {
2256+
#if defined(WOLFSSL_SEND_HRR_COOKIE)
2257+
ret = wolfSSL_send_hrr_cookie(ssl, NULL, 0);
2258+
if (ret != WOLFSSL_SUCCESS) {
2259+
WOLFSSL_MSG("DTLS1.3 Cookie secret error");
2260+
return ret;
2261+
}
2262+
#endif /* WOLFSSL_SEND_HRR_COOKIE */
2263+
#if defined(WOLFSSL_DTLS_CH_FRAG) && defined(WOLFSSL_HAVE_MLKEM)
2264+
/* Allow fragmentation of the second ClientHello due to the
2265+
* large PQC key share. */
2266+
ret = wolfSSL_dtls13_allow_ch_frag(ssl, 1);
2267+
if (ret != WOLFSSL_SUCCESS) {
2268+
WOLFSSL_MSG("DTLS1.3 CH frag error");
2269+
return ret;
2270+
}
2271+
#endif /* WOLFSSL_DTLS_CH_FRAG && WOLFSSL_HAVE_MLKEM */
2272+
}
2273+
#endif /* WOLFSSL_DTLS13 */
22542274
}
22552275
#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */
22562276

@@ -8006,15 +8026,26 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
80068026
WOLFSSL_MSG("DTLS Cookie Secret error");
80078027
return ret;
80088028
}
8009-
#if defined(WOLFSSL_DTLS13) && defined(WOLFSSL_SEND_HRR_COOKIE)
8029+
#if defined(WOLFSSL_DTLS13)
80108030
if (IsAtLeastTLSv1_3(ssl->version)) {
8031+
#if defined(WOLFSSL_SEND_HRR_COOKIE)
80118032
ret = wolfSSL_send_hrr_cookie(ssl, NULL, 0);
80128033
if (ret != WOLFSSL_SUCCESS) {
80138034
WOLFSSL_MSG("DTLS1.3 Cookie secret error");
80148035
return ret;
80158036
}
8037+
#endif /* WOLFSSL_SEND_HRR_COOKIE */
8038+
#if defined(WOLFSSL_DTLS_CH_FRAG) && defined(WOLFSSL_HAVE_MLKEM)
8039+
/* Allow fragmentation of the second ClientHello due to the
8040+
* large PQC key share. */
8041+
ret = wolfSSL_dtls13_allow_ch_frag(ssl, 1);
8042+
if (ret != WOLFSSL_SUCCESS) {
8043+
WOLFSSL_MSG("DTLS1.3 CH frag error");
8044+
return ret;
8045+
}
8046+
#endif /* WOLFSSL_DTLS_CH_FRAG && WOLFSSL_HAVE_MLKEM */
80168047
}
8017-
#endif /* WOLFSSL_DTLS13 && WOLFSSL_SEND_HRR_COOKIE */
8048+
#endif /* WOLFSSL_DTLS13 */
80188049
}
80198050
#endif /* WOLFSSL_DTLS && !NO_WOLFSSL_SERVER */
80208051

src/tls.c

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10534,6 +10534,7 @@ static int TLSX_KeyShare_HandlePqcKeyServer(WOLFSSL* ssl,
1053410534
keyShareEntry->ke = NULL;
1053510535
keyShareEntry->keLen = 0;
1053610536

10537+
XFREE(keyShareEntry->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
1053710538
keyShareEntry->pubKey = ciphertext;
1053810539
keyShareEntry->pubKeyLen = ctSz;
1053910540
ciphertext = NULL;
@@ -10770,6 +10771,7 @@ static int TLSX_KeyShare_HandlePqcHybridKeyServer(WOLFSSL* ssl,
1077010771
XMEMCPY(ciphertext + ecc_kse->pubKeyLen, pqc_kse->pubKey, ctSz);
1077110772
}
1077210773

10774+
XFREE(keyShareEntry->pubKey, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
1077310775
keyShareEntry->pubKey = ciphertext;
1077410776
keyShareEntry->pubKeyLen = ecc_kse->pubKeyLen + ctSz;
1077510777
ciphertext = NULL;
@@ -10859,13 +10861,20 @@ int TLSX_KeyShare_Use(const WOLFSSL* ssl, word16 group, word16 len, byte* data,
1085910861
#if defined(WOLFSSL_HAVE_MLKEM) && !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE)
1086010862
if (ssl->options.side == WOLFSSL_SERVER_END &&
1086110863
WOLFSSL_NAMED_GROUP_IS_PQC(group)) {
10862-
ret = TLSX_KeyShare_HandlePqcKeyServer((WOLFSSL*)ssl,
10863-
keyShareEntry,
10864-
data, len,
10865-
ssl->arrays->preMasterSecret,
10866-
&ssl->arrays->preMasterSz);
10867-
if (ret != 0)
10868-
return ret;
10864+
if (TLSX_IsGroupSupported(group)) {
10865+
ret = TLSX_KeyShare_HandlePqcKeyServer((WOLFSSL*)ssl,
10866+
keyShareEntry,
10867+
data, len,
10868+
ssl->arrays->preMasterSecret,
10869+
&ssl->arrays->preMasterSz);
10870+
if (ret != 0)
10871+
return ret;
10872+
}
10873+
else {
10874+
XFREE(keyShareEntry->ke, ssl->heap, DYNAMIC_TYPE_PUBLIC_KEY);
10875+
keyShareEntry->ke = NULL;
10876+
keyShareEntry->keLen = 0;
10877+
}
1086910878
}
1087010879
else if (ssl->options.side == WOLFSSL_SERVER_END &&
1087110880
WOLFSSL_NAMED_GROUP_IS_PQC_HYBRID(group)) {

tests/api.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@
259259
#endif
260260

261261
#if defined(WOLFSSL_STATIC_MEMORY) && !defined(WOLFCRYPT_ONLY)
262-
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) || defined(SESSION_CERTS)
262+
#if (defined(HAVE_ECC) && !defined(ALT_ECC_SIZE)) || \
263+
defined(SESSION_CERTS) || defined(WOLFSSL_HAVE_MLKEM)
263264
#ifdef OPENSSL_EXTRA
264265
#define TEST_TLS_STATIC_MEMSZ (400000)
265266
#else
@@ -32014,7 +32015,7 @@ static int test_dtls13_frag_ch_pq(void)
3201432015
{
3201532016
EXPECT_DECLS;
3201632017
#if defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && defined(WOLFSSL_DTLS13) \
32017-
&& defined(WOLFSSL_DTLS_CH_FRAG) && defined(HAVE_LIBOQS)
32018+
&& defined(WOLFSSL_DTLS_CH_FRAG) && defined(WOLFSSL_HAVE_MLKEM)
3201832019
WOLFSSL_CTX *ctx_c = NULL;
3201932020
WOLFSSL_CTX *ctx_s = NULL;
3202032021
WOLFSSL *ssl_c = NULL;

tests/suites.c

Lines changed: 116 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -169,57 +169,151 @@ static int IsValidCipherSuite(const char* line, char *suite, size_t suite_spc)
169169
}
170170

171171
#if defined(WOLFSSL_HAVE_MLKEM)
172+
173+
#define MATCH_PQC(b, s, l) ((l) == sizeof(s) - 1 && \
174+
XSTRNCMP((b), (s), sizeof(s) - 1) == 0)
175+
172176
static int IsKyberLevelAvailable(const char* line)
173177
{
174178
int available = 0;
175-
const char* find = "--pqc ";
176-
const char* begin = strstr(line, find);
177-
const char* end;
179+
const char* begin = XSTRSTR(line, "--pqc");
180+
size_t len = 0;
178181

179182
if (begin != NULL) {
180-
begin += 6;
181-
end = XSTRSTR(begin, " ");
183+
begin += XSTRLEN("--pqc");
184+
while (*begin == ' ' || *begin == '\t') {
185+
begin++;
186+
}
182187

183-
#ifndef WOLFSSL_NO_ML_KEM
184-
if ((size_t)end - (size_t)begin == 10) {
188+
if (*begin != '\0') {
189+
const char* end = begin;
190+
while (*end != '\0' && *end != ' ' && *end != '\t') {
191+
end++;
192+
}
193+
len = (size_t)(end - begin);
194+
}
195+
}
196+
197+
if (begin != NULL && len > 0) {
198+
#ifndef WOLFSSL_NO_ML_KEM
185199
#ifndef WOLFSSL_NO_ML_KEM_512
186-
if (XSTRNCMP(begin, "ML_KEM_512", 10) == 0) {
200+
if (MATCH_PQC(begin, "ML_KEM_512", len)) {
187201
available = 1;
188202
}
189203
#endif
190204
#ifndef WOLFSSL_NO_ML_KEM_768
191-
if (XSTRNCMP(begin, "ML_KEM_768", 10) == 0) {
205+
if (MATCH_PQC(begin, "ML_KEM_768", len)) {
192206
available = 1;
193207
}
194208
#endif
195-
}
196209
#ifndef WOLFSSL_NO_ML_KEM_1024
197-
if ((size_t)end - (size_t)begin == 11) {
198-
if (XSTRNCMP(begin, "ML_KEM_1024", 11) == 0) {
210+
if (MATCH_PQC(begin, "ML_KEM_1024", len)) {
199211
available = 1;
200212
}
201-
}
202213
#endif
203-
#endif
204-
#ifdef WOLFSSL_MLKEM_KYBER
205-
if ((size_t)end - (size_t)begin == 12) {
214+
215+
#if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_ECC)
216+
if (MATCH_PQC(begin, "SecP256r1MLKEM512", len)) {
217+
available = 1;
218+
}
219+
#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
220+
if (MATCH_PQC(begin, "P256_ML_KEM_512_OLD", len)) {
221+
available = 1;
222+
}
223+
#endif
224+
#endif
225+
#if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_ECC)
226+
if (MATCH_PQC(begin, "SecP384r1MLKEM768", len)) {
227+
available = 1;
228+
}
229+
if (MATCH_PQC(begin, "SecP256r1MLKEM768", len)) {
230+
available = 1;
231+
}
232+
#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
233+
if (MATCH_PQC(begin, "P384_ML_KEM_768_OLD", len)) {
234+
available = 1;
235+
}
236+
#endif
237+
#endif
238+
#if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE25519)
239+
if (MATCH_PQC(begin, "X25519MLKEM768", len)) {
240+
available = 1;
241+
}
242+
#endif
243+
#if !defined(WOLFSSL_NO_ML_KEM_1024) && defined(HAVE_ECC)
244+
if (MATCH_PQC(begin, "SecP521r1MLKEM1024", len)) {
245+
available = 1;
246+
}
247+
if (MATCH_PQC(begin, "SecP384r1MLKEM1024", len)) {
248+
available = 1;
249+
}
250+
#ifdef WOLFSSL_ML_KEM_USE_OLD_IDS
251+
if (MATCH_PQC(begin, "P521_ML_KEM_1024_OLD", len)) {
252+
available = 1;
253+
}
254+
#endif
255+
#endif
256+
#if !defined(WOLFSSL_NO_ML_KEM_512) && defined(HAVE_CURVE25519)
257+
if (MATCH_PQC(begin, "X25519MLKEM512", len)) {
258+
available = 1;
259+
}
260+
#endif
261+
#if !defined(WOLFSSL_NO_ML_KEM_768) && defined(HAVE_CURVE448)
262+
if (MATCH_PQC(begin, "X448MLKEM768", len)) {
263+
available = 1;
264+
}
265+
#endif
266+
#endif /* !WOLFSSL_NO_ML_KEM */
267+
#ifdef WOLFSSL_MLKEM_KYBER
206268
#ifndef WOLFSSL_NO_KYBER512
207-
if (XSTRNCMP(begin, "KYBER_LEVEL1", 12) == 0) {
269+
if (MATCH_PQC(begin, "KYBER_LEVEL1", len)) {
270+
available = 1;
271+
}
272+
#ifdef HAVE_ECC
273+
if (MATCH_PQC(begin, "P256_KYBER_LEVEL1", len)) {
208274
available = 1;
209275
}
210276
#endif
277+
#endif
211278
#ifndef WOLFSSL_NO_KYBER768
212-
if (XSTRNCMP(begin, "KYBER_LEVEL3", 12) == 0) {
279+
if (MATCH_PQC(begin, "KYBER_LEVEL3", len)) {
280+
available = 1;
281+
}
282+
#ifdef HAVE_ECC
283+
if (MATCH_PQC(begin, "P384_KYBER_LEVEL3", len)) {
213284
available = 1;
214285
}
286+
if (MATCH_PQC(begin, "P256_KYBER_LEVEL3", len)) {
287+
available = 1;
288+
}
289+
#endif
215290
#endif
216291
#ifndef WOLFSSL_NO_KYBER1024
217-
if (XSTRNCMP(begin, "KYBER_LEVEL5", 12) == 0) {
292+
if (MATCH_PQC(begin, "KYBER_LEVEL5", len)) {
293+
available = 1;
294+
}
295+
#ifdef HAVE_ECC
296+
if (MATCH_PQC(begin, "P521_KYBER_LEVEL5", len)) {
218297
available = 1;
219298
}
220299
#endif
221-
}
222-
#endif
300+
#endif
301+
#if !defined(WOLFSSL_NO_KYBER512) && defined(HAVE_CURVE25519)
302+
if (MATCH_PQC(begin, "X25519_KYBER_LEVEL1", len)) {
303+
available = 1;
304+
}
305+
#endif
306+
#if !defined(WOLFSSL_NO_KYBER768) && defined(HAVE_CURVE25519)
307+
if (MATCH_PQC(begin, "X25519_KYBER_LEVEL3", len)) {
308+
available = 1;
309+
}
310+
#endif
311+
#if !defined(WOLFSSL_NO_KYBER768) && defined(HAVE_CURVE448)
312+
if (MATCH_PQC(begin, "X448_KYBER_LEVEL3", len)) {
313+
available = 1;
314+
}
315+
#endif
316+
#endif /* WOLFSSL_MLKEM_KYBER */
223317
}
224318

225319
#if defined(WOLFSSL_MLKEM_NO_MAKE_KEY) || \
@@ -910,7 +1004,7 @@ int SuiteTest(int argc, char** argv)
9101004
char* myArgv[3];
9111005

9121006
#ifdef WOLFSSL_STATIC_MEMORY
913-
byte memory[200000];
1007+
byte memory[320000];
9141008
#endif
9151009

9161010
printf(" Begin Cipher Suite Tests\n");

wolfssl/ssl.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4750,16 +4750,15 @@ enum {
47504750
WOLFSSL_P256_KYBER_LEVEL3 = 25498,
47514751
#endif /* WOLFSSL_MLKEM_KYBER */
47524752
#ifndef WOLFSSL_NO_ML_KEM
4753-
/* Taken from draft-connolly-tls-mlkem-key-agreement, see:
4754-
* https://github.com/dconnolly/draft-connolly-tls-mlkem-key-agreement/
4753+
/* Taken from draft-ietf-tls-mlkem, see:
4754+
* https://datatracker.ietf.org/doc/draft-ietf-tls-mlkem/
47554755
*/
47564756
WOLFSSL_ML_KEM_512 = 512,
47574757
WOLFSSL_ML_KEM_768 = 513,
47584758
WOLFSSL_ML_KEM_1024 = 514,
47594759

4760-
/* Taken from draft-kwiatkowski-tls-ecdhe-mlkem. see:
4761-
* https://github.com/post-quantum-cryptography/
4762-
* draft-kwiatkowski-tls-ecdhe-mlkem/
4760+
/* Taken from draft-ietf-tls-ecdhe-mlkem. see:
4761+
* https://datatracker.ietf.org/doc/draft-ietf-tls-ecdhe-mlkem/
47634762
*/
47644763
WOLFSSL_SECP256R1MLKEM768 = 4587,
47654764
WOLFSSL_X25519MLKEM768 = 4588,

0 commit comments

Comments
 (0)