Skip to content

Commit 0434139

Browse files
authored
Merge pull request #10186 from Frauschi/f-159
Error out in case of unknown extensions in response message in TLS 1.3
2 parents 3d4e929 + b0763ea commit 0434139

5 files changed

Lines changed: 121 additions & 14 deletions

File tree

src/tls.c

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7547,7 +7547,7 @@ int TLSX_Cookie_Use(const WOLFSSL* ssl, const byte* data, word16 len, byte* mac,
75477547

75487548
#else
75497549

7550-
#define CKE_FREE_ALL(a, b) 0
7550+
#define CKE_FREE_ALL(a, b) WC_DO_NOTHING
75517551
#define CKE_GET_SIZE(a, b, c) 0
75527552
#define CKE_WRITE(a, b, c, d) 0
75537553
#define CKE_PARSE(a, b, c, d) 0
@@ -14677,12 +14677,10 @@ void TLSX_FreeAll(TLSX* list, void* heap)
1467714677
WOLFSSL_MSG("Supported Versions extension free");
1467814678
break;
1467914679

14680-
#ifdef WOLFSSL_SEND_HRR_COOKIE
1468114680
case TLSX_COOKIE:
1468214681
WOLFSSL_MSG("Cookie extension free");
1468314682
CKE_FREE_ALL((Cookie*)extension->data, heap);
1468414683
break;
14685-
#endif
1468614684

1468714685
#ifdef WOLFSSL_EARLY_DATA
1468814686
case TLSX_EARLY_DATA:
@@ -14874,11 +14872,9 @@ static int TLSX_GetSize(TLSX* list, byte* semaphore, byte msgType,
1487414872
ret = SV_GET_SIZE(extension->data, msgType, &length);
1487514873
break;
1487614874

14877-
#ifdef WOLFSSL_SEND_HRR_COOKIE
1487814875
case TLSX_COOKIE:
1487914876
ret = CKE_GET_SIZE((Cookie*)extension->data, msgType, &length);
1488014877
break;
14881-
#endif
1488214878

1488314879
#ifdef WOLFSSL_EARLY_DATA
1488414880
case TLSX_EARLY_DATA:
@@ -15109,13 +15105,11 @@ static int TLSX_Write(TLSX* list, byte* output, byte* semaphore,
1510915105
&offset);
1511015106
break;
1511115107

15112-
#ifdef WOLFSSL_SEND_HRR_COOKIE
1511315108
case TLSX_COOKIE:
1511415109
WOLFSSL_MSG("Cookie extension to write");
1511515110
ret = CKE_WRITE((Cookie*)extension->data, output + offset,
1511615111
msgType, &offset);
1511715112
break;
15118-
#endif
1511915113

1512015114
#ifdef WOLFSSL_EARLY_DATA
1512115115
case TLSX_EARLY_DATA:
@@ -17416,8 +17410,6 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
1741617410

1741717411
break;
1741817412

17419-
17420-
#ifdef WOLFSSL_SEND_HRR_COOKIE
1742117413
case TLSX_COOKIE:
1742217414
WOLFSSL_MSG("Cookie extension received");
1742317415
#ifdef WOLFSSL_DEBUG_TLS
@@ -17433,7 +17425,6 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
1743317425

1743417426
ret = CKE_PARSE(ssl, input + offset, size, msgType);
1743517427
break;
17436-
#endif
1743717428

1743817429
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
1743917430
case TLSX_PRE_SHARED_KEY:
@@ -17673,6 +17664,29 @@ int TLSX_Parse(WOLFSSL* ssl, const byte* input, word16 length, byte msgType,
1767317664
#endif
1767417665
default:
1767517666
WOLFSSL_MSG("Unknown TLS extension type");
17667+
#if defined(WOLFSSL_TLS13)
17668+
/* RFC 8446 Sec. 4.2: a TLS 1.3 client MUST abort with an
17669+
* unsupported_extension alert when it receives an extension
17670+
* "response" that was not advertised in the ClientHello. The
17671+
* rule applies only to messages whose extensions are responses
17672+
* to the ClientHello: ServerHello, HelloRetryRequest,
17673+
* EncryptedExtensions and Certificate.
17674+
*
17675+
* Extensions in CertificateRequest and NewSessionTicket are
17676+
* independent server-initiated payloads, not responses, and
17677+
* per RFC 8701 (GREASE) the server MAY include unknown
17678+
* (GREASE) extension types there which the client MUST treat
17679+
* like any other unknown value (i.e. ignore them). */
17680+
if (IsAtLeastTLSv1_3(ssl->version) &&
17681+
(msgType == server_hello ||
17682+
msgType == hello_retry_request ||
17683+
msgType == encrypted_extensions ||
17684+
msgType == certificate)) {
17685+
SendAlert((WOLFSSL*)ssl, alert_fatal, unsupported_extension);
17686+
WOLFSSL_ERROR_VERBOSE(UNSUPPORTED_EXTENSION);
17687+
return UNSUPPORTED_EXTENSION;
17688+
}
17689+
#endif
1767617690
}
1767717691

1767817692
/* offset should be updated here! */

tests/api.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31596,7 +31596,8 @@ static int test_TLSX_CA_NAMES_bad_extension(void)
3159631596

3159731597
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
3159831598
#ifndef WOLFSSL_DISABLE_EARLY_SANITY_CHECKS
31599-
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WC_NO_ERR_TRACE(EXT_MISSING));
31599+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
31600+
WC_NO_ERR_TRACE(UNSUPPORTED_EXTENSION));
3160031601
#else
3160131602
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WC_NO_ERR_TRACE(BUFFER_ERROR));
3160231603
#endif

