New function mbedtls_ecp_write_public_key

Directly export the public part of a key pair without having to go through
intermediate objects (using mbedtls_ecp_point_write_binary would require a
group object and a point object).

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h
index fc0a763..619a8a5 100644
--- a/include/mbedtls/ecp.h
+++ b/include/mbedtls/ecp.h
@@ -1347,6 +1347,32 @@
                           unsigned char *buf, size_t buflen);
 
 /**
+ * \brief           This function exports an elliptic curve public key.
+ *
+ * \param key       The public key.
+ * \param format    The point format. This must be either
+ *                  #MBEDTLS_ECP_PF_COMPRESSED or #MBEDTLS_ECP_PF_UNCOMPRESSED.
+ *                  (For groups without these formats, this parameter is
+ *                  ignored. But it still has to be either of the above
+ *                  values.)
+ * \param olen      The address at which to store the length of
+ *                  the output in Bytes. This must not be \c NULL.
+ * \param buf       The output buffer. This must be a writable buffer
+ *                  of length \p buflen Bytes.
+ * \param buflen    The length of the output buffer \p buf in Bytes.
+ *
+ * \return          \c 0 on success.
+ * \return          #MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL if the output buffer
+ *                  is too small to hold the point.
+ * \return          #MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format
+ *                  or the export for the given group is not implemented.
+ * \return          Another negative error code on other kinds of failure.
+ */
+int mbedtls_ecp_write_public_key(mbedtls_ecp_keypair *key,
+                                 int format, 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
  *                  same public point, and that the private key in
diff --git a/library/ecp.c b/library/ecp.c
index 43f7d69..12924bf 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -3333,6 +3333,18 @@
     return ret;
 }
 
+/*
+ * Write a public key.
+ */
+int mbedtls_ecp_write_public_key(mbedtls_ecp_keypair *key,
+                                 int format, size_t *olen,
+                                 unsigned char *buf, size_t buflen)
+{
+    return mbedtls_ecp_point_write_binary(&key->grp, &key->Q,
+                                          format, olen, buf, buflen);
+}
+
+
 #if defined(MBEDTLS_ECP_C)
 /*
  * Check a public-private key pair
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index 354a92c..ced4ca3 100644
--- a/tests/suites/test_suite_ecp.function
+++ b/tests/suites/test_suite_ecp.function
@@ -590,29 +590,41 @@
 {
     mbedtls_ecp_group grp;
     mbedtls_ecp_point P;
+    mbedtls_ecp_keypair key;
     unsigned char buf[256];
     size_t olen;
 
     memset(buf, 0, sizeof(buf));
 
     mbedtls_ecp_group_init(&grp); mbedtls_ecp_point_init(&P);
+    mbedtls_ecp_keypair_init(&key);
 
-    TEST_ASSERT(mbedtls_ecp_group_load(&grp, id) == 0);
+    TEST_EQUAL(mbedtls_ecp_group_load(&grp, id), 0);
 
-    TEST_ASSERT(mbedtls_test_read_mpi(&P.X, x) == 0);
-    TEST_ASSERT(mbedtls_test_read_mpi(&P.Y, y) == 0);
-    TEST_ASSERT(mbedtls_test_read_mpi(&P.Z, z) == 0);
+    TEST_EQUAL(mbedtls_test_read_mpi(&P.X, x), 0);
+    TEST_EQUAL(mbedtls_test_read_mpi(&P.Y, y), 0);
+    TEST_EQUAL(mbedtls_test_read_mpi(&P.Z, z), 0);
 
-    TEST_ASSERT(mbedtls_ecp_point_write_binary(&grp, &P, format,
-                                               &olen, buf, blen) == ret);
-
+    TEST_EQUAL(mbedtls_ecp_point_write_binary(&grp, &P, format,
+                                              &olen, buf, blen), ret);
     if (ret == 0) {
-        TEST_ASSERT(olen <= MBEDTLS_ECP_MAX_PT_LEN);
-        TEST_ASSERT(mbedtls_test_hexcmp(buf, out->x, olen, out->len) == 0);
+        TEST_LE_U(olen, MBEDTLS_ECP_MAX_PT_LEN);
+        ASSERT_COMPARE(buf, olen,
+                       out->x, out->len);
+    }
+
+    memset(buf, 0, blen);
+    TEST_EQUAL(mbedtls_ecp_set_public_key(grp.id, &key, &P), 0);
+    TEST_EQUAL(mbedtls_ecp_write_public_key(&key, format,
+                                            &olen, buf, blen), ret);
+    if (ret == 0) {
+        ASSERT_COMPARE(buf, olen,
+                       out->x, out->len);
     }
 
 exit:
     mbedtls_ecp_group_free(&grp); mbedtls_ecp_point_free(&P);
+    mbedtls_ecp_keypair_free(&key);
 }
 /* END_CASE */