Parsing a private key only throws an error if trying to decrypt, but not by itself

Hi all,

I’m new mbedtls and these forums, so I apologize if this is the wrong place for this!!

I’m trying to parse a 3072 bit rsa private key on an esp32 with the following code.

  int ret = 0;
  size_t olen = 0;
  char buff[128];
  
  unsigned char result[MBEDTLS_MPI_MAX_SIZE];
  unsigned int challenge_bin;
  const char *pers = "mbedtls_pk_decrypt";

  mbedtls_ssl_context ssl;
  mbedtls_pk_context pk;
  mbedtls_entropy_context entropy;
  mbedtls_ctr_drbg_context ctr_drbg;
  mbedtls_ssl_config conf;

  mbedtls_ssl_init( &ssl );
  mbedtls_ssl_config_init( &conf );
  mbedtls_entropy_init(&entropy);
  mbedtls_pk_init(&pk);
  mbedtls_ctr_drbg_init( &ctr_drbg );

  memset(result, 0, sizeof(result));

  extern const unsigned char prvtkey_pem_start[] asm("_binary_key5fdbe1ce8e_pem_start");
  extern const unsigned char prvtkey_pem_end[]   asm("_binary_key5fdbe1ce8e_pem_end");
  const unsigned int prvtkey_pem_bytes = prvtkey_pem_end - prvtkey_pem_start;


  /*
   *  Parse Challenge Token
   */

  cJSON * json = cJSON_Parse(challenge);
  char * encrypted_token = cJSON_GetObjectItem(json, "challenge_token")->valuestring;
  printf("%s\n", encrypted_token);
  cJSON_Delete(json);

  //challenge_bin = htoi(encrypted_token);

  /*
   * Read the RSA privatekey
   */

  printf("\nSeeding the random number generator..." );

  ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
                  (const unsigned char*)pers, strlen(pers));

  if( ret != 0 ) {
    char buff[128];
    getTlsError(ret,buff,sizeof(buff));
    fprintf(stderr, "\nSeeding random number has failed, error=0x%04x, msg=%s", ret, buff);
  }

  char buffer[prvtkey_pem_bytes + 1];
  memcpy(buffer, prvtkey_pem_start, prvtkey_pem_bytes);
  buffer[prvtkey_pem_bytes + 1] = '\0';

  printf("\n%s\n", buffer);

  ret =  mbedtls_pk_parse_key(&pk, (const unsigned char *) buffer, (prvtkey_pem_bytes + 1), NULL, 0 );

  if( ret != 0 ) {
    getTlsError(ret,buff,sizeof(buff));
    fprintf(stderr, "\nPrivate key parsing has failed, error=0x%04x, msg=%s", ret, buff);
  }

By itself, I get no error codes and everything seems to be peachy. However, the moment I start to try and decrypt my challenge token, with this code.

  /*
   * Decrypt the token.
   */

  printf( "\nGenerating the encrypted value" );
  ret = mbedtls_pk_decrypt(&pk, (unsigned char *)encrypted_token, sizeof(encrypted_token), result, &olen, sizeof(result), mbedtls_ctr_drbg_random, &ctr_drbg);

  if( ret != 0 ) {
      getTlsError(ret, buff,sizeof(buff));
      fprintf(stderr, "\nPrivate key decryption has failed, error=0x%04x, msg=%s", ret, buff);
   }

   //printf("\nDecrypted Token: %s\n", result);
 }

Not only do i not get my decrypted result, I start getting errors with the parsing of the key…

Private key parsing has failed, error=0xffffc300, msg=PK - Invalid key tag or value

Any idea whats going on her? Am i doing anything blatantly wrong or misunderstanding something? It’s worth mentioning that i’ve changed MBEDTLS_MPI_MAX_SIZE to a suitably large default.

Any advice or thoughts are massively appreciated.

Spencer

Hi Spencer,
What is the suitable large size of MBEDTLS_MPI_MAX_SIZE that you have changed to?

What is the stack size of that you have in your platform? It is usually 4KB, unless modified.
I suspect you have a stack overflow or a buffer overflow causing your undefined behavior.

For 3072 bit key size, you will need MBEDTLS_MPI_MAX_SIZE to be at least 384, but to avoid stack overflow, you will need it to be as small as possible.
Do you know if the key is PKCS#1 or PKCS#8 format? More information on this can be found in this article.
Regards,
Mbed TLS Team member
Ron

Ron,

Super appreciate your response. Based on your info, I made MBEDTLS_MPI_MAX_SIZE 385 and made sure that my stack size was a healthy 10000kb.

The key is in PKCS#1 format which should be valid according to my understanding.

Am I correct in adding in a null terminator and length to my key for parsing?

char buffer[prvtkey_pem_bytes + 1]; 
memcpy(buffer, prvtkey_pem_start, prvtkey_pem_bytes); buffer[prvtkey_pem_bytes + 1] = '\0'; 
printf("\n%s\n", buffer);

Anything wrong standout with how i’m decrypting either?

ret = mbedtls_pk_decrypt(&pk, (unsigned char *)encrypted_token, sizeof(encrypted_token), result, &olen, sizeof(result), mbedtls_ctr_drbg_random, &ctr_drbg);

Either way, not sure how i only get the key parse error when i try to decrypt and not by itself.

Any further advice is greatly appreciated, and thanks again for your help.

Spencer

Hi Spencer,

Am I correct in adding in a null terminator and length to my key for parsing?

As you can see in the function documentation:

For PEM, the buffer must contain a null-terminated string.

So assuming that your buffer isn’t already NULL terminated, you are correct.

Anything wrong standout with how i’m decrypting either?

I don’t see anything wrong in the function call.

Are you sure your device can handle a 10000Kb stack? There is a limit on how much stack \ heap a device can support.

Regards,
Ron

Hi Spencer,

Have you checked that your buffer buffer hasn’t changed after the call to mbedtls_pk_decrypt?

As for setting the last byte to \0, shouldn’t is be:

buffer[prvtkey_pem_bytes ] = '\0';

without the +1 as this is outside the buffer of size prvtkey_pem_bytes +1?
Regards,
Ron