tests/api/test_tls13.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3352,6 +3352,98 @@ int test_tls13_warning_alert_is_fatal(void)
33523352
return EXPECT_RESULT();
33533353
}
33543354

3355+
/* Test that an unknown extension in a TLS 1.3 server-to-client message is
3356+
* rejected with unsupported_extension (RFC 8446 Sec. 4.2). The client MUST
3357+
* abort the handshake when it receives an extension it did not advertise.
3358+
*/
3359+
int test_tls13_unknown_ext_rejected(void)
3360+
{
3361+
EXPECT_DECLS;
3362+
#if defined(WOLFSSL_TLS13) && defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
3363+
!defined(NO_WOLFSSL_CLIENT) && defined(WOLFSSL_AES_128) && \
3364+
defined(HAVE_AESGCM) && !defined(NO_SHA256) && \
3365+
!defined(WOLFSSL_TLS13_MIDDLEBOX_COMPAT)
3366+
WOLFSSL_CTX *ctx_c = NULL;
3367+
WOLFSSL *ssl_c = NULL;
3368+
struct test_memio_ctx test_ctx;
3369+
/* HelloRetryRequest carrying TLS_AES_128_GCM_SHA256, supported_versions
3370+
* (TLS 1.3), and an extra unknown extension type 0xFABC.
3371+
*
3372+
* The base HRR (from test_tls13_same_ch) extended with 4 bytes:
3373+
* extensions length: 6 -> 10 (0x00,0x0a)
3374+
* handshake body length: 46 -> 50 (0x00,0x00,0x32)
3375+
* record body length: 50 -> 54 (0x00,0x36)
3376+
* appended: 0xfa,0xbc,0x00,0x00 (unknown type, zero-length value)
3377+
*/
3378+
static const unsigned char hrr_unknown_ext[] = {
3379+
/* TLS record header: handshake, TLS 1.2 compat, len=54 */
3380+
0x16, 0x03, 0x03, 0x00, 0x36,
3381+
/* Handshake header: ServerHello, len=50 */
3382+
0x02, 0x00, 0x00, 0x32,
3383+
/* legacy_version: TLS 1.2 */
3384+
0x03, 0x03,
3385+
/* HelloRetryRequest magic random */
3386+
0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11,
3387+
0xbe, 0x1d, 0x8c, 0x02, 0x1e, 0x65, 0xb8, 0x91,
3388+
0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e,
3389+
0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
3390+
/* session ID length: 0 */
3391+
0x00,
3392+
/* cipher suite: TLS_AES_128_GCM_SHA256 */
3393+
0x13, 0x01,
3394+
/* compression: null */
3395+
0x00,
3396+
/* extensions length: 10 */
3397+
0x00, 0x0a,
3398+
/* supported_versions: TLS 1.3 (0x0304) */
3399+
0x00, 0x2b, 0x00, 0x02, 0x03, 0x04,
3400+
/* unknown extension type 0xFABC, zero-length value */
3401+
0xfa, 0xbc, 0x00, 0x00
3402+
};
3403+
3404+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
3405+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, NULL, &ssl_c, NULL,
3406+
wolfTLSv1_3_client_method, NULL), 0);
3407+
3408+
/* Inject the crafted HRR before the client starts the handshake.
3409+
* wolfSSL_connect will send the ClientHello and then read this message. */
3410+
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1,
3411+
(const char *)hrr_unknown_ext, sizeof(hrr_unknown_ext)), 0);
3412+
3413+
/* RFC 8446 Sec. 4.2: the client MUST abort with unsupported_extension. */
3414+
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
3415+
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1),
3416+
WC_NO_ERR_TRACE(UNSUPPORTED_EXTENSION));
3417+
3418+
/* The client MUST also transmit the fatal unsupported_extension alert
3419+
* on the wire, not merely surface a local error. The client's outgoing
3420+
* data lands in test_ctx.s_buff; at this point in the handshake no
3421+
* traffic keys are derived yet, so the alert record is plaintext.
3422+
* Expected record: type=alert(0x15), version=TLS1.2(0x0303), len=2,
3423+
* level=fatal(0x02), description=unsupported_extension(0x6e=110). */
3424+
{
3425+
static const unsigned char expected_alert[] =
3426+
{ 0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x6e };
3427+
int found = 0;
3428+
int i;
3429+
for (i = 0;
3430+
i + (int)sizeof(expected_alert) <= test_ctx.s_len;
3431+
i++) {
3432+
if (XMEMCMP(test_ctx.s_buff + i, expected_alert,
3433+
sizeof(expected_alert)) == 0) {
3434+
found = 1;
3435+
break;
3436+
}
3437+
}
3438+
ExpectIntEQ(found, 1);
3439+
}
3440+
3441+
wolfSSL_free(ssl_c);
3442+
wolfSSL_CTX_free(ctx_c);
3443+
#endif
3444+
return EXPECT_RESULT();
3445+
}
3446+
33553447
/* Test that wolfSSL_set1_sigalgs_list() is honored in TLS 1.3
33563448
*/
33573449
int test_tls13_cert_req_sigalgs(void)

