openssl / openssl

TLS/SSL and crypto library

Home Page:https://www.openssl.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

OpenSSL 1.1.1 AES key wrap ciphers use-after-free

guidovranken opened this issue · comments

https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=23014

This OSS-Fuzz bug triggered only in LibreSSL, not OpenSSL, because OpenSSL master branch is not affected, but the 1.1.1 branch is.

This is a different bug than #12014

Compile the following poc against the OpenSSL_1_1_1 branch.

#include <openssl/evp.h>

#define CF_CHECK_EQ(expr, res) if ( (expr) != (res) ) { goto end; }
#define CF_CHECK_GTE(expr, res) if ( (expr) < (res) ) { goto end; }
int main(void)
{
const unsigned char key[16] = { 0 };
const unsigned char iv[8] = { 0 };
unsigned char cleartext[16] = { 0 };
unsigned char out[1024];
int len = -1;
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX* ctx2 = NULL;
const EVP_CIPHER* cipher = EVP_aes_128_wrap();
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);

CF_CHECK_EQ(EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL), 1);

CF_CHECK_EQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv), 1);

/* Duplicate the ctx */
ctx2 = EVP_CIPHER_CTX_new();
CF_CHECK_EQ(EVP_CIPHER_CTX_copy(ctx2, ctx), 1);
EVP_CIPHER_CTX_free(ctx);
ctx = ctx2;


/* "the amount of data written may be anything from zero bytes to (inl + cipher_block_size - 1)" */
CF_CHECK_GTE(sizeof(out), sizeof(cleartext) + EVP_CIPHER_block_size(cipher) - 1);
CF_CHECK_EQ(EVP_EncryptUpdate(ctx, out, &len, cleartext, sizeof(cleartext)), 1);
end:
return 0;
}

This is the LibreSSL fix for this bug: openbsd/src@f72711c

A similar iv pointer is in the ocb cipher:

#include <openssl/evp.h>

#define CF_CHECK_EQ(expr, res) if ( (expr) != (res) ) { goto end; }
#define CF_CHECK_GTE(expr, res) if ( (expr) < (res) ) { goto end; }
int main(void)
{
const unsigned char key[16] = { 0 };
const unsigned char iv[16] = { 0 };
unsigned char cleartext[16] = { 0 };
unsigned char out[1024];
int len = -1;
EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX* ctx2 = NULL;
const EVP_CIPHER* cipher = EVP_aes_128_ocb ();
OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);

CF_CHECK_EQ(EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL), 1);

/* Duplicate the ctx */
ctx2 = EVP_CIPHER_CTX_new();
CF_CHECK_EQ(EVP_CIPHER_CTX_copy(ctx2, ctx), 1);
EVP_CIPHER_CTX_free(ctx);
ctx = ctx2;

CF_CHECK_EQ(EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv), 1);
CF_CHECK_EQ(EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL), 1);

/* "the amount of data written may be anything from zero bytes to (inl + cipher_block_size - 1)" */
CF_CHECK_GTE(sizeof(out), sizeof(cleartext) + EVP_CIPHER_block_size(cipher) - 1);
CF_CHECK_EQ(EVP_EncryptUpdate(ctx, out, &len, cleartext, sizeof(cleartext)), 1);
end:
return 0;
}