diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h index 3c2696fe40..043988f255 100644 --- a/include/mbedtls/ssl.h +++ b/include/mbedtls/ssl.h @@ -687,7 +687,6 @@ typedef enum { MBEDTLS_SSL_SERVER_FINISHED, MBEDTLS_SSL_FLUSH_BUFFERS, MBEDTLS_SSL_HANDSHAKE_WRAPUP, - MBEDTLS_SSL_NEW_SESSION_TICKET, MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT, MBEDTLS_SSL_HELLO_RETRY_REQUEST, diff --git a/library/ssl_tls13_server.c b/library/ssl_tls13_server.c index d983a00395..bfe805f496 100644 --- a/library/ssl_tls13_server.c +++ b/library/ssl_tls13_server.c @@ -1880,10 +1880,18 @@ static int ssl_tls13_postprocess_client_hello(mbedtls_ssl_context *ssl) #if defined(MBEDTLS_SSL_EARLY_DATA) /* There is enough information, update early data state. */ ssl_tls13_update_early_data_status(ssl); + + if (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED) { + ret = mbedtls_ssl_tls13_compute_early_transform(ssl); + if (ret != 0) { + MBEDTLS_SSL_DEBUG_RET( + 1, "mbedtls_ssl_tls13_compute_early_transform", ret); + return ret; + } + } #endif /* MBEDTLS_SSL_EARLY_DATA */ return 0; - } /* @@ -2748,6 +2756,59 @@ static int ssl_tls13_write_certificate_verify(mbedtls_ssl_context *ssl) } #endif /* MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED */ +/* + * RFC 8446 section A.2 + * + * | Send ServerHello + * | K_send = handshake + * | Send EncryptedExtensions + * | [Send CertificateRequest] + * Can send | [Send Certificate + CertificateVerify] + * app data | Send Finished + * after --> | K_send = application + * here +--------+--------+ + * No 0-RTT | | 0-RTT + * | | + * K_recv = handshake | | K_recv = early data + * [Skip decrypt errors] | +------> WAIT_EOED -+ + * | | Recv | | Recv EndOfEarlyData + * | | early data | | K_recv = handshake + * | +------------+ | + * | | + * +> WAIT_FLIGHT2 <--------+ + * | + * +--------+--------+ + * No auth | | Client auth + * | | + * | v + * | WAIT_CERT + * | Recv | | Recv Certificate + * | empty | v + * | Certificate | WAIT_CV + * | | | Recv + * | v | CertificateVerify + * +-> WAIT_FINISHED <---+ + * | Recv Finished + * + * + * The following function handles the state changes after WAIT_FLIGHT2 in the + * above diagram. We are not going to receive early data related messages + * anymore, prepare to receive the first handshake message of the client + * second flight. + */ +static void ssl_tls13_prepare_for_handshake_second_flight( + mbedtls_ssl_context *ssl) +{ + if (ssl->handshake->certificate_request_sent) { + mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE); + } else { + MBEDTLS_SSL_DEBUG_MSG(2, ("skip parse certificate")); + MBEDTLS_SSL_DEBUG_MSG(2, ("skip parse certificate verify")); + + mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_FINISHED); + } +} + /* * Handler for MBEDTLS_SSL_SERVER_FINISHED */ @@ -2769,20 +2830,200 @@ static int ssl_tls13_write_server_finished(mbedtls_ssl_context *ssl) return ret; } - MBEDTLS_SSL_DEBUG_MSG(1, ("Switch to handshake keys for inbound traffic")); +#if defined(MBEDTLS_SSL_EARLY_DATA) + if (ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED) { + /* See RFC 8446 section A.2 for more information */ + MBEDTLS_SSL_DEBUG_MSG( + 1, ("Switch to early keys for inbound traffic. " + "( K_recv = early data )")); + mbedtls_ssl_set_inbound_transform( + ssl, ssl->handshake->transform_earlydata); + mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_END_OF_EARLY_DATA); + return 0; + } +#endif /* MBEDTLS_SSL_EARLY_DATA */ + MBEDTLS_SSL_DEBUG_MSG( + 1, ("Switch to handshake keys for inbound traffic " + "( K_recv = handshake )")); mbedtls_ssl_set_inbound_transform(ssl, ssl->handshake->transform_handshake); - if (ssl->handshake->certificate_request_sent) { - mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_CERTIFICATE); - } else { - MBEDTLS_SSL_DEBUG_MSG(2, ("skip parse certificate")); - MBEDTLS_SSL_DEBUG_MSG(2, ("skip parse certificate verify")); - mbedtls_ssl_handshake_set_state(ssl, MBEDTLS_SSL_CLIENT_FINISHED); - } + ssl_tls13_prepare_for_handshake_second_flight(ssl); return 0; } +#if defined(MBEDTLS_SSL_EARLY_DATA) +/* + * Handler for MBEDTLS_SSL_END_OF_EARLY_DATA + */ +#define SSL_GOT_END_OF_EARLY_DATA 0 +#define SSL_GOT_EARLY_DATA 1 +/* Coordination: + * Deals with the ambiguity of not knowing if the next message is an + * EndOfEarlyData message or an application message containing early data. + * Returns a negative code on failure, or + * - SSL_GOT_END_OF_EARLY_DATA + * - SSL_GOT_EARLY_DATA + * indicating which message is received. + */ +MBEDTLS_CHECK_RETURN_CRITICAL +static int ssl_tls13_end_of_early_data_coordinate(mbedtls_ssl_context *ssl) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if ((ret = mbedtls_ssl_read_record(ssl, 0)) != 0) { + MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_read_record", ret); + return ret; + } + ssl->keep_current_message = 1; + + if (ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_END_OF_EARLY_DATA) { + MBEDTLS_SSL_DEBUG_MSG(3, ("Received an end_of_early_data message.")); + return SSL_GOT_END_OF_EARLY_DATA; + } + + if (ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA) { + MBEDTLS_SSL_DEBUG_MSG(3, ("Received early data")); + return SSL_GOT_EARLY_DATA; + } + + MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE, + MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE); + return MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE; +} + +MBEDTLS_CHECK_RETURN_CRITICAL +static int ssl_tls13_parse_end_of_early_data(mbedtls_ssl_context *ssl, + const unsigned char *buf, + const unsigned char *end) +{ + /* RFC 8446 section 4.5 + * + * struct {} EndOfEarlyData; + */ + if (buf != end) { + MBEDTLS_SSL_PEND_FATAL_ALERT(MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR, + MBEDTLS_ERR_SSL_DECODE_ERROR); + return MBEDTLS_ERR_SSL_DECODE_ERROR; + } + return 0; +} + +MBEDTLS_CHECK_RETURN_CRITICAL +static int ssl_tls13_process_early_application_data(mbedtls_ssl_context *ssl) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + if ((ret = mbedtls_ssl_read_record(ssl, 0)) != 0) { + MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_read_record", ret); + return ret; + } + + /* + * Output early data + * + * For the time being, we print received data via debug message. + * + * TODO: Remove it when `mbedtls_ssl_read_early_data` is ready. + */ + ssl->in_msg[ssl->in_msglen] = 0; + MBEDTLS_SSL_DEBUG_MSG(3, ("\n%s", ssl->in_msg)); + + /* RFC 8446 section 4.6.1 + * + * A server receiving more than max_early_data_size bytes of 0-RTT data + * SHOULD terminate the connection with an "unexpected_message" alert. + * + * TODO: Add received data size check here. + */ + + return 0; +} + +/* + * RFC 8446 section A.2 + * + * | Send ServerHello + * | K_send = handshake + * | Send EncryptedExtensions + * | [Send CertificateRequest] + * Can send | [Send Certificate + CertificateVerify] + * app data | Send Finished + * after --> | K_send = application + * here +--------+--------+ + * No 0-RTT | | 0-RTT + * | | + * K_recv = handshake | | K_recv = early data + * [Skip decrypt errors] | +------> WAIT_EOED -+ + * | | Recv | | Recv EndOfEarlyData + * | | early data | | K_recv = handshake + * | +------------+ | + * | | + * +> WAIT_FLIGHT2 <--------+ + * | + * +--------+--------+ + * No auth | | Client auth + * | | + * | v + * | WAIT_CERT + * | Recv | | Recv Certificate + * | empty | v + * | Certificate | WAIT_CV + * | | | Recv + * | v | CertificateVerify + * +-> WAIT_FINISHED <---+ + * | Recv Finished + * + * The function handles actions and state changes from 0-RTT to WAIT_FLIGHT2 in + * the above diagram. + */ +MBEDTLS_CHECK_RETURN_CRITICAL +static int ssl_tls13_process_end_of_early_data(mbedtls_ssl_context *ssl) +{ + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; + + MBEDTLS_SSL_DEBUG_MSG(2, ("=> ssl_tls13_process_end_of_early_data")); + + MBEDTLS_SSL_PROC_CHK_NEG(ssl_tls13_end_of_early_data_coordinate(ssl)); + + if (ret == SSL_GOT_END_OF_EARLY_DATA) { + unsigned char *buf; + size_t buf_len; + + MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_tls13_fetch_handshake_msg( + ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, + &buf, &buf_len)); + + MBEDTLS_SSL_PROC_CHK(ssl_tls13_parse_end_of_early_data( + ssl, buf, buf + buf_len)); + + MBEDTLS_SSL_DEBUG_MSG( + 1, ("Switch to handshake keys for inbound traffic" + "( K_recv = handshake )")); + mbedtls_ssl_set_inbound_transform( + ssl, ssl->handshake->transform_handshake); + + MBEDTLS_SSL_PROC_CHK(mbedtls_ssl_add_hs_msg_to_checksum( + ssl, MBEDTLS_SSL_HS_END_OF_EARLY_DATA, + buf, buf_len)); + + ssl_tls13_prepare_for_handshake_second_flight(ssl); + + } else if (ret == SSL_GOT_EARLY_DATA) { + MBEDTLS_SSL_PROC_CHK(ssl_tls13_process_early_application_data(ssl)); + } else { + MBEDTLS_SSL_DEBUG_MSG(1, ("should never happen")); + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + +cleanup: + MBEDTLS_SSL_DEBUG_MSG(2, ("<= ssl_tls13_process_end_of_early_data")); + return ret; +} +#endif /* MBEDTLS_SSL_EARLY_DATA */ + /* * Handler for MBEDTLS_SSL_CLIENT_FINISHED */ @@ -3207,6 +3448,12 @@ int mbedtls_ssl_tls13_handshake_server_step(mbedtls_ssl_context *ssl) ret = ssl_tls13_write_server_finished(ssl); break; +#if defined(MBEDTLS_SSL_EARLY_DATA) + case MBEDTLS_SSL_END_OF_EARLY_DATA: + ret = ssl_tls13_process_end_of_early_data(ssl); + break; +#endif /* MBEDTLS_SSL_EARLY_DATA */ + case MBEDTLS_SSL_CLIENT_FINISHED: ret = ssl_tls13_process_client_finished(ssl); break; diff --git a/tests/opt-testcases/tls13-misc.sh b/tests/opt-testcases/tls13-misc.sh index f03a386a04..e4df1fe2f0 100755 --- a/tests/opt-testcases/tls13-misc.sh +++ b/tests/opt-testcases/tls13-misc.sh @@ -513,12 +513,12 @@ requires_all_configs_enabled MBEDTLS_SSL_EARLY_DATA MBEDTLS_SSL_SESSION_TICKETS MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE requires_any_configs_enabled MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_ENABLED \ MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED -run_test "TLS 1.3 G->m: EarlyData: feature is enabled, fail." \ +run_test "TLS 1.3 G->m: EarlyData: feature is enabled, good." \ "$P_SRV force_version=tls13 debug_level=4 max_early_data_size=$EARLY_DATA_INPUT_LEN" \ "$G_NEXT_CLI localhost --priority=NORMAL:-VERS-ALL:+VERS-TLS1.3:+GROUP-ALL:+KX-ALL \ -d 10 -r --earlydata $EARLY_DATA_INPUT " \ - 1 \ + 0 \ -s "ClientHello: early_data(42) extension exists." \ -s "EncryptedExtensions: early_data(42) extension exists." \ -s "NewSessionTicket: early_data(42) extension does not exist." \ - -s "Last error was: -29056 - SSL - Verification of the message MAC failed" + -s "$( tail -1 $EARLY_DATA_INPUT )"