1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2010-2020. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #include "ec.h"
22 #include "bn.h"
23
24 #ifdef HAVE_EC
25 static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg, size_t *size);
26 static ERL_NIF_TERM point2term(ErlNifEnv* env,
27 const EC_GROUP *group,
28 const EC_POINT *point,
29 point_conversion_form_t form);
30
make_badarg_maybe(ErlNifEnv * env)31 ERL_NIF_TERM make_badarg_maybe(ErlNifEnv* env)
32 {
33 ERL_NIF_TERM reason;
34 if (enif_has_pending_exception(env, &reason))
35 return reason; /* dummy return value ignored */
36 else
37 return enif_make_badarg(env);
38 }
39
ec_key_new(ErlNifEnv * env,ERL_NIF_TERM curve_arg,size_t * size)40 static EC_KEY* ec_key_new(ErlNifEnv* env, ERL_NIF_TERM curve_arg, size_t *size)
41 {
42 EC_KEY *key = NULL;
43 int c_arity = -1;
44 const ERL_NIF_TERM* curve;
45 ErlNifBinary seed;
46 BIGNUM *p = NULL;
47 BIGNUM *a = NULL;
48 BIGNUM *b = NULL;
49 BIGNUM *bn_order = NULL;
50 BIGNUM *cofactor = NULL;
51 EC_GROUP *group = NULL;
52 EC_POINT *point = NULL;
53 int f_arity = -1;
54 const ERL_NIF_TERM *field;
55 int p_arity = -1;
56 const ERL_NIF_TERM *prime;
57 long field_bits;
58
59 /* {Field, Prime, Point, Order, CoFactor} = Curve */
60 if (!enif_get_tuple(env, curve_arg, &c_arity, &curve))
61 goto err;
62 if (c_arity != 5)
63 goto err;
64 if (!get_bn_from_bin_sz(env, curve[3], &bn_order, size))
65 goto err;
66 if (curve[4] != atom_none) {
67 if (!get_bn_from_bin(env, curve[4], &cofactor))
68 goto err;
69 }
70
71 /* {A, B, Seed} = Prime */
72 if (!enif_get_tuple(env, curve[1], &p_arity, &prime))
73 goto err;
74 if (!get_bn_from_bin(env, prime[0], &a))
75 goto err;
76 if (!get_bn_from_bin(env, prime[1], &b))
77 goto err;
78
79 if (!enif_get_tuple(env, curve[0], &f_arity, &field))
80 goto err;
81
82 if (f_arity == 2 && field[0] == atom_prime_field) {
83 /* {prime_field, Prime} */
84 if (!get_bn_from_bin(env, field[1], &p))
85 goto err;
86 if (BN_is_negative(p))
87 goto err;
88 if (BN_is_zero(p))
89 goto err;
90
91 field_bits = BN_num_bits(p);
92 if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS)
93 goto err;
94
95 /* create the EC_GROUP structure */
96 if ((group = EC_GROUP_new_curve_GFp(p, a, b, NULL)) == NULL)
97 goto err;
98
99 } else if (f_arity == 3 && field[0] == atom_characteristic_two_field) {
100 #if defined(OPENSSL_NO_EC2M)
101 enif_raise_exception(env, atom_notsup);
102 goto err;
103 #else
104 /* {characteristic_two_field, M, Basis} */
105 int b_arity = -1;
106 const ERL_NIF_TERM* basis;
107
108 if ((p = BN_new()) == NULL)
109 goto err;
110 if (!enif_get_long(env, field[1], &field_bits))
111 goto err;
112 if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS || field_bits > INT_MAX)
113 goto err;
114
115 if (enif_get_tuple(env, field[2], &b_arity, &basis)) {
116 if (b_arity == 2) {
117 unsigned int k1;
118
119 if (basis[0] != atom_tpbasis)
120 goto err;
121 if (!enif_get_uint(env, basis[1], &k1))
122 goto err;
123
124 /* {tpbasis, k} = Basis */
125 if (field_bits <= k1 || k1 == 0 || k1 > INT_MAX)
126 goto err;
127
128 /* create the polynomial */
129 if (!BN_set_bit(p, (int)field_bits))
130 goto err;
131 if (!BN_set_bit(p, (int)k1))
132 goto err;
133 if (!BN_set_bit(p, 0))
134 goto err;
135
136 } else if (b_arity == 4) {
137 unsigned int k1, k2, k3;
138
139 if (basis[0] != atom_ppbasis)
140 goto err;
141 if (!enif_get_uint(env, basis[1], &k1))
142 goto err;
143 if (!enif_get_uint(env, basis[2], &k2))
144 goto err;
145 if (!enif_get_uint(env, basis[3], &k3))
146 goto err;
147
148 /* {ppbasis, k1, k2, k3} = Basis */
149 if (field_bits <= k3 || k3 <= k2 || k2 <= k1 || k1 == 0 || k3 > INT_MAX || k2 > INT_MAX || k1 > INT_MAX)
150 goto err;
151
152 /* create the polynomial */
153 if (!BN_set_bit(p, (int)field_bits))
154 goto err;
155 if (!BN_set_bit(p, (int)k1))
156 goto err;
157 if (!BN_set_bit(p, (int)k2))
158 goto err;
159 if (!BN_set_bit(p, (int)k3))
160 goto err;
161 if (!BN_set_bit(p, 0))
162 goto err;
163
164 } else
165 goto err;
166 } else if (field[2] == atom_onbasis) {
167 /* onbasis = Basis */
168 /* no parameters */
169 goto err;
170
171 } else
172 goto err;
173
174 if ((group = EC_GROUP_new_curve_GF2m(p, a, b, NULL)) == NULL)
175 goto err;
176 #endif
177 } else
178 goto err;
179
180 if (enif_inspect_binary(env, prime[2], &seed)) {
181 if (!EC_GROUP_set_seed(group, seed.data, seed.size))
182 goto err;
183 }
184
185 if (!term2point(env, curve[2], group, &point))
186 goto err;
187
188 if (BN_is_negative(bn_order))
189 goto err;
190 if (BN_is_zero(bn_order))
191 goto err;
192 if (BN_num_bits(bn_order) > (int)field_bits + 1)
193 goto err;
194
195 if (!EC_GROUP_set_generator(group, point, bn_order, cofactor))
196 goto err;
197
198 EC_GROUP_set_asn1_flag(group, 0x0);
199
200 if ((key = EC_KEY_new()) == NULL)
201 goto err;
202
203 if (!EC_KEY_set_group(key, group))
204 goto err;
205
206 goto done;
207
208 err:
209 if (key)
210 EC_KEY_free(key);
211 key = NULL;
212
213 done:
214 /* some OpenSSL structures are mem-dup'ed into the key,
215 so we have to free our copies here */
216 if (bn_order)
217 BN_free(bn_order);
218 if (cofactor)
219 BN_free(cofactor);
220 if (a)
221 BN_free(a);
222 if (b)
223 BN_free(b);
224 if (p)
225 BN_free(p);
226 if (group)
227 EC_GROUP_free(group);
228 if (point)
229 EC_POINT_free(point);
230
231 return key;
232 }
233
point2term(ErlNifEnv * env,const EC_GROUP * group,const EC_POINT * point,point_conversion_form_t form)234 static ERL_NIF_TERM point2term(ErlNifEnv* env,
235 const EC_GROUP *group,
236 const EC_POINT *point,
237 point_conversion_form_t form)
238 {
239 ERL_NIF_TERM ret;
240 size_t dlen;
241 ErlNifBinary bin;
242 int bin_alloc = 0;
243
244 if ((dlen = EC_POINT_point2oct(group, point, form, NULL, 0, NULL)) == 0)
245 return atom_undefined;
246
247 if (!enif_alloc_binary(dlen, &bin))
248 goto err;
249 bin_alloc = 1;
250
251 if (!EC_POINT_point2oct(group, point, form, bin.data, bin.size, NULL))
252 goto err;
253
254 ERL_VALGRIND_MAKE_MEM_DEFINED(bin.data, bin.size);
255
256 ret = enif_make_binary(env, &bin);
257 bin_alloc = 0;
258 goto done;
259
260 err:
261 if (bin_alloc)
262 enif_release_binary(&bin);
263 ret = enif_make_badarg(env);
264
265 done:
266 return ret;
267 }
268
term2point(ErlNifEnv * env,ERL_NIF_TERM term,EC_GROUP * group,EC_POINT ** pptr)269 int term2point(ErlNifEnv* env, ERL_NIF_TERM term, EC_GROUP *group, EC_POINT **pptr)
270 {
271 ErlNifBinary bin;
272 EC_POINT *point = NULL;
273
274 if (!enif_inspect_binary(env, term, &bin))
275 goto err;
276
277 if ((point = EC_POINT_new(group)) == NULL)
278 goto err;
279
280 /* set the point conversion form */
281 EC_GROUP_set_point_conversion_form(group, (point_conversion_form_t)(bin.data[0] & ~0x01));
282
283 /* extract the ec point */
284 if (!EC_POINT_oct2point(group, point, bin.data, bin.size, NULL))
285 goto err;
286
287 *pptr = point;
288 return 1;
289
290 err:
291 if (point)
292 EC_POINT_free(point);
293 return 0;
294 }
295
get_ec_key(ErlNifEnv * env,ERL_NIF_TERM curve,ERL_NIF_TERM priv,ERL_NIF_TERM pub,EC_KEY ** res)296 int get_ec_key(ErlNifEnv* env,
297 ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub,
298 EC_KEY** res)
299 {
300 return get_ec_key_sz(env, curve, priv, pub, res, NULL);
301 }
302
get_ec_key_sz(ErlNifEnv * env,ERL_NIF_TERM curve,ERL_NIF_TERM priv,ERL_NIF_TERM pub,EC_KEY ** res,size_t * size)303 int get_ec_key_sz(ErlNifEnv* env,
304 ERL_NIF_TERM curve, ERL_NIF_TERM priv, ERL_NIF_TERM pub,
305 EC_KEY** res,
306 size_t* size)
307 {
308 EC_KEY *key = NULL;
309 BIGNUM *priv_key = NULL;
310 EC_POINT *pub_key = NULL;
311 EC_GROUP *group = NULL;
312
313 if (priv != atom_undefined) {
314 if (!get_bn_from_bin(env, priv, &priv_key))
315 goto err;
316 }
317 if (pub != atom_undefined) {
318 if (!enif_is_binary(env, pub))
319 goto err;
320 }
321
322 if ((key = ec_key_new(env, curve, size)) == NULL)
323 goto err;
324
325 if ((group = EC_GROUP_dup(EC_KEY_get0_group(key))) == NULL)
326 goto err;
327
328 if (term2point(env, pub, group, &pub_key)) {
329 if (!EC_KEY_set_public_key(key, pub_key))
330 goto err;
331 }
332
333 if (priv != atom_undefined && !BN_is_zero(priv_key)) {
334 if (!EC_KEY_set_private_key(key, priv_key))
335 goto err;
336
337 /* calculate public key (if necessary) */
338 if (EC_KEY_get0_public_key(key) == NULL) {
339 /* the public key was not included in the SEC1 private
340 * key => calculate the public key */
341 if ((pub_key = EC_POINT_new(group)) == NULL)
342 goto err;
343 if (!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group)))
344 goto err;
345 if (!EC_POINT_mul(group, pub_key, priv_key, NULL, NULL, NULL))
346 goto err;
347 if (!EC_KEY_set_public_key(key, pub_key))
348 goto err;
349 }
350 }
351 goto done;
352
353 err:
354 if (key)
355 EC_KEY_free(key);
356 key = NULL;
357
358 done:
359 /* some OpenSSL structures are mem-dup'ed into the key,
360 so we have to free our copies here */
361 if (priv_key)
362 BN_clear_free(priv_key);
363 if (group)
364 EC_GROUP_free(group);
365 if (pub_key)
366 EC_POINT_free(pub_key);
367
368 if (key == NULL)
369 return 0;
370
371 *res = key;
372 return 1;
373 }
374
375 #endif /* HAVE_EC */
376
ec_key_generate(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])377 ERL_NIF_TERM ec_key_generate(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
378 {
379 #if defined(HAVE_EC)
380 EC_KEY *key = NULL;
381 const EC_GROUP *group;
382 const EC_POINT *public_key;
383 ERL_NIF_TERM priv_key;
384 ERL_NIF_TERM pub_key;
385 ERL_NIF_TERM ret;
386 size_t size;
387
388 if (!get_ec_key_sz(env, argv[0], argv[1], atom_undefined, &key, &size))
389 goto bad_arg;
390
391 if (argv[1] == atom_undefined) {
392 if (!EC_KEY_generate_key(key))
393 goto err;
394 }
395
396 group = EC_KEY_get0_group(key);
397 public_key = EC_KEY_get0_public_key(key);
398
399 if (group == NULL || public_key == NULL) {
400 pub_key = atom_undefined;
401
402 } else {
403 pub_key = point2term(env, group, public_key,
404 EC_KEY_get_conv_form(key));
405 }
406
407 priv_key = bn2term(env, size, EC_KEY_get0_private_key(key));
408 ret = enif_make_tuple2(env, pub_key, priv_key);
409 goto done;
410
411 err:
412 bad_arg:
413 ret = make_badarg_maybe(env);
414
415 done:
416 if (key)
417 EC_KEY_free(key);
418 return ret;
419
420 #else
421 return atom_notsup;
422 #endif
423 }
424