summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/openssl/ssl.h10
-rw-r--r--ssl/record/rec_layer_s3.c8
-rw-r--r--ssl/record/ssl3_record.c17
-rw-r--r--ssl/ssl_err.c3
-rw-r--r--ssl/ssl_lib.c69
-rw-r--r--ssl/ssl_locl.h8
-rw-r--r--ssl/statem/statem.c3
-rw-r--r--ssl/statem/statem_clnt.c6
-rw-r--r--ssl/statem/statem_lib.c5
-rw-r--r--ssl/statem/statem_srvr.c12
-rw-r--r--util/libssl.num1
11 files changed, 127 insertions, 15 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 40965e6450..597f77380d 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1611,6 +1611,12 @@ __owur int SSL_accept(SSL *ssl);
__owur int SSL_connect(SSL *ssl);
__owur int SSL_read(SSL *ssl, void *buf, int num);
__owur int SSL_read_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
+
+# define SSL_READ_EARLY_ERROR 0
+# define SSL_READ_EARLY_SUCCESS 1
+# define SSL_READ_EARLY_FINISH 2
+
+__owur int SSL_read_early(SSL *s, void *buf, size_t num, size_t *readbytes);
__owur int SSL_peek(SSL *ssl, void *buf, int num);
__owur int SSL_peek_ex(SSL *ssl, void *buf, size_t num, size_t *readbytes);
__owur int SSL_write(SSL *ssl, const void *buf, int num);
@@ -2255,6 +2261,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_SSL_PEEK_EX 432
# define SSL_F_SSL_PEEK_INTERNAL 522
# define SSL_F_SSL_READ 223
+# define SSL_F_SSL_READ_EARLY 529
# define SSL_F_SSL_READ_EX 434
# define SSL_F_SSL_READ_INTERNAL 523
# define SSL_F_SSL_RENEGOTIATE 516
@@ -2330,7 +2337,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY 489
# define SSL_F_TLS_CONSTRUCT_CTOS_ALPN 466
# define SSL_F_TLS_CONSTRUCT_CTOS_CERTIFICATE 355
-# define SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA 521
+# define SSL_F_TLS_CONSTRUCT_CTOS_EARLY_DATA 530
# define SSL_F_TLS_CONSTRUCT_CTOS_EC_PT_FORMATS 467
# define SSL_F_TLS_CONSTRUCT_CTOS_EMS 468
# define SSL_F_TLS_CONSTRUCT_CTOS_ETM 469
@@ -2669,6 +2676,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS 239
# define SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES 242
# define SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES 243
+# define SSL_R_UNEXPECTED_END_OF_EARLY_DATA 178
# define SSL_R_UNEXPECTED_MESSAGE 244
# define SSL_R_UNEXPECTED_RECORD 245
# define SSL_R_UNINITIALIZED 276
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index d7b98e055b..6fa272c77a 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -1437,6 +1437,14 @@ 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];
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index 4a1c0413a1..94c221f558 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -419,15 +419,15 @@ int ssl3_get_record(SSL *s)
/*-
* enc_err is:
- * 0: (in non-constant time) if the record is publically invalid.
+ * 0: (in non-constant time) if the record is publicly invalid.
* 1: if the padding is valid
* -1: if the padding is invalid
*/
if (enc_err == 0) {
if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
/*
- * We assume this is unreadable early_data - we treat it like an
- * empty record
+ * Valid early_data that we cannot decrypt might fail here as
+ * publicly invalid. We treat it like an empty record.
*/
thisrr = &rr[0];
thisrr->length = 0;
@@ -507,6 +507,17 @@ int ssl3_get_record(SSL *s)
}
if (enc_err < 0) {
+ if (num_recs == 1 && ossl_statem_skip_early_data(s)) {
+ /*
+ * We assume this is unreadable early_data - we treat it like an
+ * empty record
+ */
+ thisrr = &rr[0];
+ thisrr->length = 0;
+ thisrr->read = 1;
+ RECORD_LAYER_set_numrpipes(&s->rlayer, 1);
+ return 1;
+ }
/*
* A separate 'decryption_failed' alert was introduced with TLS 1.0,
* SSL 3.0 only has 'bad_record_mac'. But unless a decryption
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index c6cc375643..0620966172 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -205,6 +205,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
{ERR_FUNC(SSL_F_SSL_PEEK_EX), "SSL_peek_ex"},
{ERR_FUNC(SSL_F_SSL_PEEK_INTERNAL), "ssl_peek_internal"},
{ERR_FUNC(SSL_F_SSL_READ), "SSL_read"},
+ {ERR_FUNC(SSL_F_SSL_READ_EARLY), "SSL_read_early"},
{ERR_FUNC(SSL_F_SSL_READ_EX), "SSL_read_ex"},
{ERR_FUNC(SSL_F_SSL_READ_INTERNAL), "ssl_read_internal"},
{ERR_FUNC(SSL_F_SSL_RENEGOTIATE), "SSL_renegotiate"},
@@ -793,6 +794,8 @@ static ERR_STRING_DATA SSL_str_reasons[] = {
"unable to load ssl3 md5 routines"},
{ERR_REASON(SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES),
"unable to load ssl3 sha1 routines"},
+ {ERR_REASON(SSL_R_UNEXPECTED_END_OF_EARLY_DATA),
+ "unexpected end of early data"},
{ERR_REASON(SSL_R_UNEXPECTED_MESSAGE), "unexpected message"},
{ERR_REASON(SSL_R_UNEXPECTED_RECORD), "unexpected record"},
{ERR_REASON(SSL_R_UNINITIALIZED), "uninitialized"},
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 8e28786447..e3e7853d60 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -1594,6 +1594,75 @@ int SSL_read_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
return ret;
}
+int SSL_read_early(SSL *s, void *buf, size_t num, size_t *readbytes)
+{
+ int ret;
+
+ if (!s->server) {
+ SSLerr(SSL_F_SSL_READ_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return SSL_READ_EARLY_ERROR;
+ }
+
+ /*
+ * TODO(TLS1.3): Somehow we need to check that we're not receiving too much
+ * data
+ */
+
+ switch (s->early_data_state) {
+ case SSL_EARLY_DATA_NONE:
+ if (!SSL_in_before(s)) {
+ SSLerr(SSL_F_SSL_READ_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return SSL_READ_EARLY_ERROR;
+ }
+ /* fall through */
+
+ case SSL_EARLY_DATA_ACCEPT_RETRY:
+ s->early_data_state = SSL_EARLY_DATA_ACCEPTING;
+ ret = SSL_accept(s);
+ if (ret <= 0) {
+ /* NBIO or error */
+ s->early_data_state = SSL_EARLY_DATA_ACCEPT_RETRY;
+ return SSL_READ_EARLY_ERROR;
+ }
+ /* fall through */
+
+ case SSL_EARLY_DATA_READ_RETRY:
+ if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+ 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
+ */
+ if (ret > 0 || (ret <= 0 && s->early_data_state
+ != SSL_EARLY_DATA_FINISHED_READING)) {
+ s->early_data_state = SSL_EARLY_DATA_READ_RETRY;
+ return ret > 0 ? SSL_READ_EARLY_SUCCESS : SSL_READ_EARLY_ERROR;
+ }
+ } else {
+ s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+ }
+ *readbytes = 0;
+ ossl_statem_set_in_init(s, 1);
+ return SSL_READ_EARLY_FINISH;
+
+ default:
+ SSLerr(SSL_F_SSL_READ_EARLY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return SSL_READ_EARLY_ERROR;
+ }
+}
+
+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_FINISHED_READING;
+ return 1;
+ }
+
+ return 0;
+}
+
static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
{
if (s->handshake_func == NULL) {
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 7c8e3fad21..db1d7cfad3 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -618,7 +618,12 @@ typedef enum {
SSL_EARLY_DATA_CONNECTING,
SSL_EARLY_DATA_WRITE_RETRY,
SSL_EARLY_DATA_WRITING,
- SSL_EARLY_DATA_FINISHED_WRITING
+ SSL_EARLY_DATA_FINISHED_WRITING,
+ SSL_EARLY_DATA_ACCEPT_RETRY,
+ SSL_EARLY_DATA_ACCEPTING,
+ SSL_EARLY_DATA_READ_RETRY,
+ SSL_EARLY_DATA_READING,
+ SSL_EARLY_DATA_FINISHED_READING
} SSL_EARLY_DATA_STATE;
#define MAX_COMPRESSIONS_SIZE 255
@@ -1987,6 +1992,7 @@ 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 9ec8e85426..26c9273210 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -326,7 +326,8 @@ static int state_machine(SSL *s, int server)
}
if ((SSL_IS_FIRST_HANDSHAKE(s)
- && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING)
+ && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING
+ && s->early_data_state != SSL_EARLY_DATA_FINISHED_READING)
|| s->renegotiate) {
if (!tls_setup_handshake(s)) {
ossl_statem_set_error(s);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index 390e475fa4..e70ed10932 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -1229,12 +1229,6 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
SSL_COMP *comp;
#endif
- /*
- * This is a real handshake so make sure we clean it up at the end. We set
- * this here so that we are after any early_data
- */
- s->statem.cleanuphand = 1;
-
if (!PACKET_get_net_2(pkt, &sversion)) {
al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_LENGTH_MISMATCH);
diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c
index ed1ecce160..dec8cb3e38 100644
--- a/ssl/statem/statem_lib.c
+++ b/ssl/statem/statem_lib.c
@@ -654,6 +654,10 @@ MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt)
int al = SSL_AD_INTERNAL_ERROR;
size_t md_len;
+
+ /* This is a real handshake so make sure we clean it up at the end */
+ s->statem.cleanuphand = 1;
+
/* If this occurs, we have missed a message */
if (!SSL_IS_TLS13(s) && !s->s3->change_cipher_spec) {
al = SSL_AD_UNEXPECTED_MESSAGE;
@@ -944,6 +948,7 @@ 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_srvr.c b/ssl/statem/statem_srvr.c
index 39e0f59833..3d2d39b33d 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -406,6 +406,10 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
return WRITE_TRAN_ERROR;
case TLS_ST_OK:
+ if (s->early_data_state == SSL_EARLY_DATA_FINISHED_READING) {
+ st->hand_state = TLS_ST_SW_FINISHED;
+ return WRITE_TRAN_FINISHED;
+ }
if (s->key_update != SSL_KEY_UPDATE_NONE) {
st->hand_state = TLS_ST_SW_KEY_UPDATE;
return WRITE_TRAN_CONTINUE;
@@ -450,6 +454,11 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
return WRITE_TRAN_CONTINUE;
case TLS_ST_SW_FINISHED:
+ if (s->early_data_state == SSL_EARLY_DATA_ACCEPTING) {
+ st->hand_state = TLS_ST_OK;
+ ossl_statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
+ }
return WRITE_TRAN_FINISHED;
case TLS_ST_SR_FINISHED:
@@ -1234,9 +1243,6 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
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.
*/
diff --git a/util/libssl.num b/util/libssl.num
index 52ae727b37..8d1f0b88b7 100644
--- a/util/libssl.num
+++ b/util/libssl.num
@@ -430,3 +430,4 @@ SSL_get_max_early_data 430 1_1_1 EXIST::FUNCTION:
SSL_CTX_get_max_early_data 431 1_1_1 EXIST::FUNCTION:
SSL_write_early 432 1_1_1 EXIST::FUNCTION:
SSL_write_early_finish 433 1_1_1 EXIST::FUNCTION:
+SSL_read_early 434 1_1_1 EXIST::FUNCTION: