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