]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Provide an SSL_read_early() function for reading early data
authorMatt Caswell <matt@openssl.org>
Tue, 21 Feb 2017 17:14:42 +0000 (17:14 +0000)
committerMatt Caswell <matt@openssl.org>
Thu, 2 Mar 2017 17:44:15 +0000 (17:44 +0000)
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)

include/openssl/ssl.h
ssl/record/rec_layer_s3.c
ssl/record/ssl3_record.c
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/statem/statem.c
ssl/statem/statem_clnt.c
ssl/statem/statem_lib.c
ssl/statem/statem_srvr.c
util/libssl.num

index 40965e64506e76863615615fd091b7010cefce0a..597f77380da11c60fd1f87dc38804ca44c1a83c6 100644 (file)
@@ -1611,6 +1611,12 @@ __owur int SSL_accept(SSL *ssl);
 __owur int SSL_connect(SSL *ssl);
 __owur int SSL_read(SSL *ssl, void *buf, int num);
 __owur int SSL_read_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
+
+# define SSL_READ_EARLY_ERROR   0
+# define SSL_READ_EARLY_SUCCESS 1
+# define SSL_READ_EARLY_FINISH  2
+
+__owur int SSL_read_early(SSL *s, void *buf, size_t num, size_t *readbytes);
 __owur int SSL_peek(SSL *ssl, void *buf, int num);
 __owur int SSL_peek_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
 __owur int SSL_write(SSL *ssl, const void *buf, int num);
@@ -2255,6 +2261,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_SSL_PEEK_EX                                432
 # define SSL_F_SSL_PEEK_INTERNAL                          522
 # define SSL_F_SSL_READ                                   223
+# define SSL_F_SSL_READ_EARLY                             529
 # define SSL_F_SSL_READ_EX                                434
 # define SSL_F_SSL_READ_INTERNAL                          523
 # define SSL_F_SSL_RENEGOTIATE                            516
@@ -2330,7 +2337,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY                489
 # define SSL_F_TLS_CONSTRUCT_CTOS_ALPN                    466
 # define SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE             355
-# define SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA              521
+# define SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA              530
 # define SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS           467
 # define SSL_F_TLS_CONSTRUCT_CTOS_EMS                     468
 # define SSL_F_TLS_CONSTRUCT_CTOS_ETM                     469
@@ -2669,6 +2676,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS       239
 # define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES           242
 # define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES          243
+# define SSL_R_UNEXPECTED_END_OF_EARLY_DATA               178
 # define SSL_R_UNEXPECTED_MESSAGE                         244
 # define SSL_R_UNEXPECTED_RECORD                          245
 # define SSL_R_UNINITIALIZED                              276
index d7b98e055b06d288396777e0e99a683ba0299c8f..6fa272c77a465ceaab2e557c7bde63a78f0565f6 100644 (file)
@@ -1437,6 +1437,14 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
                 al = SSL_AD_HANDSHAKE_FAILURE;
                 SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_NO_RENEGOTIATION);
                 goto f_err;
