/src/boringssl/crypto/ec/ec_asn1.cc
Line | Count | Source |
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 <algorithm> |
21 | | #include <array> |
22 | | |
23 | | #include <openssl/bn.h> |
24 | | #include <openssl/bytestring.h> |
25 | | #include <openssl/ec_key.h> |
26 | | #include <openssl/err.h> |
27 | | #include <openssl/mem.h> |
28 | | #include <openssl/nid.h> |
29 | | |
30 | | #include "../bytestring/internal.h" |
31 | | #include "../fipsmodule/ec/internal.h" |
32 | | #include "../internal.h" |
33 | | #include "../mem_internal.h" |
34 | | #include "internal.h" |
35 | | |
36 | | |
37 | | using namespace bssl; |
38 | | |
39 | | static const CBS_ASN1_TAG kParametersTag = |
40 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0; |
41 | | static const CBS_ASN1_TAG kPublicKeyTag = |
42 | | CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1; |
43 | | |
44 | 1.74k | static auto get_all_groups() { |
45 | 1.74k | return std::array{ |
46 | 1.74k | EC_group_p224(), |
47 | 1.74k | EC_group_p256(), |
48 | 1.74k | EC_group_p384(), |
49 | 1.74k | EC_group_p521(), |
50 | 1.74k | }; |
51 | 1.74k | } |
52 | | |
53 | | EC_KEY *bssl::ec_key_parse_private_key( |
54 | | CBS *cbs, const EC_GROUP *group, |
55 | 4.61k | Span<const EC_GROUP *const> allowed_groups) { |
56 | | // If a group was supplied externally, no other groups can be parsed. |
57 | 4.61k | if (group != nullptr) { |
58 | 2.86k | allowed_groups = Span(&group, 1); |
59 | 2.86k | } |
60 | | |
61 | 4.61k | CBS ec_private_key, private_key; |
62 | 4.61k | uint64_t version; |
63 | 4.61k | if (!CBS_get_asn1(cbs, &ec_private_key, CBS_ASN1_SEQUENCE) || |
64 | 4.59k | !CBS_get_asn1_uint64(&ec_private_key, &version) || // |
65 | 4.58k | version != 1 || |
66 | 4.22k | !CBS_get_asn1(&ec_private_key, &private_key, CBS_ASN1_OCTETSTRING)) { |
67 | 394 | OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); |
68 | 394 | return nullptr; |
69 | 394 | } |
70 | | |
71 | | // Parse the optional parameters field. |
72 | 4.21k | if (CBS_peek_asn1_tag(&ec_private_key, kParametersTag)) { |
73 | | // Per SEC 1, as an alternative to omitting it, one is allowed to specify |
74 | | // this field and put in a NULL to mean inheriting this value. This was |
75 | | // omitted in a previous version of this logic without problems, so leave it |
76 | | // unimplemented. |
77 | 1.67k | CBS child; |
78 | 1.67k | if (!CBS_get_asn1(&ec_private_key, &child, kParametersTag)) { |
79 | 8 | OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); |
80 | 8 | return nullptr; |
81 | 8 | } |
82 | 1.66k | const EC_GROUP *inner_group = |
83 | 1.66k | ec_key_parse_parameters(&child, allowed_groups); |
84 | 1.66k | if (inner_group == nullptr) { |
85 | | // If the caller already supplied a group, any explicit group is required |
86 | | // to match. On mismatch, `ec_key_parse_parameters` will fail to recognize |
87 | | // any other groups, so remap the error. |
88 | 697 | if (group != nullptr && |
89 | 166 | ERR_equals(ERR_peek_last_error(), ERR_LIB_EC, EC_R_UNKNOWN_GROUP)) { |
90 | 31 | ERR_clear_error(); |
91 | 31 | OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH); |
92 | 31 | } |
93 | 697 | return nullptr; |
94 | 697 | } |
95 | | // Overriding `allowed_groups` above ensures the only returned group will be |
96 | | // the matching one. |
97 | 1.66k | assert(group == nullptr || inner_group == group); |
98 | 969 | group = inner_group; |
99 | 969 | if (CBS_len(&child) != 0) { |
100 | 12 | OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); |
101 | 12 | return nullptr; |
102 | 12 | } |
103 | 969 | } |
104 | | |
105 | | // The group must have been specified either externally, or explicitly in the |
106 | | // structure. |
107 | 3.50k | if (group == nullptr) { |
108 | 103 | OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS); |
109 | 103 | return nullptr; |
110 | 103 | } |
111 | | |
112 | 3.39k | UniquePtr<ECKey> ret(FromOpaque(EC_KEY_new())); |
113 | 3.39k | if (ret == nullptr || !EC_KEY_set_group(ret.get(), group)) { |
114 | 0 | return nullptr; |
115 | 0 | } |
116 | | |
117 | | // Although RFC 5915 specifies the length of the key, OpenSSL historically |
118 | | // got this wrong, so accept any length. See upstream's |
119 | | // 30cd4ff294252c4b6a4b69cbef6a5b4117705d22. |
120 | 3.39k | UniquePtr<BIGNUM> priv_key( |
121 | 3.39k | BN_bin2bn(CBS_data(&private_key), CBS_len(&private_key), nullptr)); |
122 | 3.39k | ret->pub_key = EC_POINT_new(group); |
123 | 3.39k | if (priv_key == nullptr || ret->pub_key == nullptr || |
124 | 3.39k | !EC_KEY_set_private_key(ret.get(), priv_key.get())) { |
125 | 286 | return nullptr; |
126 | 286 | } |
127 | | |
128 | 3.11k | if (CBS_peek_asn1_tag(&ec_private_key, kPublicKeyTag)) { |
129 | 1.88k | CBS child, public_key; |
130 | 1.88k | uint8_t padding; |
131 | 1.88k | if (!CBS_get_asn1(&ec_private_key, &child, kPublicKeyTag) || |
132 | 1.87k | !CBS_get_asn1(&child, &public_key, CBS_ASN1_BITSTRING) || |
133 | | // As in a SubjectPublicKeyInfo, the byte-encoded public key is then |
134 | | // encoded as a BIT STRING with bits ordered as in the DER encoding. |
135 | 1.87k | !CBS_get_u8(&public_key, &padding) || // |
136 | 1.86k | padding != 0 || |
137 | | // Explicitly check `public_key` is non-empty to save the conversion |
138 | | // form later. |
139 | 1.83k | CBS_len(&public_key) == 0 || |
140 | 1.83k | !EC_POINT_oct2point(group, ret->pub_key, CBS_data(&public_key), |
141 | 1.83k | CBS_len(&public_key), nullptr) || |
142 | 1.40k | CBS_len(&child) != 0) { |
143 | 806 | OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); |
144 | 806 | return nullptr; |
145 | 806 | } |
146 | | |
147 | | // Save the point conversion form. |
148 | | // TODO(davidben): Consider removing this. |
149 | 1.07k | ret->conv_form = |
150 | 1.07k | (point_conversion_form_t)(CBS_data(&public_key)[0] & ~0x01); |
151 | 1.23k | } else { |
152 | | // Compute the public key instead. |
153 | 1.23k | if (!ec_point_mul_scalar_base(group, &ret->pub_key->raw, |
154 | 1.23k | &ret->priv_key->scalar)) { |
155 | 0 | return nullptr; |
156 | 0 | } |
157 | | // Remember the original private-key-only encoding. |
158 | | // TODO(davidben): Consider removing this. |
159 | 1.23k | ret->enc_flag |= EC_PKEY_NO_PUBKEY; |
160 | 1.23k | } |
161 | | |
162 | 2.30k | if (CBS_len(&ec_private_key) != 0) { |
163 | 556 | OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); |
164 | 556 | return nullptr; |
165 | 556 | } |
166 | | |
167 | | // Ensure the resulting key is valid. |
168 | 1.75k | if (!EC_KEY_check_key(ret.get())) { |
169 | 966 | return nullptr; |
170 | 966 | } |
171 | | |
172 | 784 | return ret.release(); |
173 | 1.75k | } |
174 | | |
175 | 1.74k | EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) { |
176 | 1.74k | return ec_key_parse_private_key(cbs, group, get_all_groups()); |
177 | 1.74k | } |
178 | | |
179 | | int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key, |
180 | 519 | unsigned enc_flags) { |
181 | 519 | const ECKey *key_impl = FromOpaque(key); |
182 | 519 | if (key_impl == nullptr || key_impl->group == nullptr || |
183 | 519 | key_impl->priv_key == nullptr) { |
184 | 0 | OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); |
185 | 0 | return 0; |
186 | 0 | } |
187 | | |
188 | 519 | CBB ec_private_key, private_key; |
189 | 519 | if (!CBB_add_asn1(cbb, &ec_private_key, CBS_ASN1_SEQUENCE) || |
190 | 519 | !CBB_add_asn1_uint64(&ec_private_key, 1 /* version */) || |
191 | 519 | !CBB_add_asn1(&ec_private_key, &private_key, CBS_ASN1_OCTETSTRING) || |
192 | 519 | !BN_bn2cbb_padded(&private_key, |
193 | 519 | BN_num_bytes(EC_GROUP_get0_order(key_impl->group)), |
194 | 519 | EC_KEY_get0_private_key(key_impl))) { |
195 | 0 | OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR); |
196 | 0 | return 0; |
197 | 0 | } |
198 | | |
199 | 519 | if (!(enc_flags & EC_PKEY_NO_PARAMETERS)) { |
200 | 0 | CBB child; |
201 | 0 | if (!CBB_add_asn1(&ec_private_key, &child, kParametersTag) || |
202 | 0 | !EC_KEY_marshal_curve_name(&child, key_impl->group) || |
203 | 0 | !CBB_flush(&ec_private_key)) { |
204 | 0 | OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR); |
205 | 0 | return 0; |
206 | 0 | } |
207 | 0 | } |
208 | | |
209 | | // TODO(fork): replace this flexibility with sensible default? |
210 | 519 | if (!(enc_flags & EC_PKEY_NO_PUBKEY) && key_impl->pub_key != nullptr) { |
211 | 9 | CBB child, public_key; |
212 | 9 | if (!CBB_add_asn1(&ec_private_key, &child, kPublicKeyTag) || |
213 | 9 | !CBB_add_asn1(&child, &public_key, CBS_ASN1_BITSTRING) || |
214 | | // As in a SubjectPublicKeyInfo, the byte-encoded public key is then |
215 | | // encoded as a BIT STRING with bits ordered as in the DER encoding. |
216 | 9 | !CBB_add_u8(&public_key, 0 /* padding */) || |
217 | 9 | !EC_POINT_point2cbb(&public_key, key_impl->group, key_impl->pub_key, |
218 | 9 | key_impl->conv_form, nullptr) || |
219 | 9 | !CBB_flush(&ec_private_key)) { |
220 | 0 | OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR); |
221 | 0 | return 0; |
222 | 0 | } |
223 | 9 | } |
224 | | |
225 | 519 | if (!CBB_flush(cbb)) { |
226 | 0 | OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR); |
227 | 0 | return 0; |
228 | 0 | } |
229 | | |
230 | 519 | return 1; |
231 | 519 | } |
232 | | |
233 | | // kPrimeFieldOID is the encoding of 1.2.840.10045.1.1. |
234 | | static const uint8_t kPrimeField[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01}; |
235 | | |
236 | | namespace { |
237 | | struct explicit_prime_curve { |
238 | | CBS prime, a, b, base_x, base_y, order; |
239 | | }; |
240 | | } // namespace |
241 | | |
242 | | static int parse_explicit_prime_curve(CBS *in, |
243 | 2.35k | struct explicit_prime_curve *out) { |
244 | | // See RFC 3279, section 2.3.5. Note that RFC 3279 calls this structure an |
245 | | // ECParameters while RFC 5480 calls it a SpecifiedECDomain. |
246 | 2.35k | CBS params, field_id, field_type, curve, base, cofactor; |
247 | 2.35k | int has_cofactor; |
248 | 2.35k | uint64_t version; |
249 | 2.35k | if (!CBS_get_asn1(in, ¶ms, CBS_ASN1_SEQUENCE) || |
250 | 2.35k | !CBS_get_asn1_uint64(¶ms, &version) || // |
251 | 2.31k | version != 1 || // |
252 | 2.07k | !CBS_get_asn1(¶ms, &field_id, CBS_ASN1_SEQUENCE) || |
253 | 2.06k | !CBS_get_asn1(&field_id, &field_type, CBS_ASN1_OBJECT) || |
254 | 2.06k | CBS_len(&field_type) != sizeof(kPrimeField) || |
255 | 2.03k | OPENSSL_memcmp(CBS_data(&field_type), kPrimeField, sizeof(kPrimeField)) != |
256 | 2.03k | 0 || |
257 | 2.02k | !CBS_get_asn1(&field_id, &out->prime, CBS_ASN1_INTEGER) || |
258 | 2.01k | !CBS_is_unsigned_asn1_integer(&out->prime) || // |
259 | 1.97k | CBS_len(&field_id) != 0 || |
260 | 1.95k | !CBS_get_asn1(¶ms, &curve, CBS_ASN1_SEQUENCE) || |
261 | 1.94k | !CBS_get_asn1(&curve, &out->a, CBS_ASN1_OCTETSTRING) || |
262 | 1.93k | !CBS_get_asn1(&curve, &out->b, CBS_ASN1_OCTETSTRING) || |
263 | | // `curve` has an optional BIT STRING seed which we ignore. |
264 | 1.93k | !CBS_get_optional_asn1(&curve, nullptr, nullptr, CBS_ASN1_BITSTRING) || |
265 | 1.92k | CBS_len(&curve) != 0 || |
266 | 1.42k | !CBS_get_asn1(¶ms, &base, CBS_ASN1_OCTETSTRING) || |
267 | 1.41k | !CBS_get_asn1(¶ms, &out->order, CBS_ASN1_INTEGER) || |
268 | 1.41k | !CBS_is_unsigned_asn1_integer(&out->order) || |
269 | 1.40k | !CBS_get_optional_asn1(¶ms, &cofactor, &has_cofactor, |
270 | 1.40k | CBS_ASN1_INTEGER) || |
271 | 1.39k | CBS_len(¶ms) != 0) { |
272 | 1.04k | OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); |
273 | 1.04k | return 0; |
274 | 1.04k | } |
275 | | |
276 | 1.31k | if (has_cofactor) { |
277 | | // We only support prime-order curves so the cofactor must be one. |
278 | 736 | if (CBS_len(&cofactor) != 1 || // |
279 | 581 | CBS_data(&cofactor)[0] != 1) { |
280 | 180 | OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); |
281 | 180 | return 0; |
282 | 180 | } |
283 | 736 | } |
284 | | |
285 | | // Require that the base point use uncompressed form. |
286 | 1.13k | uint8_t form; |
287 | 1.13k | if (!CBS_get_u8(&base, &form) || form != POINT_CONVERSION_UNCOMPRESSED) { |
288 | 47 | OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FORM); |
289 | 47 | return 0; |
290 | 47 | } |
291 | | |
292 | 1.08k | if (CBS_len(&base) % 2 != 0) { |
293 | 5 | OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); |
294 | 5 | return 0; |
295 | 5 | } |
296 | 1.08k | size_t field_len = CBS_len(&base) / 2; |
297 | 1.08k | CBS_init(&out->base_x, CBS_data(&base), field_len); |
298 | 1.08k | CBS_init(&out->base_y, CBS_data(&base) + field_len, field_len); |
299 | | |
300 | 1.08k | return 1; |
301 | 1.08k | } |
302 | | |
303 | | // integers_equal returns one if `bytes` is a big-endian encoding of `bn`, and |
304 | | // zero otherwise. |
305 | 1.77k | static int integers_equal(const CBS *bytes, const BIGNUM *bn) { |
306 | | // Although, in SEC 1, Field-Element-to-Octet-String has a fixed width, |
307 | | // OpenSSL mis-encodes the `a` and `b`, so we tolerate any number of leading |
308 | | // zeros. (This matters for P-521 whose `b` has a leading 0.) |
309 | 1.77k | CBS copy = *bytes; |
310 | 4.23k | while (CBS_len(©) > 0 && CBS_data(©)[0] == 0) { |
311 | 2.46k | CBS_skip(©, 1); |
312 | 2.46k | } |
313 | | |
314 | 1.77k | if (CBS_len(©) > EC_MAX_BYTES) { |
315 | 115 | return 0; |
316 | 115 | } |
317 | 1.65k | uint8_t buf[EC_MAX_BYTES]; |
318 | 1.65k | if (!BN_bn2bin_padded(buf, CBS_len(©), bn)) { |
319 | 584 | ERR_clear_error(); |
320 | 584 | return 0; |
321 | 584 | } |
322 | | |
323 | 1.07k | return CBS_mem_equal(©, buf, CBS_len(©)); |
324 | 1.65k | } |
325 | | |
326 | | const EC_GROUP *bssl::ec_key_parse_curve_name( |
327 | 141k | CBS *cbs, Span<const EC_GROUP *const> allowed_groups) { |
328 | 141k | CBS named_curve; |
329 | 141k | if (!CBS_get_asn1(cbs, &named_curve, CBS_ASN1_OBJECT)) { |
330 | 15.6k | OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR); |
331 | 15.6k | return nullptr; |
332 | 15.6k | } |
333 | | |
334 | | // Look for a matching curve. |
335 | 127k | for (const EC_GROUP *group : allowed_groups) { |
336 | 127k | if (named_curve == Span(group->oid, group->oid_len)) { |
337 | 62.2k | return group; |
338 | 62.2k | } |
339 | 127k | } |
340 | | |
341 | 64.0k | OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); |
342 | 64.0k | return nullptr; |
343 | 126k | } |
344 | | |
345 | 0 | EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs) { |
346 | | // This function only ever returns a static `EC_GROUP`, but currently returns |
347 | | // a non-const pointer for historical reasons. |
348 | 0 | return const_cast<EC_GROUP *>(ec_key_parse_curve_name(cbs, get_all_groups())); |
349 | 0 | } |
350 | | |
351 | 1.40k | int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group) { |
352 | 1.40k | if (group->oid_len == 0) { |
353 | 0 | OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); |
354 | 0 | return 0; |
355 | 0 | } |
356 | | |
357 | 1.40k | return CBB_add_asn1_element(cbb, CBS_ASN1_OBJECT, group->oid, group->oid_len); |
358 | 1.40k | } |
359 | | |
360 | | const EC_GROUP *bssl::ec_key_parse_parameters( |
361 | 9.61k | CBS *cbs, Span<const EC_GROUP *const> allowed_groups) { |
362 | 9.61k | if (!CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) { |
363 | 7.26k | return ec_key_parse_curve_name(cbs, allowed_groups); |
364 | 7.26k | } |
365 | | |
366 | | // OpenSSL sometimes produces ECPrivateKeys with explicitly-encoded versions |
367 | | // of named curves. |
368 | | // |
369 | | // TODO(davidben): Remove support for this. |
370 | 2.35k | struct explicit_prime_curve curve; |
371 | 2.35k | if (!parse_explicit_prime_curve(cbs, &curve)) { |
372 | 1.27k | return nullptr; |
373 | 1.27k | } |
374 | | |
375 | 1.08k | UniquePtr<BIGNUM> p(BN_new()); |
376 | 1.08k | UniquePtr<BIGNUM> a(BN_new()); |
377 | 1.08k | UniquePtr<BIGNUM> b(BN_new()); |
378 | 1.08k | UniquePtr<BIGNUM> x(BN_new()); |
379 | 1.08k | UniquePtr<BIGNUM> y(BN_new()); |
380 | 1.08k | if (p == nullptr || a == nullptr || b == nullptr || x == nullptr || |
381 | 1.08k | y == nullptr) { |
382 | 0 | return nullptr; |
383 | 0 | } |
384 | | |
385 | 1.09k | for (const EC_GROUP *group : allowed_groups) { |
386 | 1.09k | if (!integers_equal(&curve.order, EC_GROUP_get0_order(group))) { |
387 | 900 | continue; |
388 | 900 | } |
389 | | |
390 | | // The order alone uniquely identifies the group, but we check the other |
391 | | // parameters to avoid misinterpreting the group. |
392 | 196 | if (!EC_GROUP_get_curve_GFp(group, p.get(), a.get(), b.get(), nullptr)) { |
393 | 0 | return nullptr; |
394 | 0 | } |
395 | 196 | if (!integers_equal(&curve.prime, p.get()) || |
396 | 182 | !integers_equal(&curve.a, a.get()) || |
397 | 134 | !integers_equal(&curve.b, b.get())) { |
398 | 96 | break; |
399 | 96 | } |
400 | 100 | if (!EC_POINT_get_affine_coordinates_GFp( |
401 | 100 | group, EC_GROUP_get0_generator(group), x.get(), y.get(), nullptr)) { |
402 | 0 | return nullptr; |
403 | 0 | } |
404 | 100 | if (!integers_equal(&curve.base_x, x.get()) || |
405 | 64 | !integers_equal(&curve.base_y, y.get())) { |
406 | 48 | break; |
407 | 48 | } |
408 | 52 | return group; |
409 | 100 | } |
410 | | |
411 | 1.02k | OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP); |
412 | 1.02k | return nullptr; |
413 | 1.08k | } |
414 | | |
415 | 0 | EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) { |
416 | | // This function only ever returns a static `EC_GROUP`, but currently returns |
417 | | // a non-const pointer for historical reasons. |
418 | 0 | return const_cast<EC_GROUP *>(ec_key_parse_parameters(cbs, get_all_groups())); |
419 | 0 | } |
420 | | |
421 | | int EC_POINT_point2cbb(CBB *out, const EC_GROUP *group, const EC_POINT *point, |
422 | 15.4k | point_conversion_form_t form, BN_CTX *ctx) { |
423 | 15.4k | size_t len = EC_POINT_point2oct(group, point, form, nullptr, 0, ctx); |
424 | 15.4k | if (len == 0) { |
425 | 0 | return 0; |
426 | 0 | } |
427 | 15.4k | uint8_t *p; |
428 | 15.4k | return CBB_add_space(out, &p, len) && |
429 | 15.4k | EC_POINT_point2oct(group, point, form, p, len, ctx) == len; |
430 | 15.4k | } |
431 | | |
432 | 0 | EC_KEY *d2i_ECPrivateKey(EC_KEY **out, const uint8_t **inp, long len) { |
433 | | // This function treats its `out` parameter differently from other `d2i` |
434 | | // functions. If supplied, take the group from `*out`. |
435 | 0 | const EC_GROUP *group = nullptr; |
436 | 0 | if (out != nullptr && *out != nullptr) { |
437 | 0 | group = EC_KEY_get0_group(*out); |
438 | 0 | } |
439 | |
|
440 | 0 | return D2IFromCBS(out, inp, len, [&](CBS *cbs) { |
441 | 0 | return EC_KEY_parse_private_key(cbs, group); |
442 | 0 | }); |
443 | 0 | } |
444 | | |
445 | 0 | int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp) { |
446 | 0 | return I2DFromCBB( |
447 | 0 | /*initial_capacity=*/64, outp, [&](CBB *cbb) -> bool { |
448 | 0 | return EC_KEY_marshal_private_key(cbb, key, EC_KEY_get_enc_flags(key)); |
449 | 0 | }); |
450 | 0 | } |
451 | | |
452 | 0 | EC_GROUP *d2i_ECPKParameters(EC_GROUP **out, const uint8_t **inp, long len) { |
453 | 0 | return D2IFromCBS(out, inp, len, EC_KEY_parse_parameters); |
454 | 0 | } |
455 | | |
456 | 0 | int i2d_ECPKParameters(const EC_GROUP *group, uint8_t **outp) { |
457 | 0 | if (group == nullptr) { |
458 | 0 | OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); |
459 | 0 | return -1; |
460 | 0 | } |
461 | 0 | return I2DFromCBB( |
462 | 0 | /*initial_capacity=*/16, outp, |
463 | 0 | [&](CBB *cbb) -> bool { return EC_KEY_marshal_curve_name(cbb, group); }); |
464 | 0 | } |
465 | | |
466 | 0 | EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, long len) { |
467 | 0 | return D2IFromCBS(out_key, inp, len, [](CBS *cbs) -> UniquePtr<EC_KEY> { |
468 | 0 | const EC_GROUP *group = EC_KEY_parse_parameters(cbs); |
469 | 0 | if (group == nullptr) { |
470 | 0 | return nullptr; |
471 | 0 | } |
472 | 0 | UniquePtr<EC_KEY> ret(EC_KEY_new()); |
473 | 0 | if (ret == nullptr || !EC_KEY_set_group(ret.get(), group)) { |
474 | 0 | return nullptr; |
475 | 0 | } |
476 | 0 | return ret; |
477 | 0 | }); |
478 | 0 | } |
479 | | |
480 | 0 | int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) { |
481 | 0 | const ECKey *key_impl = FromOpaque(key); |
482 | 0 | if (key_impl == nullptr || key_impl->group == nullptr) { |
483 | 0 | OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); |
484 | 0 | return -1; |
485 | 0 | } |
486 | 0 | return I2DFromCBB( |
487 | 0 | /*initial_capacity=*/16, outp, [&](CBB *cbb) -> bool { |
488 | 0 | return EC_KEY_marshal_curve_name(cbb, key_impl->group); |
489 | 0 | }); |
490 | 0 | } |
491 | | |
492 | 0 | EC_KEY *o2i_ECPublicKey(EC_KEY **keyp, const uint8_t **inp, long len) { |
493 | 0 | ECKey *ret = nullptr; |
494 | |
|
495 | 0 | if (keyp == nullptr || *keyp == nullptr || |
496 | 0 | FromOpaque(*keyp)->group == nullptr) { |
497 | 0 | OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); |
498 | 0 | return nullptr; |
499 | 0 | } |
500 | 0 | ret = FromOpaque(*keyp); |
501 | 0 | if (ret->pub_key == nullptr && |
502 | 0 | (ret->pub_key = EC_POINT_new(ret->group)) == nullptr) { |
503 | 0 | return nullptr; |
504 | 0 | } |
505 | 0 | if (!EC_POINT_oct2point(ret->group, ret->pub_key, *inp, len, nullptr)) { |
506 | 0 | OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB); |
507 | 0 | return nullptr; |
508 | 0 | } |
509 | | // save the point conversion form |
510 | 0 | ret->conv_form = (point_conversion_form_t)(*inp[0] & ~0x01); |
511 | 0 | *inp += len; |
512 | 0 | return ret; |
513 | 0 | } |
514 | | |
515 | 0 | int i2o_ECPublicKey(const EC_KEY *key, uint8_t **outp) { |
516 | 0 | if (key == nullptr) { |
517 | 0 | OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); |
518 | 0 | return 0; |
519 | 0 | } |
520 | 0 | const ECKey *key_impl = FromOpaque(key); |
521 | | // No initial capacity because `EC_POINT_point2cbb` will internally reserve |
522 | | // the right size in one shot, so it's best to leave this at zero. |
523 | 0 | int ret = I2DFromCBB( |
524 | 0 | /*initial_capacity=*/0, outp, [&](CBB *cbb) -> bool { |
525 | 0 | return EC_POINT_point2cbb(cbb, key_impl->group, key_impl->pub_key, |
526 | 0 | key_impl->conv_form, nullptr); |
527 | 0 | }); |
528 | | // Historically, this function used the wrong return value on error. |
529 | 0 | return ret > 0 ? ret : 0; |
530 | 0 | } |
531 | | |
532 | | size_t EC_get_builtin_curves(EC_builtin_curve *out_curves, |
533 | 0 | size_t max_num_curves) { |
534 | 0 | auto all = get_all_groups(); |
535 | 0 | max_num_curves = std::min(all.size(), max_num_curves); |
536 | 0 | for (size_t i = 0; i < max_num_curves; i++) { |
537 | 0 | const EC_GROUP *group = all[i]; |
538 | 0 | out_curves[i].nid = group->curve_name; |
539 | 0 | out_curves[i].comment = group->comment; |
540 | 0 | } |
541 | 0 | return all.size(); |
542 | 0 | } |