When adding a custom extension to a certificate using mbedtls, setting the critical flag to 1 results in the following error: -0x2562: X509 - The extension tag or value is invalid : ASN1 - ASN1 tag was of an unexpected value

Describe the issue

When adding a custom extension to a certificate using mbedtls, setting the critical flag to 1 results in the following error:
-0x2562: X509 - The extension tag or value is invalid : ASN1 - ASN1 tag was of an unexpected value

Steps to Reproduce

  1. Attempt to add a custom extension to a certificate using mbedtls.
  2. Set the critical flag to 1.
  3. Encounter the error during certificate generation.

Example Code

#include "mbedtls/build_info.h"

#include "mbedtls/platform.h"

#include "mbedtls/x509_csr.h"
#include "mbedtls/pk.h"
#include "mbedtls/oid.h"
#include "mbedtls/ecp.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/x509_crt.h"
#include "mbedtls/ecdh.h"
#include <mbedtls/base64.h>

int nfi_generate_ecc_key_pair(mbedtls_pk_context *key) {
    int ret;
    mbedtls_entropy_context entropy; 
    mbedtls_ctr_drbg_context ctr_drbg; 

  
    const char *pers = "";

   
    mbedtls_pk_init(key);

    mbedtls_entropy_init(&entropy);


    mbedtls_ctr_drbg_init(&ctr_drbg);

    if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0) 
    {
        mbedtls_entropy_free(&entropy); 
        return ret;
    }

    if ((ret = mbedtls_pk_setup(key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY))) != 0) 
    {
        
        mbedtls_ctr_drbg_free(&ctr_drbg); 
        mbedtls_entropy_free(&entropy); 
        return ret;
    }
    if ((ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*key), mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
        
        mbedtls_pk_free(key); 
        mbedtls_ctr_drbg_free(&ctr_drbg); 
        mbedtls_entropy_free(&entropy); 
        return ret;
    }

    mbedtls_entropy_free(&entropy);
    mbedtls_ctr_drbg_free(&ctr_drbg);
    printf("Generating ECC key pair ok\n");
    return 0;
}

void nfi_set_certificate_validity(mbedtls_x509write_cert *crt_writer, int valid_days) {
    int ret;
    time_t now;
    struct tm *tm_info;
    char not_before[15];
    char not_after[15];

    now = time(NULL);
    tm_info = gmtime(&now);  


    strftime(not_before, sizeof(not_before), "%Y%m%d%H%M%S", tm_info);


    tm_info->tm_mday += valid_days;
    mktime(tm_info);  

    strftime(not_after, sizeof(not_after), "%Y%m%d%H%M%S", tm_info);


    ret = mbedtls_x509write_crt_set_validity(crt_writer, not_before, not_after);
    if (ret != 0) {
        printf("Failed to set certificate validity: -0x%x\n", -ret);
    } else {
        printf("Certificate validity set from %s to %s\n", not_before, not_after);
    }
}

void add_extension(mbedtls_x509write_cert *crt, const char *oid, const char *value, int critical) {
    int ret;
    
    unsigned char buf[128];
    unsigned char *p = buf + sizeof(buf);
    ret = mbedtls_asn1_write_octet_string(&p, buf, value, strlen(value));
    if (ret <= 0) 
    {
        printf("Failed to add mbedtls_asn1_write_octet_string: -0x%x\n", -ret);
    }

    int ext_valueLen = ret;

    mbedtls_asn1_buf oidASN;
    ret = mbedtls_oid_from_numeric_string(&oidASN, oid, strlen(oid));
    if (ret != 0) {
        printf("Failed to mbedtls_oid_from_numeric_string: -0x%x\n", -ret);
    }

    ret = mbedtls_x509write_crt_set_extension(crt, oidASN.p, oidASN.len, critical,p,ext_valueLen);
    if (ret != 0) {
        printf("Failed to add extension: -0x%x\n", -ret);
    }
    else
    {
        printf("add extension OK1\n");
    }
}

