blob: c0ad61f55c382eb4920ff7f9508c4683a5e715e0 [file] [log] [blame]
Adam Langleye9ada862015-05-11 17:20:37 -07001/* 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>
Robert Sloan49d063b2018-04-03 11:30:38 -070016#include <stdlib.h>
Adam Langleye9ada862015-05-11 17:20:37 -070017#include <string.h>
18
19#include <vector>
20
Robert Sloana94fe052017-02-21 08:49:28 -080021#include <gtest/gtest.h>
22
David Benjaminf0c4a6c2016-08-11 13:26:41 -040023#include <openssl/bn.h>
24#include <openssl/bytestring.h>
Adam Langleye9ada862015-05-11 17:20:37 -070025#include <openssl/crypto.h>
26#include <openssl/ec_key.h>
27#include <openssl/err.h>
28#include <openssl/mem.h>
David Benjaminf0c4a6c2016-08-11 13:26:41 -040029#include <openssl/nid.h>
Robert Sloana94fe052017-02-21 08:49:28 -080030#include <openssl/obj.h>
31
Robert Sloan49d063b2018-04-03 11:30:38 -070032#include "../../test/file_test.h"
Robert Sloan8ff03552017-06-14 12:40:58 -070033#include "../../test/test_util.h"
Robert Sloanab8b8882018-03-26 11:39:51 -070034#include "../bn/internal.h"
35#include "internal.h"
Adam Langleye9ada862015-05-11 17:20:37 -070036
Adam Langleye9ada862015-05-11 17:20:37 -070037
Adam Langleye9ada862015-05-11 17:20:37 -070038// kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
39// omitted.
40static 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
David Benjamin4969cc92016-04-22 15:02:23 -040047// kECKeySpecifiedCurve is the above key with P-256's parameters explicitly
48// spelled out rather than using a named curve.
49static 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
Adam Langleye9ada862015-05-11 17:20:37 -070077// 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.
80static 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.
93static 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.
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400108static bssl::UniquePtr<EC_KEY> DecodeECPrivateKey(const uint8_t *in,
109 size_t in_len) {
David Benjamin4969cc92016-04-22 15:02:23 -0400110 CBS cbs;
111 CBS_init(&cbs, in, in_len);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400112 bssl::UniquePtr<EC_KEY> ret(EC_KEY_parse_private_key(&cbs, NULL));
David Benjamin4969cc92016-04-22 15:02:23 -0400113 if (!ret || CBS_len(&cbs) != 0) {
Adam Langleye9ada862015-05-11 17:20:37 -0700114 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.
David Benjamin4969cc92016-04-22 15:02:23 -0400121static bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
Steven Valdez909b19f2016-11-21 15:35:44 -0500122 bssl::ScopedCBB cbb;
David Benjamin4969cc92016-04-22 15:02:23 -0400123 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;
Adam Langleye9ada862015-05-11 17:20:37 -0700133}
134
Robert Sloana94fe052017-02-21 08:49:28 -0800135TEST(ECTest, Encoding) {
136 bssl::UniquePtr<EC_KEY> key =
137 DecodeECPrivateKey(kECKeyWithoutPublic, sizeof(kECKeyWithoutPublic));
138 ASSERT_TRUE(key);
Adam Langleye9ada862015-05-11 17:20:37 -0700139
Robert Sloana94fe052017-02-21 08:49:28 -0800140 // Test that the encoding round-trips.
Adam Langleye9ada862015-05-11 17:20:37 -0700141 std::vector<uint8_t> out;
Robert Sloana94fe052017-02-21 08:49:28 -0800142 ASSERT_TRUE(EncodeECPrivateKey(&out, key.get()));
143 EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
Adam Langleye9ada862015-05-11 17:20:37 -0700144
145 const EC_POINT *pub_key = EC_KEY_get0_public_key(key.get());
Robert Sloana94fe052017-02-21 08:49:28 -0800146 ASSERT_TRUE(pub_key) << "Public key missing";
Adam Langleye9ada862015-05-11 17:20:37 -0700147
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400148 bssl::UniquePtr<BIGNUM> x(BN_new());
149 bssl::UniquePtr<BIGNUM> y(BN_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800150 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));
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400154 bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get()));
155 bssl::UniquePtr<char> y_hex(BN_bn2hex(y.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800156 ASSERT_TRUE(x_hex);
157 ASSERT_TRUE(y_hex);
Adam Langleye9ada862015-05-11 17:20:37 -0700158
Robert Sloana94fe052017-02-21 08:49:28 -0800159 EXPECT_STREQ(
160 "c81561ecf2e54edefe6617db1c7a34a70744ddb261f269b83dacfcd2ade5a681",
161 x_hex.get());
162 EXPECT_STREQ(
163 "e0e2afa3f9b6abe4c698ef6495f1be49a3196c5056acb3763fe4507eec596e88",
164 y_hex.get());
Adam Langleye9ada862015-05-11 17:20:37 -0700165}
166
Robert Sloana94fe052017-02-21 08:49:28 -0800167TEST(ECTest, ZeroPadding) {
Adam Langleye9ada862015-05-11 17:20:37 -0700168 // Check that the correct encoding round-trips.
Robert Sloana94fe052017-02-21 08:49:28 -0800169 bssl::UniquePtr<EC_KEY> key =
170 DecodeECPrivateKey(kECKeyWithZeros, sizeof(kECKeyWithZeros));
171 ASSERT_TRUE(key);
Adam Langleye9ada862015-05-11 17:20:37 -0700172 std::vector<uint8_t> out;
Robert Sloana94fe052017-02-21 08:49:28 -0800173 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
174 EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
Adam Langleye9ada862015-05-11 17:20:37 -0700175
176 // Keys without leading zeros also parse, but they encode correctly.
177 key = DecodeECPrivateKey(kECKeyMissingZeros, sizeof(kECKeyMissingZeros));
Robert Sloana94fe052017-02-21 08:49:28 -0800178 ASSERT_TRUE(key);
179 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
180 EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
Adam Langleye9ada862015-05-11 17:20:37 -0700181}
182
Robert Sloana94fe052017-02-21 08:49:28 -0800183TEST(ECTest, SpecifiedCurve) {
David Benjamin4969cc92016-04-22 15:02:23 -0400184 // Test keys with specified curves may be decoded.
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400185 bssl::UniquePtr<EC_KEY> key =
David Benjamin4969cc92016-04-22 15:02:23 -0400186 DecodeECPrivateKey(kECKeySpecifiedCurve, sizeof(kECKeySpecifiedCurve));
Robert Sloana94fe052017-02-21 08:49:28 -0800187 ASSERT_TRUE(key);
David Benjamin4969cc92016-04-22 15:02:23 -0400188
189 // The group should have been interpreted as P-256.
Robert Sloana94fe052017-02-21 08:49:28 -0800190 EXPECT_EQ(NID_X9_62_prime256v1,
191 EC_GROUP_get_curve_name(EC_KEY_get0_group(key.get())));
David Benjamin4969cc92016-04-22 15:02:23 -0400192
193 // Encoding the key should still use named form.
194 std::vector<uint8_t> out;
Robert Sloana94fe052017-02-21 08:49:28 -0800195 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
196 EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
David Benjamin4969cc92016-04-22 15:02:23 -0400197}
198
Robert Sloana94fe052017-02-21 08:49:28 -0800199TEST(ECTest, ArbitraryCurve) {
David Benjamin4969cc92016-04-22 15:02:23 -0400200 // Make a P-256 key and extract the affine coordinates.
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400201 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
Robert Sloana94fe052017-02-21 08:49:28 -0800202 ASSERT_TRUE(key);
203 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400204
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 };
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400236 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800237 ASSERT_TRUE(ctx);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400238 bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800239 ASSERT_TRUE(p);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400240 bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800241 ASSERT_TRUE(a);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400242 bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800243 ASSERT_TRUE(b);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400244 bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kX, sizeof(kX), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800245 ASSERT_TRUE(gx);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400246 bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kY, sizeof(kY), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800247 ASSERT_TRUE(gy);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400248 bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800249 ASSERT_TRUE(order);
David Benjamin4969cc92016-04-22 15:02:23 -0400250
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400251 bssl::UniquePtr<EC_GROUP> group(
David Benjamin4969cc92016-04-22 15:02:23 -0400252 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800253 ASSERT_TRUE(group);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400254 bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800255 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()));
David Benjamin4969cc92016-04-22 15:02:23 -0400260
261 // |group| should not have a curve name.
Robert Sloana94fe052017-02-21 08:49:28 -0800262 EXPECT_EQ(NID_undef, EC_GROUP_get_curve_name(group.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400263
264 // Copy |key| to |key2| using |group|.
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400265 bssl::UniquePtr<EC_KEY> key2(EC_KEY_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800266 ASSERT_TRUE(key2);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400267 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800268 ASSERT_TRUE(point);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400269 bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800270 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()));
David Benjamin4969cc92016-04-22 15:02:23 -0400280
281 // The key must be valid according to the new group too.
Robert Sloana94fe052017-02-21 08:49:28 -0800282 EXPECT_TRUE(EC_KEY_check_key(key2.get()));
Robert Sloan29c1d2c2017-10-30 14:10:28 -0700283
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));
Robert Sloanab8b8882018-03-26 11:39:51 -0700310
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
David Benjamin4969cc92016-04-22 15:02:23 -0400333}
334
Robert Sloan0da43952018-01-03 15:13:14 -0800335TEST(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
Robert Sloan89678152019-03-12 14:24:00 -0700350TEST(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
Robert Sloan0da43952018-01-03 15:13:14 -0800364TEST(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
Robert Sloanab8b8882018-03-26 11:39:51 -0700379TEST(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
Robert Sloan49d063b2018-04-03 11:30:38 -0700387static 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).
395TEST(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
Robert Sloanab8b8882018-03-26 11:39:51 -0700442class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {
443 public:
444 const EC_GROUP *group() const { return group_.get(); }
445
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};
Robert Sloana94fe052017-02-21 08:49:28 -0800454
455TEST_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
Robert Sloanab8b8882018-03-26 11:39:51 -0700461 EXPECT_TRUE(EC_POINT_is_on_curve(group(), EC_KEY_get0_public_key(key.get()),
462 nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800463
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);
Robert Sloan0db7f542018-01-16 15:48:33 -0800469 bssl::UniquePtr<BIGNUM> p(BN_new());
470 ASSERT_TRUE(p);
Robert Sloana94fe052017-02-21 08:49:28 -0800471 EXPECT_TRUE(EC_POINT_get_affine_coordinates_GFp(
Robert Sloanab8b8882018-03-26 11:39:51 -0700472 group(), EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr));
Robert Sloan0db7f542018-01-16 15:48:33 -0800473 EXPECT_TRUE(
Robert Sloanab8b8882018-03-26 11:39:51 -0700474 EC_GROUP_get_curve_GFp(group(), p.get(), nullptr, nullptr, nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800475
476 // Points on the curve should be accepted.
Robert Sloanab8b8882018-03-26 11:39:51 -0700477 auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group()));
Robert Sloana94fe052017-02-21 08:49:28 -0800478 ASSERT_TRUE(point);
Robert Sloanab8b8882018-03-26 11:39:51 -0700479 EXPECT_TRUE(EC_POINT_set_affine_coordinates_GFp(group(), point.get(), x.get(),
Robert Sloana94fe052017-02-21 08:49:28 -0800480 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.
Robert Sloanab8b8882018-03-26 11:39:51 -0700486 bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group()));
Robert Sloana94fe052017-02-21 08:49:28 -0800487 ASSERT_TRUE(invalid_point);
Robert Sloanab8b8882018-03-26 11:39:51 -0700488 EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group(), invalid_point.get(),
Robert Sloana94fe052017-02-21 08:49:28 -0800489 x.get(), y.get(), nullptr));
Robert Sloan0db7f542018-01-16 15:48:33 -0800490
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
Robert Sloanab8b8882018-03-26 11:39:51 -0700495 EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group(), invalid_point.get(),
Robert Sloan0db7f542018-01-16 15:48:33 -0800496 x.get(), y.get(), nullptr));
497 EXPECT_FALSE(
498 EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800499}
500
Robert Sloan8ff03552017-06-14 12:40:58 -0700501TEST_P(ECCurveTest, GenerateFIPS) {
Robert Sloan572a4e22017-04-17 10:52:19 -0700502 // Generate an EC_KEY.
503 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
504 ASSERT_TRUE(key);
Robert Sloan8ff03552017-06-14 12:40:58 -0700505 ASSERT_TRUE(EC_KEY_generate_key_fips(key.get()));
Robert Sloan572a4e22017-04-17 10:52:19 -0700506}
507
Robert Sloana94fe052017-02-21 08:49:28 -0800508TEST_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()));
David Benjamin4969cc92016-04-22 15:02:23 -0400512
Robert Sloanab8b8882018-03-26 11:39:51 -0700513 bssl::UniquePtr<EC_POINT> p1(EC_POINT_new(group()));
Robert Sloana94fe052017-02-21 08:49:28 -0800514 ASSERT_TRUE(p1);
515 ASSERT_TRUE(EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())));
516
Robert Sloanab8b8882018-03-26 11:39:51 -0700517 bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group()));
Robert Sloana94fe052017-02-21 08:49:28 -0800518 ASSERT_TRUE(p2);
519 ASSERT_TRUE(EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get())));
520
Robert Sloanab8b8882018-03-26 11:39:51 -0700521 bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group()));
Robert Sloana94fe052017-02-21 08:49:28 -0800522 ASSERT_TRUE(double_p1);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400523 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800524 ASSERT_TRUE(ctx);
Robert Sloanab8b8882018-03-26 11:39:51 -0700525 ASSERT_TRUE(EC_POINT_dbl(group(), double_p1.get(), p1.get(), ctx.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400526
Robert Sloanab8b8882018-03-26 11:39:51 -0700527 bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group()));
Robert Sloana94fe052017-02-21 08:49:28 -0800528 ASSERT_TRUE(p1_plus_p2);
529 ASSERT_TRUE(
Robert Sloanab8b8882018-03-26 11:39:51 -0700530 EC_POINT_add(group(), p1_plus_p2.get(), p1.get(), p2.get(), ctx.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400531
Robert Sloana94fe052017-02-21 08:49:28 -0800532 EXPECT_EQ(0,
Robert Sloanab8b8882018-03-26 11:39:51 -0700533 EC_POINT_cmp(group(), double_p1.get(), p1_plus_p2.get(), ctx.get()))
Robert Sloana94fe052017-02-21 08:49:28 -0800534 << "A+A != 2A";
David Benjamin4969cc92016-04-22 15:02:23 -0400535}
536
Robert Sloana94fe052017-02-21 08:49:28 -0800537TEST_P(ECCurveTest, MulZero) {
Robert Sloanab8b8882018-03-26 11:39:51 -0700538 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
Robert Sloana94fe052017-02-21 08:49:28 -0800539 ASSERT_TRUE(point);
Steven Valdez909b19f2016-11-21 15:35:44 -0500540 bssl::UniquePtr<BIGNUM> zero(BN_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800541 ASSERT_TRUE(zero);
Steven Valdez909b19f2016-11-21 15:35:44 -0500542 BN_zero(zero.get());
Robert Sloanab8b8882018-03-26 11:39:51 -0700543 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), zero.get(), nullptr, nullptr,
544 nullptr));
Steven Valdez909b19f2016-11-21 15:35:44 -0500545
Robert Sloanab8b8882018-03-26 11:39:51 -0700546 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
Robert Sloana94fe052017-02-21 08:49:28 -0800547 << "g * 0 did not return point at infinity.";
Steven Valdez909b19f2016-11-21 15:35:44 -0500548
549 // Test that zero times an arbitrary point is also infinity. The generator is
550 // used as the arbitrary point.
Robert Sloanab8b8882018-03-26 11:39:51 -0700551 bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group()));
Robert Sloana94fe052017-02-21 08:49:28 -0800552 ASSERT_TRUE(generator);
Robert Sloanab8b8882018-03-26 11:39:51 -0700553 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(),
Robert Sloana94fe052017-02-21 08:49:28 -0800556 zero.get(), nullptr));
Steven Valdez909b19f2016-11-21 15:35:44 -0500557
Robert Sloanab8b8882018-03-26 11:39:51 -0700558 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
Robert Sloana94fe052017-02-21 08:49:28 -0800559 << "p * 0 did not return point at infinity.";
Steven Valdez909b19f2016-11-21 15:35:44 -0500560}
561
Robert Sloan99319a12017-11-27 10:32:46 -0800562// 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.)
567TEST_P(ECCurveTest, MulOrder) {
Robert Sloan99319a12017-11-27 10:32:46 -0800568 // Test that g × order = ∞.
Robert Sloanab8b8882018-03-26 11:39:51 -0700569 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
Robert Sloan99319a12017-11-27 10:32:46 -0800570 ASSERT_TRUE(point);
Robert Sloanab8b8882018-03-26 11:39:51 -0700571 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), EC_GROUP_get0_order(group()),
572 nullptr, nullptr, nullptr));
Robert Sloan99319a12017-11-27 10:32:46 -0800573
Robert Sloanab8b8882018-03-26 11:39:51 -0700574 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
Robert Sloan99319a12017-11-27 10:32:46 -0800575 << "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));
Robert Sloanab8b8882018-03-26 11:39:51 -0700581 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
Robert Sloan99319a12017-11-27 10:32:46 -0800582 nullptr, nullptr));
Robert Sloanab8b8882018-03-26 11:39:51 -0700583 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), nullptr, point.get(),
584 EC_GROUP_get0_order(group()), nullptr));
Robert Sloan99319a12017-11-27 10:32:46 -0800585
Robert Sloanab8b8882018-03-26 11:39:51 -0700586 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), point.get()))
Robert Sloan99319a12017-11-27 10:32:46 -0800587 << "p * order did not return point at infinity.";
588}
589
Robert Sloanab8b8882018-03-26 11:39:51 -0700590// 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.
Robert Sloana815d5a2017-12-04 11:49:16 -0800592TEST_P(ECCurveTest, MulOutOfRange) {
Robert Sloanab8b8882018-03-26 11:39:51 -0700593 bssl::UniquePtr<BIGNUM> n_minus_one(BN_dup(EC_GROUP_get0_order(group())));
Robert Sloana815d5a2017-12-04 11:49:16 -0800594 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(
Robert Sloanab8b8882018-03-26 11:39:51 -0700607 BN_dup(EC_GROUP_get0_order(group())));
Robert Sloana815d5a2017-12-04 11:49:16 -0800608 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
Robert Sloanab8b8882018-03-26 11:39:51 -0700612 bssl::UniquePtr<EC_POINT> point1(EC_POINT_new(group())),
613 point2(EC_POINT_new(group()));
Robert Sloana815d5a2017-12-04 11:49:16 -0800614 ASSERT_TRUE(point1);
615 ASSERT_TRUE(point2);
616
Robert Sloanab8b8882018-03-26 11:39:51 -0700617 ASSERT_TRUE(EC_POINT_mul(group(), point1.get(), n_minus_one.get(), nullptr,
Robert Sloana815d5a2017-12-04 11:49:16 -0800618 nullptr, nullptr));
Robert Sloanab8b8882018-03-26 11:39:51 -0700619 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))
Robert Sloana815d5a2017-12-04 11:49:16 -0800622 << "-1 * G and (n-1) * G did not give the same result";
623
Robert Sloanab8b8882018-03-26 11:39:51 -0700624 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(),
Robert Sloana815d5a2017-12-04 11:49:16 -0800627 nullptr, nullptr, nullptr));
Robert Sloanab8b8882018-03-26 11:39:51 -0700628 EXPECT_EQ(0, EC_POINT_cmp(group(), point1.get(), point2.get(), nullptr))
Robert Sloana815d5a2017-12-04 11:49:16 -0800629 << "7 * G and (10n + 7) * G did not give the same result";
630}
631
Robert Sloana12bf462017-07-17 07:08:26 -0700632// Test that 10×∞ + G = G.
633TEST_P(ECCurveTest, Mul) {
Robert Sloanab8b8882018-03-26 11:39:51 -0700634 bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group()));
Robert Sloana12bf462017-07-17 07:08:26 -0700635 ASSERT_TRUE(p);
Robert Sloanab8b8882018-03-26 11:39:51 -0700636 bssl::UniquePtr<EC_POINT> result(EC_POINT_new(group()));
Robert Sloana12bf462017-07-17 07:08:26 -0700637 ASSERT_TRUE(result);
638 bssl::UniquePtr<BIGNUM> n(BN_new());
639 ASSERT_TRUE(n);
Robert Sloanab8b8882018-03-26 11:39:51 -0700640 ASSERT_TRUE(EC_POINT_set_to_infinity(group(), p.get()));
Robert Sloana12bf462017-07-17 07:08:26 -0700641 ASSERT_TRUE(BN_set_word(n.get(), 10));
642
643 // First check that 10×∞ = ∞.
Robert Sloanab8b8882018-03-26 11:39:51 -0700644 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()));
Robert Sloana12bf462017-07-17 07:08:26 -0700647
648 // Now check that 10×∞ + G = G.
Robert Sloanab8b8882018-03-26 11:39:51 -0700649 const EC_POINT *generator = EC_GROUP_get0_generator(group());
650 ASSERT_TRUE(EC_POINT_mul(group(), result.get(), BN_value_one(), p.get(),
Robert Sloana12bf462017-07-17 07:08:26 -0700651 n.get(), nullptr));
Robert Sloanab8b8882018-03-26 11:39:51 -0700652 EXPECT_EQ(0, EC_POINT_cmp(group(), result.get(), generator, nullptr));
Robert Sloana12bf462017-07-17 07:08:26 -0700653}
654
Robert Sloan8542c082018-02-05 09:07:34 -0800655TEST_P(ECCurveTest, MulNonMinimal) {
Robert Sloan8542c082018-02-05 09:07:34 -0800656 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.
Robert Sloanab8b8882018-03-26 11:39:51 -0700661 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
Robert Sloan8542c082018-02-05 09:07:34 -0800662 ASSERT_TRUE(point);
Robert Sloanab8b8882018-03-26 11:39:51 -0700663 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
Robert Sloan8542c082018-02-05 09:07:34 -0800664 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
Robert Sloanab8b8882018-03-26 11:39:51 -0700669 bssl::UniquePtr<EC_POINT> point2(EC_POINT_new(group()));
Robert Sloan8542c082018-02-05 09:07:34 -0800670 ASSERT_TRUE(point2);
Robert Sloanab8b8882018-03-26 11:39:51 -0700671 ASSERT_TRUE(EC_POINT_mul(group(), point2.get(), forty_two.get(), nullptr,
Robert Sloan8542c082018-02-05 09:07:34 -0800672 nullptr, nullptr));
Robert Sloanab8b8882018-03-26 11:39:51 -0700673 EXPECT_EQ(0, EC_POINT_cmp(group(), point.get(), point2.get(), nullptr));
Robert Sloan8542c082018-02-05 09:07:34 -0800674}
Robert Sloan8542c082018-02-05 09:07:34 -0800675
Robert Sloancd79cde2017-12-11 09:06:12 -0800676// Test that EC_KEY_set_private_key rejects invalid values.
677TEST_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
Robert Sloan8542c082018-02-05 09:07:34 -0800695TEST_P(ECCurveTest, IgnoreOct2PointReturnValue) {
Robert Sloan8542c082018-02-05 09:07:34 -0800696 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.
Robert Sloanab8b8882018-03-26 11:39:51 -0700701 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group()));
Robert Sloan8542c082018-02-05 09:07:34 -0800702 ASSERT_TRUE(point);
Robert Sloanab8b8882018-03-26 11:39:51 -0700703 ASSERT_TRUE(EC_POINT_mul(group(), point.get(), forty_two.get(), nullptr,
Robert Sloan8542c082018-02-05 09:07:34 -0800704 nullptr, nullptr));
705
706 // Serialize the point.
Robert Sloanab8b8882018-03-26 11:39:51 -0700707 size_t serialized_len = EC_POINT_point2oct(
708 group(), point.get(), POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
Robert Sloan8542c082018-02-05 09:07:34 -0800709 ASSERT_NE(0u, serialized_len);
710
711 std::vector<uint8_t> serialized(serialized_len);
Robert Sloanab8b8882018-03-26 11:39:51 -0700712 ASSERT_EQ(
713 serialized_len,
714 EC_POINT_point2oct(group(), point.get(), POINT_CONVERSION_UNCOMPRESSED,
715 serialized.data(), serialized_len, nullptr));
Robert Sloan8542c082018-02-05 09:07:34 -0800716
717 // Create a serialized point that is not on the curve.
718 serialized[serialized_len - 1]++;
719
Robert Sloanab8b8882018-03-26 11:39:51 -0700720 ASSERT_FALSE(EC_POINT_oct2point(group(), point.get(), serialized.data(),
Robert Sloan8542c082018-02-05 09:07:34 -0800721 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.
Robert Sloanab8b8882018-03-26 11:39:51 -0700724 ASSERT_EQ(0, EC_POINT_cmp(group(), point.get(),
725 EC_GROUP_get0_generator(group()), nullptr));
726}
727
728TEST_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(
Robert Sloanc9abfe42018-11-26 12:19:07 -0800744 ec_point_mul_scalar_public(group(), &p->raw, &one, &g->raw, &one));
Robert Sloanab8b8882018-03-26 11:39:51 -0700745 EXPECT_EQ(0, EC_POINT_cmp(group(), p.get(), two_g.get(), nullptr));
Robert Sloan8542c082018-02-05 09:07:34 -0800746}
747
Robert Sloan49d063b2018-04-03 11:30:38 -0700748// This a regression test for a P-224 bug, but we may as well run it for all
749// curves.
750TEST_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));
Pete Bentley0c61efe2019-08-13 09:32:23 +0100767 EXPECT_EQ(0, EC_POINT_cmp(group(), ret.get(), g, nullptr));
Robert Sloan49d063b2018-04-03 11:30:38 -0700768
Pete Bentley0c61efe2019-08-13 09:32:23 +0100769 // Repeat the computation with |ec_point_mul_scalar_public|, which ties the
770 // additions together.
771 EC_SCALAR sc31, sc32;
772 ASSERT_TRUE(ec_bignum_to_scalar(group(), &sc31, bn31.get()));
773 ASSERT_TRUE(ec_bignum_to_scalar(group(), &sc32, bn32.get()));
774 ASSERT_TRUE(
775 ec_point_mul_scalar_public(group(), &ret->raw, &sc32, &p->raw, &sc31));
Robert Sloan49d063b2018-04-03 11:30:38 -0700776 EXPECT_EQ(0, EC_POINT_cmp(group(), ret.get(), g, nullptr));
777}
778
Robert Sloanc9abfe42018-11-26 12:19:07 -0800779TEST_P(ECCurveTest, GPlusMinusG) {
780 const EC_POINT *g = EC_GROUP_get0_generator(group());
781 bssl::UniquePtr<EC_POINT> p(EC_POINT_dup(g, group()));
782 ASSERT_TRUE(p);
783 ASSERT_TRUE(EC_POINT_invert(group(), p.get(), nullptr));
784 bssl::UniquePtr<EC_POINT> sum(EC_POINT_new(group()));
785
786 ASSERT_TRUE(EC_POINT_add(group(), sum.get(), g, p.get(), nullptr));
787 EXPECT_TRUE(EC_POINT_is_at_infinity(group(), sum.get()));
788}
789
Robert Sloana94fe052017-02-21 08:49:28 -0800790static std::vector<EC_builtin_curve> AllCurves() {
David Benjamin4969cc92016-04-22 15:02:23 -0400791 const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
792 std::vector<EC_builtin_curve> curves(num_curves);
793 EC_get_builtin_curves(curves.data(), num_curves);
Robert Sloana94fe052017-02-21 08:49:28 -0800794 return curves;
David Benjamin4969cc92016-04-22 15:02:23 -0400795}
796
Robert Sloana94fe052017-02-21 08:49:28 -0800797static std::string CurveToString(
798 const testing::TestParamInfo<EC_builtin_curve> &params) {
799 // The comment field contains characters GTest rejects, so use the OBJ name.
800 return OBJ_nid2sn(params.param.nid);
Adam Langleye9ada862015-05-11 17:20:37 -0700801}
Robert Sloana94fe052017-02-21 08:49:28 -0800802
Robert Sloanf63bd1f2019-04-16 09:26:20 -0700803INSTANTIATE_TEST_SUITE_P(, ECCurveTest, testing::ValuesIn(AllCurves()),
804 CurveToString);
Robert Sloan49d063b2018-04-03 11:30:38 -0700805
806static bssl::UniquePtr<EC_GROUP> GetCurve(FileTest *t, const char *key) {
807 std::string curve_name;
808 if (!t->GetAttribute(&curve_name, key)) {
809 return nullptr;
810 }
811
812 if (curve_name == "P-224") {
813 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp224r1));
814 }
815 if (curve_name == "P-256") {
816 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(
817 NID_X9_62_prime256v1));
818 }
819 if (curve_name == "P-384") {
820 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp384r1));
821 }
822 if (curve_name == "P-521") {
823 return bssl::UniquePtr<EC_GROUP>(EC_GROUP_new_by_curve_name(NID_secp521r1));
824 }
825
826 t->PrintLine("Unknown curve '%s'", curve_name.c_str());
827 return nullptr;
828}
829
830static bssl::UniquePtr<BIGNUM> GetBIGNUM(FileTest *t, const char *key) {
831 std::vector<uint8_t> bytes;
832 if (!t->GetBytes(&bytes, key)) {
833 return nullptr;
834 }
835
836 return bssl::UniquePtr<BIGNUM>(
837 BN_bin2bn(bytes.data(), bytes.size(), nullptr));
838}
839
840TEST(ECTest, ScalarBaseMultVectors) {
841 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
842 ASSERT_TRUE(ctx);
843
844 FileTestGTest("crypto/fipsmodule/ec/ec_scalar_base_mult_tests.txt",
845 [&](FileTest *t) {
846 bssl::UniquePtr<EC_GROUP> group = GetCurve(t, "Curve");
847 ASSERT_TRUE(group);
848 bssl::UniquePtr<BIGNUM> n = GetBIGNUM(t, "N");
849 ASSERT_TRUE(n);
850 bssl::UniquePtr<BIGNUM> x = GetBIGNUM(t, "X");
851 ASSERT_TRUE(x);
852 bssl::UniquePtr<BIGNUM> y = GetBIGNUM(t, "Y");
853 ASSERT_TRUE(y);
854 bool is_infinity = BN_is_zero(x.get()) && BN_is_zero(y.get());
855
856 bssl::UniquePtr<BIGNUM> px(BN_new());
857 ASSERT_TRUE(px);
858 bssl::UniquePtr<BIGNUM> py(BN_new());
859 ASSERT_TRUE(py);
860 auto check_point = [&](const EC_POINT *p) {
861 if (is_infinity) {
862 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), p));
863 } else {
864 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
865 group.get(), p, px.get(), py.get(), ctx.get()));
866 EXPECT_EQ(0, BN_cmp(x.get(), px.get()));
867 EXPECT_EQ(0, BN_cmp(y.get(), py.get()));
868 }
869 };
870
871 const EC_POINT *g = EC_GROUP_get0_generator(group.get());
872 bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
873 ASSERT_TRUE(p);
874 // Test single-point multiplication.
875 ASSERT_TRUE(EC_POINT_mul(group.get(), p.get(), n.get(), nullptr, nullptr,
876 ctx.get()));
877 check_point(p.get());
878
879 ASSERT_TRUE(
880 EC_POINT_mul(group.get(), p.get(), nullptr, g, n.get(), ctx.get()));
881 check_point(p.get());
882
883 // These tests take a very long time, but are worth running when we make
884 // non-trivial changes to the EC code.
885#if 0
886 // Test two-point multiplication.
887 bssl::UniquePtr<BIGNUM> a(BN_new()), b(BN_new());
888 for (int i = -64; i < 64; i++) {
889 SCOPED_TRACE(i);
890 ASSERT_TRUE(BN_set_word(a.get(), abs(i)));
891 if (i < 0) {
892 ASSERT_TRUE(BN_sub(a.get(), EC_GROUP_get0_order(group.get()), a.get()));
893 }
894
895 ASSERT_TRUE(BN_copy(b.get(), n.get()));
896 ASSERT_TRUE(BN_sub(b.get(), b.get(), a.get()));
897 if (BN_is_negative(b.get())) {
898 ASSERT_TRUE(BN_add(b.get(), b.get(), EC_GROUP_get0_order(group.get())));
899 }
900
901 ASSERT_TRUE(
902 EC_POINT_mul(group.get(), p.get(), a.get(), g, b.get(), ctx.get()));
903 check_point(p.get());
904
905 EC_SCALAR a_scalar, b_scalar;
906 ASSERT_TRUE(ec_bignum_to_scalar(group.get(), &a_scalar, a.get()));
907 ASSERT_TRUE(ec_bignum_to_scalar(group.get(), &b_scalar, b.get()));
Robert Sloanc9abfe42018-11-26 12:19:07 -0800908 ASSERT_TRUE(ec_point_mul_scalar_public(group.get(), &p->raw, &a_scalar, &g->raw,
909 &b_scalar));
Robert Sloan49d063b2018-04-03 11:30:38 -0700910 check_point(p.get());
911 }
912#endif
913 });
914}