• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2002-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include <openssl/ec.h>
11 
12 #include <limits.h>
13 #include <string.h>
14 
15 #include <openssl/bn.h>
16 #include <openssl/bytestring.h>
17 #include <openssl/err.h>
18 #include <openssl/mem.h>
19 #include <openssl/nid.h>
20 
21 #include "../bytestring/internal.h"
22 #include "../fipsmodule/ec/internal.h"
23 #include "../internal.h"
24 
25 
26 static const CBS_ASN1_TAG kParametersTag =
27     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0;
28 static const CBS_ASN1_TAG kPublicKeyTag =
29     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
30 
31 // TODO(https://crbug.com/boringssl/497): Allow parsers to specify a list of
32 // acceptable groups, so parsers don't have to pull in all four.
33 typedef const EC_GROUP *(*ec_group_func)(void);
34 static const ec_group_func kAllGroups[] = {
35     &EC_group_p224,
36     &EC_group_p256,
37     &EC_group_p384,
38     &EC_group_p521,
39 };
40 
EC_KEY_parse_private_key(CBS * cbs,const EC_GROUP * group)41 EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
42   CBS ec_private_key, private_key;
43   uint64_t version;
44   if (!CBS_get_asn1(cbs, &ec_private_key, CBS_ASN1_SEQUENCE) ||
45       !CBS_get_asn1_uint64(&ec_private_key, &version) ||  //
46       version != 1 ||
47       !CBS_get_asn1(&ec_private_key, &private_key, CBS_ASN1_OCTETSTRING)) {
48     OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
49     return NULL;
50   }
51 
52   // Parse the optional parameters field.
53   EC_KEY *ret = NULL;
54   BIGNUM *priv_key = NULL;
55   if (CBS_peek_asn1_tag(&ec_private_key, kParametersTag)) {
56     // Per SEC 1, as an alternative to omitting it, one is allowed to specify
57     // this field and put in a NULL to mean inheriting this value. This was
58     // omitted in a previous version of this logic without problems, so leave it
59     // unimplemented.
60     CBS child;
61     if (!CBS_get_asn1(&ec_private_key, &child, kParametersTag)) {
62       OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
63       goto err;
64     }
65     const EC_GROUP *inner_group = EC_KEY_parse_parameters(&child);
66     if (inner_group == NULL) {
67       goto err;
68     }
69     if (group == NULL) {
70       group = inner_group;
71     } else if (EC_GROUP_cmp(group, inner_group, NULL) != 0) {
72       // If a group was supplied externally, it must match.
73       OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
74       goto err;
75     }
76     if (CBS_len(&child) != 0) {
77       OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
78       goto err;
79     }
80   }
81 
82   if (group == NULL) {
83     OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
84     goto err;
85   }
86 
87   ret = EC_KEY_new();
88   if (ret == NULL || !EC_KEY_set_group(ret, group)) {
89     goto err;
90   }
91 
92   // Although RFC 5915 specifies the length of the key, OpenSSL historically
93   // got this wrong, so accept any length. See upstream's
94   // 30cd4ff294252c4b6a4b69cbef6a5b4117705d22.
95   priv_key = BN_bin2bn(CBS_data(&private_key), CBS_len(&private_key), NULL);
96   ret->pub_key = EC_POINT_new(group);
97   if (priv_key == NULL || ret->pub_key == NULL ||
98       !EC_KEY_set_private_key(ret, priv_key)) {
99     goto err;
100   }
101 
102   if (CBS_peek_asn1_tag(&ec_private_key, kPublicKeyTag)) {
103     CBS child, public_key;
104     uint8_t padding;
105     if (!CBS_get_asn1(&ec_private_key, &child, kPublicKeyTag) ||
106         !CBS_get_asn1(&child, &public_key, CBS_ASN1_BITSTRING) ||
107         // As in a SubjectPublicKeyInfo, the byte-encoded public key is then
108         // encoded as a BIT STRING with bits ordered as in the DER encoding.
109         !CBS_get_u8(&public_key, &padding) ||  //
110         padding != 0 ||
111         // Explicitly check |public_key| is non-empty to save the conversion
112         // form later.
113         CBS_len(&public_key) == 0 ||
114         !EC_POINT_oct2point(group, ret->pub_key, CBS_data(&public_key),
115                             CBS_len(&public_key), NULL) ||
116         CBS_len(&child) != 0) {
117       OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
118       goto err;
119     }
120 
121     // Save the point conversion form.
122     // TODO(davidben): Consider removing this.
123     ret->conv_form =
124         (point_conversion_form_t)(CBS_data(&public_key)[0] & ~0x01);
125   } else {
126     // Compute the public key instead.
127     if (!ec_point_mul_scalar_base(group, &ret->pub_key->raw,
128                                   &ret->priv_key->scalar)) {
129       goto err;
130     }
131     // Remember the original private-key-only encoding.
132     // TODO(davidben): Consider removing this.
133     ret->enc_flag |= EC_PKEY_NO_PUBKEY;
134   }
135 
136   if (CBS_len(&ec_private_key) != 0) {
137     OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
138     goto err;
139   }
140 
141   // Ensure the resulting key is valid.
142   if (!EC_KEY_check_key(ret)) {
143     goto err;
144   }
145 
146   BN_free(priv_key);
147   return ret;
148 
149 err:
150   EC_KEY_free(ret);
151   BN_free(priv_key);
152   return NULL;
153 }
154 
EC_KEY_marshal_private_key(CBB * cbb,const EC_KEY * key,unsigned enc_flags)155 int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key,
156                                unsigned enc_flags) {
157   if (key == NULL || key->group == NULL || key->priv_key == NULL) {
158     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
159     return 0;
160   }
161 
162   CBB ec_private_key, private_key;
163   if (!CBB_add_asn1(cbb, &ec_private_key, CBS_ASN1_SEQUENCE) ||
164       !CBB_add_asn1_uint64(&ec_private_key, 1 /* version */) ||
165       !CBB_add_asn1(&ec_private_key, &private_key, CBS_ASN1_OCTETSTRING) ||
166       !BN_bn2cbb_padded(&private_key,
167                         BN_num_bytes(EC_GROUP_get0_order(key->group)),
168                         EC_KEY_get0_private_key(key))) {
169     OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR);
170     return 0;
171   }
172 
173   if (!(enc_flags & EC_PKEY_NO_PARAMETERS)) {
174     CBB child;
175     if (!CBB_add_asn1(&ec_private_key, &child, kParametersTag) ||
176         !EC_KEY_marshal_curve_name(&child, key->group) ||
177         !CBB_flush(&ec_private_key)) {
178       OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR);
179       return 0;
180     }
181   }
182 
183   // TODO(fork): replace this flexibility with sensible default?
184   if (!(enc_flags & EC_PKEY_NO_PUBKEY) && key->pub_key != NULL) {
185     CBB child, public_key;
186     if (!CBB_add_asn1(&ec_private_key, &child, kPublicKeyTag) ||
187         !CBB_add_asn1(&child, &public_key, CBS_ASN1_BITSTRING) ||
188         // As in a SubjectPublicKeyInfo, the byte-encoded public key is then
189         // encoded as a BIT STRING with bits ordered as in the DER encoding.
190         !CBB_add_u8(&public_key, 0 /* padding */) ||
191         !EC_POINT_point2cbb(&public_key, key->group, key->pub_key,
192                             key->conv_form, NULL) ||
193         !CBB_flush(&ec_private_key)) {
194       OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR);
195       return 0;
196     }
197   }
198 
199   if (!CBB_flush(cbb)) {
200     OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR);
201     return 0;
202   }
203 
204   return 1;
205 }
206 
207 // kPrimeFieldOID is the encoding of 1.2.840.10045.1.1.
208 static const uint8_t kPrimeField[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01};
209 
210 namespace {
211 struct explicit_prime_curve {
212   CBS prime, a, b, base_x, base_y, order;
213 };
214 }  // namespace
215 
parse_explicit_prime_curve(CBS * in,struct explicit_prime_curve * out)216 static int parse_explicit_prime_curve(CBS *in,
217                                       struct explicit_prime_curve *out) {
218   // See RFC 3279, section 2.3.5. Note that RFC 3279 calls this structure an
219   // ECParameters while RFC 5480 calls it a SpecifiedECDomain.
220   CBS params, field_id, field_type, curve, base, cofactor;
221   int has_cofactor;
222   uint64_t version;
223   if (!CBS_get_asn1(in, &params, CBS_ASN1_SEQUENCE) ||
224       !CBS_get_asn1_uint64(&params, &version) ||  //
225       version != 1 ||                             //
226       !CBS_get_asn1(&params, &field_id, CBS_ASN1_SEQUENCE) ||
227       !CBS_get_asn1(&field_id, &field_type, CBS_ASN1_OBJECT) ||
228       CBS_len(&field_type) != sizeof(kPrimeField) ||
229       OPENSSL_memcmp(CBS_data(&field_type), kPrimeField, sizeof(kPrimeField)) !=
230           0 ||
231       !CBS_get_asn1(&field_id, &out->prime, CBS_ASN1_INTEGER) ||
232       !CBS_is_unsigned_asn1_integer(&out->prime) ||  //
233       CBS_len(&field_id) != 0 ||
234       !CBS_get_asn1(&params, &curve, CBS_ASN1_SEQUENCE) ||
235       !CBS_get_asn1(&curve, &out->a, CBS_ASN1_OCTETSTRING) ||
236       !CBS_get_asn1(&curve, &out->b, CBS_ASN1_OCTETSTRING) ||
237       // |curve| has an optional BIT STRING seed which we ignore.
238       !CBS_get_optional_asn1(&curve, NULL, NULL, CBS_ASN1_BITSTRING) ||
239       CBS_len(&curve) != 0 ||
240       !CBS_get_asn1(&params, &base, CBS_ASN1_OCTETSTRING) ||
241       !CBS_get_asn1(&params, &out->order, CBS_ASN1_INTEGER) ||
242       !CBS_is_unsigned_asn1_integer(&out->order) ||
243       !CBS_get_optional_asn1(&params, &cofactor, &has_cofactor,
244                              CBS_ASN1_INTEGER) ||
245       CBS_len(&params) != 0) {
246     OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
247     return 0;
248   }
249 
250   if (has_cofactor) {
251     // We only support prime-order curves so the cofactor must be one.
252     if (CBS_len(&cofactor) != 1 ||  //
253         CBS_data(&cofactor)[0] != 1) {
254       OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
255       return 0;
256     }
257   }
258 
259   // Require that the base point use uncompressed form.
260   uint8_t form;
261   if (!CBS_get_u8(&base, &form) || form != POINT_CONVERSION_UNCOMPRESSED) {
262     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FORM);
263     return 0;
264   }
265 
266   if (CBS_len(&base) % 2 != 0) {
267     OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
268     return 0;
269   }
270   size_t field_len = CBS_len(&base) / 2;
271   CBS_init(&out->base_x, CBS_data(&base), field_len);
272   CBS_init(&out->base_y, CBS_data(&base) + field_len, field_len);
273 
274   return 1;
275 }
276 
277 // integers_equal returns one if |bytes| is a big-endian encoding of |bn|, and
278 // zero otherwise.
integers_equal(const CBS * bytes,const BIGNUM * bn)279 static int integers_equal(const CBS *bytes, const BIGNUM *bn) {
280   // Although, in SEC 1, Field-Element-to-Octet-String has a fixed width,
281   // OpenSSL mis-encodes the |a| and |b|, so we tolerate any number of leading
282   // zeros. (This matters for P-521 whose |b| has a leading 0.)
283   CBS copy = *bytes;
284   while (CBS_len(&copy) > 0 && CBS_data(&copy)[0] == 0) {
285     CBS_skip(&copy, 1);
286   }
287 
288   if (CBS_len(&copy) > EC_MAX_BYTES) {
289     return 0;
290   }
291   uint8_t buf[EC_MAX_BYTES];
292   if (!BN_bn2bin_padded(buf, CBS_len(&copy), bn)) {
293     ERR_clear_error();
294     return 0;
295   }
296 
297   return CBS_mem_equal(&copy, buf, CBS_len(&copy));
298 }
299 
EC_KEY_parse_curve_name(CBS * cbs)300 EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs) {
301   CBS named_curve;
302   if (!CBS_get_asn1(cbs, &named_curve, CBS_ASN1_OBJECT)) {
303     OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
304     return NULL;
305   }
306 
307   // Look for a matching curve.
308   for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kAllGroups); i++) {
309     const EC_GROUP *group = kAllGroups[i]();
310     if (CBS_mem_equal(&named_curve, group->oid, group->oid_len)) {
311       return (EC_GROUP *)group;
312     }
313   }
314 
315   OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
316   return NULL;
317 }
318 
EC_KEY_marshal_curve_name(CBB * cbb,const EC_GROUP * group)319 int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group) {
320   if (group->oid_len == 0) {
321     OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
322     return 0;
323   }
324 
325   CBB child;
326   return CBB_add_asn1(cbb, &child, CBS_ASN1_OBJECT) &&
327          CBB_add_bytes(&child, group->oid, group->oid_len) &&  //
328          CBB_flush(cbb);
329 }
330 
EC_KEY_parse_parameters(CBS * cbs)331 EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) {
332   if (!CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) {
333     return EC_KEY_parse_curve_name(cbs);
334   }
335 
336   // OpenSSL sometimes produces ECPrivateKeys with explicitly-encoded versions
337   // of named curves.
338   //
339   // TODO(davidben): Remove support for this.
340   struct explicit_prime_curve curve;
341   if (!parse_explicit_prime_curve(cbs, &curve)) {
342     return NULL;
343   }
344 
345   const EC_GROUP *ret = NULL;
346   BIGNUM *p = BN_new(), *a = BN_new(), *b = BN_new(), *x = BN_new(),
347          *y = BN_new();
348   if (p == NULL || a == NULL || b == NULL || x == NULL || y == NULL) {
349     goto err;
350   }
351 
352   for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kAllGroups); i++) {
353     const EC_GROUP *group = kAllGroups[i]();
354     if (!integers_equal(&curve.order, EC_GROUP_get0_order(group))) {
355       continue;
356     }
357 
358     // The order alone uniquely identifies the group, but we check the other
359     // parameters to avoid misinterpreting the group.
360     if (!EC_GROUP_get_curve_GFp(group, p, a, b, NULL)) {
361       goto err;
362     }
363     if (!integers_equal(&curve.prime, p) || !integers_equal(&curve.a, a) ||
364         !integers_equal(&curve.b, b)) {
365       break;
366     }
367     if (!EC_POINT_get_affine_coordinates_GFp(
368             group, EC_GROUP_get0_generator(group), x, y, NULL)) {
369       goto err;
370     }
371     if (!integers_equal(&curve.base_x, x) ||
372         !integers_equal(&curve.base_y, y)) {
373       break;
374     }
375     ret = group;
376     break;
377   }
378 
379   if (ret == NULL) {
380     OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
381   }
382 
383 err:
384   BN_free(p);
385   BN_free(a);
386   BN_free(b);
387   BN_free(x);
388   BN_free(y);
389   return (EC_GROUP *)ret;
390 }
391 
EC_POINT_point2cbb(CBB * out,const EC_GROUP * group,const EC_POINT * point,point_conversion_form_t form,BN_CTX * ctx)392 int EC_POINT_point2cbb(CBB *out, const EC_GROUP *group, const EC_POINT *point,
393                        point_conversion_form_t form, BN_CTX *ctx) {
394   size_t len = EC_POINT_point2oct(group, point, form, NULL, 0, ctx);
395   if (len == 0) {
396     return 0;
397   }
398   uint8_t *p;
399   return CBB_add_space(out, &p, len) &&
400          EC_POINT_point2oct(group, point, form, p, len, ctx) == len;
401 }
402 
d2i_ECPrivateKey(EC_KEY ** out,const uint8_t ** inp,long len)403 EC_KEY *d2i_ECPrivateKey(EC_KEY **out, const uint8_t **inp, long len) {
404   // This function treats its |out| parameter differently from other |d2i|
405   // functions. If supplied, take the group from |*out|.
406   const EC_GROUP *group = NULL;
407   if (out != NULL && *out != NULL) {
408     group = EC_KEY_get0_group(*out);
409   }
410 
411   if (len < 0) {
412     OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
413     return NULL;
414   }
415   CBS cbs;
416   CBS_init(&cbs, *inp, (size_t)len);
417   EC_KEY *ret = EC_KEY_parse_private_key(&cbs, group);
418   if (ret == NULL) {
419     return NULL;
420   }
421   if (out != NULL) {
422     EC_KEY_free(*out);
423     *out = ret;
424   }
425   *inp = CBS_data(&cbs);
426   return ret;
427 }
428 
i2d_ECPrivateKey(const EC_KEY * key,uint8_t ** outp)429 int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp) {
430   CBB cbb;
431   if (!CBB_init(&cbb, 0) ||
432       !EC_KEY_marshal_private_key(&cbb, key, EC_KEY_get_enc_flags(key))) {
433     CBB_cleanup(&cbb);
434     return -1;
435   }
436   return CBB_finish_i2d(&cbb, outp);
437 }
438 
d2i_ECPKParameters(EC_GROUP ** out,const uint8_t ** inp,long len)439 EC_GROUP *d2i_ECPKParameters(EC_GROUP **out, const uint8_t **inp, long len) {
440   if (len < 0) {
441     return NULL;
442   }
443 
444   CBS cbs;
445   CBS_init(&cbs, *inp, (size_t)len);
446   EC_GROUP *ret = EC_KEY_parse_parameters(&cbs);
447   if (ret == NULL) {
448     return NULL;
449   }
450 
451   if (out != NULL) {
452     EC_GROUP_free(*out);
453     *out = ret;
454   }
455   *inp = CBS_data(&cbs);
456   return ret;
457 }
458 
i2d_ECPKParameters(const EC_GROUP * group,uint8_t ** outp)459 int i2d_ECPKParameters(const EC_GROUP *group, uint8_t **outp) {
460   if (group == NULL) {
461     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
462     return -1;
463   }
464 
465   CBB cbb;
466   if (!CBB_init(&cbb, 0) ||  //
467       !EC_KEY_marshal_curve_name(&cbb, group)) {
468     CBB_cleanup(&cbb);
469     return -1;
470   }
471   return CBB_finish_i2d(&cbb, outp);
472 }
473 
d2i_ECParameters(EC_KEY ** out_key,const uint8_t ** inp,long len)474 EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, long len) {
475   if (len < 0) {
476     return NULL;
477   }
478 
479   CBS cbs;
480   CBS_init(&cbs, *inp, (size_t)len);
481   const EC_GROUP *group = EC_KEY_parse_parameters(&cbs);
482   if (group == NULL) {
483     return NULL;
484   }
485 
486   EC_KEY *ret = EC_KEY_new();
487   if (ret == NULL || !EC_KEY_set_group(ret, group)) {
488     EC_KEY_free(ret);
489     return NULL;
490   }
491 
492   if (out_key != NULL) {
493     EC_KEY_free(*out_key);
494     *out_key = ret;
495   }
496   *inp = CBS_data(&cbs);
497   return ret;
498 }
499 
i2d_ECParameters(const EC_KEY * key,uint8_t ** outp)500 int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) {
501   if (key == NULL || key->group == NULL) {
502     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
503     return -1;
504   }
505 
506   CBB cbb;
507   if (!CBB_init(&cbb, 0) ||  //
508       !EC_KEY_marshal_curve_name(&cbb, key->group)) {
509     CBB_cleanup(&cbb);
510     return -1;
511   }
512   return CBB_finish_i2d(&cbb, outp);
513 }
514 
o2i_ECPublicKey(EC_KEY ** keyp,const uint8_t ** inp,long len)515 EC_KEY *o2i_ECPublicKey(EC_KEY **keyp, const uint8_t **inp, long len) {
516   EC_KEY *ret = NULL;
517 
518   if (keyp == NULL || *keyp == NULL || (*keyp)->group == NULL) {
519     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
520     return NULL;
521   }
522   ret = *keyp;
523   if (ret->pub_key == NULL &&
524       (ret->pub_key = EC_POINT_new(ret->group)) == NULL) {
525     return NULL;
526   }
527   if (!EC_POINT_oct2point(ret->group, ret->pub_key, *inp, len, NULL)) {
528     OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
529     return NULL;
530   }
531   // save the point conversion form
532   ret->conv_form = (point_conversion_form_t)(*inp[0] & ~0x01);
533   *inp += len;
534   return ret;
535 }
536 
i2o_ECPublicKey(const EC_KEY * key,uint8_t ** outp)537 int i2o_ECPublicKey(const EC_KEY *key, uint8_t **outp) {
538   if (key == NULL) {
539     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
540     return 0;
541   }
542   CBB cbb;
543   if (!CBB_init(&cbb, 0) ||  //
544       !EC_POINT_point2cbb(&cbb, key->group, key->pub_key, key->conv_form,
545                           NULL)) {
546     CBB_cleanup(&cbb);
547     return -1;
548   }
549   int ret = CBB_finish_i2d(&cbb, outp);
550   // Historically, this function used the wrong return value on error.
551   return ret > 0 ? ret : 0;
552 }
553 
EC_get_builtin_curves(EC_builtin_curve * out_curves,size_t max_num_curves)554 size_t EC_get_builtin_curves(EC_builtin_curve *out_curves,
555                              size_t max_num_curves) {
556   if (max_num_curves > OPENSSL_ARRAY_SIZE(kAllGroups)) {
557     max_num_curves = OPENSSL_ARRAY_SIZE(kAllGroups);
558   }
559   for (size_t i = 0; i < max_num_curves; i++) {
560     const EC_GROUP *group = kAllGroups[i]();
561     out_curves[i].nid = group->curve_name;
562     out_curves[i].comment = group->comment;
563   }
564   return OPENSSL_ARRAY_SIZE(kAllGroups);
565 }
566