mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 15:00:49 +02:00
TLS 1.3 plaintext alert: ignore before seeing encrypted
Change to ignore plaintext alerts when WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC is defined only until first encrypted message from peer is seen. Negative testing added.
This commit is contained in:
+30
-12
@@ -22420,6 +22420,9 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
|
||||
byte level;
|
||||
byte code;
|
||||
word32 dataSz = (word32)ssl->curSize;
|
||||
#ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
|
||||
int ignorePtAlert;
|
||||
#endif
|
||||
|
||||
#if defined(WOLFSSL_CALLBACKS) || defined(OPENSSL_EXTRA)
|
||||
if (ssl->hsInfoOn)
|
||||
@@ -22448,9 +22451,19 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
|
||||
code = input[(*inOutIdx)++];
|
||||
*type = code;
|
||||
#ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
|
||||
/* Don't process alert when TLS 1.3 and encrypting but plaintext alert. */
|
||||
if (!IsAtLeastTLSv1_3(ssl->version) || !IsEncryptionOn(ssl, 0) ||
|
||||
ssl->keys.decryptedCur)
|
||||
/* A plaintext alert received in TLS 1.3 once we are decrypting is only
|
||||
* tolerated while still in the handshake and before the peer has sent an
|
||||
* encrypted message. The peer sequence number is reset to zero each time
|
||||
* decryption keys are installed and incremented for each record decrypted,
|
||||
* so a non-zero value means the peer has sent an encrypted message and a
|
||||
* plaintext alert is treated as an error. */
|
||||
ignorePtAlert = IsAtLeastTLSv1_3(ssl->version) && IsEncryptionOn(ssl, 0) &&
|
||||
!ssl->keys.decryptedCur && !ssl->options.handShakeDone &&
|
||||
ssl->keys.peer_sequence_number_hi == 0 &&
|
||||
ssl->keys.peer_sequence_number_lo == 0;
|
||||
|
||||
/* Don't record an ignored plaintext alert in the alert history. */
|
||||
if (!ignorePtAlert)
|
||||
#endif
|
||||
{
|
||||
ssl->alert_history.last_rx.code = code;
|
||||
@@ -22481,16 +22494,21 @@ static int DoAlert(WOLFSSL* ssl, byte* input, word32* inOutIdx, int* type)
|
||||
!ssl->keys.decryptedCur)
|
||||
{
|
||||
#ifdef WOLFSSL_TLS13_IGNORE_PT_ALERT_ON_ENC
|
||||
/* Ignore alert if TLS 1.3 and encrypting but was plaintext alert. */
|
||||
*type = invalid_alert;
|
||||
level = alert_none;
|
||||
|
||||
#else
|
||||
/* Unexpected message when encryption is on and alert not encrypted. */
|
||||
SendAlert(ssl, alert_fatal, unexpected_message);
|
||||
WOLFSSL_ERROR_VERBOSE(PARSE_ERROR);
|
||||
return PARSE_ERROR;
|
||||
if (ignorePtAlert) {
|
||||
/* Ignore plaintext alert: TLS 1.3, decrypting, and the peer has
|
||||
* not yet sent an encrypted handshake message. */
|
||||
*type = invalid_alert;
|
||||
level = alert_none;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Unexpected message when encryption is on and alert not
|
||||
* encrypted. */
|
||||
SendAlert(ssl, alert_fatal, unexpected_message);
|
||||
WOLFSSL_ERROR_VERBOSE(PARSE_ERROR);
|
||||
return PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (*type == close_notify) {
|
||||
|
||||
@@ -4542,6 +4542,129 @@ int test_tls13_plaintext_alert(void)
|
||||
|
||||
wolfSSL_free(ssl);
|
||||
wolfSSL_CTX_free(ctx);
|
||||
ssl = NULL;
|
||||
ctx = NULL;
|
||||
|
||||
/* Negative test: a plaintext alert must NOT be ignored once the peer has
|
||||
* responded with an encrypted handshake message. Complete a handshake so
|
||||
* the peer is encrypting, then feed the client a plaintext alert. */
|
||||
#if !defined(NO_WOLFSSL_CLIENT) && !defined(NO_FILESYSTEM)
|
||||
{
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
/* Plaintext alert record: fatal (2), handshake_failure (40). */
|
||||
byte ptAlert[] = { 0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x28 };
|
||||
char data[16];
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
||||
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
|
||||
ExpectIntEQ(test_memio_do_handshake(ssl_c, ssl_s, 10, NULL), 0);
|
||||
|
||||
/* Drop any post-handshake data (e.g. session tickets) queued for the
|
||||
* client and feed it only the plaintext alert. */
|
||||
test_memio_clear_buffer(&test_ctx, 1);
|
||||
ExpectIntEQ(test_memio_inject_message(&test_ctx, 1, (const char*)ptAlert,
|
||||
(int)sizeof(ptAlert)), 0);
|
||||
|
||||
/* Plaintext alert is rejected as the peer is encrypting. */
|
||||
ExpectIntLT(wolfSSL_read(ssl_c, data, (int)sizeof(data)), 0);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, WOLFSSL_FATAL_ERROR),
|
||||
WC_NO_ERR_TRACE(PARSE_ERROR));
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
}
|
||||
|
||||
/* Negative test (server): a plaintext alert must NOT be ignored once the
|
||||
* client has sent an encrypted handshake message, even before the
|
||||
* handshake is complete. Use client authentication so that the client
|
||||
* sends an encrypted Certificate message before Finished. */
|
||||
{
|
||||
WOLFSSL_CTX* ctx_c = NULL;
|
||||
WOLFSSL_CTX* ctx_s = NULL;
|
||||
WOLFSSL* ssl_c = NULL;
|
||||
WOLFSSL* ssl_s = NULL;
|
||||
struct test_memio_ctx test_ctx;
|
||||
/* Plaintext alert record: fatal (2), handshake_failure (40). */
|
||||
byte ptAlert[] = { 0x15, 0x03, 0x03, 0x00, 0x02, 0x02, 0x28 };
|
||||
int end = 0;
|
||||
|
||||
XMEMSET(&test_ctx, 0, sizeof(test_ctx));
|
||||
ExpectIntEQ(test_memio_setup(&test_ctx, &ctx_c, &ctx_s, &ssl_c, &ssl_s,
|
||||
wolfTLSv1_3_client_method, wolfTLSv1_3_server_method), 0);
|
||||
/* Server requires a client certificate. */
|
||||
ExpectTrue(wolfSSL_CTX_load_verify_locations(ctx_s, cliCertFile,
|
||||
NULL) == WOLFSSL_SUCCESS);
|
||||
if (EXPECT_SUCCESS()) {
|
||||
wolfSSL_set_verify(ssl_s, WOLFSSL_VERIFY_PEER |
|
||||
WOLFSSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
|
||||
}
|
||||
ExpectTrue(wolfSSL_use_certificate_file(ssl_c, cliCertFile,
|
||||
CERT_FILETYPE) == WOLFSSL_SUCCESS);
|
||||
ExpectTrue(wolfSSL_use_PrivateKey_file(ssl_c, cliKeyFile,
|
||||
CERT_FILETYPE) == WOLFSSL_SUCCESS);
|
||||
|
||||
/* Client Hello. */
|
||||
ExpectIntEQ(wolfSSL_connect(ssl_c), -1);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_c, -1), WOLFSSL_ERROR_WANT_READ);
|
||||
/* Server flight including CertificateRequest. */
|
||||
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_s, -1), WOLFSSL_ERROR_WANT_READ);
|
||||
/* Client flight: [CCS,] Certificate, CertificateVerify, Finished. */
|
||||
ExpectIntEQ(wolfSSL_connect(ssl_c), WOLFSSL_SUCCESS);
|
||||
|
||||
/* Find the end of the first encrypted record (outer content type
|
||||
* application_data) the client sent - the Certificate message. */
|
||||
while (end + 5 <= test_ctx.s_len) {
|
||||
byte recType = test_ctx.s_buff[end];
|
||||
end += 5 + ((test_ctx.s_buff[end + 3] << 8) |
|
||||
test_ctx.s_buff[end + 4]);
|
||||
if (recType == 0x17)
|
||||
break;
|
||||
}
|
||||
ExpectIntLE(end, test_ctx.s_len);
|
||||
ExpectIntGT(end, 0);
|
||||
/* Remove the records after it (CertificateVerify and Finished),
|
||||
* working backwards a message at a time. */
|
||||
while (EXPECT_SUCCESS() && test_ctx.s_len > end) {
|
||||
int i;
|
||||
int msgOff = 0;
|
||||
|
||||
for (i = 0; i < test_ctx.s_msg_count - 1; i++)
|
||||
msgOff += test_ctx.s_msg_sizes[i];
|
||||
if (msgOff >= end) {
|
||||
/* Last message is wholly after the Certificate record. */
|
||||
ExpectIntEQ(test_memio_drop_message(&test_ctx, 0,
|
||||
test_ctx.s_msg_count - 1), 0);
|
||||
}
|
||||
else {
|
||||
/* Last message also holds the records to keep. */
|
||||
ExpectIntEQ(test_memio_remove_from_buffer(&test_ctx, 0, end,
|
||||
test_ctx.s_len - end), 0);
|
||||
}
|
||||
}
|
||||
/* Follow the encrypted Certificate message with a plaintext alert. */
|
||||
ExpectIntEQ(test_memio_inject_message(&test_ctx, 0,
|
||||
(const char*)ptAlert, (int)sizeof(ptAlert)), 0);
|
||||
|
||||
/* Plaintext alert is rejected as the client has sent an encrypted
|
||||
* handshake message. */
|
||||
ExpectIntEQ(wolfSSL_accept(ssl_s), -1);
|
||||
ExpectIntEQ(wolfSSL_get_error(ssl_s, WOLFSSL_FATAL_ERROR),
|
||||
WC_NO_ERR_TRACE(PARSE_ERROR));
|
||||
|
||||
wolfSSL_free(ssl_c);
|
||||
wolfSSL_free(ssl_s);
|
||||
wolfSSL_CTX_free(ctx_c);
|
||||
wolfSSL_CTX_free(ctx_s);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
/* Fail on plaintext alert when encryption keys on. */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user