summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/openssl/ssl.h7
-rw-r--r--ssl/record/rec_layer_d1.c84
-rw-r--r--ssl/record/rec_layer_s3.c89
-rw-r--r--ssl/s3_lib.c18
-rw-r--r--ssl/ssl_err.c2
-rw-r--r--ssl/ssl_lib.c2
-rw-r--r--ssl/ssl_locl.h7
-rw-r--r--ssl/statem/extensions_clnt.c10
-rw-r--r--ssl/statem/extensions_srvr.c17
-rw-r--r--ssl/statem/statem.c68
-rw-r--r--ssl/statem/statem.h7
-rw-r--r--ssl/statem/statem_clnt.c61
-rw-r--r--ssl/statem/statem_dtls.c5
-rw-r--r--ssl/statem/statem_lib.c49
-rw-r--r--ssl/statem/statem_locl.h1
-rw-r--r--ssl/statem/statem_srvr.c15
16 files changed, 206 insertions, 236 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 86ffcb978f..e95fdb4842 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -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. */
diff --git a/ssl/record/rec_layer_d1.c b/ssl/record/rec_layer_d1.c
index 0a32f07c2a..67846bd19f 100644
--- a/ssl/record/rec_layer_d1.c
+++ b/ssl/record/rec_layer_d1.c
@@ -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;
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index b4dee6e21d..59aa8d4cae 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -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;
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index ff4a03b147..1655333b13 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -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;
}
/*
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index d380c86b9b..099af01371 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -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}
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 8ca1a3c778..8e6a14393c 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -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) {
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 39e27eac1b..ef525fe6e1 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -356,6 +356,8 @@
&& (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);
diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c
index fe007492c5..1e2cc3f6f7 100644
--- a/ssl/statem/extensions_clnt.c
+++ b/ssl/statem/extensions_clnt.c
@@ -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. */
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index d58eedda3a..357b3b7105 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -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)
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
index ac78d2dc24..bd7d89a461 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -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))
diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h
index 6765c304a9..021d2d06ce 100644
--- a/ssl/statem/statem.h
+++ b/ssl/statem/statem.h
@@ -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;
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 90e4df6fda..8a308f82bc 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -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;
diff --git a/ssl/statem/statem_dtls.c b/ssl/statem/statem_dtls.c
index 1c1758b464..1bc82d1625 100644
--- a/ssl/statem/statem_dtls.c
+++ b/ssl/statem/statem_dtls.c
@@ -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
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index 905a2cc460..c81c012488 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -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
diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h
index b52de70f0f..5e9f72dd69 100644
--- a/ssl/statem/statem_locl.h
+++ b/ssl/statem/statem_locl.h
@@ -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 */
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 0a72287059..cb080aa10f 100644
--- a/ssl/statem/statem_srvr.c
+++ b/