Support partial export from mbedtls_ecp_keypair

Sometimes you don't need to have all the parts of a key pair object. Relax
the behavior of mbedtls_ecp_keypair so that you can extract just the parts
that you need.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/include/mbedtls/ecp.h b/include/mbedtls/ecp.h
index a29a6f7..9effb72 100644
--- a/include/mbedtls/ecp.h
+++ b/include/mbedtls/ecp.h
@@ -1338,13 +1338,16 @@
 /**
  * \brief           This function exports generic key-pair parameters.
  *
+ *                  Each of the output parameters can be a null pointer
+ *                  if you do not need that parameter.
+ *
  * \param key       The key pair to export from.
  * \param grp       Slot for exported ECP group.
- *                  It must point to an initialized ECP group.
+ *                  It must either be null or point to an initialized ECP group.
  * \param d         Slot for the exported secret value.
- *                  It must point to an initialized mpi.
+ *                  It must either be null or point to an initialized mpi.
  * \param Q         Slot for the exported public value.
- *                  It must point to an initialized ECP point.
+ *                  It must either be null or point to an initialized ECP point.
  *
  * \return          \c 0 on success,
  * \return          #MBEDTLS_ERR_MPI_ALLOC_FAILED on memory-allocation failure.
diff --git a/library/ecp.c b/library/ecp.c
index 351e9e8..b4da3c5 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -3371,15 +3371,15 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
 
-    if ((ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) {
+    if (grp != NULL && (ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) {
         return ret;
     }
 
-    if ((ret = mbedtls_mpi_copy(d, &key->d)) != 0) {
+    if (d != NULL && (ret = mbedtls_mpi_copy(d, &key->d)) != 0) {
         return ret;
     }
 
-    if ((ret = mbedtls_ecp_copy(Q, &key->Q)) != 0) {
+    if (Q != NULL && (ret = mbedtls_ecp_copy(Q, &key->Q)) != 0) {
         return ret;
     }
 
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index 58d54ed..a4c86e2 100644
--- a/tests/suites/test_suite_ecp.function
+++ b/tests/suites/test_suite_ecp.function
@@ -1239,6 +1239,20 @@
         /* Check consistency with the group id */
         TEST_EQUAL(export_grp.id,
                    mbedtls_ecp_keypair_get_group_id(&key));
+
+        /* Test null arguments */
+        mbedtls_ecp_group_free(&export_grp);
+        mbedtls_mpi_free(&export_d);
+        mbedtls_ecp_point_free(&export_Q);
+        mbedtls_ecp_group_init(&export_grp);
+        mbedtls_mpi_init(&export_d);
+        mbedtls_ecp_point_init(&export_Q);
+        TEST_EQUAL(mbedtls_ecp_export(&key, &export_grp, NULL, NULL), 0);
+        TEST_EQUAL(mbedtls_ecp_group_cmp(&key.grp, &export_grp), 0);
+        TEST_EQUAL(mbedtls_ecp_export(&key, NULL, &export_d, NULL), 0);
+        TEST_EQUAL(mbedtls_mpi_cmp_mpi(&key.d, &export_d), 0);
+        TEST_EQUAL(mbedtls_ecp_export(&key, NULL, NULL, &export_Q), 0);
+        TEST_EQUAL(mbedtls_ecp_point_cmp(&key.Q, &export_Q), 0);
     }
 
 exit: