Skip to content

Commit 7a7ba81

Browse files
committed
Add RFC8773bis cert_with_extern_psk support
Implement RFC8773bis (draft-ietf-tls-8773bis-13) cert_with_extern_psk for TLS 1.3, including protocol checks and API support. Includes unit tests for API and handshake behavior as well as tests in the testsuite using extended examples.
1 parent 73bea90 commit 7a7ba81

19 files changed

Lines changed: 914 additions & 53 deletions

File tree

.github/workflows/cmake.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ jobs:
7373
-DWOLFSSL_X963KDF:BOOL=yes -DWOLFSSL_DILITHIUM:BOOL=yes -DWOLFSSL_PKCS11:BOOL=yes \
7474
-DWOLFSSL_ECCSI:BOOL=yes -DWOLFSSL_SAKKE:BOOL=yes -DWOLFSSL_SIPHASH:BOOL=yes \
7575
-DWOLFSSL_WC_RSA_DIRECT:BOOL=yes -DWOLFSSL_PUBLIC_MP:BOOL=yes \
76+
-DWOLFSSL_CERT_WITH_EXTERN_PSK:BOOL=yes \
7677
-DWOLFSSL_EXTRA_PQC_HYBRIDS:BOOL=yes -DWOLFSSL_TLS_NO_MLKEM_STANDALONE:BOOL=no \
7778
..
7879
cmake --build .

