Enable the client to call SSL_read() without stopping the ability to call SSL_write_e...
authorMatt Caswell <matt@openssl.org>
Sat, 25 Feb 2017 15:34:07 +0000 (15:34 +0000)
committerMatt Caswell <matt@openssl.org>
Thu, 2 Mar 2017 17:44:16 +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/ssl_lib.c
ssl/statem/statem.c
ssl/statem/statem.h
ssl/statem/statem_clnt.c

index 860edba4cf2efcf22e8a8b039faaafac973e3af8..dabcc4a6a211fa5a0a9960f9b5fb54e052ef973e 100644 (file)
@@ -900,7 +900,8 @@ typedef enum {
     TLS_ST_CW_KEY_UPDATE,
     TLS_ST_SR_KEY_UPDATE,
     TLS_ST_CR_KEY_UPDATE,
-    TLS_ST_CW_EARLY_DATA
+    TLS_ST_CW_EARLY_DATA,
+    TLS_ST_CW_PENDING_EARLY_DATA_END
 } OSSL_HANDSHAKE_STATE;
 
 /*
index 3bcb6e1643fb4c9f78d990fcaadb5c3a7c394a99..c244c3c27c8c07b0ffa58b536e4cb6a3de64cda0 100644 (file)
@@ -1545,13 +1545,16 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
         return 0;
     }
 
-    if (s->early_data_state != SSL_EARLY_DATA_NONE
-            && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING
-            && s->early_data_state != SSL_EARLY_DATA_FINISHED_READING
-            && s->early_data_state != SSL_EARLY_DATA_READING) {
+    if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
+                || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) {
         SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
         return 0;
     }
+    /*
+     * If we are a client and haven't received the ServerHello etc then we
+     * better do that
+     */
+    ossl_statem_check_finish_init(s, 0);
 
     if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
         struct ssl_async_args args;
@@ -1745,13 +1748,20 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
         return -1;
     }
 
-    if (s->early_data_state != SSL_EARLY_DATA_NONE
-            && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING
-            && s->early_data_state != SSL_EARLY_DATA_FINISHED_READING
-            && s->early_data_state != SSL_EARLY_DATA_WRITING) {
+    if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+        /*
+         * We're still writing early data. We need to stop that so we can write
+         * normal data
+         */
+        if (!SSL_write_early_finish(s))
+            return 0;
+    } else if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY
+                || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) {
         SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
         return 0;
     }
+    /* If we are a client and haven't sent the Finished we better do that */
+    ossl_statem_check_finish_init(s, 1);
 
     if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
         int ret;
index 2c202f4deb84ad2c4ed468f5491207e092929653..a1807f2a40dce3d489fa316edd789de29324b256 100644 (file)
@@ -168,6 +168,13 @@ int ossl_statem_skip_early_data(SSL *s)
     return 1;
 }
 
+void ossl_statem_check_finish_init(SSL *s, int send)
+{
+    if ((send && s->statem.hand_state == TLS_ST_CW_PENDING_EARLY_DATA_END)
+            || (!send && s->statem.hand_state == TLS_ST_CW_EARLY_DATA))
+        ossl_statem_set_in_init(s, 1);
+}
+
 void ossl_statem_set_hello_verify_done(SSL *s)
 {
     s->statem.state = MSG_FLOW_UNINITED;
index c0c9cab144d191d7cab5fce355a94292ada7b1cc..56009b0f8c1fdb2f150cfc46e9a8b719eac0c631 100644 (file)
@@ -123,6 +123,7 @@ void ossl_statem_set_in_init(SSL *s, int init);
 int ossl_statem_get_in_handshake(SSL *s);
 void ossl_statem_set_in_handshake(SSL *s, int inhand);
 __owur int ossl_statem_skip_early_data(SSL *s);
+void ossl_statem_check_finish_init(SSL *s, int send);
 void ossl_statem_set_hello_verify_done(SSL *s);
 __owur int ossl_statem_app_data_allowed(SSL *s);
 #ifndef OPENSSL_NO_SCTP
index 23a4d7663bfe11adffd8c5013e8a1279b70d15e2..6fdb37ec7a7ced95a8dacc80a7a5c11086f1013c 100644 (file)
@@ -435,6 +435,14 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
         return WRITE_TRAN_CONTINUE;
 
     case TLS_ST_CR_FINISHED:
+        if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY)
+            st->hand_state = TLS_ST_CW_PENDING_EARLY_DATA_END;
+        else
+            st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
+                                                        : TLS_ST_CW_FINISHED;
+        return WRITE_TRAN_CONTINUE;
+
+    case TLS_ST_CW_PENDING_EARLY_DATA_END:
         st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
                                                     : TLS_ST_CW_FINISHED;
         return WRITE_TRAN_CONTINUE;
@@ -659,6 +667,7 @@ WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst)
         break;
 
     case TLS_ST_CW_EARLY_DATA:
+    case TLS_ST_CW_PENDING_EARLY_DATA_END:
     case TLS_ST_OK:
         return tls_finish_handshake(s, wst, 1);
     }