Add EC_RAW_POINT serialization function.

This avoids some unnecessary EC_POINT allocations in the in-progress Trust
Tokens implementation.

Bug: chromium:1014199
Change-Id: I64e1fca61d111eacec02648e68972be30fd5a48f
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/40586
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/fipsmodule/ec/internal.h b/crypto/fipsmodule/ec/internal.h
index f98b1dd..2ac8b83 100644
--- a/crypto/fipsmodule/ec/internal.h
+++ b/crypto/fipsmodule/ec/internal.h
@@ -276,6 +276,12 @@
                                          uint8_t *out_y, size_t *out_len,
                                          size_t max_out, const EC_RAW_POINT *p);
 
+// ec_point_to_bytes behaves like |EC_POINT_point2oct| but takes an
+// |EC_RAW_POINT|.
+size_t ec_point_to_bytes(const EC_GROUP *group, const EC_RAW_POINT *point,
+                         point_conversion_form_t form, uint8_t *buf,
+                         size_t len);
+
 
 // Implementation details.
 
diff --git a/crypto/fipsmodule/ec/oct.c b/crypto/fipsmodule/ec/oct.c
index 04b1f2c..e8a98a7 100644
--- a/crypto/fipsmodule/ec/oct.c
+++ b/crypto/fipsmodule/ec/oct.c
@@ -73,10 +73,9 @@
 #include "internal.h"
 
 
-static size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
-                                      const EC_RAW_POINT *point,
-                                      point_conversion_form_t form,
-                                      uint8_t *buf, size_t len) {
+size_t ec_point_to_bytes(const EC_GROUP *group, const EC_RAW_POINT *point,
+                         point_conversion_form_t form, uint8_t *buf,
+                         size_t len) {
   if (form != POINT_CONVERSION_COMPRESSED &&
       form != POINT_CONVERSION_UNCOMPRESSED) {
     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FORM);
@@ -226,7 +225,7 @@
     OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
     return 0;
   }
-  return ec_GFp_simple_point2oct(group, &point->raw, form, buf, len);
+  return ec_point_to_bytes(group, &point->raw, form, buf, len);
 }
 
 int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
diff --git a/crypto/trust_token/privacy_pass.c b/crypto/trust_token/privacy_pass.c
index 84525ea..accb28a 100644
--- a/crypto/trust_token/privacy_pass.c
+++ b/crypto/trust_token/privacy_pass.c
@@ -141,7 +141,7 @@
 // |*out_pub| is set to the public half of the keypair. It returns one on
 // success and zero on failure.
 static int generate_keypair(EC_SCALAR *out_x, EC_SCALAR *out_y,
-                            EC_POINT **out_pub, const EC_GROUP *group) {
+                            EC_RAW_POINT *out_pub, const EC_GROUP *group) {
   EC_POINT *h = get_h();
   if (h == NULL) {
     return 0;
@@ -149,38 +149,46 @@
 
   static const uint8_t kDefaultAdditionalData[32] = {0};
   EC_RAW_POINT tmp1, tmp2;
-  EC_POINT *pub = EC_POINT_new(group);
-  if (pub == NULL ||
-      !ec_random_nonzero_scalar(group, out_x, kDefaultAdditionalData) ||
+  if (!ec_random_nonzero_scalar(group, out_x, kDefaultAdditionalData) ||
       !ec_random_nonzero_scalar(group, out_y, kDefaultAdditionalData) ||
       !ec_point_mul_scalar_base(group, &tmp1, out_x) ||
       !ec_point_mul_scalar(group, &tmp2, &h->raw, out_y)) {
     EC_POINT_free(h);
-    EC_POINT_free(pub);
     OPENSSL_PUT_ERROR(TRUST_TOKEN, ERR_R_MALLOC_FAILURE);
     return 0;
   }
-  group->meth->add(group, &pub->raw, &tmp1, &tmp2);
-  *out_pub = pub;
+  group->meth->add(group, out_pub, &tmp1, &tmp2);
 
   EC_POINT_free(h);
   return 1;
 }
 
+static int point_to_cbb(CBB *out, const EC_GROUP *group,
+                        const EC_RAW_POINT *point) {
+  size_t len =
+      ec_point_to_bytes(group, point, POINT_CONVERSION_UNCOMPRESSED, NULL, 0);
+  if (len == 0) {
+    return 0;
+  }
+  uint8_t *p;
+  return CBB_add_space(out, &p, len) &&
+         ec_point_to_bytes(group, point, POINT_CONVERSION_UNCOMPRESSED, p,
+                           len) == len;
+}
+
 int TRUST_TOKEN_generate_key(uint8_t *out_priv_key, size_t *out_priv_key_len,
                              size_t max_priv_key_len, uint8_t *out_pub_key,
                              size_t *out_pub_key_len, size_t max_pub_key_len,
                              uint32_t id) {
   int ok = 0;
-  EC_POINT *pub0 = NULL, *pub1 = NULL, *pubs = NULL;
   CBB cbb;
   CBB_zero(&cbb);
-  uint8_t *buf = NULL;
   EC_GROUP *group = EC_GROUP_new_by_curve_name(NID_secp521r1);
   if (group == NULL) {
     return 0;
   }
 
+  EC_RAW_POINT pub0, pub1, pubs;
   EC_SCALAR x0, y0, x1, y1, xs, ys;
   if (!generate_keypair(&x0, &y0, &pub0, group) ||
       !generate_keypair(&x1, &y1, &pub1, group) ||
@@ -198,6 +206,7 @@
 
   const EC_SCALAR *scalars[] = {&x0, &y0, &x1, &y1, &xs, &ys};
   for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(scalars); i++) {
+    uint8_t *buf;
     if (!CBB_add_space(&cbb, &buf, scalar_len)) {
       OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_BUFFER_TOO_SMALL);
       goto err;
@@ -214,14 +223,11 @@
   if (!CBB_init_fixed(&cbb, out_pub_key, max_pub_key_len) ||
       !CBB_add_u32(&cbb, id) ||
       !CBB_add_u16_length_prefixed(&cbb, &pub_cbb) ||
-      !EC_POINT_point2cbb(&pub_cbb, group, pub0, POINT_CONVERSION_UNCOMPRESSED,
-                          NULL) ||
+      !point_to_cbb(&pub_cbb, group, &pub0) ||
       !CBB_add_u16_length_prefixed(&cbb, &pub_cbb) ||
-      !EC_POINT_point2cbb(&pub_cbb, group, pub1, POINT_CONVERSION_UNCOMPRESSED,
-                          NULL) ||
+      !point_to_cbb(&pub_cbb, group, &pub1) ||
       !CBB_add_u16_length_prefixed(&cbb, &pub_cbb) ||
-      !EC_POINT_point2cbb(&pub_cbb, group, pubs, POINT_CONVERSION_UNCOMPRESSED,
-                          NULL) ||
+      !point_to_cbb(&pub_cbb, group, &pubs) ||
       !CBB_finish(&cbb, NULL, out_pub_key_len)) {
     OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_BUFFER_TOO_SMALL);
     goto err;
@@ -231,8 +237,5 @@
 
 err:
   CBB_cleanup(&cbb);
-  EC_POINT_free(pub0);
-  EC_POINT_free(pub1);
-  EC_POINT_free(pubs);
   return ok;
 }