1*4724848cSchristos /*
2*4724848cSchristos * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
3*4724848cSchristos *
4*4724848cSchristos * Licensed under the OpenSSL licenses, (the "License");
5*4724848cSchristos * you may not use this file except in compliance with the License.
6*4724848cSchristos * You may obtain a copy of the License at
7*4724848cSchristos * https://www.openssl.org/source/license.html
8*4724848cSchristos * or in the file LICENSE in the source distribution.
9*4724848cSchristos */
10*4724848cSchristos
11*4724848cSchristos #include "internal/nelem.h"
12*4724848cSchristos #include "testutil.h"
13*4724848cSchristos
14*4724848cSchristos #include <stdio.h>
15*4724848cSchristos #include <stdlib.h>
16*4724848cSchristos #include <string.h>
17*4724848cSchristos #include <ctype.h>
18*4724848cSchristos
19*4724848cSchristos #define NUM_REPEATS "1000000"
20*4724848cSchristos
21*4724848cSchristos static int64_t num_repeats;
22*4724848cSchristos static int print_mode = 0;
23*4724848cSchristos
24*4724848cSchristos #ifndef OPENSSL_NO_EC
25*4724848cSchristos # include <openssl/ec.h>
26*4724848cSchristos # include <openssl/err.h>
27*4724848cSchristos # include <openssl/obj_mac.h>
28*4724848cSchristos # include <openssl/objects.h>
29*4724848cSchristos # include <openssl/rand.h>
30*4724848cSchristos # include <openssl/bn.h>
31*4724848cSchristos # include <openssl/opensslconf.h>
32*4724848cSchristos
33*4724848cSchristos static const char *kP256DefaultResult =
34*4724848cSchristos "A1E24B223B8E81BC1FFF99BAFB909EDB895FACDE7D6DA5EF5E7B3255FB378E0F";
35*4724848cSchristos
36*4724848cSchristos /*
37*4724848cSchristos * Perform a deterministic walk on the curve, by starting from |point| and
38*4724848cSchristos * using the X-coordinate of the previous point as the next scalar for
39*4724848cSchristos * point multiplication.
40*4724848cSchristos * Returns the X-coordinate of the end result or NULL on error.
41*4724848cSchristos */
walk_curve(const EC_GROUP * group,EC_POINT * point,int64_t num)42*4724848cSchristos static BIGNUM *walk_curve(const EC_GROUP *group, EC_POINT *point, int64_t num)
43*4724848cSchristos {
44*4724848cSchristos BIGNUM *scalar = NULL;
45*4724848cSchristos int64_t i;
46*4724848cSchristos
47*4724848cSchristos if (!TEST_ptr(scalar = BN_new())
48*4724848cSchristos || !TEST_true(EC_POINT_get_affine_coordinates(group, point, scalar,
49*4724848cSchristos NULL, NULL)))
50*4724848cSchristos goto err;
51*4724848cSchristos
52*4724848cSchristos for (i = 0; i < num; i++) {
53*4724848cSchristos if (!TEST_true(EC_POINT_mul(group, point, NULL, point, scalar, NULL))
54*4724848cSchristos || !TEST_true(EC_POINT_get_affine_coordinates(group, point,
55*4724848cSchristos scalar,
56*4724848cSchristos NULL, NULL)))
57*4724848cSchristos goto err;
58*4724848cSchristos }
59*4724848cSchristos return scalar;
60*4724848cSchristos
61*4724848cSchristos err:
62*4724848cSchristos BN_free(scalar);
63*4724848cSchristos return NULL;
64*4724848cSchristos }
65*4724848cSchristos
test_curve(void)66*4724848cSchristos static int test_curve(void)
67*4724848cSchristos {
68*4724848cSchristos EC_GROUP *group = NULL;
69*4724848cSchristos EC_POINT *point = NULL;
70*4724848cSchristos BIGNUM *result = NULL, *expected_result = NULL;
71*4724848cSchristos int ret = 0;
72*4724848cSchristos
73*4724848cSchristos /*
74*4724848cSchristos * We currently hard-code P-256, though adaptation to other curves.
75*4724848cSchristos * would be straightforward.
76*4724848cSchristos */
77*4724848cSchristos if (!TEST_ptr(group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1))
78*4724848cSchristos || !TEST_ptr(point = EC_POINT_dup(EC_GROUP_get0_generator(group),
79*4724848cSchristos group))
80*4724848cSchristos || !TEST_ptr(result = walk_curve(group, point, num_repeats)))
81*4724848cSchristos return 0;
82*4724848cSchristos
83*4724848cSchristos if (print_mode) {
84*4724848cSchristos BN_print(bio_out, result);
85*4724848cSchristos BIO_printf(bio_out, "\n");
86*4724848cSchristos ret = 1;
87*4724848cSchristos } else {
88*4724848cSchristos if (!TEST_true(BN_hex2bn(&expected_result, kP256DefaultResult))
89*4724848cSchristos || !TEST_ptr(expected_result)
90*4724848cSchristos || !TEST_BN_eq(result, expected_result))
91*4724848cSchristos goto err;
92*4724848cSchristos ret = 1;
93*4724848cSchristos }
94*4724848cSchristos
95*4724848cSchristos err:
96*4724848cSchristos EC_GROUP_free(group);
97*4724848cSchristos EC_POINT_free(point);
98*4724848cSchristos BN_free(result);
99*4724848cSchristos BN_free(expected_result);
100*4724848cSchristos return ret;
101*4724848cSchristos }
102*4724848cSchristos #endif
103*4724848cSchristos
atoi64(const char * in,int64_t * result)104*4724848cSchristos static int atoi64(const char *in, int64_t *result)
105*4724848cSchristos {
106*4724848cSchristos int64_t ret = 0;
107*4724848cSchristos
108*4724848cSchristos for ( ; *in != '\0'; in++) {
109*4724848cSchristos char c = *in;
110*4724848cSchristos
111*4724848cSchristos if (!isdigit((unsigned char)c))
112*4724848cSchristos return 0;
113*4724848cSchristos ret *= 10;
114*4724848cSchristos ret += (c - '0');
115*4724848cSchristos }
116*4724848cSchristos *result = ret;
117*4724848cSchristos return 1;
118*4724848cSchristos }
119*4724848cSchristos
120*4724848cSchristos /*
121*4724848cSchristos * Stress test the curve. If the '-num' argument is given, runs the loop
122*4724848cSchristos * |num| times and prints the resulting X-coordinate. Otherwise runs the test
123*4724848cSchristos * the default number of times and compares against the expected result.
124*4724848cSchristos */
setup_tests(void)125*4724848cSchristos int setup_tests(void)
126*4724848cSchristos {
127*4724848cSchristos const char *p;
128*4724848cSchristos
129*4724848cSchristos if (!atoi64(NUM_REPEATS, &num_repeats)) {
130*4724848cSchristos TEST_error("Cannot parse " NUM_REPEATS);
131*4724848cSchristos return 0;
132*4724848cSchristos }
133*4724848cSchristos /*
134*4724848cSchristos * TODO(openssl-team): code under test/ should be able to reuse the option
135*4724848cSchristos * parsing framework currently in apps/.
136*4724848cSchristos */
137*4724848cSchristos p = test_get_option_argument("-num");
138*4724848cSchristos if (p != NULL) {
139*4724848cSchristos if (!atoi64(p, &num_repeats)
140*4724848cSchristos || num_repeats < 0)
141*4724848cSchristos return 0;
142*4724848cSchristos print_mode = 1;
143*4724848cSchristos }
144*4724848cSchristos
145*4724848cSchristos #ifndef OPENSSL_NO_EC
146*4724848cSchristos ADD_TEST(test_curve);
147*4724848cSchristos #endif
148*4724848cSchristos return 1;
149*4724848cSchristos }
150