blob: 71f9fd80116031dfd853a412ca162ad24e56471b [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>
16#include <string.h>
17
18#include <vector>
19
Robert Sloana94fe052017-02-21 08:49:28 -080020#include <gtest/gtest.h>
21
David Benjaminf0c4a6c2016-08-11 13:26:41 -040022#include <openssl/bn.h>
23#include <openssl/bytestring.h>
Adam Langleye9ada862015-05-11 17:20:37 -070024#include <openssl/crypto.h>
25#include <openssl/ec_key.h>
26#include <openssl/err.h>
27#include <openssl/mem.h>
David Benjaminf0c4a6c2016-08-11 13:26:41 -040028#include <openssl/nid.h>
Robert Sloana94fe052017-02-21 08:49:28 -080029#include <openssl/obj.h>
30
Robert Sloan8ff03552017-06-14 12:40:58 -070031#include "../../test/test_util.h"
Adam Langleye9ada862015-05-11 17:20:37 -070032
Adam Langleye9ada862015-05-11 17:20:37 -070033
Adam Langleye9ada862015-05-11 17:20:37 -070034// kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
35// omitted.
36static const uint8_t kECKeyWithoutPublic[] = {
37 0x30, 0x31, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc6, 0xc1, 0xaa, 0xda, 0x15, 0xb0,
38 0x76, 0x61, 0xf8, 0x14, 0x2c, 0x6c, 0xaf, 0x0f, 0xdb, 0x24, 0x1a, 0xff, 0x2e,
39 0xfe, 0x46, 0xc0, 0x93, 0x8b, 0x74, 0xf2, 0xbc, 0xc5, 0x30, 0x52, 0xb0, 0x77,
40 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
41};
42
David Benjamin4969cc92016-04-22 15:02:23 -040043// kECKeySpecifiedCurve is the above key with P-256's parameters explicitly
44// spelled out rather than using a named curve.
45static const uint8_t kECKeySpecifiedCurve[] = {
46 0x30, 0x82, 0x01, 0x22, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc6, 0xc1, 0xaa,
47 0xda, 0x15, 0xb0, 0x76, 0x61, 0xf8, 0x14, 0x2c, 0x6c, 0xaf, 0x0f, 0xdb,
48 0x24, 0x1a, 0xff, 0x2e, 0xfe, 0x46, 0xc0, 0x93, 0x8b, 0x74, 0xf2, 0xbc,
49 0xc5, 0x30, 0x52, 0xb0, 0x77, 0xa0, 0x81, 0xfa, 0x30, 0x81, 0xf7, 0x02,
50 0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01,
51 0x01, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
52 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
54 0x30, 0x5b, 0x04, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
55 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
57 0x04, 0x20, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb,
58 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
59 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, 0x03, 0x15,
60 0x00, 0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66, 0x78,
61 0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f, 0x7e, 0x90, 0x04, 0x41, 0x04,
62 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5,
63 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
64 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2,
65 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
66 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
67 0x37, 0xbf, 0x51, 0xf5, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
68 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc,
69 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc,
70 0x63, 0x25, 0x51, 0x02, 0x01, 0x01,
71};
72
Adam Langleye9ada862015-05-11 17:20:37 -070073// kECKeyMissingZeros is an ECPrivateKey containing a degenerate P-256 key where
74// the private key is one. The private key is incorrectly encoded without zero
75// padding.
76static const uint8_t kECKeyMissingZeros[] = {
77 0x30, 0x58, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0xa0, 0x0a, 0x06, 0x08, 0x2a,
78 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04,
79 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63,
80 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1,
81 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f,
82 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57,
83 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
84};
85
86// kECKeyMissingZeros is an ECPrivateKey containing a degenerate P-256 key where
87// the private key is one. The private key is encoded with the required zero
88// padding.
89static const uint8_t kECKeyWithZeros[] = {
90 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
93 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1,
94 0x44, 0x03, 0x42, 0x00, 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47,
95 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d,
96 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3,
97 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e,
98 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
99 0x37, 0xbf, 0x51, 0xf5,
100};
101
102// DecodeECPrivateKey decodes |in| as an ECPrivateKey structure and returns the
103// result or nullptr on error.
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400104static bssl::UniquePtr<EC_KEY> DecodeECPrivateKey(const uint8_t *in,
105 size_t in_len) {
David Benjamin4969cc92016-04-22 15:02:23 -0400106 CBS cbs;
107 CBS_init(&cbs, in, in_len);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400108 bssl::UniquePtr<EC_KEY> ret(EC_KEY_parse_private_key(&cbs, NULL));
David Benjamin4969cc92016-04-22 15:02:23 -0400109 if (!ret || CBS_len(&cbs) != 0) {
Adam Langleye9ada862015-05-11 17:20:37 -0700110 return nullptr;
111 }
112 return ret;
113}
114
115// EncodeECPrivateKey encodes |key| as an ECPrivateKey structure into |*out|. It
116// returns true on success or false on error.
David Benjamin4969cc92016-04-22 15:02:23 -0400117static bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
Steven Valdez909b19f2016-11-21 15:35:44 -0500118 bssl::ScopedCBB cbb;
David Benjamin4969cc92016-04-22 15:02:23 -0400119 uint8_t *der;
120 size_t der_len;
121 if (!CBB_init(cbb.get(), 0) ||
122 !EC_KEY_marshal_private_key(cbb.get(), key, EC_KEY_get_enc_flags(key)) ||
123 !CBB_finish(cbb.get(), &der, &der_len)) {
124 return false;
125 }
126 out->assign(der, der + der_len);
127 OPENSSL_free(der);
128 return true;
Adam Langleye9ada862015-05-11 17:20:37 -0700129}
130
Robert Sloana94fe052017-02-21 08:49:28 -0800131TEST(ECTest, Encoding) {
132 bssl::UniquePtr<EC_KEY> key =
133 DecodeECPrivateKey(kECKeyWithoutPublic, sizeof(kECKeyWithoutPublic));
134 ASSERT_TRUE(key);
Adam Langleye9ada862015-05-11 17:20:37 -0700135
Robert Sloana94fe052017-02-21 08:49:28 -0800136 // Test that the encoding round-trips.
Adam Langleye9ada862015-05-11 17:20:37 -0700137 std::vector<uint8_t> out;
Robert Sloana94fe052017-02-21 08:49:28 -0800138 ASSERT_TRUE(EncodeECPrivateKey(&out, key.get()));
139 EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
Adam Langleye9ada862015-05-11 17:20:37 -0700140
141 const EC_POINT *pub_key = EC_KEY_get0_public_key(key.get());
Robert Sloana94fe052017-02-21 08:49:28 -0800142 ASSERT_TRUE(pub_key) << "Public key missing";
Adam Langleye9ada862015-05-11 17:20:37 -0700143
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400144 bssl::UniquePtr<BIGNUM> x(BN_new());
145 bssl::UniquePtr<BIGNUM> y(BN_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800146 ASSERT_TRUE(x);
147 ASSERT_TRUE(y);
148 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
149 EC_KEY_get0_group(key.get()), pub_key, x.get(), y.get(), NULL));
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400150 bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get()));
151 bssl::UniquePtr<char> y_hex(BN_bn2hex(y.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800152 ASSERT_TRUE(x_hex);
153 ASSERT_TRUE(y_hex);
Adam Langleye9ada862015-05-11 17:20:37 -0700154
Robert Sloana94fe052017-02-21 08:49:28 -0800155 EXPECT_STREQ(
156 "c81561ecf2e54edefe6617db1c7a34a70744ddb261f269b83dacfcd2ade5a681",
157 x_hex.get());
158 EXPECT_STREQ(
159 "e0e2afa3f9b6abe4c698ef6495f1be49a3196c5056acb3763fe4507eec596e88",
160 y_hex.get());
Adam Langleye9ada862015-05-11 17:20:37 -0700161}
162
Robert Sloana94fe052017-02-21 08:49:28 -0800163TEST(ECTest, ZeroPadding) {
Adam Langleye9ada862015-05-11 17:20:37 -0700164 // Check that the correct encoding round-trips.
Robert Sloana94fe052017-02-21 08:49:28 -0800165 bssl::UniquePtr<EC_KEY> key =
166 DecodeECPrivateKey(kECKeyWithZeros, sizeof(kECKeyWithZeros));
167 ASSERT_TRUE(key);
Adam Langleye9ada862015-05-11 17:20:37 -0700168 std::vector<uint8_t> out;
Robert Sloana94fe052017-02-21 08:49:28 -0800169 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
170 EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
Adam Langleye9ada862015-05-11 17:20:37 -0700171
172 // Keys without leading zeros also parse, but they encode correctly.
173 key = DecodeECPrivateKey(kECKeyMissingZeros, sizeof(kECKeyMissingZeros));
Robert Sloana94fe052017-02-21 08:49:28 -0800174 ASSERT_TRUE(key);
175 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
176 EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
Adam Langleye9ada862015-05-11 17:20:37 -0700177}
178
Robert Sloana94fe052017-02-21 08:49:28 -0800179TEST(ECTest, SpecifiedCurve) {
David Benjamin4969cc92016-04-22 15:02:23 -0400180 // Test keys with specified curves may be decoded.
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400181 bssl::UniquePtr<EC_KEY> key =
David Benjamin4969cc92016-04-22 15:02:23 -0400182 DecodeECPrivateKey(kECKeySpecifiedCurve, sizeof(kECKeySpecifiedCurve));
Robert Sloana94fe052017-02-21 08:49:28 -0800183 ASSERT_TRUE(key);
David Benjamin4969cc92016-04-22 15:02:23 -0400184
185 // The group should have been interpreted as P-256.
Robert Sloana94fe052017-02-21 08:49:28 -0800186 EXPECT_EQ(NID_X9_62_prime256v1,
187 EC_GROUP_get_curve_name(EC_KEY_get0_group(key.get())));
David Benjamin4969cc92016-04-22 15:02:23 -0400188
189 // Encoding the key should still use named form.
190 std::vector<uint8_t> out;
Robert Sloana94fe052017-02-21 08:49:28 -0800191 EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
192 EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
David Benjamin4969cc92016-04-22 15:02:23 -0400193}
194
Robert Sloana94fe052017-02-21 08:49:28 -0800195TEST(ECTest, ArbitraryCurve) {
David Benjamin4969cc92016-04-22 15:02:23 -0400196 // Make a P-256 key and extract the affine coordinates.
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400197 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
Robert Sloana94fe052017-02-21 08:49:28 -0800198 ASSERT_TRUE(key);
199 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400200
201 // Make an arbitrary curve which is identical to P-256.
202 static const uint8_t kP[] = {
203 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
204 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
205 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
206 };
207 static const uint8_t kA[] = {
208 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
209 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
210 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
211 };
212 static const uint8_t kB[] = {
213 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
214 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
215 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
216 };
217 static const uint8_t kX[] = {
218 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6,
219 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
220 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96,
221 };
222 static const uint8_t kY[] = {
223 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb,
224 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
225 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
226 };
227 static const uint8_t kOrder[] = {
228 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
229 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
230 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
231 };
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400232 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800233 ASSERT_TRUE(ctx);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400234 bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800235 ASSERT_TRUE(p);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400236 bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800237 ASSERT_TRUE(a);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400238 bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800239 ASSERT_TRUE(b);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400240 bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kX, sizeof(kX), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800241 ASSERT_TRUE(gx);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400242 bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kY, sizeof(kY), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800243 ASSERT_TRUE(gy);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400244 bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
Robert Sloana94fe052017-02-21 08:49:28 -0800245 ASSERT_TRUE(order);
David Benjamin4969cc92016-04-22 15:02:23 -0400246
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400247 bssl::UniquePtr<EC_GROUP> group(
David Benjamin4969cc92016-04-22 15:02:23 -0400248 EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800249 ASSERT_TRUE(group);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400250 bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800251 ASSERT_TRUE(generator);
252 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
253 group.get(), generator.get(), gx.get(), gy.get(), ctx.get()));
254 ASSERT_TRUE(EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
255 BN_value_one()));
David Benjamin4969cc92016-04-22 15:02:23 -0400256
257 // |group| should not have a curve name.
Robert Sloana94fe052017-02-21 08:49:28 -0800258 EXPECT_EQ(NID_undef, EC_GROUP_get_curve_name(group.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400259
260 // Copy |key| to |key2| using |group|.
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400261 bssl::UniquePtr<EC_KEY> key2(EC_KEY_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800262 ASSERT_TRUE(key2);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400263 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800264 ASSERT_TRUE(point);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400265 bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800266 ASSERT_TRUE(x);
267 ASSERT_TRUE(EC_KEY_set_group(key2.get(), group.get()));
268 ASSERT_TRUE(
269 EC_KEY_set_private_key(key2.get(), EC_KEY_get0_private_key(key.get())));
270 ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
271 EC_KEY_get0_group(key.get()), EC_KEY_get0_public_key(key.get()), x.get(),
272 y.get(), nullptr));
273 ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(),
274 x.get(), y.get(), nullptr));
275 ASSERT_TRUE(EC_KEY_set_public_key(key2.get(), point.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400276
277 // The key must be valid according to the new group too.
Robert Sloana94fe052017-02-21 08:49:28 -0800278 EXPECT_TRUE(EC_KEY_check_key(key2.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400279}
280
Robert Sloana94fe052017-02-21 08:49:28 -0800281class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
282
283TEST_P(ECCurveTest, SetAffine) {
284 // Generate an EC_KEY.
285 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
286 ASSERT_TRUE(key);
287 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
288
289 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
290 EXPECT_TRUE(
291 EC_POINT_is_on_curve(group, EC_KEY_get0_public_key(key.get()), nullptr));
292
293 // Get the public key's coordinates.
294 bssl::UniquePtr<BIGNUM> x(BN_new());
295 ASSERT_TRUE(x);
296 bssl::UniquePtr<BIGNUM> y(BN_new());
297 ASSERT_TRUE(y);
298 EXPECT_TRUE(EC_POINT_get_affine_coordinates_GFp(
299 group, EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr));
300
301 // Points on the curve should be accepted.
302 auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group));
303 ASSERT_TRUE(point);
304 EXPECT_TRUE(EC_POINT_set_affine_coordinates_GFp(group, point.get(), x.get(),
305 y.get(), nullptr));
306
307 // Subtract one from |y| to make the point no longer on the curve.
308 EXPECT_TRUE(BN_sub(y.get(), y.get(), BN_value_one()));
309
310 // Points not on the curve should be rejected.
311 bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group));
312 ASSERT_TRUE(invalid_point);
313 EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(),
314 x.get(), y.get(), nullptr));
315}
316
Robert Sloan8ff03552017-06-14 12:40:58 -0700317TEST_P(ECCurveTest, GenerateFIPS) {
Robert Sloan572a4e22017-04-17 10:52:19 -0700318 // Generate an EC_KEY.
319 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
320 ASSERT_TRUE(key);
Robert Sloan8ff03552017-06-14 12:40:58 -0700321 ASSERT_TRUE(EC_KEY_generate_key_fips(key.get()));
Robert Sloan572a4e22017-04-17 10:52:19 -0700322}
323
Robert Sloana94fe052017-02-21 08:49:28 -0800324TEST_P(ECCurveTest, AddingEqualPoints) {
325 bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
326 ASSERT_TRUE(key);
327 ASSERT_TRUE(EC_KEY_generate_key(key.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400328
329 const EC_GROUP *const group = EC_KEY_get0_group(key.get());
330
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400331 bssl::UniquePtr<EC_POINT> p1(EC_POINT_new(group));
Robert Sloana94fe052017-02-21 08:49:28 -0800332 ASSERT_TRUE(p1);
333 ASSERT_TRUE(EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())));
334
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400335 bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group));
Robert Sloana94fe052017-02-21 08:49:28 -0800336 ASSERT_TRUE(p2);
337 ASSERT_TRUE(EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get())));
338
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400339 bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group));
Robert Sloana94fe052017-02-21 08:49:28 -0800340 ASSERT_TRUE(double_p1);
David Benjaminf0c4a6c2016-08-11 13:26:41 -0400341 bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800342 ASSERT_TRUE(ctx);
343 ASSERT_TRUE(EC_POINT_dbl(group, double_p1.get(), p1.get(), ctx.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400344
Robert Sloana94fe052017-02-21 08:49:28 -0800345 bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group));
346 ASSERT_TRUE(p1_plus_p2);
347 ASSERT_TRUE(
348 EC_POINT_add(group, p1_plus_p2.get(), p1.get(), p2.get(), ctx.get()));
David Benjamin4969cc92016-04-22 15:02:23 -0400349
Robert Sloana94fe052017-02-21 08:49:28 -0800350 EXPECT_EQ(0,
351 EC_POINT_cmp(group, double_p1.get(), p1_plus_p2.get(), ctx.get()))
352 << "A+A != 2A";
David Benjamin4969cc92016-04-22 15:02:23 -0400353}
354
Robert Sloana94fe052017-02-21 08:49:28 -0800355TEST_P(ECCurveTest, MulZero) {
356 bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
357 ASSERT_TRUE(group);
Steven Valdez909b19f2016-11-21 15:35:44 -0500358
359 bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800360 ASSERT_TRUE(point);
Steven Valdez909b19f2016-11-21 15:35:44 -0500361 bssl::UniquePtr<BIGNUM> zero(BN_new());
Robert Sloana94fe052017-02-21 08:49:28 -0800362 ASSERT_TRUE(zero);
Steven Valdez909b19f2016-11-21 15:35:44 -0500363 BN_zero(zero.get());
Robert Sloana94fe052017-02-21 08:49:28 -0800364 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), zero.get(), nullptr,
365 nullptr, nullptr));
Steven Valdez909b19f2016-11-21 15:35:44 -0500366
Robert Sloana94fe052017-02-21 08:49:28 -0800367 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
368 << "g * 0 did not return point at infinity.";
Steven Valdez909b19f2016-11-21 15:35:44 -0500369
370 // Test that zero times an arbitrary point is also infinity. The generator is
371 // used as the arbitrary point.
372 bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
Robert Sloana94fe052017-02-21 08:49:28 -0800373 ASSERT_TRUE(generator);
374 ASSERT_TRUE(EC_POINT_mul(group.get(), generator.get(), BN_value_one(),
375 nullptr, nullptr, nullptr));
376 ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, generator.get(),
377 zero.get(), nullptr));
Steven Valdez909b19f2016-11-21 15:35:44 -0500378
Robert Sloana94fe052017-02-21 08:49:28 -0800379 EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
380 << "p * 0 did not return point at infinity.";
Steven Valdez909b19f2016-11-21 15:35:44 -0500381}
382
Robert Sloana94fe052017-02-21 08:49:28 -0800383static std::vector<EC_builtin_curve> AllCurves() {
David Benjamin4969cc92016-04-22 15:02:23 -0400384 const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
385 std::vector<EC_builtin_curve> curves(num_curves);
386 EC_get_builtin_curves(curves.data(), num_curves);
Robert Sloana94fe052017-02-21 08:49:28 -0800387 return curves;
David Benjamin4969cc92016-04-22 15:02:23 -0400388}
389
Robert Sloana94fe052017-02-21 08:49:28 -0800390static std::string CurveToString(
391 const testing::TestParamInfo<EC_builtin_curve> &params) {
392 // The comment field contains characters GTest rejects, so use the OBJ name.
393 return OBJ_nid2sn(params.param.nid);
Adam Langleye9ada862015-05-11 17:20:37 -0700394}
Robert Sloana94fe052017-02-21 08:49:28 -0800395
396INSTANTIATE_TEST_CASE_P(, ECCurveTest, testing::ValuesIn(AllCurves()),
397 CurveToString);