diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index 4c05b4fd0..9248fd377 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -1146,6 +1146,27 @@ int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, */ int mbedtls_ecp_read_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, const unsigned char *buf, size_t buflen ); + +/** + * \brief This function exports an elliptic curve private key. + * + * \param grp_id The ECP group identifier. + * \param key The private key. + * \param olen The amount of bytes written into the output buffer. + * \param buf The output buffer containing the binary representation of + * the key. (Big endian integer for Weierstrass curves, byte + * string for Montgomery curves.) + * \param buflen The total length of the buffer in bytes. + * + * \return \c 0 on success. + * \return #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if key is larger than buffer. + * \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_group_id grp_id, mbedtls_ecp_keypair *key, + size_t *olen, unsigned char *buf, size_t buflen ); + /** * \brief This function checks that the keypair objects * \p pub and \p prv have the same group and the diff --git a/library/ecp.c b/library/ecp.c index 104e1f122..0aa61f170 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -2996,6 +2996,53 @@ cleanup: return( ret ); } +/* + * Write a private key. + */ +int mbedtls_ecp_write_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + size_t *olen, unsigned char *buf, size_t buflen ) +{ + int ret = 0; + + ECP_VALIDATE_RET( key != NULL ); + ECP_VALIDATE_RET( buf != NULL ); + ECP_VALIDATE_RET( olen != NULL ); + + if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 ) + return( ret ); + + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + +#if defined(ECP_MONTGOMERY) + if( mbedtls_ecp_get_type( &key->grp ) == MBEDTLS_ECP_TYPE_MONTGOMERY ) + { + if( grp_id == MBEDTLS_ECP_DP_CURVE25519 ) + { + if( buflen < ECP_CURVE25519_KEY_SIZE ) + return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary_le( &key->d, buf, buflen ) ); + *olen = ECP_CURVE25519_KEY_SIZE; + } + else + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + } + +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( mbedtls_ecp_get_type( &key->grp ) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &key->d, buf, buflen ) ); + *olen = mbedtls_mpi_size( &key->d ); + } + +#endif +cleanup: + + return( ret ); +} + + /* * Check a public-private key pair */ diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index 921917922..c180d379c 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -278,65 +278,69 @@ mbedtls_ecp_gen_key:MBEDTLS_ECP_DP_SECP192R1 ECP read key #1 (short weierstrass, too small) depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"00":MBEDTLS_ERR_ECP_INVALID_KEY +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"00":MBEDTLS_ERR_ECP_INVALID_KEY:0 ECP read key #2 (short weierstrass, smallest) depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"01":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"01":0:1 ECP read key #3 (short weierstrass, biggest) depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830":0:1 ECP read key #4 (short weierstrass, too big) depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831":MBEDTLS_ERR_ECP_INVALID_KEY +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_SECP192R1:"FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831":MBEDTLS_ERR_ECP_INVALID_KEY:0 ECP read key #5 (Curve25519, most significant bit set) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"000000000000000000000000000000000000000000000000000000000000000C":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"000000000000000000000000000000000000000000000000000000000000000C":0:0 ECP read key #6 (Curve25519, second most significant bit unset) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3":0:0 ECP read key #7 (Curve25519, msb OK) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000004":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0000000000000000000000000000000000000000000000000000000000000004":0:1 ECP read key #8 (Curve25519, bit 0 set) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"1000000000000000000000000000000000000000000000000000000000000000":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"1000000000000000000000000000000000000000000000000000000000000000":0:0 ECP read key #9 (Curve25519, bit 1 set) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"2000000000000000000000000000000000000000000000000000000000000004":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"2000000000000000000000000000000000000000000000000000000000000004":0:0 ECP read key #10 (Curve25519, bit 2 set) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"4000000000000000000000000000000000000000000000000000000000000004":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"4000000000000000000000000000000000000000000000000000000000000004":0:0 ECP read key #11 (Curve25519, OK) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":0 +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":0:1 ECP read key #12 (Curve25519, too long) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"00000000000000000000000000000000000000000000000000000000000000000C":MBEDTLS_ERR_ECP_INVALID_KEY +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"00000000000000000000000000000000000000000000000000000000000000000C":MBEDTLS_ERR_ECP_INVALID_KEY:0 ECP read key #13 (Curve25519, not long enough) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3":MBEDTLS_ERR_ECP_INVALID_KEY +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3":MBEDTLS_ERR_ECP_INVALID_KEY:0 ECP read key #14 (Curve448, not supported) -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE448:"FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE448:"FCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE:0 ECP read key #15 (Curve25519, not supported) depends_on:!MBEDTLS_ECP_DP_CURVE25519_ENABLED -mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE:0 ECP read key #15 (invalid curve) -mbedtls_ecp_read_key:INT_MAX:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE +mbedtls_ecp_read_key:INT_MAX:"8FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7":MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE:0 + +ECP read key #16 (Curve25519 RFC, OK) +depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED +mbedtls_ecp_read_key:MBEDTLS_ECP_DP_CURVE25519:"70076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c6a":0:1 ECP mod p192 small (more than 192 bits, less limbs than 2 * 192 bits) depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 03c3e538b..1a464ec6e 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1069,12 +1069,14 @@ exit: /* END_CASE */ /* BEGIN_CASE */ -void mbedtls_ecp_read_key( int grp_id, data_t* in_key, int expected ) +void mbedtls_ecp_read_key( int grp_id, data_t* in_key, int expected, int canonical ) { int ret = 0; mbedtls_ecp_keypair key; + mbedtls_ecp_keypair key2; mbedtls_ecp_keypair_init( &key ); + mbedtls_ecp_keypair_init( &key2 ); ret = mbedtls_ecp_read_key( grp_id, &key, in_key->x, in_key->len ); TEST_ASSERT( ret == expected ); @@ -1083,10 +1085,52 @@ void mbedtls_ecp_read_key( int grp_id, data_t* in_key, int expected ) { ret = mbedtls_ecp_check_privkey( &key.grp, &key.d ); TEST_ASSERT( ret == 0 ); + + if( canonical ) + { + unsigned char buf[MBEDTLS_ECP_MAX_BYTES]; + size_t olen; + + ret = mbedtls_ecp_write_key( grp_id, &key, &olen, buf, in_key->len ); + TEST_ASSERT( ret == 0 ); + + TEST_ASSERT( olen == in_key->len ); + + mbedtls_fprintf( stdout, "written key: "); + for( size_t i = 0; i < in_key->len; i++ ) { + mbedtls_fprintf( stdout, "%02x", buf[i]); + } + mbedtls_fprintf( stdout, "\n"); + ASSERT_COMPARE( in_key->x, in_key->len, + buf, olen ); + } + else + { + unsigned char export1[MBEDTLS_ECP_MAX_BYTES]; + size_t olen1; + + unsigned char export2[MBEDTLS_ECP_MAX_BYTES]; + size_t olen2; + + ret = mbedtls_ecp_write_key( grp_id, &key, &olen1, export1, in_key->len ); + TEST_ASSERT( ret == 0 ); + + ret = mbedtls_ecp_read_key( grp_id, &key2, export1, in_key->len ); + TEST_ASSERT( ret == expected ); + + ret = mbedtls_ecp_write_key( grp_id, &key2, &olen2, export2, in_key->len ); + TEST_ASSERT( ret == 0 ); + + TEST_ASSERT( olen2 == olen1 ); + + ASSERT_COMPARE( export1, olen1, + export2, olen2 ); + } } exit: mbedtls_ecp_keypair_free( &key ); + mbedtls_ecp_keypair_free( &key2 ); } /* END_CASE */