diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index bbcfb3c0b3..2376828e70 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -919,6 +919,10 @@ int SSL_CTX_set_max_early_data(SSL_CTX *ctx, uint32_t max_early_data); uint32_t SSL_CTX_get_max_early_data(const SSL_CTX *ctx); int SSL_set_max_early_data(SSL *s, uint32_t max_early_data); uint32_t SSL_get_max_early_data(const SSL *s); +int SSL_CTX_set_recv_max_early_data(SSL_CTX *ctx, uint32_t recv_max_early_data); +uint32_t SSL_CTX_get_recv_max_early_data(const SSL_CTX *ctx); +int SSL_set_recv_max_early_data(SSL *s, uint32_t recv_max_early_data); +uint32_t SSL_get_recv_max_early_data(const SSL *s); #ifdef __cplusplus } diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index ae510b2ec9..ad478bf375 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -103,7 +103,7 @@ static int ssl3_record_app_data_waiting(SSL *s) int early_data_count_ok(SSL *s, size_t length, size_t overhead, int send) { - uint32_t max_early_data = s->max_early_data; + uint32_t max_early_data; SSL_SESSION *sess = s->session; /* @@ -120,9 +120,14 @@ int early_data_count_ok(SSL *s, size_t length, size_t overhead, int send) } sess = s->psksession; } - if (!s->server - || (s->hit && sess->ext.max_early_data < s->max_early_data)) + + if (!s->server) max_early_data = sess->ext.max_early_data; + else if (s->ext.early_data != SSL_EARLY_DATA_ACCEPTED) + max_early_data = s->recv_max_early_data; + else + max_early_data = s->recv_max_early_data < sess->ext.max_early_data + ? s->recv_max_early_data : sess->ext.max_early_data; if (max_early_data == 0) { SSLfatal(s, send ? SSL_AD_INTERNAL_ERROR : SSL_AD_UNEXPECTED_MESSAGE, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 1387067b30..38391fd2c0 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -700,6 +700,7 @@ SSL *SSL_new(SSL_CTX *ctx) s->mode = ctx->mode; s->max_cert_list = ctx->max_cert_list; s->max_early_data = ctx->max_early_data; + s->recv_max_early_data = ctx->recv_max_early_data; s->num_tickets = ctx->num_tickets; /* Shallow copy of the ciphersuites stack */ @@ -3039,6 +3040,16 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth) */ ret->max_early_data = 0; + /* + * Default recv_max_early_data is a fully loaded single record. Could be + * split across multiple records in practice. We set this differently to + * max_early_data so that, in the default case, we do not advertise any + * support for early_data, but if a client were to send us some (e.g. + * because of an old, stale ticket) then we will tolerate it and skip over + * it. + */ + ret->recv_max_early_data = SSL3_RT_MAX_PLAIN_LENGTH; + /* By default we send two session tickets automatically in TLSv1.3 */ ret->num_tickets = 2; @@ -5376,6 +5387,30 @@ uint32_t SSL_get_max_early_data(const SSL *s) return s->max_early_data; } +int SSL_CTX_set_recv_max_early_data(SSL_CTX *ctx, uint32_t recv_max_early_data) +{ + ctx->recv_max_early_data = recv_max_early_data; + + return 1; +} + +uint32_t SSL_CTX_get_recv_max_early_data(const SSL_CTX *ctx) +{ + return ctx->recv_max_early_data; +} + +int SSL_set_recv_max_early_data(SSL *s, uint32_t recv_max_early_data) +{ + s->recv_max_early_data = recv_max_early_data; + + return 1; +} + +uint32_t SSL_get_recv_max_early_data(const SSL *s) +{ + return s->recv_max_early_data; +} + __owur unsigned int ssl_get_max_send_fragment(const SSL *ssl) { /* Return any active Max Fragment Len extension */ diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 6a2edeb190..0bf3f16f35 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1032,9 +1032,18 @@ struct ssl_ctx_st { */ SSL_CTX_keylog_cb_func keylog_callback; - /* The maximum number of bytes that can be sent as early data */ + /* + * The maximum number of bytes advertised in session tickets that can be + * sent as early data. + */ uint32_t max_early_data; + /* + * The maximum number of bytes of early data that a server will tolerate + * (which should be at least as much as max_early_data). + */ + uint32_t recv_max_early_data; + /* TLS1.3 padding callback */ size_t (*record_padding_cb)(SSL *s, int type, size_t len, void *arg); void *record_padding_arg; @@ -1406,8 +1415,17 @@ struct ssl_st { ASYNC_WAIT_CTX *waitctx; size_t asyncrw; - /* The maximum number of plaintext bytes that can be sent as early data */ + /* + * The maximum number of bytes advertised in session tickets that can be + * sent as early data. + */ uint32_t max_early_data; + /* + * The maximum number of bytes of early data that a server will tolerate + * (which should be at least as much as max_early_data). + */ + uint32_t recv_max_early_data; + /* * The number of bytes of early data received so far. If we accepted early * data then this is a count of the plaintext bytes. If we rejected it then diff --git a/util/libssl.num b/util/libssl.num index df6a71e1b5..9b6d266144 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -492,3 +492,7 @@ SSL_get_num_tickets 492 1_1_1 EXIST::FUNCTION: SSL_CTX_set_num_tickets 493 1_1_1 EXIST::FUNCTION: SSL_CTX_set_allow_early_data_cb 494 1_1_1 EXIST::FUNCTION: SSL_set_allow_early_data_cb 495 1_1_1 EXIST::FUNCTION: +SSL_set_recv_max_early_data 496 1_1_1 EXIST::FUNCTION: +SSL_get_recv_max_early_data 497 1_1_1 EXIST::FUNCTION: +SSL_CTX_get_recv_max_early_data 498 1_1_1 EXIST::FUNCTION: +SSL_CTX_set_recv_max_early_data 499 1_1_1 EXIST::FUNCTION: