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#include "internal/nelem.h"
11#include "testutil.h"
12#include <openssl/ec.h>
13#include "ec_local.h"
14#include <openssl/objects.h>
15
16static size_t crv_len = 0;
17static EC_builtin_curve *curves = NULL;
18
19/* sanity checks field_inv function pointer in EC_METHOD */
20static int group_field_tests(const EC_GROUP *group, BN_CTX *ctx)
21{
22    BIGNUM *a = NULL, *b = NULL, *c = NULL;
23    int ret = 0;
24
25    if (group->meth->field_inv == NULL || group->meth->field_mul == NULL)
26        return 1;
27
28    BN_CTX_start(ctx);
29    a = BN_CTX_get(ctx);
30    b = BN_CTX_get(ctx);
31    if (!TEST_ptr(c = BN_CTX_get(ctx))
32        /* 1/1 = 1 */
33        || !TEST_true(group->meth->field_inv(group, b, BN_value_one(), ctx))
34        || !TEST_true(BN_is_one(b))
35        /* (1/a)*a = 1 */
36        || !TEST_true(BN_pseudo_rand(a, BN_num_bits(group->field) - 1,
37                                     BN_RAND_TOP_ONE, BN_RAND_BOTTOM_ANY))
38        || !TEST_true(group->meth->field_inv(group, b, a, ctx))
39        || (group->meth->field_encode &&
40            !TEST_true(group->meth->field_encode(group, a, a, ctx)))
41        || (group->meth->field_encode &&
42            !TEST_true(group->meth->field_encode(group, b, b, ctx)))
43        || !TEST_true(group->meth->field_mul(group, c, a, b, ctx))
44        || (group->meth->field_decode &&
45            !TEST_true(group->meth->field_decode(group, c, c, ctx)))
46        || !TEST_true(BN_is_one(c)))
47        goto err;
48
49    /* 1/0 = error */
50    BN_zero(a);
51    if (!TEST_false(group->meth->field_inv(group, b, a, ctx))
52        || !TEST_true(ERR_GET_LIB(ERR_peek_last_error()) == ERR_LIB_EC)
53        || !TEST_true(ERR_GET_REASON(ERR_peek_last_error()) ==
54                      EC_R_CANNOT_INVERT)
55        /* 1/p = error */
56        || !TEST_false(group->meth->field_inv(group, b, group->field, 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        goto err;
61
62    ERR_clear_error();
63    ret = 1;
64 err:
65    BN_CTX_end(ctx);
66    return ret;
67}
68
69/* wrapper for group_field_tests for explicit curve params and EC_METHOD */
70static int field_tests(const EC_METHOD *meth, const unsigned char *params,
71                       int len)
72{
73    BN_CTX *ctx = NULL;
74    BIGNUM *p = NULL, *a = NULL, *b = NULL;
75    EC_GROUP *group = NULL;
76    int ret = 0;
77
78    if (!TEST_ptr(ctx = BN_CTX_new()))
79        return 0;
80
81    BN_CTX_start(ctx);
82    p = BN_CTX_get(ctx);
83    a = BN_CTX_get(ctx);
84    if (!TEST_ptr(b = BN_CTX_get(ctx))
85        || !TEST_ptr(group = EC_GROUP_new(meth))
86        || !TEST_true(BN_bin2bn(params, len, p))
87        || !TEST_true(BN_bin2bn(params + len, len, a))
88        || !TEST_true(BN_bin2bn(params + 2 * len, len, b))
89        || !TEST_true(EC_GROUP_set_curve(group, p, a, b, ctx))
90        || !group_field_tests(group, ctx))
91        goto err;
92    ret = 1;
93
94 err:
95    BN_CTX_end(ctx);
96    BN_CTX_free(ctx);
97    if (group != NULL)
98        EC_GROUP_free(group);
99    return ret;
100}
101
102/* NIST prime curve P-256 */
103static const unsigned char params_p256[] = {
104    /* p */
105    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
106    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
107    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
108    /* a */
109    0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
110    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
111    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC,
112    /* b */
113    0x5A, 0xC6, 0x35, 0xD8, 0xAA, 0x3A, 0x93, 0xE7, 0xB3, 0xEB, 0xBD, 0x55,
114    0x76, 0x98, 0x86, 0xBC, 0x65, 0x1D, 0x06, 0xB0, 0xCC, 0x53, 0xB0, 0xF6,
115    0x3B, 0xCE, 0x3C, 0x3E, 0x27, 0xD2, 0x60, 0x4B
116};
117
118#ifndef OPENSSL_NO_EC2M
119/* NIST binary curve B-283 */
120static const unsigned char params_b283[] = {
121    /* p */
122    0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
123    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
124    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xA1,
125    /* a */
126    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
129    /* b */
130    0x02, 0x7B, 0x68, 0x0A, 0xC8, 0xB8, 0x59, 0x6D, 0xA5, 0xA4, 0xAF, 0x8A,
131    0x19, 0xA0, 0x30, 0x3F, 0xCA, 0x97, 0xFD, 0x76, 0x45, 0x30, 0x9F, 0xA2,
132    0xA5, 0x81, 0x48, 0x5A, 0xF6, 0x26, 0x3E, 0x31, 0x3B, 0x79, 0xA2, 0xF5
133};
134#endif
135
136/* test EC_GFp_simple_method directly */
137static int field_tests_ecp_simple(void)
138{
139    TEST_info("Testing EC_GFp_simple_method()\n");
140    return field_tests(EC_GFp_simple_method(), params_p256,
141                       sizeof(params_p256) / 3);
142}
143
144/* test EC_GFp_mont_method directly */
145static int field_tests_ecp_mont(void)
146{
147    TEST_info("Testing EC_GFp_mont_method()\n");
148    return field_tests(EC_GFp_mont_method(), params_p256,
149                       sizeof(params_p256) / 3);
150}
151
152#ifndef OPENSSL_NO_EC2M
153/* test EC_GF2m_simple_method directly */
154static int field_tests_ec2_simple(void)
155{
156    TEST_info("Testing EC_GF2m_simple_method()\n");
157    return field_tests(EC_GF2m_simple_method(), params_b283,
158                       sizeof(params_b283) / 3);
159}
160#endif
161
162/* test default method for a named curve */
163static int field_tests_default(int n)
164{
165    BN_CTX *ctx = NULL;
166    EC_GROUP *group = NULL;
167    int nid = curves[n].nid;
168    int ret = 0;
169
170    TEST_info("Testing curve %s\n", OBJ_nid2sn(nid));
171
172    if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(nid))
173        || !TEST_ptr(ctx = BN_CTX_new())
174        || !group_field_tests(group, ctx))
175        goto err;
176
177    ret = 1;
178 err:
179    if (group != NULL)
180        EC_GROUP_free(group);
181    if (ctx != NULL)
182        BN_CTX_free(ctx);
183    return ret;
184}
185
186/*
187 * Tests behavior of the EC_KEY_set_private_key
188 */
189static int set_private_key(void)
190{
191    EC_KEY *key = NULL, *aux_key = NULL;
192    int testresult = 0;
193
194    key = EC_KEY_new_by_curve_name(NID_secp224r1);
195    aux_key = EC_KEY_new_by_curve_name(NID_secp224r1);
196    if (!TEST_ptr(key)
197        || !TEST_ptr(aux_key)
198        || !TEST_int_eq(EC_KEY_generate_key(key), 1)
199        || !TEST_int_eq(EC_KEY_generate_key(aux_key), 1))
200        goto err;
201
202    /* Test setting a valid private key */
203    if (!TEST_int_eq(EC_KEY_set_private_key(key, aux_key->priv_key), 1))
204        goto err;
205
206    /* Test compliance with legacy behavior for NULL private keys */
207    if (!TEST_int_eq(EC_KEY_set_private_key(key, NULL), 0)
208        || !TEST_ptr_null(key->priv_key))
209        goto err;
210
211    testresult = 1;
212
213 err:
214    EC_KEY_free(key);
215    EC_KEY_free(aux_key);
216    return testresult;
217}
218
219/*
220 * Tests behavior of the decoded_from_explicit_params flag and API
221 */
222static int decoded_flag_test(void)
223{
224    EC_GROUP *grp;
225    EC_GROUP *grp_copy = NULL;
226    ECPARAMETERS *ecparams = NULL;
227    ECPKPARAMETERS *ecpkparams = NULL;
228    EC_KEY *key = NULL;
229    unsigned char *encodedparams = NULL;
230    const unsigned char *encp;
231    int encodedlen;
232    int testresult = 0;
233
234    /* Test EC_GROUP_new not setting the flag */
235    grp = EC_GROUP_new(EC_GFp_simple_method());
236    if (!TEST_ptr(grp)
237        || !TEST_int_eq(grp->decoded_from_explicit_params, 0))
238        goto err;
239    EC_GROUP_free(grp);
240
241    /* Test EC_GROUP_new_by_curve_name not setting the flag */
242    grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
243    if (!TEST_ptr(grp)
244        || !TEST_int_eq(grp->decoded_from_explicit_params, 0))
245        goto err;
246
247    /* Test EC_GROUP_new_from_ecparameters not setting the flag */
248    if (!TEST_ptr(ecparams = EC_GROUP_get_ecparameters(grp, NULL))
249        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecparameters(ecparams))
250        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
251        goto err;
252    EC_GROUP_free(grp_copy);
253    grp_copy = NULL;
254    ECPARAMETERS_free(ecparams);
255    ecparams = NULL;
256
257    /* Test EC_GROUP_new_from_ecpkparameters not setting the flag */
258    if (!TEST_int_eq(EC_GROUP_get_asn1_flag(grp), OPENSSL_EC_NAMED_CURVE)
259        || !TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL))
260        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams))
261        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0)
262        || !TEST_ptr(key = EC_KEY_new())
263    /* Test EC_KEY_decoded_from_explicit_params on key without a group */
264        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), -1)
265        || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1)
266    /* Test EC_KEY_decoded_from_explicit_params negative case */
267        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 0))
268        goto err;
269    EC_GROUP_free(grp_copy);
270    grp_copy = NULL;
271    ECPKPARAMETERS_free(ecpkparams);
272    ecpkparams = NULL;
273
274    /* Test d2i_ECPKParameters with named params not setting the flag */
275    if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0)
276        || !TEST_ptr(encp = encodedparams)
277        || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen))
278        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
279        goto err;
280    EC_GROUP_free(grp_copy);
281    grp_copy = NULL;
282    OPENSSL_free(encodedparams);
283    encodedparams = NULL;
284
285    /* Asn1 flag stays set to explicit with EC_GROUP_new_from_ecpkparameters */
286    EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_EXPLICIT_CURVE);
287    if (!TEST_ptr(ecpkparams = EC_GROUP_get_ecpkparameters(grp, NULL))
288        || !TEST_ptr(grp_copy = EC_GROUP_new_from_ecpkparameters(ecpkparams))
289        || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE)
290        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 0))
291        goto err;
292    EC_GROUP_free(grp_copy);
293    grp_copy = NULL;
294
295    /* Test d2i_ECPKParameters with explicit params setting the flag */
296    if (!TEST_int_gt(encodedlen = i2d_ECPKParameters(grp, &encodedparams), 0)
297        || !TEST_ptr(encp = encodedparams)
298        || !TEST_ptr(grp_copy = d2i_ECPKParameters(NULL, &encp, encodedlen))
299        || !TEST_int_eq(EC_GROUP_get_asn1_flag(grp_copy), OPENSSL_EC_EXPLICIT_CURVE)
300        || !TEST_int_eq(grp_copy->decoded_from_explicit_params, 1)
301        || !TEST_int_eq(EC_KEY_set_group(key, grp_copy), 1)
302    /* Test EC_KEY_decoded_from_explicit_params positive case */
303        || !TEST_int_eq(EC_KEY_decoded_from_explicit_params(key), 1))
304        goto err;
305
306    testresult = 1;
307
308 err:
309    EC_KEY_free(key);
310    EC_GROUP_free(grp);
311    EC_GROUP_free(grp_copy);
312    ECPARAMETERS_free(ecparams);
313    ECPKPARAMETERS_free(ecpkparams);
314    OPENSSL_free(encodedparams);
315
316    return testresult;
317}
318
319static
320int ecpkparams_i2d2i_test(int n)
321{
322    EC_GROUP *g1 = NULL, *g2 = NULL;
323    FILE *fp = NULL;
324    int nid = curves[n].nid;
325    int testresult = 0;
326
327    /* create group */
328    if (!TEST_ptr(g1 = EC_GROUP_new_by_curve_name(nid)))
329        goto end;
330
331    /* encode params to file */
332    if (!TEST_ptr(fp = fopen("params.der", "wb"))
333            || !TEST_true(i2d_ECPKParameters_fp(fp, g1)))
334        goto end;
335
336    /* flush and close file */
337    if (!TEST_int_eq(fclose(fp), 0)) {
338        fp = NULL;
339        goto end;
340    }
341    fp = NULL;
342
343    /* decode params from file */
344    if (!TEST_ptr(fp = fopen("params.der", "rb"))
345            || !TEST_ptr(g2 = d2i_ECPKParameters_fp(fp, NULL)))
346        goto end;
347
348    testresult = 1; /* PASS */
349
350end:
351    if (fp != NULL)
352        fclose(fp);
353
354    EC_GROUP_free(g1);
355    EC_GROUP_free(g2);
356
357    return testresult;
358}
359
360int setup_tests(void)
361{
362    crv_len = EC_get_builtin_curves(NULL, 0);
363    if (!TEST_ptr(curves = OPENSSL_malloc(sizeof(*curves) * crv_len))
364        || !TEST_true(EC_get_builtin_curves(curves, crv_len)))
365        return 0;
366
367    ADD_TEST(field_tests_ecp_simple);
368    ADD_TEST(field_tests_ecp_mont);
369#ifndef OPENSSL_NO_EC2M
370    ADD_TEST(field_tests_ec2_simple);
371#endif
372    ADD_ALL_TESTS(field_tests_default, crv_len);
373    ADD_TEST(set_private_key);
374    ADD_TEST(decoded_flag_test);
375    ADD_ALL_TESTS(ecpkparams_i2d2i_test, crv_len);
376
377    return 1;
378}
379
380void cleanup_tests(void)
381{
382    OPENSSL_free(curves);
383}
384