Start using the key_share data to derive the PMS The previous commits put in place the logic to exchange key_share data. We now need to do something with that information. In <= TLSv1.2 the equivalent of the key_share extension is the ServerKeyExchange and ClientKeyExchange messages. With key_share those two messages are no longer necessary. The commit removes the SKE and CKE messages from the TLSv1.3 state machine. TLSv1.3 is completely different to TLSv1.2 in the messages that it sends and the transitions that are allowed. Therefore, rather than extend the existing <=TLS1.2 state transition functions, we create a whole new set for TLSv1.3. Intially these are still based on the TLSv1.2 ones, but over time they will be amended. The new TLSv1.3 transitions remove SKE and CKE completely. There's also some cleanup for some stuff which is not relevant to TLSv1.3 and is easy to remove, e.g. the DTLS support (we're not doing DTLSv1.3 yet) and NPN. I also disable EXTMS for TLSv1.3. Using it was causing some added complexity, so rather than fix it I removed it, since eventually it will not be needed anyway. Reviewed-by: Rich Salz <rsalz@openssl.org>
diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index e0d53fe..feda8d2 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c
@@ -108,6 +108,112 @@ /* * 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 @@ 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 @@ } /* - * 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 @@ 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 @@ 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 @@ 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 38a1b69..0e910aa 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c
@@ -68,10 +68,90 @@ 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 @@ { 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 @@ } /* - * 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 @@ 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 @@ } } - 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 @@ 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 @@ 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