tests/api/test_tls13.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ int test_key_share_mismatch(void);
4040
int test_tls13_middlebox_compat_empty_session_id(void);
4141
int test_tls13_plaintext_alert(void);
4242
int test_tls13_warning_alert_is_fatal(void);
43+
int test_tls13_unknown_ext_rejected(void);
4344
int test_tls13_cert_req_sigalgs(void);
4445
int test_tls13_derive_keys_no_key(void);
4546
int test_tls13_pqc_hybrid_truncated_keyshare(void);
@@ -65,6 +66,7 @@ int test_tls13_short_session_ticket(void);
6566
TEST_DECL_GROUP("tls13", test_tls13_cert_req_sigalgs), \
6667
TEST_DECL_GROUP("tls13", test_tls13_derive_keys_no_key), \
6768
TEST_DECL_GROUP("tls13", test_tls13_pqc_hybrid_truncated_keyshare), \
68-
TEST_DECL_GROUP("tls13", test_tls13_short_session_ticket)
69+
TEST_DECL_GROUP("tls13", test_tls13_short_session_ticket), \
70+
TEST_DECL_GROUP("tls13", test_tls13_unknown_ext_rejected)
6971

7072
#endif /* WOLFCRYPT_TEST_TLS13_H */

wolfssl/internal.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,9 +3009,7 @@ typedef enum {
30093009
TLSX_EARLY_DATA = TLSXT_EARLY_DATA,
30103010
#endif
30113011
TLSX_SUPPORTED_VERSIONS = TLSXT_SUPPORTED_VERSIONS,
3012-
#ifdef WOLFSSL_SEND_HRR_COOKIE
30133012
TLSX_COOKIE = TLSXT_COOKIE,
3014-
#endif
30153013
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
30163014
TLSX_PSK_KEY_EXCHANGE_MODES = TLSXT_PSK_KEY_EXCHANGE_MODES,
30173015
#endif

0 commit comments

Comments
 (0)