There are two common formats for ECDSA signatures: “raw” and “ASN.1”.
Mathematically, an ECDSA signature consists of two numbers,
conventionally written (r, s). The raw format has r and s concatenated
with a fixed size, 32 bytes each, so the signature is always 64 bytes.
The ASN.1 format has extra metadata and strips leading zeros, which
means the signature can be up to 72 bytes but sometimes a little shorter.
mbedtls_ecdsa_read_signature() and mbedtls_pk_verify() only support the
ASN.1 format, which is the one used in X.509 and TLS. If you have a
signature in the raw format, you can either use the PSA API
(psa_import_key(), psa_verify_hash() on the raw-format signature,
psa_destroy_key()), or convert r and s to bignum objects and call
mbedtls_ecdsa_verify().
Hope this helps.
--
Gilles Peskine
Mbed TLS developer
On 04/03/2023 09:59, Tilen Majerle via mbed-tls wrote:
> Hello,
>
> I have 3rd party custom ECC library, that can do ECDSA verification and uses secp256r1 compressed public key (33bytes) to do so - all works fine.
>
> Now I want to migrate to mbedTLS, to also benefit of other crypto schemes, hence use of mbedtls ECDSA was a natural way to go.
> Here I need (as I understand) PEM parser or optionally public key in uncompressed format (0x04 | X | Y).
>
> Problem is that loading of the key seems to work (func returns 0), but verification fails with -20450, indicating (if I well understood) invalid signature.
>
> Test data.
> PRIVATE KEY:
> -----BEGIN PRIVATE KEY-----
> MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgKNqyWso/lMuTlTE6
> ll47Jboqq/Iz7OYDrr7TuXN+s2ChRANCAARNgfaUcxLoWWG01ekJFiqB8ujMgnHz
> P320ZgiZErH6zKjlB9EovIHrchj0240+EIpFios+2uM609FgRvu3+NrT
> -----END PRIVATE KEY-----
>
> PUBLIC KEY:
> -----BEGIN PUBLIC KEY-----
> MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgADTYH2lHMS6FlhtNXpCRYqgfLozIJx
> 8z99tGYImRKx+sw=
> -----END PUBLIC KEY-----
>
> PUBLIC KEY UNCOMPRESSED SEC1:
> 0x4,0x4d,0x81,0xf6,0x94,0x73,0x12,0xe8,0x59,0x61,0xb4,0xd5,0xe9,0x9,0x16,0x2a,0x81,0xf2,0xe8,0xcc,0x82,0x71,0xf3,0x3f,0x7d,0xb4,0x66,0x8,0x99,0x12,0xb1,0xfa,0xcc,0xa8,0xe5,0x7,0xd1,0x28,0xbc,0x81,0xeb,0x72,0x18,0xf4,0xdb,0x8d,0x3e,0x10,0x8a,0x45,0x8a,0x8b,0x3e,0xda,0xe3,0x3a,0xd3,0xd1,0x60,0x46,0xfb,0xb7,0xf8,0xda,0xd3
>
> PUBLIC KEY COMPRESSED SEC1:
> 0x3,0x4d,0x81,0xf6,0x94,0x73,0x12,0xe8,0x59,0x61,0xb4,0xd5,0xe9,0x9,0x16,0x2a,0x81,0xf2,0xe8,0xcc,0x82,0x71,0xf3,0x3f,0x7d,0xb4,0x66,0x8,0x99,0x12,0xb1,0xfa,0xcc
>
> INPUT STRING in TEXT format:
> "This is my input data" (remove quotes)
>
> INPUT STRING in HEX format:
> 0x54,0x68,0x69,0x73,0x20,0x69,0x73,0x20,0x6d,0x79,0x20,0x69,0x6e,0x70,0x75,0x74,0x20,0x64,0x61,0x74,0x61
>
> SHA256 of INPUT STRING:
> 0xa7,0x3f,0x26,0xf4,0xa1,0xe4,0x61,0x61,0x0,0x1a,0x29,0xdf,0xd2,0xaf,0x7d,0xa,0x25,0x91,0xbb,0xcc,0x1f,0xbc,0xfb,0xdb,0x43,0xdb,0x57,0xf9,0x8d,0x94,0xeb,0x81
> (x-checked here:
https://emn178.github.io/online-tools/sha256.html)
>
> SIGNATURE of HASH signed with PRIVATE KEY:
> 0x80,0xe6,0xf5,0x97,0x6a,0x66,0xa2,0xe2,0x9a,0xd7,0x7f,0x9a,0x9b,0x3e,0x2b,0xde,0x1f,0x7c,0x3,0xb3,0x1,0xb8,0x6f,0xd8,0xf6,0xf,0x27,0x38,0x63,0x3,0x54,0x74,0x76,0x6d,0x1b,0x97,0xf0,0xbc,0xc5,0xd2,0x4b,0xae,0xf0,0x34,0xab,0x86,0xbd,0x55,0x0,0x8a,0x4c,0x9f,0x4e,0xa5,0x53,0x89,0xe8,0x0,0xb9,0x83,0x24,0x87,0x98,0x1
>
> My custom library code looks like - this one works as expected:
> if (ecdsa_verify(public_key_compressed_33_bytes_array, hash_of_input_string, signature_signed_with_private_key)) {
> printf("Custom ECDSA lib verification is OK\r\n");
> }
>
> My mbedTLS code looks like:
> ```
> /* mbedTLS */
> printf("mbedTLS way start\r\n");
> mbedtls_ecdsa_init(&ctx);
> mbedtls_ecp_group_load(&ctx.private_grp, MBEDTLS_ECP_DP_SECP256R1);
> res = mbedtls_ecp_point_read_binary(&ctx.private_grp, &ctx.private_Q, ecc_public_key_uncompressed_bin,
> sizeof(ecc_public_key_uncompressed_bin));
> if (res != 0) {
> printf("ECP point read binary failed: %d\r\n", res);
> }
>
> res = mbedtls_ecdsa_read_signature(&ctx, data_raw_hash_digest, sizeof(data_raw_hash_digest), signature,
> sizeof(signature));
> if (res == 0) {
> printf("mbedTLS Verification is OK...\r\n");
> } else {
> printf("mbedTLS Verification failed...: %d\r\n", res);
> }
> printf("mbedTLS way end\r\n");
> ```
>
> and it always fails with error code -20450. while loading keys function goes through well.
>
> Am I wrongly loading the keys?