Make sure that exporting keying material is allowed
[openssl.git] / ssl / statem / statem.c
index 7e4f524ddca76d83958f25ab33d13100affc8ef8..95c369a88315edb7a1b53a91d72264a3e2f13ffe 100644 (file)
@@ -1,63 +1,17 @@
-/* ssl/statem/statem.c */
 /*
- * Written by Matt Caswell for the OpenSSL project.
- */
-/* ====================================================================
- * Copyright (c) 1998-2015 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
+ * Copyright 2015-2017 The OpenSSL Project Authors. All Rights Reserved.
  *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
  */
 
+#include "internal/cryptlib.h"
 #include <openssl/rand.h>
 #include "../ssl_locl.h"
+#include "statem_locl.h"
+#include <assert.h>
 
 /*
  * This file implements the SSL/TLS/DTLS state machines.
@@ -83,7 +37,7 @@
  * | Message flow state machine                |            |                 |
  * |                                           |            |                 |
  * | -------------------- -------------------- | Transition | Handshake state |
- * | | MSG_FLOW_READING    | | MSG_FLOW_WRITING    | | Event      | machine         |
+ * | | MSG_FLOW_READING | | MSG_FLOW_WRITING | | Event      | machine         |
  * | | sub-state        | | sub-state        | |----------->|                 |
  * | | machine for      | | machine for      | |            |                 |
  * | | reading messages | | writing messages | |            |                 |
  */
 
 /* Sub state machine return values */
-enum SUB_STATE_RETURN {
+typedef enum {
     /* Something bad happened or NBIO */
     SUB_STATE_ERROR,
     /* Sub state finished go to the next sub state */
     SUB_STATE_FINISHED,
     /* Sub state finished and handshake was completed */
     SUB_STATE_END_HANDSHAKE
-};
+} SUB_STATE_RETURN;
 
 static int state_machine(SSL *s, int server);
 static void init_read_state_machine(SSL *s);
-static enum SUB_STATE_RETURN read_state_machine(SSL *s);
+static SUB_STATE_RETURN read_state_machine(SSL *s);
 static void init_write_state_machine(SSL *s);
-static enum SUB_STATE_RETURN write_state_machine(SSL *s);
-static inline int cert_req_allowed(SSL *s);
-static inline int key_exchange_skip_allowed(SSL *s);
-static int client_read_transition(SSL *s, int mt);
-static enum WRITE_TRAN client_write_transition(SSL *s);
-static enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst);
-static enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst);
-static int client_construct_message(SSL *s);
-static unsigned long client_max_message_size(SSL *s);
-static enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt);
-static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst);
-static int server_read_transition(SSL *s, int mt);
-static inline int send_server_key_exchange(SSL *s);
-static inline int send_certificate_request(SSL *s);
-static enum WRITE_TRAN server_write_transition(SSL *s);
-static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst);
-static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst);
-static int server_construct_message(SSL *s);
-static unsigned long server_max_message_size(SSL *s);
-static enum MSG_PROCESS_RETURN server_process_message(SSL *s, PACKET *pkt);
-static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst);
-
-
-enum HANDSHAKE_STATE SSL_state(const SSL *ssl)
-{
-    return ssl->statem.hand_state;
-}
+static SUB_STATE_RETURN write_state_machine(SSL *s);
 
-void SSL_set_state(SSL *ssl, enum HANDSHAKE_STATE state)
+OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl)
 {
-    /*
-     * This function seems like a really bad idea. Should we remove it
-     * completely?
-     */
-    ssl->statem.hand_state = state;
+    return ssl->statem.hand_state;
 }
 
 int SSL_in_init(SSL *s)
@@ -170,31 +94,52 @@ int SSL_in_before(SSL *s)
 /*
  * Clear the state machine state and reset back to MSG_FLOW_UNINITED
  */
-void statem_clear(SSL *s)
+void ossl_statem_clear(SSL *s)
 {
     s->statem.state = MSG_FLOW_UNINITED;
     s->statem.hand_state = TLS_ST_BEFORE;
     s->statem.in_init = 1;
+    s->statem.no_cert_verify = 0;
 }
 
 /*
  * Set the state machine up ready for a renegotiation handshake
  */
-void statem_set_renegotiate(SSL *s)
+void ossl_statem_set_renegotiate(SSL *s)
 {
-    s->statem.state = MSG_FLOW_RENEGOTIATE;
     s->statem.in_init = 1;
+    s->statem.request_state = TLS_ST_SW_HELLO_REQ;
 }
 
 /*
- * Put the state machine into an error state. This is a permanent error for
- * the current connection.
+ * Put the state machine into an error state and send an alert if appropriate.
+ * This is a permanent error for the current connection.
  */
-void statem_set_error(SSL *s)
+void ossl_statem_fatal(SSL *s, int al, int func, int reason, const char *file,
+                       int line)
 {
+    /* We shouldn't call SSLfatal() twice. Once is enough */
+    assert(s->statem.state != MSG_FLOW_ERROR);
+    s->statem.in_init = 1;
     s->statem.state = MSG_FLOW_ERROR;
+    ERR_put_error(ERR_LIB_SSL, func, reason, file, line);
+    if (al != SSL_AD_NO_ALERT)
+        ssl3_send_alert(s, SSL3_AL_FATAL, al);
 }
 
+/*
+ * This macro should only be called if we are already expecting to be in
+ * a fatal error state. We verify that we are, and set it if not (this would
+ * indicate a bug).
+ */
+#define check_fatal(s, f) \
+    do { \
+        if (!ossl_assert((s)->statem.in_init \
+                         && (s)->statem.state == MSG_FLOW_ERROR)) \
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, (f), \
+                     SSL_R_MISSING_FATAL); \
+    } while (0)
+
 /*
  * Discover whether the current connection is in the error state.
  *
@@ -202,7 +147,7 @@ void statem_set_error(SSL *s)
  *   1: Yes
  *   0: No
  */
-int statem_in_error(const SSL *s)
+int ossl_statem_in_error(const SSL *s)
 {
     if (s->statem.state == MSG_FLOW_ERROR)
         return 1;
@@ -210,26 +155,120 @@ int statem_in_error(const SSL *s)
     return 0;
 }
 
-void statem_set_in_init(SSL *s, int init)
+void ossl_statem_set_in_init(SSL *s, int init)
 {
     s->statem.in_init = init;
 }
 
-int statem_connect(SSL *s) {
+int ossl_statem_get_in_handshake(SSL *s)
+{
+    return s->statem.in_handshake;
+}
+
+void ossl_statem_set_in_handshake(SSL *s, int inhand)
+{
+    if (inhand)
+        s->statem.in_handshake++;
+    else
+        s->statem.in_handshake--;
+}
+
+/* Are we in a sensible state to skip over unreadable early data? */
+int ossl_statem_skip_early_data(SSL *s)
+{
+    if (s->ext.early_data != SSL_EARLY_DATA_REJECTED)
+        return 0;
+
+    if (!s->server || s->statem.hand_state != TLS_ST_EARLY_DATA)
+        return 0;
+
+    return 1;
+}
+
+/*
+ * Called when we are in SSL_read*(), SSL_write*(), or SSL_accept()
+ * /SSL_connect()/SSL_do_handshake(). Used to test whether we are in an early
+ * data state and whether we should attempt to move the handshake on if so.
+ * |sending| is 1 if we are attempting to send data (SSL_write*()), 0 if we are
+ * attempting to read data (SSL_read*()), or -1 if we are in SSL_do_handshake()
+ * or similar.
+ */
+void ossl_statem_check_finish_init(SSL *s, int sending)
+{
+    if (sending == -1) {
+        if (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
+                || s->statem.hand_state == TLS_ST_EARLY_DATA) {
+            ossl_statem_set_in_init(s, 1);
+            if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+                /*
+                 * SSL_connect() or SSL_do_handshake() has been called directly.
+                 * We don't allow any more writing of early data.
+                 */
+                s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+            }
+        }
+    } else if (!s->server) {
+        if ((sending && (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END
+                      || s->statem.hand_state == TLS_ST_EARLY_DATA)
+                  && s->early_data_state != SSL_EARLY_DATA_WRITING)
+                || (!sending && s->statem.hand_state == TLS_ST_EARLY_DATA)) {
+            ossl_statem_set_in_init(s, 1);
+            /*
+             * SSL_write() has been called directly. We don't allow any more
+             * writing of early data.
+             */
+            if (sending && s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY)
+                s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING;
+        }
+    } else {
+        if (s->early_data_state == SSL_EARLY_DATA_FINISHED_READING
+                && s->statem.hand_state == TLS_ST_EARLY_DATA)
+            ossl_statem_set_in_init(s, 1);
+    }
+}
+
+void ossl_statem_set_hello_verify_done(SSL *s)
+{
+    s->statem.state = MSG_FLOW_UNINITED;
+    s->statem.in_init = 1;
+    /*
+     * This will get reset (briefly) back to TLS_ST_BEFORE when we enter
+     * state_machine() because |state| is MSG_FLOW_UNINITED, but until then any
+     * calls to SSL_in_before() will return false. Also calls to
+     * SSL_state_string() and SSL_state_string_long() will return something
+     * sensible.
+     */
+    s->statem.hand_state = TLS_ST_SR_CLNT_HELLO;
+}
+
+int ossl_statem_connect(SSL *s)
+{
     return state_machine(s, 0);
 }
 
-int statem_accept(SSL *s)
+int ossl_statem_accept(SSL *s)
 {
     return state_machine(s, 1);
 }
 
