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 <string.h>
17
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include <openssl/bn.h>
23 #include <openssl/bytestring.h>
24 #include <openssl/crypto.h>
25 #include <openssl/ec_key.h>
26 #include <openssl/err.h>
27 #include <openssl/mem.h>
28 #include <openssl/nid.h>
29 #include <openssl/obj.h>
30
31 #include "../bn/internal.h"
32 #include "../../test/test_util.h"
33
34
35 // kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
36 // omitted.
37 static const uint8_t kECKeyWithoutPublic[] = {
38 0x30, 0x31, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc6, 0xc1, 0xaa, 0xda, 0x15, 0xb0,
39 0x76, 0x61, 0xf8, 0x14, 0x2c, 0x6c, 0xaf, 0x0f, 0xdb, 0x24, 0x1a, 0xff, 0x2e,
40 0xfe, 0x46, 0xc0, 0x93, 0x8b, 0x74, 0xf2, 0xbc, 0xc5, 0x30, 0x52, 0xb0, 0x77,
41 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
42 };
43
44 // kECKeySpecifiedCurve is the above key with P-256's parameters explicitly
45 // spelled out rather than using a named curve.
46 static const uint8_t kECKeySpecifiedCurve[] = {
47 0x30, 0x82, 0x01, 0x22, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc6, 0xc1, 0xaa,
48 0xda, 0x15, 0xb0, 0x76, 0x61, 0xf8, 0x14, 0x2c, 0x6c, 0xaf, 0x0f, 0xdb,
49 0x24, 0x1a, 0xff, 0x2e, 0xfe, 0x46, 0xc0, 0x93, 0x8b, 0x74, 0xf2, 0xbc,
50 0xc5, 0x30, 0x52, 0xb0, 0x77, 0xa0, 0x81, 0xfa, 0x30, 0x81, 0xf7, 0x02,
51 0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01,
52 0x01, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
53 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
54 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
55 0x30, 0x5b, 0x04, 0x20, 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, 0xfc,
58 0x04, 0x20, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb,
59 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
60 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, 0x03, 0x15,
61 0x00, 0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66, 0x78,
62 0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f, 0x7e, 0x90, 0x04, 0x41, 0x04,
63 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5,
64 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
65 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2,
66 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
67 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
68 0x37, 0xbf, 0x51, 0xf5, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
69 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc,
70 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc,
71 0x63, 0x25, 0x51, 0x02, 0x01, 0x01,
72 };
73
74 // kECKeyMissingZeros is an ECPrivateKey containing a degenerate P-256 key where
75 // the private key is one. The private key is incorrectly encoded without zero
76 // padding.
77 static const uint8_t kECKeyMissingZeros[] = {
78 0x30, 0x58, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0xa0, 0x0a, 0x06, 0x08, 0x2a,
79 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04,
80 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63,
81 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1,
82 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f,
83 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57,
84 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
85 };
86
87 // kECKeyMissingZeros is an ECPrivateKey containing a degenerate P-256 key where
88 // the private key is one. The private key is encoded with the required zero
89 // padding.
90 static const uint8_t kECKeyWithZeros[] = {
91 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
94 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1,
95 0x44, 0x03, 0x42, 0x00, 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47,
96 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d,
97 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3,
98 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e,
99 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
100 0x37, 0xbf, 0x51, 0xf5,
101 };
102
103 // DecodeECPrivateKey decodes |in| as an ECPrivateKey structure and returns the
104 // result or nullptr on error.
DecodeECPrivateKey(const uint8_t * in,size_t in_len)105 static bssl::UniquePtr<EC_KEY> DecodeECPrivateKey(const uint8_t *in,
106 size_t in_len) {
107 CBS cbs;
108 CBS_init(&cbs, in, in_len);
109 bssl::UniquePtr<EC_KEY> ret(EC_KEY_parse_private_key(&cbs, NULL));
110 if (!ret || CBS_len(&cbs) != 0) {
111 return nullptr;
112 }
113 return ret;
114 }
115
116 // EncodeECPrivateKey encodes |key| as an ECPrivateKey structure into |*out|. It
117 // returns true on success or false on error.
EncodeECPrivateKey(std::vector<uint8_t> * out,const EC_KEY * key)118 static bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
119 bssl::ScopedCBB cbb;
120 uint8_t *der;
121 size_t der_len;
122 if (!CBB_init(cbb.get(), 0) ||
123 !EC_KEY_marshal_private_key(cbb.get(), key, EC_KEY_get_enc_flags(key)) ||
124 !CBB_finish(cbb.get(), &der, &der_len)) {
125 return false;
126 }
127 out->assign(der, der + der_len);
128 OPENSSL_free(der);
129 return true;
130 }
131
TEST(ECTest,Encoding)132 TEST(ECTest, Encoding) {
133 bssl::UniquePtr<EC_KEY> key =
134 DecodeECPrivateKey(kECKeyWithoutPublic, sizeof(kECKeyWithoutPublic));
135 ASSERT_TRUE(key);
136
137 // Test that the encoding round-trips.
138 std::vector<uint8_t> out;
139 ASSERT_TRUE(EncodeECPrivateKey(&out, key.get()));
140 EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
141
142 const EC_POINT *pub_key = EC_KEY_get0_public_key(key.get());
143 ASSERT_TRUE(pub_key) << "Public key missing";
144
145 bssl::UniquePtr<BIGNUM> x(BN_new());
146 bssl::UniquePtr<BIGNUM> y(BN_new());
147 ASSERT_TRUE(x);
148 ASSERT_TRUE(y);
149 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
150 EC_KEY_get0_group(key.get()), pub_key, x.get(), y.get(), NULL));
151 bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get()));
152 bssl::UniquePtr<char> y_hex(BN_bn2hex(y.get()));
153 ASSERT_TRUE(x_hex);
154 ASSERT_TRUE(y_hex);
155
156 EXPECT_STREQ(
157 "c81561ecf2e54edefe6617db1c7a34a70744ddb261f269b83dacfcd2ade5a681",
158 x_hex.get());
159 EXPECT_STREQ(
160 "e0e2afa3f9b6abe4c698ef6495f1be49a3196c5056acb3763fe4507eec596e88",
161 y_hex.get());
162 }
163
TEST(ECTest,ZeroPadding)164 TEST(ECTest, ZeroPadding) {
165 // Check that the correct encoding round-trips.
166 bssl::UniquePtr<EC_KEY> key =
167 DecodeECPrivateKey(kECKeyWithZeros, sizeof(kECKeyWithZeros));
168 ASSERT_TRUE(key);
169 std::vector<uint8_t> out;
170 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
171 EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
172
173 // Keys without leading zeros also parse, but they encode correctly.
174 key = DecodeECPrivateKey(kECKeyMissingZeros, sizeof(kECKeyMissingZeros));
175 ASSERT_TRUE(key);
176 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
177 EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
178 }
179
TEST(ECTest,SpecifiedCurve)180 TEST(ECTest, SpecifiedCurve) {
181 // Test keys with specified curves may be decoded.
182 bssl::UniquePtr<EC_KEY> key =
183 DecodeECPrivateKey(kECKeySpecifiedCurve, sizeof(kECKeySpecifiedCurve));
184 ASSERT_TRUE(key);
185
186 // The group should have been interpreted as P-256.
187 EXPECT_EQ(NID_X9_62_prime256v1,
188 EC_GROUP_get_curve_name(EC_KEY_get0_group(key.get())));
189
190 // Encoding the key should still use named form.
191 std::vector<uint8_t> out;
192 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
193 EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
194 }
195
TEST(ECTest,ArbitraryCurve)196 TEST(ECTest, ArbitraryCurve) {
197 // Make a P-256 key and extract the affine coordinates.
198 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
199 ASSERT_TRUE(key);
200 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
201
202 // Make an arbitrary curve which is identical to P-256.
203 static const uint8_t kP[] = {
204 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
205 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
206 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
207 };
208 static const uint8_t kA[] = {
209 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
210 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
211 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
212 };
213 static const uint8_t kB[] = {
214 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
215 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
216 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
217 };
218 static const uint8_t kX[] = {
219 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6,
220 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
221 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96,
222 };
223 static const uint8_t kY[] = {
224 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb,
225 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
226 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
227 };
228 static const uint8_t kOrder[] = {
229 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
230 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
231 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
232 };
233 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
234 ASSERT_TRUE(ctx);
235 bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
236 ASSERT_TRUE(p);
237 bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
238 ASSERT_TRUE(a);
239 bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
240 ASSERT_TRUE(b);
241 bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kX, sizeof(kX), nullptr));
242 ASSERT_TRUE(gx);
243 bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kY, sizeof(kY), nullptr));
244 ASSERT_TRUE(gy);
245 bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
246 ASSERT_TRUE(order);
247
248 bssl::UniquePtr<EC_GROUP> group(
249 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
250 ASSERT_TRUE(group);
251 bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
252 ASSERT_TRUE(generator);
253 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
254 group.get(), generator.get(), gx.get(), gy.get(), ctx.get()));
255 ASSERT_TRUE(EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
256 BN_value_one()));
257
258 // |group| should not have a curve name.
259 EXPECT_EQ(NID_undef, EC_GROUP_get_curve_name(group.get()));
260
261 // Copy |key| to |key2| using |group|.
262 bssl::UniquePtr<EC_KEY> key2(EC_KEY_new());
263 ASSERT_TRUE(key2);
264 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
265 ASSERT_TRUE(point);
266 bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new());
267 ASSERT_TRUE(x);
268 ASSERT_TRUE(EC_KEY_set_group(key2.get(), group.get()));
269 ASSERT_TRUE(
270 EC_KEY_set_private_key(key2.get(), EC_KEY_get0_private_key(key.get())));
271 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
272 EC_KEY_get0_group(key.get()), EC_KEY_get0_public_key(key.get()), x.get(),
273 y.get(), nullptr));
274 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(),
275 x.get(), y.get(), nullptr));
276 ASSERT_TRUE(EC_KEY_set_public_key(key2.get(), point.get()));
277
278 // The key must be valid according to the new group too.
279 EXPECT_TRUE(EC_KEY_check_key(key2.get()));
280
281 // Make a second instance of |group|.
282 bssl::UniquePtr<EC_GROUP> group2(
283 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
284 ASSERT_TRUE(group2);
285 bssl::UniquePtr<EC_POINT> generator2(EC_POINT_new(group2.get()));
286 ASSERT_TRUE(generator2);
287 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
288 group2.get(), generator2.get(), gx.get(), gy.get(), ctx.get()));
289 ASSERT_TRUE(EC_GROUP_set_generator(group2.get(), generator2.get(),
290 order.get(), BN_value_one()));
291
292 EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group.get(), NULL));
293 EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), NULL));
294
295 // group3 uses the wrong generator.
296 bssl::UniquePtr<EC_GROUP> group3(
297 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
298 ASSERT_TRUE(group3);
299 bssl::UniquePtr<EC_POINT> generator3(EC_POINT_new(group3.get()));
300 ASSERT_TRUE(generator3);
301 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
302 group3.get(), generator3.get(), x.get(), y.get(), ctx.get()));
303 ASSERT_TRUE(EC_GROUP_set_generator(group3.get(), generator3.get(),
304 order.get(), BN_value_one()));
305
306 EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
307 }
308
TEST(ECTest,SetKeyWithoutGroup)309 TEST(ECTest, SetKeyWithoutGroup) {
310 bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
311 ASSERT_TRUE(key);
312
313 // Private keys may not be configured without a group.
314 EXPECT_FALSE(EC_KEY_set_private_key(key.get(), BN_value_one()));
315
316 // Public keys may not be configured without a group.
317 bssl::UniquePtr<EC_GROUP> group(
318 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
319 ASSERT_TRUE(group);
320 EXPECT_FALSE(
321 EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(group.get())));
322 }
323
TEST(ECTest,GroupMismatch)324 TEST(ECTest, GroupMismatch) {
325 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_secp384r1));
326 ASSERT_TRUE(key);
327 bssl::UniquePtr<EC_GROUP> p256(
328 EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
329 ASSERT_TRUE(p256);
330
331 // Changing a key's group is invalid.
332 EXPECT_FALSE(EC_KEY_set_group(key.get(), p256.get()));
333
334 // Configuring a public key with the wrong group is invalid.
335 EXPECT_FALSE(
336 EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
337 }
338
339 class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
340
TEST_P(ECCurveTest,SetAffine)341 TEST_P(ECCurveTest, SetAffine) {
342 // Generate an EC_KEY.
343 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
344 ASSERT_TRUE(key);
345 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
346
347 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
348 EXPECT_TRUE(
349 EC_POINT_is_on_curve(group, EC_KEY_get0_public_key(key.get()), nullptr));
350
351 // Get the public key's coordinates.
352 bssl::UniquePtr<BIGNUM> x(BN_new());
353 ASSERT_TRUE(x);
354 bssl::UniquePtr<BIGNUM> y(BN_new());
355 ASSERT_TRUE(y);
356 bssl::UniquePtr<BIGNUM> p(BN_new());
357 ASSERT_TRUE(p);
358 EXPECT_TRUE(EC_POINT_get_affine_coordinates_GFp(
359 group, EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr));
360 EXPECT_TRUE(
361 EC_GROUP_get_curve_GFp(group, p.get(), nullptr, nullptr, nullptr));
362
363 // Points on the curve should be accepted.
364 auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group));
365 ASSERT_TRUE(point);
366 EXPECT_TRUE(EC_POINT_set_affine_coordinates_GFp(group, point.get(), x.get(),
367 y.get(), nullptr));
368
369 // Subtract one from |y| to make the point no longer on the curve.
370 EXPECT_TRUE(BN_sub(y.get(), y.get(), BN_value_one()));
371
372 // Points not on the curve should be rejected.
373 bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group));
374 ASSERT_TRUE(invalid_point);
375 EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(),
376 x.get(), y.get(), nullptr));
377
378 // Coordinates out of range should be rejected.
379 EXPECT_TRUE(BN_add(y.get(), y.get(), BN_value_one()));
380 EXPECT_TRUE(BN_add(y.get(), y.get(), p.get()));
381
382 EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(),
383 x.get(), y.get(), nullptr));
384 EXPECT_FALSE(
385 EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()));
386 }
387
TEST_P(ECCurveTest,GenerateFIPS)388 TEST_P(ECCurveTest, GenerateFIPS) {
389 // Generate an EC_KEY.
390 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
391 ASSERT_TRUE(key);
392 ASSERT_TRUE(EC_KEY_generate_key_fips(key.get()));
393 }
394
TEST_P(ECCurveTest,AddingEqualPoints)395 TEST_P(ECCurveTest, AddingEqualPoints) {
396 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
397 ASSERT_TRUE(key);
398 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
399
400 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
401
402 bssl::UniquePtr<EC_POINT> p1(EC_POINT_new(group));
403 ASSERT_TRUE(p1);
404 ASSERT_TRUE(EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())));
405
406 bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group));
407 ASSERT_TRUE(p2);
408 ASSERT_TRUE(EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get())));
409
410 bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group));
411 ASSERT_TRUE(double_p1);
412 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
413 ASSERT_TRUE(ctx);
414 ASSERT_TRUE(EC_POINT_dbl(group, double_p1.get(), p1.get(), ctx.get()));
415
416 bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group));
417 ASSERT_TRUE(p1_plus_p2);
418 ASSERT_TRUE(
419 EC_POINT_add(group, p1_plus_p2.get(), p1.get(), p2.get(), ctx.get()));
420
421 EXPECT_EQ(0,
422 EC_POINT_cmp(group, double_p1.get(), p1_plus_p2.get(), ctx.get()))
423 << "A+A != 2A";
424 }
425
TEST_P(ECCurveTest,MulZero)426 TEST_P(ECCurveTest, MulZero) {
427 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
428 ASSERT_TRUE(group);
429
430 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
431 ASSERT_TRUE(point);
432 bssl::UniquePtr<BIGNUM> zero(BN_new());
433 ASSERT_TRUE(zero);
434 BN_zero(zero.get());
435 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), zero.get(), nullptr,
436 nullptr, nullptr));
437
438 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
439 << "g * 0 did not return point at infinity.";
440
441 // Test that zero times an arbitrary point is also infinity. The generator is
442 // used as the arbitrary point.
443 bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
444 ASSERT_TRUE(generator);
445 ASSERT_TRUE(EC_POINT_mul(group.get(), generator.get(), BN_value_one(),
446 nullptr, nullptr, nullptr));
447 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, generator.get(),
448 zero.get(), nullptr));
449
450 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
451 << "p * 0 did not return point at infinity.";
452 }
453
454 // Test that multiplying by the order produces ∞ and, moreover, that callers may
455 // do so. |EC_POINT_mul| is almost exclusively used with reduced scalars, with
456 // this exception. This comes from consumers following NIST SP 800-56A section
457 // 5.6.2.3.2. (Though all our curves have cofactor one, so this check isn't
458 // useful.)
TEST_P(ECCurveTest,MulOrder)459 TEST_P(ECCurveTest, MulOrder) {
460 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
461 ASSERT_TRUE(group);
462
463 // Test that g × order = ∞.
464 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
465 ASSERT_TRUE(point);
466 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(),
467 EC_GROUP_get0_order(group.get()), nullptr, nullptr,
468 nullptr));
469
470 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
471 << "g * order did not return point at infinity.";
472
473 // Test that p × order = ∞, for some arbitrary p.
474 bssl::UniquePtr<BIGNUM> forty_two(BN_new());
475 ASSERT_TRUE(forty_two);
476 ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
477 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
478 nullptr, nullptr));
479 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, point.get(),
480 EC_GROUP_get0_order(group.get()), nullptr));
481
482 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
483 << "p * order did not return point at infinity.";
484 }
485
486 // Test that |EC_POINT_mul| works with out-of-range scalars. Even beyond the
487 // usual |bn_correct_top| disclaimer, we completely disclaim all hope here as a
488 // reduction is needed, but we'll compute the right answer.
TEST_P(ECCurveTest,MulOutOfRange)489 TEST_P(ECCurveTest, MulOutOfRange) {
490 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
491 ASSERT_TRUE(group);
492
493 bssl::UniquePtr<BIGNUM> n_minus_one(BN_dup(EC_GROUP_get0_order(group.get())));
494 ASSERT_TRUE(n_minus_one);
495 ASSERT_TRUE(BN_sub_word(n_minus_one.get(), 1));
496
497 bssl::UniquePtr<BIGNUM> minus_one(BN_new());
498 ASSERT_TRUE(minus_one);
499 ASSERT_TRUE(BN_one(minus_one.get()));
500 BN_set_negative(minus_one.get(), 1);
501
502 bssl::UniquePtr<BIGNUM> seven(BN_new());
503 ASSERT_TRUE(seven);
504 ASSERT_TRUE(BN_set_word(seven.get(), 7));
505
506 bssl::UniquePtr<BIGNUM> ten_n_plus_seven(
507 BN_dup(EC_GROUP_get0_order(group.get())));
508 ASSERT_TRUE(ten_n_plus_seven);
509 ASSERT_TRUE(BN_mul_word(ten_n_plus_seven.get(), 10));
510 ASSERT_TRUE(BN_add_word(ten_n_plus_seven.get(), 7));
511
512 bssl::UniquePtr<EC_POINT> point1(EC_POINT_new(group.get())),
513 point2(EC_POINT_new(group.get()));
514 ASSERT_TRUE(point1);
515 ASSERT_TRUE(point2);
516
517 ASSERT_TRUE(EC_POINT_mul(group.get(), point1.get(), n_minus_one.get(),
518 nullptr, nullptr, nullptr));
519 ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), minus_one.get(), nullptr,
520 nullptr, nullptr));
521 EXPECT_EQ(0, EC_POINT_cmp(group.get(), point1.get(), point2.get(), nullptr))
522 << "-1 * G and (n-1) * G did not give the same result";
523
524 ASSERT_TRUE(EC_POINT_mul(group.get(), point1.get(), seven.get(), nullptr,
525 nullptr, nullptr));
526 ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), ten_n_plus_seven.get(),
527 nullptr, nullptr, nullptr));
528 EXPECT_EQ(0, EC_POINT_cmp(group.get(), point1.get(), point2.get(), nullptr))
529 << "7 * G and (10n + 7) * G did not give the same result";
530 }
531
532 // Test that 10×∞ + G = G.
TEST_P(ECCurveTest,Mul)533 TEST_P(ECCurveTest, Mul) {
534 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
535 ASSERT_TRUE(group);
536 bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
537 ASSERT_TRUE(p);
538 bssl::UniquePtr<EC_POINT> result(EC_POINT_new(group.get()));
539 ASSERT_TRUE(result);
540 bssl::UniquePtr<BIGNUM> n(BN_new());
541 ASSERT_TRUE(n);
542 ASSERT_TRUE(EC_POINT_set_to_infinity(group.get(), p.get()));
543 ASSERT_TRUE(BN_set_word(n.get(), 10));
544
545 // First check that 10×∞ = ∞.
546 ASSERT_TRUE(EC_POINT_mul(group.get(), result.get(), nullptr, p.get(), n.get(),
547 nullptr));
548 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), result.get()));
549
550 // Now check that 10×∞ + G = G.
551 const EC_POINT *generator = EC_GROUP_get0_generator(group.get());
552 ASSERT_TRUE(EC_POINT_mul(group.get(), result.get(), BN_value_one(), p.get(),
553 n.get(), nullptr));
554 EXPECT_EQ(0, EC_POINT_cmp(group.get(), result.get(), generator, nullptr));
555 }
556
557 #if !defined(BORINGSSL_SHARED_LIBRARY)
TEST_P(ECCurveTest,MulNonMinimal)558 TEST_P(ECCurveTest, MulNonMinimal) {
559 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
560 ASSERT_TRUE(group);
561
562 bssl::UniquePtr<BIGNUM> forty_two(BN_new());
563 ASSERT_TRUE(forty_two);
564 ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
565
566 // Compute g × 42.
567 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
568 ASSERT_TRUE(point);
569 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
570 nullptr, nullptr));
571
572 // Compute it again with a non-minimal 42, much larger than the scalar.
573 ASSERT_TRUE(bn_resize_words(forty_two.get(), 64));
574
575 bssl::UniquePtr<EC_POINT> point2(EC_POINT_new(group.get()));
576 ASSERT_TRUE(point2);
577 ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), forty_two.get(), nullptr,
578 nullptr, nullptr));
579 EXPECT_EQ(0, EC_POINT_cmp(group.get(), point.get(), point2.get(), nullptr));
580 }
581 #endif // BORINGSSL_SHARED_LIBRARY
582
583 // Test that EC_KEY_set_private_key rejects invalid values.
TEST_P(ECCurveTest,SetInvalidPrivateKey)584 TEST_P(ECCurveTest, SetInvalidPrivateKey) {
585 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
586 ASSERT_TRUE(key);
587
588 bssl::UniquePtr<BIGNUM> bn(BN_new());
589 ASSERT_TRUE(BN_one(bn.get()));
590 BN_set_negative(bn.get(), 1);
591 EXPECT_FALSE(EC_KEY_set_private_key(key.get(), bn.get()))
592 << "Unexpectedly set a key of -1";
593 ERR_clear_error();
594
595 ASSERT_TRUE(
596 BN_copy(bn.get(), EC_GROUP_get0_order(EC_KEY_get0_group(key.get()))));
597 EXPECT_FALSE(EC_KEY_set_private_key(key.get(), bn.get()))
598 << "Unexpectedly set a key of the group order.";
599 ERR_clear_error();
600 }
601
TEST_P(ECCurveTest,IgnoreOct2PointReturnValue)602 TEST_P(ECCurveTest, IgnoreOct2PointReturnValue) {
603 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
604 ASSERT_TRUE(group);
605
606 bssl::UniquePtr<BIGNUM> forty_two(BN_new());
607 ASSERT_TRUE(forty_two);
608 ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
609
610 // Compute g × 42.
611 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
612 ASSERT_TRUE(point);
613 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
614 nullptr, nullptr));
615
616 // Serialize the point.
617 size_t serialized_len =
618 EC_POINT_point2oct(group.get(), point.get(),
619 POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
620 ASSERT_NE(0u, serialized_len);
621
622 std::vector<uint8_t> serialized(serialized_len);
623 ASSERT_EQ(serialized_len,
624 EC_POINT_point2oct(group.get(), point.get(),
625 POINT_CONVERSION_UNCOMPRESSED, serialized.data(),
626 serialized_len, nullptr));
627
628 // Create a serialized point that is not on the curve.
629 serialized[serialized_len - 1]++;
630
631 ASSERT_FALSE(EC_POINT_oct2point(group.get(), point.get(), serialized.data(),
632 serialized.size(), nullptr));
633 // After a failure, |point| should have been set to the generator to defend
634 // against code that doesn't check the return value.
635 ASSERT_EQ(0, EC_POINT_cmp(group.get(), point.get(),
636 EC_GROUP_get0_generator(group.get()), nullptr));
637 }
638
AllCurves()639 static std::vector<EC_builtin_curve> AllCurves() {
640 const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
641 std::vector<EC_builtin_curve> curves(num_curves);
642 EC_get_builtin_curves(curves.data(), num_curves);
643 return curves;
644 }
645
CurveToString(const testing::TestParamInfo<EC_builtin_curve> & params)646 static std::string CurveToString(
647 const testing::TestParamInfo<EC_builtin_curve> ¶ms) {
648 // The comment field contains characters GTest rejects, so use the OBJ name.
649 return OBJ_nid2sn(params.param.nid);
650 }
651
652 INSTANTIATE_TEST_CASE_P(, ECCurveTest, testing::ValuesIn(AllCurves()),
653 CurveToString);
654