From ef6c191bceb7f09918cfd39e780759c32afb2396 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Thu, 9 Mar 2017 15:03:07 +0000 Subject: [PATCH] Update end of early data processing for draft-19 The end of early data is now indicated by a new handshake message rather than an alert. Reviewed-by: Rich Salz (Merged from https://github.com/openssl/openssl/pull/2895) --- include/openssl/ssl.h | 7 +++- include/openssl/ssl3.h | 1 + ssl/record/rec_layer_s3.c | 41 +++++--------------- ssl/record/ssl3_record_tls13.c | 3 +- ssl/ssl_err.c | 4 ++ ssl/ssl_lib.c | 62 ++---------------------------- ssl/ssl_locl.h | 4 +- ssl/statem/statem.c | 22 +++++++++-- ssl/statem/statem.h | 1 - ssl/statem/statem_clnt.c | 54 +++++++++++++++++++++++++- ssl/statem/statem_lib.c | 1 - ssl/statem/statem_locl.h | 3 ++ ssl/statem/statem_srvr.c | 70 ++++++++++++++++++++++++++++------ ssl/tls13_enc.c | 2 +- test/sslapitest.c | 9 ----- 15 files changed, 161 insertions(+), 123 deletions(-) diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 488ce4f39c..bf0dd6bdd7 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -901,7 +901,9 @@ typedef enum { TLS_ST_SR_KEY_UPDATE, TLS_ST_CR_KEY_UPDATE, TLS_ST_EARLY_DATA, - TLS_ST_PENDING_EARLY_DATA_END + TLS_ST_PENDING_EARLY_DATA_END, + TLS_ST_CW_END_OF_EARLY_DATA, + TLS_ST_SR_END_OF_EARLY_DATA } OSSL_HANDSHAKE_STATE; /* @@ -1027,7 +1029,6 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) # define SSL_AD_INTERNAL_ERROR TLS1_AD_INTERNAL_ERROR # define SSL_AD_USER_CANCELLED TLS1_AD_USER_CANCELLED # define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION -# define SSL_AD_END_OF_EARLY_DATA TLS13_AD_END_OF_EARLY_DATA # define SSL_AD_MISSING_EXTENSION TLS13_AD_MISSING_EXTENSION # define SSL_AD_CERTIFICATE_REQUIRED TLS13_AD_CERTIFICATE_REQUIRED # define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION @@ -2373,6 +2374,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_CTOS_USE_SRTP 482 # define SSL_F_TLS_CONSTRUCT_CTOS_VERIFY 358 # define SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS 443 +# define SSL_F_TLS_CONSTRUCT_END_OF_EARLY_DATA 536 # define SSL_F_TLS_CONSTRUCT_EXTENSIONS 447 # define SSL_F_TLS_CONSTRUCT_FINISHED 359 # define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST 373 @@ -2434,6 +2436,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_PROCESS_CLIENT_HELLO 381 # define SSL_F_TLS_PROCESS_CLIENT_KEY_EXCHANGE 382 # define SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS 444 +# define SSL_F_TLS_PROCESS_END_OF_EARLY_DATA 537 # define SSL_F_TLS_PROCESS_FINISHED 364 # define SSL_F_TLS_PROCESS_HELLO_REQ 507 # define SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST 511 diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index 604a704a2e..0ecb509a9e 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -280,6 +280,7 @@ extern "C" { # define SSL3_MT_CLIENT_HELLO 1 # define SSL3_MT_SERVER_HELLO 2 # define SSL3_MT_NEWSESSION_TICKET 4 +# define SSL3_MT_END_OF_EARLY_DATA 5 # define SSL3_MT_HELLO_RETRY_REQUEST 6 # define SSL3_MT_ENCRYPTED_EXTENSIONS 8 # define SSL3_MT_CERTIFICATE 11 diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index a14d372611..e8e9329f6e 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -904,7 +904,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, SSL3_RECORD_set_length(thiswr, len); } - if (s->early_data_state == SSL_EARLY_DATA_WRITING) { + if (s->early_data_state == SSL_EARLY_DATA_WRITING + || s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) { /* * We haven't actually negotiated the version yet, but we're trying to * send early data - so we need to use the the tls13enc function. @@ -1367,17 +1368,16 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, n = SSL3_RECORD_get_length(rr); /* available bytes */ /* now move 'n' bytes: */ - while (n-- > 0) { - dest[(*dest_len)++] = - SSL3_RECORD_get_data(rr)[SSL3_RECORD_get_off(rr)]; - SSL3_RECORD_add_off(rr, 1); - SSL3_RECORD_add_length(rr, -1); - } - - if (*dest_len < dest_maxlen) { + memcpy(dest + *dest_len, + SSL3_RECORD_get_data(rr) + SSL3_RECORD_get_off(rr), n); + SSL3_RECORD_add_off(rr, n); + SSL3_RECORD_add_length(rr, -n); + *dest_len += n; + if (SSL3_RECORD_get_length(rr) == 0) SSL3_RECORD_set_read(rr); + + if (*dest_len < dest_maxlen) goto start; /* fragment was too small */ - } } } @@ -1454,14 +1454,6 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, al = SSL_AD_HANDSHAKE_FAILURE; SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_NO_RENEGOTIATION); goto f_err; - } else if (alert_descr == SSL_AD_END_OF_EARLY_DATA) { - if (!ssl_end_of_early_data_seen(s)) { - al = SSL_AD_UNEXPECTED_MESSAGE; - SSLerr(SSL_F_SSL3_READ_BYTES, - SSL_R_UNEXPECTED_END_OF_EARLY_DATA); - goto f_err; - } - return 0; } } else if (alert_level == SSL3_AL_FATAL) { char tmp[16]; @@ -1504,19 +1496,6 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf, */ if ((s->rlayer.handshake_fragment_len >= 4) && !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); diff --git a/ssl/record/ssl3_record_tls13.c b/ssl/record/ssl3_record_tls13.c index 87041df2c7..c6ea511b4d 100644 --- a/ssl/record/ssl3_record_tls13.c +++ b/ssl/record/ssl3_record_tls13.c @@ -56,7 +56,8 @@ int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int send) ivlen = EVP_CIPHER_CTX_iv_length(ctx); - if (s->early_data_state == SSL_EARLY_DATA_WRITING) { + if (s->early_data_state == SSL_EARLY_DATA_WRITING + || s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) { alg_enc = s->session->cipher->algorithm_enc; } else { /* diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 23987e64a4..f8d344b563 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -343,6 +343,8 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_TLS_CONSTRUCT_CTOS_VERIFY), "TLS_CONSTRUCT_CTOS_VERIFY"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_ENCRYPTED_EXTENSIONS), "tls_construct_encrypted_extensions"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_END_OF_EARLY_DATA), + "tls_construct_end_of_early_data"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_EXTENSIONS), "tls_construct_extensions"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_FINISHED), "tls_construct_finished"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_HELLO_REQUEST), @@ -438,6 +440,8 @@ static ERR_STRING_DATA SSL_str_functs[] = { "tls_process_client_key_exchange"}, {ERR_FUNC(SSL_F_TLS_PROCESS_ENCRYPTED_EXTENSIONS), "tls_process_encrypted_extensions"}, + {ERR_FUNC(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA), + "tls_process_end_of_early_data"}, {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_HELLO_RETRY_REQUEST), diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 581941ecb3..482c810e1e 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -105,8 +105,6 @@ static const struct { }, }; -static int ssl_write_early_finish(SSL *s); - static int dane_ctx_enable(struct dane_ctx_st *dctx) { const EVP_MD **mdevp; @@ -1641,9 +1639,9 @@ int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes) s->early_data_state = SSL_EARLY_DATA_READING; ret = SSL_read_ex(s, buf, num, readbytes); /* - * Record layer will call ssl_end_of_early_data_seen() if we see - * that alert - which updates the early_data_state to - * SSL_EARLY_DATA_FINISHED_READING + * State machine will update early_data_state to + * SSL_EARLY_DATA_FINISHED_READING if we get an EndOfEarlyData + * message */ if (ret > 0 || (ret <= 0 && s->early_data_state != SSL_EARLY_DATA_FINISHED_READING)) { @@ -1663,18 +1661,6 @@ int SSL_read_early_data(SSL *s, void *buf, size_t num, size_t *readbytes) } } -int ssl_end_of_early_data_seen(SSL *s) -{ - if (s->early_data_state == SSL_EARLY_DATA_READING - || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) { - s->early_data_state = SSL_EARLY_DATA_FINISHED_READING; - ossl_statem_finish_early_data(s); - return 1; - } - - return 0; -} - int SSL_get_early_data_status(const SSL *s) { return s->ext.early_data; @@ -1753,14 +1739,7 @@ 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_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 + if (s->early_data_state == SSL_EARLY_DATA_CONNECT_RETRY || s->early_data_state == SSL_EARLY_DATA_ACCEPT_RETRY || s->early_data_state == SSL_EARLY_DATA_READ_RETRY) { SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); @@ -1863,32 +1842,6 @@ int SSL_write_early_data(SSL *s, const void *buf, size_t num, size_t *written) } } -static int ssl_write_early_finish(SSL *s) -{ - int ret; - - if (s->early_data_state != SSL_EARLY_DATA_WRITE_RETRY) { - SSLerr(SSL_F_SSL_WRITE_EARLY_FINISH, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; - } - - s->early_data_state = SSL_EARLY_DATA_WRITING; - ret = ssl3_send_alert(s, SSL3_AL_WARNING, SSL_AD_END_OF_EARLY_DATA); - if (ret <= 0) { - s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY; - return 0; - } - s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING; - /* - * We set the enc_write_ctx back to NULL because we may end up writing - * in cleartext again if we get a HelloRetryRequest from the server. - */ - EVP_CIPHER_CTX_free(s->enc_write_ctx); - s->enc_write_ctx = NULL; - ossl_statem_set_in_init(s, 1); - return 1; -} - int SSL_shutdown(SSL *s) { /* @@ -3252,13 +3205,6 @@ int SSL_do_handshake(SSL *s) return -1; } - if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) { - int edfin; - - edfin = ssl_write_early_finish(s); - if (edfin <= 0) - return edfin; - } ossl_statem_check_finish_init(s, -1); s->method->ssl_renegotiate_check(s, 0); diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index f4860ea1fd..b2e0f66638 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -350,7 +350,8 @@ && (s)->method->version != TLS_ANY_VERSION) # define SSL_TREAT_AS_TLS13(s) \ - (SSL_IS_TLS13(s) || (s)->early_data_state == SSL_EARLY_DATA_WRITING) + (SSL_IS_TLS13(s) || (s)->early_data_state == SSL_EARLY_DATA_WRITING \ + || (s)->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) # define SSL_IS_FIRST_HANDSHAKE(S) ((s)->s3->tmp.finish_md_len == 0) @@ -2030,7 +2031,6 @@ static ossl_inline int ssl_has_cert(const SSL *s, int idx) # ifndef OPENSSL_UNIT_TEST -int ssl_end_of_early_data_seen(SSL *s); __owur int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes); __owur int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written); void ssl_clear_cipher_ctx(SSL *s); diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 11cbe551a6..92a0e8f1ec 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -180,13 +180,29 @@ void ossl_statem_check_finish_init(SSL *s, int send) { if (send == -1) { if (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END - || s->statem.hand_state == TLS_ST_EARLY_DATA) + || s->statem.hand_state == TLS_ST_EARLY_DATA) { ossl_statem_set_in_init(s, 1); + if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) { + /* + * SSL_connect() or SSL_do_handshake() has been called directly. + * We don't allow any more writing of early data. + */ + s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING; + } + } } else if (!s->server) { - if ((send && s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END + if ((send && (s->statem.hand_state == TLS_ST_PENDING_EARLY_DATA_END + || s->statem.hand_state == TLS_ST_EARLY_DATA) && s->early_data_state != SSL_EARLY_DATA_WRITING) - || (!send && s->statem.hand_state == TLS_ST_EARLY_DATA)) + || (!send && s->statem.hand_state == TLS_ST_EARLY_DATA)) { ossl_statem_set_in_init(s, 1); + /* + * SSL_write() has been called directly. We don't allow any more + * writing of early data. + */ + if (send && s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) + s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING; + } } else { if (s->early_data_state == SSL_EARLY_DATA_FINISHED_READING && s->statem.hand_state == TLS_ST_EARLY_DATA) diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h index 56009b0f8c..7012115c49 100644 --- a/ssl/statem/statem.h +++ b/ssl/statem/statem.h @@ -130,4 +130,3 @@ __owur int ossl_statem_app_data_allowed(SSL *s); void ossl_statem_set_sctp_read_sock(SSL *s, int read_sock); __owur int ossl_statem_in_sctp_read_sock(SSL *s); #endif -int ossl_statem_finish_early_data(SSL *s); diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index 9f4a719fa1..32b7300e45 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -435,7 +435,8 @@ 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) + if (s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY + || s->early_data_state == SSL_EARLY_DATA_FINISHED_WRITING) st->hand_state = TLS_ST_PENDING_EARLY_DATA_END; else st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT @@ -443,6 +444,13 @@ static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s) return WRITE_TRAN_CONTINUE; case TLS_ST_PENDING_EARLY_DATA_END: + if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { + st->hand_state = TLS_ST_CW_END_OF_EARLY_DATA; + return WRITE_TRAN_CONTINUE; + } + /* Fall through */ + + case TLS_ST_CW_END_OF_EARLY_DATA: st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT : TLS_ST_CW_FINISHED; return WRITE_TRAN_CONTINUE; @@ -666,8 +674,18 @@ WORK_STATE ossl_statem_client_pre_work(SSL *s, WORK_STATE wst) } break; - case TLS_ST_EARLY_DATA: case TLS_ST_PENDING_EARLY_DATA_END: + /* + * If we've been called by SSL_do_handshake()/SSL_write(), or we did not + * attempt to write early data before calling SSL_read() then we press + * on with the handshake. Otherwise we pause here. + */ + if (s->early_data_state == SSL_EARLY_DATA_FINISHED_WRITING + || s->early_data_state == SSL_EARLY_DATA_NONE) + return WORK_FINISHED_CONTINUE; + /* Fall through */ + + case TLS_ST_EARLY_DATA: case TLS_ST_OK: return tls_finish_handshake(s, wst, 1); } @@ -712,6 +730,15 @@ WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst) } break; + case TLS_ST_CW_END_OF_EARLY_DATA: + /* + * We set the enc_write_ctx back to NULL because we may end up writing + * in cleartext again if we get a HelloRetryRequest from the server. + */ + EVP_CIPHER_CTX_free(s->enc_write_ctx); + s->enc_write_ctx = NULL; + break; + case TLS_ST_CW_KEY_EXCH: if (tls_client_key_exchange_post_work(s) == 0) return WORK_ERROR; @@ -813,6 +840,16 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt, *mt = SSL3_MT_CLIENT_HELLO; break; + case TLS_ST_CW_END_OF_EARLY_DATA: + *confunc = tls_construct_end_of_early_data; + *mt = SSL3_MT_END_OF_EARLY_DATA; + break; + + case TLS_ST_PENDING_EARLY_DATA_END: + *confunc = NULL; + *mt = SSL3_MT_DUMMY; + break; + case TLS_ST_CW_CERT: *confunc = tls_construct_client_certificate; *mt = SSL3_MT_CERTIFICATE; @@ -3543,3 +3580,16 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, WPACKET *pkt) return 1; } + +int tls_construct_end_of_early_data(SSL *s, WPACKET *pkt) +{ + if (s->early_data_state != SSL_EARLY_DATA_WRITE_RETRY + && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING) { + SSLerr(SSL_F_TLS_CONSTRUCT_END_OF_EARLY_DATA, + ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + s->early_data_state = SSL_EARLY_DATA_FINISHED_WRITING; + return 1; +} diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index 36c96e5697..98bd2f714f 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -986,7 +986,6 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs) s->d1->next_handshake_write_seq = 0; dtls1_clear_received_buffer(s); } - s->early_data_state = SSL_EARLY_DATA_NONE; } /* diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index 68160c9bc7..daf8a5b192 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -18,6 +18,7 @@ /* The spec allows for a longer length than this, but we limit it */ #define HELLO_VERIFY_REQUEST_MAX_LENGTH 258 +#define END_OF_EARLY_DATA_MAX_LENGTH 0 #define SERVER_HELLO_MAX_LENGTH 20000 #define HELLO_RETRY_REQUEST_MAX_LENGTH 20000 #define ENCRYPTED_EXTENSIONS_MAX_LENGTH 20000 @@ -147,6 +148,7 @@ __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); +__owur int tls_construct_end_of_early_data(SSL *s, WPACKET *pkt); /* some server-only functions */ __owur MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt); @@ -165,6 +167,7 @@ __owur MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt); __owur MSG_PROCESS_RETURN tls_process_next_proto(SSL *s, PACKET *pkt); #endif __owur int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt); +MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt); /* Extension processing */ diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 2e381fdd02..259be22106 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -94,6 +94,16 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt) break; case TLS_ST_EARLY_DATA: + if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) { + if (mt == SSL3_MT_END_OF_EARLY_DATA) { + st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA; + return 1; + } + break; + } + /* Fall through */ + + case TLS_ST_SR_END_OF_EARLY_DATA: case TLS_ST_SW_FINISHED: if (s->s3->tmp.cert_request) { if (mt == SSL3_MT_CERTIFICATE) { @@ -144,9 +154,6 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt) } /* No valid transition found */ - ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE); - SSLerr(SSL_F_OSSL_STATEM_SERVER13_READ_TRANSITION, - SSL_R_UNEXPECTED_MESSAGE); return 0; } @@ -1009,6 +1016,9 @@ size_t ossl_statem_server_max_message_size(SSL *s) case TLS_ST_SR_CLNT_HELLO: return CLIENT_HELLO_MAX_LENGTH; + case TLS_ST_SR_END_OF_EARLY_DATA: + return END_OF_EARLY_DATA_MAX_LENGTH; + case TLS_ST_SR_CERT: return s->max_cert_list; @@ -1049,6 +1059,9 @@ MSG_PROCESS_RETURN ossl_statem_server_process_message(SSL *s, PACKET *pkt) case TLS_ST_SR_CLNT_HELLO: return tls_process_client_hello(s, pkt); + case TLS_ST_SR_END_OF_EARLY_DATA: + return tls_process_end_of_early_data(s, pkt); + case TLS_ST_SR_CERT: return tls_process_client_certificate(s, pkt); @@ -1115,15 +1128,6 @@ WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst) return WORK_FINISHED_CONTINUE; } -int ossl_statem_finish_early_data(SSL *s) -{ - if (!s->method->ssl3_enc->change_cipher_state(s, - SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ)) - return 0; - - return 1; -} - #ifndef OPENSSL_NO_SRP static int ssl_check_srp_ext_ClientHello(SSL *s, int *al) { @@ -3670,3 +3674,45 @@ static int tls_construct_hello_retry_request(SSL *s, WPACKET *pkt) return 1; } + +MSG_PROCESS_RETURN tls_process_end_of_early_data(SSL *s, PACKET *pkt) +{ + int al = SSL_AD_INTERNAL_ERROR; + + if (PACKET_remaining(pkt) != 0) { + al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA, SSL_R_LENGTH_MISMATCH); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; + } + + if (s->early_data_state != SSL_EARLY_DATA_READING + && s->early_data_state != SSL_EARLY_DATA_READ_RETRY) { + SSLerr(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA, ERR_R_INTERNAL_ERROR); + goto err; + } + + /* + * EndOfEarlyData signals a key change so the end of the message must be on + * a record boundary. + */ + if (RECORD_LAYER_processed_read_pending(&s->rlayer)) { + al = SSL_AD_UNEXPECTED_MESSAGE; + SSLerr(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA, + SSL_R_NOT_ON_RECORD_BOUNDARY); + goto err; + } + + s->early_data_state = SSL_EARLY_DATA_FINISHED_READING; + if (!s->method->ssl3_enc->change_cipher_state(s, + SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ)) { + SSLerr(SSL_F_TLS_PROCESS_END_OF_EARLY_DATA, ERR_R_INTERNAL_ERROR); + goto err; + } + + return MSG_PROCESS_CONTINUE_READING; + err: + ssl3_send_alert(s, SSL3_AL_FATAL, al); + ossl_statem_set_error(s); + return MSG_PROCESS_ERROR; +} diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index cac4a424ef..910336281d 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -600,7 +600,7 @@ int tls13_update_key(SSL *s, int send) int tls13_alert_code(int code) { - if (code == SSL_AD_MISSING_EXTENSION || code == SSL_AD_END_OF_EARLY_DATA) + if (code == SSL_AD_MISSING_EXTENSION) return code; return tls1_alert_code(code); diff --git a/test/sslapitest.c b/test/sslapitest.c index 1b96527320..85fcabc66c 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -1764,15 +1764,6 @@ static int test_early_data_read_write(void) goto end; } - /* - * We expect SSL_accept() to initially block as it handles the end of early - * data alert - */ - if (SSL_accept(serverssl) > 0) { - printf("Unexpected success completing server handshake\n"); - goto end; - } - if (SSL_accept(serverssl) <= 0) { printf("Unable to complete server handshake\n"); goto end; -- 2.25.1