Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to free/allocate the context in the OpenSSL

I'am using the Open SSL in my program, to encrypt and decrypt the data using aes ciphers. At the moment there is a little memory leak, so i'm looking for a way to fix that. In my encrypt decrypt routines, i have the contexts free like so

EVP_CIPHER_CTX_free(ctx);

And created by:

EVP_CIPHER_CTX_new

This was on the OpenSSL wiki page in the examples

But! On the MAN page, there is a suggestion for using EVP_CIPHER_CTX_cleanup and EVP_CIPHER_CTX_init functions. So basically what should be correct to use, is the EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_free is somehow deprecated? And is there any big difference between EVP_CIPHER_CTX_new/EVP_CIPHER_CTX_free and EVP_CIPHER_CTX_init / EVP_CIPHER_CTX_cleanup ?

if(!(ctx = EVP_CIPHER_CTX_new())) return -1;


  if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
  {
    EVP_CIPHER_CTX_free(ctx);
    return -1;
  }

  if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
  {
    EVP_CIPHER_CTX_free(ctx);
    return -1;
  }
  ciphertext_len = len;


  if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) { EVP_CIPHER_CTX_free(ctx); return -1; }
  ciphertext_len += len;


  EVP_CIPHER_CTX_free(ctx);
like image 442
Vanya Avatar asked Oct 13 '14 17:10

Vanya


2 Answers

First of all if you want a precise answer, you should always specify which version of OpenSSL you are using. FYI 1.0.2 is current Long Term Support version, while 1.1.0 is the newest (in Sept 2016).

If you read the 1.1.0 man pages you will notice:

EVP_CIPHER_CTX was made opaque in OpenSSL 1.1.0. As a result, EVP_CIPHER_CTX_reset() appeared and EVP_CIPHER_CTX_cleanup() disappeared. EVP_CIPHER_CTX_init() remains as an alias for EVP_CIPHER_CTX_reset().

Short answer is: you should use EVP_CIPHER_CTX_new to initialize and EVP_CIPHER_CTX_free do free the memory, regardless of the version, here's why.

Allocating:

1.0.2 man pages say:

EVP_CIPHER_CTX ctx;
EVP_CIPHER_CTX_init(&ctx);

and 1.1.0 man pages say:

EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();

If you look at the code of EVP_CIPHER_CTX_init in 1.0.2

void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx)
{
   memset(ctx, 0, sizeof(EVP_CIPHER_CTX));
   /* ctx->cipher=NULL; */
}

while EVP_CIPHER_CTX_new is:

EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void)
{
   EVP_CIPHER_CTX *ctx = OPENSSL_malloc(sizeof *ctx);
   if (ctx)
      EVP_CIPHER_CTX_init(ctx);
   return ctx;
}

so you you are still better off initializing the context, like in 1.1.0 example:

EVP_CIPHER_CTX *ctx;
ctx = EVP_CIPHER_CTX_new();

for 1.1.0 the same applies.

For freeing the memory:

1.0.2 man pages:

EVP_CIPHER_CTX_cleanup(&ctx);

1.1.0 man pages:

EVP_CIPHER_CTX_free(ctx);

But if you check the code you can see that for 1.0.2:

void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx)
{
   if (ctx) {
       EVP_CIPHER_CTX_cleanup(ctx);
      OPENSSL_free(ctx);
   }
}

So you should use EVP_CIPHER_CTX_free for deallocating. If you just want to reset the context for another operation then EVP_CIPHER_CTX_cleanup(1.0.2) and EVP_CIPHER_CTX_reset(1.1.0) are your friends.

If you are curious about malloc memset and calloc, here's a good explanation

like image 99
mwojtera Avatar answered Oct 21 '22 08:10

mwojtera


You should not use EVP_EncryptInit anymore. That function did automatically create a specific context, but it didn't support the crypto engines that were later added. EVP_EncryptInit_ex however explicitly states that:

ctx must be initialized before calling this function.

so you are required to use EVP_CIPHER_CTX_new here I suppose.

EVP_CIPHER_CTX_free is another matter, it seems to have been deprecated, I don't see any mention of it on the manual pages of OpenSSL. It is good practice (and required for NIST certified functionality) to delete key material and other state of a cipher after use. Otherwise an attacker may scan the memory or use an overflow at a later stage.

The name of EVP_CIPHER_CTX_free only indicates that the CTX memory should be released. But freeing of memory does not imply that it is scrubbed of sensitive information first; it's just returned to the system, which is under no obligation to overwrite it either. EVP_CIPHER_CTX_cleanup on the other hand does explicitly scrub such information before freeing the memory (or it does at least make a decent attempt to do so, I presume). So you need to call this function after you've supplied your key material.

like image 6
Maarten Bodewes Avatar answered Oct 21 '22 08:10

Maarten Bodewes