Main Content

CWE Rule 354

Improper Validation of Integrity Check Value

Since R2024a

Description

Rule Description

The product does not validate or incorrectly validates the integrity check values or "checksums" of a message. This may prevent it from detecting if the data has been modified or corrupted in transmission.

Polyspace Implementation

The rule checker checks for Context initialized incorrectly for digest operation.

Examples

expand all

Issue

This issue occurs when you initialize an EVP_MD_CTX context object for a specific digest operation but use the context for a different operation.

For instance, you initialize the context for creating a message digest only.

ret = EVP_DigestInit(ctx, EVP_sha256())
However, you perform a final step for signing:
ret = EVP_SignFinal(&ctx, out, &out_len, pkey);
The error is shown only if the final step is not consistent with the initialization of the context. If the intermediate update steps are inconsistent, it does not trigger an error because the intermediate steps do not depend on the nature of the operation. For instance, EVP_DigestUpdate works identically to EVP_SignUpdate.

Risk

Mixing up different operations on the same context can lead to obscure code. It is difficult to determine at a glance whether the current object is used for message digest creation, signing, or verification. The mixup can also lead to a failure in the operation or unexpected message digest.

Fix

After you set up a context for a certain family of operations, use the context for only that family of operations. For instance, use these pairs of functions for initialization and final steps.

  • EVP_DigestInit : EVP_DigestFinal

  • EVP_DigestInit_ex : EVP_DigestFinal_ex

  • EVP_DigestSignInit : EVP_DigestSignFinal

If you want to reuse an existing context object for a different family of operations, reinitialize the context.

Example — Inconsistent Initial and Final Digest Operation
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf16;
unsigned int out_len16;

void func(unsigned char *src, size_t len){
  EVP_MD_CTX* ctx = EVP_MD_CTX_create();

  ret = EVP_SignInit_ex(ctx, EVP_sha256(), NULL);
  if (ret != 1) fatal_error();

  ret = EVP_SignUpdate(ctx, src, len);
  if (ret != 1) fatal_error();

  ret = EVP_DigestSignFinal(ctx, out_buf16, (size_t*) out_len16); //Noncompliant

  if (ret != 1) fatal_error();
}

In this example, the context object is initialized for signing only with EVP_SignInit but the final step attempts to create a signed digest with EVP_DigestSignFinal.

Correction — Use One Family of Operations

One possible correction is to use the context object for signing only. Change the final step to EVP_SignFinal in keeping with the initialization step.

#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf16;
unsigned int out_len16;

void corrected_cryptomdbadfunction(unsigned char *src, size_t len, EVP_PKEY* pkey){
  EVP_MD_CTX* ctx = EVP_MD_CTX_create();

  ret = EVP_SignInit_ex(ctx, EVP_sha256(), NULL); 
  if (ret != 1) fatal_error();

  ret = EVP_SignUpdate(ctx, src, len);
  if (ret != 1) fatal_error();

  ret = EVP_SignFinal(ctx, out_buf16, &out_len16, pkey); 
  if (ret != 1) fatal_error();
}

Check Information

Category: Data Integrity Issues

Version History

Introduced in R2024a