cancel
Showing results for 
Search instead for 
Did you mean: 

ECC Signature Failure

rrooyen
Associate III

Reference: STM32CubeExpansion_Crypto_V4..1.0, MCU: STM32G474RE

The cmox_ecdsa_verify(...) function is failing with a fault code of 0x6c706, which is not contained within cmox_ecc_retvals.h header file. All arguments to the cmox_ecdsa_verify(...) function have been verified and the generated signature has been verified on the development platform. Perhaps the fault code definition in the source code (not available) will provide some insight into the problem? Are there any additional steps I can take to debug this issue?

20 REPLIES 20
CMYL
ST Employee

Hello @rrooyen 

Are you running the same vector test [P-256,SHA-224] as in the following project example ? "~\STM32CubeExpansion_Crypto_V4.0.1\Projects\NUCLEO-G474RE\Applications\ECC\ECDSA_SignVerify" 

or another vector test ?

If another vector test, could you share it with me ? I will get a board to test.

Best Regards

 

 

Hi CMYL,

Thank you very much for having a look at this issue.  As mentioned above, the fault code is 0x6c706, which is not in the cmox_ecc_retvals.h header file.

Signature (DER):

$ openssl asn1parse -in meta.sign -inform DER
0:d=0 hl=2 l= 69 cons: SEQUENCE
2:d=1 hl=2 l= 33 prim: INTEGER :DFEF764BAA19B0D3F24EA250E522D853FD7426351A6DC92C4192F775BD040717
37:d=1 hl=2 l= 32 prim: INTEGER :06B702D318F3BEE865FE3B2F1F7E182DEE7E6437CB203DAE29D76F207E407117

BAT file for generating the binary signature (see signature[] below):

