diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 597f77380d..d2f9fc6daa 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -1629,6 +1629,12 @@ long SSL_callback_ctrl(SSL *, int, void (*)(void)); long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg); long SSL_CTX_callback_ctrl(SSL_CTX *, int, void (*)(void)); +# define SSL_EARLY_DATA_NOT_SENT 0 +# define SSL_EARLY_DATA_REJECTED 1 +# define SSL_EARLY_DATA_ACCEPTED 2 + +__owur int SSL_get_early_data_status(SSL *s); + __owur int SSL_get_error(const SSL *s, int ret_code); __owur const char *SSL_get_version(const SSL *s); @@ -2374,6 +2380,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_STOC_CERTIFICATE 374 # define SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG 452 # define SSL_F_TLS_CONSTRUCT_STOC_DONE 375 +# define SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA 531 # define SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA_INFO 525 # define SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS 453 # define SSL_F_TLS_CONSTRUCT_STOC_EMS 454 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 0620966172..d896ff9e58 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -362,6 +362,8 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_CRYPTOPRO_BUG), "tls_construct_stoc_cryptopro_bug"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_DONE), "TLS_CONSTRUCT_STOC_DONE"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA), + "tls_construct_stoc_early_data"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA_INFO), "tls_construct_stoc_early_data_info"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_STOC_EC_PT_FORMATS), diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index e3e7853d60..a774452a61 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1663,6 +1663,11 @@ int ssl_end_of_early_data_seen(SSL *s) return 0; } +int SSL_get_early_data_status(SSL *s) +{ + return s->ext.early_data; +} + static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes) { if (s->handshake_func == NULL) { diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index db1d7cfad3..3175009d80 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1182,8 +1182,8 @@ struct ssl_st { /* Set to one if we have negotiated ETM */ int use_etm; - /* Set to 1 if we are expecting to receive early data */ - int expect_early_data; + /* Are we expecting to receive early data? */ + int early_data; } ext; /* Parsed form of the ClientHello, kept around across early_cb calls. */ diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index ccc60b6a26..f8bd47a1e0 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -138,7 +138,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { { TLSEXT_TYPE_early_data, EXT_CLIENT_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS, - NULL, tls_parse_ctos_early_data, NULL, NULL, + NULL, tls_parse_ctos_early_data, NULL, tls_construct_stoc_early_data, tls_construct_ctos_early_data, NULL }, #ifndef OPENSSL_NO_EC diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 8994ab9cc1..57f38738d8 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -170,7 +170,18 @@ int tls_parse_ctos_early_data(SSL *s, PACKET *pkt, unsigned int context, return 0; } - s->ext.expect_early_data = 1; + if (s->max_early_data == 0 || !s->hit || s->session->ext.tick_identity != 0 + || s->early_data_state != SSL_EARLY_DATA_ACCEPTING) { + s->ext.early_data = SSL_EARLY_DATA_REJECTED; + } else { + s->ext.early_data = SSL_EARLY_DATA_ACCEPTED; + + if (!tls13_change_cipher_state(s, + SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_SERVER_READ)) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + } return 1; } @@ -832,6 +843,22 @@ int tls_construct_stoc_early_data_info(SSL *s, WPACKET *pkt, return 1; } +int tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, unsigned int context, + X509 *x, size_t chainidx, int *al) +{ + if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED) + return 1; + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_close(pkt)) { + SSLerr(SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + #ifndef OPENSSL_NO_EC int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al) diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 26c9273210..9c74a2932e 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -154,7 +154,7 @@ void ossl_statem_set_in_handshake(SSL *s, int inhand) /* Are we in a sensible state to skip over unreadable early data? */ int ossl_statem_skip_early_data(SSL *s) { - if (!s->ext.expect_early_data) + if (s->ext.early_data != SSL_EARLY_DATA_REJECTED) return 0; if (s->statem.hand_state != TLS_ST_SW_FINISHED) diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index e70ed10932..4f4409300e 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -714,7 +714,7 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst) */ if (!tls13_change_cipher_state(s, SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_CLIENT_WRITE)) - return WORK_ERROR; + return WORK_ERROR; } break; diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index 02c367910b..9dc9b1f515 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -235,6 +235,8 @@ int tls_construct_stoc_server_name(SSL *s, WPACKET *pkt, unsigned int context, int tls_construct_stoc_early_data_info(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al); +int tls_construct_stoc_early_data(SSL *s, WPACKET *pkt, unsigned int context, + X509 *x, size_t chainidx, int *al); #ifndef OPENSSL_NO_EC int tls_construct_stoc_ec_pt_formats(SSL *s, WPACKET *pkt, unsigned int context, X509 *x, size_t chainidx, int *al); diff --git a/util/libssl.num b/util/libssl.num index 8d1f0b88b7..1d59a60dd0 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -431,3 +431,4 @@ SSL_CTX_get_max_early_data 431 1_1_1 EXIST::FUNCTION: SSL_write_early 432 1_1_1 EXIST::FUNCTION: SSL_write_early_finish 433 1_1_1 EXIST::FUNCTION: SSL_read_early 434 1_1_1 EXIST::FUNCTION: +SSL_get_early_data_status 435 1_1_1 EXIST::FUNCTION: