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
21static size_t crv_len = 0;
22static EC_builtin_curve *curves = NULL;
23
24/* sanity checks field_inv function pointer in EC_METHOD */
25static 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 */
75static 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 */
108static 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 */
125static 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 */
142static 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 */
150static 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. */
159static 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 */
209static 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 */
218static 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 */
246static 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 */
315static 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 */
348static 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
445static
446int 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
476end:
477    if (fp != NULL)
478        fclose(fp);
479
480    EC_GROUP_free(g1);
481    EC_GROUP_free(g2);
482
483    return testresult;
484}
485
486int 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
510void cleanup_tests(void)
511{
512    OPENSSL_free(curves);
513}
514