Main Content

Missing private key

Context used for cryptography operation is associated with NULL private key or not associated with a private key at all

Description

This defect occurs when you use a context object for decryption, signature, or shared secret derivation but you have not previously associated the object with a non-NULL private key.

For instance, you initialize the context object with a NULL private key and use the object for decryption later.

ctx = EVP_PKEY_CTX_new(pkey, NULL);
...
ret = EVP_PKEY_decrypt_init(ctx);
...
ret = EVP_PKEY_decrypt(ctx, out, &out_len, in, in_len);

The counterpart checker Missing public key checks for a public key in encryption and authentication operations. The checker Missing peer key checks for a peer key in shared secret derivation.

Risk

Without a private key, the decryption, signature, or shared secret derivation step does not occur. The redundant operation often indicates a coding error.

Fix

Check the placement of the operation (decryption, signature, or shared secret derivation). If the operation is intended, make sure you have completed these steps prior to the operation:

  • Generate a non-NULL private key.

    For instance:

    EVP_PKEY *pkey = NULL;
    kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
    
    EVP_PKEY_keygen_init(kctx);
    EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, RSA_2048BITS);
    EVP_PKEY_keygen(kctx, &pkey);

  • Associate a non-NULL context object with the private key.

    For instance:

    ctx = EVP_PKEY_CTX_new(pkey, NULL);
    

    Note: If you use EVP_PKEY_CTX_new_id instead of EVP_PKEY_CTX_new, you are not associating the context object with a private key.

Examples

expand all

#include <stddef.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(unsigned char *src, size_t len){
  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_decrypt_init(ctx);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_decrypt(ctx, out_buf, &out_len, src, len); 
}

In this example, the context object ctx is initialized with EVP_PKEY_CTX_new_id instead of EVP_PKEY_CTX_new. The function EVP_PKEY_CTX_new_id does not associate the context object with a key. However, the EVP_PKEY_decrypt function uses this object for decryption.

Correction — Associate Private Key with Context During Initialization

One possible correction is to use the EVP_PKEY_CTX_new function for context initialization and associate a private key with the context object. In the following correction, the private key pkey is obtained from an external source and checked for NULL before use.

#include <stddef.h>
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
size_t out_len;

int func(unsigned char *src, size_t len, EVP_PKEY *pkey){
  if (pkey == NULL) fatal_error(); 
  
  EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
  if (ctx == NULL) fatal_error();

  ret = EVP_PKEY_decrypt_init(ctx);
  if (ret <= 0) fatal_error();
  return EVP_PKEY_decrypt(ctx, out_buf, &out_len, src, len); 
}

Result Information

Group: Cryptography
Language: C | C++
Default: Off
Command-Line Syntax: CRYPTO_PKEY_NO_PRIVATE_KEY
Impact: Medium

Version History

Introduced in R2018a