Skip to content

Commit

Permalink
Don't change the state of the ETM flags until CCS processing
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mattcaswell committed Feb 16, 2017
1 parent 9c5a691 commit 4ad9361
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 19 deletions.
5 changes: 4 additions & 1 deletion include/openssl/ssl3.h
Expand Up @@ -264,11 +264,14 @@ extern "C" {
# define TLS1_FLAGS_SKIP_CERT_VERIFY 0x0010

/* Set if we encrypt then mac instead of usual mac then encrypt */
# define TLS1_FLAGS_ENCRYPT_THEN_MAC 0x0100
# define TLS1_FLAGS_ENCRYPT_THEN_MAC_READ 0x0100
# define TLS1_FLAGS_ENCRYPT_THEN_MAC TLS1_FLAGS_ENCRYPT_THEN_MAC_READ

/* Set if extended master secret extension received from peer */
# define TLS1_FLAGS_RECEIVED_EXTMS 0x0200

# define TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE 0x0400

# define SSL3_MT_HELLO_REQUEST 0
# define SSL3_MT_CLIENT_HELLO 1
# define SSL3_MT_SERVER_HELLO 2
Expand Down
6 changes: 3 additions & 3 deletions ssl/record/rec_layer_s3.c
Expand Up @@ -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];
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions ssl/record/ssl3_record.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
/*
Expand All @@ -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)) {
Expand Down
7 changes: 6 additions & 1 deletion ssl/ssl_locl.h
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 12 additions & 3 deletions ssl/t1_enc.c
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
}
Expand Down
12 changes: 6 additions & 6 deletions ssl/t1_lib.c
Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 4ad9361

Please sign in to comment.