diff options
-rw-r--r-- | include/openssl/ssl.h | 2 | ||||
-rw-r--r-- | ssl/s3_lib.c | 8 | ||||
-rw-r--r-- | ssl/ssl_err.c | 4 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 3 | ||||
-rw-r--r-- | ssl/statem/statem_clnt.c | 203 | ||||
-rw-r--r-- | ssl/statem/statem_srvr.c | 214 | ||||
-rw-r--r-- | ssl/t1_enc.c | 8 | ||||
-rw-r--r-- | ssl/t1_lib.c | 27 | ||||
-rwxr-xr-x | test/recipes/70-test_sslsessiontick.t | 2 | ||||
-rw-r--r-- | test/recipes/70-test_tlsextms.t | 52 | ||||
-rw-r--r-- | test/recipes/80-test_ssl_new.t | 3 | ||||
-rw-r--r-- | test/ssl-tests/08-npn.conf | 22 | ||||
-rw-r--r-- | test/ssl-tests/08-npn.conf.in | 33 |
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 |