+typedef void (*info_cb) (const SSL *, int, int);
+
+static info_cb get_callback(SSL *s)
+{
+    if (s->info_callback != NULL)
+        return s->info_callback;
+    else if (s->ctx->info_callback != NULL)
+        return s->ctx->info_callback;
+
+    return NULL;
+}
+
 /*
  * The main message flow state machine. We start in the MSG_FLOW_UNINITED or
- * MSG_FLOW_RENEGOTIATE state and finish in MSG_FLOW_FINISHED. Valid states and
+ * MSG_FLOW_FINISHED state and finish in MSG_FLOW_FINISHED. Valid states and
  * transitions are as follows:
  *
- * MSG_FLOW_UNINITED     MSG_FLOW_RENEGOTIATE
+ * MSG_FLOW_UNINITED     MSG_FLOW_FINISHED
  *        |                       |
  *        +-----------------------+
  *        v
@@ -252,11 +291,11 @@ int statem_accept(SSL *s)
  *   1: Success
  * <=0: NBIO or error
  */
-static int state_machine(SSL *s, int server) {
+static int state_machine(SSL *s, int server)
+{
     BUF_MEM *buf = NULL;
-    unsigned long Time = (unsigned long)time(NULL);
     void (*cb) (const SSL *ssl, int type, int val) = NULL;
-    STATEM *st = &s->statem;
+    OSSL_STATEM *st = &s->statem;
     int ret = -1;
     int ssret;
 
@@ -265,91 +304,79 @@ static int state_machine(SSL *s, int server) {
         return -1;
     }
 
-    RAND_add(&Time, sizeof(Time), 0);
     ERR_clear_error();
     clear_sys_error();
 
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
+    cb = get_callback(s);
 
-    s->in_handshake++;
+    st->in_handshake++;
     if (!SSL_in_init(s) || SSL_in_before(s)) {
-        if (!SSL_clear(s))
+        /*
+         * If we are stateless then we already called SSL_clear() - don't do
+         * it again and clear the STATELESS flag itself.
+         */
+        if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(s))
             return -1;
     }
-
 #ifndef OPENSSL_NO_SCTP
-    if (SSL_IS_DTLS(s)) {
+    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
         /*
          * Notify SCTP BIO socket to enter handshake mode and prevent stream
-         * identifier other than 0. Will be ignored if no SCTP is used.
+         * identifier other than 0.
          */
         BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
-                 s->in_handshake, NULL);
-    }
-#endif
-
-#ifndef OPENSSL_NO_HEARTBEATS
-    /*
-     * If we're awaiting a HeartbeatResponse, pretend we already got and
-     * don't await it anymore, because Heartbeats don't make sense during
-     * handshakes anyway.
-     */
-    if (s->tlsext_hb_pending) {
-        if (SSL_IS_DTLS(s))
-            dtls1_stop_timer(s);
-        s->tlsext_hb_pending = 0;
-        s->tlsext_hb_seq++;
+                 st->in_handshake, NULL);
     }
 #endif
 
     /* Initialise state machine */
-
-    if (st->state == MSG_FLOW_RENEGOTIATE) {
-        s->renegotiate = 1;
-        if (!server)
-            s->ctx->stats.sess_connect_renegotiate++;
-    }
-
-    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE) {
+    if (st->state == MSG_FLOW_UNINITED
+            || st->state == MSG_FLOW_FINISHED) {
         if (st->state == MSG_FLOW_UNINITED) {
             st->hand_state = TLS_ST_BEFORE;
+            st->request_state = TLS_ST_BEFORE;
         }
 
         s->server = server;
         if (cb != NULL)
             cb(s, SSL_CB_HANDSHAKE_START, 1);
 
+        /*
+         * Fatal errors in this block don't send an alert because we have
+         * failed to even initialise properly. Sending an alert is probably
+         * doomed to failure.
+         */
+
         if (SSL_IS_DTLS(s)) {
             if ((s->version & 0xff00) != (DTLS1_VERSION & 0xff00) &&
-                    (server
-                    || (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00))) {
-                SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+                (server || (s->version & 0xff00) != (DTLS1_BAD_VER & 0xff00))) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
                 goto end;
             }
         } else {
-            if ((s->version >> 8) != SSL3_VERSION_MAJOR
-                    && s->version != TLS_ANY_VERSION) {
-                SSLerr(SSL_F_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+            if ((s->version >> 8) != SSL3_VERSION_MAJOR) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
                 goto end;
             }
         }
 
-        if (!SSL_IS_DTLS(s)) {
-            if (s->version != TLS_ANY_VERSION &&
-                    !ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
-                SSLerr(SSL_F_STATE_MACHINE, SSL_R_VERSION_TOO_LOW);
-                goto end;
-            }
+        if (!ssl_security(s, SSL_SECOP_VERSION, 0, s->version, NULL)) {
+            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                     ERR_R_INTERNAL_ERROR);
+            goto end;
         }
 
         if (s->init_buf == NULL) {
             if ((buf = BUF_MEM_new()) == NULL) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
                 goto end;
             }
             if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
                 goto end;
             }
             s->init_buf = buf;
@@ -357,6 +384,8 @@ static int state_machine(SSL *s, int server) {
         }
 
         if (!ssl3_setup_buffers(s)) {
+            SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                     ERR_R_INTERNAL_ERROR);
             goto end;
         }
         s->init_num = 0;
@@ -366,64 +395,36 @@ static int state_machine(SSL *s, int server) {
          */
         s->s3->change_cipher_spec = 0;
 
-        if (!server || st->state != MSG_FLOW_RENEGOTIATE) {
-                /*
-                 * Ok, we now need to push on a buffering BIO ...but not with
-                 * SCTP
-                 */
+        /*
+         * Ok, we now need to push on a buffering BIO ...but not with
+         * SCTP
+         */
 #ifndef OPENSSL_NO_SCTP
-                if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s)))
+        if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s)))
 #endif
