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;
}