1 /* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18
19 #include <vector>
20
21 #include <gtest/gtest.h>
22
23 #include <openssl/bn.h>
24 #include <openssl/bytestring.h>
25 #include <openssl/crypto.h>
26 #include <openssl/ec_key.h>
27 #include <openssl/err.h>
28 #include <openssl/mem.h>
29 #include <openssl/nid.h>
30 #include <openssl/obj.h>
31
32 #include "../../test/file_test.h"
33 #include "../../test/test_util.h"
34 #include "../bn/internal.h"
35 #include "internal.h"
36
37
38 // kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
39 // omitted.
40 static const uint8_t kECKeyWithoutPublic[] = {
41 0x30, 0x31, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc6, 0xc1, 0xaa, 0xda, 0x15, 0xb0,
42 0x76, 0x61, 0xf8, 0x14, 0x2c, 0x6c, 0xaf, 0x0f, 0xdb, 0x24, 0x1a, 0xff, 0x2e,
43 0xfe, 0x46, 0xc0, 0x93, 0x8b, 0x74, 0xf2, 0xbc, 0xc5, 0x30, 0x52, 0xb0, 0x77,
44 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
45 };
46
47 // kECKeySpecifiedCurve is the above key with P-256's parameters explicitly
48 // spelled out rather than using a named curve.
49 static const uint8_t kECKeySpecifiedCurve[] = {
50 0x30, 0x82, 0x01, 0x22, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc6, 0xc1, 0xaa,
51 0xda, 0x15, 0xb0, 0x76, 0x61, 0xf8, 0x14, 0x2c, 0x6c, 0xaf, 0x0f, 0xdb,
52 0x24, 0x1a, 0xff, 0x2e, 0xfe, 0x46, 0xc0, 0x93, 0x8b, 0x74, 0xf2, 0xbc,
53 0xc5, 0x30, 0x52, 0xb0, 0x77, 0xa0, 0x81, 0xfa, 0x30, 0x81, 0xf7, 0x02,
54 0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01,
55 0x01, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
56 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
58 0x30, 0x5b, 0x04, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
59 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
60 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
61 0x04, 0x20, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb,
62 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
63 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, 0x03, 0x15,
64 0x00, 0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66, 0x78,
65 0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f, 0x7e, 0x90, 0x04, 0x41, 0x04,
66 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5,
67 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
68 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2,
69 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
70 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
71 0x37, 0xbf, 0x51, 0xf5, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
72 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc,
73 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc,
74 0x63, 0x25, 0x51, 0x02, 0x01, 0x01,
75 };
76
77 // kECKeyMissingZeros is an ECPrivateKey containing a degenerate P-256 key where
78 // the private key is one. The private key is incorrectly encoded without zero
79 // padding.
80 static const uint8_t kECKeyMissingZeros[] = {
81 0x30, 0x58, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0xa0, 0x0a, 0x06, 0x08, 0x2a,
82 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04,
83 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63,
84 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1,
85 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f,
86 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57,
87 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
88 };
89
90 // kECKeyMissingZeros is an ECPrivateKey containing a degenerate P-256 key where
91 // the private key is one. The private key is encoded with the required zero
92 // padding.
93 static const uint8_t kECKeyWithZeros[] = {
94 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
97 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1,
98 0x44, 0x03, 0x42, 0x00, 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47,
99 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d,
100 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3,
101 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e,
102 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
103 0x37, 0xbf, 0x51, 0xf5,
104 };
105
106 // DecodeECPrivateKey decodes |in| as an ECPrivateKey structure and returns the
107 // result or nullptr on error.
DecodeECPrivateKey(const uint8_t * in,size_t in_len)108 static bssl::UniquePtr<EC_KEY> DecodeECPrivateKey(const uint8_t *in,
109 size_t in_len) {
110 CBS cbs;
111 CBS_init(&cbs, in, in_len);
112 bssl::UniquePtr<EC_KEY> ret(EC_KEY_parse_private_key(&cbs, NULL));
113 if (!ret || CBS_len(&cbs) != 0) {
114 return nullptr;
115 }
116 return ret;
117 }
118
119 // EncodeECPrivateKey encodes |key| as an ECPrivateKey structure into |*out|. It
120 // returns true on success or false on error.
EncodeECPrivateKey(std::vector<uint8_t> * out,const EC_KEY * key)121 static bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
122 bssl::ScopedCBB cbb;
123 uint8_t *der;
124 size_t der_len;
125 if (!CBB_init(cbb.get(), 0) ||
126 !EC_KEY_marshal_private_key(cbb.get(), key, EC_KEY_get_enc_flags(key)) ||
127 !CBB_finish(cbb.get(), &der, &der_len)) {
128 return false;
129 }
130 out->assign(der, der + der_len);
131 OPENSSL_free(der);
132 return true;
133 }
134
TEST(ECTest,Encoding)135 TEST(ECTest, Encoding) {
136 bssl::UniquePtr<EC_KEY> key =
137 DecodeECPrivateKey(kECKeyWithoutPublic, sizeof(kECKeyWithoutPublic));
138 ASSERT_TRUE(key);
139
140 // Test that the encoding round-trips.
141 std::vector<uint8_t> out;
142 ASSERT_TRUE(EncodeECPrivateKey(&out, key.get()));
143 EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
144
145 const EC_POINT *pub_key = EC_KEY_get0_public_key(key.get());
146 ASSERT_TRUE(pub_key) << "Public key missing";
147
148 bssl::UniquePtr<BIGNUM> x(BN_new());
149 bssl::UniquePtr<BIGNUM> y(BN_new());
150 ASSERT_TRUE(x);
151 ASSERT_TRUE(y);
152 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
153 EC_KEY_get0_group(key.get()), pub_key, x.get(), y.get(), NULL));
154 bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get()));
155 bssl::UniquePtr<char> y_hex(BN_bn2hex(y.get()));
156 ASSERT_TRUE(x_hex);
157 ASSERT_TRUE(y_hex);
158
159 EXPECT_STREQ(
160 "c81561ecf2e54edefe6617db1c7a34a70744ddb261f269b83dacfcd2ade5a681",
161 x_hex.get());
162 EXPECT_STREQ(
163 "e0e2afa3f9b6abe4c698ef6495f1be49a3196c5056acb3763fe4507eec596e88",
164 y_hex.get());
165 }
166
TEST(ECTest,ZeroPadding)167 TEST(ECTest, ZeroPadding) {
168 // Check that the correct encoding round-trips.
169 bssl::UniquePtr<EC_KEY> key =
170 DecodeECPrivateKey(kECKeyWithZeros, sizeof(kECKeyWithZeros));
171 ASSERT_TRUE(key);
172 std::vector<uint8_t> out;
173 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
174 EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
175
176 // Keys without leading zeros also parse, but they encode correctly.
177 key = DecodeECPrivateKey(kECKeyMissingZeros, sizeof(kECKeyMissingZeros));
178 ASSERT_TRUE(key);
179 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
180 EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
181 }
182
TEST(ECTest,SpecifiedCurve)183 TEST(ECTest, SpecifiedCurve) {
184 // Test keys with specified curves may be decoded.
185 bssl::UniquePtr<EC_KEY> key =
186 DecodeECPrivateKey(kECKeySpecifiedCurve, sizeof(kECKeySpecifiedCurve));
187 ASSERT_TRUE(key);
188
189 // The group should have been interpreted as P-256.
190 EXPECT_EQ(NID_X9_62_prime256v1,
191 EC_GROUP_get_curve_name(EC_KEY_get0_group(key.get())));
192
193 // Encoding the key should still use named form.
194 std::vector<uint8_t> out;
195 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
196 EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
197 }
198
TEST(ECTest,ArbitraryCurve)199 TEST(ECTest, ArbitraryCurve) {
200 // Make a P-256 key and extract the affine coordinates.
201 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
202 ASSERT_TRUE(key);
203 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
204
205 // Make an arbitrary curve which is identical to P-256.
206 static const uint8_t kP[] = {
207 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
208 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
209 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
210 };
211 static const uint8_t kA[] = {
212 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
214 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
215 };
216 static const uint8_t kB[] = {
217 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
218 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
219 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
220 };
221 static const uint8_t kX[] = {
222 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6,
223 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
224 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96,
225 };
226 static const uint8_t kY[] = {
227 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb,
228 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
229 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
230 };
231 static const uint8_t kOrder[] = {
232 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
233 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
234 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
235 };
236 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
237 ASSERT_TRUE(ctx);
238 bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
239 ASSERT_TRUE(p);
240 bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
241 ASSERT_TRUE(a);
242 bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
243 ASSERT_TRUE(b);
244 bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kX, sizeof(kX), nullptr));
245 ASSERT_TRUE(gx);
246 bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kY, sizeof(kY), nullptr));
247 ASSERT_TRUE(gy);
248 bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
249 ASSERT_TRUE(order);
250
251 bssl::UniquePtr<EC_GROUP> group(
252 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
253 ASSERT_TRUE(group);
254 bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
255 ASSERT_TRUE(generator);
256 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
257 group.get(), generator.get(), gx.get(), gy.get(), ctx.get()));
258 ASSERT_TRUE(EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
259 BN_value_one()));
260
261 // |group| should not have a curve name.
262 EXPECT_EQ(NID_undef, EC_GROUP_get_curve_name(group.get()));
263
264 // Copy |key| to |key2| using |group|.
265 bssl::UniquePtr<EC_KEY> key2(EC_KEY_new());
266 ASSERT_TRUE(key2);
267 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
268 ASSERT_TRUE(point);
269 bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new());
270 ASSERT_TRUE(x);
271 ASSERT_TRUE(EC_KEY_set_group(key2.get(), group.get()));
272 ASSERT_TRUE(
273 EC_KEY_set_private_key(key2.get(), EC_KEY_get0_private_key(key.get())));
274 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
275 EC_KEY_get0_group(key.get()), EC_KEY_get0_public_key(key.get()), x.get(),
276 y.get(), nullptr));
277 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(),
278 x.get(), y.get(), nullptr));
279 ASSERT_TRUE(EC_KEY_set_public_key(key2.get(), point.get()));
280
281 // The key must be valid according to the new group too.
282 EXPECT_TRUE(EC_KEY_check_key(key2.get()));
283
284 // Make a second instance of |group|.
285 bssl::UniquePtr<EC_GROUP> group2(
286 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
287 ASSERT_TRUE(group2);
288 bssl::UniquePtr<EC_POINT> generator2(EC_POINT_new(group2.get()));
289 ASSERT_TRUE(generator2);
290 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
291 group2.get(), generator2.get(), gx.get(), gy.get(), ctx.get()));
292 ASSERT_TRUE(EC_GROUP_set_generator(group2.get(), generator2.get(),
293 order.get(), BN_value_one()));
294
295 EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group.get(), NULL));
296 EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), NULL));
297
298 // group3 uses the wrong generator.
299 bssl::UniquePtr<EC_GROUP> group3(
300 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
301 ASSERT_TRUE(group3);
302 bssl::UniquePtr<EC_POINT> generator3(EC_POINT_new(group3.get()));
303 ASSERT_TRUE(generator3);
304 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
305 group3.get(), generator3.get(), x.get(), y.get(), ctx.get()));
306 ASSERT_TRUE(EC_GROUP_set_generator(group3.get(), generator3.get(),
307 order.get(), BN_value_one()));
308
309 EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
310
311 #if !defined(BORINGSSL_SHARED_LIBRARY)
312 // group4 has non-minimal components that do not fit in |EC_SCALAR| and the
313 // future |EC_FELEM|.
314 ASSERT_TRUE(bn_resize_words(p.get(), 32));
315 ASSERT_TRUE(bn_resize_words(a.get(), 32));
316 ASSERT_TRUE(bn_resize_words(b.get(), 32));
317 ASSERT_TRUE(bn_resize_words(gx.get(), 32));
318 ASSERT_TRUE(bn_resize_words(gy.get(), 32));
319 ASSERT_TRUE(bn_resize_words(order.get(), 32));
320
321 bssl::UniquePtr<EC_GROUP> group4(
322 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
323 ASSERT_TRUE(group4);
324 bssl::UniquePtr<EC_POINT> generator4(EC_POINT_new(group4.get()));
325 ASSERT_TRUE(generator4);
326 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
327 group4.get(), generator4.get(), gx.get(), gy.get(), ctx.get()));
328 ASSERT_TRUE(EC_GROUP_set_generator(group4.get(), generator4.get(),
329 order.get(), BN_value_one()));
330
331 EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group4.get(), NULL));
332 #endif
333 }
334
TEST(ECTest,SetKeyWithoutGroup)335 TEST(ECTest, SetKeyWithoutGroup) {
336 bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
337 ASSERT_TRUE(key);
338
339 // Private keys may not be configured without a group.
340 EXPECT_FALSE(EC_KEY_set_private_key(key.get(), BN_value_one()));
341
342 // Public keys may not be configured without a group.
343 bssl::UniquePtr<EC_GROUP> group(
344 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
345 ASSERT_TRUE(group);
346 EXPECT_FALSE(
347 EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(group.get())));
348 }
349
TEST(ECTest,SetNULLKey)350 TEST(ECTest, SetNULLKey) {
351 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
352 ASSERT_TRUE(key);
353
354 EXPECT_TRUE(EC_KEY_set_public_key(
355 key.get(), EC_GROUP_get0_generator(EC_KEY_get0_group(key.get()))));
356 EXPECT_TRUE(EC_KEY_get0_public_key(key.get()));
357
358 // Setting a NULL public-key should clear the public-key and return zero, in
359 // order to match OpenSSL behaviour exactly.
360 EXPECT_FALSE(EC_KEY_set_public_key(key.get(), nullptr));
361 EXPECT_FALSE(EC_KEY_get0_public_key(key.get()));
362 }
363
TEST(ECTest,GroupMismatch)364 TEST(ECTest, GroupMismatch) {
365 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_secp384r1));
366 ASSERT_TRUE(key);
367 bssl::UniquePtr<EC_GROUP> p256(
368 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
369 ASSERT_TRUE(p256);
370
371 // Changing a key's group is invalid.
372 EXPECT_FALSE(EC_KEY_set_group(key.get(), p256.get()));
373
374 // Configuring a public key with the wrong group is invalid.
375 EXPECT_FALSE(
376 EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
377 }
378
TEST(ECTest,EmptyKey)379 TEST(ECTest, EmptyKey) {
380 bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
381 ASSERT_TRUE(key);
382 EXPECT_FALSE(EC_KEY_get0_group(key.get()));
383 EXPECT_FALSE(EC_KEY_get0_public_key(key.get()));
384 EXPECT_FALSE(EC_KEY_get0_private_key(key.get()));
385 }
386
HexToBIGNUM(const char * hex)387 static bssl::UniquePtr<BIGNUM> HexToBIGNUM(const char *hex) {
388 BIGNUM *bn = nullptr;
389 BN_hex2bn(&bn, hex);
390 return bssl::UniquePtr<BIGNUM>(bn);
391 }
392
393 // Test that point arithmetic works with custom curves using an arbitrary |a|,
394 // rather than -3, as is common (and more efficient).
TEST(ECTest,BrainpoolP256r1)395 TEST(ECTest, BrainpoolP256r1) {
396 static const char kP[] =
397 "a9fb57dba1eea9bc3e660a909d838d726e3bf623d52620282013481d1f6e5377";
398 static const char kA[] =
399 "7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9";
400 static const char kB[] =
401 "26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6";
402 static const char kX[] =
403 "8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262";
404 static const char kY[] =
405 "547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997";
406 static const char kN[] =
407 "a9fb57dba1eea9bc3e660a909d838d718c397aa3b561a6f7901e0e82974856a7";
408 static const char kD[] =
409 "0da21d76fed40dd82ac3314cce91abb585b5c4246e902b238a839609ea1e7ce1";
410 static const char kQX[] =
411 "3a55e0341cab50452fe27b8a87e4775dec7a9daca94b0d84ad1e9f85b53ea513";
412 static const char kQY[] =
413 "40088146b33bbbe81b092b41146774b35dd478cf056437cfb35ef0df2d269339";
414
415 bssl::UniquePtr<BIGNUM> p = HexToBIGNUM(kP), a = HexToBIGNUM(kA),
416 b = HexToBIGNUM(kB), x = HexToBIGNUM(kX),
417 y = HexToBIGNUM(kY), n = HexToBIGNUM(kN),
418 d = HexToBIGNUM(kD), qx = HexToBIGNUM(kQX),
419 qy = HexToBIGNUM(kQY);
420 ASSERT_TRUE(p && a && b && x && y && n && d && qx && qy);
421
422 bssl::UniquePtr<EC_GROUP> group(
423 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), nullptr));
424 ASSERT_TRUE(group);
425 bssl::UniquePtr<EC_POINT> g(EC_POINT_new(group.get()));
426 ASSERT_TRUE(g);
427 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), g.get(), x.get(),
428 y.get(), nullptr));
429 ASSERT_TRUE(
430 EC_GROUP_set_generator(group.get(), g.get(), n.get(), BN_value_one()));
431
432 bssl::UniquePtr<EC_POINT> q(EC_POINT_new(group.get()));
433 ASSERT_TRUE(q);
434 ASSERT_TRUE(
435 EC_POINT_mul(group.get(), q.get(), d.get(), nullptr, nullptr, nullptr));
436 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(group.get(), q.get(), x.get(),
437 y.get(), nullptr));
438 EXPECT_EQ(0, BN_cmp(x.get(), qx.get()));
439 EXPECT_EQ(0, BN_cmp(y.get(), qy.get()));
440 }
441
442 class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {
443 public:
group() const444 const EC_GROUP *group() const { return group_.get(); }
445
SetUp()446 void SetUp() override {
447 group_.reset(EC_GROUP_new_by_curve_name(GetParam().nid));
448 ASSERT_TRUE(group_);
449 }
450
451 private:
452 bssl::UniquePtr<EC_GROUP> group_;
453 };
454
TEST_P(ECCurveTest,SetAffine)455 TEST_P(ECCurveTest, SetAffine) {
456 // Generate an EC_KEY.
457 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
458 ASSERT_TRUE(key);
459 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
460
461 EXPECT_TRUE(EC_POINT_is_on_curve(group(), EC_KEY_get0_public_key(key.get()),
462 nullptr));
463
464 // Get the public key's coordinates.
465 bssl::UniquePtr<BIGNUM> x(BN_new());
466 ASSERT_TRUE(x);
467 bssl::UniquePtr<BIGNUM> y(BN_new());
468 ASSERT_TRUE(y);
469 bssl::UniquePtr<BIGNUM> p(BN_new());
470 ASSERT_TRUE(p);
471 EXPECT_TRUE(EC_POINT_get_affine_coordinates_GFp(
472 group(), EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr));
473 EXPECT_TRUE(
474 EC_GROUP_get_curve_GFp(group(), p.get(), nullptr, nullptr, nullptr));
475
476 // Points on the curve should be accepted.
477 auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group()));
478 ASSERT_TRUE(point);
479 EXPECT_TRUE(EC_POINT_set_affine_coordinates_GFp(group(), point.get(), x.get(),
480 y.get(), nullptr));
481
482 // Subtract one from |y| to make the point no longer on the curve.
483 EXPECT_TRUE(BN_sub(y.get(), y.get(), BN_value_one()));
484
485 // Points not on the curve should be rejected.
486 bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group()));
487 ASSERT_TRUE(invalid_point);
488 EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group(), invalid_point.get(),
489 x.get(), y.get(), nullptr));
490
491 // Coordinates out of range should be rejected.
492 EXPECT_TRUE(BN_add(y.get(), y.get(), BN_value_one()));
493 EXPECT_TRUE(BN_add(y.get(), y.get(), p.get()));
494
495 EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group(), invalid_point.get(),
496 x.get(), y.get(), nullptr));
497 EXPECT_FALSE(
498 EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()));
499 }
500
TEST_P(ECCurveTest,GenerateFIPS)501 TEST_P(ECCurveTest, GenerateFIPS) {
502 // Generate an EC_KEY.
503 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
504 ASSERT_TRUE(key);
505 ASSERT_TRUE(EC_KEY_generate_key_fips(key.get()));
506 }
507
TEST_P(ECCurveTest,AddingEqualPoints)508 TEST_P(ECCurveTest, AddingEqualPoints) {
509 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
510 ASSERT_TRUE(key);
511 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
512
513 bssl::UniquePtr<EC_POINT> p1(EC_POINT_new(group()));
514 ASSERT_TRUE(p1);
515 ASSERT_TRUE(EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())));
516
517 bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group()));
518 ASSERT_TRUE(p2);
519 ASSERT_TRUE(EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get())));
520
521 bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group()));
522 ASSERT_TRUE(double_p1);
523 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
524 ASSERT_TRUE(ctx);
525 ASSERT_TRUE(EC_POINT_dbl(group(), double_p1.get(), p1.get(), ctx.get()));
526
527 bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group()));
528 ASSERT_TRUE(p1_plus_p2);
529 ASSERT_TRUE(
530 EC_POINT_add(group(), p1_plus_p2.get(), p1.get(), p2.get(), ctx.get()));
531
532 EXPECT_EQ(0,
533 EC_POINT_cmp(group(), double_p1.get(), p1_plus_p2.get(), ctx.get()))
534 << "A+A != 2A";
535 }
536
TEST_P(ECCurveTest,MulZero)537 TEST_P(ECCurveTest, MulZero) {
538 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
539 ASSERT_TRUE(point);
540 bssl::UniquePtr<BIGNUM> zero(BN_new());
541 ASSERT_TRUE(zero);
542 BN_zero(zero.get());
543 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), zero.get(), nullptr, nullptr,
544 nullptr));
545
546 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
547 << "g * 0 did not return point at infinity.";
548
549 // Test that zero times an arbitrary point is also infinity. The generator is
550 // used as the arbitrary point.
551 bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group()));
552 ASSERT_TRUE(generator);
553 ASSERT_TRUE(EC_POINT_mul(group(), generator.get(), BN_value_one(), nullptr,
554 nullptr, nullptr));
555 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), nullptr, generator.get(),
556 zero.get(), nullptr));
557
558 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
559 << "p * 0 did not return point at infinity.";
560 }
561
562 // Test that multiplying by the order produces ∞ and, moreover, that callers may
563 // do so. |EC_POINT_mul| is almost exclusively used with reduced scalars, with
564 // this exception. This comes from consumers following NIST SP 800-56A section
565 // 5.6.2.3.2. (Though all our curves have cofactor one, so this check isn't
566 // useful.)
TEST_P(ECCurveTest,MulOrder)567 TEST_P(ECCurveTest, MulOrder) {
568 // Test that g × order = ∞.
569 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
570 ASSERT_TRUE(point);
571 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), EC_GROUP_get0_order(group()),
572 nullptr, nullptr, nullptr));
573
574 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
575 << "g * order did not return point at infinity.";
576
577 // Test that p × order = ∞, for some arbitrary p.
578 bssl::UniquePtr<BIGNUM> forty_two(BN_new());
579 ASSERT_TRUE(forty_two);
580 ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
581 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
582 nullptr, nullptr));
583 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), nullptr, point.get(),
584 EC_GROUP_get0_order(group()), nullptr));
585
586 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
587 << "p * order did not return point at infinity.";
588 }
589
590 // Test that |EC_POINT_mul| works with out-of-range scalars. The operation will
591 // not be constant-time, but we'll compute the right answer.
TEST_P(ECCurveTest,MulOutOfRange)592 TEST_P(ECCurveTest, MulOutOfRange) {
593 bssl::UniquePtr<BIGNUM> n_minus_one(BN_dup(EC_GROUP_get0_order(group())));
594 ASSERT_TRUE(n_minus_one);
595 ASSERT_TRUE(BN_sub_word(n_minus_one.get(), 1));
596
597 bssl::UniquePtr<BIGNUM> minus_one(BN_new());
598 ASSERT_TRUE(minus_one);
599 ASSERT_TRUE(BN_one(minus_one.get()));
600 BN_set_negative(minus_one.get(), 1);
601
602 bssl::UniquePtr<BIGNUM> seven(BN_new());
603 ASSERT_TRUE(seven);
604 ASSERT_TRUE(BN_set_word(seven.get(), 7));
605
606 bssl::UniquePtr<BIGNUM> ten_n_plus_seven(
607 BN_dup(EC_GROUP_get0_order(group())));
608 ASSERT_TRUE(ten_n_plus_seven);
609 ASSERT_TRUE(BN_mul_word(ten_n_plus_seven.get(), 10));
610 ASSERT_TRUE(BN_add_word(ten_n_plus_seven.get(), 7));
611
612 bssl::UniquePtr<EC_POINT> point1(EC_POINT_new(group())),
613 point2(EC_POINT_new(group()));
614 ASSERT_TRUE(point1);
615 ASSERT_TRUE(point2);
616
617 ASSERT_TRUE(EC_POINT_mul(group(), point1.get(), n_minus_one.get(), nullptr,
618 nullptr, nullptr));
619 ASSERT_TRUE(EC_POINT_mul(group(), point2.get(), minus_one.get(), nullptr,
620 nullptr, nullptr));
621 EXPECT_EQ(0, EC_POINT_cmp(group(), point1.get(), point2.get(), nullptr))
622 << "-1 * G and (n-1) * G did not give the same result";
623
624 ASSERT_TRUE(EC_POINT_mul(group(), point1.get(), seven.get(), nullptr, nullptr,
625 nullptr));
626 ASSERT_TRUE(EC_POINT_mul(group(), point2.get(), ten_n_plus_seven.get(),
627 nullptr, nullptr, nullptr));
628 EXPECT_EQ(0, EC_POINT_cmp(group(), point1.get(), point2.get(), nullptr))
629 << "7 * G and (10n + 7) * G did not give the same result";
630 }
631
632 // Test that 10×∞ + G = G.
TEST_P(ECCurveTest,Mul)633 TEST_P(ECCurveTest, Mul) {
634 bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group()));
635 ASSERT_TRUE(p);
636 bssl::UniquePtr<EC_POINT> result(EC_POINT_new(group()));
637 ASSERT_TRUE(result);
638 bssl::UniquePtr<BIGNUM> n(BN_new());
639 ASSERT_TRUE(n);
640 ASSERT_TRUE(EC_POINT_set_to_infinity(group(), p.get()));
641 ASSERT_TRUE(BN_set_word(n.get(), 10));
642
643 // First check that 10×∞ = ∞.
644 ASSERT_TRUE(
645 EC_POINT_mul(group(), result.get(), nullptr, p.get(), n.get(), nullptr));
646 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), result.get()));
647
648 // Now check that 10×∞ + G = G.
649 const EC_POINT *generator = EC_GROUP_get0_generator(group());
650 ASSERT_TRUE(EC_POINT_mul(group(), result.get(), BN_value_one(), p.get(),
651 n.get(), nullptr));
652 EXPECT_EQ(0, EC_POINT_cmp(group(), result.get(), generator, nullptr));
653 }
654
TEST_P(ECCurveTest,MulNonMinimal)655 TEST_P(ECCurveTest, MulNonMinimal) {
656 bssl::UniquePtr<BIGNUM> forty_two(BN_new());
657 ASSERT_TRUE(forty_two);
658 ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
659
660 // Compute g × 42.
661 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
662 ASSERT_TRUE(point);
663 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
664 nullptr, nullptr));
665
666 // Compute it again with a non-minimal 42, much larger than the scalar.
667 ASSERT_TRUE(bn_resize_words(forty_two.get(), 64));
668
669 bssl::UniquePtr<EC_POINT> point2(EC_POINT_new(group()));
670 ASSERT_TRUE(point2);
671 ASSERT_TRUE(EC_POINT_mul(group(), point2.get(), forty_two.get(), nullptr,
672 nullptr, nullptr));
673 EXPECT_EQ(0, EC_POINT_cmp(group(), point.get(), point2.get(), nullptr));
674 }
675
676 // Test that EC_KEY_set_private_key rejects invalid values.
TEST_P(ECCurveTest,SetInvalidPrivateKey)677 TEST_P(ECCurveTest, SetInvalidPrivateKey) {
678 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
679 ASSERT_TRUE(key);
680
681 bssl::UniquePtr<BIGNUM> bn(BN_new());
682 ASSERT_TRUE(BN_one(bn.get()));
683 BN_set_negative(bn.get(), 1);
684 EXPECT_FALSE(EC_KEY_set_private_key(key.get(), bn.get()))
685 << "Unexpectedly set a key of -1";
686 ERR_clear_error();
687
688 ASSERT_TRUE(
689 BN_copy(bn.get(), EC_GROUP_get0_order(EC_KEY_get0_group(key.get()))));
690 EXPECT_FALSE(EC_KEY_set_private_key(key.get(), bn.get()))
691 << "Unexpectedly set a key of the group order.";
692 ERR_clear_error();
693 }
694
TEST_P(ECCurveTest,IgnoreOct2PointReturnValue)695 TEST_P(ECCurveTest, IgnoreOct2PointReturnValue) {
696 bssl::UniquePtr<BIGNUM> forty_two(BN_new());
697 ASSERT_TRUE(forty_two);
698 ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
699
700 // Compute g × 42.
701 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
702 ASSERT_TRUE(point);
703 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
704 nullptr, nullptr));
705
706 // Serialize the point.
707 size_t serialized_len = EC_POINT_point2oct(
708 group(), point.get(), POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
709 ASSERT_NE(0u, serialized_len);
710
711 std::vector<uint8_t> serialized(serialized_len);
712 ASSERT_EQ(
713 serialized_len,
714 EC_POINT_point2oct(group(), point.get(), POINT_CONVERSION_UNCOMPRESSED,
715 serialized.data(), serialized_len, nullptr));
716
717 // Create a serialized point that is not on the curve.
718 serialized[serialized_len - 1]++;
719
720 ASSERT_FALSE(EC_POINT_oct2point(group(), point.get(), serialized.data(),
721 serialized.size(), nullptr));
722 // After a failure, |point| should have been set to the generator to defend
723 // against code that doesn't check the return value.
724 ASSERT_EQ(0, EC_POINT_cmp(group(), point.get(),
725 EC_GROUP_get0_generator(group()), nullptr));
726 }
727
TEST_P(ECCurveTest,DoubleSpecialCase)728 TEST_P(ECCurveTest, DoubleSpecialCase) {
729 const EC_POINT *g = EC_GROUP_get0_generator(group());
730
731 bssl::UniquePtr<EC_POINT> two_g(EC_POINT_new(group()));
732 ASSERT_TRUE(two_g);
733 ASSERT_TRUE(EC_POINT_dbl(group(), two_g.get(), g, nullptr));
734
735 bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group()));
736 ASSERT_TRUE(p);
737 ASSERT_TRUE(EC_POINT_mul(group(), p.get(), BN_value_one(), g, BN_value_one(),
738 nullptr));
739 EXPECT_EQ(0, EC_POINT_cmp(group(), p.get(), two_g.get(), nullptr));
740
741 EC_SCALAR one;
742 ASSERT_TRUE(ec_bignum_to_scalar(group(), &one, BN_value_one()));
743 ASSERT_TRUE(
744 ec_point_mul_scalar_public(group(), &p->raw, &one, &g->raw, &one));
745 EXPECT_EQ(0, EC_POINT_cmp(group(), p.get(), two_g.get(), nullptr));
746 }
747
748 // This a regression test for a P-224 bug, but we may as well run it for all
749 // curves.
TEST_P(ECCurveTest,P224Bug)750 TEST_P(ECCurveTest, P224Bug) {
751 // P = -G
752 const EC_POINT *g = EC_GROUP_get0_generator(group());
753 bssl::UniquePtr<EC_POINT> p(EC_POINT_dup(g, group()));
754 ASSERT_TRUE(p);
755 ASSERT_TRUE(EC_POINT_invert(group(), p.get(), nullptr));
756
757 // Compute 31 * P + 32 * G = G
758 bssl::UniquePtr<EC_POINT> ret(EC_POINT_new(group()));
759 ASSERT_TRUE(ret);
760 bssl::UniquePtr<BIGNUM> bn31(BN_new()), bn32(BN_new());
761 ASSERT_TRUE(bn31);
762 ASSERT_TRUE(bn32);
763 ASSERT_TRUE(BN_set_word(bn31.get(), 31));
764 ASSERT_TRUE(BN_set_word(bn32.get(), 32));
765 ASSERT_TRUE(EC_POINT_mul(group(), ret.get(), bn32.get(), p.get(), bn31.get(),
766 nullptr));
767
768 EXPECT_EQ(0, EC_POINT_cmp(group(), ret.get(), g, nullptr));
769 }
770
TEST_P(ECCurveTest,GPlusMinusG)771 TEST_P(ECCurveTest, GPlusMinusG) {
772 const EC_POINT *g = EC_GROUP_get0_generator(group());
773 bssl::UniquePtr<EC_POINT> p(EC_POINT_dup(g, group()));
774 ASSERT_TRUE(p);
775 ASSERT_TRUE(EC_POINT_invert(group(), p.get(), nullptr));
776 bssl::UniquePtr<EC_POINT> sum(EC_POINT_new(group()));
777
778 ASSERT_TRUE(EC_POINT_add(group(), sum.get(), g, p.get(), nullptr));
779 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), sum.get()));
780 }
781
AllCurves()782 static std::vector<EC_builtin_curve> AllCurves() {
783 const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
784 std::vector<EC_builtin_curve> curves(num_curves);
785 EC_get_builtin_curves(curves.data(), num_curves);
786 return curves;
787 }
788
CurveToString(const testing::TestParamInfo<EC_builtin_curve> & params)789 static std::string CurveToString(
790 const testing::TestParamInfo<EC_builtin_curve> ¶ms) {
791 // The comment field contains characters GTest rejects, so use the OBJ name.
792 return OBJ_nid2sn(params.param.nid);
793 }
794
795 INSTANTIATE_TEST_CASE_P(, ECCurveTest, testing::ValuesIn(AllCurves()),
796 CurveToString);
797
GetCurve(FileTest * t,const char * key)798 static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
799 std::string curve_name;
800 if (!t->GetAttribute(&curve_name, key)) {
801 return nullptr;
802 }
803
804 if (curve_name == "P-224") {
805 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1));
806 }
807 if (curve_name == "P-256") {
808 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(
809 NID_X9_62_prime256v1));
810 }
811 if (curve_name == "P-384") {
812 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1));
813 }
814 if (curve_name == "P-521") {
815 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
816 }
817
818 t->PrintLine("Unknown curve '%s'", curve_name.c_str());
819 return nullptr;
820 }
821
GetBIGNUM(FileTest * t,const char * key)822 static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
823 std::vector<uint8_t> bytes;
824 if (!t->GetBytes(&bytes, key)) {
825 return nullptr;
826 }
827
828 return bssl::UniquePtr<BIGNUM>(
829 BN_bin2bn(bytes.data(), bytes.size(), nullptr));
830 }
831
TEST(ECTest,ScalarBaseMultVectors)832 TEST(ECTest, ScalarBaseMultVectors) {
833 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
834 ASSERT_TRUE(ctx);
835
836 FileTestGTest("crypto/fipsmodule/ec/ec_scalar_base_mult_tests.txt",
837 [&](FileTest *t) {
838 bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
839 ASSERT_TRUE(group);
840 bssl::UniquePtr<BIGNUM> n = GetBIGNUM(t, "N");
841 ASSERT_TRUE(n);
842 bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
843 ASSERT_TRUE(x);
844 bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
845 ASSERT_TRUE(y);
846 bool is_infinity = BN_is_zero(x.get()) && BN_is_zero(y.get());
847
848 bssl::UniquePtr<BIGNUM> px(BN_new());
849 ASSERT_TRUE(px);
850 bssl::UniquePtr<BIGNUM> py(BN_new());
851 ASSERT_TRUE(py);
852 auto check_point = [&](const EC_POINT *p) {
853 if (is_infinity) {
854 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), p));
855 } else {
856 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
857 group.get(), p, px.get(), py.get(), ctx.get()));
858 EXPECT_EQ(0, BN_cmp(x.get(), px.get()));
859 EXPECT_EQ(0, BN_cmp(y.get(), py.get()));
860 }
861 };
862
863 const EC_POINT *g = EC_GROUP_get0_generator(group.get());
864 bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
865 ASSERT_TRUE(p);
866 // Test single-point multiplication.
867 ASSERT_TRUE(EC_POINT_mul(group.get(), p.get(), n.get(), nullptr, nullptr,
868 ctx.get()));
869 check_point(p.get());
870
871 ASSERT_TRUE(
872 EC_POINT_mul(group.get(), p.get(), nullptr, g, n.get(), ctx.get()));
873 check_point(p.get());
874
875 // These tests take a very long time, but are worth running when we make
876 // non-trivial changes to the EC code.
877 #if 0
878 // Test two-point multiplication.
879 bssl::UniquePtr<BIGNUM> a(BN_new()), b(BN_new());
880 for (int i = -64; i < 64; i++) {
881 SCOPED_TRACE(i);
882 ASSERT_TRUE(BN_set_word(a.get(), abs(i)));
883 if (i < 0) {
884 ASSERT_TRUE(BN_sub(a.get(), EC_GROUP_get0_order(group.get()), a.get()));
885 }
886
887 ASSERT_TRUE(BN_copy(b.get(), n.get()));
888 ASSERT_TRUE(BN_sub(b.get(), b.get(), a.get()));
889 if (BN_is_negative(b.get())) {
890 ASSERT_TRUE(BN_add(b.get(), b.get(), EC_GROUP_get0_order(group.get())));
891 }
892
893 ASSERT_TRUE(
894 EC_POINT_mul(group.get(), p.get(), a.get(), g, b.get(), ctx.get()));
895 check_point(p.get());
896
897 EC_SCALAR a_scalar, b_scalar;
898 ASSERT_TRUE(ec_bignum_to_scalar(group.get(), &a_scalar, a.get()));
899 ASSERT_TRUE(ec_bignum_to_scalar(group.get(), &b_scalar, b.get()));
900 ASSERT_TRUE(ec_point_mul_scalar_public(group.get(), &p->raw, &a_scalar, &g->raw,
901 &b_scalar));
902 check_point(p.get());
903 }
904 #endif
905 });
906 }
907