Move state machine knowledge out of the record layer
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)
This commit is contained in:
parent
0386aad1ab
commit
c7f47786a5
16 changed files with 206 additions and 236 deletions
|
@ -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. */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
18
ssl/s3_lib.c
18
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 (SSL_IS_FIRST_HANDSHAKE(s) || s->renegotiate) {
|
||||
if (!tls_setup_handshake(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;
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue