1 /*
2 * Copyright 2019-2022 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 /*
11 * Low level APIs are deprecated for public use, but still ok for internal use.
12 */
13 #include "internal/deprecated.h"
14
15 #include "internal/nelem.h"
16 #include "testutil.h"
17 #include <openssl/ec.h>
18 #include "ec_local.h"
19 #include <openssl/objects.h>
20
21 static size_t crv_len = 0;
22 static EC_builtin_curve *curves = NULL;
23
24 /* sanity checks field_inv function pointer in EC_METHOD */
group_field_tests(const EC_GROUP * group,BN_CTX * ctx)25 static int group_field_tests(const EC_GROUP *group, BN_CTX *ctx)
26 {
27 BIGNUM *a = NULL, *b = NULL, *c = NULL;
28 int ret = 0;
29
30 if (group->meth->field_inv == NULL || group->meth->field_mul == NULL)
31 return 1;
32
33 BN_CTX_start(ctx);
34 a = BN_CTX_get(ctx);
35 b = BN_CTX_get(ctx);
36 if (!TEST_ptr(c = BN_CTX_get(ctx))
37 /* 1/1 = 1 */
38 || !TEST_true(group->meth->field_inv(group, b, BN_value_one(), ctx))
39 || !TEST_true(BN_is_one(b))
40 /* (1/a)*a = 1 */
41 || !TEST_true(BN_rand(a, BN_num_bits(group->field) - 1,
42 BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
43 || !TEST_true(group->meth->field_inv(group, b, a, ctx))
44 || (group->meth->field_encode &&
45 !TEST_true(group->meth->field_encode(group, a, a, ctx)))
46 || (group->meth->field_encode &&
47 !TEST_true(group->meth->field_encode(group, b, b, ctx)))
48 || !TEST_true(group->meth->field_mul(group, c, a, b, ctx))
49 || (group->meth->field_decode &&
50 !TEST_true(group->meth->field_decode(group, c, c, ctx)))
51 || !TEST_true(BN_is_one(c)))
52 goto err;
53
54 /* 1/0 = error */
55 BN_zero(a);
56 if (!TEST_false(group->meth->field_inv(group, b, a, ctx))
57 || !TEST_true(ERR_GET_LIB(ERR_peek_last_error()) == ERR_LIB_EC)
58 || !TEST_true(ERR_GET_REASON(ERR_peek_last_error()) ==
59 EC_R_CANNOT_INVERT)
60 /* 1/p = error */
61 || !TEST_false(group->meth->field_inv(group, b, group->field, ctx))
62 || !TEST_true(ERR_GET_LIB(ERR_peek_last_error()) == ERR_LIB_EC)
63 || !TEST_true(ERR_GET_REASON(ERR_peek_last_error()) ==
64 EC_R_CANNOT_INVERT))
65 goto err;
66
67 ERR_clear_error();
68 ret = 1;
69 err:
70 BN_CTX_end(ctx);
71 return ret;
72 }
73
74 /* wrapper for group_field_tests for explicit curve params and EC_METHOD */
field_tests(const EC_METHOD * meth,const unsigned char * params,int len)75 static int field_tests(const EC_METHOD *meth, const unsigned char *params,
76 int len)
77 {
78 BN_CTX *ctx = NULL;
79 BIGNUM *p = NULL, *a = NULL, *b = NULL;
80 EC_GROUP *group = NULL;
81 int ret = 0;
82
83 if (!TEST_ptr(ctx = BN_CTX_new()))
84 return 0;
85
86 BN_CTX_start(ctx);
87 p = BN_CTX_get(ctx);
88 a = BN_CTX_get(ctx);
89 if (!TEST_ptr(b = BN_CTX_get(ctx))
90 || !TEST_ptr(group = EC_GROUP_new(meth))
91 || !TEST_true(BN_bin2bn(params, len, p))
92 || !TEST_true(BN_bin2bn(params + len, len, a))
93 || !TEST_true(BN_bin2bn(params + 2 * len, len, b))
94 || !TEST_true(EC_GROUP_set_curve(group, p, a, b, ctx))
95 || !group_field_tests(group, ctx))
96 goto err;
97 ret = 1;
98
99 err:
100 BN_CTX_end(ctx);
101 BN_CTX_free(ctx);
102 if (group != NULL)
103 EC_GROUP_free(group);
104 return ret;
105 }
106
107 /* NIST prime curve P-256 */
108 static const unsigned char params_p256[] = {
109 /* p */
110 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
112 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
113 /* a */
114 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
116 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
117 /* b */
118 0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55,
119 0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6,
120 0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B
121 };
122
123 #ifndef OPENSSL_NO_EC2M
124 /* NIST binary curve B-283 */
125 static const unsigned char params_b283[] = {
126 /* p */
127 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA1,
130 /* a */
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
134 /* b */
135 0x02, 0x7B, 0x68, 0x0A, 0xC8, 0xB8, 0x59, 0x6D, 0xA5, 0xA4, 0xAF, 0x8A,
136 0x19, 0xA0, 0x30, 0x3F, 0xCA, 0x97, 0xFD, 0x76, 0x45, 0x30, 0x9F, 0xA2,
137 0xA5, 0x81, 0x48, 0x5A, 0xF6, 0x26, 0x3E, 0x31, 0x3B, 0x79, 0xA2, 0xF5
138 };
139 #endif
140
141 /* test EC_GFp_simple_method directly */
field_tests_ecp_simple(void)142 static int field_tests_ecp_simple(void)
143 {
144 TEST_info("Testing EC_GFp_simple_method()\n");
145 return field_tests(EC_GFp_simple_method(), params_p256,
146 sizeof(params_p256) / 3);
147 }
148
149 /* test EC_GFp_mont_method directly */
field_tests_ecp_mont(void)150 static int field_tests_ecp_mont(void)
151 {
152 TEST_info("Testing EC_GFp_mont_method()\n");
153 return field_tests(EC_GFp_mont_method(), params_p256,
154 sizeof(params_p256) / 3);
155 }
156
157 #ifndef OPENSSL_NO_EC2M
158 /* Test that decoding of invalid GF2m field parameters fails. */
ec2m_field_sanity(void)159 static int ec2m_field_sanity(void)
160 {
161 int ret = 0;
162 BN_CTX *ctx = BN_CTX_new();
163 BIGNUM *p, *a, *b;
164 EC_GROUP *group1 = NULL, *group2 = NULL, *group3 = NULL;
165
166 TEST_info("Testing GF2m hardening\n");
167
168 BN_CTX_start(ctx);
169 p = BN_CTX_get(ctx);
170 a = BN_CTX_get(ctx);
171 if (!TEST_ptr(b = BN_CTX_get(ctx))
172 || !TEST_true(BN_one(a))
173 || !TEST_true(BN_one(b)))
174 goto out;
175
176 /* Even pentanomial value should be rejected */
177 if (!TEST_true(BN_set_word(p, 0xf2)))
178 goto out;
179 if (!TEST_ptr_null(group1 = EC_GROUP_new_curve_GF2m(p, a, b, ctx)))
180 TEST_error("Zero constant term accepted in GF2m polynomial");
181
182 /* Odd hexanomial should also be rejected */
183 if (!TEST_true(BN_set_word(p, 0xf3)))
184 goto out;
185 if (!TEST_ptr_null(group2 = EC_GROUP_new_curve_GF2m(p, a, b, ctx)))
186 TEST_error("Hexanomial accepted as GF2m polynomial");
187
188 /* Excessive polynomial degree should also be rejected */
189 if (!TEST_true(BN_set_word(p, 0x71))
190 || !TEST_true(BN_set_bit(p, OPENSSL_ECC_MAX_FIELD_BITS + 1)))
191 goto out;
192 if (!TEST_ptr_null(group3 = EC_GROUP_new_curve_GF2m(p, a, b, ctx)))
193 TEST_error("GF2m polynomial degree > %d accepted",
194 OPENSSL_ECC_MAX_FIELD_BITS);
195
196 ret = group1 == NULL && group2 == NULL && group3 == NULL;
197
198 out:
199 EC_GROUP_free(group1);
200 EC_GROUP_free(group2);
201 EC_GROUP_free(group3);
202 BN_CTX_end(ctx);
203 BN_CTX_free(ctx);
204
205 return ret;
206 }
207
208 /* test EC_GF2m_simple_method directly */
field_tests_ec2_simple(void)209 static int field_tests_ec2_simple(void)
210 {
211 TEST_info("Testing EC_GF2m_simple_method()\n");
212 return field_tests(EC_GF2m_simple_method(), params_b283,
213 sizeof(params_b283) / 3);
214 }
215 #endif
216
217 /* test default method for a named curve */
field_tests_default(int n)218 static int field_tests_default(int n)
219 {
220 BN_CTX *ctx = NULL;
221 EC_GROUP *group = NULL;
222 int nid = curves[n].nid;
223 int ret = 0;
224
225 TEST_info("Testing curve %s\n", OBJ_nid2sn(nid));
226
227 if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(nid))
228 || !TEST_ptr(ctx = BN_CTX_new())
229 || !group_field_tests(group, ctx))
230 goto err;
231
232 ret = 1;
233 err:
234 if (group != NULL)
235 EC_GROUP_free(group);
236 if (ctx != NULL)
237 BN_CTX_free(ctx);
238 return ret;
239 }
240
241 #ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
242 /*
243 * Tests a point known to cause an incorrect underflow in an old version of
244 * ecp_nist521.c
245 */
underflow_test(void)246 static int underflow_test(void)
247 {
248 BN_CTX *ctx = NULL;
249 EC_GROUP *grp = NULL;
250 EC_POINT *P = NULL, *Q = NULL, *R = NULL;
251 BIGNUM *x1 = NULL, *y1 = NULL, *z1 = NULL, *x2 = NULL, *y2 = NULL;
252 BIGNUM *k = NULL;
253 int testresult = 0;
254 const char *x1str =
255 "1534f0077fffffe87e9adcfe000000000000000000003e05a21d2400002e031b1f4"
256 "b80000c6fafa4f3c1288798d624a247b5e2ffffffffffffffefe099241900004";
257 const char *p521m1 =
258 "1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
259 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe";
260
261 ctx = BN_CTX_new();
262 if (!TEST_ptr(ctx))
263 return 0;
264
265 BN_CTX_start(ctx);
266 x1 = BN_CTX_get(ctx);
267 y1 = BN_CTX_get(ctx);
268 z1 = BN_CTX_get(ctx);
269 x2 = BN_CTX_get(ctx);
270 y2 = BN_CTX_get(ctx);
271 k = BN_CTX_get(ctx);
272 if (!TEST_ptr(k))
273 goto err;
274
275 grp = EC_GROUP_new_by_curve_name(NID_secp521r1);
276 P = EC_POINT_new(grp);
277 Q = EC_POINT_new(grp);
278 R = EC_POINT_new(grp);
279 if (!TEST_ptr(grp) || !TEST_ptr(P) || !TEST_ptr(Q) || !TEST_ptr(R))
280 goto err;
281
282 if (!TEST_int_gt(BN_hex2bn(&x1, x1str), 0)
283 || !TEST_int_gt(BN_hex2bn(&y1, p521m1), 0)
284 || !TEST_int_gt(BN_hex2bn(&z1, p521m1), 0)
285 || !TEST_int_gt(BN_hex2bn(&k, "02"), 0)
286 || !TEST_true(ossl_ec_GFp_simple_set_Jprojective_coordinates_GFp(grp, P, x1,
287 y1, z1, ctx))
288 || !TEST_true(EC_POINT_mul(grp, Q, NULL, P, k, ctx))
289 || !TEST_true(EC_POINT_get_affine_coordinates(grp, Q, x1, y1, ctx))
290 || !TEST_true(EC_POINT_dbl(grp, R, P, ctx))
291 || !TEST_true(EC_POINT_get_affine_coordinates(grp, R, x2, y2, ctx)))
292 goto err;
293
294 if (!TEST_int_eq(BN_cmp(x1, x2), 0)
295 || !TEST_int_eq(BN_cmp(y1, y2), 0))
296 goto err;
297
298 testresult = 1;
299
300 err:
301 BN_CTX_end(ctx);
302 EC_POINT_free(P);
303 EC_POINT_free(Q);
304 EC_POINT_free(R);
305 EC_GROUP_free(grp);
306 BN_CTX_free(ctx);
307
308 return testresult;
309 }
310 #endif
311
312 /*
313 * Tests behavior of the EC_KEY_set_private_key
314 */
set_private_key(void)315 static int set_private_key(void)
316 {
317 EC_KEY *key = NULL, *aux_key = NULL;
318 int testresult = 0;
319
320 key = EC_KEY_new_by_curve_name(NID_secp224r1);
321 aux_key = EC_KEY_new_by_curve_name(NID_secp224r1);
322 if (!TEST_ptr(key)
323 || !TEST_ptr(aux_key)
324 || !TEST_int_eq(EC_KEY_generate_key(key), 1)
325 || !TEST_int_eq(EC_KEY_generate_key(aux_key), 1))
326 goto err;
327
328 /* Test setting a valid private key */
329 if (!TEST_int_eq(EC_KEY_set_private_key(key, aux_key->priv_key), 1))
330 goto err;
331
332 /* Test compliance with legacy behavior for NULL private keys */
333 if (!TEST_int_eq(EC_KEY_set_private_key(key, NULL), 0)
334 || !TEST_ptr_null(key->priv_key))
335 goto err;
336
337 testresult = 1;
338
339 err:
340 EC_KEY_free(key);
341 EC_KEY_free(aux_key);
342 return testresult;
343 }
344
345 /*
346 * Tests behavior of the decoded_from_explicit_params flag and API
347 */
decoded_flag_test(void)348 static int decoded_flag_test(void)
349 {
350 EC_GROUP *grp;
351 EC_GROUP *grp_copy = NULL;
352 ECPARAMETERS *ecparams = NULL;
353 ECPKPARAMETERS *ecpkparams = NULL;
354 EC_KEY *key = NULL;
355 unsigned char *encodedparams = NULL;
356 const unsigned char *encp;
357 int encodedlen;
358 int testresult = 0;
359
360 /* Test EC_GROUP_new not setting the flag */
361 grp = EC_GROUP_new(EC_GFp_simple_method());
362 if (!TEST_ptr(grp)
363 || !TEST_int_eq(grp->decoded_from_explicit_params, 0))
364 goto err;
365 EC_GROUP_free(grp);
366
367 /* Test EC_GROUP_new_by_curve_name not setting the flag */
368 grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
369 if (!TEST_ptr(grp)
370 || !TEST_int_eq(grp->decoded_from_explicit_params, 0))
371 goto err;
372
373 /* Test EC_GROUP_new_from_ecparameters not setting the flag */
374 if (!TEST_ptr(ecparams = EC_GROUP_get_ecparameters(grp, NULL))
375 || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecparameters(ecparams))
376 || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
377 goto err;
378 EC_GROUP_free(grp_copy);
379 grp_copy = NULL;
380 ECPARAMETERS_free(ecparams);
381 ecparams = NULL;
382
383 /* Test EC_GROUP_new_from_ecpkparameters not setting the flag */
384 if (!TEST_int_eq(EC_GROUP_get_asn1_flag(grp), OPENSSL_EC_NAMED_CURVE)
385 || !TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL))
386 || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams))
387 || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0)
388 || !TEST_ptr(key = EC_KEY_new())
389 /* Test EC_KEY_decoded_from_explicit_params on key without a group */
390 || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), -1)
391 || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1)
392 /* Test EC_KEY_decoded_from_explicit_params negative case */
393 || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 0))
394 goto err;
395 EC_GROUP_free(grp_copy);
396 grp_copy = NULL;
397 ECPKPARAMETERS_free(ecpkparams);
398 ecpkparams = NULL;
399
400 /* Test d2i_ECPKParameters with named params not setting the flag */
401 if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0)
402 || !TEST_ptr(encp = encodedparams)
403 || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen))
404 || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
405 goto err;
406 EC_GROUP_free(grp_copy);
407 grp_copy = NULL;
408 OPENSSL_free(encodedparams);
409 encodedparams = NULL;
410
411 /* Asn1 flag stays set to explicit with EC_GROUP_new_from_ecpkparameters */
412 EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_EXPLICIT_CURVE);
413 if (!TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL))
414 || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams))
415 || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE)
416 || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
417 goto err;
418 EC_GROUP_free(grp_copy);
419 grp_copy = NULL;
420
421 /* Test d2i_ECPKParameters with explicit params setting the flag */
422 if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0)
423 || !TEST_ptr(encp = encodedparams)
424 || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen))
425 || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE)
426 || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 1)
427 || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1)
428 /* Test EC_KEY_decoded_from_explicit_params positive case */
429 || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 1))
430 goto err;
431
432 testresult = 1;
433
434 err:
435 EC_KEY_free(key);
436 EC_GROUP_free(grp);
437 EC_GROUP_free(grp_copy);
438 ECPARAMETERS_free(ecparams);
439 ECPKPARAMETERS_free(ecpkparams);
440 OPENSSL_free(encodedparams);
441
442 return testresult;
443 }
444
445 static
ecpkparams_i2d2i_test(int n)446 int ecpkparams_i2d2i_test(int n)
447 {
448 EC_GROUP *g1 = NULL, *g2 = NULL;
449 FILE *fp = NULL;
450 int nid = curves[n].nid;
451 int testresult = 0;
452
453 /* create group */
454 if (!TEST_ptr(g1 = EC_GROUP_new_by_curve_name(nid)))
455 goto end;
456
457 /* encode params to file */
458 if (!TEST_ptr(fp = fopen("params.der", "wb"))
459 || !TEST_true(i2d_ECPKParameters_fp(fp, g1)))
460 goto end;
461
462 /* flush and close file */
463 if (!TEST_int_eq(fclose(fp), 0)) {
464 fp = NULL;
465 goto end;
466 }
467 fp = NULL;
468
469 /* decode params from file */
470 if (!TEST_ptr(fp = fopen("params.der", "rb"))
471 || !TEST_ptr(g2 = d2i_ECPKParameters_fp(fp, NULL)))
472 goto end;
473
474 testresult = 1; /* PASS */
475
476 end:
477 if (fp != NULL)
478 fclose(fp);
479
480 EC_GROUP_free(g1);
481 EC_GROUP_free(g2);
482
483 return testresult;
484 }
485
setup_tests(void)486 int setup_tests(void)
487 {
488 crv_len = EC_get_builtin_curves(NULL, 0);
489 if (!TEST_ptr(curves = OPENSSL_malloc(sizeof(*curves) * crv_len))
490 || !TEST_true(EC_get_builtin_curves(curves, crv_len)))
491 return 0;
492
493 ADD_TEST(field_tests_ecp_simple);
494 ADD_TEST(field_tests_ecp_mont);
495 #ifndef OPENSSL_NO_EC2M
496 ADD_TEST(ec2m_field_sanity);
497 ADD_TEST(field_tests_ec2_simple);
498 #endif
499 ADD_ALL_TESTS(field_tests_default, crv_len);
500 #ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
501 ADD_TEST(underflow_test);
502 #endif
503 ADD_TEST(set_private_key);
504 ADD_TEST(decoded_flag_test);
505 ADD_ALL_TESTS(ecpkparams_i2d2i_test, crv_len);
506
507 return 1;
508 }
509
cleanup_tests(void)510 void cleanup_tests(void)
511 {
512 OPENSSL_free(curves);
513 }
514