From e3fb4ccabf02784bbf41010b837b520a4b43c115 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Mon, 19 Feb 2024 16:27:35 +0100 Subject: [PATCH] mbedtls_ecp_write_key_ext(): new function Same as mbedtls_ecp_write_key(), but doesn't require the caller to figure out the length of the output and possibly distinguish between Weierstrass and Montgomery curves. Signed-off-by: Gilles Peskine --- ChangeLog.d/ecp_write_key.txt | 4 ++ include/mbedtls/ecp.h | 20 ++++++ library/ecp.c | 32 +++++++++ tests/suites/test_suite_ecp.data | 103 +++++++++++++++++++++++++++ tests/suites/test_suite_ecp.function | 36 ++++++++++ 5 files changed, 195 insertions(+) create mode 100644 ChangeLog.d/ecp_write_key.txt diff --git a/ChangeLog.d/ecp_write_key.txt b/ChangeLog.d/ecp_write_key.txt new file mode 100644 index 000000000..19612396c --- /dev/null +++ b/ChangeLog.d/ecp_write_key.txt @@ -0,0 +1,4 @@ +Features + * The new function mbedtls_ecp_write_key_ext() is similar to + mbedtls_ecp_write_key(), but can be used without separately calculating + the output length. diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index 0201963ab..b46d6c3dc 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -1370,6 +1370,26 @@ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key, unsigned char *buf, size_t buflen); +/** + * \brief This function exports an elliptic curve private key. + * + * \param key The private key. + * \param olen On success, the length of the private key. + * This is always (`grp->nbits` + 7) / 8 bytes + * where `grp->nbits` is the private key size in bits. + * \param buf The output buffer for containing the binary representation + * of the key. + * \param buflen The total length of the buffer in bytes. + * #MBEDTLS_ECP_MAX_BYTES is always sufficient. + * + * \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 Another negative error code on different kinds of failure. + */ +int mbedtls_ecp_write_key_ext(mbedtls_ecp_keypair *key, + size_t *olen, unsigned char *buf, size_t buflen); + /** * \brief This function exports an elliptic curve public key. * diff --git a/library/ecp.c b/library/ecp.c index 66b3dc1be..930102f97 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -3333,6 +3333,38 @@ cleanup: return ret; } +int mbedtls_ecp_write_key_ext(mbedtls_ecp_keypair *key, + size_t *olen, unsigned char *buf, size_t buflen) +{ + size_t len = (key->grp.nbits + 7) / 8; + if (len > buflen) { + /* For robustness, ensure *olen <= buflen even on error. */ + *olen = 0; + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + } + *olen = len; + + /* Private key not set */ + if (key->d.n == 0) { + return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + } + +#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) + if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { + return mbedtls_mpi_write_binary_le(&key->d, buf, len); + } +#endif + +#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) + if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { + return mbedtls_mpi_write_binary(&key->d, buf, len); + } +#endif + + /* Private key set but no recognized curve type? This shouldn't happen. */ + return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; +} + /* * Write a public key. */ diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index 1dd963a23..fd63657aa 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -888,6 +888,109 @@ 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 write key ext: secp256r1, nominal +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":32:0 + +ECP write key ext: secp256r1, output longer by 1 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":33:0 + +ECP write key ext: secp256r1, output short by 1 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: secp256r1, output_size=0 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"f12a1320760270a83cbffd53f6031ef76a5d86c8a204f2c30ca9ebf51f0f0ea7":0:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: secp256r1, top byte = 0, output_size=32 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":32:0 + +ECP write key ext: secp256r1, top byte = 0, output_size=31 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: secp256r1, top byte = 0, output_size=30 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff":30:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: secp256r1, mostly-0 key, output_size=32 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":32:0 + +ECP write key ext: secp256r1, mostly-0 key, output_size=1 +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"0000000000000000000000000000000000000000000000000000000000000001":1:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: secp256r1, private key not set +depends_on:MBEDTLS_ECP_DP_SECP256R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP256R1:"":32:MBEDTLS_ERR_ECP_BAD_INPUT_DATA + +ECP write key ext: secp384r1, nominal +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":48:0 + +ECP write key ext: secp384r1, output longer by 1 +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":49:0 + +ECP write key ext: secp384r1, output short by 1 +depends_on:MBEDTLS_ECP_DP_SECP384R1_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_SECP384R1:"d27335ea71664af244dd14e9fd1260715dfd8a7965571c48d709ee7a7962a156d706a90cbcb5df2986f05feadb9376f1":47:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: Curve25519, nominal +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":32:0 + +ECP write key ext: Curve25519, output longer by 1 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":33:0 + +ECP write key ext: Curve25519, output short by 1 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: Curve25519, output_size=0 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"a046e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449a44":0:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: Curve25519, mostly-0 key, output_size=32 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000040":32:0 + +ECP write key ext: Curve25519, mostly-0 key, output_size=31 +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000040":31:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: Curve25519, private key not set +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE25519:"":32:MBEDTLS_ERR_ECP_BAD_INPUT_DATA + +ECP write key ext: Curve448, nominal +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":56:0 + +ECP write key ext: Curve448, output longer by 1 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":57:0 + +ECP write key ext: Curve448, output short by 1 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"3c262fddf9ec8e88495266fea19a34d28882acef045104d0d1aae121700a779c984c24f8cdd78fbff44943eba368f54b29259a4f1c600ad3":55:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: Curve448, mostly-0 key, output_size=56 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080":56:0 + +ECP write key ext: Curve448, mostly-0 key, output_size=55 +depends_on:MBEDTLS_ECP_DP_CURVE448_ENABLED +ecp_write_key_ext:MBEDTLS_ECP_DP_CURVE448:"0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080":55:MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + +ECP write key ext: group not set +ecp_write_key_ext:MBEDTLS_ECP_DP_NONE:"":32:MBEDTLS_ERR_ECP_BAD_INPUT_DATA + 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 9cf0ce1b7..c0612755f 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1296,6 +1296,42 @@ exit: } /* END_CASE */ +/* BEGIN_CASE */ +void ecp_write_key_ext(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; + + if (in_key->len != 0) { + TEST_EQUAL(mbedtls_ecp_read_key(grp_id, &key, in_key->x, in_key->len), 0); + } else if (grp_id != MBEDTLS_ECP_DP_NONE) { + TEST_EQUAL(mbedtls_ecp_group_load(&key.grp, grp_id), 0); + } + + TEST_CALLOC(exported, exported_size); + size_t olen = 0xdeadbeef; + TEST_EQUAL(mbedtls_ecp_write_key_ext(&key, &olen, exported, exported_size), + expected_ret); + + if (expected_ret == 0) { + TEST_EQUAL(olen, (key.grp.nbits + 7) / 8); + TEST_LE_U(olen, MBEDTLS_ECP_MAX_BYTES); + TEST_MEMORY_COMPARE(in_key->x, in_key->len, + exported, olen); + } else { + /* Robustness check: even in the error case, insist that olen is less + * than the buffer size. */ + TEST_LE_U(olen, exported_size); + } + +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) {