Move state machine knowledge out of the record layer
authorMatt Caswell <matt@openssl.org>
Tue, 10 Jan 2017 23:02:28 +0000 (23:02 +0000)
committerMatt Caswell <matt@openssl.org>
Mon, 30 Jan 2017 10:17:00 +0000 (10:17 +0000)
The record layer was making decisions that should really be left to the
state machine around unexpected handshake messages that are received after
the initial handshake (i.e. renegotiation related messages). This commit
removes that code from the record layer and updates the state machine
accordingly. This simplifies the state machine and paves the way for
handling other messages post-handshake such as the NewSessionTicket in
TLSv1.3.

Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2259)

16 files changed:
include/openssl/ssl.h
ssl/record/rec_layer_d1.c
ssl/record/rec_layer_s3.c
ssl/s3_lib.c
ssl/ssl_err.c
ssl/ssl_lib.c
ssl/ssl_locl.h
ssl/statem/extensions_clnt.c
ssl/statem/extensions_srvr.c
ssl/statem/statem.c
ssl/statem/statem.h
ssl/statem/statem_clnt.c
ssl/statem/statem_dtls.c
ssl/statem/statem_lib.c
ssl/statem/statem_locl.h
ssl/statem/statem_srvr.c

index 86ffcb978f43c1f2a82fbbe5023fd7ed6b4e2b43..e95fdb484261ec29bd9349267a83e90cb23ecb5c 100644 (file)
@@ -878,7 +878,8 @@ typedef enum {
     TLS_ST_SW_ENCRYPTED_EXTENSIONS,
     TLS_ST_CR_ENCRYPTED_EXTENSIONS,
     TLS_ST_CR_CERT_VRFY,
-    TLS_ST_SW_CERT_VRFY
+    TLS_ST_SW_CERT_VRFY,
+    TLS_ST_CR_HELLO_REQ
 } OSSL_HANDSHAKE_STATE;
 
 /*
@@ -1647,7 +1648,7 @@ __owur STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s);
 
 __owur int SSL_do_handshake(SSL *s);
 int SSL_renegotiate(SSL *s);
-__owur int SSL_renegotiate_abbreviated(SSL *s);
+int SSL_renegotiate_abbreviated(SSL *s);
 __owur int SSL_renegotiate_pending(SSL *s);
 int SSL_shutdown(SSL *s);
 
@@ -2344,6 +2345,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE            382
 # define SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS           444
 # define SSL_F_TLS_PROCESS_FINISHED                       364
+# define SSL_F_TLS_PROCESS_HELLO_REQ                      507
 # define SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT          442
 # define SSL_F_TLS_PROCESS_KEY_EXCHANGE                   365
 # define SSL_F_TLS_PROCESS_NEW_SESSION_TICKET             366
@@ -2356,6 +2358,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_TLS_PROCESS_SKE_PSK_PREAMBLE               421
 # define SSL_F_TLS_PROCESS_SKE_SRP                        422
 # define SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT                450
+# define SSL_F_TLS_SETUP_HANDSHAKE                        508
 # define SSL_F_USE_CERTIFICATE_CHAIN_FILE                 220
 
 /* Reason codes. */
index 0a32f07c2a778f9e1b712a45ad61bb65484971ee..67846bd19f62ed833358c8756d4b1af1e9422367 100644 (file)
@@ -14,6 +14,7 @@
 #include <openssl/evp.h>
 #include <openssl/buffer.h>
 #include "record_locl.h"
