Skip to content

Commit 7a56e62

Browse files
Ensure post_handshake_auth extension was sent before accepting post-handshake CertificateRequest message as per RFC 8446 4.6.2.
Thanks to Xiangdong Li for the report.
1 parent 8541142 commit 7a56e62

3 files changed

Lines changed: 82 additions & 0 deletions

File tree

src/tls13.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13016,6 +13016,21 @@ static int SanityCheckTls13MsgReceived(WOLFSSL* ssl, byte type)
1301613016
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
1301713017
return OUT_OF_ORDER_E;
1301813018
}
13019+
/* RFC 8446 4.6.2: A client that receives a post-handshake
13020+
* CertificateRequest message without having sent the
13021+
* "post_handshake_auth" extension MUST send an
13022+
* "unexpected_message" fatal alert. The caller of
13023+
* SanityCheckTls13MsgReceived() converts OUT_OF_ORDER_E into an
13024+
* unexpected_message alert. */
13025+
if (ssl->options.serverState >= SERVER_FINISHED_COMPLETE &&
13026+
ssl->options.clientState == CLIENT_FINISHED_COMPLETE &&
13027+
!ssl->options.postHandshakeAuth) {
13028+
WOLFSSL_MSG("Post-handshake CertificateRequest received "
13029+
"without having sent post_handshake_auth "
13030+
"extension");
13031+
WOLFSSL_ERROR_VERBOSE(OUT_OF_ORDER_E);
13032+
return OUT_OF_ORDER_E;
13033+
}
1301913034
#endif
1302013035
#if defined(HAVE_SESSION_TICKET) || !defined(NO_PSK)
1302113036
/* Server's authenticating with PSK must not send this. */

tests/api/test_tls13.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5058,6 +5058,71 @@ int test_tls13_zero_inner_content_type(void)
50585058
return EXPECT_RESULT();
50595059
}
50605060

5061+
/* RFC 8446 Section 4.6.2: A client that receives a post-handshake
5062+
* CertificateRequest message without having sent the "post_handshake_auth"
5063+
* extension MUST send an "unexpected_message" fatal alert.
5064+
*
5065+
* This test completes a TLS 1.3 handshake in which the client never enabled
5066+
* post-handshake auth (so no extension was sent in the ClientHello), then
5067+
* forces the server to transmit a post-handshake CertificateRequest anyway.
5068+
* The client must reject the message with an unexpected_message fatal
5069+
* alert. */
5070+
int test_tls13_post_handshake_auth_no_ext(void)
5071+
{
5072+
EXPECT_DECLS;
5073+
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_POST_HANDSHAKE_AUTH) && \
5074+
defined(HAVE_MANUAL_MEMIO_TESTS_DEPENDENCIES) && \
5075+
!defined(NO_WOLFSSL_CLIENT) && !defined(NO_WOLFSSL_SERVER)
5076+
WOLFSSL_CTX *ctx_c = NULL;
5077+
WOLFSSL_CTX *ctx_s = NULL;
5078+
WOLFSSL *ssl_c = NULL;
5079+
WOLFSSL *ssl_s = NULL;
5080+
struct test_memio_ctx test_ctx;
5081+
WOLFSSL_ALERT_HISTORY h;
5082+
char readBuf[8];
5083+
5084+
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
5085+
XMEMSET(&h, 0, sizeof(h));
5086+
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
5087+
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
5088+
/* Keep the post-handshake byte stream simple by suppressing the server's
5089+
* NewSessionTicket so the only post-handshake record from the server is
5090+
* the CertificateRequest under test. */
5091+
ExpectIntEQ(wolfSSL_no_ticket_TLSv13(ssl_s), 0);
5092+
5093+
/* Intentionally do NOT call wolfSSL_allow_post_handshake_auth() on the
5094+
* client so the post_handshake_auth extension is omitted from the
5095+
* ClientHello. */
5096+
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
5097+
5098+
/* The server's wolfSSL_request_certificate() refuses to send a
5099+
* post-handshake CertificateRequest unless its postHandshakeAuth flag is
5100+
* set (normally set when parsing the client's extension). To exercise
5101+
* the receive-side check we are testing, simulate a server that sends
5102+
* one anyway by toggling the flag directly. */
5103+
if (ssl_s != NULL)
5104+
ssl_s->options.postHandshakeAuth = 1;
5105+
ExpectIntEQ(wolfSSL_request_certificate(ssl_s), WOLFSSL_SUCCESS);
5106+
5107+
/* The client must reject the unsolicited CertificateRequest. */
5108+
ExpectIntEQ(wolfSSL_read(ssl_c, readBuf, (int)sizeof(readBuf)),
5109+
WOLFSSL_FATAL_ERROR);
5110+
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
5111+
WC_NO_ERR_TRACE(OUT_OF_ORDER_E));
5112+
5113+
/* And the client must transmit a fatal unexpected_message alert. */
5114+
ExpectIntEQ(wolfSSL_get_alert_history(ssl_c, &h), WOLFSSL_SUCCESS);
5115+
ExpectIntEQ(h.last_tx.code, unexpected_message);
5116+
ExpectIntEQ(h.last_tx.level, alert_fatal);
5117+
5118+
wolfSSL_free(ssl_c);
5119+
wolfSSL_CTX_free(ctx_c);
5120+
wolfSSL_free(ssl_s);
5121+
wolfSSL_CTX_free(ctx_s);
5122+
#endif
5123+
return EXPECT_RESULT();
5124+
}
5125+
50615126
/* Test that a TLS 1.3-capable client rejects downgrade sentinels in a
50625127
* downgraded ServerHello random for both TLS 1.2 and TLS 1.1-or-lower. */
50635128
int test_tls13_downgrade_sentinel(void)

tests/api/test_tls13.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ int test_tls13_corrupted_finished(void);
5252
int test_tls13_peerauth_failsafe(void);
5353
int test_tls13_hrr_bad_cookie(void);
5454
int test_tls13_zero_inner_content_type(void);
55+
int test_tls13_post_handshake_auth_no_ext(void);
5556
int test_tls13_downgrade_sentinel(void);
5657
int test_tls13_serverhello_bad_cipher_suites(void);
5758
int test_tls13_cert_with_extern_psk_apis(void);
@@ -90,6 +91,7 @@ int test_tls13_cert_with_extern_psk_sh_confirms_resumption(void);
9091
TEST_DECL_GROUP("tls13", test_tls13_peerauth_failsafe), \
9192
TEST_DECL_GROUP("tls13", test_tls13_hrr_bad_cookie), \
9293
TEST_DECL_GROUP("tls13", test_tls13_zero_inner_content_type), \
94+
TEST_DECL_GROUP("tls13", test_tls13_post_handshake_auth_no_ext), \
9395
TEST_DECL_GROUP("tls13", test_tls13_downgrade_sentinel), \
9496
TEST_DECL_GROUP("tls13", test_tls13_serverhello_bad_cipher_suites), \
9597
TEST_DECL_GROUP("tls13", test_tls13_cert_with_extern_psk_apis), \

0 commit comments

Comments
 (0)