for /F "tokens=4 delims=:" %%A IN ('%OPENSSL% asn1parse -in meta.sign -inform=DER') do >>temp.txt echo(%%A
%certutil% -f -decodehex temp.txt meta.sign.bin >nul

Public key (EC):
static uint8_t key[] =
{
0x6c, 0x5a, 0xd7, 0x93, 0x8c, 0x29, 0x05, 0x82, 0x5f, 0x4b, 0x1b, 0xc8, 0x37, 0x93, 0x9e, 0x9e,
0x64, 0xcf, 0x15, 0xfe, 0x3d, 0x03, 0x75, 0x9c, 0x06, 0x6b, 0x66, 0xeb, 0x24, 0x32, 0xa5, 0x12,
0x79, 0xca, 0xe0, 0x45, 0x52, 0xbb, 0x3e, 0xcd, 0x45, 0x2b, 0xe4, 0x27, 0x4a, 0x45, 0x9f, 0xb0,
0xf3, 0xf9, 0x79, 0x81, 0x0c, 0xfd, 0x8e, 0xf2, 0x2a, 0xc9, 0x7f, 0x24, 0x1f, 0xee, 0x24, 0xb5
};

Digest (sha256):

static uint8_t digest[] =
{

0x3d, 0xef, 0x6a, 0xcc, 0x33, 0xa8, 0x36, 0x8b, 0x12, 0x70, 0x84, 0xb0, 0x49, 0x27, 0xb9, 0x2a,

0xce, 0x98, 0x1c, 0xe8, 0xd5, 0x3a, 0xc4, 0xaf, 0xb5, 0x2a, 0xaa, 0xbf, 0x19, 0x3a, 0x50, 0xcd

};

Signature (sha256):

static uint8_t signature[] =
{

0xdf, 0xef, 0x76, 0x4b, 0xaa, 0x19, 0xb0, 0xd3, 0xf2, 0x4e, 0xa2, 0x50, 0xe5, 0x22, 0xd8, 0x53,
0xfd, 0x74, 0x26, 0x35, 0x1a, 0x6d, 0xc9, 0x2c, 0x41, 0x92, 0xf7, 0x75, 0xbd, 0x04, 0x07, 0x17,
0x06, 0xb7, 0x02, 0xd3, 0x18, 0xf3, 0xbe, 0xe8, 0x65, 0xfe, 0x3b, 0x2f, 0x1f, 0x7e, 0x18, 0x2d,
0xee, 0x7e, 0x64, 0x37, 0xcb, 0x20, 0x3d, 0xae, 0x29, 0xd7, 0x6f, 0x20, 0x7e, 0x40, 0x71, 0x17

};

Basic code snippet from the firmware:

static uint8_t buffer[2048];

uint32_t fault = CMOX_ECC_AUTH_FAIL;
cmox_ecc_handle_t rEcc;

cmox_ecc_retval_t status;

cmox_ecc_construct(&rEcc, CMOX_ECC256_MATH_FUNCS, buffer, sizeof(buffer));

if (CMOX_ECC_AUTH_SUCCESS != (status = cmox_ecdsa_verify(&rEcc, CMOX_ECC_CURVE_SECP256R1, key, sizeof(key), digest, sizeof(digest), signature, sizeof(signature), &fault)))

{

    return -1;

}

cmox_ecc_cleanup(&rEcc);

 

CMYL
ST Employee

Hello @rrooyen 

Sorry I missed your last comment, I'm working on your test vector 🙂

 

Best Regards,

Younes

Hi Younes,

Thank you very much for trying my test vector and I am looking forward to your findings.

Cheers,

 

Robert

CMYL
ST Employee

Hi Robert,

I tried your example and found the same issue.

The problem is that the sign/verify is working with provided NIST vector tests but not working with tests generated by openssl. I even generated more test vectors, signatures for a other supported ECC curves and got the same issues.

I created a CR Ticket asking the Cryptolib team to help how to format and integrate opensl-based vectors. I'm waiting their support.

 

best Regards

Hi Younes,

Thank you so very much for finding root cause in the Cryptolib and forwarding it to the appropriate team for review. I am looking forward to applying the patch when it becomes available.

Cheers,

Robert

I was able to confirm the private key was valid with MicroECC, the version I'm using I had the byte-reverse the key.

I was unable to validate the signature.

What you might want to try is to use CMOX to sign and then validate locally on the STM32, basically proving the path end-to-end. As I recall the signature will be different each time due to the injection of a random pattern.

If you can generate a couple of patterns that way I can check.

I'm currently using SECP192R1 in a different application

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

I tested this FIPS test pattern with my MicroECC build for SECP256R1

 

//[P-256,SHA-256]
//
// Msg = 5905238877c77421f73e43ee3da6f2d9e2ccad5fc942dcec0cbd25482935faaf416983fe165b1a045ee2bcd2e6dca3bdf46c4310a7461f9a37960ca672d3feb5473e253605fb1ddfd28065b53cb5858a8ad28175bf9bd386a5e471ea7a65c17cc934a9d791e91491eb3754d03799790fe2d308d16146d5c9b0d0debd97d79ce8
// d   = 519b423d715f8b581f4fa8ee59f4771a5b44c8130b4e3eacca54a56dda72b464
// Qx  = 1ccbe91c075fc7f4f033bfa248db8fccd3565de94bbfb12f3c59ff46c271bf83
// Qy  = ce4014c68811f9a21a1fdb2c0e6113e06db7ca93b7404e78dc7ccd5ca89a4ca9
// k   = 94a1bbb14b906a61a280f245f9e93c7f3b4a6247824f5d33b9670787642a68de
// R   = f3ac8061b514795b8843e3d6629527ed2afd6b1f6a555a7acabb5e6f79c8c2ac
// S   = 8bf77819ca05a6b2786c76262bf7371cef97b218e96f175a3ccdda2acc058903

static uint8_t msg[] = { // Message
0x59,0x05,0x23,0x88,0x77,0xc7,0x74,0x21,0xf7,0x3e,0x43,0xee,0x3d,0xa6,0xf2,0xd9,
0xe2,0xcc,0xad,0x5f,0xc9,0x42,0xdc,0xec,0x0c,0xbd,0x25,0x48,0x29,0x35,0xfa,0xaf,
0x41,0x69,0x83,0xfe,0x16,0x5b,0x1a,0x04,0x5e,0xe2,0xbc,0xd2,0xe6,0xdc,0xa3,0xbd,
0xf4,0x6c,0x43,0x10,0xa7,0x46,0x1f,0x9a,0x37,0x96,0x0c,0xa6,0x72,0xd3,0xfe,0xb5,
0x47,0x3e,0x25,0x36,0x05,0xfb,0x1d,0xdf,0xd2,0x80,0x65,0xb5,0x3c,0xb5,0x85,0x8a,
0x8a,0xd2,0x81,0x75,0xbf,0x9b,0xd3,0x86,0xa5,0xe4,0x71,0xea,0x7a,0x65,0xc1,0x7c,
0xc9,0x34,0xa9,0xd7,0x91,0xe9,0x14,0x91,0xeb,0x37,0x54,0xd0,0x37,0x99,0x79,0x0f,
0xe2,0xd3,0x08,0xd1,0x61,0x46,0xd5,0xc9,0xb0,0xd0,0xde,0xbd,0x97,0xd7,0x9c,0xe8 };

static uint8_t digest[] = { // Digest (sha256) Actual
0x44,0xac,0xf6,0xb7,0xe3,0x6c,0x13,0x42,0xc2,0xc5,0x89,0x72,0x04,0xfe,0x09,0x50, // sha256(msg)
0x4e,0x1e,0x2e,0xfb,0x1a,0x90,0x03,0x77,0xdb,0xc4,0xe7,0xa6,0xa1,0x33,0xec,0x56 };

static uint8_t keyprivate[] = { // Private Key
0x51,0x9b,0x42,0x3d,0x71,0x5f,0x8b,0x58,0x1f,0x4f,0xa8,0xee,0x59,0xf4,0x77,0x1a, // d
0x5b,0x44,0xc8,0x13,0x0b,0x4e,0x3e,0xac,0xca,0x54,0xa5,0x6d,0xda,0x72,0xb4,0x64 };

static uint8_t key[] = { // Public Key
0x1c,0xcb,0xe9,0x1c,0x07,0x5f,0xc7,0xf4,0xf0,0x33,0xbf,0xa2,0x48,0xdb,0x8f,0xcc, // Qx
0xd3,0x56,0x5d,0xe9,0x4b,0xbf,0xb1,0x2f,0x3c,0x59,0xff,0x46,0xc2,0x71,0xbf,0x83,
0xce,0x40,0x14,0xc6,0x88,0x11,0xf9,0xa2,0x1a,0x1f,0xdb,0x2c,0x0e,0x61,0x13,0xe0, // Qy
0x6d,0xb7,0xca,0x93,0xb7,0x40,0x4e,0x78,0xdc,0x7c,0xcd,0x5c,0xa8,0x9a,0x4c,0xa9 };

static uint8_t k[] = {
0x94,0xa1,0xbb,0xb1,0x4b,0x90,0x6a,0x61,0xa2,0x80,0xf2,0x45,0xf9,0xe9,0x3c,0x7f, // k
0x3b,0x4a,0x62,0x47,0x82,0x4f,0x5d,0x33,0xb9,0x67,0x07,0x87,0x64,0x2a,0x68,0xde };

static uint8_t signature[] = { // Signature (sha256)
0xf3,0xac,0x80,0x61,0xb5,0x14,0x79,0x5b,0x88,0x43,0xe3,0xd6,0x62,0x95,0x27,0xed, // R
0x2a,0xfd,0x6b,0x1f,0x6a,0x55,0x5a,0x7a,0xca,0xbb,0x5e,0x6f,0x79,0xc8,0xc2,0xac,
0x8b,0xf7,0x78,0x19,0xca,0x05,0xa6,0xb2,0x78,0x6c,0x76,0x26,0x2b,0xf7,0x37,0x1c, // S
0xef,0x97,0xb2,0x18,0xe9,0x6f,0x17,0x5a,0x3c,0xcd,0xda,0x2a,0xcc,0x05,0x89,0x03 };

 

#if (FIPS_TEST == 2)

// Msg = c35e2f092553c55772926bdbe87c9796827d17024dbb9233a545366e2e5987dd344deb72df987144b8c6c43bc41b654b94cc856e16b96d7a821c8ec039b503e3d86728c494a967d83011a0e090b5d54cd47f4e366c0912bc808fbb2ea96efac88fb3ebec9342738e225f7c7c2b011ce375b56621a20642b4d36e060db4524af1
// d   = 0f56db78ca460b055c500064824bed999a25aaf48ebb519ac201537b85479813
// Qx  = e266ddfdc12668db30d4ca3e8f7749432c416044f2d2b8c10bf3d4012aeffa8a
// Qy  = bfa86404a2e9ffe67d47c587ef7a97a7f456b863b4d02cfc6928973ab5b1cb39
// k   = 6d3e71882c3b83b156bb14e0ab184aa9fb728068d3ae9fac421187ae0b2f34c6
// R   = 976d3a4e9d23326dc0baa9fa560b7c4e53f42864f508483a6473b6a11079b2db
// S   = 1b766e9ceb71ba6c01dcd46e0af462cd4cfa652ae5017d4555b8eeefe36e1932

static uint8_t msg[] = { // Message
0xc3,0x5e,0x2f,0x09,0x25,0x53,0xc5,0x57,0x72,0x92,0x6b,0xdb,0xe8,0x7c,0x97,0x96, // Msg
0x82,0x7d,0x17,0x02,0x4d,0xbb,0x92,0x33,0xa5,0x45,0x36,0x6e,0x2e,0x59,0x87,0xdd,
0x34,0x4d,0xeb,0x72,0xdf,0x98,0x71,0x44,0xb8,0xc6,0xc4,0x3b,0xc4,0x1b,0x65,0x4b,
0x94,0xcc,0x85,0x6e,0x16,0xb9,0x6d,0x7a,0x82,0x1c,0x8e,0xc0,0x39,0xb5,0x03,0xe3,
0xd8,0x67,0x28,0xc4,0x94,0xa9,0x67,0xd8,0x30,0x11,0xa0,0xe0,0x90,0xb5,0xd5,0x4c,
0xd4,0x7f,0x4e,0x36,0x6c,0x09,0x12,0xbc,0x80,0x8f,0xbb,0x2e,0xa9,0x6e,0xfa,0xc8,
0x8f,0xb3,0xeb,0xec,0x93,0x42,0x73,0x8e,0x22,0x5f,0x7c,0x7c,0x2b,0x01,0x1c,0xe3,
0x75,0xb5,0x66,0x21,0xa2,0x06,0x42,0xb4,0xd3,0x6e,0x06,0x0d,0xb4,0x52,0x4a,0xf1 };

static uint8_t digest[] = { // Digest (sha256) Actual
0x9b,0x2d,0xb8,0x9c,0xb0,0xe8,0xfa,0x3c,0xc7,0x60,0x8b,0x4d,0x6c,0xc1,0xde,0xc0, // sha256(Msg)
0x11,0x4e,0x0b,0x9f,0xf4,0x08,0x0b,0xea,0x12,0xb1,0x34,0xf4,0x89,0xab,0x2b,0xbc };

static uint8_t keyprivate[] = { // Private Key
0x0f,0x56,0xdb,0x78,0xca,0x46,0x0b,0x05,0x5c,0x50,0x00,0x64,0x82,0x4b,0xed,0x99, // d
0x9a,0x25,0xaa,0xf4,0x8e,0xbb,0x51,0x9a,0xc2,0x01,0x53,0x7b,0x85,0x47,0x98,0x13 };

static uint8_t key[] = { // Public Key
0xe2,0x66,0xdd,0xfd,0xc1,0x26,0x68,0xdb,0x30,0xd4,0xca,0x3e,0x8f,0x77,0x49,0x43, // Qx
0x2c,0x41,0x60,0x44,0xf2,0xd2,0xb8,0xc1,0x0b,0xf3,0xd4,0x01,0x2a,0xef,0xfa,0x8a,
0xbf,0xa8,0x64,0x04,0xa2,0xe9,0xff,0xe6,0x7d,0x47,0xc5,0x87,0xef,0x7a,0x97,0xa7, // Qy
0xf4,0x56,0xb8,0x63,0xb4,0xd0,0x2c,0xfc,0x69,0x28,0x97,0x3a,0xb5,0xb1,0xcb,0x39 };

static uint8_t k[] = {
0x6d,0x3e,0x71,0x88,0x2c,0x3b,0x83,0xb1,0x56,0xbb,0x14,0xe0,0xab,0x18,0x4a,0xa9, // k
0xfb,0x72,0x80,0x68,0xd3,0xae,0x9f,0xac,0x42,0x11,0x87,0xae,0x0b,0x2f,0x34,0xc6 };

static uint8_t signature[] = { // Signature (sha256)
0x97,0x6d,0x3a,0x4e,0x9d,0x23,0x32,0x6d,0xc0,0xba,0xa9,0xfa,0x56,0x0b,0x7c,0x4e, // R
0x53,0xf4,0x28,0x64,0xf5,0x08,0x48,0x3a,0x64,0x73,0xb6,0xa1,0x10,0x79,0xb2,0xdb,
0x1b,0x76,0x6e,0x9c,0xeb,0x71,0xba,0x6c,0x01,0xdc,0xd4,0x6e,0x0a,0xf4,0x62,0xcd, // S
0x4c,0xfa,0x65,0x2a,0xe5,0x01,0x7d,0x45,0x55,0xb8,0xee,0xef,0xe3,0x6e,0x19,0x32 };

#endif // FIPS_TEST == 2
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Well the NIST/FIPS test vectors should be definitive. I wonder what OPENSSL is doing here?

Some kind of Byte/Endian swap expectations?

[P-256,SHA-224] or [P-256,SHA-256] being attempted? SECP256R1 curve or SECP256K1 ?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..