xref: /openssl/test/ec_internal_test.c (revision 7ed6de99)
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