+            } else if (alert_descr == SSL_AD_END_OF_EARLY_DATA) {
+                if (!ssl_end_of_early_data_seen(s)) {
+                    al = SSL_AD_UNEXPECTED_MESSAGE;
+                    SSLerr(SSL_F_SSL3_READ_BYTES,
+                           SSL_R_UNEXPECTED_END_OF_EARLY_DATA);
+                    goto f_err;
+                }
+                return 0;
             }
         } else if (alert_level == SSL3_AL_FATAL) {
             char tmp[16];
index 4a1c0413a145669f0dae1b52f5a166138022d20b..94c221f558ba6bbc06fbbb95b7f9e5054f24d104 100644 (file)
@@ -419,15 +419,15 @@ int ssl3_get_record(SSL *s)
 
     /*-
      * enc_err is:
-     *    0: (in non-constant time) if the record is publically invalid.
+     *    0: (in non-constant time) if the record is publicly invalid.
      *    1: if the padding is valid
      *    -1: if the padding is invalid
      */
     if (enc_err == 0) {
         if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
             /*
-             * We assume this is unreadable early_data - we treat it like an
-             * empty record
+             * Valid early_data that we cannot decrypt might fail here as
+             * publicly invalid. We treat it like an empty record.
              */
             thisrr = &rr[0];
             thisrr->length = 0;
@@ -507,6 +507,17 @@ int ssl3_get_record(SSL *s)
     }
 
     if (enc_err < 0) {
+        if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
+            /*
+             * We assume this is unreadable early_data - we treat it like an
+             * empty record
+             */
+            thisrr = &rr[0];
+            thisrr->length = 0;
+            thisrr->read = 1;
+            RECORD_LAYER_set_numrpipes(&s->rlayer, 1);
+            return 1;
+        }
         /*
          * A separate 'decryption_failed' alert was introduced with TLS 1.0,
          * SSL 3.0 only has 'bad_record_mac'.  But unless a decryption
index c6cc375643e88dda4129147effe0ce3abf32efe6..0620966172ad409b2f7cc0cbe506b5c98f036e36 100644 (file)
@@ -205,6 +205,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_SSL_PEEK_EX), "SSL_peek_ex"},
     {ERR_FUNC(SSL_F_SSL_PEEK_INTERNAL), "ssl_peek_internal"},
     {ERR_FUNC(SSL_F_SSL_READ), "SSL_read"},
+    {ERR_FUNC(SSL_F_SSL_READ_EARLY), "SSL_read_early"},
     {ERR_FUNC(SSL_F_SSL_READ_EX), "SSL_read_ex"},
     {ERR_FUNC(SSL_F_SSL_READ_INTERNAL), "ssl_read_internal"},
     {ERR_FUNC(SSL_F_SSL_RENEGOTIATE), "SSL_renegotiate"},
@@ -793,6 +794,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
      "unable to load ssl3 md5 routines"},
     {ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES),
      "unable to load ssl3 sha1 routines"},
+    {ERR_REASON(SSL_R_UNEXPECTED_END_OF_EARLY_DATA),
+     "unexpected end of early data"},
     {ERR_REASON(SSL_R_UNEXPECTED_MESSAGE), "unexpected message"},
     {ERR_REASON(SSL_R_UNEXPECTED_RECORD), "unexpected record"},
     {ERR_REASON(SSL_R_UNINITIALIZED), "uninitialized"},
index 8e28786447c86feeb0e1dd0c432f54969a33ddc5..e3e7853d602997103ff1365d4ee8b8c38ef406f9 100644 (file)
@@ -1594,6 +1594,75 @@ int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
     return ret;
 }
 
+int SSL_read_early(SSL *s, void *buf, size_t num, size_t *readbytes)
+{
+    int ret;
+
+    if (!s->server) {
+        SSLerr(SSL_F_SSL_READ_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return SSL_READ_EARLY_ERROR;
+    }
+
+    /*
+     * TODO(TLS1.3): Somehow we need to check that we're not receiving too much
+     * data
+     */
+
+    switch (s->early_data_state) {
+    case SSL_EARLY_DATA_NONE:
+        if (!SSL_in_before(s)) {
+            SSLerr(SSL_F_SSL_READ_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+            return SSL_READ_EARLY_ERROR;
+        }
+        /* fall through */
+
+    case SSL_EARLY_DATA_ACCEPT_RETRY:
+        s->early_data_state = SSL_EARLY_DATA_ACCEPTING;
+        ret = SSL_accept(s);
+        if (ret <= 0) {
+            /* NBIO or error */
+            s->early_data_state = SSL_EARLY_DATA_ACCEPT_RETRY;
+            return SSL_READ_EARLY_ERROR;
+        }
+        /* fall through */
+
+    case SSL_EARLY_DATA_READ_RETRY:
+        if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+            s->early_data_state = SSL_EARLY_DATA_READING;
+            ret = SSL_read_ex(s, buf, num, readbytes);
+            /*
+             * Record layer will call ssl_end_of_early_data_seen() if we see
+             * that alert - which updates the early_data_state to
+             * SSL_EARLY_DATA_FINISHED_READING
+             */
+            if (ret > 0 || (ret <= 0 && s->early_data_state
+                                        != SSL_EARLY_DATA_FINISHED_READING)) {
+                s->early_data_state = SSL_EARLY_DATA_READ_RETRY;
+                return ret > 0 ? SSL_READ_EARLY_SUCCESS : SSL_READ_EARLY_ERROR;
+            }
+        } else {
+            s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+        }
+        *readbytes = 0;
+        ossl_statem_set_in_init(s, 1);
+        return SSL_READ_EARLY_FINISH;
+
+    default:
+        SSLerr(SSL_F_SSL_READ_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return SSL_READ_EARLY_ERROR;
+    }
+}
+
+int ssl_end_of_early_data_seen(SSL *s)
+{
+    if (s->early_data_state == SSL_EARLY_DATA_READING) {
+        s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+        return 1;
+    }
+
+    return 0;
+}
+
 static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
 {
     if (s->handshake_func == NULL) {
index 7c8e3fad21f6d7c0bcf1e1e9e41eb7f909769f8a..db1d7cfad3e8b8a027779a8941110f1f0ebe422a 100644 (file)
@@ -618,7 +618,12 @@ typedef enum {
     SSL_EARLY_DATA_CONNECTING,
     SSL_EARLY_DATA_WRITE_RETRY,
     SSL_EARLY_DATA_WRITING,
-    SSL_EARLY_DATA_FINISHED_WRITING
+    SSL_EARLY_DATA_FINISHED_WRITING,
+    SSL_EARLY_DATA_ACCEPT_RETRY,
+    SSL_EARLY_DATA_ACCEPTING,
+    SSL_EARLY_DATA_READ_RETRY,
+    SSL_EARLY_DATA_READING,
+    SSL_EARLY_DATA_FINISHED_READING
 } SSL_EARLY_DATA_STATE;
 
 #define MAX_COMPRESSIONS_SIZE   255
@@ -1987,6 +1992,7 @@ static ossl_inline int ssl_has_cert(const SSL *s, int idx)
 
 # ifndef OPENSSL_UNIT_TEST
 
+int ssl_end_of_early_data_seen(SSL *s);
 __owur int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes);
 __owur int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written);
 void ssl_clear_cipher_ctx(SSL *s);
index 9ec8e85426763084dcf8c3234422f3f2237956d3..26c927321060de1113eb6da61b618feefabff931 100644 (file)
@@ -326,7 +326,8 @@ static int state_machine(SSL *s, int server)
             }
 
         if ((SSL_IS_FIRST_HANDSHAKE(s)
-                    && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING)
+                    && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING
+                    && s->early_data_state != SSL_EARLY_DATA_FINISHED_READING)
                 || s->renegotiate) {
             if (!tls_setup_handshake(s)) {
                 ossl_statem_set_error(s);
index 390e475fa4d6f140ba5a4648d7328464885e6e93..e70ed10932b28f7c163e737fd9acad04ff37e44b 100644 (file)
@@ -1229,12 +1229,6 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
     SSL_COMP *comp;
 #endif
 
-    /*
-     * This is a real handshake so make sure we clean it up at the end. We set
-     * this here so that we are after any early_data
-     */
-    s->statem.cleanuphand = 1;
-
     if (!PACKET_get_net_2(pkt, &sversion)) {
         al = SSL_AD_DECODE_ERROR;
         SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
index ed1ecce160e8302251713cb1d400bc9d11d98d20..dec8cb3e3803b9f9d49eb492b483ec4e06eaec66 100644 (file)
@@ -654,6 +654,10 @@ MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
     int al = SSL_AD_INTERNAL_ERROR;
     size_t md_len;
 
+
+    /* This is a real handshake so make sure we clean it up at the end */
+    s->statem.cleanuphand = 1;
+
     /* If this occurs, we have missed a message */
     if (!SSL_IS_TLS13(s) && !s->s3->change_cipher_spec) {
         al = SSL_AD_UNEXPECTED_MESSAGE;
@@ -944,6 +948,7 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs)
             s->d1->next_handshake_write_seq = 0;
             dtls1_clear_received_buffer(s);
         }
+        s->early_data_state = SSL_EARLY_DATA_NONE;
     }
 
     /*
index 39e0f59833f2b0744d071cc90bdf3151c3dacdeb..3d2d39b33d31a42a4a64181d5f19daf6ae36babd 100644 (file)
@@ -406,6 +406,10 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
         return WRITE_TRAN_ERROR;
 
     case TLS_ST_OK:
+        if (s->early_data_state == SSL_EARLY_DATA_FINISHED_READING) {
+            st->hand_state = TLS_ST_SW_FINISHED;
+            return WRITE_TRAN_FINISHED;
+        }
         if (s->key_update != SSL_KEY_UPDATE_NONE) {
             st->hand_state = TLS_ST_SW_KEY_UPDATE;
             return WRITE_TRAN_CONTINUE;
@@ -450,6 +454,11 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
         return WRITE_TRAN_CONTINUE;
 
     case TLS_ST_SW_FINISHED:
+        if (s->early_data_state == SSL_EARLY_DATA_ACCEPTING) {
+            st->hand_state = TLS_ST_OK;
+            ossl_statem_set_in_init(s, 0);
+            return WRITE_TRAN_CONTINUE;
+        }
         return WRITE_TRAN_FINISHED;
 
     case TLS_ST_SR_FINISHED:
@@ -1234,9 +1243,6 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         s->new_session = 1;
     }
 
-    /* This is a real handshake so make sure we clean it up at the end */
-    s->statem.cleanuphand = 1;
-
     /*
      * First, parse the raw ClientHello data into the CLIENTHELLO_MSG structure.
      */
index 52ae727b373c0a5590012419045b8feb143c7e63..8d1f0b88b77995456039aee28012e9742661cc26 100644 (file)
@@ -430,3 +430,4 @@ SSL_get_max_early_data                  430 1_1_1   EXIST::FUNCTION:
 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: