1e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley/* Copyright (c) 2014, Google Inc.
2e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley *
3e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * Permission to use, copy, modify, and/or distribute this software for any
4e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * purpose with or without fee is hereby granted, provided that the above
5e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * copyright notice and this permission notice appear in all copies.
6e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley *
7e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
15e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <stdio.h>
16e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <string.h>
17e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
18e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <vector>
19e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
20a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan#include <gtest/gtest.h>
21a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
22f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/bn.h>
23f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/bytestring.h>
24e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <openssl/crypto.h>
25e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <openssl/ec_key.h>
26e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <openssl/err.h>
27e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley#include <openssl/mem.h>
28f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin#include <openssl/nid.h>
29a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan#include <openssl/obj.h>
30a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
318542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan#include "../bn/internal.h"
328ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan#include "../../test/test_util.h"
33e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
34e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
35e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
36e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// omitted.
37e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic const uint8_t kECKeyWithoutPublic[] = {
38e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x30, 0x31, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc6, 0xc1, 0xaa, 0xda, 0x15, 0xb0,
39e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x76, 0x61, 0xf8, 0x14, 0x2c, 0x6c, 0xaf, 0x0f, 0xdb, 0x24, 0x1a, 0xff, 0x2e,
40e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0xfe, 0x46, 0xc0, 0x93, 0x8b, 0x74, 0xf2, 0xbc, 0xc5, 0x30, 0x52, 0xb0, 0x77,
41e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07,
42e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley};
43e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
444969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin// kECKeySpecifiedCurve is the above key with P-256's parameters explicitly
454969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin// spelled out rather than using a named curve.
464969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjaminstatic const uint8_t kECKeySpecifiedCurve[] = {
474969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x30, 0x82, 0x01, 0x22, 0x02, 0x01, 0x01, 0x04, 0x20, 0xc6, 0xc1, 0xaa,
484969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xda, 0x15, 0xb0, 0x76, 0x61, 0xf8, 0x14, 0x2c, 0x6c, 0xaf, 0x0f, 0xdb,
494969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x24, 0x1a, 0xff, 0x2e, 0xfe, 0x46, 0xc0, 0x93, 0x8b, 0x74, 0xf2, 0xbc,
504969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xc5, 0x30, 0x52, 0xb0, 0x77, 0xa0, 0x81, 0xfa, 0x30, 0x81, 0xf7, 0x02,
514969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01,
524969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x01, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
534969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
554969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x30, 0x5b, 0x04, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
564969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
574969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
584969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x04, 0x20, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb,
594969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
604969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, 0x03, 0x15,
614969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x00, 0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66, 0x78,
624969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f, 0x7e, 0x90, 0x04, 0x41, 0x04,
634969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5,
644969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0,
654969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2,
664969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16,
674969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
684969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x37, 0xbf, 0x51, 0xf5, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00,
694969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc,
704969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc,
714969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    0x63, 0x25, 0x51, 0x02, 0x01, 0x01,
724969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin};
734969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
74e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// kECKeyMissingZeros is an ECPrivateKey containing a degenerate P-256 key where
75e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// the private key is one. The private key is incorrectly encoded without zero
76e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// padding.
77e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic const uint8_t kECKeyMissingZeros[] = {
78e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x30, 0x58, 0x02, 0x01, 0x01, 0x04, 0x01, 0x01, 0xa0, 0x0a, 0x06, 0x08, 0x2a,
79e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04,
80e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63,
81e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1,
82e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f,
83e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57,
84e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
85e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley};
86e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
87e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// kECKeyMissingZeros is an ECPrivateKey containing a degenerate P-256 key where
88e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// the private key is one. The private key is encoded with the required zero
89e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// padding.
90e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langleystatic const uint8_t kECKeyWithZeros[] = {
91e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
94e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1,
95e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x44, 0x03, 0x42, 0x00, 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47,
96e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d,
97e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3,
98e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e,
99e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68,
100e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  0x37, 0xbf, 0x51, 0xf5,
101e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley};
102e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
103e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// DecodeECPrivateKey decodes |in| as an ECPrivateKey structure and returns the
104e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// result or nullptr on error.
105f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjaminstatic bssl::UniquePtr<EC_KEY> DecodeECPrivateKey(const uint8_t *in,
106f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin                                                  size_t in_len) {
1074969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  CBS cbs;
1084969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  CBS_init(&cbs, in, in_len);
109f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_KEY> ret(EC_KEY_parse_private_key(&cbs, NULL));
1104969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  if (!ret || CBS_len(&cbs) != 0) {
111e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    return nullptr;
112e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
113e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  return ret;
114e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley}
115e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
116e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// EncodeECPrivateKey encodes |key| as an ECPrivateKey structure into |*out|. It
117e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley// returns true on success or false on error.
1184969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjaminstatic bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
119909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez  bssl::ScopedCBB cbb;
1204969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  uint8_t *der;
1214969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  size_t der_len;
1224969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  if (!CBB_init(cbb.get(), 0) ||
1234969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      !EC_KEY_marshal_private_key(cbb.get(), key, EC_KEY_get_enc_flags(key)) ||
1244969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      !CBB_finish(cbb.get(), &der, &der_len)) {
1254969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin    return false;
1264969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  }
1274969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  out->assign(der, der + der_len);
1284969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  OPENSSL_free(der);
1294969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  return true;
130e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley}
131e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
132a94fe0531b3c196ad078174259af2201b2e3a246Robert SloanTEST(ECTest, Encoding) {
133a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_KEY> key =
134a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      DecodeECPrivateKey(kECKeyWithoutPublic, sizeof(kECKeyWithoutPublic));
135a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(key);
136e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
137a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  // Test that the encoding round-trips.
138e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  std::vector<uint8_t> out;
139a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EncodeECPrivateKey(&out, key.get()));
140a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
141e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
142e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  const EC_POINT *pub_key = EC_KEY_get0_public_key(key.get());
143a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(pub_key) << "Public key missing";
144e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
145f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> x(BN_new());
146f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> y(BN_new());
147a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(x);
148a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(y);
149a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
150a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      EC_KEY_get0_group(key.get()), pub_key, x.get(), y.get(), NULL));
151f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get()));
152f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<char> y_hex(BN_bn2hex(y.get()));
153a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(x_hex);
154a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(y_hex);
155a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
156a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_STREQ(
157a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      "c81561ecf2e54edefe6617db1c7a34a70744ddb261f269b83dacfcd2ade5a681",
158a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      x_hex.get());
159a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_STREQ(
160a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      "e0e2afa3f9b6abe4c698ef6495f1be49a3196c5056acb3763fe4507eec596e88",
161a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      y_hex.get());
162e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley}
163e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
164a94fe0531b3c196ad078174259af2201b2e3a246Robert SloanTEST(ECTest, ZeroPadding) {
165e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  // Check that the correct encoding round-trips.
166a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_KEY> key =
167a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      DecodeECPrivateKey(kECKeyWithZeros, sizeof(kECKeyWithZeros));
168a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(key);
169e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  std::vector<uint8_t> out;
170a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
171a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
172e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
173e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  // Keys without leading zeros also parse, but they encode correctly.
174e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  key = DecodeECPrivateKey(kECKeyMissingZeros, sizeof(kECKeyMissingZeros));
175a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(key);
176a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
177a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
178e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley}
179e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley
180a94fe0531b3c196ad078174259af2201b2e3a246Robert SloanTEST(ECTest, SpecifiedCurve) {
1814969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  // Test keys with specified curves may be decoded.
182f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_KEY> key =
1834969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      DecodeECPrivateKey(kECKeySpecifiedCurve, sizeof(kECKeySpecifiedCurve));
184a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(key);
1854969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1864969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  // The group should have been interpreted as P-256.
187a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_EQ(NID_X9_62_prime256v1,
188a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan            EC_GROUP_get_curve_name(EC_KEY_get0_group(key.get())));
1894969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
1904969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  // Encoding the key should still use named form.
1914969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  std::vector<uint8_t> out;
192a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
193a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
194fad6327e4112082b1e77e89a995723f26bd5a9aaAdam Langley}
195fad6327e4112082b1e77e89a995723f26bd5a9aaAdam Langley
196a94fe0531b3c196ad078174259af2201b2e3a246Robert SloanTEST(ECTest, ArbitraryCurve) {
1974969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  // Make a P-256 key and extract the affine coordinates.
198f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
199a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(key);
200a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_KEY_generate_key(key.get()));
2014969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
2024969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  // Make an arbitrary curve which is identical to P-256.
2034969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  static const uint8_t kP[] = {
2044969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2054969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
2064969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2074969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  };
2084969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  static const uint8_t kA[] = {
2094969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
2104969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
2114969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
2124969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  };
2134969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  static const uint8_t kB[] = {
2144969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd,
2154969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53,
2164969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b,
2174969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  };
2184969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  static const uint8_t kX[] = {
2194969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6,
2204969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb,
2214969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96,
2224969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  };
2234969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  static const uint8_t kY[] = {
2244969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb,
2254969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31,
2264969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5,
2274969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  };
2284969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  static const uint8_t kOrder[] = {
2294969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
2304969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17,
2314969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
2324969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  };
233f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
234a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(ctx);
235f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
236a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(p);
237f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
238a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(a);
239f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
240a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(b);
241f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kX, sizeof(kX), nullptr));
242a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(gx);
243f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kY, sizeof(kY), nullptr));
244a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(gy);
245f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
246a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(order);
2474969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
248f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_GROUP> group(
2494969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin      EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
250a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(group);
251f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
252a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(generator);
253a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
254a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      group.get(), generator.get(), gx.get(), gy.get(), ctx.get()));
255a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
256a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan                                     BN_value_one()));
2574969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
2584969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  // |group| should not have a curve name.
259a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_EQ(NID_undef, EC_GROUP_get_curve_name(group.get()));
2604969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
2614969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  // Copy |key| to |key2| using |group|.
262f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_KEY> key2(EC_KEY_new());
263a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(key2);
264f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
265a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(point);
266f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new());
267a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(x);
268a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_KEY_set_group(key2.get(), group.get()));
269a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(
270a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      EC_KEY_set_private_key(key2.get(), EC_KEY_get0_private_key(key.get())));
271a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
272a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      EC_KEY_get0_group(key.get()), EC_KEY_get0_public_key(key.get()), x.get(),
273a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      y.get(), nullptr));
274a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(),
275a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan                                                  x.get(), y.get(), nullptr));
276a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_KEY_set_public_key(key2.get(), point.get()));
2774969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
2784969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  // The key must be valid according to the new group too.
279a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(EC_KEY_check_key(key2.get()));
28029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
28129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  // Make a second instance of |group|.
28229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<EC_GROUP> group2(
28329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
28429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(group2);
28529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<EC_POINT> generator2(EC_POINT_new(group2.get()));
28629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(generator2);
28729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
28829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      group2.get(), generator2.get(), gx.get(), gy.get(), ctx.get()));
28929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(EC_GROUP_set_generator(group2.get(), generator2.get(),
29029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan                                     order.get(), BN_value_one()));
29129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
29229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group.get(), NULL));
29329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), NULL));
29429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
29529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  // group3 uses the wrong generator.
29629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<EC_GROUP> group3(
29729c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
29829c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(group3);
29929c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  bssl::UniquePtr<EC_POINT> generator3(EC_POINT_new(group3.get()));
30029c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(generator3);
30129c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
30229c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan      group3.get(), generator3.get(), x.get(), y.get(), ctx.get()));
30329c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  ASSERT_TRUE(EC_GROUP_set_generator(group3.get(), generator3.get(),
30429c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan                                     order.get(), BN_value_one()));
30529c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan
30629c1d2cf8620ad14e06d8e7ff91db8f4de04d481Robert Sloan  EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
3074969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin}
3084969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
3090da4395e6883298b793bb05d45e57ed2e03167f9Robert SloanTEST(ECTest, SetKeyWithoutGroup) {
3100da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
3110da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  ASSERT_TRUE(key);
3120da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan
3130da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  // Private keys may not be configured without a group.
3140da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  EXPECT_FALSE(EC_KEY_set_private_key(key.get(), BN_value_one()));
3150da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan
3160da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  // Public keys may not be configured without a group.
3170da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  bssl::UniquePtr<EC_GROUP> group(
3180da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan      EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
3190da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  ASSERT_TRUE(group);
3200da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  EXPECT_FALSE(
3210da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan      EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(group.get())));
3220da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan}
3230da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan
3240da4395e6883298b793bb05d45e57ed2e03167f9Robert SloanTEST(ECTest, GroupMismatch) {
3250da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_secp384r1));
3260da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  ASSERT_TRUE(key);
3270da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  bssl::UniquePtr<EC_GROUP> p256(
3280da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan      EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
3290da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  ASSERT_TRUE(p256);
3300da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan
3310da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  // Changing a key's group is invalid.
3320da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  EXPECT_FALSE(EC_KEY_set_group(key.get(), p256.get()));
3330da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan
3340da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  // Configuring a public key with the wrong group is invalid.
3350da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan  EXPECT_FALSE(
3360da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan      EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
3370da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan}
3380da4395e6883298b793bb05d45e57ed2e03167f9Robert Sloan
339a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloanclass ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
340a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
341a94fe0531b3c196ad078174259af2201b2e3a246Robert SloanTEST_P(ECCurveTest, SetAffine) {
342a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  // Generate an EC_KEY.
343a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
344a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(key);
345a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_KEY_generate_key(key.get()));
3464969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
3474969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  const EC_GROUP *const group = EC_KEY_get0_group(key.get());
348a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(
349a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      EC_POINT_is_on_curve(group, EC_KEY_get0_public_key(key.get()), nullptr));
3504969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
351a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  // Get the public key's coordinates.
352a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<BIGNUM> x(BN_new());
353a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(x);
354a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<BIGNUM> y(BN_new());
355a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(y);
3560db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan  bssl::UniquePtr<BIGNUM> p(BN_new());
3570db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan  ASSERT_TRUE(p);
358a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(EC_POINT_get_affine_coordinates_GFp(
359a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      group, EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr));
3600db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan  EXPECT_TRUE(
3610db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan      EC_GROUP_get_curve_GFp(group, p.get(), nullptr, nullptr, nullptr));
362a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
363a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  // Points on the curve should be accepted.
364a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group));
365a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(point);
366a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(EC_POINT_set_affine_coordinates_GFp(group, point.get(), x.get(),
367a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan                                                  y.get(), nullptr));
368a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
369a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  // Subtract one from |y| to make the point no longer on the curve.
370a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(BN_sub(y.get(), y.get(), BN_value_one()));
371a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
372a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  // Points not on the curve should be rejected.
373a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group));
374a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(invalid_point);
375a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(),
376a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan                                                   x.get(), y.get(), nullptr));
3770db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan
3780db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan  // Coordinates out of range should be rejected.
3790db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan  EXPECT_TRUE(BN_add(y.get(), y.get(), BN_value_one()));
3800db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan  EXPECT_TRUE(BN_add(y.get(), y.get(), p.get()));
3810db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan
3820db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan  EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(),
3830db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan                                                   x.get(), y.get(), nullptr));
3840db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan  EXPECT_FALSE(
3850db7f543e9eb4209a3124ef956229ed0e942193dRobert Sloan      EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get()));
386a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan}
387a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
3888ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert SloanTEST_P(ECCurveTest, GenerateFIPS) {
389572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan  // Generate an EC_KEY.
390572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan  bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
391572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan  ASSERT_TRUE(key);
3928ff035535f7cf2903f02bbe94d2fa10b7ab855f1Robert Sloan  ASSERT_TRUE(EC_KEY_generate_key_fips(key.get()));
393572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan}
394572a4e2e687520da9e518528d7371b794b1decc0Robert Sloan
395a94fe0531b3c196ad078174259af2201b2e3a246Robert SloanTEST_P(ECCurveTest, AddingEqualPoints) {
396a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
397a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(key);
398a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_KEY_generate_key(key.get()));
399a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
400a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  const EC_GROUP *const group = EC_KEY_get0_group(key.get());
4014969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
402f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<EC_POINT> p1(EC_POINT_new(group));
403a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(p1);
404a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())));
4054969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
406a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group));
407a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(p2);
408a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get())));
4094969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
410a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group));
411a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(double_p1);
412f0c4a6c4bbde5229ceb86740703243fe5c436aadDavid Benjamin  bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
413a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(ctx);
414a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_dbl(group, double_p1.get(), p1.get(), ctx.get()));
4154969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
416a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group));
417a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(p1_plus_p2);
418a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(
419a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      EC_POINT_add(group, p1_plus_p2.get(), p1.get(), p2.get(), ctx.get()));
4204969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
421a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_EQ(0,
422a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan            EC_POINT_cmp(group, double_p1.get(), p1_plus_p2.get(), ctx.get()))
423a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      << "A+A != 2A";
4244969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin}
4254969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
426a94fe0531b3c196ad078174259af2201b2e3a246Robert SloanTEST_P(ECCurveTest, MulZero) {
427a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
428a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(group);
429909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez
430909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez  bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
431a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(point);
432909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez  bssl::UniquePtr<BIGNUM> zero(BN_new());
433a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(zero);
434909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez  BN_zero(zero.get());
435a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), zero.get(), nullptr,
436a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan                           nullptr, nullptr));
437909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez
438a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
439a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      << "g * 0 did not return point at infinity.";
440909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez
441909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez  // Test that zero times an arbitrary point is also infinity. The generator is
442909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez  // used as the arbitrary point.
443909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez  bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
444a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(generator);
445a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), generator.get(), BN_value_one(),
446a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan                           nullptr, nullptr, nullptr));
447a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, generator.get(),
448a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan                           zero.get(), nullptr));
449a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
450a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
451a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan      << "p * 0 did not return point at infinity.";
452909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez}
453909b19f027eb0af12513f4d5589efdd67e34bd91Steven Valdez
45499319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan// Test that multiplying by the order produces ∞ and, moreover, that callers may
45599319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan// do so. |EC_POINT_mul| is almost exclusively used with reduced scalars, with
45699319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan// this exception. This comes from consumers following NIST SP 800-56A section
45799319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan// 5.6.2.3.2. (Though all our curves have cofactor one, so this check isn't
45899319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan// useful.)
45999319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert SloanTEST_P(ECCurveTest, MulOrder) {
46099319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
46199319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  ASSERT_TRUE(group);
46299319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan
46399319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  // Test that g × order = ∞.
46499319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
46599319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  ASSERT_TRUE(point);
46699319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(),
46799319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan                           EC_GROUP_get0_order(group.get()), nullptr, nullptr,
46899319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan                           nullptr));
46999319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan
47099319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
47199319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan      << "g * order did not return point at infinity.";
47299319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan
47399319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  // Test that p × order = ∞, for some arbitrary p.
47499319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  bssl::UniquePtr<BIGNUM> forty_two(BN_new());
47599319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  ASSERT_TRUE(forty_two);
47699319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
47799319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
47899319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan                           nullptr, nullptr));
47999319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, point.get(),
48099319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan                           EC_GROUP_get0_order(group.get()), nullptr));
48199319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan
48299319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan  EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
48399319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan      << "p * order did not return point at infinity.";
48499319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan}
48599319a18ffbf8991a8e752b4b8dacc9d39cdbd31Robert Sloan
486a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan// Test that |EC_POINT_mul| works with out-of-range scalars. Even beyond the
487a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan// usual |bn_correct_top| disclaimer, we completely disclaim all hope here as a
488a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan// reduction is needed, but we'll compute the right answer.
489a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert SloanTEST_P(ECCurveTest, MulOutOfRange) {
490a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
491a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(group);
492a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan
493a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  bssl::UniquePtr<BIGNUM> n_minus_one(BN_dup(EC_GROUP_get0_order(group.get())));
494a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(n_minus_one);
495a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(BN_sub_word(n_minus_one.get(), 1));
496a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan
497a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  bssl::UniquePtr<BIGNUM> minus_one(BN_new());
498a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(minus_one);
499a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(BN_one(minus_one.get()));
500a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  BN_set_negative(minus_one.get(), 1);
501a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan
502a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  bssl::UniquePtr<BIGNUM> seven(BN_new());
503a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(seven);
504a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(BN_set_word(seven.get(), 7));
505a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan
506a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  bssl::UniquePtr<BIGNUM> ten_n_plus_seven(
507a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan      BN_dup(EC_GROUP_get0_order(group.get())));
508a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(ten_n_plus_seven);
509a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(BN_mul_word(ten_n_plus_seven.get(), 10));
510a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(BN_add_word(ten_n_plus_seven.get(), 7));
511a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan
512a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  bssl::UniquePtr<EC_POINT> point1(EC_POINT_new(group.get())),
513a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan      point2(EC_POINT_new(group.get()));
514a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(point1);
515a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(point2);
516a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan
517a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point1.get(), n_minus_one.get(),
518a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan                           nullptr, nullptr, nullptr));
519a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), minus_one.get(), nullptr,
520a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan                           nullptr, nullptr));
521a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  EXPECT_EQ(0, EC_POINT_cmp(group.get(), point1.get(), point2.get(), nullptr))
522a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan      << "-1 * G and (n-1) * G did not give the same result";
523a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan
524a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point1.get(), seven.get(), nullptr,
525a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan                           nullptr, nullptr));
526a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), ten_n_plus_seven.get(),
527a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan                           nullptr, nullptr, nullptr));
528a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan  EXPECT_EQ(0, EC_POINT_cmp(group.get(), point1.get(), point2.get(), nullptr))
529a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan      << "7 * G and (10n + 7) * G did not give the same result";
530a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan}
531a815d5abd1078d03df3278e5e3d512c7f6a11f9aRobert Sloan
532a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan// Test that 10×∞ + G = G.
533a12bf4695c4916207f946efafd9728eb941e3f0aRobert SloanTEST_P(ECCurveTest, Mul) {
534a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
535a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  ASSERT_TRUE(group);
536a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  bssl::UniquePtr<EC_POINT> p(EC_POINT_new(group.get()));
537a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  ASSERT_TRUE(p);
538a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  bssl::UniquePtr<EC_POINT> result(EC_POINT_new(group.get()));
539a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  ASSERT_TRUE(result);
540a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  bssl::UniquePtr<BIGNUM> n(BN_new());
541a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  ASSERT_TRUE(n);
542a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  ASSERT_TRUE(EC_POINT_set_to_infinity(group.get(), p.get()));
543a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  ASSERT_TRUE(BN_set_word(n.get(), 10));
544a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan
545a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  // First check that 10×∞ = ∞.
546a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), result.get(), nullptr, p.get(), n.get(),
547a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan                           nullptr));
548a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), result.get()));
549a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan
550a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  // Now check that 10×∞ + G = G.
551a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  const EC_POINT *generator = EC_GROUP_get0_generator(group.get());
552a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), result.get(), BN_value_one(), p.get(),
553a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan                           n.get(), nullptr));
554a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan  EXPECT_EQ(0, EC_POINT_cmp(group.get(), result.get(), generator, nullptr));
555a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan}
556a12bf4695c4916207f946efafd9728eb941e3f0aRobert Sloan
5578542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan#if !defined(BORINGSSL_SHARED_LIBRARY)
5588542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert SloanTEST_P(ECCurveTest, MulNonMinimal) {
5598542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
5608542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(group);
5618542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
5628542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  bssl::UniquePtr<BIGNUM> forty_two(BN_new());
5638542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(forty_two);
5648542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
5658542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
5668542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  // Compute g × 42.
5678542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
5688542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(point);
5698542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
5708542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan                           nullptr, nullptr));
5718542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
5728542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  // Compute it again with a non-minimal 42, much larger than the scalar.
5738542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(bn_resize_words(forty_two.get(), 64));
5748542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
5758542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  bssl::UniquePtr<EC_POINT> point2(EC_POINT_new(group.get()));
5768542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(point2);
5778542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), forty_two.get(), nullptr,
5788542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan                           nullptr, nullptr));
5798542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  EXPECT_EQ(0, EC_POINT_cmp(group.get(), point.get(), point2.get(), nullptr));
5808542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan}
5818542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan#endif  // BORINGSSL_SHARED_LIBRARY
5828542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
583cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan// Test that EC_KEY_set_private_key rejects invalid values.
584cd79cdebdcdadadb156e037973c927abf3dac79dRobert SloanTEST_P(ECCurveTest, SetInvalidPrivateKey) {
585cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
586cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  ASSERT_TRUE(key);
587cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan
588cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  bssl::UniquePtr<BIGNUM> bn(BN_new());
589cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  ASSERT_TRUE(BN_one(bn.get()));
590cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  BN_set_negative(bn.get(), 1);
591cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  EXPECT_FALSE(EC_KEY_set_private_key(key.get(), bn.get()))
592cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan      << "Unexpectedly set a key of -1";
593cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  ERR_clear_error();
594cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan
595cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  ASSERT_TRUE(
596cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan      BN_copy(bn.get(), EC_GROUP_get0_order(EC_KEY_get0_group(key.get()))));
597cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  EXPECT_FALSE(EC_KEY_set_private_key(key.get(), bn.get()))
598cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan      << "Unexpectedly set a key of the group order.";
599cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan  ERR_clear_error();
600cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan}
601cd79cdebdcdadadb156e037973c927abf3dac79dRobert Sloan
6028542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert SloanTEST_P(ECCurveTest, IgnoreOct2PointReturnValue) {
6038542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
6048542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(group);
6058542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
6068542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  bssl::UniquePtr<BIGNUM> forty_two(BN_new());
6078542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(forty_two);
6088542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(BN_set_word(forty_two.get(), 42));
6098542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
6108542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  // Compute g × 42.
6118542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
6128542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(point);
6138542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), forty_two.get(), nullptr,
6148542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan                           nullptr, nullptr));
6158542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
6168542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  // Serialize the point.
6178542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  size_t serialized_len =
6188542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan      EC_POINT_point2oct(group.get(), point.get(),
6198542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan                         POINT_CONVERSION_UNCOMPRESSED, nullptr, 0, nullptr);
6208542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_NE(0u, serialized_len);
6218542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
6228542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  std::vector<uint8_t> serialized(serialized_len);
6238542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_EQ(serialized_len,
6248542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan            EC_POINT_point2oct(group.get(), point.get(),
6258542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan                               POINT_CONVERSION_UNCOMPRESSED, serialized.data(),
6268542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan                               serialized_len, nullptr));
6278542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
6288542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  // Create a serialized point that is not on the curve.
6298542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  serialized[serialized_len - 1]++;
6308542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
6318542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_FALSE(EC_POINT_oct2point(group.get(), point.get(), serialized.data(),
6328542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan                                  serialized.size(), nullptr));
6338542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  // After a failure, |point| should have been set to the generator to defend
6348542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  // against code that doesn't check the return value.
6358542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan  ASSERT_EQ(0, EC_POINT_cmp(group.get(), point.get(),
6368542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan                            EC_GROUP_get0_generator(group.get()), nullptr));
6378542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan}
6388542c08a00c332af2ebca2a0c64b8d4d5fbd4cd2Robert Sloan
639a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloanstatic std::vector<EC_builtin_curve> AllCurves() {
6404969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
6414969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  std::vector<EC_builtin_curve> curves(num_curves);
6424969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin  EC_get_builtin_curves(curves.data(), num_curves);
643a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  return curves;
6444969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin}
6454969cc9b0ab2905ec478277f50ed3849b37a6c6bDavid Benjamin
646a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloanstatic std::string CurveToString(
647a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan    const testing::TestParamInfo<EC_builtin_curve> &params) {
648a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  // The comment field contains characters GTest rejects, so use the OBJ name.
649a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan  return OBJ_nid2sn(params.param.nid);
650e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley}
651a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan
652a94fe0531b3c196ad078174259af2201b2e3a246Robert SloanINSTANTIATE_TEST_CASE_P(, ECCurveTest, testing::ValuesIn(AllCurves()),
653a94fe0531b3c196ad078174259af2201b2e3a246Robert Sloan                        CurveToString);
654