summaryrefslogtreecommitdiffstats
path: root/ssl/statem
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2017-03-09 15:03:07 +0000
committerMatt Caswell <matt@openssl.org>2017-03-16 14:20:38 +0000
commitef6c191bceb7f09918cfd39e780759c32afb2396 (patch)
tree1a91e3b4be56102bb9ad9706b122c9e8c87e4cda /ssl/statem
parentbc993d30fcff70667618d83f5b58d99e119f4c23 (diff)
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 <rsalz@openssl.org> (Merged from https://github.com/openssl/openssl/pull/2895)
Diffstat (limited to 'ssl/statem')
-rw-r--r--ssl/statem/statem.c22
-rw-r--r--ssl/statem/statem.h1
-rw-r--r--ssl/statem/statem_clnt.c54
-rw-r--r--ssl/statem/statem_lib.c1
-rw-r--r--ssl/statem/statem_locl.h3
-rw-r--r--ssl/statem/statem_srvr.c70
6 files changed, 132 insertions, 19 deletions
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;
+}