From 420d7d9cbd8ffe6a7be0b0de3bc5716ddd592104 Mon Sep 17 00:00:00 2001 From: Gilles Peskine Date: Fri, 10 Nov 2017 15:21:12 +0100 Subject: [PATCH] ECP: Write RFC5480 representation of a group/point New functions to write a representation of an elliptic curve group and point according to X9.62 and RFC5480: ECParameters as OID and ECPoint as octet string. --- include/mbedtls/ecp.h | 44 +++++++++++++++++++++ library/ecp.c | 51 ++++++++++++++++++++++++ tests/suites/test_suite_ecp.data | 20 ++++++++++ tests/suites/test_suite_ecp.function | 58 ++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+) diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h index dad9aef00..43d001ce2 100644 --- a/include/mbedtls/ecp.h +++ b/include/mbedtls/ecp.h @@ -501,6 +501,50 @@ int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **bu int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, unsigned char *buf, size_t blen ); +#if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) +/** + * \brief Maximum size of the output of mbedtls_ecp_ansi_write_group + */ +#define MBEDTLS_OID_EC_GRP_MAX_SIZE 12 + +/** + * \brief Write the ANSI X9.62/RFC5480 OID ECParameters of a group + * + * The output is the group's OID wrapped as ASN.1. + * + * \param grp ECP group used + * \param buf Buffer to write to + * \param size Buffer size + * + * \return Number of bytes written to \c buf, + * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * or \c MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, + unsigned char *p, size_t size ); + +/** + * \brief Export a point in ANSI X9.62/RFC5480 ECPoint + * + * The output is the point wrapped as an ASN.1 octet string + * as defined in X9.62 and RFC 5480. + * + * \param ec ECP public key or key pair + * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro + * \param p Buffer to write to + * \param size Buffer size + * + * \return Number of bytes written to \c buf, + * or \c MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + * or \c MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or \c MBEDTLS_ERR_ASN1_BUF_TOO_SMALL + */ +int mbedtls_ecp_ansi_write_point( const mbedtls_ecp_keypair *ec, + int format, + unsigned char *p, + size_t size ); +#endif /* defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) */ + /** * \brief Multiplication by an integer: R = m * P * (Not thread-safe to use same group in multiple threads) diff --git a/library/ecp.c b/library/ecp.c index 5ad686398..851d230d8 100644 --- a/library/ecp.c +++ b/library/ecp.c @@ -2061,6 +2061,57 @@ cleanup: return( ret ); } +#if defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" +int mbedtls_ecp_ansi_write_group( const mbedtls_ecp_group *grp, + unsigned char *p, + size_t size ) +{ + const char *oid; + unsigned char *q; + size_t oid_length; + int ret; + ret = mbedtls_oid_get_oid_by_ec_grp( grp->id, &oid, &oid_length ); + if( ret != 0 ) + return( ret ); + // Output is a TLV with len(T)=1, len(L)=1, V=OID + if( size < 2 + oid_length ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + q = p + 2 + oid_length; + return( mbedtls_asn1_write_oid( &q, p, oid, oid_length ) ); +} + +int mbedtls_ecp_ansi_write_point( const mbedtls_ecp_keypair *ec, + int format, + unsigned char *p, + size_t size ) +{ + unsigned char *q; + size_t length; + size_t tl_size = 3; /* room for the OCTET_STRING tag and length */ + int ret; + if( size < tl_size ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + q = p + tl_size; + ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q, + format, + &length, q, size - 3 ); + if( ret < 0 ) + return( ret ); + ret = mbedtls_asn1_write_len( &q, p, length ); + if( ret < 0 ) + return( ret ); + ret = mbedtls_asn1_write_tag( &q, p, MBEDTLS_ASN1_OCTET_STRING ); + if( ret < 0 ) + return( ret ); + length += tl_size - ( q - p ); + if( q != p ) + memmove( p, q, length ); + return( length ); +} +#endif /* defined(MBEDTLS_ASN1_WRITE_C) && defined(MBEDTLS_OID_C) */ + #if defined(MBEDTLS_SELF_TEST) /* diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data index a43e7d75d..c165d1889 100644 --- a/tests/suites/test_suite_ecp.data +++ b/tests/suites/test_suite_ecp.data @@ -30,6 +30,26 @@ ECP curve info #8 depends_on:MBEDTLS_ECP_DP_SECP192R1_ENABLED mbedtls_ecp_curve_info:MBEDTLS_ECP_DP_SECP192R1:19:192:"secp192r1" +ECP write ECParameters OID secp192r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_SECP192R1:"06082a8648ce3d030101" + +ECP write ECParameters OID secp521r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_SECP521R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_SECP521R1:"06052b81040023" + +ECP write ECParameters OID brainpoolP512r1 +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_ECP_DP_BP512R1_ENABLED +ecp_ansi_write_group:MBEDTLS_ECP_DP_BP512R1:"06092b240303020801010d" + +ECP write ECPoint octet string (uncompressed) +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_point:"data_files/ec_pub.der":MBEDTLS_ECP_PF_UNCOMPRESSED:"043104bc797db3ae7f08ec3d496b4fb411b3f620a558a501e0222d08cfe0dc8aec8b1a7bf24be92951cc5ba1bebb2474909ae0" + +ECP write ECPoint octet string (compressed) +depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_ECP_DP_SECP192R1_ENABLED +ecp_ansi_write_point:"data_files/ec_pub.der":MBEDTLS_ECP_PF_COMPRESSED:"041902bc797db3ae7f08ec3d496b4fb411b3f620a558a501e0222d" + ECP check pubkey Montgomery #1 (too big) depends_on:MBEDTLS_ECP_DP_CURVE25519_ENABLED ecp_check_pub:MBEDTLS_ECP_DP_CURVE25519:"010000000000000000000000000000000000000000000000000000000000000000":"0":"1":MBEDTLS_ERR_ECP_INVALID_KEY diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function index 99780c0de..4b8109023 100644 --- a/tests/suites/test_suite_ecp.function +++ b/tests/suites/test_suite_ecp.function @@ -1,5 +1,6 @@ /* BEGIN_HEADER */ #include "mbedtls/ecp.h" +#include "mbedtls/pk.h" #define ECP_PF_UNKNOWN -1 /* END_HEADER */ @@ -412,6 +413,63 @@ exit: } /* END_CASE */ +/* BEGIN_CASE depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C */ +void ecp_ansi_write_group( int id, char *hex ) +{ + mbedtls_ecp_group grp; + unsigned char good[MBEDTLS_OID_EC_GRP_MAX_SIZE]; + unsigned char tested[MBEDTLS_OID_EC_GRP_MAX_SIZE]; + size_t good_len = unhexify( good, hex ); + int ret = 0; + mbedtls_ecp_group_init( &grp ); + TEST_ASSERT( mbedtls_ecp_group_load( &grp, id ) == 0 ); + + /* Positive test */ + ret = mbedtls_ecp_ansi_write_group( &grp, tested, sizeof( tested ) ); + TEST_ASSERT( ret >= 0 && good_len == (unsigned) ret ); + TEST_ASSERT( memcmp( good, tested, good_len ) == 0 ); + + /* Buffer too small */ + TEST_ASSERT( mbedtls_ecp_ansi_write_group( &grp, tested, good_len - 1 ) == + MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + +exit: + mbedtls_ecp_group_free( &grp ); +} +/* END_CASE */ + +/* BEGIN_CASE depends_on:MBEDTLS_ASN1_WRITE_C:MBEDTLS_OID_C:MBEDTLS_PK_PARSE_C:MBEDTLS_FS_IO */ +void ecp_ansi_write_point( char *key_file, int format, char *good_hex ) +{ + unsigned char good_buf[1000]; + unsigned char tested_buf[1000]; + size_t good_len = unhexify( good_buf, good_hex ); + mbedtls_pk_context pk; + int ret = 0; + mbedtls_pk_init( &pk ); + TEST_ASSERT( mbedtls_pk_parse_public_keyfile( &pk, key_file ) == 0 ); + + /* Positive test */ + ret = mbedtls_ecp_ansi_write_point( mbedtls_pk_ec( pk ), format, + tested_buf, sizeof( tested_buf ) ); + TEST_ASSERT( ret >= 0 && good_len == (unsigned) ret ); + TEST_ASSERT( memcmp( good_buf, tested_buf, good_len ) == 0 ); + + /* Buffer too small */ + TEST_ASSERT( mbedtls_ecp_ansi_write_point( mbedtls_pk_ec( pk ), format, + tested_buf, good_len - 1 ) == + MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + +exit: + if( ret >= 0 ) { + unsigned char out[999] = {0}; + hexify( out, tested_buf, ret ); + printf("== %s ==\n", out); + } + mbedtls_pk_free( &pk ); +} +/* END_CASE */ + /* BEGIN_CASE */ void mbedtls_ecp_check_privkey( int id, char *key_hex, int ret ) {