If we sent early_data and then received back an HRR, the enc_write_ctx
was stale resulting in errors if an alert needed to be sent.
Thanks to Quarkslab for reporting this.
In any case it makes little sense to encrypt alerts using the
client_early_traffic_secret, so we add special handling for alerts sent
after early_data. All such alerts are sent in plaintext.
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/6887)
* In TLSv1.3, once encrypting, we always use application data for the
* record type
*/
* In TLSv1.3, once encrypting, we always use application data for the
* record type
*/
- if (SSL_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL)
+ if (SSL_TREAT_AS_TLS13(s)
+ && s->enc_write_ctx != NULL
+ && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
+ || type != SSL3_RT_ALERT))
rectype = SSL3_RT_APPLICATION_DATA;
else
rectype = type;
rectype = SSL3_RT_APPLICATION_DATA;
else
rectype = type;
SSL3_RECORD_reset_input(&wr[j]);
}
SSL3_RECORD_reset_input(&wr[j]);
}
- if (SSL_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) {
+ if (SSL_TREAT_AS_TLS13(s)
+ && s->enc_write_ctx != NULL
+ && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
+ || type != SSL3_RT_ALERT)) {
size_t rlen, max_send_fragment;
if (!WPACKET_put_bytes_u8(thispkt, type)) {
size_t rlen, max_send_fragment;
if (!WPACKET_put_bytes_u8(thispkt, type)) {
SSL3_RECORD_set_length(thiswr, len);
}
SSL3_RECORD_set_length(thiswr, len);
}
- if (s->early_data_state == SSL_EARLY_DATA_WRITING
- || s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) {
+ if (s->statem.enc_write_state == ENC_WRITE_STATE_WRITE_PLAIN_ALERTS) {
/*
* We haven't actually negotiated the version yet, but we're trying to
* send early data - so we need to use the tls13enc function.
/*
* We haven't actually negotiated the version yet, but we're trying to
* send early data - so we need to use the tls13enc function.
seq = RECORD_LAYER_get_read_sequence(&s->rlayer);
}
seq = RECORD_LAYER_get_read_sequence(&s->rlayer);
}
+ if (ctx == NULL
+ || (rec->type == SSL3_RT_ALERT
+ && s->statem.enc_write_state
+ == ENC_WRITE_STATE_WRITE_PLAIN_ALERTS)) {
memmove(rec->data, rec->input, rec->length);
rec->input = rec->data;
return 1;
memmove(rec->data, rec->input, rec->length);
rec->input = rec->data;
return 1;
RECORD_LAYER_reset_read_sequence(&s->rlayer);
mac_secret = &(s->s3->read_mac_secret[0]);
} else {
RECORD_LAYER_reset_read_sequence(&s->rlayer);
mac_secret = &(s->s3->read_mac_secret[0]);
} else {
- s->statem.invalid_enc_write_ctx = 1;
+ s->statem.enc_write_state = ENC_WRITE_STATE_INVALID;
if (s->enc_write_ctx != NULL) {
reuse_dd = 1;
} else if ((s->enc_write_ctx = EVP_CIPHER_CTX_new()) == NULL) {
if (s->enc_write_ctx != NULL) {
reuse_dd = 1;
} else if ((s->enc_write_ctx = EVP_CIPHER_CTX_new()) == NULL) {
- s->statem.invalid_enc_write_ctx = 0;
+ s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
OPENSSL_cleanse(exp_key, sizeof(exp_key));
OPENSSL_cleanse(exp_iv, sizeof(exp_iv));
return 1;
OPENSSL_cleanse(exp_key, sizeof(exp_key));
OPENSSL_cleanse(exp_iv, sizeof(exp_iv));
return 1;
s->statem.in_init = 1;
s->statem.state = MSG_FLOW_ERROR;
ERR_put_error(ERR_LIB_SSL, func, reason, file, line);
s->statem.in_init = 1;
s->statem.state = MSG_FLOW_ERROR;
ERR_put_error(ERR_LIB_SSL, func, reason, file, line);
- if (al != SSL_AD_NO_ALERT && !s->statem.invalid_enc_write_ctx)
+ if (al != SSL_AD_NO_ALERT
+ && s->statem.enc_write_state != ENC_WRITE_STATE_INVALID)
ssl3_send_alert(s, SSL3_AL_FATAL, al);
}
ssl3_send_alert(s, SSL3_AL_FATAL, al);
}
WRITE_STATE_POST_WORK
} WRITE_STATE;
WRITE_STATE_POST_WORK
} WRITE_STATE;
+typedef enum {
+ /* The enc_write_ctx can be used normally */
+ ENC_WRITE_STATE_VALID,
+ /* The enc_write_ctx cannot be used */
+ ENC_WRITE_STATE_INVALID,
+ /* Write alerts in plaintext, but otherwise use the enc_write_ctx */
+ ENC_WRITE_STATE_WRITE_PLAIN_ALERTS
+} ENC_WRITE_STATES;
+
/*****************************************************************************
* *
* This structure should be considered "opaque" to anything outside of the *
/*****************************************************************************
* *
* This structure should be considered "opaque" to anything outside of the *
/* Should we skip the CertificateVerify message? */
unsigned int no_cert_verify;
int use_timer;
/* Should we skip the CertificateVerify message? */
unsigned int no_cert_verify;
int use_timer;
- int invalid_enc_write_ctx;
+ ENC_WRITE_STATES enc_write_state;
};
typedef struct ossl_statem_st OSSL_STATEM;
};
typedef struct ossl_statem_st OSSL_STATEM;
mac_secret = &(s->s3->read_mac_secret[0]);
mac_secret_size = &(s->s3->read_mac_secret_size);
} else {
mac_secret = &(s->s3->read_mac_secret[0]);
mac_secret_size = &(s->s3->read_mac_secret_size);
} else {
- s->statem.invalid_enc_write_ctx = 1;
+ s->statem.enc_write_state = ENC_WRITE_STATE_INVALID;
if (s->ext.use_etm)
s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE;
else
if (s->ext.use_etm)
s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE;
else
ERR_R_INTERNAL_ERROR);
goto err;
}
ERR_R_INTERNAL_ERROR);
goto err;
}
- s->statem.invalid_enc_write_ctx = 0;
+ s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
#ifdef SSL_DEBUG
printf("which = %04X\nkey=", which);
#ifdef SSL_DEBUG
printf("which = %04X\nkey=", which);
RECORD_LAYER_reset_read_sequence(&s->rlayer);
} else {
RECORD_LAYER_reset_read_sequence(&s->rlayer);
} else {
- s->statem.invalid_enc_write_ctx = 1;
+ s->statem.enc_write_state = ENC_WRITE_STATE_INVALID;
if (s->enc_write_ctx != NULL) {
EVP_CIPHER_CTX_reset(s->enc_write_ctx);
} else {
if (s->enc_write_ctx != NULL) {
EVP_CIPHER_CTX_reset(s->enc_write_ctx);
} else {
- s->statem.invalid_enc_write_ctx = 0;
+ if (!s->server && label == client_early_traffic)
+ s->statem.enc_write_state = ENC_WRITE_STATE_WRITE_PLAIN_ALERTS;
+ else
+ s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
ret = 1;
err:
OPENSSL_cleanse(secret, sizeof(secret));
ret = 1;
err:
OPENSSL_cleanse(secret, sizeof(secret));
insecret = s->client_app_traffic_secret;
if (sending) {
insecret = s->client_app_traffic_secret;
if (sending) {
- s->statem.invalid_enc_write_ctx = 1;
+ s->statem.enc_write_state = ENC_WRITE_STATE_INVALID;
iv = s->write_iv;
ciph_ctx = s->enc_write_ctx;
RECORD_LAYER_reset_write_sequence(&s->rlayer);
iv = s->write_iv;
ciph_ctx = s->enc_write_ctx;
RECORD_LAYER_reset_write_sequence(&s->rlayer);
memcpy(insecret, secret, hashlen);
memcpy(insecret, secret, hashlen);
- s->statem.invalid_enc_write_ctx = 0;
+ s->statem.enc_write_state = ENC_WRITE_STATE_VALID;
ret = 1;
err:
OPENSSL_cleanse(secret, sizeof(secret));
ret = 1;
err:
OPENSSL_cleanse(secret, sizeof(secret));