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.
diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h
index dad9aef..43d001c 100644
--- a/include/mbedtls/ecp.h
+++ b/include/mbedtls/ecp.h
@@ -501,6 +501,50 @@
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 5ad6863..851d230 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -2061,6 +2061,57 @@
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 a43e7d7..c165d18 100644
--- a/tests/suites/test_suite_ecp.data
+++ b/tests/suites/test_suite_ecp.data
@@ -30,6 +30,26 @@
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 99780c0..4b81090 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 @@
}
/* 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 )
{