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, ¶ms, CBS_ASN1_SEQUENCE) ||
223 !CBS_get_asn1_uint64(¶ms, &version) || //
224 version != 1 || //
225 !CBS_get_asn1(¶ms, &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(¶ms, &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(¶ms, &base, CBS_ASN1_OCTETSTRING) ||
240 !CBS_get_asn1(¶ms, &out->order, CBS_ASN1_INTEGER) ||
241 !CBS_is_unsigned_asn1_integer(&out->order) ||
242 !CBS_get_optional_asn1(¶ms, &cofactor, &has_cofactor,
243 CBS_ASN1_INTEGER) ||
244 CBS_len(¶ms) != 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(©) > 0 && CBS_data(©)[0] == 0) {
284 CBS_skip(©, 1);
285 }
286
287 if (CBS_len(©) > EC_MAX_BYTES) {
288 return 0;
289 }
290 uint8_t buf[EC_MAX_BYTES];
291 if (!BN_bn2bin_padded(buf, CBS_len(©), bn)) {
292 ERR_clear_error();
293 return 0;
294 }
295
296 return CBS_mem_equal(©, buf, CBS_len(©));
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