Fix changing of the cipher state when dealing with early data
[openssl.git] / ssl / ssl_lib.c
index 72c101b5f0b18f5f193c5674eee2909b37802337..2f62f4b0e1bfa24854e54b1b1d5edc7d6e31d6ff 100644 (file)
@@ -551,6 +551,7 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->mode = ctx->mode;
     s->max_cert_list = ctx->max_cert_list;
     s->references = 1;
+    s->max_early_data = ctx->max_early_data;
 
     /*
      * Earlier library versions used to copy the pointer to the CERT, not
@@ -1593,6 +1594,81 @@ 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;
+        ossl_statem_finish_early_data(s);
+        return 1;
+    }
+
+    return 0;
+}
+
+int SSL_get_early_data_status(SSL *s)
+{
+    return s->ext.early_data;
+}
+
 static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
 {
     if (s->handshake_func == NULL) {
@@ -1666,6 +1742,10 @@ 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)
+        return 0;
+
     if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
         int ret;
         struct ssl_async_args args;
@@ -1715,6 +1795,76 @@ int SSL_write_ex(SSL *s, const void *buf, size_t num, size_t *written)
     return ret;
 }
 
+int SSL_write_early(SSL *s, const void *buf, size_t num, size_t *written)
+{
+    int ret;
+
+    if (s->server) {
+        SSLerr(SSL_F_SSL_WRITE_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return 0;
+    }
+
+    /*
+     * TODO(TLS1.3): Somehow we need to check that we're not sending too much
+     * data
+     */
+
+    switch (s->early_data_state) {
+    case SSL_EARLY_DATA_NONE:
+        if (!SSL_in_before(s)) {
+            SSLerr(SSL_F_SSL_WRITE_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+            return 0;
+        }
+        /* fall through */
+
+    case SSL_EARLY_DATA_CONNECT_RETRY:
+        s->early_data_state = SSL_EARLY_DATA_CONNECTING;
+        ret = SSL_connect(s);
+        if (ret <= 0) {
+            /* NBIO or error */
+            s->early_data_state = SSL_EARLY_DATA_CONNECT_RETRY;
+            return 0;
+        }
+        /* fall through */
+
+    case SSL_EARLY_DATA_WRITE_RETRY:
+        s->early_data_state = SSL_EARLY_DATA_WRITING;
+        ret = SSL_write_ex(s, buf, num, written);
+        s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
+        return ret;
+
+    default:
+        SSLerr(SSL_F_SSL_WRITE_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return 0;
+    }
+}
+
+int SSL_write_early_finish(SSL *s)
+{
+    int ret;
+
+    if (s->early_data_state != SSL_EARLY_DATA_WRITE_RETRY) {
+        SSLerr(SSL_F_SSL_WRITE_EARLY_FINISH, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+        return 0;
+    }
+
+    s->early_data_state = SSL_EARLY_DATA_WRITING;
+    ret = ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_END_OF_EARLY_DATA);
+    if (ret <= 0) {
+        s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
+        return 0;
+    }
+    s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+    /*
+     * We set the enc_write_ctx back to NULL because we may end up writing
+     * in cleartext again if we get a HelloRetryRequest from the server.
+     */
+    EVP_CIPHER_CTX_free(s->enc_write_ctx);
+    s->enc_write_ctx = NULL;
+    ossl_statem_set_in_init(s, 1);
+    return 1;
+}
+
 int SSL_shutdown(SSL *s)
 {
     /*
@@ -2504,11 +2654,6 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth)
     if (!OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL))
         return NULL;
 
-    if (FIPS_mode() && (meth->version < TLS1_VERSION)) {
-        SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_AT_LEAST_TLS_1_0_NEEDED_IN_FIPS_MODE);
-        return NULL;
-    }
-
     if (SSL_get_ex_data_X509_STORE_CTX_idx() < 0) {
         SSLerr(SSL_F_SSL_CTX_NEW, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS);
         goto err;
@@ -3077,6 +3222,10 @@ int SSL_do_handshake(SSL *s)
         return -1;
     }
 
+    if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY
+            || s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY)
+        return -1;
+
     s->method->ssl_renegotiate_check(s, 0);
 
     if (SSL_in_init(s) || SSL_in_before(s)) {
@@ -3612,11 +3761,6 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *s, int idx)
     return (CRYPTO_get_ex_data(&s->ex_data, idx));
 }
 
-int ssl_ok(SSL *s)
-{
-    return (1);
-}
-
 X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx)
 {
     return (ctx->cert_store);
@@ -4667,3 +4811,27 @@ int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites,
     sk_SSL_CIPHER_free(scsvs);
     return 0;
 }
+
+int SSL_CTX_set_max_early_data(SSL_CTX *ctx, uint32_t max_early_data)
+{
+    ctx->max_early_data = max_early_data;
+
+    return 1;
+}
+
+uint32_t SSL_CTX_get_max_early_data(SSL_CTX *ctx)
+{
+    return ctx->max_early_data;
+}
+
+int SSL_set_max_early_data(SSL *s, uint32_t max_early_data)
+{
+    s->max_early_data = max_early_data;
+
+    return 1;
+}
+
+uint32_t SSL_get_max_early_data(SSL_CTX *s)
+{
+    return s->max_early_data;
+}