Skip to content

Commit 9b4e964

Browse files
Merge pull request #8760 from ronald-cron-arm/tls13-write-early-data
TLS 1.3: Add mbedtls_ssl_write_early_data() API
2 parents 7f523bf + dcb09ca commit 9b4e964

File tree

12 files changed

+875
-226
lines changed

12 files changed

+875
-226
lines changed

include/mbedtls/ssl.h

Lines changed: 91 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,51 @@ typedef enum {
734734
}
735735
mbedtls_ssl_states;
736736

737+
/*
738+
* Early data status, client side only.
739+
*/
740+
741+
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
742+
typedef enum {
743+
/*
744+
* The client has not sent the first ClientHello yet, it is unknown if the
745+
* client will send an early data indication extension or not.
746+
*/
747+
MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN,
748+
749+
/*
750+
* See documentation of mbedtls_ssl_get_early_data_status().
751+
*/
752+
MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT,
753+
MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED,
754+
MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED,
755+
756+
/*
757+
* The client has sent an early data indication extension in its first
758+
* ClientHello, it has not received the response (ServerHello or
759+
* HelloRetryRequest) from the server yet. The transform to protect early data
760+
* is not set and early data cannot be sent yet.
761+
*/
762+
MBEDTLS_SSL_EARLY_DATA_STATUS_SENT,
763+
764+
/*
765+
* The client has sent an early data indication extension in its first
766+
* ClientHello, it has not received the response (ServerHello or
767+
* HelloRetryRequest) from the server yet. The transform to protect early data
768+
* has been set and early data can be written now.
769+
*/
770+
MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE,
771+
772+
/*
773+
* The client has sent an early data indication extension in its first
774+
* ClientHello, the server has accepted them and the client has received the
775+
* server Finished message. It cannot send early data to the server anymore.
776+
*/
777+
MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED,
778+
} mbedtls_ssl_early_data_status;
779+
780+
#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */
781+
737782
/**
738783
* \brief Callback type: send data on the network.
739784
*
@@ -1673,33 +1718,29 @@ struct mbedtls_ssl_context {
16731718
#endif /* MBEDTLS_SSL_RENEGOTIATION */
16741719

16751720
/**
1676-
* Maximum TLS version to be negotiated, then negotiated TLS version.
1721+
* Maximum TLS version to be negotiated, then negotiated TLS version.
16771722
*
1678-
* It is initialized as the configured maximum TLS version to be
1679-
* negotiated by mbedtls_ssl_setup().
1723+
* It is initialized as the configured maximum TLS version to be
1724+
* negotiated by mbedtls_ssl_setup().
16801725
*
1681-
* When renegotiating or resuming a session, it is overwritten in the
1682-
* ClientHello writing preparation stage with the previously negotiated
1683-
* TLS version.
1726+
* When renegotiating or resuming a session, it is overwritten in the
1727+
* ClientHello writing preparation stage with the previously negotiated
1728+
* TLS version.
16841729
*
1685-
* On client side, it is updated to the TLS version selected by the server
1686-
* for the handshake when the ServerHello is received.
1730+
* On client side, it is updated to the TLS version selected by the server
1731+
* for the handshake when the ServerHello is received.
16871732
*
1688-
* On server side, it is updated to the TLS version the server selects for
1689-
* the handshake when the ClientHello is received.
1733+
* On server side, it is updated to the TLS version the server selects for
1734+
* the handshake when the ClientHello is received.
16901735
*/
16911736
mbedtls_ssl_protocol_version MBEDTLS_PRIVATE(tls_version);
16921737

16931738
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
16941739
/**
1695-
* Status of the negotiation of the use of early data.
1696-
* See the documentation of mbedtls_ssl_get_early_data_status() for more
1697-
* information.
1698-
*
1699-
* Reset to #MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT when the context is
1700-
* reset.
1740+
* Status of the negotiation of the use of early data. Reset to
1741+
* MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN when the context is reset.
17011742
*/
1702-
int MBEDTLS_PRIVATE(early_data_status);
1743+
mbedtls_ssl_early_data_status MBEDTLS_PRIVATE(early_data_status);
17031744
#endif
17041745

17051746
unsigned MBEDTLS_PRIVATE(badmac_seen); /*!< records with a bad MAC received */
@@ -5150,10 +5191,6 @@ int mbedtls_ssl_close_notify(mbedtls_ssl_context *ssl);
51505191

