Commit 4ad93618 authored by Matt Caswell's avatar Matt Caswell
Browse files

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: default avatarRichard Levitte <levitte@openssl.org>
parent 9c5a691d
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -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
+3 −3
Original line number Diff line number Diff line
@@ -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;
+5 −5
Original line number Diff line number Diff line
@@ -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)) {
+6 −1
Original line number Diff line number Diff line
@@ -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
+12 −3
Original line number Diff line number Diff line
@@ -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);
    }
Loading