+#include <assert.h>
 
 int DTLS_RECORD_LAYER_new(RECORD_LAYER *rl)
 {
@@ -632,70 +633,6 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
      */
 
-    /* If we are a client, check for an incoming 'Hello Request': */
-    if ((!s->server) &&
-        (s->rlayer.d->handshake_fragment_len >= DTLS1_HM_HEADER_LENGTH) &&
-        (s->rlayer.d->handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
-        (s->session != NULL) && (s->session->cipher != NULL)) {
-        s->rlayer.d->handshake_fragment_len = 0;
-
-        if ((s->rlayer.d->handshake_fragment[1] != 0) ||
-            (s->rlayer.d->handshake_fragment[2] != 0) ||
-            (s->rlayer.d->handshake_fragment[3] != 0)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_BAD_HELLO_REQUEST);
-            goto f_err;
-        }
-
-        /*
-         * no need to check sequence number on HELLO REQUEST messages
-         */
-
-        if (s->msg_callback)
-            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
-                            s->rlayer.d->handshake_fragment, 4, s,
-                            s->msg_callback_arg);
-
-        if (SSL_is_init_finished(s) &&
-            !s->s3->renegotiate) {
-            s->d1->handshake_read_seq++;
-            s->new_session = 1;
-            ssl3_renegotiate(s);
-            if (ssl3_renegotiate_check(s)) {
-                i = s->handshake_func(s);
-                if (i < 0)
-                    return i;
-                if (i == 0) {
-                    SSLerr(SSL_F_DTLS1_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);
-                    return -1;
-                }
-
-                if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
-                    if (SSL3_BUFFER_get_left(&s->rlayer.rbuf) == 0) {
-                        /* no read-ahead left? */
-                        BIO *bio;
-                        /*
-                         * In the case where we try to read application data,
-                         * but we trigger an SSL handshake, we return -1 with
-                         * the retry option set.  Otherwise renegotiation may
-                         * cause nasty problems in the blocking world
-                         */
-                        s->rwstate = SSL_READING;
-                        bio = SSL_get_rbio(s);
-                        BIO_clear_retry_flags(bio);
-                        BIO_set_retry_read(bio);
-                        return -1;
-                    }
-                }
-            }
-        }
-        /*
-         * we either finished a handshake or ignored the request, now try
-         * again to obtain the (application) data we were asked for
-         */
-        goto start;
-    }
-
     if (s->rlayer.d->alert_fragment_len >= DTLS1_AL_HEADER_LENGTH) {
         int alert_level = s->rlayer.d->alert_fragment[0];
         int alert_descr = s->rlayer.d->alert_fragment[1];
@@ -837,11 +774,22 @@ int dtls1_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
             goto start;
         }
 
-        if (SSL_is_init_finished(s)) {
-            ossl_statem_set_in_init(s, 1);
-            s->renegotiate = 1;
-            s->new_session = 1;
+        /*
+         * To get here we must be trying to read app data but found handshake
+         * data. But if we're trying to read app data, and we're not in init
+         * (which is tested for at the top of this function) then init must be
+         * finished
+         */
+        assert(SSL_is_init_finished(s));
+        if (!SSL_is_init_finished(s)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_DTLS1_READ_BYTES, ERR_R_INTERNAL_ERROR);
+            goto f_err;
         }
+
+        /* We found handshake data, so we're going back into init */
+        ossl_statem_set_in_init(s, 1);
+
         i = s->handshake_func(s);
         if (i < 0)
             return i;
index b4dee6e21d48a9c5887586b5579523d61a159ac1..59aa8d4caec0db47acc6172346a9fe2aaa594cb7 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <stdio.h>
+#include <assert.h>
 #include <limits.h>
 #include <errno.h>
 #define USE_SOCKETS
@@ -1387,69 +1388,6 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
      * (Possibly rr is 'empty' now, i.e. rr->length may be 0.)
      */
 
