[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