[openssl-commits] [openssl] master update
Matt Caswell
matt at openssl.org
Fri Jul 6 08:30:40 UTC 2018
The branch master has been updated
via 2ce71b60272325c4453914b501a2c2ff1b75c80d (commit)
via bafe9cf5e34e194f299762c270843781003a84ca (commit)
via 0d1b778901764f9bc747674f0e23b40c82877e6e (commit)
via 4e8548e80e12ee73db77417ea159c58751bf4b06 (commit)
from 2ddee136ec4157598b0679f9d5a5097ed77c4c01 (commit)
- Log -----------------------------------------------------------------
commit 2ce71b60272325c4453914b501a2c2ff1b75c80d
Author: Matt Caswell <matt at openssl.org>
Date: Thu Jul 5 16:53:56 2018 +0100
Document SSL_CTX_set_recv_max_early_data() etc
Reviewed-by: Paul Dale <paul.dale at oracle.com>
(Merged from https://github.com/openssl/openssl/pull/6655)
commit bafe9cf5e34e194f299762c270843781003a84ca
Author: Matt Caswell <matt at openssl.org>
Date: Thu Jul 5 15:42:36 2018 +0100
Add the ability to configure recv_max_early_data via s_server
Reviewed-by: Paul Dale <paul.dale at oracle.com>
(Merged from https://github.com/openssl/openssl/pull/6655)
commit 0d1b778901764f9bc747674f0e23b40c82877e6e
Author: Matt Caswell <matt at openssl.org>
Date: Thu Jul 5 15:31:51 2018 +0100
Add a test for the recv_max_early_data setting
Reviewed-by: Paul Dale <paul.dale at oracle.com>
(Merged from https://github.com/openssl/openssl/pull/6655)
commit 4e8548e80e12ee73db77417ea159c58751bf4b06
Author: Matt Caswell <matt at openssl.org>
Date: Thu Jul 5 14:40:39 2018 +0100
Introduce the recv_max_early_data setting
Previoulsy we just had max_early_data which controlled both the value of
max early_data that we advertise in tickets *and* the amount of early_data
that we are willing to receive from clients. This doesn't work too well in
the case where we want to reduce a previously advertised max_early_data
value. In that case clients with old, stale tickets may attempt to send us
more early data than we are willing to receive. Instead of rejecting the
early data we abort the connection if that happens.
To avoid this we introduce a new "recv_max_early_data" value. The old
max_early_data becomes the value that is advertised in tickets while
recv_max_early_data is the maximum we will tolerate from clients.
Fixes #6647
Reviewed-by: Paul Dale <paul.dale at oracle.com>
(Merged from https://github.com/openssl/openssl/pull/6655)
-----------------------------------------------------------------------
Summary of changes:
apps/s_server.c | 19 ++++++++++++++----
doc/man3/SSL_read_early_data.pod | 33 ++++++++++++++++++++++++++++---
include/openssl/ssl.h | 4 ++++
ssl/record/ssl3_record.c | 11 ++++++++---
ssl/ssl_lib.c | 35 +++++++++++++++++++++++++++++++++
ssl/ssl_locl.h | 22 +++++++++++++++++++--
test/sslapitest.c | 42 +++++++++++++++++++++++++++++++++++-----
util/libssl.num | 4 ++++
8 files changed, 153 insertions(+), 17 deletions(-)
diff --git a/apps/s_server.c b/apps/s_server.c
index b050200..4e8a9e2 100644
--- a/apps/s_server.c
+++ b/apps/s_server.c
@@ -748,8 +748,8 @@ typedef enum OPTION_choice {
OPT_ID_PREFIX, OPT_SERVERNAME, OPT_SERVERNAME_FATAL,
OPT_CERT2, OPT_KEY2, OPT_NEXTPROTONEG, OPT_ALPN,
OPT_SRTP_PROFILES, OPT_KEYMATEXPORT, OPT_KEYMATEXPORTLEN,
- OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_EARLY_DATA, OPT_S_NUM_TICKETS,
- OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY,
+ OPT_KEYLOG_FILE, OPT_MAX_EARLY, OPT_RECV_MAX_EARLY, OPT_EARLY_DATA,
+ OPT_S_NUM_TICKETS, OPT_ANTI_REPLAY, OPT_NO_ANTI_REPLAY,
OPT_R_ENUM,
OPT_S_ENUM,
OPT_V_ENUM,
@@ -955,7 +955,9 @@ const OPTIONS s_server_options[] = {
#endif
{"keylogfile", OPT_KEYLOG_FILE, '>', "Write TLS secrets to file"},
{"max_early_data", OPT_MAX_EARLY, 'n',
- "The maximum number of bytes of early data"},
+ "The maximum number of bytes of early data as advertised in tickets"},
+ {"recv_max_early_data", OPT_RECV_MAX_EARLY, 'n',
+ "The maximum number of bytes of early data (hard limit)"},
{"early_data", OPT_EARLY_DATA, '-', "Attempt to read early data"},
{"num_tickets", OPT_S_NUM_TICKETS, 'n',
"The number of TLSv1.3 session tickets that a server will automatically issue" },
@@ -1041,7 +1043,7 @@ int s_server_main(int argc, char *argv[])
unsigned int split_send_fragment = 0, max_pipelines = 0;
const char *s_serverinfo_file = NULL;
const char *keylog_file = NULL;
- int max_early_data = -1;
+ int max_early_data = -1, recv_max_early_data = -1;
char *psksessf = NULL;
/* Init of few remaining global variables */
@@ -1570,6 +1572,13 @@ int s_server_main(int argc, char *argv[])
goto end;
}
break;
+ case OPT_RECV_MAX_EARLY:
+ recv_max_early_data = atoi(opt_arg());
+ if (recv_max_early_data < 0) {
+ BIO_printf(bio_err, "Invalid value for recv_max_early_data\n");
+ goto end;
+ }
+ break;
case OPT_EARLY_DATA:
early_data = 1;
if (max_early_data == -1)
@@ -2110,6 +2119,8 @@ int s_server_main(int argc, char *argv[])
if (max_early_data >= 0)
SSL_CTX_set_max_early_data(ctx, max_early_data);
+ if (recv_max_early_data >= 0)
+ SSL_CTX_set_recv_max_early_data(ctx, recv_max_early_data);
if (rev)
server_cb = rev_body;
diff --git a/doc/man3/SSL_read_early_data.pod b/doc/man3/SSL_read_early_data.pod
index cf6f757..27c127d 100644
--- a/doc/man3/SSL_read_early_data.pod
+++ b/doc/man3/SSL_read_early_data.pod
@@ -6,6 +6,10 @@ SSL_set_max_early_data,
SSL_CTX_set_max_early_data,
SSL_get_max_early_data,
SSL_CTX_get_max_early_data,
+SSL_set_recv_max_early_data,
+SSL_CTX_set_recv_max_early_data,
+SSL_get_recv_max_early_data,
+SSL_CTX_get_recv_max_early_data,
SSL_SESSION_get_max_early_data,
SSL_SESSION_set_max_early_data,
SSL_write_early_data,
@@ -24,6 +28,12 @@ SSL_set_allow_early_data_cb
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);
+
uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *s);
int SSL_SESSION_set_max_early_data(SSL_SESSION *s, uint32_t max_early_data);
@@ -195,9 +205,26 @@ since there is no practical benefit from using only one of them. If the maximum
early data setting for a server is non-zero then replay protection is
automatically enabled (see L</REPLAY PROTECTION> below).
-In the event that the current maximum early data setting for the server is
-different to that originally specified in a session that a client is resuming
-with then the lower of the two values will apply.
+If the server rejects the early data sent by a client then it will skip over
+the data that is sent. The maximum amount of received early data that is skipped
+is controlled by the recv_max_early_data setting. If a client sends more than
+this then the connection will abort. This value can be set by calling
+SSL_CTX_set_recv_max_early_data() or SSL_set_recv_max_early_data(). The current
+value for this setting can be obtained by calling
+SSL_CTX_get_recv_max_early_data() or SSL_get_recv_max_early_data(). The default
+value for this setting is 16,384 bytes.
+
+The recv_max_early_data value also has an impact on early data that is accepted.
+The amount of data that is accepted will always be the lower of the
+max_early_data for the session and the recv_max_early_data setting for the
+server. If a client sends more data than this then the connection will abort.
+
+The configured value for max_early_data on a server may change over time as
+required. However clients may have tickets containing the previously configured
+max_early_data value. The recv_max_early_data should always be equal to or
+higher than any recently configured max_early_data value in order to avoid
+aborted connections. The recv_max_early_data should never be set to less than
+the current configured max_early_data value.
Some server applications may wish to have more control over whether early data
is accepted or not, for example to mitigate replay risks (see L</REPLAY PROTECTION>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index bbcfb3c..2376828 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 ae510b2..ad478bf 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 1387067..38391fd 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 6a2edeb..0bf3f16 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,9 +1415,18 @@ 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
* this is a count of the ciphertext bytes.
diff --git a/test/sslapitest.c b/test/sslapitest.c
index 64f8f59..cdac8bc 100644
--- a/test/sslapitest.c
+++ b/test/sslapitest.c
@@ -2314,8 +2314,11 @@ static int test_early_data_replay(int idx)
/*
* Helper function to test that a server attempting to read early data can
* handle a connection from a client where the early data should be skipped.
+ * testtype: 0 == No HRR
+ * testtype: 1 == HRR
+ * testtype: 2 == recv_max_early_data set to 0
*/
-static int early_data_skip_helper(int hrr, int idx)
+static int early_data_skip_helper(int testtype, int idx)
{
SSL_CTX *cctx = NULL, *sctx = NULL;
SSL *clientssl = NULL, *serverssl = NULL;
@@ -2328,7 +2331,7 @@ static int early_data_skip_helper(int hrr, int idx)
&serverssl, &sess, idx)))
goto end;
- if (hrr) {
+ if (testtype == 1) {
/* Force an HRR to occur */
if (!TEST_true(SSL_set1_groups_list(serverssl, "P-256")))
goto end;
@@ -2348,13 +2351,17 @@ static int early_data_skip_helper(int hrr, int idx)
goto end;
}
+ if (testtype == 2
+ && !TEST_true(SSL_set_recv_max_early_data(serverssl, 0)))
+ goto end;
+
/* Write some early data */
if (!TEST_true(SSL_write_early_data(clientssl, MSG1, strlen(MSG1),
&written))
|| !TEST_size_t_eq(written, strlen(MSG1)))
goto end;
- /* Server should reject the early data and skip over it */
+ /* Server should reject the early data */
if (!TEST_int_eq(SSL_read_early_data(serverssl, buf, sizeof(buf),
&readbytes),
SSL_READ_EARLY_DATA_FINISH)
@@ -2363,7 +2370,7 @@ static int early_data_skip_helper(int hrr, int idx)
SSL_EARLY_DATA_REJECTED))
goto end;
- if (hrr) {
+ if (testtype == 1) {
/*
* Finish off the handshake. We perform the same writes and reads as
* further down but we expect them to fail due to the incomplete
@@ -2373,9 +2380,24 @@ static int early_data_skip_helper(int hrr, int idx)
|| !TEST_false(SSL_read_ex(serverssl, buf, sizeof(buf),
&readbytes)))
goto end;
+ } else if (testtype == 2) {
+ /*
+ * This client has sent more early_data than we are willing to skip so
+ * the connection should abort.
+ */
+ if (!TEST_false(SSL_read_ex(serverssl, buf, sizeof(buf), &readbytes))
+ || !TEST_int_eq(SSL_get_error(serverssl, 0), SSL_ERROR_SSL))
+ goto end;
+
+ /* Connection has failed - nothing more to do */
+ testresult = 1;
+ goto end;
}
- /* Should be able to send normal data despite rejection of early data */
+ /*
+ * Should be able to send normal data despite rejection of early data. The
+ * early_data should be skipped.
+ */
if (!TEST_true(SSL_write_ex(clientssl, MSG2, strlen(MSG2), &written))
|| !TEST_size_t_eq(written, strlen(MSG2))
|| !TEST_int_eq(SSL_get_early_data_status(clientssl),
@@ -2417,6 +2439,15 @@ static int test_early_data_skip_hrr(int idx)
}
/*
+ * Test that a server attempting to read early data will abort if it tries to
+ * skip over too much.
+ */
+static int test_early_data_skip_abort(int idx)
+{
+ return early_data_skip_helper(2, idx);
+}
+
+/*
* Test that a server attempting to read early data can handle a connection
* from a client that doesn't send any.
*/
@@ -5267,6 +5298,7 @@ int setup_tests(void)
ADD_ALL_TESTS(test_early_data_replay, 2);
ADD_ALL_TESTS(test_early_data_skip, 3);
ADD_ALL_TESTS(test_early_data_skip_hrr, 3);
+ ADD_ALL_TESTS(test_early_data_skip_abort, 3);
ADD_ALL_TESTS(test_early_data_not_sent, 3);
ADD_ALL_TESTS(test_early_data_psk, 8);
ADD_ALL_TESTS(test_early_data_not_expected, 3);
diff --git a/util/libssl.num b/util/libssl.num
index df6a71e..9b6d266 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:
More information about the openssl-commits
mailing list