int  with_out(void *p_ctx,
              mbedtls_x509_crt const *crt,
              mbedtls_x509_buf const *oid,
              int critical,
              const unsigned char *p,
              const unsigned char *end)
{
  return 0;
}

int main()
{
  mbedtls_x509_crt crt;
  mbedtls_pk_context key;

  nfi_generate_ecc_key_pair(&key);
  int ret;
  mbedtls_mpi serial;
  mbedtls_x509write_cert crt_writer;
  mbedtls_entropy_context entropy;
  mbedtls_ctr_drbg_context ctr_drbg;
  const char *pers = "crt_gen";
  uint8_t *subject_namem = "CN=TestCN";

  mbedtls_x509write_crt_init(&crt_writer);
  mbedtls_mpi_init(&serial);
  mbedtls_x509_crt_init(&crt);

  mbedtls_entropy_init(&entropy);
  mbedtls_ctr_drbg_init(&ctr_drbg);

  if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0) {
      return ret;
  }

  if ((ret = mbedtls_mpi_read_string(&serial, 10, "1")) != 0) {
      return ret;
  }

  mbedtls_x509write_crt_set_serial(&crt_writer, &serial);
  nfi_set_certificate_validity(&crt_writer,365);
  mbedtls_x509write_crt_set_subject_key(&crt_writer, &key);
  mbedtls_x509write_crt_set_issuer_key(&crt_writer, &key);
  mbedtls_x509write_crt_set_md_alg(&crt_writer, MBEDTLS_MD_SHA256);
  
  if ((ret = mbedtls_x509write_crt_set_subject_name(&crt_writer, subject_namem)) != 0) {
      return ret;
  }

  if ((ret = mbedtls_x509write_crt_set_issuer_name(&crt_writer, subject_namem)) != 0) {
      return ret;
  }
  
  mbedtls_x509write_crt_set_basic_constraints(&crt_writer, 1, 0);
  mbedtls_x509write_crt_set_key_usage(&crt_writer, MBEDTLS_X509_KU_DIGITAL_SIGNATURE |
                                                  MBEDTLS_X509_KU_NON_REPUDIATION   |
                                                  MBEDTLS_X509_KU_KEY_ENCIPHERMENT  |
                                                  MBEDTLS_X509_KU_DATA_ENCIPHERMENT |
                                                  MBEDTLS_X509_KU_KEY_AGREEMENT     |
                                                  MBEDTLS_X509_KU_KEY_CERT_SIGN     |
                                                  MBEDTLS_X509_KU_CRL_SIGN          |
                                                  MBEDTLS_X509_KU_ENCIPHER_ONLY     |
                                                  MBEDTLS_X509_KU_DECIPHER_ONLY     );

  add_extension(&crt_writer,"1.3.2.5.444.2.1","0123",1);

  unsigned char output_buf[4096];
  memset(output_buf, 0, sizeof(output_buf));
  ret = mbedtls_x509write_crt_pem(&crt_writer, output_buf, sizeof(output_buf), mbedtls_ctr_drbg_random, &ctr_drbg);
  if (ret < 0) {
      return ret;
  }

  ret = mbedtls_x509_crt_parse(&crt, output_buf, sizeof(output_buf));
  if (ret < 0) {
      return ret;
  }

  memset(output_buf, 0, sizeof(output_buf));
  ret = mbedtls_x509write_crt_der(&crt_writer,output_buf, sizeof(output_buf), mbedtls_ctr_drbg_random, &ctr_drbg);

  printf("der Len [%d]\n",ret);
  for (size_t i = 0; i < ret; i++)
  {
    printf("%02x", output_buf[sizeof(output_buf) - ret + i]);
  }
  printf("\n");

  mbedtls_mpi_free(&serial);
  mbedtls_x509write_crt_free(&crt_writer);
  mbedtls_entropy_free(&entropy);
  mbedtls_ctr_drbg_free(&ctr_drbg);

  return 0;
}