Program stops execution on the mbedtls_x509_crt_verify() call

I’m using mbedTLS to verify previously generated certificates:

  1. Self signed root certificate
  2. Intermediate certificate signed by the root certificate
  3. Device certificate signed by the intermediate certificate

Certificates are generated using OpenSSL:

Root cert:

openssl ecparam -genkey -name prime256v1 -out %ROOT_CA_DIR%\root_private.key
openssl req -new -x509 -SHA256 -days 3650 -key %ROOT_CA_DIR%\root_private.key -nodes -out %ROOT_CA_DIR%\root_cert.pem -subj "/C=US/O=Wcompany/OU=ATDE/CN=ROOT-CN"
openssl x509 -in %ROOT_CA_DIR%\root_cert.pem -out %ROOT_CA_DIR%\root_cert.der -outform DER

Intermediate cert:

openssl ecparam -genkey -name prime256v1 -out %CHAIN_DIR%\ica_private.key
openssl req -new -SHA256 -key %CHAIN_DIR%\ica_private.key -nodes -out %CHAIN_DIR%\ica_sign_req.csr -subj "/C=US/O=Wcompany/OU=SubComp/CN=INTERIM-CN"
openssl x509 -req -SHA256 -extfile v3_intermediate_ca.ext -days 365 -in %CHAIN_DIR%\ica_sign_req.csr -CA %ROOT_CA_DIR%\root_cert.pem -CAkey %ROOT_CA_DIR%\root_private.key -CAcreateserial -out %CHAIN_DIR%\ica_cert.pem
openssl x509 -in %CHAIN_DIR%\ica_cert.pem -out %CHAIN_DIR%\ica_cert.der -outform DER

Device cert:

openssl ecparam -genkey -name prime256v1 -out %CHAIN_DIR%\device_private.key
openssl req -new -SHA256 -key %CHAIN_DIR%\device_private.key -nodes -out %CHAIN_DIR%\device_sign_req.csr -subj "/C=US/O=Wcompany/OU=SubComp/CN=MyDevice"
openssl x509 -req -SHA256 -days 365 -in %CHAIN_DIR%\device_sign_req.csr -CA %CHAIN_DIR%\ica_cert.pem -CAkey %CHAIN_DIR%\ica_private.key -CAcreateserial -out %CHAIN_DIR%\device_cert.pem
openssl x509 -in %CHAIN_DIR%\device_cert.pem -out %CHAIN_DIR%\device_cert.der -outform DER
openssl ec -in %CHAIN_DIR%\device_private.key -outform DER -out %CHAIN_DIR%\device_private.der

Afterwards, raw data in the .der files is converted to char array using python:

import binascii

files_list = list()
files_list.append(("root_cert.der", "root_array"))
files_list.append(("ica_cert.der", "ica_array"))
files_list.append(("device_cert.der", "device_array"))

main_h = "certificates.h"

for input_file, output_name in files_list:
    with open(input_file, "rb") as file:
        der_bytes = file.read()
        hex_string = binascii.hexlify(der_bytes).decode("utf-8")

    with open(main_h, "a") as file:
        file.write(f"const unsigned char {output_name}[] = {{\n")
        for i in range(0, len(hex_string), 2):
            file.write(f"0x{hex_string[i:i+2]}, ")
            if i % 32 == 30:
                file.write("\n")
        file.write(f"\n}};\n\n")

Next, I’ve copied the “const unsigned char root_cert” and “const unsigned char ica_cert” from the “certificates.h” and created the following code:

#include <stdint.h>
#include <stdlib.h>
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/rsa.h"
#include "mbedtls/entropy.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/x509_csr.h"
#include "mbedtls/error.h"
#include "mbedtls/platform_util.h"

const unsigned char root_cert[] = {0x30, ... 0xf7};
const unsigned char ica_cert[] = {0x30, ... 0x01};

extern void mbedtls_memory_buffer_alloc_init(unsigned char *buf, size_t len);
uint32_t flags = 0;
unsigned char local_buf[32*1024];