51515192
#if defined(MBEDTLS_SSL_EARLY_DATA)
51525193

5153-
#define MBEDTLS_SSL_EARLY_DATA_STATUS_NOT_SENT 1
5154-
#define MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED 2
5155-
#define MBEDTLS_SSL_EARLY_DATA_STATUS_REJECTED 3
5156-
51575194
#if defined(MBEDTLS_SSL_SRV_C)
51585195
/**
51595196
* \brief Read at most 'len' bytes of early data
@@ -5206,17 +5243,43 @@ int mbedtls_ssl_read_early_data(mbedtls_ssl_context *ssl,
52065243
* \brief Try to write exactly 'len' application data bytes while
52075244
* performing the handshake (early data).
52085245
*
5246+
* \warning Early data is defined in the TLS 1.3 specification, RFC 8446.
5247+
* IMPORTANT NOTE from section 2.3 of the specification:
5248+
*
5249+
* The security properties for 0-RTT data are weaker than
5250+
* those for other kinds of TLS data. Specifically:
5251+
* - This data is not forward secret, as it is encrypted
5252+
* solely under keys derived using the offered PSK.
5253+
* - There are no guarantees of non-replay between connections.
5254+
* Protection against replay for ordinary TLS 1.3 1-RTT data
5255+
* is provided via the server's Random value, but 0-RTT data
5256+
* does not depend on the ServerHello and therefore has
5257+
* weaker guarantees. This is especially relevant if the
5258+
* data is authenticated either with TLS client
5259+
* authentication or inside the application protocol. The
5260+
* same warnings apply to any use of the
5261+
* early_exporter_master_secret.
5262+
*
52095263
* \note This function behaves mainly as mbedtls_ssl_write(). The
52105264
* specification of mbedtls_ssl_write() relevant to TLS 1.3
52115265
* (thus not the parts specific to (D)TLS1.2) applies to this
5212-
* function and the present documentation is restricted to the
5213-
* differences with mbedtls_ssl_write().
5266+
* function and the present documentation is mainly restricted
5267+
* to the differences with mbedtls_ssl_write(). One noticeable
5268+
* difference though is that mbedtls_ssl_write() aims to
5269+
* complete the handshake before to write application data
5270+
* while mbedtls_ssl_write_early() aims to drive the handshake
5271+
* just past the point where it is not possible to send early
5272+
* data anymore.
52145273
*
52155274
* \param ssl SSL context
52165275
* \param buf buffer holding the data
52175276
* \param len how many bytes must be written
52185277
*
5219-
* \return One additional specific return value:
5278+
* \return The (non-negative) number of bytes actually written if
5279+
* successful (may be less than \p len).
5280+
*
5281+
* \return One additional specific error code compared to
5282+
* mbedtls_ssl_write():
52205283
* #MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA.
52215284
*
52225285
* #MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA is returned when it
@@ -5237,9 +5300,11 @@ int mbedtls_ssl_read_early_data(mbedtls_ssl_context *ssl,
52375300
* already completed.
52385301
*
52395302
* It is not possible to write early data for the SSL context
5240-
* \p ssl but this does not preclude for using it with
5303+
* \p ssl and any subsequent call to this API will return this
5304+
* error code. But this does not preclude for using it with
52415305
* mbedtls_ssl_write(), mbedtls_ssl_read() or
5242-
* mbedtls_ssl_handshake().
5306+
* mbedtls_ssl_handshake() and the handshake can be
5307+
* completed by calling one of these APIs.
52435308
*
52445309
* \note This function may write early data only if the SSL context
52455310
* has been configured for the handshake with a PSK for which

library/ssl_debug_helpers.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121

2222
const char *mbedtls_ssl_states_str(mbedtls_ssl_states in);
2323

24+
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
25+
const char *mbedtls_ssl_early_data_status_str(mbedtls_ssl_early_data_status in);
26+
#endif
27+
2428
const char *mbedtls_ssl_protocol_version_str(mbedtls_ssl_protocol_version in);
2529

2630
const char *mbedtls_tls_prf_types_str(mbedtls_tls_prf_types in);

library/ssl_misc.h

Lines changed: 25 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -665,21 +665,21 @@ struct mbedtls_ssl_handshake_params {
665665
#if defined(MBEDTLS_SSL_CLI_C)
666666
/** Minimum TLS version to be negotiated.
667667
*
668-
* It is set up in the ClientHello writing preparation stage and used
669-
* throughout the ClientHello writing. Not relevant anymore as soon as
670-
* the protocol version has been negotiated thus as soon as the
671-
* ServerHello is received.
672-
* For a fresh handshake not linked to any previous handshake, it is
673-
* equal to the configured minimum minor version to be negotiated. When
674-
* renegotiating or resuming a session, it is equal to the previously
675-
* negotiated minor version.
668+
* It is set up in the ClientHello writing preparation stage and used
669+
* throughout the ClientHello writing. Not relevant anymore as soon as
670+
* the protocol version has been negotiated thus as soon as the
671+
* ServerHello is received.
672+
* For a fresh handshake not linked to any previous handshake, it is
673+
* equal to the configured minimum minor version to be negotiated. When
674+
* renegotiating or resuming a session, it is equal to the previously
675+
* negotiated minor version.
676676
*
677-
* There is no maximum TLS version field in this handshake context.
678-
* From the start of the handshake, we need to define a current protocol
679-
* version for the record layer which we define as the maximum TLS
680-
* version to be negotiated. The `tls_version` field of the SSL context is
681-
* used to store this maximum value until it contains the actual
682-
* negotiated value.
677+
* There is no maximum TLS version field in this handshake context.
678+
* From the start of the handshake, we need to define a current protocol
679+
* version for the record layer which we define as the maximum TLS
680+
* version to be negotiated. The `tls_version` field of the SSL context is
681+
* used to store this maximum value until it contains the actual
682+
* negotiated value.
683683
*/
684684
mbedtls_ssl_protocol_version min_tls_version;
685685
#endif
@@ -730,16 +730,21 @@ struct mbedtls_ssl_handshake_params {
730730
#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
731731
uint8_t key_exchange_mode; /*!< Selected key exchange mode */
732732

733-
/** Number of HelloRetryRequest messages received/sent from/to the server. */
734-
uint8_t hello_retry_request_count;
733+
/**
734+
* Flag indicating if, in the course of the current handshake, an
735+
* HelloRetryRequest message has been sent by the server or received by
736+
* the client (<> 0) or not (0).
737+
*/
738+
uint8_t hello_retry_request_flag;
735739

736740
#if defined(MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE)
737741
/**
738-
* Number of dummy change_cipher_spec (CCS) record sent. Used to send only
739-
* one CCS per handshake without having to complicate the handshake state
740-
* transitions.
742+
* Flag indicating if, in the course of the current handshake, a dummy
743+
* change_cipher_spec (CCS) record has already been sent. Used to send only
744+
* one CCS per handshake while not complicating the handshake state
745+
* transitions for that purpose.
741746
*/
742-
uint8_t ccs_count;
747+
uint8_t ccs_sent;
743748
#endif
744749

745750
#if defined(MBEDTLS_SSL_SRV_C)
@@ -2145,38 +2150,6 @@ int mbedtls_ssl_tls13_write_early_data_ext(mbedtls_ssl_context *ssl,
21452150
unsigned char *buf,
21462151
const unsigned char *end,
21472152
size_t *out_len);
2148-
2149-
#if defined(MBEDTLS_SSL_CLI_C)
2150-
/*
2151-
* The client has not sent the first ClientHello yet, it is unknown if the
2152-
* client will send an early data indication extension or not.
2153-
*/
2154-
#define MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN 0
2155-
2156-
/*
2157-
* The client has sent an early data indication extension in its first
2158-
* ClientHello, it has not received the response (ServerHello or
2159-
* HelloRetryRequest) from the server yet. The transform to protect early data
2160-
* is not set and early data cannot be sent yet.
2161-
*/
2162-
#define MBEDTLS_SSL_EARLY_DATA_STATUS_SENT 4
2163-
2164-
/*
2165-
* The client has sent an early data indication extension in its first
2166-
* ClientHello, it has not received the response (ServerHello or
2167-
* HelloRetryRequest) from the server yet. The transform to protect early data
2168-
* has been set and early data can be written now.
2169-
*/
2170-
#define MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE 5
2171-
2172-
/*
2173-
* The client has sent an early data indication extension in its first
2174-
* ClientHello, the server has accepted them and the client has received the
2175-
* server Finished message. It cannot send early data to the server anymore.
2176-
*/
2177-
#define MBEDTLS_SSL_EARLY_DATA_STATUS_SERVER_FINISHED_RECEIVED 6
2178-
#endif /* MBEDTLS_SSL_CLI_C */
2179-
21802153
#endif /* MBEDTLS_SSL_EARLY_DATA */
21812154

21822155
#endif /* MBEDTLS_SSL_PROTO_TLS1_3 */

library/ssl_msg.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6058,6 +6058,94 @@ int mbedtls_ssl_write(mbedtls_ssl_context *ssl, const unsigned char *buf, size_t
60586058
return ret;
60596059
}
60606060

6061+
#if defined(MBEDTLS_SSL_EARLY_DATA) && defined(MBEDTLS_SSL_CLI_C)
6062+
int mbedtls_ssl_write_early_data(mbedtls_ssl_context *ssl,
6063+
const unsigned char *buf, size_t len)
6064+
{
6065+
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
6066+
const struct mbedtls_ssl_config *conf;
6067+
int written_data_len = 0;
6068+
6069+
MBEDTLS_SSL_DEBUG_MSG(2, ("=> write early_data"));
6070+
6071+
if (ssl == NULL || (conf = ssl->conf) == NULL) {
6072+
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
6073+
}
6074+
6075+
if (conf->endpoint != MBEDTLS_SSL_IS_CLIENT) {
6076+
return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
6077+
}
6078+
6079+
if ((!mbedtls_ssl_conf_is_tls13_enabled(conf)) ||
6080+
(conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM) ||
6081+
(conf->early_data_enabled != MBEDTLS_SSL_EARLY_DATA_ENABLED)) {
6082+
return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA;
6083+
}
6084+
6085+
if (ssl->tls_version != MBEDTLS_SSL_VERSION_TLS1_3) {
6086+
return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA;
6087+
}
6088+
6089+
/*
6090+
* If we are at the beginning of the handshake, the early data status being
6091+
* equal to MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN or
6092+
* MBEDTLS_SSL_EARLY_DATA_STATUS_SENT advance the handshake just
6093+
* enough to be able to send early data if possible. That way, we can
6094+
* guarantee that when starting the handshake with this function we will
6095+
* send at least one record of early data. Note that when the status is
6096+
* MBEDTLS_SSL_EARLY_DATA_STATUS_SENT and not yet
6097+
* MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE, we cannot send early data yet
6098+
* as the early data outbound transform has not been set as we may have to
6099+
* first send a dummy CCS in clear.
6100+
*/
6101+
if ((ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN) ||
6102+
(ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_SENT)) {
6103+
while ((ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_UNKNOWN) ||
6104+
(ssl->early_data_status == MBEDTLS_SSL_EARLY_DATA_STATUS_SENT)) {
6105+
ret = mbedtls_ssl_handshake_step(ssl);
6106+
if (ret != 0) {
6107+
MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_handshake_step", ret);
6108+
return ret;
6109+
}
6110+
6111+
ret = mbedtls_ssl_flush_output(ssl);
6112+
if (ret != 0) {
6113+
MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_flush_output", ret);
6114+
return ret;
6115+
}
6116+
}
6117+
} else {
6118+
/*
6119+
* If we are past the point where we can send early data, return
6120+
* immediatly. Otherwise, progress the handshake as much as possible to
6121+
* not delay it too much. If we reach a point where we can still send
6122+
* early data, then we will send some.
6123+
*/
6124+
if ((ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE) &&
6125+
(ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED)) {
6126+
return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA;
6127+
}
6128+
6129+
ret = mbedtls_ssl_handshake(ssl);
6130+
if ((ret != 0) && (ret != MBEDTLS_ERR_SSL_WANT_READ)) {
6131+
MBEDTLS_SSL_DEBUG_RET(1, "mbedtls_ssl_handshake", ret);
6132+
return ret;
6133+
}
6134+
}
6135+
6136+
if ((ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_CAN_WRITE) &&
6137+
(ssl->early_data_status != MBEDTLS_SSL_EARLY_DATA_STATUS_ACCEPTED)) {
6138+
return MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA;
6139+
}
6140+
6141+
written_data_len = ssl_write_real(ssl, buf, len);
6142+
6143+
MBEDTLS_SSL_DEBUG_MSG(2, ("<= write early_data, len=%d", written_data_len));
6144+
6145+
return written_data_len;
6146+
}
6147+
#endif /* MBEDTLS_SSL_EARLY_DATA && MBEDTLS_SSL_CLI_C */
6148+
60616149
/*
60626150
* Notify the peer that the connection is being closed
60636151
*/

0 commit comments

Comments
 (0)