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