From 564547e482406c2d4c56a59e288b3a479dac2d74 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Sat, 25 Feb 2017 15:34:07 +0000 Subject: [PATCH] Enable the client to call SSL_read() without stopping the ability to call SSL_write_early() Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/2737) --- include/openssl/ssl.h | 3 ++- ssl/ssl_lib.c | 26 ++++++++++++++++++-------- ssl/statem/statem.c | 7 +++++++ ssl/statem/statem.h | 1 + ssl/statem/statem_clnt.c | 9 +++++++++ 5 files changed, 37 insertions(+), 9 deletions(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 860edba4cf..dabcc4a6a2 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -900,7 +900,8 @@ typedef enum { TLS_ST_CW_KEY_UPDATE, TLS_ST_SR_KEY_UPDATE, TLS_ST_CR_KEY_UPDATE, - TLS_ST_CW_EARLY_DATA + TLS_ST_CW_EARLY_DATA, + TLS_ST_CW_PENDING_EARLY_DATA_END } OSSL_HANDSHAKE_STATE; /* diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 3bcb6e1643..c244c3c27c 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1545,13 +1545,16 @@ int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes) return 0; } - if (s->early_data_state != SSL_EARLY_DATA_NONE - && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING - && s->early_data_state != SSL_EARLY_DATA_FINISHED_READING - && s->early_data_state != SSL_EARLY_DATA_READING) { + if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY + || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) { SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } + /* + * If we are a client and haven't received the ServerHello etc then we + * better do that + */ + ossl_statem_check_finish_init(s, 0); if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) { struct ssl_async_args args; @@ -1745,13 +1748,20 @@ int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written) return -1; } - if (s->early_data_state != SSL_EARLY_DATA_NONE - && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING - && s->early_data_state != SSL_EARLY_DATA_FINISHED_READING - && s->early_data_state != SSL_EARLY_DATA_WRITING) { + if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) { + /* + * We're still writing early data. We need to stop that so we can write + * normal data + */ + if (!SSL_write_early_finish(s)) + return 0; + } else if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY + || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY) { SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } + /* If we are a client and haven't sent the Finished we better do that */ + ossl_statem_check_finish_init(s, 1); if ((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) { int ret; diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 2c202f4deb..a1807f2a40 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -168,6 +168,13 @@ int ossl_statem_skip_early_data(SSL *s) return 1; } +void ossl_statem_check_finish_init(SSL *s, int send) +{ + if ((send && s->statem.hand_state == TLS_ST_CW_PENDING_EARLY_DATA_END) + || (!send && s->statem.hand_state == TLS_ST_CW_EARLY_DATA)) + ossl_statem_set_in_init(s, 1); +} + void ossl_statem_set_hello_verify_done(SSL *s) { s->statem.state = MSG_FLOW_UNINITED; diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h index c0c9cab144..56009b0f8c 100644 --- a/ssl/statem/statem.h +++ b/ssl/statem/statem.h @@ -123,6 +123,7 @@ void ossl_statem_set_in_init(SSL *s, int init); int ossl_statem_get_in_handshake(SSL *s); void ossl_statem_set_in_handshake(SSL *s, int inhand); __owur int ossl_statem_skip_early_data(SSL *s); +void ossl_statem_check_finish_init(SSL *s, int send); void ossl_statem_set_hello_verify_done(SSL *s); __owur int ossl_statem_app_data_allowed(SSL *s); #ifndef OPENSSL_NO_SCTP diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 23a4d7663b..6fdb37ec7a 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -435,6 +435,14 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s) return WRITE_TRAN_CONTINUE; case TLS_ST_CR_FINISHED: + if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) + st->hand_state = TLS_ST_CW_PENDING_EARLY_DATA_END; + else + st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT + : TLS_ST_CW_FINISHED; + return WRITE_TRAN_CONTINUE; + + case TLS_ST_CW_PENDING_EARLY_DATA_END: st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT : TLS_ST_CW_FINISHED; return WRITE_TRAN_CONTINUE; @@ -659,6 +667,7 @@ WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst) break; case TLS_ST_CW_EARLY_DATA: + case TLS_ST_CW_PENDING_EARLY_DATA_END: case TLS_ST_OK: return tls_finish_handshake(s, wst, 1); } -- GitLab