Commit a4aea443 authored by Bernd Edlinger's avatar Bernd Edlinger Committed by Richard Levitte
Browse files

Fix the crash due to inconsistent enc_write_ctx


- add error handling in ssl3_generate_key_block and ssl3_change_cipher_state

Fixes #2114

Reviewed-by: default avatarRich Salz <rsalz@openssl.org>
Reviewed-by: default avatarRichard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2137)
parent dbdb9661
Loading
Loading
Loading
Loading
+45 −30
Original line number Diff line number Diff line
@@ -177,32 +177,34 @@ static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num)
    EVP_MD_CTX_init(&s1);
    for (i = 0; (int)i < num; i += MD5_DIGEST_LENGTH) {
        k++;
        if (k > sizeof buf) {
        if (k > sizeof(buf))
            /* bug: 'buf' is too small for this ciphersuite */
            SSLerr(SSL_F_SSL3_GENERATE_KEY_BLOCK, ERR_R_INTERNAL_ERROR);
            return 0;
        }
            goto err;

        for (j = 0; j < k; j++)
            buf[j] = c;
        c++;
        EVP_DigestInit_ex(&s1, EVP_sha1(), NULL);
        EVP_DigestUpdate(&s1, buf, k);
        EVP_DigestUpdate(&s1, s->session->master_key,
                         s->session->master_key_length);
        EVP_DigestUpdate(&s1, s->s3->server_random, SSL3_RANDOM_SIZE);
        EVP_DigestUpdate(&s1, s->s3->client_random, SSL3_RANDOM_SIZE);
        EVP_DigestFinal_ex(&s1, smd, NULL);

        EVP_DigestInit_ex(&m5, EVP_md5(), NULL);
        EVP_DigestUpdate(&m5, s->session->master_key,
                         s->session->master_key_length);
        EVP_DigestUpdate(&m5, smd, SHA_DIGEST_LENGTH);
        if (!EVP_DigestInit_ex(&s1, EVP_sha1(), NULL) ||
            !EVP_DigestUpdate(&s1, buf, k) ||
            !EVP_DigestUpdate(&s1, s->session->master_key,
                              s->session->master_key_length) ||
            !EVP_DigestUpdate(&s1, s->s3->server_random, SSL3_RANDOM_SIZE) ||
            !EVP_DigestUpdate(&s1, s->s3->client_random, SSL3_RANDOM_SIZE) ||
            !EVP_DigestFinal_ex(&s1, smd, NULL))
            goto err2;

        if (!EVP_DigestInit_ex(&m5, EVP_md5(), NULL) ||
            !EVP_DigestUpdate(&m5, s->session->master_key,
                              s->session->master_key_length) ||
            !EVP_DigestUpdate(&m5, smd, SHA_DIGEST_LENGTH))
            goto err2;
        if ((int)(i + MD5_DIGEST_LENGTH) > num) {
            EVP_DigestFinal_ex(&m5, smd, NULL);
            if (!EVP_DigestFinal_ex(&m5, smd, NULL))
                goto err2;
            memcpy(km, smd, (num - i));
        } else
            EVP_DigestFinal_ex(&m5, km, NULL);
            if (!EVP_DigestFinal_ex(&m5, km, NULL))
                goto err2;

        km += MD5_DIGEST_LENGTH;
    }
@@ -210,6 +212,12 @@ static int ssl3_generate_key_block(SSL *s, unsigned char *km, int num)
    EVP_MD_CTX_cleanup(&m5);
    EVP_MD_CTX_cleanup(&s1);
    return 1;
 err:
    SSLerr(SSL_F_SSL3_GENERATE_KEY_BLOCK, ERR_R_INTERNAL_ERROR);
 err2:
    EVP_MD_CTX_cleanup(&m5);
    EVP_MD_CTX_cleanup(&s1);
    return 0;
}

int ssl3_change_cipher_state(SSL *s, int which)
@@ -360,25 +368,33 @@ int ssl3_change_cipher_state(SSL *s, int which)
         * In here I set both the read and write key/iv to the same value
         * since only the correct one will be used :-).
         */
        EVP_DigestInit_ex(&md, EVP_md5(), NULL);
        EVP_DigestUpdate(&md, key, j);
        EVP_DigestUpdate(&md, er1, SSL3_RANDOM_SIZE);
        EVP_DigestUpdate(&md, er2, SSL3_RANDOM_SIZE);
        EVP_DigestFinal_ex(&md, &(exp_key[0]), NULL);
        if (!EVP_DigestInit_ex(&md, EVP_md5(), NULL) ||
            !EVP_DigestUpdate(&md, key, j) ||
            !EVP_DigestUpdate(&md, er1, SSL3_RANDOM_SIZE) ||
            !EVP_DigestUpdate(&md, er2, SSL3_RANDOM_SIZE) ||
            !EVP_DigestFinal_ex(&md, &(exp_key[0]), NULL)) {
            EVP_MD_CTX_cleanup(&md);
            goto err2;
        }
        key = &(exp_key[0]);

        if (k > 0) {
            EVP_DigestInit_ex(&md, EVP_md5(), NULL);
            EVP_DigestUpdate(&md, er1, SSL3_RANDOM_SIZE);
            EVP_DigestUpdate(&md, er2, SSL3_RANDOM_SIZE);
            EVP_DigestFinal_ex(&md, &(exp_iv[0]), NULL);
            if (!EVP_DigestInit_ex(&md, EVP_md5(), NULL) ||
                !EVP_DigestUpdate(&md, er1, SSL3_RANDOM_SIZE) ||
                !EVP_DigestUpdate(&md, er2, SSL3_RANDOM_SIZE) ||
                !EVP_DigestFinal_ex(&md, &(exp_iv[0]), NULL)) {
                EVP_MD_CTX_cleanup(&md);
                goto err2;
            }
            iv = &(exp_iv[0]);
        }
    }
    EVP_MD_CTX_cleanup(&md);

    s->session->key_arg_length = 0;

    EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE));
    if (!EVP_CipherInit_ex(dd, c, NULL, key, iv, (which & SSL3_CC_WRITE)))
        goto err2;

#ifdef OPENSSL_SSL_TRACE_CRYPTO
    if (s->msg_callback) {
@@ -399,7 +415,6 @@ int ssl3_change_cipher_state(SSL *s, int which)

    OPENSSL_cleanse(&(exp_key[0]), sizeof(exp_key));
    OPENSSL_cleanse(&(exp_iv[0]), sizeof(exp_iv));
    EVP_MD_CTX_cleanup(&md);
    return (1);
 err:
    SSLerr(SSL_F_SSL3_CHANGE_CIPHER_STATE, ERR_R_MALLOC_FAILURE);
@@ -903,7 +918,7 @@ int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
                        s, s->msg_callback_arg);
    }
#endif
    OPENSSL_cleanse(buf, sizeof buf);
    OPENSSL_cleanse(buf, sizeof(buf));
    return (ret);
}