-                    if (!ssl_init_wbio_buffer(s, server ? 1 : 0)) {
-                        goto end;
-                    }
-
-            ssl3_init_finished_mac(s);
-        }
-
-        if (server) {
-            if (st->state != MSG_FLOW_RENEGOTIATE) {
-                s->ctx->stats.sess_accept++;
-            } else if (!s->s3->send_connection_binding &&
-                       !(s->options &
-                         SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION)) {
-                /*
-                 * Server attempting to renegotiate with client that doesn't
-                 * support secure renegotiation.
-                 */
-                SSLerr(SSL_F_STATE_MACHINE,
-                       SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
-                statem_set_error(s);
+            if (!ssl_init_wbio_buffer(s)) {
+                SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
                 goto end;
-            } else {
-                /*
-                 * s->state == SSL_ST_RENEGOTIATE, we will just send a
-                 * HelloRequest
-                 */
-                s->ctx->stats.sess_accept_renegotiate++;
             }
-        } else {
-            s->ctx->stats.sess_connect++;
-
-            /* mark client_random uninitialized */
-            memset(s->s3->client_random, 0, sizeof(s->s3->client_random));
-            s->hit = 0;
 
-            s->s3->tmp.cert_request = 0;
-
-            if (SSL_IS_DTLS(s)) {
-                st->use_timer = 1;
+        if ((SSL_in_before(s))
+                || s->renegotiate) {
+            if (!tls_setup_handshake(s)) {
+                /* SSLfatal() already called */
+                goto end;
             }
+
+            if (SSL_IS_FIRST_HANDSHAKE(s))
+                st->read_state_first_init = 1;
         }
 
         st->state = MSG_FLOW_WRITING;
         init_write_state_machine(s);
-        st->read_state_first_init = 1;
     }
 
-    while(st->state != MSG_FLOW_FINISHED) {
-        if(st->state == MSG_FLOW_READING) {
+    while (st->state != MSG_FLOW_FINISHED) {
+        if (st->state == MSG_FLOW_READING) {
             ssret = read_state_machine(s);
             if (ssret == SUB_STATE_FINISHED) {
                 st->state = MSG_FLOW_WRITING;
@@ -445,25 +446,25 @@ static int state_machine(SSL *s, int server) {
             }
         } else {
             /* Error */
-            statem_set_error(s);
+            check_fatal(s, SSL_F_STATE_MACHINE);
+            SSLerr(SSL_F_STATE_MACHINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
             goto end;
         }
     }
 
-    st->state = MSG_FLOW_UNINITED;
     ret = 1;
 
  end:
-    s->in_handshake--;
+    st->in_handshake--;
 
 #ifndef OPENSSL_NO_SCTP
-    if (SSL_IS_DTLS(s)) {
+    if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
         /*
          * Notify SCTP BIO socket to leave handshake mode and allow stream
-         * identifier other than 0. Will be ignored if no SCTP is used.
+         * identifier other than 0.
          */
         BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE,
-                 s->in_handshake, NULL);
+                 st->in_handshake, NULL);
     }
 #endif
 
@@ -482,11 +483,26 @@ static int state_machine(SSL *s, int server) {
  */
 static void init_read_state_machine(SSL *s)
 {
-    STATEM *st = &s->statem;
+    OSSL_STATEM *st = &s->statem;
 
     st->read_state = READ_STATE_HEADER;
 }
 
+static int grow_init_buf(SSL *s, size_t size) {
+
+    size_t msg_offset = (char *)s->init_msg - s->init_buf->data;
+
+    if (!BUF_MEM_grow_clean(s->init_buf, (int)size))
+        return 0;
+
+    if (size < msg_offset)
+        return 0;
+
+    s->init_msg = s->init_buf->data + msg_offset;
+
+    return 1;
+}
+
 /*
  * This function implements the sub-state machine when the message flow is in
  * MSG_FLOW_READING. The valid sub-states and transitions are:
@@ -509,36 +525,34 @@ static void init_read_state_machine(SSL *s)
  * READ_STATE_POST_PROCESS is an optional step that may occur if some post
  * processing activity performed on the message may block.
  *
- * Any of the above states could result in an NBIO event occuring in which case
+ * Any of the above states could result in an NBIO event occurring in which case
  * control returns to the calling application. When this function is recalled we
  * will resume in the same state where we left off.
  */
-static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
-    STATEM *st = &s->statem;
+static SUB_STATE_RETURN read_state_machine(SSL *s)
+{
+    OSSL_STATEM *st = &s->statem;
     int ret, mt;
-    unsigned long len;
-    int (*transition)(SSL *s, int mt);
+    size_t len = 0;
+    int (*transition) (SSL *s, int mt);
     PACKET pkt;
-    enum MSG_PROCESS_RETURN (*process_message)(SSL *s, PACKET *pkt);
-    enum WORK_STATE (*post_process_message)(SSL *s, enum WORK_STATE wst);
-    unsigned long (*max_message_size)(SSL *s);
+    MSG_PROCESS_RETURN(*process_message) (SSL *s, PACKET *pkt);
+    WORK_STATE(*post_process_message) (SSL *s, WORK_STATE wst);
+    size_t (*max_message_size) (SSL *s);
     void (*cb) (const SSL *ssl, int type, int val) = NULL;
 
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
+    cb = get_callback(s);
 
-    if(s->server) {
-        transition = server_read_transition;
-        process_message = server_process_message;
-        max_message_size = server_max_message_size;
-        post_process_message = server_post_process_message;
+    if (s->server) {
+        transition = ossl_statem_server_read_transition;
+        process_message = ossl_statem_server_process_message;
+        max_message_size = ossl_statem_server_max_message_size;
+        post_process_message = ossl_statem_server_post_process_message;
     } else {
-        transition = client_read_transition;
-        process_message = client_process_message;
-        max_message_size = client_max_message_size;
-        post_process_message = client_post_process_message;
+        transition = ossl_statem_client_read_transition;
+        process_message = ossl_statem_client_process_message;
+        max_message_size = ossl_statem_client_max_message_size;
+        post_process_message = ossl_statem_client_post_process_message;
     }
 
     if (st->read_state_first_init) {
@@ -546,10 +560,9 @@ static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
         st->read_state_first_init = 0;
     }
 
-    while(1) {
-        switch(st->read_state) {
+    while (1) {
+        switch (st->read_state) {
         case READ_STATE_HEADER:
-            s->init_num = 0;
             /* Get the state the peer wants to move to */
             if (SSL_IS_DTLS(s)) {
                 /*
@@ -576,15 +589,24 @@ static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
              * Validate that we are allowed to move to the new state and move
              * to that state if so
              */
-            if(!transition(s, mt)) {
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
-                SSLerr(SSL_F_READ_STATE_MACHINE, SSL_R_UNEXPECTED_MESSAGE);
+            if (!transition(s, mt)) {
+                check_fatal(s, SSL_F_READ_STATE_MACHINE);
                 return SUB_STATE_ERROR;
             }
 
             if (s->s3->tmp.message_size > max_message_size(s)) {
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
-                SSLerr(SSL_F_READ_STATE_MACHINE, SSL_R_EXCESSIVE_MESSAGE_SIZE);
+                SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_READ_STATE_MACHINE,
+                         SSL_R_EXCESSIVE_MESSAGE_SIZE);
+                return SUB_STATE_ERROR;
+            }
+
+            /* dtls_get_message already did this */
+            if (!SSL_IS_DTLS(s)
+                    && s->s3->tmp.message_size > 0
+                    && !grow_init_buf(s, s->s3->tmp.message_size
+                                         + SSL3_HM_HEADER_LENGTH)) {
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE,
+                         ERR_R_BUF_LIB);
                 return SUB_STATE_ERROR;
             }
 
@@ -603,34 +625,46 @@ static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
 
             s->first_packet = 0;
             if (!PACKET_buf_init(&pkt, s->init_msg, len)) {
-                ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-                SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
                 return SUB_STATE_ERROR;
             }
             ret = process_message(s, &pkt);
-            if (ret == MSG_PROCESS_ERROR) {
+
+            /* Discard the packet data */
+            s->init_num = 0;
+
+            switch (ret) {
+            case MSG_PROCESS_ERROR:
+                check_fatal(s, SSL_F_READ_STATE_MACHINE);
                 return SUB_STATE_ERROR;
-            }
 
-            if (ret == MSG_PROCESS_FINISHED_READING) {
+            case MSG_PROCESS_FINISHED_READING:
                 if (SSL_IS_DTLS(s)) {
                     dtls1_stop_timer(s);
                 }
                 return SUB_STATE_FINISHED;
-            }
 
-            if (ret == MSG_PROCESS_CONTINUE_PROCESSING) {
+            case MSG_PROCESS_CONTINUE_PROCESSING:
                 st->read_state = READ_STATE_POST_PROCESS;
                 st->read_state_work = WORK_MORE_A;
-            } else {
+                break;
+
+            default:
                 st->read_state = READ_STATE_HEADER;
+                break;
             }
             break;
 
         case READ_STATE_POST_PROCESS:
             st->read_state_work = post_process_message(s, st->read_state_work);
-            switch(st->read_state_work) {
-            default:
+            switch (st->read_state_work) {
+            case WORK_ERROR:
+                check_fatal(s, SSL_F_READ_STATE_MACHINE);
+                /* Fall through */
+            case WORK_MORE_A:
+            case WORK_MORE_B:
+            case WORK_MORE_C:
                 return SUB_STATE_ERROR;
 
             case WORK_FINISHED_CONTINUE:
@@ -647,9 +681,8 @@ static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
 
         default:
             /* Shouldn't happen */
-            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
-            SSLerr(SSL_F_READ_STATE_MACHINE, ERR_R_INTERNAL_ERROR);
-            statem_set_error(s);
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_READ_STATE_MACHINE,
+                     ERR_R_INTERNAL_ERROR);
             return SUB_STATE_ERROR;
         }
     }
@@ -660,10 +693,10 @@ static enum SUB_STATE_RETURN read_state_machine(SSL *s) {
  */
 static int statem_do_write(SSL *s)
 {
-    STATEM *st = &s->statem;
+    OSSL_STATEM *st = &s->statem;
 
     if (st->hand_state == TLS_ST_CW_CHANGE
-            || st->hand_state == TLS_ST_SW_CHANGE) {
+        || st->hand_state == TLS_ST_SW_CHANGE) {
         if (SSL_IS_DTLS(s))
             return dtls1_do_write(s, SSL3_RT_CHANGE_CIPHER_SPEC);
         else
@@ -678,7 +711,7 @@ static int statem_do_write(SSL *s)
  */
 static void init_write_state_machine(SSL *s)
 {
-    STATEM *st = &s->statem;
+    OSSL_STATEM *st = &s->statem;
 
     st->write_state = WRITE_STATE_TRANSITION;
 }
@@ -703,7 +736,7 @@ static void init_write_state_machine(SSL *s)
  * WRITE_STATE_TRANSITION transitions the state of the handshake state machine
 
  * WRITE_STATE_PRE_WORK performs any work necessary to prepare the later
- * sending of the message. This could result in an NBIO event occuring in
+ * sending of the message. This could result in an NBIO event occurring in
  * which case control returns to the calling application. When this function
  * is recalled we will resume in the same state where we left off.
  *
@@ -714,35 +747,37 @@ static void init_write_state_machine(SSL *s)
  * message has been completed. As for WRITE_STATE_PRE_WORK this could also
  * result in an NBIO event.
  */
-static enum SUB_STATE_RETURN write_state_machine(SSL *s)
+static SUB_STATE_RETURN write_state_machine(SSL *s)
 {
-    STATEM *st = &s->statem;
+    OSSL_STATEM *st = &s->statem;
     int ret;
-    enum WRITE_TRAN (*transition)(SSL *s);
-    enum WORK_STATE (*pre_work)(SSL *s, enum WORK_STATE wst);
-    enum WORK_STATE (*post_work)(SSL *s, enum WORK_STATE wst);
-    int (*construct_message)(SSL *s);
+    WRITE_TRAN(*transition) (SSL *s);
+    WORK_STATE(*pre_work) (SSL *s, WORK_STATE wst);
+    WORK_STATE(*post_work) (SSL *s, WORK_STATE wst);
+    int (*get_construct_message_f) (SSL *s, WPACKET *pkt,
+                                    int (**confunc) (SSL *s, WPACKET *pkt),
+                                    int *mt);
     void (*cb) (const SSL *ssl, int type, int val) = NULL;
+    int (*confunc) (SSL *s, WPACKET *pkt);
+    int mt;
+    WPACKET pkt;
 
-    if (s->info_callback != NULL)
-        cb = s->info_callback;
-    else if (s->ctx->info_callback != NULL)
-        cb = s->ctx->info_callback;
+    cb = get_callback(s);
 
-    if(s->server) {
-        transition = server_write_transition;
-        pre_work = server_pre_work;
-        post_work = server_post_work;
-        construct_message = server_construct_message;
+    if (s->server) {
+        transition = ossl_statem_server_write_transition;
+        pre_work = ossl_statem_server_pre_work;
+        post_work = ossl_statem_server_post_work;
+        get_construct_message_f = ossl_statem_server_construct_message;
     } else {
-        transition = client_write_transition;
-        pre_work = client_pre_work;
-        post_work = client_post_work;
-        construct_message = client_construct_message;
+        transition = ossl_statem_client_write_transition;
+        pre_work = ossl_statem_client_pre_work;
+        post_work = ossl_statem_client_post_work;
+        get_construct_message_f = ossl_statem_client_construct_message;
     }
 
-    while(1) {
-        switch(st->write_state) {
+    while (1) {
+        switch (st->write_state) {
         case WRITE_STATE_TRANSITION:
             if (cb != NULL) {
                 /* Notify callback of an impending state change */
@@ -751,7 +786,7 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
                 else
                     cb(s, SSL_CB_CONNECT_LOOP, 1);
             }
-            switch(transition(s)) {
+            switch (transition(s)) {
             case WRITE_TRAN_CONTINUE:
                 st->write_state = WRITE_STATE_PRE_WORK;
                 st->write_state_work = WORK_MORE_A;
@@ -761,14 +796,20 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
                 return SUB_STATE_FINISHED;
                 break;
 
-            default:
+            case WRITE_TRAN_ERROR:
+                check_fatal(s, SSL_F_WRITE_STATE_MACHINE);
                 return SUB_STATE_ERROR;
             }
             break;
 
         case WRITE_STATE_PRE_WORK:
-            switch(st->write_state_work = pre_work(s, st->write_state_work)) {
-            default:
+            switch (st->write_state_work = pre_work(s, st->write_state_work)) {
+            case WORK_ERROR:
+                check_fatal(s, SSL_F_WRITE_STATE_MACHINE);
+                /* Fall through */
+            case WORK_MORE_A:
+            case WORK_MORE_B:
+            case WORK_MORE_C:
                 return SUB_STATE_ERROR;
 
             case WORK_FINISHED_CONTINUE:
@@ -778,8 +819,35 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
             case WORK_FINISHED_STOP:
                 return SUB_STATE_END_HANDSHAKE;
             }
-            if(construct_message(s) == 0)
+            if (!get_construct_message_f(s, &pkt, &confunc, &mt)) {
+                /* SSLfatal() already called */
+                return SUB_STATE_ERROR;
+            }
+            if (mt == SSL3_MT_DUMMY) {
+                /* Skip construction and sending. This isn't a "real" state */
+                st->write_state = WRITE_STATE_POST_WORK;
+                st->write_state_work = WORK_MORE_A;
+                break;
+            }
+            if (!WPACKET_init(&pkt, s->init_buf)
+                    || !ssl_set_handshake_header(s, &pkt, mt)) {
+                WPACKET_cleanup(&pkt);
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
+                return SUB_STATE_ERROR;
+            }
+            if (confunc != NULL && !confunc(s, &pkt)) {
+                WPACKET_cleanup(&pkt);
+                check_fatal(s, SSL_F_WRITE_STATE_MACHINE);
+                return SUB_STATE_ERROR;
+            }
+            if (!ssl_close_construct_packet(s, &pkt, mt)
+                    || !WPACKET_finish(&pkt)) {
+                WPACKET_cleanup(&pkt);
+                SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE,
+                         ERR_R_INTERNAL_ERROR);
                 return SUB_STATE_ERROR;
+            }
 
             /* Fall through */
 
@@ -796,8 +864,13 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
             /* Fall through */
 
         case WRITE_STATE_POST_WORK:
-            switch(st->write_state_work = post_work(s, st->write_state_work)) {
-            default:
+            switch (st->write_state_work = post_work(s, st->write_state_work)) {
+            case WORK_ERROR:
+                check_fatal(s, SSL_F_WRITE_STATE_MACHINE);
+                /* Fall through */
+            case WORK_MORE_A:
+            case WORK_MORE_B:
+            case WORK_MORE_C:
                 return SUB_STATE_ERROR;
 
             case WORK_FINISHED_CONTINUE:
@@ -810,6 +883,8 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
             break;
 
         default:
+            SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_WRITE_STATE_MACHINE,
+                     ERR_R_INTERNAL_ERROR);
             return SUB_STATE_ERROR;
         }
     }
@@ -818,7 +893,7 @@ static enum SUB_STATE_RETURN write_state_machine(SSL *s)
 /*
  * Flush the write BIO
  */
-static int statem_flush(SSL *s)
+int statem_flush(SSL *s)
 {
     s->rwstate = SSL_WRITING;
     if (BIO_flush(s->wbio) <= 0) {
@@ -831,17 +906,17 @@ static int statem_flush(SSL *s)
 
 /*
  * Called by the record layer to determine whether application data is
- * allowed to be sent in the current handshake state or not.
+ * allowed to be received in the current handshake state or not.
  *
  * Return values are:
  *   1: Yes (application data allowed)
  *   0: No (application data not allowed)
  */
-int statem_app_data_allowed(SSL *s)
+int ossl_statem_app_data_allowed(SSL *s)
 {
-    STATEM *st = &s->statem;
+    OSSL_STATEM *st = &s->statem;
 
-    if (st->state == MSG_FLOW_UNINITED || st->state == MSG_FLOW_RENEGOTIATE)
+    if (st->state == MSG_FLOW_UNINITED)
         return 0;
 
     if (!s->s3->in_read_app_data || (s->s3->total_renegotiations == 0))
@@ -853,7 +928,7 @@ int statem_app_data_allowed(SSL *s)
          * ServerHello yet then we allow app data
          */
         if (st->hand_state == TLS_ST_BEFORE
-                || st->hand_state == TLS_ST_SR_CLNT_HELLO)
+            || st->hand_state == TLS_ST_SR_CLNT_HELLO)
             return 1;
     } else {
         /*
@@ -867,1375 +942,12 @@ int statem_app_data_allowed(SSL *s)
     return 0;
 }
 
-
-#ifndef OPENSSL_NO_SCTP
-/*
- * Set flag used by SCTP to determine whether we are in the read sock state
- */
-void statem_set_sctp_read_sock(SSL *s, int read_sock)
-{
-    s->statem.in_sctp_read_sock = read_sock;
-}
-
-/*
- * Called by the record layer to determine whether we are in the read sock
- * state or not.
- *
- * Return values are:
- *   1: Yes (we are in the read sock state)
- *   0: No (we are not in the read sock state)
- */
-int statem_in_sctp_read_sock(SSL *s)
-{
-    return s->statem.in_sctp_read_sock;
-}
-#endif
-
-/*
- * Is a CertificateRequest message allowed at the moment or not?
- *
- *  Return values are:
- *  1: Yes
- *  0: No
- */
-static inline int cert_req_allowed(SSL *s)
-{
-    /* TLS does not like anon-DH with client cert */
-    if (s->version > SSL3_VERSION
-            && (s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL))
-        return 0;
-
-    return 1;
-}
-
-/*
- * Are we allowed to skip the ServerKeyExchange message?
- *
- *  Return values are:
- *  1: Yes
- *  0: No
- */
-static inline int key_exchange_skip_allowed(SSL *s)
-{
-    long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-    /*
-     * Can't skip server key exchange if this is an ephemeral
-     * ciphersuite.
-     */
-    if (alg_k & (SSL_kDHE | SSL_kECDHE)) {
-        return 0;
-    }
-
-    return 1;
-}
-
-/*
- * client_read_transition() encapsulates the logic for the allowed handshake
- * state transitions when the client is reading messages from the server. The
- * message type that the server has sent is provided in |mt|. The current state
- * is in |s->statem.hand_state|.
- *
- *  Return values are:
- *  1: Success (transition allowed)
- *  0: Error (transition not allowed)
- */
-static int client_read_transition(SSL *s, int mt)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_CW_CLNT_HELLO:
-        if (mt == SSL3_MT_SERVER_HELLO) {
-            st->hand_state = TLS_ST_CR_SRVR_HELLO;
-            return 1;
-        }
-
-        if (SSL_IS_DTLS(s)) {
-            if (mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
-                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
-                return 1;
-            }
-        }
-        break;
-
-    case TLS_ST_CR_SRVR_HELLO:
-        if (s->hit) {
-            if (s->tlsext_ticket_expected) {
-                if (mt == SSL3_MT_NEWSESSION_TICKET) {
-                    st->hand_state = TLS_ST_CR_SESSION_TICKET;
-                    return 1;
-                }
-            } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-                st->hand_state = TLS_ST_CR_CHANGE;
-                return 1;
-            }
-        } else {
-            if (SSL_IS_DTLS(s) && mt == DTLS1_MT_HELLO_VERIFY_REQUEST) {
-                st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
-                return 1;
-            } else if (!(s->s3->tmp.new_cipher->algorithm_auth
-                        & (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
-                if (mt == SSL3_MT_CERTIFICATE) {
-                    st->hand_state = TLS_ST_CR_CERT;
-                    return 1;
-                }
-            } else {
-                if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
-                    st->hand_state = TLS_ST_CR_KEY_EXCH;
-                    return 1;
-                } else if (key_exchange_skip_allowed(s)) {
-                    if (mt == SSL3_MT_CERTIFICATE_REQUEST
-                            && cert_req_allowed(s)) {
-                        st->hand_state = TLS_ST_CR_CERT_REQ;
-                        return 1;
-                    } else if (mt == SSL3_MT_SERVER_DONE) {
-                        st->hand_state = TLS_ST_CR_SRVR_DONE;
-                        return 1;
-                    }
-                }
-            }
-        }
-        break;
-
-    case TLS_ST_CR_CERT:
-        if (s->tlsext_status_expected) {
-            if (mt == SSL3_MT_CERTIFICATE_STATUS) {
-                st->hand_state = TLS_ST_CR_CERT_STATUS;
-                return 1;
-            }
-        } else {
-            if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
-                st->hand_state = TLS_ST_CR_KEY_EXCH;
-                return 1;
-            } else if (key_exchange_skip_allowed(s)) {
-                if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
-                    st->hand_state = TLS_ST_CR_CERT_REQ;
-                    return 1;
-                } else if (mt == SSL3_MT_SERVER_DONE) {
-                    st->hand_state = TLS_ST_CR_SRVR_DONE;
-                    return 1;
-                }
-            }
-        }
-        break;
-
-    case TLS_ST_CR_CERT_STATUS:
-        if (mt == SSL3_MT_SERVER_KEY_EXCHANGE) {
-            st->hand_state = TLS_ST_CR_KEY_EXCH;
-            return 1;
-        } else if (key_exchange_skip_allowed(s)) {
-            if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
-                st->hand_state = TLS_ST_CR_CERT_REQ;
-                return 1;
-            } else if (mt == SSL3_MT_SERVER_DONE) {
-                st->hand_state = TLS_ST_CR_SRVR_DONE;
-                return 1;
-            }
-        }
-        break;
-
-    case TLS_ST_CR_KEY_EXCH:
-        if (mt == SSL3_MT_CERTIFICATE_REQUEST && cert_req_allowed(s)) {
-            st->hand_state = TLS_ST_CR_CERT_REQ;
-            return 1;
-        } else if (mt == SSL3_MT_SERVER_DONE) {
-            st->hand_state = TLS_ST_CR_SRVR_DONE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_CR_CERT_REQ:
-        if (mt == SSL3_MT_SERVER_DONE) {
-            st->hand_state = TLS_ST_CR_SRVR_DONE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_CW_FINISHED:
-        if (mt == SSL3_MT_NEWSESSION_TICKET && s->tlsext_ticket_expected) {
-            st->hand_state = TLS_ST_CR_SESSION_TICKET;
-            return 1;
-        } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            st->hand_state = TLS_ST_CR_CHANGE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_CR_SESSION_TICKET:
-        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            st->hand_state = TLS_ST_CR_CHANGE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_CR_CHANGE:
-        if (mt == SSL3_MT_FINISHED) {
-            st->hand_state = TLS_ST_CR_FINISHED;
-            return 1;
-        }
-        break;
-
-    default:
-        break;
-    }
-
-    /* No valid transition found */
-    return 0;
-}
-
 /*
- * client_write_transition() works out what handshake state to move to next
- * when the client is writing messages to be sent to the server.
+ * This function returns 1 if TLS exporter is ready to export keying
+ * material, or 0 if otherwise.
  */
-static enum WRITE_TRAN client_write_transition(SSL *s)
+int ossl_statem_export_allowed(SSL *s)
 {
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-        case TLS_ST_OK:
-            /* Renegotiation - fall through */
-        case TLS_ST_BEFORE:
-            st->hand_state = TLS_ST_CW_CLNT_HELLO;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_CLNT_HELLO:
-            /*
-             * No transition at the end of writing because we don't know what
-             * we will be sent
-             */
-            return WRITE_TRAN_FINISHED;
-
-        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
-            st->hand_state = TLS_ST_CW_CLNT_HELLO;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CR_SRVR_DONE:
-            if (s->s3->tmp.cert_req)
-                st->hand_state = TLS_ST_CW_CERT;
-            else
-                st->hand_state = TLS_ST_CW_KEY_EXCH;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_CERT:
-            st->hand_state = TLS_ST_CW_KEY_EXCH;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_KEY_EXCH:
-            /*
-             * For TLS, cert_req is set to 2, so a cert chain of nothing is
-             * sent, but no verify packet is sent
-             */
-            /*
-             * XXX: For now, we do not support client authentication in ECDH
-             * cipher suites with ECDH (rather than ECDSA) certificates. We
-             * need to skip the certificate verify message when client's
-             * ECDH public key is sent inside the client certificate.
-             */
-            if (s->s3->tmp.cert_req == 1) {
-                st->hand_state = TLS_ST_CW_CERT_VRFY;
-            } else {
-                st->hand_state = TLS_ST_CW_CHANGE;
-            }
-            if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY) {
-                st->hand_state = TLS_ST_CW_CHANGE;
-            }
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_CERT_VRFY:
-            st->hand_state = TLS_ST_CW_CHANGE;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_CW_CHANGE:
-#if defined(OPENSSL_NO_NEXTPROTONEG)
-            st->hand_state = TLS_ST_CW_FINISHED;
-#else
-            if (!SSL_IS_DTLS(s) && s->s3->next_proto_neg_seen)
-                st->hand_state = TLS_ST_CW_NEXT_PROTO;
-            else
-                st->hand_state = TLS_ST_CW_FINISHED;
-#endif
-            return WRITE_TRAN_CONTINUE;
-
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-        case TLS_ST_CW_NEXT_PROTO:
-            st->hand_state = TLS_ST_CW_FINISHED;
-            return WRITE_TRAN_CONTINUE;
-#endif
-
-        case TLS_ST_CW_FINISHED:
-            if (s->hit) {
-                st->hand_state = TLS_ST_OK;
-                statem_set_in_init(s, 0);
-                return WRITE_TRAN_CONTINUE;
-            } else {
-                return WRITE_TRAN_FINISHED;
-            }
-
-        case TLS_ST_CR_FINISHED:
-            if (s->hit) {
-                st->hand_state = TLS_ST_CW_CHANGE;
-                return WRITE_TRAN_CONTINUE;
-            } else {
-                st->hand_state = TLS_ST_OK;
-                statem_set_in_init(s, 0);
-                return WRITE_TRAN_CONTINUE;
-            }
-
-        default:
-            /* Shouldn't happen */
-            return WRITE_TRAN_ERROR;
-    }
-}
-
-/*
- * Perform any pre work that needs to be done prior to sending a message from
- * the client to the server.
- */
-static enum WORK_STATE client_pre_work(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_CW_CLNT_HELLO:
-        s->shutdown = 0;
-        if (SSL_IS_DTLS(s)) {
-            /* every DTLS ClientHello resets Finished MAC */
-            ssl3_init_finished_mac(s);
-        }
-        break;
-
-    case TLS_ST_CW_CERT:
-        return tls_prepare_client_certificate(s, wst);
-
-    case TLS_ST_CW_CHANGE:
-        if (SSL_IS_DTLS(s)) {
-            if (s->hit) {
-                /*
-                 * We're into the last flight so we don't retransmit these
-                 * messages unless we need to.
-                 */
-                st->use_timer = 0;
-            }
-#ifndef OPENSSL_NO_SCTP
-            if (BIO_dgram_is_sctp(SSL_get_wbio(s)))
-                return dtls_wait_for_dry(s);
-#endif
-        }
-        return WORK_FINISHED_CONTINUE;
-
-    case TLS_ST_OK:
-        return tls_finish_handshake(s, wst);
-
-    default:
-        /* No pre work to be done */
-        break;
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Perform any work that needs to be done after sending a message from the
- * client to the server.
- */
-static enum WORK_STATE client_post_work(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    s->init_num = 0;
-
-    switch(st->hand_state) {
-    case TLS_ST_CW_CLNT_HELLO:
-        if (SSL_IS_DTLS(s) && s->d1->cookie_len > 0 && statem_flush(s) != 1)
-            return WORK_MORE_A;
-#ifndef OPENSSL_NO_SCTP
-        /* Disable buffering for SCTP */
-        if (!SSL_IS_DTLS(s) || !BIO_dgram_is_sctp(SSL_get_wbio(s))) {
-#endif
-            /*
-             * turn on buffering for the next lot of output
-             */
-            if (s->bbio != s->wbio)
-                s->wbio = BIO_push(s->bbio, s->wbio);
-#ifndef OPENSSL_NO_SCTP
-            }
-#endif
-        if (SSL_IS_DTLS(s)) {
-            /* Treat the next message as the first packet */
-            s->first_packet = 1;
-        }
-        break;
-
-    case TLS_ST_CW_KEY_EXCH:
-        if (tls_client_key_exchange_post_work(s) == 0)
-            return WORK_ERROR;
-        break;
-
-    case TLS_ST_CW_CHANGE:
-        s->session->cipher = s->s3->tmp.new_cipher;
-#ifdef OPENSSL_NO_COMP
-        s->session->compress_meth = 0;
-#else
-        if (s->s3->tmp.new_compression == NULL)
-            s->session->compress_meth = 0;
-        else
-            s->session->compress_meth = s->s3->tmp.new_compression->id;
-#endif
-        if (!s->method->ssl3_enc->setup_key_block(s))
-            return WORK_ERROR;
-
-        if (!s->method->ssl3_enc->change_cipher_state(s,
-                                                      SSL3_CHANGE_CIPHER_CLIENT_WRITE))
-            return WORK_ERROR;
-
-        if (SSL_IS_DTLS(s)) {
-#ifndef OPENSSL_NO_SCTP
-            if (s->hit) {
-                /*
-                 * Change to new shared key of SCTP-Auth, will be ignored if
-                 * no SCTP used.
-                 */
-                BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                         0, NULL);
-            }
-#endif
-
-            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
-        }
-        break;
-
-    case TLS_ST_CW_FINISHED:
-#ifndef OPENSSL_NO_SCTP
-        if (wst == WORK_MORE_A && SSL_IS_DTLS(s) && s->hit == 0) {
-            /*
-             * Change to new shared key of SCTP-Auth, will be ignored if
-             * no SCTP used.
-             */
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                     0, NULL);
-        }
-#endif
-        if (statem_flush(s) != 1)
-            return WORK_MORE_B;
-
-        if (s->hit && tls_finish_handshake(s, WORK_MORE_A) != 1)
-                return WORK_ERROR;
-        break;
-
-    default:
-        /* No post work to be done */
-        break;
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Construct a message to be sent from the client to the server.
- *
- * Valid return values are:
- *   1: Success
- *   0: Error
- */
-static int client_construct_message(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_CW_CLNT_HELLO:
-        return tls_construct_client_hello(s);
-
-    case TLS_ST_CW_CERT:
-        return tls_construct_client_certificate(s);
-
-    case TLS_ST_CW_KEY_EXCH:
-        return tls_construct_client_key_exchange(s);
-
-    case TLS_ST_CW_CERT_VRFY:
-        return tls_construct_client_verify(s);
-
-    case TLS_ST_CW_CHANGE:
-        if (SSL_IS_DTLS(s))
-            return dtls_construct_change_cipher_spec(s);
-        else
-            return tls_construct_change_cipher_spec(s);
-
-#if !defined(OPENSSL_NO_NEXTPROTONEG)
-    case TLS_ST_CW_NEXT_PROTO:
-        return tls_construct_next_proto(s);
-#endif
-    case TLS_ST_CW_FINISHED:
-        return tls_construct_finished(s,
-                                      s->method->
-                                      ssl3_enc->client_finished_label,
-                                      s->method->
-                                      ssl3_enc->client_finished_label_len);
-
-    default:
-        /* Shouldn't happen */
-        break;
-    }
-
-    return 0;
-}
-
-/* The spec allows for a longer length than this, but we limit it */
-#define HELLO_VERIFY_REQUEST_MAX_LENGTH 258
-#define SERVER_HELLO_MAX_LENGTH         20000
-#define SERVER_KEY_EXCH_MAX_LENGTH      102400
-#define SERVER_HELLO_DONE_MAX_LENGTH    0
-#define CCS_MAX_LENGTH                  1
-/* Max should actually be 36 but we are generous */
-#define FINISHED_MAX_LENGTH             64
-
-/*
- * Returns the maximum allowed length for the current message that we are
- * reading. Excludes the message header.
- */
-static unsigned long client_max_message_size(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-        case TLS_ST_CR_SRVR_HELLO:
-            return SERVER_HELLO_MAX_LENGTH;
-
-        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
-            return HELLO_VERIFY_REQUEST_MAX_LENGTH;
-
-        case TLS_ST_CR_CERT:
-            return s->max_cert_list;
-
-        case TLS_ST_CR_CERT_STATUS:
-            return SSL3_RT_MAX_PLAIN_LENGTH;
-
-        case TLS_ST_CR_KEY_EXCH:
-            return SERVER_KEY_EXCH_MAX_LENGTH;
-
-        case TLS_ST_CR_CERT_REQ:
-            return SSL3_RT_MAX_PLAIN_LENGTH;
-
-        case TLS_ST_CR_SRVR_DONE:
-            return SERVER_HELLO_DONE_MAX_LENGTH;
-
-        case TLS_ST_CR_CHANGE:
-            return CCS_MAX_LENGTH;
-
-        case TLS_ST_CR_SESSION_TICKET:
-            return SSL3_RT_MAX_PLAIN_LENGTH;
-
-        case TLS_ST_CR_FINISHED:
-            return FINISHED_MAX_LENGTH;
-
-        default:
-            /* Shouldn't happen */
-            break;
-    }
-
-    return 0;
-}
-
-/*
- * Process a message that the client has been received from the server.
- */
-static enum MSG_PROCESS_RETURN client_process_message(SSL *s, PACKET *pkt)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-        case TLS_ST_CR_SRVR_HELLO:
-            return tls_process_server_hello(s, pkt);
-
-        case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
-            return dtls_process_hello_verify(s, pkt);
-
-        case TLS_ST_CR_CERT:
-            return tls_process_server_certificate(s, pkt);
-
-        case TLS_ST_CR_CERT_STATUS:
-            return tls_process_cert_status(s, pkt);
-
-        case TLS_ST_CR_KEY_EXCH:
-            return tls_process_key_exchange(s, pkt);
-
-        case TLS_ST_CR_CERT_REQ:
-            return tls_process_certificate_request(s, pkt);
-
-        case TLS_ST_CR_SRVR_DONE:
-            return tls_process_server_done(s, pkt);
-
-        case TLS_ST_CR_CHANGE:
-            return tls_process_change_cipher_spec(s, pkt);
-
-        case TLS_ST_CR_SESSION_TICKET:
-            return tls_process_new_session_ticket(s, pkt);
-
-        case TLS_ST_CR_FINISHED:
-            return tls_process_finished(s, pkt);
-
-        default:
-            /* Shouldn't happen */
-            break;
-    }
-
-    return MSG_PROCESS_ERROR;
-}
-
-/*
- * Perform any further processing required following the receipt of a message
- * from the server
- */
-static enum WORK_STATE client_post_process_message(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-#ifndef OPENSSL_NO_SCTP
-    case TLS_ST_CR_SRVR_DONE:
-        /* We only get here if we are using SCTP and we are renegotiating */
-        if (BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-            s->s3->in_read_app_data = 2;
-            s->rwstate = SSL_READING;
-            BIO_clear_retry_flags(SSL_get_rbio(s));
-            BIO_set_retry_read(SSL_get_rbio(s));
-            statem_set_sctp_read_sock(s, 1);
-            return WORK_MORE_A;
-        }
-        statem_set_sctp_read_sock(s, 0);
-        return WORK_FINISHED_STOP;
-#endif
-
-    case TLS_ST_CR_FINISHED:
-        if (!s->hit)
-            return tls_finish_handshake(s, wst);
-        else
-            return WORK_FINISHED_STOP;
-    default:
-        break;
-    }
-
-    /* Shouldn't happen */
-    return WORK_ERROR;
-}
-
-
-/*
- * server_read_transition() encapsulates the logic for the allowed handshake
- * state transitions when the server is reading messages from the client. The
- * message type that the client has sent is provided in |mt|. The current state
- * is in |s->statem.hand_state|.
- *
- *  Valid return values are:
- *  1: Success (transition allowed)
- *  0: Error (transition not allowed)
- */
-static int server_read_transition(SSL *s, int mt)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_BEFORE:
-    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-        if (mt == SSL3_MT_CLIENT_HELLO) {
-            st->hand_state = TLS_ST_SR_CLNT_HELLO;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_SW_SRVR_DONE:
-        /*
-         * If we get a CKE message after a ServerDone then either
-         * 1) We didn't request a Certificate
-         * OR
-         * 2) If we did request one then
-         *      a) We allow no Certificate to be returned
-         *      AND
-         *      b) We are running SSL3 (in TLS1.0+ the client must return a 0
-         *         list if we requested a certificate)
-         */
-        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE
-                && (!s->s3->tmp.cert_request
-                    || (!((s->verify_mode & SSL_VERIFY_PEER) &&
-                          (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
-                        && (s->version == SSL3_VERSION)))) {
-            st->hand_state = TLS_ST_SR_KEY_EXCH;
-            return 1;
-        } else if (s->s3->tmp.cert_request) {
-            if (mt == SSL3_MT_CERTIFICATE) {
-                st->hand_state = TLS_ST_SR_CERT;
-                return 1;
-            } 
-        }
-        break;
-
-    case TLS_ST_SR_CERT:
-        if (mt == SSL3_MT_CLIENT_KEY_EXCHANGE) {
-            st->hand_state = TLS_ST_SR_KEY_EXCH;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_SR_KEY_EXCH:
-        /*
-         * We should only process a CertificateVerify message if we have
-         * received a Certificate from the client. If so then |s->session->peer|
-         * will be non NULL. In some instances a CertificateVerify message is
-         * not required even if the peer has sent a Certificate (e.g. such as in
-         * the case of static DH). In that case |s->no_cert_verify| should be
-         * set.
-         */
-        if (s->session->peer == NULL || s->no_cert_verify) {
-            if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-                /*
-                 * For the ECDH ciphersuites when the client sends its ECDH
-                 * pub key in a certificate, the CertificateVerify message is
-                 * not sent. Also for GOST ciphersuites when the client uses
-                 * its key from the certificate for key exchange.
-                 */
-                st->hand_state = TLS_ST_SR_CHANGE;
-                return 1;
-            }
-        } else {
-            if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
-                st->hand_state = TLS_ST_SR_CERT_VRFY;
-                return 1;
-            }
-        }
-        break;
-
-    case TLS_ST_SR_CERT_VRFY:
-        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            st->hand_state = TLS_ST_SR_CHANGE;
-            return 1;
-        }
-        break;
-
-    case TLS_ST_SR_CHANGE:
-#ifndef OPENSSL_NO_NEXTPROTONEG
-        if (s->s3->next_proto_neg_seen) {
-            if (mt == SSL3_MT_NEXT_PROTO) {
-                st->hand_state = TLS_ST_SR_NEXT_PROTO;
-                return 1;
-            }
-        } else {
-#endif
-            if (mt == SSL3_MT_FINISHED) {
-                st->hand_state = TLS_ST_SR_FINISHED;
-                return 1;
-            }
-#ifndef OPENSSL_NO_NEXTPROTONEG
-        }
-#endif
-        break;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    case TLS_ST_SR_NEXT_PROTO:
-        if (mt == SSL3_MT_FINISHED) {
-            st->hand_state = TLS_ST_SR_FINISHED;
-            return 1;
-        }
-        break;
-#endif
-
-    case TLS_ST_SW_FINISHED:
-        if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
-            st->hand_state = TLS_ST_SR_CHANGE;
-            return 1;
-        }
-        break;
-
-    default:
-        break;
-    }
-
-    /* No valid transition found */
-    return 0;
-}
-
-/*
- * Should we send a ServerKeyExchange message?
- *
- * Valid return values are:
- *   1: Yes
- *   0: No
- */
-static inline int send_server_key_exchange(SSL *s)
-{
-    unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
-
-    /*
-     * only send a ServerKeyExchange if DH, fortezza or RSA but we have a
-     * sign only certificate PSK: may send PSK identity hints For
-     * ECC ciphersuites, we send a serverKeyExchange message only if
-     * the cipher suite is either ECDH-anon or ECDHE. In other cases,
-     * the server certificate contains the server's public key for
-     * key exchange.
-     */
-    if (   (alg_k & SSL_kDHE)
-        || (alg_k & SSL_kECDHE)
-        || ((alg_k & SSL_kRSA)
-            && (s->cert->pkeys[SSL_PKEY_RSA_ENC].privatekey == NULL
-                || (SSL_C_IS_EXPORT(s->s3->tmp.new_cipher)
-                    && EVP_PKEY_size(s->cert->pkeys
-                                     [SSL_PKEY_RSA_ENC].privatekey) *
-                    8 > SSL_C_EXPORT_PKEYLENGTH(s->s3->tmp.new_cipher)
-                   )
-               )
-           )
-        /*
-         * PSK: send ServerKeyExchange if PSK identity hint if
-         * provided
-         */
-#ifndef OPENSSL_NO_PSK
-        /* Only send SKE if we have identity hint for plain PSK */
-        || ((alg_k & (SSL_kPSK | SSL_kRSAPSK))
-            && s->cert->psk_identity_hint)
-        /* For other PSK always send SKE */
-        || (alg_k & (SSL_PSK & (SSL_kDHEPSK | SSL_kECDHEPSK)))
-#endif
-#ifndef OPENSSL_NO_SRP
-        /* SRP: send ServerKeyExchange */
-        || (alg_k & SSL_kSRP)
-#endif
-       ) {
-        return 1;
-    }
-
-    return 0;
-}
-
-/*
- * Should we send a CertificateRequest message?
- *
- * Valid return values are:
- *   1: Yes
- *   0: No
- */
-static inline int send_certificate_request(SSL *s)
-{
-    if (
-           /* don't request cert unless asked for it: */
-           s->verify_mode & SSL_VERIFY_PEER
-           /*
-            * if SSL_VERIFY_CLIENT_ONCE is set, don't request cert
-            * during re-negotiation:
-            */
-           && ((s->session->peer == NULL) ||
-               !(s->verify_mode & SSL_VERIFY_CLIENT_ONCE))
-           /*
-            * never request cert in anonymous ciphersuites (see
-            * section "Certificate request" in SSL 3 drafts and in
-            * RFC 2246):
-            */
-           && (!(s->s3->tmp.new_cipher->algorithm_auth & SSL_aNULL)
-           /*
-            * ... except when the application insists on
-            * verification (against the specs, but s3_clnt.c accepts
-            * this for SSL 3)
-            */
-               || (s->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT))
-           /* don't request certificate for SRP auth */
-           && !(s->s3->tmp.new_cipher->algorithm_auth & SSL_aSRP)
-           /*
-            * With normal PSK Certificates and Certificate Requests
-            * are omitted
-            */
-           && !(s->s3->tmp.new_cipher->algorithm_mkey & SSL_PSK)) {
-        return 1;
-    }
-
-    return 0;
-}
-
-/*
- * server_write_transition() works out what handshake state to move to next
- * when the server is writing messages to be sent to the client.
- */
-static enum WRITE_TRAN server_write_transition(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-        case TLS_ST_BEFORE:
-            /* Just go straight to trying to read from the client */;
-            return WRITE_TRAN_FINISHED;
-
-        case TLS_ST_OK:
-            /* We must be trying to renegotiate */
-            st->hand_state = TLS_ST_SW_HELLO_REQ;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_HELLO_REQ:
-            st->hand_state = TLS_ST_OK;
-            statem_set_in_init(s, 0);
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SR_CLNT_HELLO:
-            if (SSL_IS_DTLS(s) && !s->d1->cookie_verified
-                    && (SSL_get_options(s) & SSL_OP_COOKIE_EXCHANGE))
-                st->hand_state = DTLS_ST_SW_HELLO_VERIFY_REQUEST;
-            else
-                st->hand_state = TLS_ST_SW_SRVR_HELLO;
-            return WRITE_TRAN_CONTINUE;
-
-        case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-            return WRITE_TRAN_FINISHED;
-
-        case TLS_ST_SW_SRVR_HELLO:
-            if (s->hit) {
-                if (s->tlsext_ticket_expected)
-                    st->hand_state = TLS_ST_SW_SESSION_TICKET;
-                else
-                    st->hand_state = TLS_ST_SW_CHANGE;
-            } else {
-                /* Check if it is anon DH or anon ECDH, */
-                /* normal PSK or SRP */
-                if (!(s->s3->tmp.new_cipher->algorithm_auth &
-                     (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
-                    st->hand_state = TLS_ST_SW_CERT;
-                } else if (send_server_key_exchange(s)) {
-                    st->hand_state = TLS_ST_SW_KEY_EXCH;
-                } else if (send_certificate_request(s)) {
-                    st->hand_state = TLS_ST_SW_CERT_REQ;
-                } else {
-                    st->hand_state = TLS_ST_SW_SRVR_DONE;
-                }
-            }
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_CERT:
-            if (s->tlsext_status_expected) {
-                st->hand_state = TLS_ST_SW_CERT_STATUS;
-                return WRITE_TRAN_CONTINUE;
-            }
-            /* Fall through */
-
-        case TLS_ST_SW_CERT_STATUS:
-            if (send_server_key_exchange(s)) {
-                st->hand_state = TLS_ST_SW_KEY_EXCH;
-                return WRITE_TRAN_CONTINUE;
-            }
-            /* Fall through */
-
-        case TLS_ST_SW_KEY_EXCH:
-            if (send_certificate_request(s)) {
-                st->hand_state = TLS_ST_SW_CERT_REQ;
-                return WRITE_TRAN_CONTINUE;
-            }
-            /* Fall through */
-
-        case TLS_ST_SW_CERT_REQ:
-            st->hand_state = TLS_ST_SW_SRVR_DONE;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_SRVR_DONE:
-            return WRITE_TRAN_FINISHED;
-
-        case TLS_ST_SR_FINISHED:
-            if (s->hit) {
-                st->hand_state = TLS_ST_OK;
-                statem_set_in_init(s, 0);
-                return WRITE_TRAN_CONTINUE;
-            } else if (s->tlsext_ticket_expected) {
-                st->hand_state = TLS_ST_SW_SESSION_TICKET;
-            } else {
-                st->hand_state = TLS_ST_SW_CHANGE;
-            }
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_SESSION_TICKET:
-            st->hand_state = TLS_ST_SW_CHANGE;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_CHANGE:
-            st->hand_state = TLS_ST_SW_FINISHED;
-            return WRITE_TRAN_CONTINUE;
-
-        case TLS_ST_SW_FINISHED:
-            if (s->hit) {
-                return WRITE_TRAN_FINISHED;
-            }
-            st->hand_state = TLS_ST_OK;
-            statem_set_in_init(s, 0);
-            return WRITE_TRAN_CONTINUE;
-
-        default:
-            /* Shouldn't happen */
-            return WRITE_TRAN_ERROR;
-    }
-}
-
-/*
- * Perform any pre work that needs to be done prior to sending a message from
- * the server to the client.
- */
-static enum WORK_STATE server_pre_work(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_SW_HELLO_REQ:
-        s->shutdown = 0;
-        if (SSL_IS_DTLS(s))
-            dtls1_clear_record_buffer(s);
-        break;
-
-    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-        s->shutdown = 0;
-        if (SSL_IS_DTLS(s)) {
-            dtls1_clear_record_buffer(s);
-            /* We don't buffer this message so don't use the timer */
-            st->use_timer = 0;
-        }
-        break;
-
-    case TLS_ST_SW_SRVR_HELLO:
-        if (SSL_IS_DTLS(s)) {
-            /*
-             * Messages we write from now on should be bufferred and
-             * retransmitted if necessary, so we need to use the timer now
-             */
-            st->use_timer = 1;
-        }
-        break;
-
-    case TLS_ST_SW_SRVR_DONE:
-#ifndef OPENSSL_NO_SCTP
-        if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s)))
-            return dtls_wait_for_dry(s);
-#endif
-        return WORK_FINISHED_CONTINUE;
-
-    case TLS_ST_SW_SESSION_TICKET:
-        if (SSL_IS_DTLS(s)) {
-            /*
-             * We're into the last flight. We don't retransmit the last flight
-             * unless we need to, so we don't use the timer
-             */
-            st->use_timer = 0;
-        }
-        break;
-
-    case TLS_ST_SW_CHANGE:
-        s->session->cipher = s->s3->tmp.new_cipher;
-        if (!s->method->ssl3_enc->setup_key_block(s)) {
-            statem_set_error(s);
-            return WORK_ERROR;
-        }
-        if (SSL_IS_DTLS(s)) {
-            /*
-             * We're into the last flight. We don't retransmit the last flight
-             * unless we need to, so we don't use the timer. This might have
-             * already been set to 0 if we sent a NewSessionTicket message,
-             * but we'll set it again here in case we didn't.
-             */
-            st->use_timer = 0;
-        }
-        return WORK_FINISHED_CONTINUE;
-
-    case TLS_ST_OK:
-        return tls_finish_handshake(s, wst);
-
-    default:
-        /* No pre work to be done */
-        break;
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Perform any work that needs to be done after sending a message from the
- * server to the client.
- */
-static enum WORK_STATE server_post_work(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    s->init_num = 0;
-
-    switch(st->hand_state) {
-    case TLS_ST_SW_HELLO_REQ:
-        if (statem_flush(s) != 1)
-            return WORK_MORE_A;
-        ssl3_init_finished_mac(s);
-        break;
-
-    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-        if (statem_flush(s) != 1)
-            return WORK_MORE_A;
-        /* HelloVerifyRequest resets Finished MAC */
-        if (s->version != DTLS1_BAD_VER)
-            ssl3_init_finished_mac(s);
-        /*
-         * The next message should be another ClientHello which we need to
-         * treat like it was the first packet
-         */
-        s->first_packet = 1;
-        break;
-
-    case TLS_ST_SW_SRVR_HELLO:
-#ifndef OPENSSL_NO_SCTP
-        if (SSL_IS_DTLS(s) && s->hit) {
-            unsigned char sctpauthkey[64];
-            char labelbuffer[sizeof(DTLS1_SCTP_AUTH_LABEL)];
-
-            /*
-             * Add new shared key for SCTP-Auth, will be ignored if no
-             * SCTP used.
-             */
-            snprintf((char *)labelbuffer, sizeof(DTLS1_SCTP_AUTH_LABEL),
-                     DTLS1_SCTP_AUTH_LABEL);
-
-            if (SSL_export_keying_material(s, sctpauthkey,
-                    sizeof(sctpauthkey), labelbuffer,
-                    sizeof(labelbuffer), NULL, 0, 0) <= 0) {
-                statem_set_error(s);
-                return WORK_ERROR;
-            }
-
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY,
-                     sizeof(sctpauthkey), sctpauthkey);
-        }
-#endif
-        break;
-
-    case TLS_ST_SW_CHANGE:
-#ifndef OPENSSL_NO_SCTP
-        if (SSL_IS_DTLS(s) && !s->hit) {
-            /*
-             * Change to new shared key of SCTP-Auth, will be ignored if
-             * no SCTP used.
-             */
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                     0, NULL);
-        }
-#endif
-        if (!s->method->ssl3_enc->change_cipher_state(s,
-                SSL3_CHANGE_CIPHER_SERVER_WRITE)) {
-            statem_set_error(s);
-            return WORK_ERROR;
-        }
-
-        if (SSL_IS_DTLS(s))
-            dtls1_reset_seq_numbers(s, SSL3_CC_WRITE);
-        break;
-
-    case TLS_ST_SW_SRVR_DONE:
-        if (statem_flush(s) != 1)
-            return WORK_MORE_A;
-        break;
-
-    case TLS_ST_SW_FINISHED:
-        if (statem_flush(s) != 1)
-            return WORK_MORE_A;
-#ifndef OPENSSL_NO_SCTP
-        if (SSL_IS_DTLS(s) && s->hit) {
-            /*
-             * Change to new shared key of SCTP-Auth, will be ignored if
-             * no SCTP used.
-             */
-            BIO_ctrl(SSL_get_wbio(s), BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY,
-                     0, NULL);
-        }
-#endif
-        break;
-
-    default:
-        /* No post work to be done */
-        break;
-    }
-
-    return WORK_FINISHED_CONTINUE;
-}
-
-/*
- * Construct a message to be sent from the server to the client.
- *
- * Valid return values are:
- *   1: Success
- *   0: Error
- */
-static int server_construct_message(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case DTLS_ST_SW_HELLO_VERIFY_REQUEST:
-        return dtls_construct_hello_verify_request(s);
-
-    case TLS_ST_SW_HELLO_REQ:
-        return tls_construct_hello_request(s);
-
-    case TLS_ST_SW_SRVR_HELLO:
-        return tls_construct_server_hello(s);
-
-    case TLS_ST_SW_CERT:
-        return tls_construct_server_certificate(s);
-
-    case TLS_ST_SW_KEY_EXCH:
-        return tls_construct_server_key_exchange(s);
-
-    case TLS_ST_SW_CERT_REQ:
-        return tls_construct_certificate_request(s);
-
-    case TLS_ST_SW_SRVR_DONE:
-        return tls_construct_server_done(s);
-
-    case TLS_ST_SW_SESSION_TICKET:
-        return tls_construct_new_session_ticket(s);
-
-    case TLS_ST_SW_CERT_STATUS:
-        return tls_construct_cert_status(s);
-
-    case TLS_ST_SW_CHANGE:
-        if (SSL_IS_DTLS(s))
-            return dtls_construct_change_cipher_spec(s);
-        else
-            return tls_construct_change_cipher_spec(s);
-
-    case TLS_ST_SW_FINISHED:
-        return tls_construct_finished(s,
-                                      s->method->
-                                      ssl3_enc->server_finished_label,
-                                      s->method->
-                                      ssl3_enc->server_finished_label_len);
-
-    default:
-        /* Shouldn't happen */
-        break;
-    }
-
-    return 0;
-}
-
-#define CLIENT_KEY_EXCH_MAX_LENGTH      2048
-#define NEXT_PROTO_MAX_LENGTH           514
-
-/*
- * Returns the maximum allowed length for the current message that we are
- * reading. Excludes the message header.
- */
-static unsigned long server_max_message_size(SSL *s)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_SR_CLNT_HELLO:
-        return SSL3_RT_MAX_PLAIN_LENGTH;
-
-    case TLS_ST_SR_CERT:
-        return s->max_cert_list;
-
-    case TLS_ST_SR_KEY_EXCH:
-        return CLIENT_KEY_EXCH_MAX_LENGTH;
-
-    case TLS_ST_SR_CERT_VRFY:
-        return SSL3_RT_MAX_PLAIN_LENGTH;
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    case TLS_ST_SR_NEXT_PROTO:
-        return NEXT_PROTO_MAX_LENGTH;
-#endif
-
-    case TLS_ST_SR_CHANGE:
-        return CCS_MAX_LENGTH;
-
-    case TLS_ST_SR_FINISHED:
-        return FINISHED_MAX_LENGTH;
-
-    default:
-        /* Shouldn't happen */
-        break;
-    }
-
-    return 0;
-}
-
-/*
- * Process a message that the server has received from the client.
- */
-static enum MSG_PROCESS_RETURN  server_process_message(SSL *s, PACKET *pkt)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_SR_CLNT_HELLO:
-        return tls_process_client_hello(s, pkt);
-
-    case TLS_ST_SR_CERT:
-        return tls_process_client_certificate(s, pkt);
-
-    case TLS_ST_SR_KEY_EXCH:
-        return tls_process_client_key_exchange(s, pkt);
-
-    case TLS_ST_SR_CERT_VRFY:
-        return tls_process_cert_verify(s, pkt);
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
-    case TLS_ST_SR_NEXT_PROTO:
-        return tls_process_next_proto(s, pkt);
-#endif
-
-    case TLS_ST_SR_CHANGE:
-        return tls_process_change_cipher_spec(s, pkt);
-
-    case TLS_ST_SR_FINISHED:
-        return tls_process_finished(s, pkt);
-
-    default:
-        /* Shouldn't happen */
-        break;
-    }
-
-    return MSG_PROCESS_ERROR;
-}
-
-/*
- * Perform any further processing required following the receipt of a message
- * from the client
- */
-static enum WORK_STATE server_post_process_message(SSL *s, enum WORK_STATE wst)
-{
-    STATEM *st = &s->statem;
-
-    switch(st->hand_state) {
-    case TLS_ST_SR_CLNT_HELLO:
-        return tls_post_process_client_hello(s, wst);
-
-    case TLS_ST_SR_KEY_EXCH:
-        return tls_post_process_client_key_exchange(s, wst);
-
-    case TLS_ST_SR_CERT_VRFY:
-#ifndef OPENSSL_NO_SCTP
-        if (    /* Is this SCTP? */
-                BIO_dgram_is_sctp(SSL_get_wbio(s))
-                /* Are we renegotiating? */
-                && s->renegotiate
-                && BIO_dgram_sctp_msg_waiting(SSL_get_rbio(s))) {
-            s->s3->in_read_app_data = 2;
-            s->rwstate = SSL_READING;
-            BIO_clear_retry_flags(SSL_get_rbio(s));
-            BIO_set_retry_read(SSL_get_rbio(s));
-            statem_set_sctp_read_sock(s, 1);
-            return WORK_MORE_A;
-        } else {
-            statem_set_sctp_read_sock(s, 0);
-        }
-#endif
-        return WORK_FINISHED_CONTINUE;
-
-
-    case TLS_ST_SR_FINISHED:
-        if (s->hit)
-            return tls_finish_handshake(s, wst);
-        else
-            return WORK_FINISHED_STOP;
-    default:
-        break;
-    }
-
-    /* Shouldn't happen */
-    return WORK_ERROR;
+    return s->s3->previous_server_finished_len != 0
+           && s->statem.hand_state != TLS_ST_SW_FINISHED;
 }