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