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 EC_GF2m_simple_method directly */
159static int field_tests_ec2_simple(void)
160{
161    TEST_info("Testing EC_GF2m_simple_method()\n");
162    return field_tests(EC_GF2m_simple_method(), params_b283,
163                       sizeof(params_b283) / 3);
164}
165#endif
166
167/* test default method for a named curve */
168static int field_tests_default(int n)
169{
170    BN_CTX *ctx = NULL;
171    EC_GROUP *group = NULL;
172    int nid = curves[n].nid;
173    int ret = 0;
174
175    TEST_info("Testing curve %s\n", OBJ_nid2sn(nid));
176
177    if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(nid))
178        || !TEST_ptr(ctx = BN_CTX_new())
179        || !group_field_tests(group, ctx))
180        goto err;
181
182    ret = 1;
183 err:
184    if (group != NULL)
185        EC_GROUP_free(group);
186    if (ctx != NULL)
187        BN_CTX_free(ctx);
188    return ret;
189}
190
191#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
192/*
193 * Tests a point known to cause an incorrect underflow in an old version of
194 * ecp_nist521.c
195 */
196static int underflow_test(void)
197{
198    BN_CTX *ctx = NULL;
199    EC_GROUP *grp = NULL;
200    EC_POINT *P = NULL, *Q = NULL, *R = NULL;
201    BIGNUM *x1 = NULL, *y1 = NULL, *z1 = NULL, *x2 = NULL, *y2 = NULL;
202    BIGNUM *k = NULL;
203    int testresult = 0;
204    const char *x1str =
205        "1534f0077fffffe87e9adcfe000000000000000000003e05a21d2400002e031b1f4"
206        "b80000c6fafa4f3c1288798d624a247b5e2ffffffffffffffefe099241900004";
207    const char *p521m1 =
208        "1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
209        "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe";
210
211    ctx = BN_CTX_new();
212    if (!TEST_ptr(ctx))
213        return 0;
214
215    BN_CTX_start(ctx);
216    x1 = BN_CTX_get(ctx);
217    y1 = BN_CTX_get(ctx);
218    z1 = BN_CTX_get(ctx);
219    x2 = BN_CTX_get(ctx);
220    y2 = BN_CTX_get(ctx);
221    k = BN_CTX_get(ctx);
222    if (!TEST_ptr(k))
223        goto err;
224
225    grp = EC_GROUP_new_by_curve_name(NID_secp521r1);
226    P = EC_POINT_new(grp);
227    Q = EC_POINT_new(grp);
228    R = EC_POINT_new(grp);
229    if (!TEST_ptr(grp) || !TEST_ptr(P) || !TEST_ptr(Q) || !TEST_ptr(R))
230        goto err;
231
232    if (!TEST_int_gt(BN_hex2bn(&x1, x1str), 0)
233            || !TEST_int_gt(BN_hex2bn(&y1, p521m1), 0)
234            || !TEST_int_gt(BN_hex2bn(&z1, p521m1), 0)
235            || !TEST_int_gt(BN_hex2bn(&k, "02"), 0)
236            || !TEST_true(ossl_ec_GFp_simple_set_Jprojective_coordinates_GFp(grp, P, x1,
237                                                                             y1, z1, ctx))
238            || !TEST_true(EC_POINT_mul(grp, Q, NULL, P, k, ctx))
239            || !TEST_true(EC_POINT_get_affine_coordinates(grp, Q, x1, y1, ctx))
240            || !TEST_true(EC_POINT_dbl(grp, R, P, ctx))
241            || !TEST_true(EC_POINT_get_affine_coordinates(grp, R, x2, y2, ctx)))
242        goto err;
243
244    if (!TEST_int_eq(BN_cmp(x1, x2), 0)
245            || !TEST_int_eq(BN_cmp(y1, y2), 0))
246        goto err;
247
248    testresult = 1;
249
250 err:
251    BN_CTX_end(ctx);
252    EC_POINT_free(P);
253    EC_POINT_free(Q);
254    EC_POINT_free(R);
255    EC_GROUP_free(grp);
256    BN_CTX_free(ctx);
257
258    return testresult;
259}
260#endif
261
262/*
263 * Tests behavior of the EC_KEY_set_private_key
264 */
265static int set_private_key(void)
266{
267    EC_KEY *key = NULL, *aux_key = NULL;
268    int testresult = 0;
269
270    key = EC_KEY_new_by_curve_name(NID_secp224r1);
271    aux_key = EC_KEY_new_by_curve_name(NID_secp224r1);
272    if (!TEST_ptr(key)
273        || !TEST_ptr(aux_key)
274        || !TEST_int_eq(EC_KEY_generate_key(key), 1)
275        || !TEST_int_eq(EC_KEY_generate_key(aux_key), 1))
276        goto err;
277
278    /* Test setting a valid private key */
279    if (!TEST_int_eq(EC_KEY_set_private_key(key, aux_key->priv_key), 1))
280        goto err;
281
282    /* Test compliance with legacy behavior for NULL private keys */
283    if (!TEST_int_eq(EC_KEY_set_private_key(key, NULL), 0)
284        || !TEST_ptr_null(key->priv_key))
285        goto err;
286
287    testresult = 1;
288
289 err:
290    EC_KEY_free(key);
291    EC_KEY_free(aux_key);
292    return testresult;
293}
294
295/*
296 * Tests behavior of the decoded_from_explicit_params flag and API
297 */
298static int decoded_flag_test(void)
299{
300    EC_GROUP *grp;
301    EC_GROUP *grp_copy = NULL;
302    ECPARAMETERS *ecparams = NULL;
303    ECPKPARAMETERS *ecpkparams = NULL;
304    EC_KEY *key = NULL;
305    unsigned char *encodedparams = NULL;
306    const unsigned char *encp;
307    int encodedlen;
308    int testresult = 0;
309
310    /* Test EC_GROUP_new not setting the flag */
311    grp = EC_GROUP_new(EC_GFp_simple_method());
312    if (!TEST_ptr(grp)
313        || !TEST_int_eq(grp->decoded_from_explicit_params, 0))
314        goto err;
315    EC_GROUP_free(grp);
316
317    /* Test EC_GROUP_new_by_curve_name not setting the flag */
318    grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
319    if (!TEST_ptr(grp)
320        || !TEST_int_eq(grp->decoded_from_explicit_params, 0))
321        goto err;
322
323    /* Test EC_GROUP_new_from_ecparameters not setting the flag */
324    if (!TEST_ptr(ecparams = EC_GROUP_get_ecparameters(grp, NULL))
325        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecparameters(ecparams))
326        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
327        goto err;
328    EC_GROUP_free(grp_copy);
329    grp_copy = NULL;
330    ECPARAMETERS_free(ecparams);
331    ecparams = NULL;
332
333    /* Test EC_GROUP_new_from_ecpkparameters not setting the flag */
334    if (!TEST_int_eq(EC_GROUP_get_asn1_flag(grp), OPENSSL_EC_NAMED_CURVE)
335        || !TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL))
336        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams))
337        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0)
338        || !TEST_ptr(key = EC_KEY_new())
339    /* Test EC_KEY_decoded_from_explicit_params on key without a group */
340        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), -1)
341        || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1)
342    /* Test EC_KEY_decoded_from_explicit_params negative case */
343        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 0))
344        goto err;
345    EC_GROUP_free(grp_copy);
346    grp_copy = NULL;
347    ECPKPARAMETERS_free(ecpkparams);
348    ecpkparams = NULL;
349
350    /* Test d2i_ECPKParameters with named params not setting the flag */
351    if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0)
352        || !TEST_ptr(encp = encodedparams)
353        || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen))
354        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
355        goto err;
356    EC_GROUP_free(grp_copy);
357    grp_copy = NULL;
358    OPENSSL_free(encodedparams);
359    encodedparams = NULL;
360
361    /* Asn1 flag stays set to explicit with EC_GROUP_new_from_ecpkparameters */
362    EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_EXPLICIT_CURVE);
363    if (!TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL))
364        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams))
365        || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE)
366        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
367        goto err;
368    EC_GROUP_free(grp_copy);
369    grp_copy = NULL;
370
371    /* Test d2i_ECPKParameters with explicit params setting the flag */
372    if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0)
373        || !TEST_ptr(encp = encodedparams)
374        || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen))
375        || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE)
376        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 1)
377        || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1)
378    /* Test EC_KEY_decoded_from_explicit_params positive case */
379        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 1))
380        goto err;
381
382    testresult = 1;
383
384 err:
385    EC_KEY_free(key);
386    EC_GROUP_free(grp);
387    EC_GROUP_free(grp_copy);
388    ECPARAMETERS_free(ecparams);
389    ECPKPARAMETERS_free(ecpkparams);
390    OPENSSL_free(encodedparams);
391
392    return testresult;
393}
394
395static
396int ecpkparams_i2d2i_test(int n)
397{
398    EC_GROUP *g1 = NULL, *g2 = NULL;
399    FILE *fp = NULL;
400    int nid = curves[n].nid;
401    int testresult = 0;
402
403    /* create group */
404    if (!TEST_ptr(g1 = EC_GROUP_new_by_curve_name(nid)))
405        goto end;
406
407    /* encode params to file */
408    if (!TEST_ptr(fp = fopen("params.der", "wb"))
409            || !TEST_true(i2d_ECPKParameters_fp(fp, g1)))
410        goto end;
411
412    /* flush and close file */
413    if (!TEST_int_eq(fclose(fp), 0)) {
414        fp = NULL;
415        goto end;
416    }
417    fp = NULL;
418
419    /* decode params from file */
420    if (!TEST_ptr(fp = fopen("params.der", "rb"))
421            || !TEST_ptr(g2 = d2i_ECPKParameters_fp(fp, NULL)))
422        goto end;
423
424    testresult = 1; /* PASS */
425
426end:
427    if (fp != NULL)
428        fclose(fp);
429
430    EC_GROUP_free(g1);
431    EC_GROUP_free(g2);
432
433    return testresult;
434}
435
436int setup_tests(void)
437{
438    crv_len = EC_get_builtin_curves(NULL, 0);
439    if (!TEST_ptr(curves = OPENSSL_malloc(sizeof(*curves) * crv_len))
440        || !TEST_true(EC_get_builtin_curves(curves, crv_len)))
441        return 0;
442
443    ADD_TEST(field_tests_ecp_simple);
444    ADD_TEST(field_tests_ecp_mont);
445#ifndef OPENSSL_NO_EC2M
446    ADD_TEST(field_tests_ec2_simple);
447#endif
448    ADD_ALL_TESTS(field_tests_default, crv_len);
449#ifndef OPENSSL_NO_EC_NISTP_64_GCC_128
450    ADD_TEST(underflow_test);
451#endif
452    ADD_TEST(set_private_key);
453    ADD_TEST(decoded_flag_test);
454    ADD_ALL_TESTS(ecpkparams_i2d2i_test, crv_len);
455
456    return 1;
457}
458
459void cleanup_tests(void)
460{
461    OPENSSL_free(curves);
462}
463