xref: /freebsd/crypto/openssl/test/ec_internal_test.c (revision 0d0c8621fd181e507f0fb50ffcca606faf66a8c2)
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