-    /* If we are a client, check for an incoming 'Hello Request': */
-    if ((!s->server) &&
-        (s->rlayer.handshake_fragment_len >= 4) &&
-        !SSL_IS_TLS13(s) &&
-        (s->rlayer.handshake_fragment[0] == SSL3_MT_HELLO_REQUEST) &&
-        (s->session != NULL) && (s->session->cipher != NULL)) {
-        s->rlayer.handshake_fragment_len = 0;
-
-        if ((s->rlayer.handshake_fragment[1] != 0) ||
-            (s->rlayer.handshake_fragment[2] != 0) ||
-            (s->rlayer.handshake_fragment[3] != 0)) {
-            al = SSL_AD_DECODE_ERROR;
-            SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_BAD_HELLO_REQUEST);
-            goto f_err;
-        }
-
-        if (s->msg_callback)
-            s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE,
-                            s->rlayer.handshake_fragment, 4, s,
-                            s->msg_callback_arg);
-
-        if (SSL_is_init_finished(s) &&
-            !s->s3->renegotiate) {
-            ssl3_renegotiate(s);
-            if (ssl3_renegotiate_check(s)) {
-                i = s->handshake_func(s);
-                if (i < 0)
-                    return i;
-                if (i == 0) {
-                    SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_SSL_HANDSHAKE_FAILURE);
-                    return -1;
-                }
-
-                if (!(s->mode & SSL_MODE_AUTO_RETRY)) {
-                    if (SSL3_BUFFER_get_left(rbuf) == 0) {
-                        /* no read-ahead left? */
-                        BIO *bio;
-                        /*
-                         * In the case where we try to read application data,
-                         * but we trigger an SSL handshake, we return -1 with
-                         * the retry option set.  Otherwise renegotiation may
-                         * cause nasty problems in the blocking world
-                         */
-                        s->rwstate = SSL_READING;
-                        bio = SSL_get_rbio(s);
-                        BIO_clear_retry_flags(bio);
-                        BIO_set_retry_read(bio);
-                        return -1;
-                    }
-                }
-            } else {
-                SSL3_RECORD_set_read(rr);
-            }
-        } else {
-            /* Does this ever happen? */
-            SSL3_RECORD_set_read(rr);
-        }
-        /*
-         * we either finished a handshake or ignored the request, now try
-         * again to obtain the (application) data we were asked for
-         */
-        goto start;
-    }
     /*
      * If we are a server and get a client hello when renegotiation isn't
      * allowed send back a no renegotiation alert and carry on. WARNING:
@@ -1558,18 +1496,27 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
     }
 
     /*
-     * Unexpected handshake message (Client Hello, NewSessionTicket (TLS1.3) or
+     * Unexpected handshake message (ClientHello, NewSessionTicket (TLS1.3) or
      * protocol violation)
      */
     if ((s->rlayer.handshake_fragment_len >= 4)
-        && !ossl_statem_get_in_handshake(s)) {
-        if (SSL_is_init_finished(s)) {
-            ossl_statem_set_in_init(s, 1);
-            if (!SSL_IS_TLS13(s)) {
-                s->renegotiate = 1;
-                s->new_session = 1;
-            }
+            && !ossl_statem_get_in_handshake(s)) {
+        /*
+         * To get here we must be trying to read app data but found handshake
+         * data. But if we're trying to read app data, and we're not in init
+         * (which is tested for at the top of this function) then init must be
+         * finished
+         */
+        assert(SSL_is_init_finished(s));
+        if (!SSL_is_init_finished(s)) {
+            al = SSL_AD_INTERNAL_ERROR;
+            SSLerr(SSL_F_SSL3_READ_BYTES, ERR_R_INTERNAL_ERROR);
+            goto f_err;
         }
+
+        /* We found handshake data, so we're going back into init */
+        ossl_statem_set_in_init(s, 1);
+
         i = s->handshake_func(s);
         if (i < 0)
             return i;
index ff4a03b14782f9222edeab48af330b7bee5196ae..1655333b13d0f384207f5d8b0d6549c486eeed93 100644 (file)
@@ -3822,7 +3822,7 @@ int ssl3_write(SSL *s, const void *buf, size_t len, size_t *written)
 {
     clear_sys_error();
     if (s->s3->renegotiate)
-        ssl3_renegotiate_check(s);
+        ssl3_renegotiate_check(s, 0);
 
     return s->method->ssl_write_bytes(s, SSL3_RT_APPLICATION_DATA, buf, len,
                                       written);
@@ -3835,7 +3835,7 @@ static int ssl3_read_internal(SSL *s, void *buf, size_t len, int peek,
 
     clear_sys_error();
     if (s->s3->renegotiate)
-        ssl3_renegotiate_check(s);
+        ssl3_renegotiate_check(s, 0);
     s->s3->in_read_app_data = 1;
     ret =
         s->method->ssl_read_bytes(s, SSL3_RT_APPLICATION_DATA, NULL, buf, len,
@@ -3878,14 +3878,22 @@ int ssl3_renegotiate(SSL *s)
     return (1);
 }
 
-int ssl3_renegotiate_check(SSL *s)
+/*
+ * Check if we are waiting to do a renegotiation and if so whether now is a
+ * good time to do it. If |initok| is true then we are being called from inside
+ * the state machine so ignore the result of SSL_in_init(s). Otherwise we
+ * should not do a renegotiation if SSL_in_init(s) is true. Returns 1 if we
+ * should do a renegotiation now and sets up the state machine for it. Otherwise
+ * returns 0.
+ */
+int ssl3_renegotiate_check(SSL *s, int initok)
 {
     int ret = 0;
 
     if (s->s3->renegotiate) {
         if (!RECORD_LAYER_read_pending(&s->rlayer)
             && !RECORD_LAYER_write_pending(&s->rlayer)
-            && !SSL_in_init(s)) {
+            && (initok || !SSL_in_init(s))) {
             /*
              * if we are the server, and we have sent a 'RENEGOTIATE'
              * message, we need to set the state machine into the renegotiate
@@ -3898,7 +3906,7 @@ int ssl3_renegotiate_check(SSL *s)
             ret = 1;
         }
     }
-    return (ret);
+    return ret;
 }
 
 /*
index d380c86b9b7c050335555001b5f4c0ae541e833a..099af01371629018ab064a764f08b31b42a8d3c3 100644 (file)
@@ -402,6 +402,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS),
      "tls_process_encrypted_extensions"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_FINISHED), "tls_process_finished"},
+    {ERR_FUNC(SSL_F_TLS_PROCESS_HELLO_REQ), "tls_process_hello_req"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT),
      "tls_process_initial_server_flight"},
     {ERR_FUNC(SSL_F_TLS_PROCESS_KEY_EXCHANGE), "tls_process_key_exchange"},
@@ -419,6 +420,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_TLS_PROCESS_SKE_SRP), "tls_process_ske_srp"},
     {ERR_FUNC(SSL_F_TLS_SCAN_CLIENTHELLO_TLSEXT),
      "tls_scan_clienthello_tlsext"},
+    {ERR_FUNC(SSL_F_TLS_SETUP_HANDSHAKE), "tls_setup_handshake"},
     {ERR_FUNC(SSL_F_USE_CERTIFICATE_CHAIN_FILE),
      "use_certificate_chain_file"},
     {0, NULL}
index 8ca1a3c778b26d2126e2def02f86a1453a2775d3..8e6a14393c731a7b82c8e0f0a7710dfed88b4e01 100644 (file)
@@ -3087,7 +3087,7 @@ int SSL_do_handshake(SSL *s)
         return -1;
     }
 
-    s->method->ssl_renegotiate_check(s);
+    s->method->ssl_renegotiate_check(s, 0);
 
     if (SSL_in_init(s) || SSL_in_before(s)) {
         if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) {
index 39e27eac1b7f0ce6a62e69e7763980d3409b4d9a..ef525fe6e103d8c459529b23783318379b2885b9 100644 (file)
                           && (s)->method->version >= TLS1_3_VERSION \
                           && (s)->method->version != TLS_ANY_VERSION)
 
+# define SSL_IS_FIRST_HANDSHAKE(S) ((s)->s3->tmp.finish_md_len == 0)
+
 /* See if we need explicit IV */
 # define SSL_USE_EXPLICIT_IV(s)  \
                 (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_EXPLICIT_IV)
@@ -456,7 +458,7 @@ struct ssl_method_st {
     int (*ssl_write) (SSL *s, const void *buf, size_t len, size_t *written);
     int (*ssl_shutdown) (SSL *s);
     int (*ssl_renegotiate) (SSL *s);
-    int (*ssl_renegotiate_check) (SSL *s);
+    int (*ssl_renegotiate_check) (SSL *s, int);
     int (*ssl_read_bytes) (SSL *s, int type, int *recvd_type,
                            unsigned char *buf, size_t len, int peek,
                            size_t *readbytes);
@@ -1985,7 +1987,7 @@ __owur int ssl3_get_req_cert_type(SSL *s, WPACKET *pkt);
 __owur int ssl3_num_ciphers(void);
 __owur const SSL_CIPHER *ssl3_get_cipher(unsigned int u);
 int ssl3_renegotiate(SSL *ssl);
-int ssl3_renegotiate_check(SSL *ssl);
+int ssl3_renegotiate_check(SSL *ssl, int initok);
 __owur int ssl3_dispatch_alert(SSL *s);
 __owur size_t ssl3_final_finish_mac(SSL *s, const char *sender, size_t slen,
                                     unsigned char *p);
@@ -2014,6 +2016,7 @@ __owur long ssl3_default_timeout(void);
 
 __owur int ssl3_set_handshake_header(SSL *s, WPACKET *pkt, int htype);
 __owur int tls_close_construct_packet(SSL *s, WPACKET *pkt, int htype);
+__owur int tls_setup_handshake(SSL *s);
 __owur int dtls1_set_handshake_header(SSL *s, WPACKET *pkt, int htype);
 __owur int dtls1_close_construct_packet(SSL *s, WPACKET *pkt, int htype);
 __owur int ssl3_handshake_write(SSL *s);
index fe007492c5f971ba303d354a893afab950afc4db..1e2cc3f6f70f3f311f5a834fbad969235341589d 100644 (file)
@@ -318,7 +318,7 @@ int tls_construct_ctos_status_request(SSL *s, WPACKET *pkt, X509 *x,
 int tls_construct_ctos_npn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
                            int *al)
 {
-    if (s->ctx->ext.npn_select_cb == NULL || s->s3->tmp.finish_md_len != 0)
+    if (s->ctx->ext.npn_select_cb == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
 
     /*
@@ -340,11 +340,7 @@ int tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, X509 *x, size_t chainidx,
 {
     s->s3->alpn_sent = 0;
 
-    /*
-     * finish_md_len is non-zero during a renegotiation, so
-     * this avoids sending ALPN during the renegotiation
-     */
-    if (s->ext.alpn == NULL || s->s3->tmp.finish_md_len != 0)
+    if (s->ext.alpn == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
 
     if (!WPACKET_put_bytes_u16(pkt,
@@ -866,7 +862,7 @@ int tls_parse_stoc_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
     PACKET tmppkt;
 
     /* Check if we are in a renegotiation. If so ignore this extension */
-    if (s->s3->tmp.finish_md_len != 0)
+    if (!SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
 
     /* We must have requested it. */
index d58eedda3a1dda62bec8f0b829df948d19f3489d..357b3b710555ae57a56f89c21746d4526b29406e 100644 (file)
@@ -322,21 +322,8 @@ int tls_parse_ctos_npn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
     /*
      * We shouldn't accept this extension on a
      * renegotiation.
-     *
-     * s->new_session will be set on renegotiation, but we
-     * probably shouldn't rely that it couldn't be set on
-     * the initial renegotiation too in certain cases (when
-     * there's some other reason to disallow resuming an
-     * earlier session -- the current code won't be doing
-     * anything like that, but this might change).
-     *
-     * A valid sign that there's been a previous handshake
-     * in this connection is if s->s3->tmp.finish_md_len >
-     * 0.  (We are talking about a check that will happen
-     * in the Hello protocol round, well before a new
-     * Finished message could have been computed.)
      */
-    if (s->s3->tmp.finish_md_len == 0)
+    if (SSL_IS_FIRST_HANDSHAKE(s))
         s->s3->npn_seen = 1;
 
     return 1;
@@ -352,7 +339,7 @@ int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chainidx, int *al)
 {
     PACKET protocol_list, save_protocol_list, protocol;
 
-    if (s->s3->tmp.finish_md_len != 0)
+    if (!SSL_IS_FIRST_HANDSHAKE(s))
         return 1;
 
     if (!PACKET_as_length_prefixed_2(pkt, &protocol_list)
index ac78d2dc24a0ee1b51d36a31ab296b4ef6adc7bd..bd7d89a4610d126b2131c05777a3eb2fa5b7fb59 100644 (file)
@@ -105,7 +105,6 @@ void ossl_statem_clear(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;
 }
@@ -190,10 +189,10 @@ static info_cb get_callback(SSL *s)
 
 /*
  * 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
@@ -253,15 +252,7 @@ static int state_machine(SSL *s, int server)
 #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
             || st->state == MSG_FLOW_FINISHED) {
         if (st->state == MSG_FLOW_UNINITED) {
             st->hand_state = TLS_ST_BEFORE;
@@ -322,53 +313,14 @@ static int state_machine(SSL *s, int server)
                 goto end;
             }
 
-        if (!SSL_IS_TLS13(s)) {
-            if (!server || st->state != MSG_FLOW_RENEGOTIATE) {
-                if (!ssl3_init_finished_mac(s)) {
-                    ossl_statem_set_error(s);
-                    goto end;
-                }
-            }
-
-            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);
-                    ossl_statem_set_error(s);
-                    goto end;
-                } else {
-                    /*
-                     * st->state == MSG_FLOW_RENEGOTIATE, we will just send a
-                     * HelloRequest
-                     */
-                    s->ctx->stats.sess_accept_renegotiate++;
-
-                    s->s3->tmp.cert_request = 0;
-                }
-            } 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_req = 0;
-
-                if (SSL_IS_DTLS(s)) {
-                    st->use_timer = 1;
-                }
+        if (SSL_IS_FIRST_HANDSHAKE(s) || s->renegotiate) {
+            if (!tls_setup_handshake(s)) {
+                ossl_statem_set_error(s);
+                goto end;
             }
 
-            st->read_state_first_init = 1;
+            if (SSL_IS_FIRST_HANDSHAKE(s))
+                st->read_state_first_init = 1;
         }
 
         st->state = MSG_FLOW_WRITING;
@@ -826,7 +778,7 @@ 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)
@@ -836,7 +788,7 @@ int ossl_statem_app_data_allowed(SSL *s)
 {
     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))
index 6765c304a9fc2cdca7aef0c1efc1f26f3a7089c5..021d2d06ce310291ceb3087611aeda2a0b6ce120 100644 (file)
@@ -46,8 +46,6 @@ typedef enum {
     MSG_FLOW_UNINITED,
     /* A permanent error with this connection */
     MSG_FLOW_ERROR,
-    /* We are about to renegotiate */
-    MSG_FLOW_RENEGOTIATE,
     /* We are reading messages */
     MSG_FLOW_READING,
     /* We are writing messages */
@@ -92,6 +90,11 @@ struct ossl_statem_st {
     int read_state_first_init;
     /* true when we are actually in SSL_accept() or SSL_connect() */
     int in_handshake;
+    /*
+     * True when are processing a "real" handshake that needs cleaning up (not
+     * just a HelloRequest or similar).
+     */
+    int cleanuphand;
     /* Should we skip the CertificateVerify message? */
     unsigned int no_cert_verify;
     int use_timer;
index 90e4df6fda3cc2cf94d9d9c194fe461576fbb30c..8a308f82bc9b5ca0cf486e67dc3028fba33fa533 100644 (file)
@@ -351,6 +351,13 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
             return 1;
         }
         break;
+
+    case TLS_ST_OK:
+        if (mt == SSL3_MT_HELLO_REQUEST) {
+            st->hand_state = TLS_ST_CR_HELLO_REQ;
+            return 1;
+        }
+        break;
     }
 
  err:
@@ -428,6 +435,13 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
         return WRITE_TRAN_ERROR;
 
     case TLS_ST_OK:
+        if (!s->renegotiate) {
+            /*
+             * We haven't requested a renegotiation ourselves so we must have
+             * received a message from the server. Better read it.
+             */
+            return WRITE_TRAN_FINISHED;
+        }
         /* Renegotiation - fall through */
     case TLS_ST_BEFORE:
         st->hand_state = TLS_ST_CW_CLNT_HELLO;
@@ -515,6 +529,23 @@ WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
             ossl_statem_set_in_init(s, 0);
             return WRITE_TRAN_CONTINUE;
         }
+
+    case TLS_ST_CR_HELLO_REQ:
+        /*
+         * If we can renegotiate now then do so, otherwise wait for a more
+         * convenient time.
+         */
+        if (ssl3_renegotiate_check(s, 1)) {
+            if (!tls_setup_handshake(s)) {
+                ossl_statem_set_error(s);
+                return WRITE_TRAN_ERROR;
+            }
+            st->hand_state = TLS_ST_CW_CLNT_HELLO;
+            return WRITE_TRAN_CONTINUE;
+        }
+        st->hand_state = TLS_ST_OK;
+        ossl_statem_set_in_init(s, 0);
+        return WRITE_TRAN_CONTINUE;
     }
 }
 
@@ -819,6 +850,9 @@ MSG_PROCESS_RETURN ossl_statem_client_process_message(SSL *s, PACKET *pkt)
     case TLS_ST_CR_FINISHED:
         return tls_process_finished(s, pkt);
 
+    case TLS_ST_CR_HELLO_REQ:
+        return tls_process_hello_req(s, pkt);
+
     case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
         return tls_process_encrypted_extensions(s, pkt);
     }
@@ -893,6 +927,9 @@ int tls_construct_client_hello(SSL *s, WPACKET *pkt)
     }
     /* else use the pre-loaded session */
 
+    /* This is a real handshake so make sure we clean it up at the end */
+    s->statem.cleanuphand = 1;
+
     p = s->s3->client_random;
 
     /*
@@ -3112,6 +3149,30 @@ int tls_construct_next_proto(SSL *s, WPACKET *pkt)
 }
 #endif
 
+MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt)
+{
+    if (PACKET_remaining(pkt) > 0) {
+        /* should contain no data */
+        SSLerr(SSL_F_TLS_PROCESS_HELLO_REQ, SSL_R_LENGTH_MISMATCH);
+        ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+        ossl_statem_set_error(s);
+        return MSG_PROCESS_ERROR;
+    }
+
+    /*
+     * This is a historical discrepancy maintained for compatibility
+     * reasons. If a TLS client receives a HelloRequest it will attempt
+     * an abbreviated handshake. However if a DTLS client receives a
+     * HelloRequest it will do a full handshake.
+     */
+    if (SSL_IS_DTLS(s))
+        SSL_renegotiate(s);
+    else
+        SSL_renegotiate_abbreviated(s);
+
+    return MSG_PROCESS_FINISHED_READING;
+}
+
 static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt)
 {
     int al = SSL_AD_INTERNAL_ERROR;
index 1c1758b464e7b0ec2596537b2657130ba2391daf..1bc82d1625a9f1d0e2ef3394d5d9d827074a0c81 100644 (file)
@@ -788,8 +788,9 @@ static int dtls_get_reassembled_message(SSL *s, int *errtype, size_t *len)
         return 0;
     }
 
-    if (!s->server && s->d1->r_msg_hdr.frag_off == 0 &&
-        wire[0] == SSL3_MT_HELLO_REQUEST) {
+    if (!s->server && s->d1->r_msg_hdr.frag_off == 0
+            && s->statem.hand_state != TLS_ST_OK
+            && wire[0] == SSL3_MT_HELLO_REQUEST) {
         /*
          * The server may always send 'Hello Request' messages -- we are
          * doing a handshake anyway now, so ignore them if their format is
index 905a2cc4602d7e4f557ebf1c643fd11d6daf9908..c81c012488582525f722963b05667d20b9da8b22 100644 (file)
@@ -72,6 +72,49 @@ int tls_close_construct_packet(SSL *s, WPACKET *pkt, int htype)
     return 1;
 }
 
+int tls_setup_handshake(SSL *s) {
+    if (!ssl3_init_finished_mac(s))
+        return 0;
+
+    if (s->server) {
+        if (SSL_IS_FIRST_HANDSHAKE(s)) {
+            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_TLS_SETUP_HANDSHAKE,
+                   SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED);
+            ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+            return 0;
+        } else {
+            s->ctx->stats.sess_accept_renegotiate++;
+
+            s->s3->tmp.cert_request = 0;
+        }
+    } else {
+        if (SSL_IS_FIRST_HANDSHAKE(s))
+            s->ctx->stats.sess_connect++;
+        else
+            s->ctx->stats.sess_connect_renegotiate++;
+
+        /* mark client_random uninitialized */
+        memset(s->s3->client_random, 0, sizeof(s->s3->client_random));
+        s->hit = 0;
+
+        s->s3->tmp.cert_req = 0;
+
+        if (SSL_IS_DTLS(s)) {
+            s->statem.use_timer = 1;
+        }
+    }
+
+    return 1;
+}
+
 /*
  * Size of the to-be-signed TLS13 data, without the hash size itself:
  * 64 bytes of value 32, 33 context bytes, 1 byte separator
@@ -807,10 +850,11 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst)
 
     s->init_num = 0;
 
-    if (!s->server || s->renegotiate == 2) {
+    if (s->statem.cleanuphand) {
         /* skipped if we just sent a HelloRequest */
         s->renegotiate = 0;
         s->new_session = 0;
+        s->statem.cleanuphand = 0;
 
         if (s->server) {
             ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
@@ -891,7 +935,8 @@ int tls_get_message_header(SSL *s, int *mt)
 
         skip_message = 0;
         if (!s->server)
-            if (p[0] == SSL3_MT_HELLO_REQUEST)
+            if (s->statem.hand_state != TLS_ST_OK
+                    && p[0] == SSL3_MT_HELLO_REQUEST)
                 /*
                  * The server may always send 'Hello Request' messages --
                  * we are doing a handshake anyway now, so ignore them if
index b52de70f0f25361669cf4953d5e3c62bb3134f20..5e9f72dd696a6d5c618f22743e4db7ec260d5798 100644 (file)
@@ -132,6 +132,7 @@ __owur int ssl3_check_cert_and_algorithm(SSL *s);
 #ifndef OPENSSL_NO_NEXTPROTONEG
 __owur int tls_construct_next_proto(SSL *s, WPACKET *pkt);
 #endif
+__owur MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt);
 __owur MSG_PROCESS_RETURN dtls_process_hello_verify(SSL *s, PACKET *pkt);
 
 /* some server-only functions */
index 0a722870592ebfc12776ec18692a1ca6f4d755ed..cb080aa10f4a1ae194385324627d894b1426f426 100644 (file)
@@ -473,6 +473,11 @@ WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
             st->request_state = TLS_ST_BEFORE;
             return WRITE_TRAN_CONTINUE;
         }
+        /* Must be an incoming ClientHello */
+        if (!tls_setup_handshake(s)) {
+            ossl_statem_set_error(s);
+            return WRITE_TRAN_ERROR;
+        }
         /* Fall through */
 
     case TLS_ST_BEFORE:
@@ -1152,6 +1157,15 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
     static const unsigned char null_compression = 0;
     CLIENTHELLO_MSG clienthello;
 
+    /* Check if this is actually an unexpected renegotiation ClientHello */
+    if (s->renegotiate == 0 && !SSL_IS_FIRST_HANDSHAKE(s)) {
+        s->renegotiate = 1;
+        s->new_session = 1;
+    }
+
+    /* This is a real handshake so make sure we clean it up at the end */
+    s->statem.cleanuphand = 1;
+
     /*
      * First, parse the raw ClientHello data into the CLIENTHELLO_MSG structure.
      */
@@ -1850,7 +1864,6 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
         }
     }
 #endif
-    s->renegotiate = 2;
 
     return WORK_FINISHED_STOP;
  f_err: