Main Content

No data added into context

Performing hash operation on empty context might cause run-time errors

Since R2020a

Description

The defect occurs when you only update a message digest context with null data, or you perform a final step on a message digest context without performing any update step.

When you use message digest functions, you typically initialize a message digest context and perform at least one update step to add data into the context. You then sign, verify, or retrieve the data in the context as a final step.

The checker raises no defect if no information is available about the context. For instance, if the context is passed as an argument to the function that calls the hashing operation or if the context is declared outside the scope of the function. For example, no defect is raised in this code snippet.

void bar(unsigned char* src, int len, EVP_MD_CTX *ctx) {
    //ctx passed as argument of bar()
    EVP_DigestFinal(ctx, out_buf, &out_len); //no defect
}
EVP_MD_CTX glob_ctx;
void foo(unsigned char* src, int len) {
    //glob_ctx declared outside scope of foo()
    EVP_DigestFinal(&glob_ctx, out_buf, &out_len); //no defect
}

Risk

Performing an update step on a context with null data might result in a run-time error.

Performing a final step on a context with no data might result in unexpected behavior.

Fix

Perform at least one update operation with non-null data on a message digest context before you sign, verify, or retrieve the data in the context.

Examples

expand all

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

unsigned char out_buf[EVP_MAX_MD_SIZE];
unsigned int out_len;

void func(unsigned char* src, int len)
{
    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);


    EVP_DigestInit(&ctx, EVP_sha256());
    EVP_DigestUpdate(&ctx, src, len);
    EVP_MD_CTX_init(&ctx);
    EVP_DigestFinal(&ctx, out_buf, &out_len);
}

In this example, the message digest context ctx is initialized and an update operation is performed to add data src into the context. The context is then reinitialized but no data is added to ctx before EVP_DigestFinal attempts to retrieve data from ctx, which results in an error.

Correction — Perform Final Step Before Reinitializing Context

One possible correction is to perform the final step that retrieves data from the context before you reinitialize the context.

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

unsigned char out_buf[EVP_MAX_MD_SIZE];
unsigned int out_len;

void func(unsigned char* src, int len)
{
    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);


    EVP_DigestInit(&ctx, EVP_sha256());
    EVP_DigestUpdate(&ctx, src, len);
    EVP_DigestFinal(&ctx, out_buf, &out_len);
    EVP_MD_CTX_init(&ctx);
} 
#include <openssl/evp.h>
#include <stdio.h>

unsigned char out_buf[EVP_MAX_MD_SIZE];
unsigned int out_len;

void func(unsigned char* src, int len)
{
    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);
    size_t cnt = 0;

    EVP_DigestInit(&ctx, EVP_sha256());
    EVP_DigestUpdate(&ctx, src, cnt);
    EVP_DigestFinal(&ctx, out_buf, &out_len);
}

In this example, zero bytes of data is hashed into the message digest context during the update operation. Retrieving data from the context in the final step results in unexpected behavior.

Correction — Add non-Null Data Into Context

A possible correction is to add data into the context during the update step before you retrieve data from the context.

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

unsigned char out_buf[EVP_MAX_MD_SIZE];
unsigned int out_len;

void func(unsigned char* src, int len)
{
    EVP_MD_CTX ctx;
    EVP_MD_CTX_init(&ctx);

    EVP_DigestInit(&ctx, EVP_sha256());
    EVP_DigestUpdate(&ctx, src, len);
    EVP_DigestFinal(&ctx, out_buf, &out_len);
}

Result Information

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

Version History

Introduced in R2020a