Various fixes required to allow SSL_write/SSL_read during early data
[openssl.git] / ssl / ssl_lib.c
index b36e4a7eafddbf809681ac4eb2454e9099510f4c..baeb3bbec80c2a7b88166b3ac6b895c907cd004b 100644 (file)
@@ -1545,6 +1545,17 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
         return 0;
     }
 
+    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;
         int ret;
@@ -1639,7 +1650,6 @@ int SSL_read_early(SSL *s, void *buf, size_t num, size_t *readbytes)
             s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
         }
         *readbytes = 0;
-        ossl_statem_set_in_init(s, 1);
         return SSL_READ_EARLY_FINISH;
 
     default:
@@ -1650,7 +1660,8 @@ int SSL_read_early(SSL *s, void *buf, size_t num, size_t *readbytes)
 
 int ssl_end_of_early_data_seen(SSL *s)
 {
-    if (s->early_data_state == SSL_EARLY_DATA_READING) {
+    if (s->early_data_state == SSL_EARLY_DATA_READING
+            || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
         s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
         ossl_statem_finish_early_data(s);
         return 1;
@@ -1737,9 +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_WRITE_RETRY
-            || s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY)
+    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;
@@ -1801,7 +1823,9 @@ int SSL_write_early(SSL *s, const void *buf, size_t num, size_t *written)
 
     switch (s->early_data_state) {
     case SSL_EARLY_DATA_NONE:
-        if (!SSL_in_before(s)) {
+        if (!SSL_in_before(s)
+                || s->session == NULL
+                || s->session->ext.max_early_data == 0) {
             SSLerr(SSL_F_SSL_WRITE_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
             return 0;
         }
@@ -3219,8 +3243,20 @@ int SSL_do_handshake(SSL *s)
     }
 
     if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY
-            || s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY)
-        return -1;
+            || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) {
+        /*
+         * We skip this if we were called via SSL_read_early() or
+         * SSL_write_early()
+         */
+        if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+            int edfin;
+
+            edfin = SSL_write_early_finish(s);
+            if (edfin <= 0)
+                return edfin;
+        }
+        ossl_statem_set_in_init(s, 1);
+    }
 
     s->method->ssl_renegotiate_check(s, 0);