int main(void) {
  mbedtls_memory_buffer_alloc_init(local_buf, 32*1024);
  mbedtls_x509_crt root_cert_struct;
  mbedtls_x509_crt_init(&root_cert_struct);
  mbedtls_x509_crt ica_cert_struct;

  mbedtls_x509_crt_init(&ica_cert_struct);

  if (mbedtls_x509_crt_parse_der(&root_cert_struct, root_cert, sizeof(root_cert)) != 0) {
    mbedtls_x509_crt_free(&root_cert_struct);
    fail_blink(); }
  else { success_blink(); }

  if (mbedtls_x509_crt_parse_der(&ica_cert_struct, ica_cert, sizeof(ica_cert)) != 0) {
    mbedtls_x509_crt_free(&ica_cert_struct);
    fail_blink(); }
  else { success_blink(); }

  // Load the self-signed certificate into a certificate structure
  if (mbedtls_x509_crt_verify(&ica_cert_struct, &root_cert_struct, NULL, NULL, &flags, NULL, NULL) != 0) {
    mbedtls_x509_crt_free(&ica_cert_struct); 
    mbedtls_x509_crt_free(&root_cert_struct);
    fail_blink(); }
  else { success_blink(); }

  mbedtls_x509_crt_free(&ica_cert_struct); 
  mbedtls_x509_crt_free(&root_cert_struct);

  while (1) { // do something }
}

Also the medTLS_config.h file contains the following:

#define MBEDTLS_CONFIG_VERSION 0x03010000
#define MBEDTLS_PLATFORM_MEMORY
#define MBEDTLS_ECP_DP_SECP192R1_ENABLED
#define MBEDTLS_ECP_DP_SECP224R1_ENABLED
#define MBEDTLS_ECP_DP_SECP256R1_ENABLED
#define MBEDTLS_ECP_DP_SECP384R1_ENABLED
#define MBEDTLS_ECP_DP_SECP521R1_ENABLED
#define MBEDTLS_ECP_DP_SECP192K1_ENABLED
#define MBEDTLS_ECP_DP_SECP224K1_ENABLED
#define MBEDTLS_ECP_DP_SECP256K1_ENABLED
#define MBEDTLS_ECP_DP_BP256R1_ENABLED
#define MBEDTLS_ECP_DP_BP384R1_ENABLED
#define MBEDTLS_ECP_DP_BP512R1_ENABLED
#define MBEDTLS_ECP_DP_CURVE25519_ENABLED
#define MBEDTLS_ECP_DP_CURVE448_ENABLED
#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED
#define MBEDTLS_ERROR_STRERROR_DUMMY
#define MBEDTLS_NO_PLATFORM_ENTROPY
#define MBEDTLS_PKCS1_V21
#define MBEDTLS_PSA_CRYPTO_CONFIG
#define MBEDTLS_AES_C
#define MBEDTLS_ASN1_PARSE_C
#define MBEDTLS_BASE64_C
#define MBEDTLS_BIGNUM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ECDH_C
#define MBEDTLS_ECDSA_C
#define MBEDTLS_ECP_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_ERROR_C
#define MBEDTLS_HMAC_DRBG_C
#define MBEDTLS_MD_C
#define MBEDTLS_MD5_C
#define MBEDTLS_MEMORY_BUFFER_ALLOC_C
#define MBEDTLS_OID_C
#define MBEDTLS_PEM_PARSE_C
#define MBEDTLS_PK_C
#define MBEDTLS_PK_PARSE_C
#define MBEDTLS_PLATFORM_C
#define MBEDTLS_PSA_CRYPTO_C
#define MBEDTLS_RIPEMD160_C
#define MBEDTLS_RSA_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA384_C
#define MBEDTLS_SHA512_C
#define MBEDTLS_X509_USE_C
#define MBEDTLS_X509_CRT_PARSE_C
#define MBEDTLS_X509_CRL_PARSE_C
#define MBEDTLS_X509_CSR_PARSE_C

With this parsing of certificate data passes without issues. But:

  1. The issue I’m having is that when I use mbedtls_x509_crt_verify() with root_cert_struct for the first two arguments, everything is working fine.
  2. But if I set ica_cert_struct and root_cert_struct for the first two arguments respectively, the program execution stops on the mbedtls_x509_crt_verify() call. During debugging I’m finding that this function calls another function … and so on until the file “bignum.c” in function “mbedtls_mpi_grow()” line:
    if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ) ) == NULL )
    When I enter the mbedtls_calloc() it ends up in the file “memory_buffer_alloc.c”, function “buffer_alloc_calloc()” line:
    mbedtls_exit( 1 );

And program execution stops there, never continuing to another line.

Can someone help me with this? I don’t understand why it would stop executing at the exit function.

Sounds like maybe you ran out of heap memory?

I did not mention that I’m using STM32F407 MCU for this.
I thought that by using:

unsigned char local_buf[32*1024];
mbedtls_memory_buffer_alloc_init(local_buf, 32*1024);

that I can change the size of heap. But no matter to the size of this array, the behavior is the same.
Is there another way to influence the size of heap?

In my previous answer, the function used is for changing the calloc/free functions to use stack memory instead of heap memory. I did not understood the documentation correctly.

If I disable macro “MBEDTLS_MEMORY_BUFFER_ALLOC_C" and remove function and buffer from my previous answer, the calloc/free functions use the heap memory.

And yes, MultipleMonoials you are right. By default, IDE that I’m using uVision Keil sets the size of heap memory to 0xC00 in the “startup_stm32f407xx.s” project file, which is not enough for this program example. Once this is increased to value 0x8000, the given program example is working, but with 10 second slowdown on mbedtls_x509_crt_verify() function call. Program execution stops for around 10 seconds during this function execution (which is an issue for different topic on this forum).

As far as I’m concerned, this is solved. Thank you MultipleMonoials for hint.