#include <openssl/bn.h>
#include <openssl/engine.h>
-static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt);
+static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s, PACKET *pkt);
static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt);
static ossl_inline int cert_req_allowed(SSL *s);
st->hand_state = DTLS_ST_CR_HELLO_VERIFY_REQUEST;
return 1;
}
- } else {
- if (mt == SSL3_MT_HELLO_RETRY_REQUEST) {
- st->hand_state = TLS_ST_CR_HELLO_RETRY_REQUEST;
- return 1;
- }
}
break;
st->hand_state = TLS_ST_CR_SRVR_HELLO;
return 1;
}
- if (mt == SSL3_MT_HELLO_RETRY_REQUEST) {
- st->hand_state = TLS_ST_CR_HELLO_RETRY_REQUEST;
- return 1;
- }
break;
case TLS_ST_CR_SRVR_HELLO:
ERR_R_INTERNAL_ERROR);
return WRITE_TRAN_ERROR;
- case TLS_ST_CW_CLNT_HELLO:
- /* We only hit this in the case of HelloRetryRequest */
- return WRITE_TRAN_FINISHED;
-
case TLS_ST_CR_FINISHED:
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 if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0
+ && s->hello_retry_request == SSL_HRR_NONE)
+ st->hand_state = TLS_ST_CW_CHANGE;
else
st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
: TLS_ST_CW_FINISHED;
/* Fall through */
case TLS_ST_CW_END_OF_EARLY_DATA:
+ case TLS_ST_CW_CHANGE:
st->hand_state = (s->s3->tmp.cert_req != 0) ? TLS_ST_CW_CERT
: TLS_ST_CW_FINISHED;
return WRITE_TRAN_CONTINUE;
* We are assuming this is a TLSv1.3 connection, although we haven't
* actually selected a version yet.
*/
- st->hand_state = TLS_ST_EARLY_DATA;
+ if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0)
+ st->hand_state = TLS_ST_CW_CHANGE;
+ else
+ st->hand_state = TLS_ST_EARLY_DATA;
return WRITE_TRAN_CONTINUE;
}
/*
*/
return WRITE_TRAN_FINISHED;
- case TLS_ST_CR_HELLO_RETRY_REQUEST:
- st->hand_state = TLS_ST_CW_CLNT_HELLO;
+ case TLS_ST_CR_SRVR_HELLO:
+ /*
+ * We only get here in TLSv1.3. We just received an HRR, so issue a
+ * CCS unless middlebox compat mode is off, or we already issued one
+ * because we did early data.
+ */
+ if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0
+ && s->early_data_state != SSL_EARLY_DATA_FINISHED_WRITING)
+ st->hand_state = TLS_ST_CW_CHANGE;
+ else
+ st->hand_state = TLS_ST_CW_CLNT_HELLO;
return WRITE_TRAN_CONTINUE;
case TLS_ST_EARLY_DATA:
return WRITE_TRAN_CONTINUE;
case TLS_ST_CW_CHANGE:
+ if (s->hello_retry_request == SSL_HRR_PENDING) {
+ st->hand_state = TLS_ST_CW_CLNT_HELLO;
+ } else if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) {
+ st->hand_state = TLS_ST_EARLY_DATA;
+ } else {
#if defined(OPENSSL_NO_NEXTPROTONEG)
- st->
- hand_state = TLS_ST_CW_FINISHED;
-#else
- if (!SSL_IS_DTLS(s) && s->s3->npn_seen)
- st->hand_state = TLS_ST_CW_NEXT_PROTO;
- else
st->hand_state = TLS_ST_CW_FINISHED;
+#else
+ if (!SSL_IS_DTLS(s) && s->s3->npn_seen)
+ st->hand_state = TLS_ST_CW_NEXT_PROTO;
+ else
+ st->hand_state = TLS_ST_CW_FINISHED;
#endif
+ }
return WRITE_TRAN_CONTINUE;
#if !defined(OPENSSL_NO_NEXTPROTONEG)
break;
case TLS_ST_CW_CLNT_HELLO:
- if (wst == WORK_MORE_A && statem_flush(s) != 1)
- return WORK_MORE_A;
-
- if (SSL_IS_DTLS(s)) {
- /* Treat the next message as the first packet */
- s->first_packet = 1;
- }
-
if (s->early_data_state == SSL_EARLY_DATA_CONNECTING
&& s->max_early_data > 0) {
/*
* cipher state function associated with the SSL_METHOD. Instead
* we call tls13_change_cipher_state() directly.
*/
- if (!tls13_change_cipher_state(s,
- SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
- /* SSLfatal() already called */
- return WORK_ERROR;
+ if ((s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) == 0) {
+ if (!statem_flush(s))
+ return WORK_MORE_A;
+ if (!tls13_change_cipher_state(s,
+ SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_CLIENT_WRITE)) {
+ /* SSLfatal() already called */
+ return WORK_ERROR;
+ }
}
+ /* else we're in compat mode so we delay flushing until after CCS */
+ } else if (!statem_flush(s)) {
+ return WORK_MORE_A;
+ }
+
+ if (SSL_IS_DTLS(s)) {
+ /* Treat the next message as the first packet */
+ s->first_packet = 1;
}
break;
break;
case TLS_ST_CW_CHANGE:
+ if (SSL_IS_TLS13(s) || s->hello_retry_request == SSL_HRR_PENDING)
+ break;
+ if (s->early_data_state == SSL_EARLY_DATA_CONNECTING
+ && s->max_early_data > 0) {
+ if (statem_flush(s) != 1)
+ return WORK_MORE_A;
+ /*
+ * We haven't selected TLSv1.3 yet so we don't call the change
+ * cipher state function associated with the SSL_METHOD. Instead
+ * we call tls13_change_cipher_state() directly.
+ */
+ if (!tls13_change_cipher_state(s,
+ SSL3_CC_EARLY | SSL3_CHANGE_CIPHER_CLIENT_WRITE))
+ return WORK_ERROR;
+ break;
+ }
s->session->cipher = s->s3->tmp.new_cipher;
#ifdef OPENSSL_NO_COMP
s->session->compress_meth = 0;
case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
return HELLO_VERIFY_REQUEST_MAX_LENGTH;
- case TLS_ST_CR_HELLO_RETRY_REQUEST:
- return HELLO_RETRY_REQUEST_MAX_LENGTH;
-
case TLS_ST_CR_CERT:
return s->max_cert_list;
case DTLS_ST_CR_HELLO_VERIFY_REQUEST:
return dtls_process_hello_verify(s, pkt);
- case TLS_ST_CR_HELLO_RETRY_REQUEST:
- return tls_process_hello_retry_request(s, pkt);
-
case TLS_ST_CR_CERT:
return tls_process_server_certificate(s, pkt);
SSL_COMP *comp;
#endif
SSL_SESSION *sess = s->session;
+ unsigned char *session_id;
if (!WPACKET_set_max_size(pkt, SSL3_RT_MAX_PLAIN_LENGTH)) {
/* Should not happen */
if (sess == NULL
|| !ssl_version_supported(s, sess->ssl_version)
|| !SSL_SESSION_is_resumable(sess)) {
- if (!ssl_get_new_session(s, 0)) {
+ if (s->hello_retry_request == SSL_HRR_NONE
+ && !ssl_get_new_session(s, 0)) {
/* SSLfatal() already called */
return 0;
}
}
}
} else {
- i = s->hello_retry_request == 0;
+ i = (s->hello_retry_request == SSL_HRR_NONE);
}
if (i && ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random),
}
/* Session ID */
- if (s->new_session || s->session->ssl_version == TLS1_3_VERSION)
- sess_id_len = 0;
- else
+ session_id = s->session->session_id;
+ if (s->new_session || s->session->ssl_version == TLS1_3_VERSION) {
+ if (s->version == TLS1_3_VERSION
+ && (s->options & SSL_OP_ENABLE_MIDDLEBOX_COMPAT) != 0) {
+ sess_id_len = sizeof(s->tmp_session_id);
+ s->tmp_session_id_len = sess_id_len;
+ session_id = s->tmp_session_id;
+ if (s->hello_retry_request == SSL_HRR_NONE
+ && ssl_randbytes(s, s->tmp_session_id,
+ sess_id_len) <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ } else {
+ sess_id_len = 0;
+ }
+ } else {
sess_id_len = s->session->session_id_length;
+ if (s->version == TLS1_3_VERSION) {
+ s->tmp_session_id_len = sess_id_len;
+ memcpy(s->tmp_session_id, s->session->session_id, sess_id_len);
+ }
+ }
if (sess_id_len > sizeof(s->session->session_id)
|| !WPACKET_start_sub_packet_u8(pkt)
- || (sess_id_len != 0 && !WPACKET_memcpy(pkt, s->session->session_id,
+ || (sess_id_len != 0 && !WPACKET_memcpy(pkt, session_id,
sess_id_len))
|| !WPACKET_close(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CLIENT_HELLO,
PACKET session_id, extpkt;
size_t session_id_len;
const unsigned char *cipherchars;
- int al = SSL_AD_INTERNAL_ERROR;
+ int hrr = 0;
unsigned int compression;
unsigned int sversion;
unsigned int context;
- int protverr, discard;
+ int discard;
RAW_EXTENSION *extensions = NULL;
#ifndef OPENSSL_NO_COMP
SSL_COMP *comp;
}
/* load the server random */
- if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
- SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
- SSL_R_LENGTH_MISMATCH);
- goto err;
- }
-
- /*
- * We do this immediately so we know what format the ServerHello is in.
- * Must be done after reading the random data so we can check for the
- * TLSv1.3 downgrade sentinels
- */
- protverr = ssl_choose_client_version(s, sversion, 1, &al);
- if (protverr != 0) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
- protverr);
- goto err;
- }
-
- /*
- * In TLSv1.3 a ServerHello message signals a key change so the end of the
- * message must be on a record boundary.
- */
- if (SSL_IS_TLS13(s) && RECORD_LAYER_processed_read_pending(&s->rlayer)) {
- SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_TLS_PROCESS_SERVER_HELLO,
- SSL_R_NOT_ON_RECORD_BOUNDARY);
- goto err;
- }
-
- /* Get the session-id. */
- if (!SSL_IS_TLS13(s)) {
- if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
+ if (s->version == TLS1_3_VERSION
+ && sversion == TLS1_2_VERSION
+ && PACKET_remaining(pkt) >= SSL3_RANDOM_SIZE
+ && memcmp(hrrrandom, PACKET_data(pkt), SSL3_RANDOM_SIZE) == 0) {
+ s->hello_retry_request = SSL_HRR_PENDING;
+ hrr = 1;
+ if (!PACKET_forward(pkt, SSL3_RANDOM_SIZE)) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
SSL_R_LENGTH_MISMATCH);
goto err;
}
- session_id_len = PACKET_remaining(&session_id);
- if (session_id_len > sizeof s->session->session_id
- || session_id_len > SSL3_SESSION_ID_SIZE) {
- SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
- SSL_F_TLS_PROCESS_SERVER_HELLO,
- SSL_R_SSL3_SESSION_ID_TOO_LONG);
+ } else {
+ if (!PACKET_copy_bytes(pkt, s->s3->server_random, SSL3_RANDOM_SIZE)) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+ SSL_R_LENGTH_MISMATCH);
goto err;
}
- } else {
- PACKET_null_init(&session_id);
- session_id_len = 0;
+ }
+
+ /* Get the session-id. */
+ if (!PACKET_get_length_prefixed_1(pkt, &session_id)) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+ SSL_R_LENGTH_MISMATCH);
+ goto err;
+ }
+ session_id_len = PACKET_remaining(&session_id);
+ if (session_id_len > sizeof(s->session->session_id)
+ || session_id_len > SSL3_SESSION_ID_SIZE) {
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
+ SSL_R_SSL3_SESSION_ID_TOO_LONG);
+ goto err;
}
if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
goto err;
}
- if (!SSL_IS_TLS13(s)) {
- if (!PACKET_get_1(pkt, &compression)) {
- SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
- SSL_R_LENGTH_MISMATCH);
- goto err;
- }
- } else {
- compression = 0;
+ if (!PACKET_get_1(pkt, &compression)) {
+ SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_SERVER_HELLO,
+ SSL_R_LENGTH_MISMATCH);
+ goto err;
}
/* TLS extensions */
- if (PACKET_remaining(pkt) == 0) {
+ if (PACKET_remaining(pkt) == 0 && !hrr) {
PACKET_null_init(&extpkt);
} else if (!PACKET_as_length_prefixed_2(pkt, &extpkt)
|| PACKET_remaining(pkt) != 0) {
goto err;
}
+ if (!hrr) {
+ if (!tls_collect_extensions(s, &extpkt,
+ SSL_EXT_TLS1_2_SERVER_HELLO
+ | SSL_EXT_TLS1_3_SERVER_HELLO,
+ &extensions, NULL, 1)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+
+ if (!ssl_choose_client_version(s, sversion, extensions)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+ }
+
+ if (SSL_IS_TLS13(s) || hrr) {
+ if (compression != 0) {
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+ SSL_F_TLS_PROCESS_SERVER_HELLO,
+ SSL_R_INVALID_COMPRESSION_ALGORITHM);
+ goto err;
+ }
+
+ if (session_id_len != s->tmp_session_id_len
+ || memcmp(PACKET_data(&session_id), s->tmp_session_id,
+ session_id_len) != 0) {
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+ SSL_F_TLS_PROCESS_SERVER_HELLO, SSL_R_INVALID_SESSION_ID);
+ goto err;
+ }
+ }
+
+ if (hrr) {
+ if (!set_client_ciphersuite(s, cipherchars)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+
+ return tls_process_as_hello_retry_request(s, &extpkt);
+ }
+
+ /*
+ * Now we have chosen the version we need to check again that the extensions
+ * are appropriate for this version.
+ */
context = SSL_IS_TLS13(s) ? SSL_EXT_TLS1_3_SERVER_HELLO
: SSL_EXT_TLS1_2_SERVER_HELLO;
- if (!tls_collect_extensions(s, &extpkt, context, &extensions, NULL, 1)) {
- /* SSLfatal() already called */
+ if (!tls_validate_all_contexts(s, context, extensions)) {
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
+ SSL_R_BAD_EXTENSION);
goto err;
}
s->hit = 0;
if (SSL_IS_TLS13(s)) {
+ /*
+ * In TLSv1.3 a ServerHello message signals a key change so the end of
+ * the message must be on a record boundary.
+ */
+ if (RECORD_LAYER_processed_read_pending(&s->rlayer)) {
+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+ SSL_F_TLS_PROCESS_SERVER_HELLO,
+ SSL_R_NOT_ON_RECORD_BOUNDARY);
+ goto err;
+ }
+
/* This will set s->hit if we are resuming */
if (!tls_parse_extension(s, TLSEXT_IDX_psk,
SSL_EXT_TLS1_3_SERVER_HELLO,
- extensions, NULL, 0l)) {
+ extensions, NULL, 0)) {
/* SSLfatal() already called */
goto err;
}
}
s->session->ssl_version = s->version;
- s->session->session_id_length = session_id_len;
- /* session_id_len could be 0 */
- if (session_id_len > 0)
- memcpy(s->session->session_id, PACKET_data(&session_id),
- session_id_len);
+ /*
+ * In TLSv1.2 and below we save the session id we were sent so we can
+ * resume it later. In TLSv1.3 the session id we were sent is just an
+ * echo of what we originally sent in the ClientHello and should not be
+ * used for resumption.
+ */
+ if (!SSL_IS_TLS13(s)) {
+ s->session->session_id_length = session_id_len;
+ /* session_id_len could be 0 */
+ if (session_id_len > 0)
+ memcpy(s->session->session_id, PACKET_data(&session_id),
+ session_id_len);
+ }
}
/* Session version and negotiated protocol version should match */
#else
if (s->hit && compression != s->session->compress_meth) {
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_SERVER_HELLO,
- SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
+ SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED);
goto err;
}
if (compression == 0)
return MSG_PROCESS_ERROR;
}
-static MSG_PROCESS_RETURN tls_process_hello_retry_request(SSL *s, PACKET *pkt)
+static MSG_PROCESS_RETURN tls_process_as_hello_retry_request(SSL *s,
+ PACKET *extpkt)
{
- unsigned int sversion;
- const unsigned char *cipherchars;
RAW_EXTENSION *extensions = NULL;
- PACKET extpkt;
-
- if (!PACKET_get_net_2(pkt, &sversion)) {
- SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST,
- SSL_R_LENGTH_MISMATCH);
- goto err;
- }
-
- /* TODO(TLS1.3): Remove the TLS1_3_VERSION_DRAFT clause before release */
- if (sversion != TLS1_3_VERSION && sversion != TLS1_3_VERSION_DRAFT) {
- SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
- SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST,
- SSL_R_WRONG_SSL_VERSION);
- goto err;
- }
-
- s->hello_retry_request = 1;
/*
* If we were sending early_data then the enc_write_ctx is now invalid and
EVP_CIPHER_CTX_free(s->enc_write_ctx);
s->enc_write_ctx = NULL;
- if (!PACKET_get_bytes(pkt, &cipherchars, TLS_CIPHER_LEN)) {
- SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST,
- SSL_R_LENGTH_MISMATCH);
- goto err;
- }
-
- if (!set_client_ciphersuite(s, cipherchars)) {
- /* SSLfatal() already called */
- goto err;
- }
-
- if (!PACKET_as_length_prefixed_2(pkt, &extpkt)
- /* Must have a non-empty extensions block */
- || PACKET_remaining(&extpkt) == 0
- /* Must be no trailing data after extensions */
- || PACKET_remaining(pkt) != 0) {
- SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST,
- SSL_R_BAD_LENGTH);
- goto err;
- }
-
- if (!tls_collect_extensions(s, &extpkt, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST,
+ if (!tls_collect_extensions(s, extpkt, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST,
&extensions, NULL, 1)
|| !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST,
extensions, NULL, 0, 1)) {
* ClientHello will not change
*/
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
- SSL_F_TLS_PROCESS_HELLO_RETRY_REQUEST,
- SSL_R_NO_CHANGE_FOLLOWING_HRR);
+ SSL_F_TLS_PROCESS_AS_HELLO_RETRY_REQUEST,
+ SSL_R_NO_CHANGE_FOLLOWING_HRR);
goto err;
}
md_ctx = EVP_MD_CTX_new();
if (md_ctx == NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_KEY_EXCHANGE,
- ERR_R_MALLOC_FAILURE);
+ ERR_R_MALLOC_FAILURE);
goto err;
}
if (ret < 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_PROCESS_INITIAL_SERVER_FLIGHT,
- ERR_R_MALLOC_FAILURE);
+ ERR_R_MALLOC_FAILURE);
return 0;
}
}
return 1;
err:
EVP_PKEY_free(ckey);
-#endif
+ return 0;
+#else
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CKE_DHE,
ERR_R_INTERNAL_ERROR);
return 0;
+#endif
}
static int tls_construct_cke_ecdhe(SSL *s, WPACKET *pkt)
sizeof(sctpauthkey), labelbuffer,
sizeof(labelbuffer), NULL, 0, 0) <= 0) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
- SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK, ERR_R_INTERNAL_ERROR);
+ SSL_F_TLS_CLIENT_KEY_EXCHANGE_POST_WORK,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
* state and thus ssl3_send_alert may crash.
*/
SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_TLS_CONSTRUCT_CLIENT_CERTIFICATE,
- SSL_R_CANNOT_CHANGE_CIPHER);
+ SSL_R_CANNOT_CHANGE_CIPHER);
return 0;
}