ECDSA verify problems

The configuration for my project is with config-suite-b.h with only a few modifications.
The application is running on a Silabs Giant Gecko and will utilize MbedTLS for AES-CCM, ECDSA and ECDH.

Currently, I am attempting to validate a ECDSA signed payload using mbedtls_ecdsa_verify(). The signing is done remotely, so my target only has the public cert and not the private key.

I’m confused on how to derive the Q from the x509 certificate. Look for the comment, “Some sorta magic here” in the code snippet below. There could be other problems.

      mbedtls_x509_crt crt;
      mbedtls_x509_crt_init(&crt);
      
      int mresult = mbedtls_x509_crt_parse_der(&crt, (const uint8_t*)&cert, ccr.CertLen);
      if (mresult != 0)
         print("x509 parse failed\n");
      
      mbedtls_ecdsa_context ctx;   // mbedtls_ecp_keypair
      mbedtls_ecdsa_init(&ctx);
      
      mresult = mbedtls_ecp_group_load(&ctx.grp, MBEDTLS_ECP_DP_SECP256R1);
      if (result != 0)
         print("group load fail %d\n", result);

      // load r and s from signature
      mbedtls_mpi r;
      mbedtls_mpi s;

      mbedtls_mpi_init( &r );
      mbedtls_mpi_init( &s );

      const uint8_t* sp = (const uint8_t*)signaturePtr;
      size_t sz = sizeof(Security_Signature512_t) / 2;

      mbedtls_mpi_read_binary(&r, sp, sz);
      mbedtls_mpi_read_binary(&s, sp + sz, sz);

      // Some sorta magic here, to derive Q from crt!
      // 
      // the following line doesn't work but may be close
      //mbedtls_ecp_point_read_binary(&ctx.grp, &ctx.Q, crt.pubkey, sizeof(crt.pubkey));
   
      mresult = mbedtls_ecdsa_verify(&ctx.grp, hash, sizeof(hash), &ctx.Q, &r, &s);
      if (mresult != 0)
         INFO("sig validation failed\n");

      return mresult;
   }

Thanks in advance!

1 Like

HI @dcorbin
Thank you for your query.

In order to get the public key from the certificate, I would first parse the certificate using mbedtls_x509_crt_parse(). The parsed certificate is stored as a mbedtls_x509_crt structure, which has a mbedtls_pk_context within.

This stucture can be used to verify yourhash using mbedtls_pk_verify().
I agree that it’s not good to access internal members of a struct, for ABI compatability, and for that we raised API to extract public key from parsed certificate · Issue #2294 · Mbed-TLS/mbedtls · GitHub, which already has an unmerged fix.
Regards,
Mbed TLS Support
Ron

Thanks, using mbedtls_pk_ec() allowed me to use mbedtls_ecdsa_verify() to verify signature of my message payload, looks like this:

      static mbedtls_x509_crt crt;
      mbedtls_x509_crt_init(&crt);

      int mresult = mbedtls_x509_crt_parse_der(&crt, (const uint8_t*)&Cert, CertLen);

      // load r and s from message signature
      . . .

      mresult = mbedtls_ecdsa_verify(&mbedtls_pk_ec(crt.pk)->grp, hash, sizeof(hash), &mbedtls_pk_ec(crt.pk)->Q, &r, &s);
      if (mresult == 0)
      {
         INFO("signature is valid\n");
      }
      else
      {
         INFO("signature failed\n");
      }

Yes, this should work, but I would recommend you use the mbedtls_pk_verify() for as much data abstraction as possible. ( For example, if you change certificate to an RSA certificate, with your solution requires additional change, while with the pk layer API, it is seemless, assuming RSA is configured in your product)
Regards

No go. This results in -20540 error (from mbedtls_pk_verify()).

      static mbedtls_x509_crt crt;
      mbedtls_x509_crt_init(&crt);

      int mresult = mbedtls_x509_crt_parse_der(&crt, (const uint8_t*)&cert, ccr.CertLen);
      
      mresult = mbedtls_pk_verify(&crt.pk, MBEDTLS_MD_SHA256, dataPtr, dataLen, (uint8_t*)signaturePtr, sizeof(Security_Signature512_t));

Strange, -20540 is not an error returned from Mbed TLS.
Why in your previous examples you used hash and hashlen and in this one you used data and datalen?
Note that mbedtls_pk_verify() also expects the hashed message.

It was a bad assumption that the mbedtls_pk_verify did the hash.

Anyway, I fixed that and still seeing the error. The error (MBEDTLS_ERR_ECP_BAD_INPUT_DATA) is coming from mbedtls_ecdsa_read_signature() which is called by mbedtls_pk_verify.

It looks like mbedtls_pk_verify() expects the signature to be asn1, the signature in my application is passed OTA as 512-bit binary.

Yes, mbedtls_ecdsa_read_signature() requires to have an ASN.1 signature, as given in TLS, unfortunately.
In this case, you should use mbedtls_ecdsa_verify() as you did earlier.
I apologize for confusion.

2 Likes

Hello @dcorbin, I know I’m late to the party, but could I ask you how to load r and s
from message signature?

UPDATE: sorry… I read the first comment too fast.