summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/openssl/ssl.h2
-rw-r--r--ssl/s3_lib.c8
-rw-r--r--ssl/ssl_err.c4
-rw-r--r--ssl/ssl_locl.h3
-rw-r--r--ssl/statem/statem_clnt.c203
-rw-r--r--ssl/statem/statem_srvr.c214
-rw-r--r--ssl/t1_enc.c8
-rw-r--r--ssl/t1_lib.c27
-rwxr-xr-xtest/recipes/70-test_sslsessiontick.t2
-rw-r--r--test/recipes/70-test_tlsextms.t52
-rw-r--r--test/recipes/80-test_ssl_new.t3
-rw-r--r--test/ssl-tests/08-npn.conf22
-rw-r--r--test/ssl-tests/08-npn.conf.in33
13 files changed, 531 insertions, 50 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index fdef8c54e3..f05ec9d0b4 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -2099,8 +2099,10 @@ int ERR_load_SSL_strings(void);
# define SSL_F_DTLS_GET_REASSEMBLED_MESSAGE 370
# define SSL_F_DTLS_PROCESS_HELLO_VERIFY 386
# define SSL_F_OPENSSL_INIT_SSL 342
+# define SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION 436
# define SSL_F_OSSL_STATEM_CLIENT_CONSTRUCT_MESSAGE 430
# define SSL_F_OSSL_STATEM_CLIENT_READ_TRANSITION 417
+# define SSL_F_OSSL_STATEM_SERVER13_READ_TRANSITION 437
# define SSL_F_OSSL_STATEM_SERVER_CONSTRUCT_MESSAGE 431
# define SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION 418
# define SSL_F_READ_STATE_MACHINE 352
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 2439167307..bcc0f9e5fd 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -4068,7 +4068,7 @@ EVP_PKEY *ssl_generate_pkey_curve(int id)
#endif
/* Derive premaster or master secret for ECDH/DH */
-int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey)
+int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int genmaster)
{
int rv = 0;
unsigned char *pms = NULL;
@@ -4093,12 +4093,12 @@ int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey)
if (EVP_PKEY_derive(pctx, pms, &pmslen) <= 0)
goto err;
- if (s->server) {
- /* For server generate master secret and discard premaster */
+ if (genmaster) {
+ /* Generate master secret and discard premaster */
rv = ssl_generate_master_secret(s, pms, pmslen, 1);
pms = NULL;
} else {
- /* For client just save premaster secret */
+ /* Save premaster secret */
s->s3->tmp.pms = pms;
s->s3->tmp.pmslen = pmslen;
pms = NULL;
diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c
index fcd4375c24..4b4559d08e 100644
--- a/ssl/ssl_err.c
+++ b/ssl/ssl_err.c
@@ -49,10 +49,14 @@ static ERR_STRING_DATA SSL_str_functs[] = {
"dtls_get_reassembled_message"},
{ERR_FUNC(SSL_F_DTLS_PROCESS_HELLO_VERIFY), "dtls_process_hello_verify"},
{ERR_FUNC(SSL_F_OPENSSL_INIT_SSL), "OPENSSL_init_ssl"},
+ {ERR_FUNC(SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION),
+ "ossl_statem_client13_read_transition"},
{ERR_FUNC(SSL_F_OSSL_STATEM_CLIENT_CONSTRUCT_MESSAGE),
"ossl_statem_client_construct_message"},
{ERR_FUNC(SSL_F_OSSL_STATEM_CLIENT_READ_TRANSITION),
"ossl_statem_client_read_transition"},
+ {ERR_FUNC(SSL_F_OSSL_STATEM_SERVER13_READ_TRANSITION),
+ "ossl_statem_server13_read_transition"},
{ERR_FUNC(SSL_F_OSSL_STATEM_SERVER_CONSTRUCT_MESSAGE),
"ossl_statem_server_construct_message"},
{ERR_FUNC(SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION),
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index ec0d0b4824..88b2f8b575 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -1879,7 +1879,8 @@ __owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field,
__owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
int free_pms);
__owur EVP_PKEY *ssl_generate_pkey(EVP_PKEY *pm);
-__owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey);
+__owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey,
+ int genmaster);
__owur EVP_PKEY *ssl_dh_to_pkey(DH *dh);
__owur const SSL_CIPHER *ssl3_get_cipher_by_char(const unsigned char *p);
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c
index e0d53fe33b..feda8d2119 100644
--- a/ssl/statem/statem_clnt.c
+++ b/ssl/statem/statem_clnt.c
@@ -108,6 +108,112 @@ static int key_exchange_expected(SSL *s)
/*
* ossl_statem_client_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when a TLS1.3 client is reading messages from the
+ * server. The message type that the server has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
+ *
+ * Return values are:
+ * 1: Success (transition allowed)
+ * 0: Error (transition not allowed)
+ */
+static int ossl_statem_client13_read_transition(SSL *s, int mt)
+{
+ OSSL_STATEM *st = &s->statem;
+
+ /*
+ * Note: There is no case for TLS_ST_CW_CLNT_HELLO, because we haven't
+ * yet negotiated TLSv1.3 at that point so that is handled by
+ * ossl_statem_client_read_transition()
+ */
+
+ switch (st->hand_state) {
+ default:
+ break;
+
+ case TLS_ST_CR_SRVR_HELLO:
+ if (s->hit) {
+ if (s->tlsext_ticket_expected) {
+ if (mt == SSL3_MT_NEWSESSION_TICKET) {
+ st->hand_state = TLS_ST_CR_SESSION_TICKET;
+ return 1;
+ }
+ } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ st->hand_state = TLS_ST_CR_CHANGE;
+ return 1;
+ }
+ } else {
+ if (mt == SSL3_MT_CERTIFICATE) {
+ st->hand_state = TLS_ST_CR_CERT;
+ return 1;
+ }
+ }
+ break;
+
+ case TLS_ST_CR_CERT:
+ /*
+ * The CertificateStatus message is optional even if
+ * |tlsext_status_expected| is set
+ */
+ if (s->tlsext_status_expected && mt == SSL3_MT_CERTIFICATE_STATUS) {
+ st->hand_state = TLS_ST_CR_CERT_STATUS;
+ return 1;
+ }
+ /* Fall through */
+
+ case TLS_ST_CR_CERT_STATUS:
+ if (mt == SSL3_MT_CERTIFICATE_REQUEST) {
+ if (cert_req_allowed(s)) {
+ st->hand_state = TLS_ST_CR_CERT_REQ;
+ return 1;
+ }
+ goto err;
+ }
+ /* Fall through */
+
+ case TLS_ST_CR_CERT_REQ:
+ if (mt == SSL3_MT_SERVER_DONE) {
+ st->hand_state = TLS_ST_CR_SRVR_DONE;
+ return 1;
+ }
+ break;
+
+ case TLS_ST_CW_FINISHED:
+ if (s->tlsext_ticket_expected) {
+ if (mt == SSL3_MT_NEWSESSION_TICKET) {
+ st->hand_state = TLS_ST_CR_SESSION_TICKET;
+ return 1;
+ }
+ } else if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ st->hand_state = TLS_ST_CR_CHANGE;
+ return 1;
+ }
+ break;
+
+ case TLS_ST_CR_SESSION_TICKET:
+ if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ st->hand_state = TLS_ST_CR_CHANGE;
+ return 1;
+ }
+ break;
+
+ case TLS_ST_CR_CHANGE:
+ if (mt == SSL3_MT_FINISHED) {
+ st->hand_state = TLS_ST_CR_FINISHED;
+ return 1;
+ }
+ break;
+ }
+
+ err:
+ /* No valid transition found */
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_UNEXPECTED_MESSAGE);
+ SSLerr(SSL_F_OSSL_STATEM_CLIENT13_READ_TRANSITION,
+ SSL_R_UNEXPECTED_MESSAGE);
+ return 0;
+}
+
+/*
+ * ossl_statem_client_read_transition() encapsulates the logic for the allowed
* handshake state transitions when the client is reading messages from the
* server. The message type that the server has sent is provided in |mt|. The
* current state is in |s->statem.hand_state|.
@@ -121,6 +227,13 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
OSSL_STATEM *st = &s->statem;
int ske_expected;
+ /*
+ * Note that after a ClientHello we don't know what version we are going
+ * to negotiate yet, so we don't take this branch until later
+ */
+ if (s->method->version == TLS1_3_VERSION)
+ return ossl_statem_client13_read_transition(s, mt);
+
switch (st->hand_state) {
default:
break;
@@ -271,13 +384,94 @@ int ossl_statem_client_read_transition(SSL *s, int mt)
}
/*
- * client_write_transition() works out what handshake state to move to next
- * when the client is writing messages to be sent to the server.
+ * ossl_statem_client13_write_transition() works out what handshake state to
+ * move to next when the TLSv1.3 client is writing messages to be sent to the
+ * server.
+ *
+ * Return values:
+ * WRITE_TRAN_ERROR - an error occurred
+ * WRITE_TRAN_CONTINUE - Successful transition, more writing to be done
+ * WRITE_TRAN_FINISHED - Successful transition, no more writing to be done
+ */
+static WRITE_TRAN ossl_statem_client13_write_transition(SSL *s)
+{
+ OSSL_STATEM *st = &s->statem;
+
+ /*
+ * Note: There are no cases for TLS_ST_BEFORE or TLS_ST_CW_CLNT_HELLO,
+ * because we haven't negotiated TLSv1.3 yet at that point. They are
+ * handled by ossl_statem_client_write_transition().
+ */
+ switch (st->hand_state) {
+ default:
+ /* Shouldn't happen */
+ return WRITE_TRAN_ERROR;
+
+ case TLS_ST_CR_SRVR_DONE:
+ if (s->s3->tmp.cert_req)
+ st->hand_state = TLS_ST_CW_CERT;
+ else
+ st->hand_state = TLS_ST_CW_CHANGE;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_CW_CERT:
+ /* If a non-empty Certificate we also send CertificateVerify */
+ if (s->s3->tmp.cert_req == 1)
+ st->hand_state = TLS_ST_CW_CERT_VRFY;
+ else
+ st->hand_state = TLS_ST_CW_CHANGE;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_CW_CERT_VRFY:
+ st->hand_state = TLS_ST_CW_CHANGE;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_CW_CHANGE:
+ st->hand_state = TLS_ST_CW_FINISHED;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_CW_FINISHED:
+ if (s->hit) {
+ st->hand_state = TLS_ST_OK;
+ ossl_statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
+ } else {
+ return WRITE_TRAN_FINISHED;
+ }
+
+ case TLS_ST_CR_FINISHED:
+ if (s->hit) {
+ st->hand_state = TLS_ST_CW_CHANGE;
+ return WRITE_TRAN_CONTINUE;
+ } else {
+ st->hand_state = TLS_ST_OK;
+ ossl_statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
+ }
+ }
+}
+
+/*
+ * ossl_statem_client_write_transition() works out what handshake state to
+ * move to next when the client is writing messages to be sent to the server.
+ *
+ * Return values:
+ * WRITE_TRAN_ERROR - an error occurred
+ * WRITE_TRAN_CONTINUE - Successful transition, more writing to be done
+ * WRITE_TRAN_FINISHED - Successful transition, no more writing to be done
*/
WRITE_TRAN ossl_statem_client_write_transition(SSL *s)
{
OSSL_STATEM *st = &s->statem;
+ /*
+ * Note that immediately before/after a ClientHello we don't know what
+ * version we are going to negotiate yet, so we don't take this branch until
+ * later
+ */
+ if (s->method->version == TLS1_3_VERSION)
+ return ossl_statem_client13_write_transition(s);
+
switch (st->hand_state) {
default:
/* Shouldn't happen */
@@ -2282,7 +2476,7 @@ static int tls_construct_cke_dhe(SSL *s, WPACKET *pkt, int *al)
ckey = ssl_generate_pkey(skey);
dh_clnt = EVP_PKEY_get0_DH(ckey);
- if (dh_clnt == NULL || ssl_derive(s, ckey, skey) == 0)
+ if (dh_clnt == NULL || ssl_derive(s, ckey, skey, 0) == 0)
goto err;
/* send off the data */
@@ -2318,7 +2512,7 @@ static int tls_construct_cke_ecdhe(SSL *s, WPACKET *pkt, int *al)
ckey = ssl_generate_pkey(skey);
- if (ssl_derive(s, ckey, skey) == 0) {
+ if (ssl_derive(s, ckey, skey, 0) == 0) {
SSLerr(SSL_F_TLS_CONSTRUCT_CKE_ECDHE, ERR_R_EVP_LIB);
goto err;
}
@@ -2626,6 +2820,7 @@ int tls_construct_client_verify(SSL *s, WPACKET *pkt)
SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
goto err;
}
+
if (SSL_USE_SIGALGS(s)&& !tls12_get_sigandhash(pkt, pkey, md)) {
SSLerr(SSL_F_TLS_CONSTRUCT_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
goto err;
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index 38a1b6931d..0e910aa2f2 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -68,10 +68,90 @@ static STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s,
int *al);
/*
- * server_read_transition() encapsulates the logic for the allowed handshake
- * state transitions when the server is reading messages from the client. The
- * message type that the client has sent is provided in |mt|. The current state
- * is in |s->statem.hand_state|.
+ * ossl_statem_server13_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when a TLSv1.3 server is reading messages from
+ * the client. The message type that the client has sent is provided in |mt|.
+ * The current state is in |s->statem.hand_state|.
+ *
+ * Valid return values are:
+ * 1: Success (transition allowed)
+ * 0: Error (transition not allowed)
+ */
+static int ossl_statem_server13_read_transition(SSL *s, int mt)
+{
+ OSSL_STATEM *st = &s->statem;
+
+ /*
+ * Note: There is no case for TLS_ST_BEFORE because at that stage we have
+ * not negotiated TLSv1.3 yet, so that case is handled by
+ * ossl_statem_server_read_transition()
+ */
+ switch (st->hand_state) {
+ default:
+ break;
+
+ case TLS_ST_SW_SRVR_DONE:
+ if (s->s3->tmp.cert_request) {
+ if (mt == SSL3_MT_CERTIFICATE) {
+ st->hand_state = TLS_ST_SR_CERT;
+ return 1;
+ }
+ } else {
+ if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ st->hand_state = TLS_ST_SR_CHANGE;
+ return 1;
+ }
+ }
+ break;
+
+ case TLS_ST_SR_CERT:
+ if (s->session->peer == NULL) {
+ if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ st->hand_state = TLS_ST_SR_CHANGE;
+ return 1;
+ }
+ } else {
+ if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
+ st->hand_state = TLS_ST_SR_CERT_VRFY;
+ return 1;
+ }
+ }
+ break;
+
+ case TLS_ST_SR_CERT_VRFY:
+ if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ st->hand_state = TLS_ST_SR_CHANGE;
+ return 1;
+ }
+ break;
+
+ case TLS_ST_SR_CHANGE:
+ if (mt == SSL3_MT_FINISHED) {
+ st->hand_state = TLS_ST_SR_FINISHED;
+ return 1;
+ }
+ break;
+
+ case TLS_ST_SW_FINISHED:
+ if (mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ st->hand_state = TLS_ST_SR_CHANGE;
+ return 1;
+ }
+ break;
+ }
+
+ /* 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;
+}
+
+/*
+ * ossl_statem_server_read_transition() encapsulates the logic for the allowed
+ * handshake state transitions when the server is reading messages from the
+ * client. The message type that the client has sent is provided in |mt|. The
+ * current state is in |s->statem.hand_state|.
*
* Valid return values are:
* 1: Success (transition allowed)
@@ -81,6 +161,9 @@ int ossl_statem_server_read_transition(SSL *s, int mt)
{
OSSL_STATEM *st = &s->statem;
+ if (s->method->version == TLS1_3_VERSION)
+ return ossl_statem_server13_read_transition(s, mt);
+
switch (st->hand_state) {
default:
break;
@@ -304,13 +387,116 @@ static int send_certificate_request(SSL *s)
}
/*
- * server_write_transition() works out what handshake state to move to next
- * when the server is writing messages to be sent to the client.
+ * ossl_statem_server13_write_transition() works out what handshake state to
+ * move to next when a TLSv1.3 server is writing messages to be sent to the
+ * client.
+ *
+ * Return values:
+ * WRITE_TRAN_ERROR - an error occurred
+ * WRITE_TRAN_CONTINUE - Successful transition, more writing to be done
+ * WRITE_TRAN_FINISHED - Successful transition, no more writing to be done
+ */
+static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
+{
+ OSSL_STATEM *st = &s->statem;
+
+ /*
+ * No case for TLS_ST_BEFORE, because at that stage we have not negotiated
+ * TLSv1.3 yet, so that is handled by ossl_statem_server_write_transition()
+ */
+
+ switch (st->hand_state) {
+ default:
+ /* Shouldn't happen */
+ return WRITE_TRAN_ERROR;
+
+ case TLS_ST_SR_CLNT_HELLO:
+ st->hand_state = TLS_ST_SW_SRVR_HELLO;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_SRVR_HELLO:
+ if (s->hit) {
+ if (s->tlsext_ticket_expected)
+ st->hand_state = TLS_ST_SW_SESSION_TICKET;
+ else
+ st->hand_state = TLS_ST_SW_CHANGE;
+ } else {
+ st->hand_state = TLS_ST_SW_CERT;
+ }
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_CERT:
+ if (s->tlsext_status_expected) {
+ st->hand_state = TLS_ST_SW_CERT_STATUS;
+ return WRITE_TRAN_CONTINUE;
+ }
+ /* Fall through */
+
+ case TLS_ST_SW_CERT_STATUS:
+ if (send_certificate_request(s)) {
+ st->hand_state = TLS_ST_SW_CERT_REQ;
+ return WRITE_TRAN_CONTINUE;
+ }
+ /* Fall through */
+
+ case TLS_ST_SW_CERT_REQ:
+ st->hand_state = TLS_ST_SW_SRVR_DONE;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_SRVR_DONE:
+ return WRITE_TRAN_FINISHED;
+
+ case TLS_ST_SR_FINISHED:
+ if (s->hit) {
+ st->hand_state = TLS_ST_OK;
+ ossl_statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
+ } else if (s->tlsext_ticket_expected) {
+ st->hand_state = TLS_ST_SW_SESSION_TICKET;
+ } else {
+ st->hand_state = TLS_ST_SW_CHANGE;
+ }
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_SESSION_TICKET:
+ st->hand_state = TLS_ST_SW_CHANGE;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_CHANGE:
+ st->hand_state = TLS_ST_SW_FINISHED;
+ return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_SW_FINISHED:
+ if (s->hit) {
+ return WRITE_TRAN_FINISHED;
+ }
+ st->hand_state = TLS_ST_OK;
+ ossl_statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
+ }
+}
+
+/*
+ * ossl_statem_server_write_transition() works out what handshake state to move
+ * to next when the server is writing messages to be sent to the client.
+ *
+ * Return values:
+ * WRITE_TRAN_ERROR - an error occurred
+ * WRITE_TRAN_CONTINUE - Successful transition, more writing to be done
+ * WRITE_TRAN_FINISHED - Successful transition, no more writing to be done
*/
WRITE_TRAN ossl_statem_server_write_transition(SSL *s)
{
OSSL_STATEM *st = &s->statem;
+ /*
+ * Note that before the ClientHello we don't know what version we are going
+ * to negotiate yet, so we don't take this branch until later
+ */
+
+ if (s->method->version == TLS1_3_VERSION)
+ return ossl_statem_server13_write_transition(s);
+
switch (st->hand_state) {
default:
/* Shouldn't happen */
@@ -2316,7 +2502,7 @@ static int tls_process_cke_dhe(SSL *s, PACKET *pkt, int *al)
goto err;
}
- if (ssl_derive(s, skey, ckey) == 0) {
+ if (ssl_derive(s, skey, ckey, 1) == 0) {
*al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_PROCESS_CKE_DHE, ERR_R_INTERNAL_ERROR);
goto err;
@@ -2376,7 +2562,7 @@ static int tls_process_cke_ecdhe(SSL *s, PACKET *pkt, int *al)
}
}
- if (ssl_derive(s, skey, ckey) == 0) {
+ if (ssl_derive(s, skey, ckey, 1) == 0) {
*al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_PROCESS_CKE_ECDHE, ERR_R_INTERNAL_ERROR);
goto err;
@@ -2776,6 +2962,7 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL *s, PACKET *pkt)
al = SSL_AD_INTERNAL_ERROR;
goto f_err;
}
+
#ifdef SSL_DEBUG
fprintf(stderr, "Using client verify alg %s\n", EVP_MD_name(md));
#endif
@@ -2931,6 +3118,17 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt)
sk_X509_pop_free(s->session->peer_chain, X509_free);
s->session->peer_chain = sk;
+
+ /*
+ * Freeze the handshake buffer. For <TLS1.3 we do this after the CKE
+ * message
+ */
+ if (s->version == TLS1_3_VERSION && !ssl3_digest_cached_records(s, 1)) {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ }
+
/*
* Inconsistency alert: cert_chain does *not* include the peer's own
* certificate, while we do include it in statem_clnt.c
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 8d1e350a61..df2ce37030 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -474,7 +474,13 @@ size_t tls1_final_finish_mac(SSL *s, const char *str, size_t slen,
int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
size_t len, size_t *secret_size)
{
- if (s->session->flags & SSL_SESS_FLAG_EXTMS) {
+ /*
+ * TODO(TLS1.3): We haven't implemented TLS1.3 key derivation yet. For now
+ * we will just force no use of EMS (which adds complications around the
+ * handshake has). This will need to be removed later
+ */
+ if ((s->session->flags & SSL_SESS_FLAG_EXTMS)
+ && s->version != TLS1_3_VERSION) {
unsigned char hash[EVP_MAX_MD_SIZE * 2];
size_t hashlen;
/*
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index f87b7ef1ea..46ca29099e 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1684,9 +1684,15 @@ int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al)
OPENSSL_free(encodedPoint);
return 0;
}
+ OPENSSL_free(encodedPoint);
s->s3->tmp.pkey = skey;
- OPENSSL_free(encodedPoint);
+
+ if (ssl_derive(s, skey, ckey, 1) == 0) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
}
if (!custom_ext_add(s, 1, pkt, al)) {
@@ -2633,7 +2639,8 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
s->s3->tmp.new_cipher->algorithm_mac != SSL_AEAD
&& s->s3->tmp.new_cipher->algorithm_enc != SSL_RC4)
s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
- } else if (type == TLSEXT_TYPE_extended_master_secret) {
+ } else if (type == TLSEXT_TYPE_extended_master_secret &&
+ (SSL_IS_DTLS(s) || s->version < TLS1_3_VERSION)) {
s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
if (!s->hit)
s->session->flags |= SSL_SESS_FLAG_EXTMS;
@@ -2668,7 +2675,6 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
return 0;
}
- /* TODO(TLS1.3): Create skey from ckey */
skey = ssl_generate_pkey(ckey);
if (!PACKET_as_length_prefixed_2(&spkt, &encoded_pt)) {
@@ -2685,10 +2691,12 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
return 0;
}
- /*
- * TODO(TLS1.3): Throw it all away for now, later we will use the
- * two keys.
- */
+ if (ssl_derive(s, ckey, skey, 1) == 0) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_SSL_SCAN_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
+ EVP_PKEY_free(skey);
+ return 0;
+ }
EVP_PKEY_free(skey);
/*
* If this extension type was not otherwise handled, but matches a
@@ -3128,7 +3136,7 @@ int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello,
/*
* Sets the extended master secret flag if the extension is present in the
- * ClientHello
+ * ClientHello and we can support it
* Returns:
* 1 on success
* 0 on error
@@ -3139,7 +3147,8 @@ int tls_check_client_ems_support(SSL *s, const CLIENTHELLO_MSG *hello)
s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
- if (s->version <= SSL3_VERSION)
+ if (!SSL_IS_DTLS(s) && (s->version < TLS1_VERSION
+ || s->version > TLS1_2_VERSION))
return 1;
emsext = tls_get_extension_by_type(hello->pre_proc_exts,
diff --git a/test/recipes/70-test_sslsessiontick.t b/test/recipes/70-test_sslsessiontick.t
index 89ef12f75b..0c29ec7ce0 100755
--- a/test/recipes/70-test_sslsessiontick.t
+++ b/test/recipes/70-test_sslsessiontick.t
@@ -229,7 +229,7 @@ sub checkmessages($$$$$$)
$shellotickext = 1;
}
}
- } elsif ($message->mt == TLSProxy::Message::MT_CLIENT_KEY_EXCHANGE) {
+ } elsif ($message->mt == TLSProxy::Message::MT_CERTIFICATE) {
#Must be doing a full handshake
$fullhand = 1;
} elsif ($message->mt == TLSProxy::Message::MT_NEW_SESSION_TICKET) {
diff --git a/test/recipes/70-test_tlsextms.t b/test/recipes/70-test_tlsextms.t
index 1248594c06..dd2a6a47f6 100644
--- a/test/recipes/70-test_tlsextms.t
+++ b/test/recipes/70-test_tlsextms.t
@@ -24,8 +24,8 @@ plan skip_all => "$test_name needs the dynamic engine feature enabled"
plan skip_all => "$test_name needs the sock feature enabled"
if disabled("sock");
-plan skip_all => "$test_name needs TLS enabled"
- if alldisabled(available_protocols("tls"));
+plan skip_all => "$test_name needs TLSv1.0, TLSv1.1 or TLSv1.2 enabled"
+ if disabled("tls1") && disabled("tls1_1") && disabled("tls1_2");
$ENV{OPENSSL_ia32cap} = '~0x200000200000000';
@@ -46,14 +46,21 @@ my $proxy = TLSProxy::Proxy->new(
(!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE})
);
+#Note that EXTMS is only relevant for <TLS1.3
+
#Test 1: By default server and client should send extended master secret
# extension.
#Expected result: ClientHello extension seen; ServerHello extension seen
# Full handshake
setrmextms(0, 0);
+$proxy->clientflags("-no_tls1_3");
$proxy->start() or plan skip_all => "Unable to start up Proxy for tests";
-plan tests => 9;
+my $numtests = 9;
+if (!disabled("tls1_3")) {
+ $numtests++;
+}
+plan tests => $numtests;
checkmessages(1, "Default extended master secret test", 1, 1, 1);
#Test 2: If client omits extended master secret extension, server should too.
@@ -62,6 +69,7 @@ checkmessages(1, "Default extended master secret test", 1, 1, 1);
clearall();
setrmextms(1, 0);
+$proxy->clientflags("-no_tls1_3");
$proxy->start();
checkmessages(2, "No client extension extended master secret test", 0, 0, 1);
@@ -69,7 +77,7 @@ checkmessages(2, "No client extension extended master secret test", 0, 0, 1);
# Expected result: same as test 1.
clearall();
-$proxy->clientflags("-no_ticket");
+$proxy->clientflags("-no_ticket -no_tls1_3");
setrmextms(0, 0);
$proxy->start();
checkmessages(3, "No ticket extended master secret test", 1, 1, 1);
@@ -78,10 +86,10 @@ checkmessages(3, "No ticket extended master secret test", 1, 1, 1);
# Expected result: same as test 2.
clearall();
-$proxy->clientflags("-no_ticket");
+$proxy->clientflags("-no_ticket -no_tls1_3");
setrmextms(1, 0);
$proxy->start();
-checkmessages(2, "No ticket, no client extension extended master secret test", 0, 0, 1);
+checkmessages(4, "No ticket, no client extension extended master secret test", 0, 0, 1);
#Test 5: Session resumption extended master secret test
#
@@ -92,10 +100,10 @@ clearall();
setrmextms(0, 0);
(undef, my $session) = tempfile();
$proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
$proxy->start();
$proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
$proxy->clientstart();
checkmessages(5, "Session resumption extended master secret test", 1, 1, 0);
unlink $session;
@@ -109,10 +117,10 @@ clearall();
setrmextms(1, 0);
(undef, $session) = tempfile();
$proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
$proxy->start();
$proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
setrmextms(0, 0);
$proxy->clientstart();
checkmessages(6, "Session resumption extended master secret test", 1, 1, 1);
@@ -126,10 +134,10 @@ clearall();
setrmextms(0, 0);
(undef, $session) = tempfile();
$proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
$proxy->start();
$proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
setrmextms(1, 0);
$proxy->clientstart();
ok(TLSProxy::Message->fail(), "Client inconsistent session resumption");
@@ -143,10 +151,10 @@ clearall();
setrmextms(0, 0);
(undef, $session) = tempfile();
$proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
$proxy->start();
$proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
setrmextms(0, 1);
$proxy->clientstart();
ok(TLSProxy::Message->fail(), "Server inconsistent session resumption 1");
@@ -160,15 +168,27 @@ clearall();
setrmextms(0, 1);
(undef, $session) = tempfile();
$proxy->serverconnects(2);
-$proxy->clientflags("-sess_out ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_out ".$session);
$proxy->start();
$proxy->clearClient();
-$proxy->clientflags("-sess_in ".$session);
+$proxy->clientflags("-no_tls1_3 -sess_in ".$session);
setrmextms(0, 0);
$proxy->clientstart();
ok(TLSProxy::Message->fail(), "Server inconsistent session resumption 2");
unlink $session;
+#Test 10: In TLS1.3 we should not negotiate extended master secret
+#Expected result: ClientHello extension seen; ServerHello extension not seen
+# TLS1.3 handshake (will appear as abbreviated handshake
+# because of no CKE message)
+if (!disabled("tls1_3")) {
+ clearall();
+ setrmextms(0, 0);
+ $proxy->start();
+ checkmessages(10, "TLS1.3 extended master secret test", 1, 0, 0);
+}
+
+
sub extms_filter
{
my $proxy = shift;
diff --git a/test/recipes/80-test_ssl_new.t b/test/recipes/80-test_ssl_new.t
index d89aa3cf05..65d2be9e5e 100644
--- a/test/recipes/80-test_ssl_new.t
+++ b/test/recipes/80-test_ssl_new.t
@@ -62,7 +62,8 @@ my %conf_dependent_tests = (
# conditions.
my %skip = (
"07-dtls-protocol-version.conf" => $no_dtls,
- "08-npn.conf" => $no_tls || $no_npn,
+ "08-npn.conf" => (disabled("tls1") && disabled("tls1_1")
+ && disabled("tls1_2")) || $no_npn,
"10-resumption.conf" => disabled("tls1_1") || disabled("tls1_2"),
"11-dtls_resumption.conf" => disabled("dtls1") || disabled("dtls1_2"),
"12-ct.conf" => $no_tls || $no_ct || $no_ec,
diff --git a/test/ssl-tests/08-npn.conf b/test/ssl-tests/08-npn.conf
index 9115ef458b..f38b3f6975 100644
--- a/test/ssl-tests/08-npn.conf
+++ b/test/ssl-tests/08-npn.conf
@@ -38,6 +38,7 @@ PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem
[0-npn-simple-client]
CipherS