From 5bb04e03ac82909d4ab90855597d0fe12aac0544 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 19 Feb 2024 13:24:41 +0100 Subject: [PATCH 1/4] mbedtls_ecp_write_key: no FEATURE_UNAVAILABLE error When exporting a key, MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE should not happen. This error indicates that the curve is not supported, but that would prevent the creation of the key. Signed-off-by: Gilles Peskine --- include/mbedtls/ecp.h | 2 -- library/ecp.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index 76aef32fbc..3d14f36b31 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -1339,8 +1339,6 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, * \return \c 0 on success. * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the \p key representation is larger than the available space in \p buf. - * \return #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the operation for - * the group is not implemented. * \return Another negative error code on different kinds of failure. */ int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key, diff --git a/library/ecp.c b/library/ecp.c index 758d54bd76..66b3dc1be1 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -3305,7 +3305,7 @@ cleanup: int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key, unsigned char *buf, size_t buflen) { - int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { From a395bdd06601da6853b5c50afd3eb1c738aa15f8 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 19 Feb 2024 13:30:31 +0100 Subject: [PATCH 2/4] mbedtls_ecp_write_key: document and test larger output buffer Signed-off-by: Gilles Peskine --- include/mbedtls/ecp.h | 21 ++++++++- tests/suites/test_suite_ecp.data | 64 ++++++++++++++++++++++++++++ tests/suites/test_suite_ecp.function | 47 ++++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index 3d14f36b31..54f29615d9 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -1330,11 +1330,28 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, /** * \brief This function exports an elliptic curve private key. * + * \note Note that although this function accepts an output + * buffer that is larger than the key, most key import + * interfaces require the output to be trimmed to the + * key's nominal length. It is generally simplest to + * pass the key's nominal length as \c buflen, after + * checking that the output buffer is large enough. + * See the description of the \p buflen parameter for + * how to calculate the nominal length. + * * \param key The private key. * \param buf The output buffer for containing the binary representation - * of the key. (Big endian integer for Weierstrass curves, byte - * string for Montgomery curves.) + * of the key. + * For Weierstrass curves, this is the big-endian + * representation, padded with null bytes at the beginning + * to reach \p buflen bytes. + * For Montgomery curves, this is the standard byte string + * representation (which is little-endian), padded with + * null bytes at the end to reach \p buflen bytes. * \param buflen The total length of the buffer in bytes. + * The length of the output is always + * (`grp->nbits` + 7) / 8 bytes + * where `grp->nbits` is the private key size in bits. * * \return \c 0 on success. * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the \p key diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index 01fdc477f7..ac57a68414 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -736,6 +736,70 @@ ECP read key #24 (Curve25519 RFC, OK) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a":0:1 +ECP write key: secp256r1, nominal +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":32:0 + +ECP write key: secp256r1, output longer by 1 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":33:0 + +ECP write key: secp256r1, output longer by 32 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":64:0 + +ECP write key: secp256r1, output longer by 33 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":65:0 + +ECP write key: secp384r1, nominal +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":48:0 + +ECP write key: secp384r1, output longer by 1 +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":49:0 + +ECP write key: secp384r1, output longer by 48 +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":96:0 + +ECP write key: secp384r1, output longer by 49 +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":97:0 + +ECP write key: Curve25519, nominal +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":32:0 + +ECP write key: Curve25519, output longer by 1 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":33:0 + +ECP write key: Curve25519, output longer by 32 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":64:0 + +ECP write key: Curve25519, output longer by 33 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":65:0 + +ECP write key: Curve448, nominal +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":56:0 + +ECP write key: Curve448, output longer by 1 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":57:0 + +ECP write key: Curve448, output longer by 32 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":112:0 + +ECP write key: Curve448, output longer by 33 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":113:0 + ECP mod p192 small (more than 192 bits, less limbs than 2 * 192 bits) depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"0100000000000103010000000000010201000000000001010100000000000100" diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 295fe7f151..80fff2065b 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1236,6 +1236,53 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void ecp_write_key(int grp_id, data_t *in_key, + int exported_size, int expected_ret) +{ + mbedtls_ecp_keypair key; + mbedtls_ecp_keypair_init(&key); + unsigned char *exported = NULL; + + TEST_EQUAL(mbedtls_ecp_read_key(grp_id, &key, in_key->x, in_key->len), 0); + + TEST_CALLOC(exported, exported_size); + TEST_EQUAL(mbedtls_ecp_write_key(&key, exported, exported_size), + expected_ret); + + if (expected_ret == 0) { + size_t length = (key.grp.nbits + 7) / 8; + TEST_LE_U(length, exported_size); + + const unsigned char *key_start = NULL; + const unsigned char *zeros_start = NULL; + switch (mbedtls_ecp_get_type(&key.grp)) { + case MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS: + key_start = exported + exported_size - length; + zeros_start = exported; + break; + case MBEDTLS_ECP_TYPE_MONTGOMERY: + key_start = exported; + zeros_start = exported + length; + break; + default: + TEST_FAIL("Unknown ECP curve type"); + break; + } + TEST_MEMORY_COMPARE(in_key->x, in_key->len, + key_start, length); + for (size_t i = 0; i < exported_size - length; i++) { + mbedtls_test_set_step(i); + TEST_EQUAL(zeros_start[i], 0); + } + } + +exit: + mbedtls_ecp_keypair_free(&key); + mbedtls_free(exported); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:MBEDTLS_TEST_HOOKS:MBEDTLS_ECP_MONTGOMERY_ENABLED:MBEDTLS_ECP_LIGHT */ void genkey_mx_known_answer(int bits, data_t *seed, data_t *expected) { From 1c7ff7ea5371835da8d0473f31557610ee1773cd Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 19 Feb 2024 13:49:45 +0100 Subject: [PATCH 3/4] mbedtls_ecp_write_key: document and test smaller output buffer Document and test the current behavior, even if it is weird: * For Weierstrass keys, the error is MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL, not MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL. * For Weierstrass keys, a smaller output buffer is ok if the output fits. Signed-off-by: Gilles Peskine --- include/mbedtls/ecp.h | 15 +++-- tests/suites/test_suite_ecp.data | 88 ++++++++++++++++++++++++++++ tests/suites/test_suite_ecp.function | 27 ++++++--- 3 files changed, 118 insertions(+), 12 deletions(-) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index 54f29615d9..e3bde01801 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -1331,8 +1331,8 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, * \brief This function exports an elliptic curve private key. * * \note Note that although this function accepts an output - * buffer that is larger than the key, most key import - * interfaces require the output to be trimmed to the + * buffer that is smaller or larger than the key, most key + * import interfaces require the output to have exactly * key's nominal length. It is generally simplest to * pass the key's nominal length as \c buflen, after * checking that the output buffer is large enough. @@ -1349,13 +1349,18 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, * representation (which is little-endian), padded with * null bytes at the end to reach \p buflen bytes. * \param buflen The total length of the buffer in bytes. - * The length of the output is always + * The length of the output is * (`grp->nbits` + 7) / 8 bytes * where `grp->nbits` is the private key size in bits. + * For Weierstrass keys, if the output buffer is smaller, + * leading zeros are trimmed to fit if possible. For + * Montgomery keys, the output buffer must always be large + * enough for the nominal length. * * \return \c 0 on success. - * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the \p key - representation is larger than the available space in \p buf. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL or + * #MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if the \p key + * representation is larger than the available space in \p buf. * \return Another negative error code on different kinds of failure. */ int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key, diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index ac57a68414..1dd963a23e 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -752,6 +752,42 @@ ECP write key: secp256r1, output longer by 33 depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":65:0 +ECP write key: secp256r1, output short by 1 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":31:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL + +ECP write key: secp256r1, output_size=1 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":1:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL + +ECP write key: secp256r1, output_size=0 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL + +ECP write key: secp256r1, top byte = 0, output_size=32 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":32:0 + +ECP write key: secp256r1, top byte = 0, output_size=31 (fits) +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":31:0 + +ECP write key: secp256r1, top byte = 0, output_size=30 (too small) +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":30:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL + +ECP write key: secp256r1, mostly-0 key, output_size=32 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":32:0 + +ECP write key: secp256r1, mostly-0 key, output_size=31 (fits) +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":31:0 + +ECP write key: secp256r1, mostly-0 key, output_size=1 (fits) +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":1:0 + ECP write key: secp384r1, nominal depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":48:0 @@ -768,6 +804,18 @@ ECP write key: secp384r1, output longer by 49 depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":97:0 +ECP write key: secp384r1, output short by 1 +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":47:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL + +ECP write key: secp384r1, output_size=1 +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":1:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL + +ECP write key: secp384r1, output_size=0 +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":0:MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL + ECP write key: Curve25519, nominal depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":32:0 @@ -784,6 +832,26 @@ ECP write key: Curve25519, output longer by 33 depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":65:0 +ECP write key: Curve25519, output short by 1 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key: Curve25519, output_size=1 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":1:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key: Curve25519, output_size=0 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":0:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key: Curve25519, mostly-0 key, output_size=32 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000040":32:0 + +ECP write key: Curve25519, mostly-0 key, output_size=31 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000040":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + ECP write key: Curve448, nominal depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":56:0 @@ -800,6 +868,26 @@ ECP write key: Curve448, output longer by 33 depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":113:0 +ECP write key: Curve448, output short by 1 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":55:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key: Curve448, output_size=1 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":1:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key: Curve448, output_size=0 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":0:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key: Curve448, mostly-0 key, output_size=56 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080":56:0 + +ECP write key: Curve448, mostly-0 key, output_size=55 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key:MBEDTLS_ECP_DP_CURVE448:"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080":55:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + ECP mod p192 small (more than 192 bits, less limbs than 2 * 192 bits) depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED:MBEDTLS_ECP_NIST_OPTIM ecp_fast_mod:MBEDTLS_ECP_DP_SECP192R1:"0100000000000103010000000000010201000000000001010100000000000100" diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 80fff2065b..9cf0ce1b7a 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1252,16 +1252,18 @@ void ecp_write_key(int grp_id, data_t *in_key, if (expected_ret == 0) { size_t length = (key.grp.nbits + 7) / 8; - TEST_LE_U(length, exported_size); - const unsigned char *key_start = NULL; const unsigned char *zeros_start = NULL; switch (mbedtls_ecp_get_type(&key.grp)) { case MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS: + if ((size_t) exported_size < length) { + length = exported_size; + } key_start = exported + exported_size - length; zeros_start = exported; break; case MBEDTLS_ECP_TYPE_MONTGOMERY: + TEST_LE_U(length, exported_size); key_start = exported; zeros_start = exported + length; break; @@ -1269,11 +1271,22 @@ void ecp_write_key(int grp_id, data_t *in_key, TEST_FAIL("Unknown ECP curve type"); break; } - TEST_MEMORY_COMPARE(in_key->x, in_key->len, - key_start, length); - for (size_t i = 0; i < exported_size - length; i++) { - mbedtls_test_set_step(i); - TEST_EQUAL(zeros_start[i], 0); + + if (length < in_key->len) { + /* Shorter output (only possible with Weierstrass keys) */ + for (size_t i = 0; i < in_key->len - length; i++) { + mbedtls_test_set_step(i); + TEST_EQUAL(in_key->x[i], 0); + } + TEST_MEMORY_COMPARE(in_key->x + in_key->len - length, length, + key_start, length); + } else { + TEST_MEMORY_COMPARE(in_key->x, in_key->len, + key_start, length); + for (size_t i = 0; i < exported_size - length; i++) { + mbedtls_test_set_step(i); + TEST_EQUAL(zeros_start[i], 0); + } } } From 7511d4aed79b58b8d211c2bd31b8014a7380d1bf Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 19 Feb 2024 13:56:39 +0100 Subject: [PATCH 4/4] ECP write/export key: document that these functions don't detect unset data Fixes #8803. Signed-off-by: Gilles Peskine --- include/mbedtls/ecp.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index e3bde01801..0201963ab9 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -1339,6 +1339,10 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, * See the description of the \p buflen parameter for * how to calculate the nominal length. * + * \note If the private key was not set in \p key, + * the output is unspecified. Future versions + * may return an error in that case. + * * \param key The private key. * \param buf The output buffer for containing the binary representation * of the key. @@ -1369,6 +1373,10 @@ int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key, /** * \brief This function exports an elliptic curve public key. * + * \note If the public key was not set in \p key, + * the output is unspecified. Future versions + * may return an error in that case. + * * \param key The public key. * \param format The point format. This must be either * #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED. @@ -1451,6 +1459,10 @@ mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id( * Each of the output parameters can be a null pointer * if you do not need that parameter. * + * \note If the private key or the public key was not set in \p key, + * the corresponding output is unspecified. Future versions + * may return an error in that case. + * * \param key The key pair to export from. * \param grp Slot for exported ECP group. * It must either be null or point to an initialized ECP group.