summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorMatt Caswell <matt@openssl.org>2017-02-03 14:06:20 +0000
committerMatt Caswell <matt@openssl.org>2017-02-16 09:39:06 +0000
commit4ad93618d26a3ea23d36ad5498ff4f59eff3a4d2 (patch)
treecf50c7a4eaaf7620c3decf0d116d5c0b08523e1b /ssl
parent9c5a691d578a4debfd6ecacc030a85900906bf0d (diff)
Don't change the state of the ETM flags until CCS processing
Changing the ciphersuite during a renegotiation can result in a crash leading to a DoS attack. ETM has not been implemented in 1.1.0 for DTLS so this is TLS only. The problem is caused by changing the flag indicating whether to use ETM or not immediately on negotiation of ETM, rather than at CCS. Therefore, during a renegotiation, if the ETM state is changing (usually due to a change of ciphersuite), then an error/crash will occur. Due to the fact that there are separate CCS messages for read and write we actually now need two flags to determine whether to use ETM or not. CVE-2017-3733 Reviewed-by: Richard Levitte <levitte@openssl.org>
Diffstat (limited to 'ssl')
-rw-r--r--ssl/record/rec_layer_s3.c6
-rw-r--r--ssl/record/ssl3_record.c10
-rw-r--r--ssl/ssl_locl.h7
-rw-r--r--ssl/t1_enc.c15
-rw-r--r--ssl/t1_lib.c12
5 files changed, 32 insertions, 18 deletions
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index 00379ea601..4a7e59bc99 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -395,7 +395,7 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, int len)
if (type == SSL3_RT_APPLICATION_DATA &&
u_len >= 4 * (max_send_fragment = s->max_send_fragment) &&
s->compress == NULL && s->msg_callback == NULL &&
- !SSL_USE_ETM(s) && SSL_USE_EXPLICIT_IV(s) &&
+ !SSL_WRITE_ETM(s) && SSL_USE_EXPLICIT_IV(s) &&
EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(s->enc_write_ctx)) &
EVP_CIPH_FLAG_TLS1_1_MULTIBLOCK) {
unsigned char aad[13];
@@ -791,7 +791,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
* wb->buf
*/
- if (!SSL_USE_ETM(s) && mac_size != 0) {
+ if (!SSL_WRITE_ETM(s) && mac_size != 0) {
if (s->method->ssl3_enc->mac(s, &wr[j],
&(outbuf[j][wr[j].length + eivlen]),
1) < 0)
@@ -814,7 +814,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf,
goto err;
for (j = 0; j < numpipes; j++) {
- if (SSL_USE_ETM(s) && mac_size != 0) {
+ if (SSL_WRITE_ETM(s) && mac_size != 0) {
if (s->method->ssl3_enc->mac(s, &wr[j],
outbuf[j] + wr[j].length, 1) < 0)
goto err;
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index e5cbd614ca..1f07933924 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -346,7 +346,7 @@ int ssl3_get_record(SSL *s)
* If in encrypt-then-mac mode calculate mac from encrypted record. All
* the details below are public so no timing details can leak.
*/
- if (SSL_USE_ETM(s) && s->read_hash) {
+ if (SSL_READ_ETM(s) && s->read_hash) {
unsigned char *mac;
mac_size = EVP_MD_CTX_size(s->read_hash);
OPENSSL_assert(mac_size <= EVP_MAX_MD_SIZE);
@@ -393,7 +393,7 @@ int ssl3_get_record(SSL *s)
/* r->length is now the compressed data plus mac */
if ((sess != NULL) &&
(s->enc_read_ctx != NULL) &&
- (EVP_MD_CTX_md(s->read_hash) != NULL) && !SSL_USE_ETM(s)) {
+ (!SSL_READ_ETM(s) && EVP_MD_CTX_md(s->read_hash) != NULL)) {
/* s->read_hash != NULL => mac_size != -1 */
unsigned char *mac = NULL;
unsigned char mac_tmp[EVP_MAX_MD_SIZE];
@@ -823,7 +823,7 @@ int tls1_enc(SSL *s, SSL3_RECORD *recs, unsigned int n_recs, int send)
}
ret = 1;
- if (!SSL_USE_ETM(s) && EVP_MD_CTX_md(s->read_hash) != NULL)
+ if (!SSL_READ_ETM(s) && EVP_MD_CTX_md(s->read_hash) != NULL)
mac_size = EVP_MD_CTX_size(s->read_hash);
if ((bs != 1) && !send) {
int tmpret;
@@ -997,7 +997,7 @@ int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int send)
header[11] = (rec->length) >> 8;
header[12] = (rec->length) & 0xff;
- if (!send && !SSL_USE_ETM(ssl) &&
+ if (!send && !SSL_READ_ETM(ssl) &&
EVP_CIPHER_CTX_mode(ssl->enc_read_ctx) == EVP_CIPH_CBC_MODE &&
ssl3_cbc_record_digest_supported(mac_ctx)) {
/*
@@ -1022,7 +1022,7 @@ int tls1_mac(SSL *ssl, SSL3_RECORD *rec, unsigned char *md, int send)
EVP_MD_CTX_free(hmac);
return -1;
}
- if (!send && !SSL_USE_ETM(ssl) && FIPS_mode())
+ if (!send && !SSL_READ_ETM(ssl) && FIPS_mode())
if (!tls_fips_digest_extra(ssl->enc_read_ctx,
mac_ctx, rec->input,
rec->length, rec->orig_len)) {
diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h
index 1586a46f63..08de52eea2 100644
--- a/ssl/ssl_locl.h
+++ b/ssl/ssl_locl.h
@@ -378,7 +378,8 @@
# define SSL_CLIENT_USE_SIGALGS(s) \
SSL_CLIENT_USE_TLS1_2_CIPHERS(s)
-# define SSL_USE_ETM(s) (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC)
+# define SSL_READ_ETM(s) (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC_READ)
+# define SSL_WRITE_ETM(s) (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE)
/* Mostly for SSLv3 */
# define SSL_PKEY_RSA_ENC 0
@@ -1110,6 +1111,10 @@ struct ssl_st {
*/
unsigned char *alpn_client_proto_list;
unsigned alpn_client_proto_list_len;
+
+ /* Set to one if we have negotiated ETM */
+ int tlsext_use_etm;
+
/*-
* 1 if we are renegotiating.
* 2 if we are a server and are inside a handshake
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 4aa5ddd18a..0fb88af249 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -130,6 +130,11 @@ int tls1_change_cipher_state(SSL *s, int which)
#endif
if (which & SSL3_CC_READ) {
+ if (s->tlsext_use_etm)
+ s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC_READ;
+ else
+ s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC_READ;
+
if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
s->mac_flags |= SSL_MAC_FLAG_READ_MAC_STREAM;
else
@@ -168,6 +173,11 @@ int tls1_change_cipher_state(SSL *s, int which)
mac_secret = &(s->s3->read_mac_secret[0]);
mac_secret_size = &(s->s3->read_mac_secret_size);
} else {
+ if (s->tlsext_use_etm)
+ s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE;
+ else
+ s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE;
+
if (s->s3->tmp.new_cipher->algorithm2 & TLS1_STREAM_MAC)
s->mac_flags |= SSL_MAC_FLAG_WRITE_MAC_STREAM;
else
@@ -367,9 +377,8 @@ int tls1_setup_key_block(SSL *s)
if (s->s3->tmp.key_block_length != 0)
return (1);
- if (!ssl_cipher_get_evp
- (s->session, &c, &hash, &mac_type, &mac_secret_size, &comp,
- SSL_USE_ETM(s))) {
+ if (!ssl_cipher_get_evp(s->session, &c, &hash, &mac_type, &mac_secret_size,
+ &comp, s->tlsext_use_etm)) {
SSLerr(SSL_F_TLS1_SETUP_KEY_BLOCK, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
return (0);
}
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index b51d60a7cc..b2688f6552 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1674,7 +1674,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
#endif
if (!custom_ext_add(s, 1, &ret, limit, al))
return NULL;
- if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) {
+ if (s->tlsext_use_etm) {
/*
* Don't use encrypt_then_mac if AEAD or RC4 might want to disable
* for other cases too.
@@ -1683,7 +1683,7 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf,
|| s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
|| s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
|| s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12)
- s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
+ s->tlsext_use_etm = 0;
else {
/*-
* check for enough space.
@@ -1916,7 +1916,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al)
/* Clear any signature algorithms extension received */
OPENSSL_free(s->s3->tmp.peer_sigalgs);
s->s3->tmp.peer_sigalgs = NULL;
- s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
+ s->tlsext_use_etm = 0;
#ifndef OPENSSL_NO_SRP
OPENSSL_free(s->srp_ctx.login);
@@ -2264,7 +2264,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, PACKET *pkt, int *al)
}
#endif
else if (type == TLSEXT_TYPE_encrypt_then_mac)
- s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
+ s->tlsext_use_etm = 1;
/*
* Note: extended master secret extension handled in
* tls_check_serverhello_tlsext_early()
@@ -2366,7 +2366,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
SSL_DTLSEXT_HB_DONT_SEND_REQUESTS);
#endif
- s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
+ s->tlsext_use_etm = 0;
s->s3->flags &= ~TLS1_FLAGS_RECEIVED_EXTMS;
@@ -2585,7 +2585,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, PACKET *pkt, int *al)
/* Ignore if inappropriate ciphersuite */
if (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;
+ s->tlsext_use_etm = 1;
} else if (type == TLSEXT_TYPE_extended_master_secret) {
s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
if (!s->hit)