Open maxgerhardt opened 1 year ago
FYI, I came up with at least a starting point for the ECDSA verify that works:
#include <mbedtls/ecdsa.h>
#include <mbedtls/sha256.h>
int self_test_ecdsa() {
/* Good vector from https://github.com/STMicroelectronics/STM32CubeWL/blob/main/Projects/NUCLEO-WL55JC/Examples/PKA/PKA_ECDSA_Verify/Src/SigVer.rsp
[P-256,SHA-256]
Msg = e1130af6a38ccb412a9c8d13e15dbfc9e69a16385af3c3f1e5da954fd5e7c45fd75e2b8c36699228e92840c0562fbf3772f07e17f1add56588dd45f7450e1217ad239922dd9c32695dc71ff2424ca0dec1321aa47064a044b7fe3c2b97d03ce470a592304c5ef21eed9f93da56bb232d1eeb0035f9bf0dfafdcc4606272b20a3
Qx = e424dc61d4bb3cb7ef4344a7f8957a0c5134e16f7a67c074f82e6e12f49abf3c
Qy = 970eed7aa2bc48651545949de1dddaf0127e5965ac85d1243d6f60e7dfaee927
R = bf96b99aa49c705c910be33142017c642ff540c76349b9dab72f981fd9347f4f
S = 17c55095819089c2e03b9cd415abdf12444e323075d98f31920b9e0f57ec871c
Result = P (0 )
*/
APP_PPRINTF("Starting ECDSA verify test!\n");
const uint8_t msg[] = {
0xe1, 0x13, 0x0a, 0xf6, 0xa3, 0x8c, 0xcb, 0x41, 0x2a, 0x9c, 0x8d, 0x13, 0xe1, 0x5d, 0xbf, 0xc9, 0xe6, 0x9a, 0x16, 0x38, 0x5a, 0xf3, 0xc3, 0xf1, 0xe5, 0xda, 0x95, 0x4f, 0xd5, 0xe7, 0xc4, 0x5f, 0xd7, 0x5e, 0x2b, 0x8c, 0x36, 0x69, 0x92, 0x28, 0xe9, 0x28, 0x40, 0xc0, 0x56, 0x2f, 0xbf, 0x37, 0x72, 0xf0, 0x7e, 0x17, 0xf1, 0xad, 0xd5, 0x65, 0x88, 0xdd, 0x45, 0xf7, 0x45, 0x0e, 0x12, 0x17, 0xad, 0x23, 0x99, 0x22, 0xdd, 0x9c, 0x32, 0x69, 0x5d, 0xc7, 0x1f, 0xf2, 0x42, 0x4c, 0xa0, 0xde, 0xc1, 0x32, 0x1a, 0xa4, 0x70, 0x64, 0xa0, 0x44, 0xb7, 0xfe, 0x3c, 0x2b, 0x97, 0xd0, 0x3c, 0xe4, 0x70, 0xa5, 0x92, 0x30, 0x4c, 0x5e, 0xf2, 0x1e, 0xed, 0x9f, 0x93, 0xda, 0x56, 0xbb, 0x23, 0x2d, 0x1e, 0xeb, 0x00, 0x35, 0xf9, 0xbf, 0x0d, 0xfa, 0xfd, 0xcc, 0x46, 0x06, 0x27, 0x2b, 0x20, 0xa3
};
const uint8_t pubpoint[] = {
0x04 /* MBEDTLS_ECP_PF_UNCOMPRESSED */,
//Qx
0xe4, 0x24, 0xdc, 0x61, 0xd4, 0xbb, 0x3c, 0xb7, 0xef, 0x43, 0x44, 0xa7, 0xf8, 0x95, 0x7a, 0x0c, 0x51, 0x34, 0xe1, 0x6f, 0x7a, 0x67, 0xc0, 0x74, 0xf8, 0x2e, 0x6e, 0x12, 0xf4, 0x9a, 0xbf, 0x3c,
// Qy
0x97, 0x0e, 0xed, 0x7a, 0xa2, 0xbc, 0x48, 0x65, 0x15, 0x45, 0x94, 0x9d, 0xe1, 0xdd, 0xda, 0xf0, 0x12, 0x7e, 0x59, 0x65, 0xac, 0x85, 0xd1, 0x24, 0x3d, 0x6f, 0x60, 0xe7, 0xdf, 0xae, 0xe9, 0x27
};
const uint8_t Sig_R[] = {
0xbf, 0x96, 0xb9, 0x9a, 0xa4, 0x9c, 0x70, 0x5c, 0x91, 0x0b, 0xe3, 0x31, 0x42, 0x01, 0x7c, 0x64, 0x2f, 0xf5, 0x40, 0xc7, 0x63, 0x49, 0xb9, 0xda, 0xb7, 0x2f, 0x98, 0x1f, 0xd9, 0x34, 0x7f, 0x4f
};
const uint8_t Sig_S[] = {
0x17, 0xc5, 0x50, 0x95, 0x81, 0x90, 0x89, 0xc2, 0xe0, 0x3b, 0x9c, 0xd4, 0x15, 0xab, 0xdf, 0x12, 0x44, 0x4e, 0x32, 0x30, 0x75, 0xd9, 0x8f, 0x31, 0x92, 0x0b, 0x9e, 0x0f, 0x57, 0xec, 0x87, 0x1c
};
unsigned char hashOut[256 / 8]; //SHA256 output
int ret = 0;
if( (ret = mbedtls_sha256(msg, sizeof(msg), hashOut, 0 /* is SHA224 = no */)) != 0) {
APP_PPRINTF("Hashing failed: %d\n", ret);
return ret;
}
mbedtls_ecp_group ec_group;
mbedtls_ecp_group_init(&ec_group);
if( (ret = mbedtls_ecp_group_load(&ec_group, MBEDTLS_ECP_DP_SECP256R1)) != 0) {
APP_PPRINTF("Loading group failed: %d\n", ret);
return ret;
}
mbedtls_ecp_point Q; //public key point
mbedtls_ecp_point_init(&Q);
mbedtls_ecp_point_read_binary(&ec_group, &Q, pubpoint, sizeof(pubpoint));
mbedtls_mpi r, s;
mbedtls_mpi_init(&r);
mbedtls_mpi_init(&s);
mbedtls_mpi_read_binary(&r, Sig_R, sizeof(Sig_R));
mbedtls_mpi_read_binary(&s, Sig_S, sizeof(Sig_S));
APP_PPRINTF("Loaded all parameters, calling into ECDSA verify..\n");
ret = mbedtls_ecdsa_verify(&ec_group, hashOut, sizeof(hashOut), &Q, &r, &s);
if(ret != 0) {
APP_PPRINTF("Signature verify failed, ret = %d\n", ret);
} else {
APP_PPRINTF("Signature verify OK!\n");
}
mbedtls_mpi_free(&r);
mbedtls_mpi_free(&s);
mbedtls_ecp_point_free(&Q);
mbedtls_ecp_group_free(&ec_group);
return ret;
}
I agree that we should have a self-test, but that's mainly because some certifications require one. To test your driver, please run the unit tests (in particular test_suite_ecdsa
and test_suite_psa_crypto
). They're mainly written with a software implementation in mind, and might not catch issues that are specific to accelerators (such as not resetting the hardware state properly between calls), but they're a start.
The unit test framework may require some adaptation to run on embedded targets, since it assumes that some stdio is available. If that's an issue, please let us know what problems you run into: we do know that there's a potential gap there, but not what the exact requirements should be.
./scripts/generate_test_code.py -f suites/test_suite_ecdsa.function -d suites/test_suite_ecdsa.data -t suites/main_test.function -p suites/host_test.function -s suites --helpers-file suites/helpers.function -o .
Does indeed generate the test suite files, but this wants to read and parse its vectors from the .datax
file, and I don't have a filesystem setup on the microcontroller. Unless I do a rewrite to have the ECC vectors directly in C, add in LittleFS or similiar filesystem or copy the .datax file content in C and hack around fread(), fopen(), etc., this doesn't work for me right now.
But I can at least cherry pick the test vectors and test functions and do my own stuff with it.
Do I see it correctly that.. mbedTLS does currenetly not have this testbed (tests/
) running on.. embedded devices in their CI etc?
Do I see it correctly that.. mbedTLS does currenetly not have this testbed (tests/) running on.. embedded devices in their CI etc?
Unfortunately, that is the case. We only test on Linux, FreeBSD and Windows at the moment. We used to also test under Mbed OS but we stopped a couple of years ago.
It's not that much of a problem because the code is largely OS-independent, apart from some small parts where we do test on the OSes for which we provide the platform integration. But it does make life harder if you want to test the integration on a platform. And for us it also means that we don't notice stack size increases (we don't monitor for that).
Unless I do a rewrite to have the ECC vectors directly in C, add in LittleFS or similiar filesystem or copy the .datax file content in C and hack around fread(), fopen(), etc., this doesn't work for me right now.
All right, thanks for the feedback. We plan to add a mechanism where you can either bundle the test data in the executable (at the cost of having large executables) or transmit the test data over e.g. a serial connection (at the cost of needing the machinery to transmit the data). But I can't give a timeline for that.
Suggested enhancement
mbedTLS should provide should provide a
mbedtls_ecdsa_self_test()
function, just like it does formbedtls_ecp_self_test()
for generate elliptic curve point tests.While there is programs/pkey/ecdsa.c, it does not contain test vectors.
Justification
Mbed TLS needs this because in the case of alternative ECDSA impelmentations, developers can check the correctness of their implementation with the internal test bench function (as e.g. executed by selftest.c).
As I am for example activating
MBEDTLS_ECDSA_VERIFY_ALT
andMBEDTLS_ECDSA_SIGN_ALT
and writing the necessary code to use the Public Key Accelerator (PKA) hardware of a STM32WLxxxx chip (example), I am getting exactly 0 feedback from the mbedtls testbench whether it works. Writinghappily outputs