]>
Commit | Line | Data |
---|---|---|
0abae163 RL |
1 | /* |
2 | * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved. | |
3 | * | |
4 | * Licensed under the Apache License 2.0 (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/core_names.h> | |
11 | #include <openssl/objects.h> | |
12 | #include <openssl/params.h> | |
c0f39ded | 13 | #include <openssl/err.h> |
0abae163 RL |
14 | #include "crypto/bn.h" |
15 | #include "crypto/ec.h" | |
c0f39ded SL |
16 | #include "ec_local.h" |
17 | #include "e_os.h" | |
18 | #include "internal/param_build_set.h" | |
19 | ||
20 | /* Mapping between a flag and a name */ | |
21 | static const OSSL_ITEM encoding_nameid_map[] = { | |
22 | { OPENSSL_EC_EXPLICIT_CURVE, OSSL_PKEY_EC_ENCODING_EXPLICIT }, | |
23 | { OPENSSL_EC_NAMED_CURVE, OSSL_PKEY_EC_ENCODING_GROUP }, | |
24 | }; | |
25 | ||
26 | int ec_encoding_name2id(const char *name) | |
27 | { | |
28 | size_t i, sz; | |
29 | ||
30 | /* Return the default value if there is no name */ | |
31 | if (name == NULL) | |
32 | return OPENSSL_EC_NAMED_CURVE; | |
33 | ||
34 | for (i = 0, sz = OSSL_NELEM(encoding_nameid_map); i < sz; i++) { | |
35 | if (strcasecmp(name, encoding_nameid_map[i].ptr) == 0) | |
36 | return encoding_nameid_map[i].id; | |
37 | } | |
38 | return -1; | |
39 | } | |
40 | ||
41 | static char *ec_param_encoding_id2name(int id) | |
42 | { | |
43 | size_t i, sz; | |
44 | ||
45 | for (i = 0, sz = OSSL_NELEM(encoding_nameid_map); i < sz; i++) { | |
46 | if (id == (int)encoding_nameid_map[i].id) | |
47 | return encoding_nameid_map[i].ptr; | |
48 | } | |
49 | return NULL; | |
50 | } | |
51 | ||
52 | int ec_group_todata(const EC_GROUP *group, OSSL_PARAM_BLD *tmpl, | |
b4250010 DMSP |
53 | OSSL_PARAM params[], OSSL_LIB_CTX *libctx, |
54 | const char *propq, | |
c0f39ded SL |
55 | BN_CTX *bnctx, unsigned char **genbuf) |
56 | { | |
57 | int ret = 0, curve_nid, encoding_flag; | |
58 | const char *field_type, *encoding_name; | |
59 | const BIGNUM *cofactor, *order; | |
60 | BIGNUM *p = NULL, *a = NULL, *b = NULL; | |
61 | point_conversion_form_t genform; | |
62 | const EC_POINT *genpt; | |
63 | unsigned char *seed = NULL; | |
64 | size_t genbuf_len, seed_len; | |
65 | ||
66 | if (group == NULL) { | |
9311d0c4 | 67 | ERR_raise(ERR_LIB_EC,EC_R_PASSED_NULL_PARAMETER); |
c0f39ded SL |
68 | return 0; |
69 | } | |
70 | ||
71 | encoding_flag = EC_GROUP_get_asn1_flag(group) & OPENSSL_EC_NAMED_CURVE; | |
72 | encoding_name = ec_param_encoding_id2name(encoding_flag); | |
73 | if (encoding_name == NULL | |
74 | || !ossl_param_build_set_utf8_string(tmpl, params, | |
75 | OSSL_PKEY_PARAM_EC_ENCODING, | |
76 | encoding_name)) { | |
9311d0c4 | 77 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_ENCODING); |
c0f39ded SL |
78 | return 0; |
79 | } | |
80 | ||
81 | curve_nid = EC_GROUP_get_curve_name(group); | |
82 | if (curve_nid == NID_undef) { | |
83 | /* explicit curve */ | |
84 | int fid = EC_GROUP_get_field_type(group); | |
85 | ||
86 | if (fid == NID_X9_62_prime_field) { | |
87 | field_type = SN_X9_62_prime_field; | |
88 | } else if (fid == NID_X9_62_characteristic_two_field) { | |
89 | field_type = SN_X9_62_characteristic_two_field; | |
90 | } else { | |
9311d0c4 | 91 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_FIELD); |
c0f39ded SL |
92 | return 0; |
93 | } | |
94 | ||
95 | p = BN_CTX_get(bnctx); | |
96 | a = BN_CTX_get(bnctx); | |
97 | b = BN_CTX_get(bnctx); | |
98 | if (b == NULL) { | |
9311d0c4 | 99 | ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); |
c0f39ded SL |
100 | goto err; |
101 | } | |
102 | ||
103 | if (!EC_GROUP_get_curve(group, p, a, b, bnctx)) { | |
9311d0c4 | 104 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_CURVE); |
c0f39ded SL |
105 | goto err; |
106 | } | |
107 | ||
108 | order = EC_GROUP_get0_order(group); | |
109 | if (order == NULL) { | |
9311d0c4 | 110 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_GROUP_ORDER); |
c0f39ded SL |
111 | goto err; |
112 | } | |
113 | genpt = EC_GROUP_get0_generator(group); | |
114 | if (genpt == NULL) { | |
9311d0c4 | 115 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_GENERATOR); |
c0f39ded SL |
116 | goto err; |
117 | } | |
118 | genform = EC_GROUP_get_point_conversion_form(group); | |
119 | genbuf_len = EC_POINT_point2buf(group, genpt, genform, genbuf, bnctx); | |
120 | if (genbuf_len == 0) { | |
9311d0c4 | 121 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_GENERATOR); |
c0f39ded SL |
122 | goto err; |
123 | } | |
124 | ||
125 | if (!ossl_param_build_set_utf8_string(tmpl, params, | |
126 | OSSL_PKEY_PARAM_EC_FIELD_TYPE, | |
127 | field_type) | |
128 | || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_P, p) | |
129 | || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_A, a) | |
130 | || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_B, b) | |
131 | || !ossl_param_build_set_bn(tmpl, params, OSSL_PKEY_PARAM_EC_ORDER, | |
132 | order) | |
133 | || !ossl_param_build_set_octet_string(tmpl, params, | |
134 | OSSL_PKEY_PARAM_EC_GENERATOR, | |
135 | *genbuf, genbuf_len)) { | |
9311d0c4 | 136 | ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); |
c0f39ded SL |
137 | goto err; |
138 | } | |
139 | ||
140 | cofactor = EC_GROUP_get0_cofactor(group); | |
141 | if (cofactor != NULL | |
142 | && !ossl_param_build_set_bn(tmpl, params, | |
143 | OSSL_PKEY_PARAM_EC_COFACTOR, cofactor)) { | |
9311d0c4 | 144 | ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); |
c0f39ded SL |
145 | goto err; |
146 | } | |
147 | ||
148 | seed = EC_GROUP_get0_seed(group); | |
149 | seed_len = EC_GROUP_get_seed_len(group); | |
150 | if (seed != NULL | |
151 | && seed_len > 0 | |
152 | && !ossl_param_build_set_octet_string(tmpl, params, | |
153 | OSSL_PKEY_PARAM_EC_SEED, | |
154 | seed, seed_len)) { | |
9311d0c4 | 155 | ERR_raise(ERR_LIB_EC, ERR_R_MALLOC_FAILURE); |
c0f39ded SL |
156 | goto err; |
157 | } | |
158 | #ifdef OPENSSL_NO_EC2M | |
159 | if (fid == NID_X9_62_characteristic_two_field) { | |
9311d0c4 | 160 | ERR_raise(ERR_LIB_EC, EC_R_GF2M_NOT_SUPPORTED); |
c0f39ded SL |
161 | goto err; |
162 | } | |
163 | #endif | |
164 | } else { | |
165 | /* named curve */ | |
ea478697 | 166 | const char *curve_name = ec_curve_nid2name(curve_nid); |
c0f39ded SL |
167 | |
168 | if (curve_name == NULL | |
169 | || !ossl_param_build_set_utf8_string(tmpl, params, | |
170 | OSSL_PKEY_PARAM_GROUP_NAME, | |
171 | curve_name)) { | |
9311d0c4 | 172 | ERR_raise(ERR_LIB_EC, EC_R_INVALID_CURVE); |
c0f39ded SL |
173 | goto err; |
174 | } | |
175 | } | |
176 | ret = 1; | |
177 | err: | |
178 | return ret; | |
179 | } | |
0abae163 RL |
180 | |
181 | /* | |
182 | * The intention with the "backend" source file is to offer backend support | |
183 | * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider | |
184 | * implementations alike. | |
185 | */ | |
b8086652 | 186 | int ec_set_ecdh_cofactor_mode(EC_KEY *ec, int mode) |
0abae163 RL |
187 | { |
188 | const EC_GROUP *ecg = EC_KEY_get0_group(ec); | |
189 | const BIGNUM *cofactor; | |
0abae163 RL |
190 | /* |
191 | * mode can be only 0 for disable, or 1 for enable here. | |
192 | * | |
193 | * This is in contrast with the same parameter on an ECDH EVP_PKEY_CTX that | |
194 | * also supports mode == -1 with the meaning of "reset to the default for | |
195 | * the associated key". | |
196 | */ | |
197 | if (mode < 0 || mode > 1) | |
198 | return 0; | |
199 | ||
200 | if ((cofactor = EC_GROUP_get0_cofactor(ecg)) == NULL ) | |
201 | return 0; | |
202 | ||
203 | /* ECDH cofactor mode has no effect if cofactor is 1 */ | |
204 | if (BN_is_one(cofactor)) | |
205 | return 1; | |
206 | ||
207 | if (mode == 1) | |
208 | EC_KEY_set_flags(ec, EC_FLAG_COFACTOR_ECDH); | |
209 | else if (mode == 0) | |
210 | EC_KEY_clear_flags(ec, EC_FLAG_COFACTOR_ECDH); | |
211 | ||
212 | return 1; | |
213 | } | |
214 | ||
215 | /* | |
216 | * Callers of ec_key_fromdata MUST make sure that ec_key_params_fromdata has | |
217 | * been called before! | |
218 | * | |
219 | * This function only gets the bare keypair, domain parameters and other | |
220 | * parameters are treated separately, and domain parameters are required to | |
221 | * define a keypair. | |
222 | */ | |
223 | int ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_private) | |
224 | { | |
9e2c0358 | 225 | const OSSL_PARAM *param_priv_key = NULL, *param_pub_key = NULL; |
0abae163 RL |
226 | BN_CTX *ctx = NULL; |
227 | BIGNUM *priv_key = NULL; | |
228 | unsigned char *pub_key = NULL; | |
229 | size_t pub_key_len; | |
230 | const EC_GROUP *ecg = NULL; | |
231 | EC_POINT *pub_point = NULL; | |
232 | int ok = 0; | |
233 | ||
234 | ecg = EC_KEY_get0_group(ec); | |
235 | if (ecg == NULL) | |
236 | return 0; | |
237 | ||
0abae163 RL |
238 | param_pub_key = |
239 | OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); | |
9e2c0358 RL |
240 | if (include_private) |
241 | param_priv_key = | |
242 | OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); | |
0abae163 RL |
243 | |
244 | ctx = BN_CTX_new_ex(ec_key_get_libctx(ec)); | |
245 | if (ctx == NULL) | |
246 | goto err; | |
9e2c0358 RL |
247 | |
248 | /* OpenSSL decree: If there's a private key, there must be a public key */ | |
249 | if (param_priv_key != NULL && param_pub_key == NULL) | |
250 | goto err; | |
251 | ||
252 | if (param_pub_key != NULL) | |
253 | if (!OSSL_PARAM_get_octet_string(param_pub_key, | |
254 | (void **)&pub_key, 0, &pub_key_len) | |
0abae163 | 255 | || (pub_point = EC_POINT_new(ecg)) == NULL |
9e2c0358 | 256 | || !EC_POINT_oct2point(ecg, pub_point, pub_key, pub_key_len, ctx)) |
0abae163 RL |
257 | goto err; |
258 | ||
259 | if (param_priv_key != NULL && include_private) { | |
260 | int fixed_words; | |
261 | const BIGNUM *order; | |
262 | ||
263 | /* | |
264 | * Key import/export should never leak the bit length of the secret | |
265 | * scalar in the key. | |
266 | * | |
267 | * For this reason, on export we use padded BIGNUMs with fixed length. | |
268 | * | |
269 | * When importing we also should make sure that, even if short lived, | |
270 | * the newly created BIGNUM is marked with the BN_FLG_CONSTTIME flag as | |
271 | * soon as possible, so that any processing of this BIGNUM might opt for | |
272 | * constant time implementations in the backend. | |
273 | * | |
274 | * Setting the BN_FLG_CONSTTIME flag alone is never enough, we also have | |
275 | * to preallocate the BIGNUM internal buffer to a fixed public size big | |
276 | * enough that operations performed during the processing never trigger | |
277 | * a realloc which would leak the size of the scalar through memory | |
278 | * accesses. | |
279 | * | |
280 | * Fixed Length | |
281 | * ------------ | |
282 | * | |
283 | * The order of the large prime subgroup of the curve is our choice for | |
284 | * a fixed public size, as that is generally the upper bound for | |
285 | * generating a private key in EC cryptosystems and should fit all valid | |
286 | * secret scalars. | |
287 | * | |
288 | * For padding on export we just use the bit length of the order | |
289 | * converted to bytes (rounding up). | |
290 | * | |
291 | * For preallocating the BIGNUM storage we look at the number of "words" | |
292 | * required for the internal representation of the order, and we | |
293 | * preallocate 2 extra "words" in case any of the subsequent processing | |
294 | * might temporarily overflow the order length. | |
295 | */ | |
296 | order = EC_GROUP_get0_order(ecg); | |
297 | if (order == NULL || BN_is_zero(order)) | |
298 | goto err; | |
299 | ||
300 | fixed_words = bn_get_top(order) + 2; | |
301 | ||
302 | if ((priv_key = BN_secure_new()) == NULL) | |
303 | goto err; | |
304 | if (bn_wexpand(priv_key, fixed_words) == NULL) | |
305 | goto err; | |
306 | BN_set_flags(priv_key, BN_FLG_CONSTTIME); | |
307 | ||
308 | if (!OSSL_PARAM_get_BN(param_priv_key, &priv_key)) | |
309 | goto err; | |
310 | } | |
311 | ||
312 | if (priv_key != NULL | |
9e2c0358 | 313 | && !EC_KEY_set_private_key(ec, priv_key)) |
0abae163 RL |
314 | goto err; |
315 | ||
9e2c0358 RL |
316 | if (pub_point != NULL |
317 | && !EC_KEY_set_public_key(ec, pub_point)) | |
0abae163 RL |
318 | goto err; |
319 | ||
320 | ok = 1; | |
321 | ||
322 | err: | |
323 | BN_CTX_free(ctx); | |
324 | BN_clear_free(priv_key); | |
325 | OPENSSL_free(pub_key); | |
326 | EC_POINT_free(pub_point); | |
327 | return ok; | |
328 | } | |
329 | ||
c0f39ded | 330 | int ec_group_fromdata(EC_KEY *ec, const OSSL_PARAM params[]) |
0abae163 | 331 | { |
0abae163 | 332 | int ok = 0; |
c0f39ded | 333 | EC_GROUP *group = NULL; |
0abae163 RL |
334 | |
335 | if (ec == NULL) | |
336 | return 0; | |
337 | ||
c0f39ded SL |
338 | group = EC_GROUP_new_from_params(params, ec_key_get_libctx(ec), |
339 | ec_key_get0_propq(ec)); | |
0abae163 | 340 | |
c0f39ded | 341 | if (!EC_KEY_set_group(ec, group)) |
0abae163 RL |
342 | goto err; |
343 | ||
344 | /* | |
345 | * TODO(3.0): if the group has changed, should we invalidate the private and | |
346 | * public key? | |
347 | */ | |
0abae163 | 348 | ok = 1; |
c0f39ded SL |
349 | err: |
350 | EC_GROUP_free(group); | |
0abae163 RL |
351 | return ok; |
352 | } | |
353 | ||
354 | int ec_key_otherparams_fromdata(EC_KEY *ec, const OSSL_PARAM params[]) | |
355 | { | |
356 | const OSSL_PARAM *p; | |
357 | ||
358 | if (ec == NULL) | |
359 | return 0; | |
360 | ||
361 | p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_USE_COFACTOR_ECDH); | |
b8086652 SL |
362 | if (p != NULL) { |
363 | int mode; | |
0abae163 | 364 | |
b8086652 SL |
365 | if (!OSSL_PARAM_get_int(p, &mode) |
366 | || !ec_set_ecdh_cofactor_mode(ec, mode)) | |
367 | return 0; | |
368 | } | |
c0f39ded | 369 | |
0abae163 RL |
370 | return 1; |
371 | } |