Main Content

CWE Rule 353

Missing Support for Integrity Check

Since R2023a

Description

Rule Description

The software uses a transmission protocol that does not include a mechanism for verifying the integrity of the data during transmission, such as a checksum.

Polyspace Implementation

The rule checker checks for these issues:

  • Context initialized incorrectly for digest operation

  • Nonsecure hash algorithm

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();
}
Issue

This issue occurs when you use a cryptographic hash function that is proven to be weak against certain forms of attack.

The hash functions flagged by this checker include SHA-0, SHA-1, MD4, MD5, and RIPEMD-160. The checker detects the use of these hash functions in:

  • Functions from the EVP API such as EVP_DigestUpdate or EVP_SignUpdate.

  • Functions from the low level API such as SHA1_Update or MD5_Update.

Risk

You use a hash function to create a message digest from input data and thereby ensure integrity of your data. The hash functions flagged by this checker use algorithms with known weaknesses that an attacker can exploit. The attacks can comprise the integrity of your data.

Fix

Use a more secure hash function. For instance, use the later SHA functions such as SHA-224, SHA-256, SHA-384, and SHA-512.

Example — Use of MD5 Algorithm
#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
unsigned int out_len;

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

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

  ret = EVP_DigestUpdate(ctx,src,len);  //Noncompliant

  if (ret != 1) fatal_error();

  ret = EVP_SignFinal(ctx, out_buf, &out_len, pkey);
  if (ret != 1) fatal_error();
}

In this example, during initialization with EVP_SignInit_ex, the context object is associated with the weak hash function MD5. The checker flags the usage of this context in the update step with EVP_DigestUpdate.

Correction — Use SHA-2 Family Function

One possible correction is to use a hash function from the SHA-2 family, such as SHA-256.

#include <openssl/evp.h>

#define fatal_error() exit(-1)

int ret;
unsigned char *out_buf;
unsigned int out_len;

void func(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_buf, &out_len, pkey);
  if (ret != 1) fatal_error();
}

Check Information

Category: Data Integrity Issues

Version History

Introduced in R2023a