.github/workflows/psk.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ jobs:
1818
matrix:
1919
config: [
2020
# Add new configs here
21+
'--enable-psk --enable-cert-with-extern-psk --disable-mlkem',
2122
'--enable-psk --disable-mlkem C_EXTRA_FLAGS="-DWOLFSSL_STATIC_PSK -DWOLFSSL_OLDTLS_SHA2_CIPHERSUITES"',
2223
'--enable-psk --disable-mlkem C_EXTRA_FLAGS=-DWOLFSSL_STATIC_PSK --disable-rsa --disable-ecc --disable-dh',
2324
'--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',

CMakeLists.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,24 @@ if(WOLFSSL_POSTAUTH)
376376
endif()
377377
endif()
378378

379+
# Certificate Authentication with External PSK (RFC 8773bis)
380+
add_option("WOLFSSL_CERT_WITH_EXTERN_PSK"
381+
"Enable Certificate Authentication with External PSKs for TLS 1.3 (default: disabled)"
382+
"no" "yes;no")
383+
384+
if(WOLFSSL_CERT_WITH_EXTERN_PSK)
385+
if(NOT WOLFSSL_TLS13)
386+
message(WARNING "TLS 1.3 is disabled - disabling cert-with-extern-psk")
387+
override_cache(WOLFSSL_CERT_WITH_EXTERN_PSK "no")
388+
elseif(NOT WOLFSSL_PSK)
389+
message(WARNING "PSK is disabled - disabling cert-with-extern-psk")
390+
override_cache(WOLFSSL_CERT_WITH_EXTERN_PSK "no")
391+
else()
392+
list(APPEND WOLFSSL_DEFINITIONS
393+
"-DWOLFSSL_CERT_WITH_EXTERN_PSK")
394+
endif()
395+
endif()
396+
379397
# Hello Retry Request Cookie
380398
add_option("WOLFSSL_HRR_COOKIE"
381399
"Enable the server to send Cookie Extension in HRR with state (default: disabled)"

cmake/options.h.in

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,8 @@ extern "C" {
308308
#cmakedefine WOLFSSL_DTLS13
309309
#undef WOLFSSL_DTLS_CH_FRAG
310310
#cmakedefine WOLFSSL_DTLS_CH_FRAG
311+
#undef WOLFSSL_CERT_WITH_EXTERN_PSK
312+
#cmakedefine WOLFSSL_CERT_WITH_EXTERN_PSK
311313
#undef WOLFSSL_EITHER_SIDE
312314
#cmakedefine WOLFSSL_EITHER_SIDE
313315
#undef WOLFSSL_ENCRYPTED_KEYS
@@ -427,4 +429,3 @@ extern "C" {
427429

428430

429431
#endif /* WOLFSSL_OPTIONS_H */
430-

configure.ac

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5142,6 +5142,27 @@ then
51425142
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_PSK_ONE_ID"
51435143
fi
51445144

5145+
# Certificate Authentication with External PSK (RFC 8773bis)
5146+
AC_ARG_ENABLE([cert-with-extern-psk],
5147+
[AS_HELP_STRING([--enable-cert-with-extern-psk],[Enable Certificate Authentication with External PSKs for TLS 1.3 (default: disabled)])],
5148+
[ ENABLED_CERT_WITH_EXTERN_PSK=$enableval ],
5149+
[ ENABLED_CERT_WITH_EXTERN_PSK=no ]
5150+
)
5151+
if test "$ENABLED_CERT_WITH_EXTERN_PSK" = "yes"
5152+
then
5153+
if test "$ENABLED_TLS13" = "no"
5154+
then
5155+
AC_MSG_NOTICE([TLS 1.3 is disabled - disabling cert-with-extern-psk])
5156+
ENABLED_CERT_WITH_EXTERN_PSK="no"
5157+
elif test "$ENABLED_PSK" = "no"
5158+
then
5159+
AC_MSG_NOTICE([PSK is disabled - disabling cert-with-extern-psk])
5160+
ENABLED_CERT_WITH_EXTERN_PSK="no"
5161+
else
5162+
AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_CERT_WITH_EXTERN_PSK"
5163+
fi
5164+
fi
5165+
51455166
# ERROR STRINGS
51465167
AC_ARG_ENABLE([errorstrings],
51475168
[AS_HELP_STRING([--enable-errorstrings],[Enable error strings table (default: enabled)])],

doc/dox_comments/header_files/ssl.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14721,6 +14721,75 @@ void wolfSSL_CTX_set_psk_server_tls13_callback(WOLFSSL_CTX* ctx,
1472114721
void wolfSSL_set_psk_server_tls13_callback(WOLFSSL* ssl,
1472214722
wc_psk_server_tls13_callback cb);
1472314723

14724+
/*!
14725+
\ingroup Setup
14726+
14727+
\brief Enable or disable TLS 1.3 certificate authentication with external
14728+
PSK (RFC8773bis) on a context.
14729+
14730+
When enabled, wolfSSL advertises and accepts the
14731+
`tls_cert_with_extern_psk` extension for TLS 1.3 handshakes using external
14732+
PSKs. Any non-zero \p state value enables the feature and zero disables it.
14733+
14734+
Availability:
14735+
- Built with `--enable-tls13 --enable-psk --enable-cert-with-extern-psk`
14736+
- Or with `WOLFSSL_TLS13` and `WOLFSSL_CERT_WITH_EXTERN_PSK` defined
14737+
14738+
\param [in,out] ctx a pointer to a WOLFSSL_CTX structure, created with
14739+
wolfSSL_CTX_new().
14740+
\param [in] state 0 to disable, non-zero to enable.
14741+
14742+
\return WOLFSSL_SUCCESS on success.
14743+
\return WOLFSSL_FAILURE when \p ctx is NULL.
14744+
14745+
_Example_
14746+
\code
14747+
WOLFSSL_CTX* ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
14748+
if (wolfSSL_CTX_set_cert_with_extern_psk(ctx, 1) != WOLFSSL_SUCCESS) {
14749+
/* handle error */
14750+
}
14751+
\endcode
14752+
14753+
\sa wolfSSL_set_cert_with_extern_psk
14754+
\sa wolfSSL_CTX_set_psk_client_tls13_callback
14755+
\sa wolfSSL_CTX_set_psk_server_tls13_callback
14756+
*/
14757+
int wolfSSL_CTX_set_cert_with_extern_psk(WOLFSSL_CTX* ctx, int state);
14758+
14759+
/*!
14760+
\ingroup Setup
14761+
14762+
\brief Enable or disable TLS 1.3 certificate authentication with external
14763+
PSK (RFC8773bis) on a connection.
14764+
14765+
This call applies to a single WOLFSSL object. Any non-zero \p state value
14766+
enables the feature and zero disables it.
14767+
14768+
Availability:
14769+
- Built with `--enable-tls13 --enable-psk --enable-cert-with-extern-psk`
14770+
- Or with `WOLFSSL_TLS13` and `WOLFSSL_CERT_WITH_EXTERN_PSK` defined
14771+
14772+
\param [in,out] ssl a pointer to a WOLFSSL structure, created using
14773+
wolfSSL_new().
14774+
\param [in] state 0 to disable, non-zero to enable.
14775+
14776+
\return WOLFSSL_SUCCESS on success.
14777+
\return WOLFSSL_FAILURE when \p ssl is NULL.
14778+
14779+
_Example_
14780+
\code
14781+
WOLFSSL* ssl = wolfSSL_new(ctx);
14782+
if (wolfSSL_set_cert_with_extern_psk(ssl, 1) != WOLFSSL_SUCCESS) {
14783+
/* handle error */
14784+
}
14785+
\endcode
14786+
14787+
\sa wolfSSL_CTX_set_cert_with_extern_psk
14788+
\sa wolfSSL_set_psk_client_tls13_callback
14789+
\sa wolfSSL_set_psk_server_tls13_callback
14790+
*/
14791+
int wolfSSL_set_cert_with_extern_psk(WOLFSSL* ssl, int state);
14792+
1472414793
/*!
1472514794
\ingroup Setup
1472614795

examples/client/client.c

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,7 @@ static int ClientWriteRead(WOLFSSL* ssl, const char* msg, int msgSz,
12091209
/* 4. add the same message into Japanese section */
12101210
/* (will be translated later) */
12111211
/* 5. add printf() into suitable position of Usage() */
1212-
static const char* client_usage_msg[][80] = {
1212+
static const char* client_usage_msg[][81] = {
12131213
/* English */
12141214
{
12151215
" NOTE: All files relative to wolfSSL home dir\n", /* 0 */
@@ -1454,24 +1454,28 @@ static const char* client_usage_msg[][80] = {
14541454
#ifndef NO_PSK
14551455
"--openssl-psk Use TLS 1.3 PSK callback compatible with OpenSSL\n", /* 73 */
14561456
#endif
1457+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
1458+
!defined(NO_PSK)
1459+
"--psk-with-certs Use TLS 1.3 PSK with certificates\n", /* 74 */
1460+
#endif
14571461
#ifdef HAVE_RPK
1458-
"--rpk Use RPK for the defined certificates\n", /* 74 */
1462+
"--rpk Use RPK for the defined certificates\n", /* 75 */
14591463
#endif
1460-
"--files-are-der Specified files are in DER, not PEM format\n", /* 75 */
1464+
"--files-are-der Specified files are in DER, not PEM format\n", /* 76 */
14611465
#ifdef WOLFSSL_SYS_CRYPTO_POLICY
1462-
"--crypto-policy <path to crypto policy file>\n", /* 76 */
1466+
"--crypto-policy <path to crypto policy file>\n", /* 77 */
14631467
#endif
14641468
#ifdef HAVE_ECC_BRAINPOOL
1465-
"--bpKs Use Brainpool ECC group for key share\n", /* 77 */
1469+
"--bpKs Use Brainpool ECC group for key share\n", /* 78 */
14661470
#endif
14671471
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
14681472
"--ech <base64> Use Encrypted Client Hello with base64 encoded "
14691473
"ECH configs\n",
1470-
/* 78 */
1474+
/* 79 */
14711475
#endif
14721476
"\n"
14731477
"For simpler wolfSSL TLS client examples, visit\n"
1474-
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 79 */
1478+
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 80 */
14751479
NULL,
14761480
},
14771481
#ifndef NO_MULTIBYTE_PRINT
@@ -1720,20 +1724,24 @@ static const char* client_usage_msg[][80] = {
17201724
#ifndef NO_PSK
17211725
"--openssl-psk Use TLS 1.3 PSK callback compatible with OpenSSL\n", /* 73 */
17221726
#endif
1727+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
1728+
!defined(NO_PSK)
1729+
"--psk-with-certs Use TLS 1.3 PSK with certificates\n", /* 74 */
1730+
#endif
17231731
#ifdef HAVE_RPK
1724-
"--rpk Use RPK for the defined certificates\n", /* 74 */
1732+
"--rpk Use RPK for the defined certificates\n", /* 75 */
17251733
#endif
1726-
"--files-are-der Specified files are in DER, not PEM format\n", /* 75 */
1734+
"--files-are-der Specified files are in DER, not PEM format\n", /* 76 */
17271735
#ifdef WOLFSSL_SYS_CRYPTO_POLICY
1728-
"--crypto-policy <path to crypto policy file>\n", /* 76 */
1736+
"--crypto-policy <path to crypto policy file>\n", /* 77 */
17291737
#endif
17301738
#ifdef HAVE_ECC_BRAINPOOL
1731-
"--bpKs Use Brainpool ECC group for key share\n", /* 77 */
1739+
"--bpKs Use Brainpool ECC group for key share\n", /* 78 */
17321740
#endif
17331741
"\n"
17341742
"より簡単なwolfSSL TLS クライアントの例については"
17351743
"下記にアクセスしてください\n"
1736-
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 78 */
1744+
"https://github.com/wolfSSL/wolfssl-examples/tree/master/tls\n", /* 79 */
17371745
NULL,
17381746
},
17391747
#endif
@@ -1969,6 +1977,10 @@ static void Usage(void)
19691977
#ifndef NO_PSK
19701978
printf("%s", msg[++msgid]); /* --openssl-psk */
19711979
#endif
1980+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
1981+
!defined(NO_PSK)
1982+
printf("%s", msg[++msgid]); /* --psk-with-certs */
1983+
#endif
19721984
#ifdef HAVE_RPK
19731985
printf("%s", msg[++msgid]); /* --rpk */
19741986
#endif
@@ -2168,6 +2180,10 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
21682180
#endif
21692181
#if defined(WOLFSSL_TLS13) && defined(HAVE_ECH)
21702182
{ "ech", 1, 271 },
2183+
#endif
2184+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
2185+
!defined(NO_PSK)
2186+
{ "psk-with-certs", 0, 272 },
21712187
#endif
21722188
{ 0, 0, 0 }
21732189
};
@@ -2176,6 +2192,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
21762192
int minVersion = CLIENT_INVALID_VERSION;
21772193
int usePsk = 0;
21782194
int opensslPsk = 0;
2195+
int usePskWithCerts = 0;
21792196
int useAnon = 0;
21802197
int sendGET = 0;
21812198
int benchmark = 0;
@@ -2415,6 +2432,7 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
24152432
(void)pqcAlg;
24162433
(void)opensslPsk;
24172434
(void)fileFormat;
2435+
(void)usePskWithCerts;
24182436
StackTrap();
24192437

24202438
/* Reinitialize the global myVerifyAction. */
@@ -3070,6 +3088,12 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
30703088
echConfigs64 = myoptarg;
30713089
break;
30723090
#endif
3091+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
3092+
!defined(NO_PSK)
3093+
case 272:
3094+
usePskWithCerts = 1;
3095+
break;
3096+
#endif
30733097

30743098
default:
30753099
Usage();
@@ -3080,6 +3104,18 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
30803104
myoptind = 0; /* reset for test cases */
30813105
#endif /* !WOLFSSL_VXWORKS */
30823106

3107+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && \
3108+
!defined(NO_PSK)
3109+
if (usePskWithCerts) {
3110+
usePsk = 1;
3111+
if (noPskDheKe) {
3112+
LOG_ERROR("--psk-with-certs requires PSK key exchange with (EC)DHE");
3113+
Usage();
3114+
XEXIT_T(MY_EX_USAGE);
3115+
}
3116+
}
3117+
#endif
3118+
30833119
if (externalTest) {
30843120
/* detect build cases that wouldn't allow test against wolfssl.com */
30853121
int done = 0;
@@ -3486,6 +3522,14 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
34863522
wolfSSL_CTX_set_psk_client_tls13_callback(ctx,
34873523
my_psk_client_tls13_cb);
34883524
}
3525+
#if defined(WOLFSSL_CERT_WITH_EXTERN_PSK)
3526+
if (usePskWithCerts) {
3527+
if (wolfSSL_CTX_set_cert_with_extern_psk(ctx, 1) != WOLFSSL_SUCCESS) {
3528+
wolfSSL_CTX_free(ctx); ctx = NULL;
3529+
err_sys("client can't enable cert_with_extern_psk");
3530+
}
3531+
}
3532+
#endif
34893533
#endif
34903534
if (defaultCipherList == NULL) {
34913535
#if defined(HAVE_AESGCM) && !defined(NO_DH)
@@ -3637,7 +3681,8 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
36373681
#endif
36383682
}
36393683

3640-
if (!usePsk && !useAnon && !useVerifyCb && myVerifyAction != VERIFY_FORCE_FAIL) {
3684+
if ((!usePsk || usePskWithCerts) && !useAnon && !useVerifyCb &&
3685+
myVerifyAction != VERIFY_FORCE_FAIL) {
36413686
#if defined(OPENSSL_ALL) && defined(WOLFSSL_CERT_GEN) && \
36423687
(defined(WOLFSSL_CERT_REQ) || defined(WOLFSSL_CERT_EXT)) && \
36433688
!defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR)
@@ -3721,10 +3766,11 @@ THREAD_RETURN WOLFSSL_THREAD client_test(void* args)
37213766
myVerifyAction == VERIFY_USE_PREVERIFY) {
37223767
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, myVerify);
37233768
}
3724-
else if (!usePsk && !useAnon && doPeerCheck == 0) {
3769+
else if ((!usePsk || usePskWithCerts) && !useAnon && doPeerCheck == 0) {
37253770
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_NONE, NULL);
37263771
}
3727-
else if (!usePsk && !useAnon && myVerifyAction == VERIFY_OVERRIDE_DATE_ERR) {
3772+
else if ((!usePsk || usePskWithCerts) && !useAnon &&
3773+
myVerifyAction == VERIFY_OVERRIDE_DATE_ERR) {
37283774
wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, myVerify);
37293775
}
37303776
#endif /* !NO_CERTS */

0 commit comments

Comments
 (0)